class Google::Auth::ExternalAccount::PluggableAuthCredentials
This module handles the retrieval of credentials from Google
Cloud by utilizing the any 3PI provider then exchanging the credentials for a short-lived Google
Cloud access token.
Constants
- ENABLE_PLUGGABLE_ENV
constant for pluggable auth enablement in environment variable.
- EXECUTABLE_SUPPORTED_MAX_VERSION
- EXECUTABLE_TIMEOUT_MILLIS_DEFAULT
- EXECUTABLE_TIMEOUT_MILLIS_LOWER_BOUND
- EXECUTABLE_TIMEOUT_MILLIS_UPPER_BOUND
- ID_TOKEN_TYPE
Attributes
client_id[R]
Will always be nil, but method still gets used.
Public Class Methods
new(options = {})
click to toggle source
Initialize from options map.
@param [string] audience @param [hash{symbol => value}] credential_source
credential_source is a hash that contains either source file or url. credential_source_format is either text or json. To define how we parse the credential response.
# File lib/googleauth/external_account/pluggable_credentials.rb, line 49 def initialize options = {} base_setup options @audience = options[:audience] @credential_source = options[:credential_source] || {} @credential_source_executable = @credential_source[:executable] raise "Missing excutable source. An 'executable' must be provided" if @credential_source_executable.nil? @credential_source_executable_command = @credential_source_executable[:command] if @credential_source_executable_command.nil? raise "Missing command field. Executable command must be provided." end @credential_source_executable_timeout_millis = @credential_source_executable[:timeout_millis] || EXECUTABLE_TIMEOUT_MILLIS_DEFAULT if @credential_source_executable_timeout_millis < EXECUTABLE_TIMEOUT_MILLIS_LOWER_BOUND || @credential_source_executable_timeout_millis > EXECUTABLE_TIMEOUT_MILLIS_UPPER_BOUND raise "Timeout must be between 5 and 120 seconds." end @credential_source_executable_output_file = @credential_source_executable[:output_file] end
Public Instance Methods
retrieve_subject_token!()
click to toggle source
# File lib/googleauth/external_account/pluggable_credentials.rb, line 69 def retrieve_subject_token! unless ENV[ENABLE_PLUGGABLE_ENV] == "1" raise "Executables need to be explicitly allowed (set GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES to '1') " \ "to run." end # check output file first subject_token = load_subject_token_from_output_file return subject_token unless subject_token.nil? # environment variable injection env = inject_environment_variables output = subprocess_with_timeout env, @credential_source_executable_command, @credential_source_executable_timeout_millis response = MultiJson.load output, symbolize_keys: true parse_subject_token response end
Private Instance Methods
inject_environment_variables()
click to toggle source
# File lib/googleauth/external_account/pluggable_credentials.rb, line 130 def inject_environment_variables env = ENV.to_h env["GOOGLE_EXTERNAL_ACCOUNT_AUDIENCE"] = @audience env["GOOGLE_EXTERNAL_ACCOUNT_TOKEN_TYPE"] = @subject_token_type env["GOOGLE_EXTERNAL_ACCOUNT_INTERACTIVE"] = "0" # only non-interactive mode we support. unless @service_account_impersonation_url.nil? env["GOOGLE_EXTERNAL_ACCOUNT_IMPERSONATED_EMAIL"] = service_account_email end unless @credential_source_executable_output_file.nil? env["GOOGLE_EXTERNAL_ACCOUNT_OUTPUT_FILE"] = @credential_source_executable_output_file end env end
load_subject_token_from_output_file()
click to toggle source
# File lib/googleauth/external_account/pluggable_credentials.rb, line 87 def load_subject_token_from_output_file return nil if @credential_source_executable_output_file.nil? return nil unless File.exist? @credential_source_executable_output_file begin content = File.read @credential_source_executable_output_file, encoding: "utf-8" response = MultiJson.load content, symbolize_keys: true rescue StandardError return nil end begin subject_token = parse_subject_token response rescue StandardError => e return nil if e.message.match(/The token returned by the executable is expired/) raise e end subject_token end
parse_subject_token(response)
click to toggle source
# File lib/googleauth/external_account/pluggable_credentials.rb, line 105 def parse_subject_token response validate_response_schema response unless response[:success] if response[:code].nil? || response[:message].nil? raise "Error code and message fields are required in the response." end raise "Executable returned unsuccessful response: code: #{response[:code]}, message: #{response[:message]}." end if response[:expiration_time] && response[:expiration_time] < Time.now.to_i raise "The token returned by the executable is expired." end raise "The executable response is missing the token_type field." if response[:token_type].nil? return response[:id_token] if ID_TOKEN_TYPE.include? response[:token_type] return response[:saml_response] if response[:token_type] == "urn:ietf:params:oauth:token-type:saml2" raise "Executable returned unsupported token type." end
subprocess_with_timeout(environment_vars, command, timeout_seconds)
click to toggle source
# File lib/googleauth/external_account/pluggable_credentials.rb, line 144 def subprocess_with_timeout environment_vars, command, timeout_seconds Timeout.timeout timeout_seconds do output, error, status = Open3.capture3 environment_vars, command unless status.success? raise "Executable exited with non-zero return code #{status.exitstatus}. Error: #{output}, #{error}" end output end end
validate_response_schema(response)
click to toggle source
# File lib/googleauth/external_account/pluggable_credentials.rb, line 122 def validate_response_schema response raise "The executable response is missing the version field." if response[:version].nil? if response[:version] > EXECUTABLE_SUPPORTED_MAX_VERSION raise "Executable returned unsupported version #{response[:version]}." end raise "The executable response is missing the success field." if response[:success].nil? end