require 'auth/middleware' require 'hws_settings' require 'p4_error' require 'pathname' require 'P4' require 'json' require 'pp' # This is mostly a namespace of Authentication-related methods. module Auth # 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 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. # # We also have special handling here to take care of setting up p4trust. def self.ticket_from_login(p4) results = nil p4.at_exception_level(P4::RAISE_NONE) do results = p4.run_login('-p', '-a') end # Look for trust failure. # # If a TRUSTED_FINGERPRINTS file is set, then trust it only if fingerprint # is in the file. If it's not in the file, we do not trust. # # Otherwise, if ENABLE_MAN_IN_MIDDLE_ATTACKS is true, we run 'p4 trust -f'. # This should generally be disabled by default, and only enabled for # test servers. if p4.messages && p4.messages.any? { |m| m.msgid == 3120 || m.msgid == 3121 } if !HWSSettings.system.TRUST_FINGERPRINTS.nil? fprint = load_fingerprint(p4.messages.first { |m| m.msgid == 3120 || m.msgid == 3121 }) trusted = load_trust_fingerprints if trusted.include?(fprint) p4.run_trust('-f', '-i', fprint) end elsif HWSSettings.system.ENABLE_MAN_IN_MIDDLE_ATTACKS == true # This will throw exceptions in cases where the trust actually succeeded p4.at_exception_level(P4::RAISE_NONE) do trust_results = p4.run_trust('-y', '-f') puts "p4 trust -y -f:" pp trust_results end else raise_error(p4) end p4.at_exception_level(P4::RAISE_NONE) do results = p4.run_login('-p', '-a') puts "p4 login -p -a:" pp results end end auth_ok = raise_unless_auth_error(p4) if !auth_ok nil else # In security 0 servers, if the user does not need to log in, return an # empty string as our valid ticket value. if p4.messages && !p4.messages.empty? && p4.messages.first.msgid == 7481 p4.password = '' else p4.password = results[0] end end end def self.load_trust_fingerprints IO.read(HWSSettings.system.TRUST_FINGERPRINTS).split(/\n/) end # Yep. I can not figure out any other information sent by the server that # provides the fingerprint that we need to validate. def self.load_fingerprint(message) re = /The fingerprint for the key sent to your client is\n(.*)\nTo allow connection use the 'p4 trust' command./ re.match(message.to_s)[1] 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 | |
---|---|---|---|---|---|
#6 | 16196 | Doug Scheirer | Merge from main | ||
#5 | 16114 | Doug Scheirer | Merge from main | ||
#4 | 16079 | Doug Scheirer | Merge from main | ||
#3 | 16014 | Doug Scheirer | Merge down from main | ||
#2 | 15884 | Doug Scheirer | Merge from main | ||
#1 | 15688 | Doug Scheirer |
Populate -o //guest/perforce_software/helix-web-services/... //guest/doug_scheirer/helix-web-services/.... |
||
//guest/perforce_software/helix-web-services/main/source/helix_web_services/lib/auth.rb | |||||
#1 | 15622 | tjuricek |
Move source code to 'source/' subdirectory of branch. build/ will remain where it is. |
||
//guest/perforce_software/helix-web-services/main/helix_web_services/lib/auth.rb | |||||
#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. |