class Aws::SSOCredentials

An auto-refreshing credential provider that assumes a role via {Aws::SSO::Client#get_role_credentials} using a cached access token. When ‘sso_session` is specified, token refresh logic from {Aws::SSOTokenProvider} will be used to refresh the token if possible. This class does NOT implement the SSO login token flow - tokens must generated separately by running `aws login` from the AWS CLI with the correct profile. The `SSOCredentials` will auto-refresh the AWS credentials from SSO.

# You must first run aws sso login --profile your-sso-profile
sso_credentials = Aws::SSOCredentials.new(
  sso_account_id: '123456789',
  sso_role_name: "role_name",
  sso_region: "us-east-1",
  sso_session: 'my_sso_session'
)
ec2 = Aws::EC2::Client.new(credentials: sso_credentials)

If you omit ‘:client` option, a new {Aws::SSO::Client} object will be constructed with additional options that were provided.

@see Aws::SSO::Client#get_role_credentials @see docs.aws.amazon.com/singlesignon/latest/userguide/what-is.html

Constants

LEGACY_REQUIRED_OPTS

@api private

SSO_LOGIN_GUIDANCE

@api private

TOKEN_PROVIDER_REQUIRED_OPTS

Attributes

client[R]

@return [SSO::Client]

Public Class Methods

new(options = {}) click to toggle source

@option options [required, String] :sso_account_id The AWS account ID

that temporary AWS credentials will be resolved for

@option options [required, String] :sso_role_name The corresponding

IAM role in the AWS account that temporary AWS credentials
will be resolved for.

@option options [required, String] :sso_region The AWS region where the

SSO directory for the given sso_start_url is hosted.

@option options [String] :sso_session The SSO Token used for fetching

the token. If provided, refresh logic from the {Aws::SSOTokenProvider}
will be used.

@option options [String] :sso_start_url (legacy profiles) If provided,

legacy token fetch behavior will be used, which does not support
token refreshing.  The start URL is provided by the SSO
service via the console and is the URL used to
login to the SSO directory. This is also sometimes referred to as
the "User Portal URL".

@option options [SSO::Client] :client Optional ‘SSO::Client`. If not

provided, a client will be constructed.

@option options [Callable] before_refresh Proc called before

credentials are refreshed. `before_refresh` is called
with an instance of this object when
AWS credentials are required and need to be refreshed.
Calls superclass method Aws::RefreshingCredentials::new
# File lib/aws-sdk-core/sso_credentials.rb, line 69
def initialize(options = {})
  options = options.select {|k, v| !v.nil? }
  if (options[:sso_session])
    missing_keys = TOKEN_PROVIDER_REQUIRED_OPTS.select { |k| options[k].nil? }
    unless missing_keys.empty?
      raise ArgumentError, "Missing required keys: #{missing_keys}"
    end
    @legacy = false
    @sso_role_name = options.delete(:sso_role_name)
    @sso_account_id = options.delete(:sso_account_id)

    # if client has been passed, don't pass through to SSOTokenProvider
    @client = options.delete(:client)
    options.delete(:sso_start_url)
    @token_provider = Aws::SSOTokenProvider.new(options.dup)
    @sso_session = options.delete(:sso_session)
    @sso_region = options.delete(:sso_region)

    unless @client
      client_opts = {}
      options.each_pair { |k,v| client_opts[k] = v unless CLIENT_EXCLUDE_OPTIONS.include?(k) }
      client_opts[:region] = @sso_region
      client_opts[:credentials] = nil
      @client = Aws::SSO::Client.new(client_opts)
    end
  else # legacy behavior
    missing_keys = LEGACY_REQUIRED_OPTS.select { |k| options[k].nil? }
    unless missing_keys.empty?
      raise ArgumentError, "Missing required keys: #{missing_keys}"
    end
    @legacy = true
    @sso_start_url = options.delete(:sso_start_url)
    @sso_region = options.delete(:sso_region)
    @sso_role_name = options.delete(:sso_role_name)
    @sso_account_id = options.delete(:sso_account_id)

    # validate we can read the token file
    read_cached_token

    client_opts = {}
    options.each_pair { |k,v| client_opts[k] = v unless CLIENT_EXCLUDE_OPTIONS.include?(k) }
    client_opts[:region] = @sso_region
    client_opts[:credentials] = nil

    @client = options[:client] || Aws::SSO::Client.new(client_opts)
  end

  @async_refresh = true
  super
end

Private Instance Methods

read_cached_token() click to toggle source
# File lib/aws-sdk-core/sso_credentials.rb, line 125
def read_cached_token
  cached_token = Json.load(File.read(sso_cache_file))
  # validation
  unless cached_token['accessToken'] && cached_token['expiresAt']
    raise ArgumentError, 'Missing required field(s)'
  end
  expires_at = DateTime.parse(cached_token['expiresAt'])
  if expires_at < DateTime.now
    raise ArgumentError, 'Cached SSO Token is expired.'
  end
  cached_token
rescue Errno::ENOENT, Aws::Json::ParseError, ArgumentError
  raise Errors::InvalidSSOCredentials, SSO_LOGIN_GUIDANCE
end
refresh() click to toggle source
# File lib/aws-sdk-core/sso_credentials.rb, line 140
def refresh
  c = if @legacy
        cached_token = read_cached_token
        @client.get_role_credentials(
          account_id: @sso_account_id,
          role_name: @sso_role_name,
          access_token: cached_token['accessToken']
        ).role_credentials
      else
        @client.get_role_credentials(
          account_id: @sso_account_id,
          role_name: @sso_role_name,
          access_token: @token_provider.token.token
        ).role_credentials
      end

  @credentials = Credentials.new(
    c.access_key_id,
    c.secret_access_key,
    c.session_token,
    account_id: @sso_account_id
  )
  @expiration = Time.at(c.expiration / 1000.0)
end
sso_cache_file() click to toggle source
# File lib/aws-sdk-core/sso_credentials.rb, line 165
def sso_cache_file
  start_url_sha1 = OpenSSL::Digest::SHA1.hexdigest(@sso_start_url.encode('utf-8'))
  File.join(Dir.home, '.aws', 'sso', 'cache', "#{start_url_sha1}.json")
rescue ArgumentError
  # Dir.home raises ArgumentError when ENV['home'] is not set
  raise ArgumentError, "Unable to load sso_cache_file: ENV['HOME'] is not set."
end