aws_assume_role 0.0.3 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +31 -11
  4. data/Gemfile +7 -13
  5. data/LICENSE.md +201 -19
  6. data/README.md +176 -145
  7. data/aws_assume_role.gemspec +35 -21
  8. data/bin/aws-assume-role +1 -83
  9. data/i18n/en.yml +106 -0
  10. data/lib/aws_assume_role.rb +2 -3
  11. data/lib/aws_assume_role/cli.rb +15 -0
  12. data/lib/aws_assume_role/cli/actions/abstract_action.rb +53 -0
  13. data/lib/aws_assume_role/cli/actions/configure_profile.rb +21 -0
  14. data/lib/aws_assume_role/cli/actions/configure_role_assumption.rb +19 -0
  15. data/lib/aws_assume_role/cli/actions/console.rb +68 -0
  16. data/lib/aws_assume_role/cli/actions/delete_profile.rb +20 -0
  17. data/lib/aws_assume_role/cli/actions/includes.rb +18 -0
  18. data/lib/aws_assume_role/cli/actions/list_profiles.rb +10 -0
  19. data/lib/aws_assume_role/cli/actions/migrate_profile.rb +18 -0
  20. data/lib/aws_assume_role/cli/actions/reset_environment.rb +48 -0
  21. data/lib/aws_assume_role/cli/actions/run.rb +34 -0
  22. data/lib/aws_assume_role/cli/actions/set_environment.rb +60 -0
  23. data/lib/aws_assume_role/cli/actions/test.rb +31 -0
  24. data/lib/aws_assume_role/cli/commands/configure.rb +29 -0
  25. data/lib/aws_assume_role/cli/commands/console.rb +17 -0
  26. data/lib/aws_assume_role/cli/commands/delete.rb +11 -0
  27. data/lib/aws_assume_role/cli/commands/environment.rb +32 -0
  28. data/lib/aws_assume_role/cli/commands/list.rb +10 -0
  29. data/lib/aws_assume_role/cli/commands/migrate.rb +11 -0
  30. data/lib/aws_assume_role/cli/commands/run.rb +17 -0
  31. data/lib/aws_assume_role/cli/commands/test.rb +18 -0
  32. data/lib/aws_assume_role/configuration.rb +19 -0
  33. data/lib/aws_assume_role/core_ext/aws-sdk/credential_provider_chain.rb +2 -0
  34. data/lib/aws_assume_role/core_ext/aws-sdk/includes.rb +7 -0
  35. data/lib/aws_assume_role/credentials/factories.rb +9 -0
  36. data/lib/aws_assume_role/credentials/factories/abstract_factory.rb +31 -0
  37. data/lib/aws_assume_role/credentials/factories/assume_role.rb +38 -0
  38. data/lib/aws_assume_role/credentials/factories/default_chain_provider.rb +101 -0
  39. data/lib/aws_assume_role/credentials/factories/environment.rb +24 -0
  40. data/lib/aws_assume_role/credentials/factories/includes.rb +17 -0
  41. data/lib/aws_assume_role/credentials/factories/instance_profile.rb +17 -0
  42. data/lib/aws_assume_role/credentials/factories/repository.rb +35 -0
  43. data/lib/aws_assume_role/credentials/factories/shared.rb +15 -0
  44. data/lib/aws_assume_role/credentials/factories/shared_keyring.rb +16 -0
  45. data/lib/aws_assume_role/credentials/factories/static.rb +16 -0
  46. data/lib/aws_assume_role/credentials/providers/assume_role_credentials.rb +58 -0
  47. data/lib/aws_assume_role/credentials/providers/includes.rb +9 -0
  48. data/lib/aws_assume_role/credentials/providers/mfa_session_credentials.rb +102 -0
  49. data/lib/aws_assume_role/credentials/providers/shared_keyring_credentials.rb +22 -0
  50. data/lib/aws_assume_role/includes.rb +30 -0
  51. data/lib/aws_assume_role/logging.rb +16 -28
  52. data/lib/aws_assume_role/profile_configuration.rb +71 -0
  53. data/lib/aws_assume_role/runner.rb +39 -0
  54. data/lib/aws_assume_role/store/includes.rb +16 -0
  55. data/lib/aws_assume_role/store/keyring.rb +59 -0
  56. data/lib/aws_assume_role/store/serialization.rb +18 -0
  57. data/lib/aws_assume_role/store/shared_config_with_keyring.rb +175 -0
  58. data/lib/aws_assume_role/types.rb +30 -0
  59. data/lib/aws_assume_role/ui.rb +55 -0
  60. data/lib/aws_assume_role/vendored/aws.rb +4 -0
  61. data/lib/aws_assume_role/vendored/aws/README.md +2 -0
  62. data/lib/aws_assume_role/vendored/aws/assume_role_credentials.rb +68 -0
  63. data/lib/aws_assume_role/vendored/aws/includes.rb +9 -0
  64. data/lib/aws_assume_role/vendored/aws/refreshing_credentials.rb +60 -0
  65. data/lib/aws_assume_role/vendored/aws/shared_config.rb +220 -0
  66. data/lib/aws_assume_role/version.rb +3 -0
  67. metadata +264 -20
  68. data/.rspec +0 -2
  69. data/Rakefile +0 -2
  70. data/bin/test.rb +0 -39
  71. data/lib/aws_assume_role/credentials.rb +0 -92
  72. data/lib/aws_assume_role/profile.rb +0 -203
  73. data/lib/aws_assume_role/profile/assume_role.rb +0 -127
  74. data/lib/aws_assume_role/profile/basic.rb +0 -152
  75. data/lib/aws_assume_role/profile/list.rb +0 -57
@@ -1,32 +1,46 @@
1
1
  # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
3
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
-
2
+ require_relative "lib/aws_assume_role/version"
5
3
  Gem::Specification.new do |spec|
6
- spec.name = 'aws_assume_role'
7
- spec.version = '0.0.3'
8
- spec.authors = ['Jon Topper', 'Jack Thomas']
9
- spec.email = ['jon@scalefactory.com', 'jack@scalefactory.com']
4
+ spec.name = "aws_assume_role"
5
+ spec.version = AwsAssumeRole::VERSION
6
+ spec.authors = ["Jon Topper", "Jack Thomas", "Naadir Jeewa"]
7
+ spec.email = ["jon@scalefactory.com", "jack@scalefactory.com", "naadir@scalefactory.com"]
10
8
 
11
- spec.description = 'Used to fetch multiple AWS Role Credential '\
12
- 'Keys using different Session Keys '\
13
- 'and store them securely using Gnome Keyring '\
14
- 'or OSX keychain'
15
- spec.summary = 'Manage AWS STS credentials with MFA'
16
- spec.homepage = 'https://github.com/scalefactory/aws_assume_role'
17
- spec.license = 'MIT'
9
+ spec.description = "Used to fetch multiple AWS Role Credential "\
10
+ "Keys using different Session Keys "\
11
+ "and store them securely using Gnome Keyring "\
12
+ "or OSX keychain"
13
+ spec.summary = "Manage AWS STS credentials with MFA"
14
+ spec.homepage = "https://github.com/scalefactory/aws-assume-role"
15
+ spec.license = "Apache-2.0"
18
16
 
19
17
  spec.files = `git ls-files -z`.split("\x0").reject { |f|
20
18
  f.match(%r{^(test|spec|features)/})
21
19
  }
22
- spec.bindir = 'bin'
20
+ spec.bindir = "bin"
23
21
  spec.executables = spec.files.grep(%r{^bin/aws}) { |f| File.basename(f) }
24
- spec.require_paths = ['lib']
22
+ spec.require_paths = ["lib"]
25
23
 
26
- spec.add_runtime_dependency 'aws-sdk'
27
- spec.add_runtime_dependency 'inifile'
28
- spec.add_runtime_dependency 'keyring', '~> 0.4.1'
24
+ spec.add_runtime_dependency "activesupport", "~> 4.0"
25
+ spec.add_runtime_dependency "aws-sdk", "~> 2.7"
26
+ spec.add_runtime_dependency "dry-configurable", "~> 0.5"
27
+ spec.add_runtime_dependency "dry-initializer", "~> 1.1"
28
+ spec.add_runtime_dependency "dry-types", "~> 0.9"
29
+ spec.add_runtime_dependency "dry-validation", "~> 0.10"
30
+ spec.add_runtime_dependency "gli", "~> 2.15"
31
+ spec.add_runtime_dependency "highline", "~> 1.7"
32
+ spec.add_runtime_dependency "i18n", "~> 0.7"
33
+ spec.add_runtime_dependency "inifile", "~> 3.0"
34
+ spec.add_runtime_dependency "launchy", "~> 2.4"
35
+ spec.add_runtime_dependency "keyring", "~> 0.4", ">= 0.4.1"
36
+ spec.add_runtime_dependency "pastel", "~> 0.7"
37
+ spec.add_development_dependency "rubocop", "~> 0.46"
38
+ spec.add_development_dependency "yard", "~> 0.9"
29
39
 
30
- # spec.add_development_dependency 'bundler', '~> 1.12'
31
- # spec.add_development_dependency 'rake', '~> 10.0'
40
+ case Gem::Platform.local.os
41
+ when "linux"
42
+ spec.add_dependency "gir_ffi-gnome_keyring", "~> 0.0", ">= 0.0.3"
43
+ when "darwin"
44
+ spec.add_dependency "ruby-keychain", "~> 0.3", ">= 0.3.2"
45
+ end
32
46
  end
data/bin/aws-assume-role CHANGED
@@ -1,84 +1,2 @@
1
1
  #!/usr/bin/env ruby
2
-
3
- $LOAD_PATH.unshift File.expand_path('../lib/', __FILE__)
4
-
5
- require 'optparse'
6
- require 'aws_assume_role'
7
-
8
- options = {}
9
- optparse = OptionParser.new do |opts|
10
-
11
- options[:config] = "#{ENV['HOME']}/.aws/assume.yaml"
12
- opts.on('-c', '--config file', 'Config file. defaults to' \
13
- '~/.aws/assume.yaml.') do |c|
14
- options[:config] = c
15
- end
16
-
17
- options[:profile] = false
18
- opts.on('-p', '--profile name', 'Load the credentials for a profile into AWS ' \
19
- 'environment variables.') do |c|
20
- options[:profile] = c
21
- end
22
-
23
- options[:add] = false
24
- opts.on('-a', '--add', 'Add basic/parent account credentials to keystore' \
25
- 'environment variables. Must provide a profile name') do |c|
26
- options[:add] = c
27
- end
28
-
29
- options[:delete] = false
30
- opts.on('-d', '--delete', 'Delete credentials from keystore. Must ' \
31
- 'provide a profile name.') do
32
- options[:delete] = true
33
- end
34
-
35
- options[:debug] = false
36
- opts.on('--debug', 'Enable debugging') do
37
- options[:debug] = true
38
- end
39
-
40
- options[:verbose] = false
41
- opts.on('-v', '--verbose', 'Get more words') do
42
- options[:verbose] = true
43
- end
44
-
45
- end
46
-
47
- optdata = optparse.parse!
48
-
49
- if options[:debug]
50
- AWSAssumeRole::Profile.logger.level = Logger::DEBUG
51
- else
52
- AWSAssumeRole::Profile.logger.level = Logger::WARN
53
- end
54
-
55
-
56
- begin
57
- AWSAssumeRole::Profile.load_profiles
58
- AWSAssumeRole::Profile.load_config_file(options[:config])
59
- rescue Errno::ENOENT
60
- STDERR.puts "No config file at options[:config]. Please create one!"
61
- exit -1 # rubocop:disable Lint/AmbiguousOperator
62
- end
63
-
64
- if options[:profile] != false
65
- profile = AWSAssumeRole::Profile.get_by_name(options[:profile] )
66
-
67
- if options[:delete]
68
- profile.remove
69
- elsif options[:add]
70
- profile.add
71
- else
72
- profile.use
73
- end
74
-
75
- if options[:verbose]
76
- system('env | grep "AWS" | sort')
77
- end
78
- end
79
-
80
- unless optdata.empty?
81
- cmd = optdata.join(' ')
82
- AWSAssumeRole::Profile.logger.debug "Executing Command '#{cmd}'"
83
- system(cmd)
84
- end
2
+ require_relative "../lib/aws_assume_role/cli"
data/i18n/en.yml ADDED
@@ -0,0 +1,106 @@
1
+ en:
2
+ commands:
3
+ configure:
4
+ desc: Configure AWS
5
+ long_desc: |
6
+ Configure AWS profiles. If this command is run with no arguments,
7
+ you will be prompted for configuration values such as your AWS Access
8
+ Key Id and you AWS Secret Access Key. You can configure a named pro-
9
+ file using the --profile argument. If your config file does not exist
10
+ (the default location is ~/.aws/config), the AWS CLI will create it for
11
+ you. To keep an existing value, hit enter when prompted for the value.
12
+ When you are prompted for information, the current value will be dis-
13
+ played in [brackets]. If the config item has no value, it be displayed
14
+ as [None]. Note that the configure command only work with values from
15
+ the config file. It does not use any configuration values from envi-
16
+ ronment variables or the IAM role.
17
+
18
+ Note: The values you provide for the AWS Access Key ID and the AWS
19
+ Secret Access Key will be written to your keyring backend.
20
+ saved: Profile %s saved to %s
21
+ console:
22
+ desc: Launch the AWS console to switch to the profile role.
23
+ long_desc: |
24
+ Looks up the Role ARN in the profile, constructs the AWS console
25
+ URL and launches your browser with it. It's a convenience, doesn't
26
+ use any of the credentials.
27
+ set_environment:
28
+ desc: Export assumed credentials to your shell environment.
29
+ long_desc: |
30
+ Set up environment variables in your shell so that you can run AWS CLI
31
+ or other apps using those credentials without running aws-assume-role
32
+ again.
33
+ Supports Bourne, CSh, Fish and PowerShell.
34
+ shells:
35
+ powershell: Use `aws-assume-role environment set -s powershell -p <profile_name> | Invoke-Expression` to load into environment
36
+ others: Use `eval aws-assume-role environment set -p <profile_name>` to load into environment
37
+ fish: Use `set creds (bin/aws-assume-role environment set -s fish); eval $creds; set -e creds`
38
+ reset_environment:
39
+ desc: Delete AWS environment variables.
40
+ long_desc: |
41
+ Cleans up your shell environment by removing the following environment variables:
42
+ AWS_ACCESS_KEY_ID
43
+ AWS_SECRET_ACCESS_KEY
44
+ AWS_DEFAULT_REGION
45
+ AWS_PROFILE
46
+ AWS_ASSUME_ROLE_LOG_LEVEL
47
+ GLI_DEBUG
48
+ Supports Bourne, CSh, Fish and PowerShell.
49
+ shells:
50
+ powershell: Use `aws-assume-role environment reset -s powershell -p <profile_name> | Invoke-Expression` to load into environment
51
+ others: Use `eval aws-assume-role environment reset -p <profile_name>` to load into environment
52
+ fish: Use `set creds (bin/aws-assume-role environment reset -s fish); eval $creds; set -e creds`
53
+ run:
54
+ desc: Run a program with credentials set in the environment.
55
+ delete:
56
+ desc: Delete a profile
57
+ completed: "Profile %s deleted"
58
+ not_found: "Cannot find profile %s. Try running `aws-assume-role list`"
59
+ list:
60
+ desc: List configured profiles
61
+ migrate:
62
+ desc: Migrate a store to secure storage.
63
+ not_found: "Cannot find profile %s. Try running `aws-assume-role list`"
64
+ saved: Profile %s migrated within %s
65
+ test:
66
+ desc: Check that credentials work
67
+ output: |
68
+ Logged in as:
69
+ User: %s
70
+ Account: %s
71
+ ARN: %s
72
+ options:
73
+ aws_access_key_id: "Enter the AWS Access Key ID to use for this profile"
74
+ aws_secret_access_key: "Enter the AWS Secret Access Key to use for this profile"
75
+ region: Enter the AWS region you would like to default to
76
+ profile_name: Enter the profile name to save into configuration
77
+ mfa_token:
78
+ first_time: "Please provide an MFA token"
79
+ other_times: "Credentials have expired, please provide another MFA"
80
+ default_role: "A default role to assume (leave blank to not use)"
81
+ external_id: String provided by the external account holder to uniquely identify you.
82
+ source_profile: Which profile to use to assume this role.
83
+ role_session_name: Name to uniquely identify your session
84
+ mfa_serial: The identification number of the MFA device. Leave blank to determine dynamically at run time.
85
+ role_arn: The Amazon Resource Name (ARN) of the role to assume.
86
+ duration_seconds: Default session length
87
+ shell_type: What type of shell to use.
88
+ name_to_delete: Please type the name of the profile, i.e. %s , to continue deletion.
89
+ program_description: "A tool for AWS credential management"
90
+ errors:
91
+ NoSuchProfileError: Profile %s not found in shared configuration.
92
+ MissingCredentialsError: No credentials found!
93
+ rules:
94
+ profile:
95
+ filled?: --profile must be specified.
96
+ role-arn:
97
+ format?: "--role-arn must be specified as an ARN in the format `arn:aws:iam::account-id:role/role-name`"
98
+ filled?: --role-arn is required.
99
+ serial-number:
100
+ format?: "--mfa-serial must be specified as an ARN in the format `arn:aws:iam::account-id:mfa/virtual-device-name`"
101
+ filled?: --mfa-serial is required.
102
+ region:
103
+ format?: "--region must be a valid AWS Standard, China or GovCloud region"
104
+ filled?: --region is required
105
+ role_specification:
106
+ filled?: "Either specify --profile OR (--role-arn AND --role-session-name, or neither)"
@@ -1,3 +1,2 @@
1
- require 'aws_assume_role/logging'
2
- require 'aws_assume_role/profile'
3
- require 'aws_assume_role/credentials'
1
+ require_relative "aws_assume_role/store/shared_config_with_keyring"
2
+ require_relative "aws_assume_role/credentials/factories/default_chain_provider"
@@ -0,0 +1,15 @@
1
+ require_relative "includes"
2
+ require_relative "ui"
3
+
4
+ module AwsAssumeRole::Cli
5
+ include GLI::DSL
6
+ include GLI::App
7
+ include AwsAssumeRole
8
+ include AwsAssumeRole::Ui
9
+ extend self # rubocop:disable Style/ModuleFunction
10
+
11
+ commands_from File.join(File.realpath(__dir__), "cli", "commands")
12
+ program_desc t "program_description"
13
+
14
+ exit run(ARGV)
15
+ end
@@ -0,0 +1,53 @@
1
+ require_relative "includes"
2
+ require_relative "../../profile_configuration"
3
+
4
+ class AwsAssumeRole::Cli::Actions::AbstractAction
5
+ include AwsAssumeRole
6
+ include AwsAssumeRole::Types
7
+ include Ui
8
+ CommandSchema = proc { raise "CommandSchema Not implemented" }
9
+
10
+ def initialize(global_options, options, args)
11
+ config = ProfileConfiguration.new_from_cli(global_options, options, args)
12
+ result = validate_options(config.to_h.deep_symbolize_keys)
13
+ return act_on(config) if result.success?
14
+ Ui.show_validation_errors result
15
+ end
16
+
17
+ private
18
+
19
+ def try_for_credentials(config)
20
+ @provider ||= AwsAssumeRole::Credentials::Factories::DefaultChainProvider.new(config.to_h)
21
+ creds = @provider.resolve(nil_with_role_not_set: true)
22
+ return creds unless creds.nil?
23
+ rescue NoMethodError
24
+ error "Cannot find any credentials"
25
+ exit 404
26
+ end
27
+
28
+ def resolved_region
29
+ @provider.region
30
+ end
31
+
32
+ def resolved_profile
33
+ @provider.profile
34
+ end
35
+
36
+ def validate_options(options)
37
+ command_schema = self.class::CommandSchema
38
+ ::Dry::Validation.Schema do
39
+ configure { config.messages = :i18n }
40
+ instance_eval(&command_schema)
41
+ end.call(options)
42
+ end
43
+
44
+ def prompt_for_option(key, option_name, validator, fmt: nil)
45
+ text_lookup = t("options.#{key}")
46
+ text = fmt.nil? ? text_lookup : format(text_lookup, fmt)
47
+ Ui.ask_with_validation(option_name, text) { instance_eval(&validator) }
48
+ end
49
+
50
+ def act_on(_options)
51
+ raise "Act On Not Implemented"
52
+ end
53
+ end
@@ -0,0 +1,21 @@
1
+ require_relative "abstract_action"
2
+ require_relative "../../store/shared_config_with_keyring"
3
+
4
+ class AwsAssumeRole::Cli::Actions::ConfigureProfile < AwsAssumeRole::Cli::Actions::AbstractAction
5
+ CommandSchema = proc do
6
+ required(:profile)
7
+ optional(:region) { filled? > format?(REGION_REGEX) }
8
+ optional(:mfa_serial)
9
+ optional(:profile_name)
10
+ end
11
+
12
+ def act_on(config)
13
+ new_hash = config.to_h
14
+ profile = config.profile || prompt_for_option(:profile_name, "profile", proc { filled? })
15
+ new_hash[:region] = prompt_for_option(:region, "region", proc { filled? > format?(REGION_REGEX) })
16
+ new_hash[:aws_access_key_id] = prompt_for_option(:aws_access_key_id, "aws_access_key_id", ACCESS_KEY_VALIDATOR)
17
+ new_hash[:aws_secret_access_key] = prompt_for_option(:aws_secret_access_key, "aws_secret_access_key", proc { filled? })
18
+ AwsAssumeRole.shared_config.save_profile(profile, new_hash)
19
+ out format(t("commands.configure.saved"), config.profile, AwsAssumeRole.shared_config.config_path)
20
+ end
21
+ end
@@ -0,0 +1,19 @@
1
+ require_relative "abstract_action"
2
+
3
+ class AwsAssumeRole::Cli::Actions::ConfigureRoleAssumption < AwsAssumeRole::Cli::Actions::AbstractAction
4
+ CommandSchema = proc do
5
+ required(:profile)
6
+ required(:source_profile) { str? }
7
+ optional(:region) { filled? > format?(REGION_REGEX) }
8
+ optional(:serial_number) { filled? > format?(MFA_REGEX) }
9
+ required(:role_session_name).filled?
10
+ required(:role_arn) { filled? & format?(ROLE_REGEX) }
11
+ required(:external_id).filled?
12
+ required(:duration_seconds).filled?
13
+ end
14
+
15
+ def act_on(config)
16
+ AwsAssumeRole.shared_config.save_profile(config.profile, config.to_h.compact)
17
+ out format(t("commands.configure.saved"), config.profile, AwsAssumeRole.shared_config.config_path)
18
+ end
19
+ end
@@ -0,0 +1,68 @@
1
+ require_relative "includes"
2
+ require_relative "../../runner"
3
+ require "cgi"
4
+ require "json"
5
+
6
+ class AwsAssumeRole::Cli::Actions::Console < AwsAssumeRole::Cli::Actions::AbstractAction
7
+ include AwsAssumeRole::Ui
8
+ include AwsAssumeRole::Logging
9
+
10
+ FEDERATION_URL = "https://signin.aws.amazon.com/federation".freeze
11
+ CONSOLE_URL = "https://console.aws.amazon.com".freeze
12
+ GENERIC_SIGNIN_URL = "https://signin.aws.amazon.com/console".freeze
13
+ SIGNIN_URL = [FEDERATION_URL, "?Action=getSigninToken", "&Session=%s"].join
14
+ LOGIN_URL = [FEDERATION_URL, "?Action=login", "&Destination=%s", "&SigninToken=%s"].join
15
+
16
+ CommandSchema = proc do
17
+ required(:profile).maybe
18
+ optional(:region) { filled? > format?(REGION_REGEX) }
19
+ optional(:serial_number) { filled? > format?(MFA_REGEX) }
20
+ required(:role_arn).maybe
21
+ required(:role_session_name).maybe
22
+ required(:duration_seconds).maybe
23
+ rule(role_specification: [:profile, :role_arn, :role_session_name, :duration_seconds]) do |p, r, s, d|
24
+ (p.filled? | p.empty? & r.filled?) & (r.filled? > s.filled? & d.filled?)
25
+ end
26
+ end
27
+
28
+ def try_federation(config)
29
+ credentials = try_for_credentials config.to_h
30
+ return unless credentials.set?
31
+ session = session_json(credentials)
32
+ signin_url = format SIGNIN_URL, CGI.escape(session)
33
+ sso_token = JSON.parse(URI.parse(signin_url).read)["SigninToken"]
34
+ format LOGIN_URL, CGI.escape(CONSOLE_URL), CGI.escape(sso_token)
35
+ rescue OpenURI::HTTPError
36
+ error "Error getting federated session, forming simple switch URL instead"
37
+ end
38
+
39
+ def session_json(credentials)
40
+ {
41
+ sessionId: credentials.credentials.access_key_id,
42
+ sessionKey: credentials.credentials.secret_access_key,
43
+ sessionToken: credentials.credentials.session_token,
44
+ }.to_json
45
+ end
46
+
47
+ def try_switch_url(config)
48
+ profile = AwsAssumeRole.shared_config.determine_profile(profile_name: config.profile)
49
+ config_section = AwsAssumeRole.shared_config.parsed_config[profile]
50
+ raise Aws::Errors::NoSuchProfileError if config_section.nil?
51
+ resolved_role_arn = config.role_arn || config_section.fetch("role_arn", nil)
52
+ return unless resolved_role_arn
53
+ components = resolved_role_arn.split(":")
54
+ account = components[4]
55
+ role = components[5].split("/").last
56
+ display_name = config.profile || "#{account}_#{role}"
57
+ format "https://signin.aws.amazon.com/switchrole?account=%s&roleName=%s&displayName=%s", account, role, display_name
58
+ end
59
+
60
+ def act_on(config)
61
+ final_url = try_federation(config) || try_switch_url(config) || CONSOLE_URL
62
+ Launchy.open final_url
63
+ rescue KeyError, Aws::Errors::NoSuchProfileError
64
+ error format(t("errors.NoSuchProfileError"), config.profile)
65
+ rescue Aws::Errors::MissingCredentialsError
66
+ error t("errors.MissingCredentialsError")
67
+ end
68
+ end