require 'auth/app' require 'auth/middleware' require 'p4_error' require 'pathname' require 'P4' require 'json' # This is mostly a namespace of Authentication-related methods. module Auth # TODO delete this # def self.accept_json?(str) # str =~ /application\/json/ # end # TODO replace this # # # If the login/password combination is valid, we'll create a new session and # # return the session ID (which is just a GUID). # # # # This assumes that the p4 connection already has the user name set. # # # # If the password is a ticket, that'll be stored as is. If it's a password # # (currently determined if it's not a 32 character alphanumeric string) # # we'll create a ticket and store that. # # # # Settings is the Sinatra application configuration. # def self.create_session(p4, password, settings) # ticket = nil # # if Auth.p4_ticket?(password) # ticket = password # else # ticket = ticket_from_login(p4) # end # # return if ticket.nil? # # results = p4.run_user('-o') # # save_token(user_info(p4, results, ticket), settings) # end # Returns true if the string looks like a Perforce authentication ticket. def self.p4_ticket?(str) /^[a-zA-Z0-9]{32,}$/.match(str) != nil end # # We only count uuids that were returned via SecureRandom.uuid used to # # generate internal security tokens. # def self.uuid?(str) # /^[a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{12}$/ # .match(str) # end # # # Saves the information stored in the user_info hash to a new randomly # # generated ticket file, and returns that new ticket file's name. # # # # user_info should have the following values: # # * login # # * email # # * full_name # # * ticket # def self.save_token(user_info, settings) # unless File.directory?(settings.token_path) # Pathname.new(settings.token_path).mkpath # FileUtils.chmod(0700, settings.token_path) # end # # token = SecureRandom.uuid # token_path = Pathname.new(settings.token_path) + token # # File.open(token_path, 'w', 0600) do |file| # file.write(JSON.generate(user_info)) # end # # token # end # # # Removes the session file # # # # Assumes blindly that we're supposed to be able to do this. The caller # # should ensure that the token is deletable. # def self.delete_session(token, settings) # token_path = Pathname.new(settings.token_path) + token # File.delete(token_path) if File.exist?(token_path) # end # Takes an array with [login, password], and returns true if the password # is a legal token for that login, or looks like a p4 ticket. # # The second array, hws_settings, is used to indicate our perforce connection def self.credentials_valid?(credentials, hws_settings) user = credentials.first password = credentials.last # TODO see if we can initialize our p4 object and obtain user information end def self.read_token(token, settings) token_path = Pathname.new(settings.token_path) + token if File.exist?(token_path) File.open(token_path, 'r') do |file| return JSON.parse(file.read) end end nil end private def self.warn_if_tmp_dir(token_dir) if token_dir.start_with?('/tmp') puts "Your token directory is using the default '/tmp' location, "\ 'please reconfigure to a reliable location' end end def self.warn_illegal_privileges(mode, token_dir) warn_unless_user_rwx(mode, token_dir) warn_no_group_write(mode, token_dir) warn_no_group_read(mode, token_dir) warn_no_group_execute(mode, token_dir) warn_no_other_write(mode, token_dir) warn_no_other_read(mode, token_dir) warn_no_other_execute(mode, token_dir) end # Check owner read/write/execute - should all be there def self.warn_unless_user_rwx(mode, token_dir) unless (mode & 0400 == 0400) && (mode & 0200 == 0200) && (mode & 0100 == 0100) puts "The token_path '#{token_dir}' should allow the owner read, "\ 'write and execute privileges' end end def self.warn_no_group_write(mode, token_dir) if (mode & 0040 == 0040) puts "The token_path '#{token_dir}' should not have group write access" end end def self.warn_no_group_read(mode, token_dir) if (mode & 0020 == 0020) puts "The token_path '#{token_dir}' should not have group read access" end end def self.warn_no_group_execute(mode, token_dir) if (mode & 0010 == 0010) puts "The token_path '#{token_dir}' should not have group "\ 'execute access' end end def self.warn_no_other_write(mode, token_dir) if (mode & 0004 == 0004) puts "The token_path '#{token_dir}' should not have other write access" end end def self.warn_no_other_read(mode, token_dir) if (mode & 0002 == 0002) puts "The token_path '#{token_dir}' should not have other read access" end end def self.warn_no_other_execute(mode, token_dir) if (mode & 0001 == 0001) puts "The token_path '#{token_dir}' should not have other "\ 'execute access' end end # We want special error handling here to return 4xx codes instead of 5xx # in the face of an invalid password. Temporarily drop to lowest # exception level, and # just return nil when login doesn't work. def self.ticket_from_login(p4) results = nil p4.at_exception_level(P4::RAISE_NONE) do results = p4.run_login('-p', '-a') end auth_ok = raise_unless_auth_error(p4) if !auth_ok nil else p4.password = results[0] end end def self.raise_unless_auth_error(p4) if Auth.error?(p4) msg = p4.messages[0] if msg.msgid == 7205 || # invalid user msg.msgid == 7206 # invalid password return false else Auth.raise_error(p4) end end true end def self.user_info(p4, results, ticket) { user: p4.user, email: results[0]['Email'], full_name: results[0]['FullName'], ticket: ticket } end # Check for P4 errors def self.error?(p4) !p4.errors.empty? end # Raise an exception if necessary on a P4 Error def self.raise_error(p4) err = p4.messages.find { |m| m.severity > 2 } fail P4Error.new(err.msgid, err.severity, err.to_s) end end
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#5 | 15622 | tjuricek |
Move source code to 'source/' subdirectory of branch. build/ will remain where it is. |
||
#4 | 15073 | tjuricek | Update Auth::Middleware and add spec | ||
#3 | 15059 | tjuricek | Tested authentication of the core /auth/v1/login method. | ||
#2 | 15032 | tjuricek |
Starting config and doc revisions. System is now broken while revisions underway. Configuration of the p4d connection is now done via a single HWSSettings middleware object injected into the Rack env. The HWSP4Cleanup middleware now cleans up any p4 injected into the Rack env. The Auth::App class now mostly just contains one method to generate a p4 ticket. /auth/v1/login. Added yard documentation for the main project. Yard docs have been reconfigured to dump into build/ directories. This should probably be done with each release. Hm... The top level rake file contains a task, 'all:doc', to update our documentation. This should probably be run for each checkin. Hm... Specs are now using Rack::Test on top of a 'live' p4d. I'd suggest you still use the p4util mechanism, which now dumps to a /tmp folder, so we can safely add P4IGNORE rules back into your local .p4config file. Old 'perforce' application now called 'helix_versioning_engine'. Removing cache data. Helix Sync may be slow. It may also get axed. We'll see. |
||
#1 | 13799 | tjuricek |
Start with branch specs hosting in a new monolithic 'helix web services' project. Converting from a microservice to a monolithic architecture due to resource constraints at getting a deployable system running. Additionally, since it's not expected that people will upgrade often, the major benefit of microservices - being able to add services individually without affecting others - is not really a major benefit. The Ruby SDK will be consolidated into a single 'helix web services client' project. It may end up being distributed via Rubygems. This only runs branch specs at the moment. I want to get a CD pipeline setup for the monolithic server before revising more methods. |