awsudo 1.0.1 → 2.0.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8e4b45a3d628800167e5024b822807b35157daa3
4
- data.tar.gz: 6d4ba8e55a5795fa72b89f1c4e4d9aa4212a3da5
3
+ metadata.gz: 55636d46f188efba965077b306ccd5c99df46923
4
+ data.tar.gz: dcec6bd5c2684851a1d6c010882658fd6d270b43
5
5
  SHA512:
6
- metadata.gz: 18fe20ae36c9fb52041fa179880bba1131ba220f87d50955f4befc8d1a6bc3d03b7bda06e7f353613e2e39c2a47326196f7d0bf8f82eead9eaa94d24e3d15271
7
- data.tar.gz: e1d3e25b4cd51d0494a99f0fd772f499704deefb3f25340a89fa8e28e2a17823450e823a267b78b385b349696a356d0fe46dfecc385dd1ee119126c55db82686
6
+ metadata.gz: 942140a15481c643d3a8ee3dd95ba492cd2a4f6aedcd329b3ff98a4bb4f0c94a2799943da35321558b472768cc8fe968bc53eea211d8a4d7c3a2e363920cabb9
7
+ data.tar.gz: 3c6b0b2f230b8c4cbd97e44dc5ed597d1214038d93a004d724c20790a0194fabd91412f3b3aa981630fa18f28d9685e30d476d3780b279a80db2a6175870e4a5
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (C) 2015 Electronic Arts Inc. All rights reserved.
1
+ Copyright (C) 2015-2017 Electronic Arts Inc. All rights reserved.
2
2
 
3
3
  Redistribution and use in source and binary forms, with or without
4
4
  modification, are permitted provided that the following conditions
data/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  awsudo + aws-agent
2
2
  ==================
3
3
 
4
+ [![Build Status](https://travis-ci.org/electronicarts/awsudo.svg?branch=master)](https://travis-ci.org/electronicarts/awsudo)
5
+
4
6
  Overview
5
7
  ------------
6
8
 
@@ -15,17 +17,17 @@ to use.
15
17
  Synopsis
16
18
  ------------
17
19
 
18
- awsudo {role-name | role-arn} command
20
+ awsudo {role-name | role-arn} command
19
21
 
20
- aws-agent
22
+ aws-agent
21
23
 
22
24
  Requirements
23
25
  ------------
24
26
 
25
27
  * UNIX, UNIX-like or GNU/Linux operating system
26
28
  * SAML compliant federation service
27
- * ruby 1.9 or above
28
- * ruby gems: aws-sdk
29
+ * ruby 2.1 or above
30
+ * rubygems: aws-sdk, nokogiri
29
31
 
30
32
  Install
31
33
  ------------
@@ -37,33 +39,43 @@ Configuration
37
39
 
38
40
  awsudo and aws-agent expect a configuration file named .awsudo in your home directory
39
41
  containing the values for your identity provider login url and the SAML provider name
40
- configured in AWS. This is an example, your setup may vary:
42
+ configured in AWS.
43
+
44
+ Example for AD FS:
45
+
46
+ IDP = adfs
47
+ IDP_LOGIN_URL = https://sts.example.com/adfs/ls/IdpInitiatedSignOn.aspx?loginToRp=urn:amazon:webservices
48
+ SAML_PROVIDER_NAME = adfs
41
49
 
42
- IDP_LOGIN_URL = https://sts.example.com/adfs/ls/IdpInitiatedSignOn.aspx?loginToRp=urn:amazon:webservices
43
- SAML_PROVIDER_NAME = ADFS
50
+ Example for Okta:
51
+
52
+ IDP = okta
53
+ IDP_LOGIN_URL = https://example.okta.com/app/example/abc123/sso/saml
54
+ SAML_PROVIDER_NAME = okta
55
+ API_ENDPOINT = https://example.okta.com/api/v1
44
56
 
45
57
  In addition to .awsudo, you can create .aws-roles in your home directory to map
46
58
  IAM roles ARNs to more easy to remember alias names, one per line, separated by spaces. Example:
47
59
 
48
- myaccount-admin arn:aws:iam::123456789012:role/myaccount-admin
60
+ myaccount-admin arn:aws:iam::123456789012:role/myaccount-admin
49
61
 
50
62
  Examples
51
63
  ------------
52
64
 
53
65
  ### awsudo
54
66
 
55
- $ awsudo arn:aws:iam::123456789012:role/myaccount-admin aws ec2 describe-tags --region us-west-2
56
-
57
- $ awsudo myaccount-admin aws ec2 describe-instances --region us-east-1
67
+ $ awsudo arn:aws:iam::123456789012:role/myaccount-admin aws ec2 describe-tags --region us-west-2
68
+
69
+ $ awsudo myaccount-admin aws ec2 describe-instances --region us-east-1
58
70
 
59
71
  awsudo will ask your federated credentials every time. To avoid this use aws-agent as follows:
60
72
 
61
73
  ### aws-agent
62
74
 
63
- $ aws-agent
64
- Login: username
65
- Password:
66
- AWS_AUTH_SOCK=/var/folders/xz/lx178g0d0rb36x95446zwgd80000gp/T/aws-20150623-20990-58v1c4/agent; export AWS_AUTH_SOCK;
75
+ $ aws-agent
76
+ Login: username
77
+ Password:
78
+ AWS_AUTH_SOCK=/var/folders/xz/lx178g0d0rb36x95446zwgd80000gp/T/aws-20150623-20990-58v1c4/agent; export AWS_AUTH_SOCK;
67
79
 
68
80
  then execute the commands printed by aws-agent. awsudo will now ask for temporary credentials to aws-agent.
69
81
 
@@ -1,11 +1,12 @@
1
1
  #!/usr/bin/env ruby
2
- # Copyright (C) 2015 Electronic Arts Inc. All rights reserved.
2
+ # Copyright (C) 2015-2017 Electronic Arts Inc. All rights reserved.
3
3
 
4
- require 'awsudo'
5
4
  require 'logger'
6
5
  require 'socket'
7
6
  require 'tmpdir'
8
7
 
8
+ require 'awsudo'
9
+
9
10
  def usage
10
11
  warn <<EOS
11
12
  Usage:
@@ -15,36 +16,48 @@ EOS
15
16
  exit 1
16
17
  end
17
18
 
18
- config = Hash[*File.read(File.join(ENV['HOME'], '.awsudo')).
19
- scan(/^(\w+)\s*=\s*(.*)$/).flatten]
20
- AWSUDO.config(config['IDP_LOGIN_URL'], config['SAML_PROVIDER_NAME'])
19
+ LOG_FILENAME = File.join(ENV['HOME'], ".aws-agent.log")
20
+ CONFIG_FILENAME = File.join(ENV['HOME'], '.awsudo')
21
+ SUPPORTED_IDPS = AWSUDO::IdentityProviders.constants
21
22
 
22
- LOGFILE = File.join(ENV['HOME'], ".aws-agent.log")
23
- logger = Logger.new(LOGFILE, "weekly")
23
+ logger = Logger.new(LOG_FILENAME, "weekly")
24
24
  logger.progname = "aws-agent"
25
25
  logger.level = Logger::WARN
26
26
 
27
- username, password = AWSUDO.get_federated_credentials
27
+ config = AWSUDO.load_config(CONFIG_FILENAME)
28
+ idpname = config['IDP'].to_s.capitalize.to_sym
29
+ unless SUPPORTED_IDPS.include?(idpname)
30
+ warn "`#{config['IDP']}' is not a supported identity provider"
31
+ exit 4
32
+ end
33
+ username, password = AWSUDO.ask_for_credentials
34
+ idp = AWSUDO::IdentityProviders.new(idpname, config, username, password)
35
+ idp.logger = logger
28
36
 
29
37
  socket_dir = Dir.mktmpdir("aws-")
30
38
  socket_name = File.join(socket_dir, "agent")
31
- puts "AWS_AUTH_SOCK=#{socket_name}; export AWS_AUTH_SOCK;"
39
+
40
+ case ENV['SHELL'].split('/').last
41
+ when 'csh', 'tcsh'
42
+ puts "setenv AWS_AUTH_SOCK #{socket_name}"
43
+ when 'fish'
44
+ puts "set -gx AWS_AUTH_SOCK #{socket_name}"
45
+ else
46
+ puts "AWS_AUTH_SOCK=#{socket_name}; export AWS_AUTH_SOCK;"
47
+ end
48
+
32
49
  Process.daemon
33
50
  $0 = 'aws-agent'
34
51
  Process.setrlimit(Process::RLIMIT_CORE, 0, 0)
35
52
  UNIXServer.open(socket_name) do |socket|
36
53
  loop do
37
54
  Thread.new(socket.accept) do |client|
38
- logger.debug "thread started"
39
- logger.debug "connection accepted: #{socket.inspect}"
55
+ logger.debug "Thread started"
56
+ logger.debug {"connection accepted: #{socket.inspect}"}
40
57
  begin
41
- role = client.gets.strip
42
- logger.debug "role received: #{role}"
43
- role_arn = AWSUDO.resolve_role(role)
44
- logger.debug "role ARN resolved: #{role_arn}"
45
- saml_assertion = AWSUDO.get_saml_assertion(username, password)
46
- credentials = AWSUDO.assume_role_with_saml(saml_assertion, role_arn)
47
- client.puts credentials.to_h.to_json
58
+ role_arn = client.gets.strip
59
+ logger.debug {"role ARN received: #{role_arn}"}
60
+ client.puts idp.assume_role(role_arn).to_json
48
61
  rescue => e
49
62
  logger.error e
50
63
  error = {:error => e}.to_json
data/bin/awsudo CHANGED
@@ -1,8 +1,13 @@
1
1
  #!/usr/bin/env ruby
2
- # Copyright (C) 2015 Electronic Arts Inc. All rights reserved.
2
+ # Copyright (C) 2015-2017 Electronic Arts Inc. All rights reserved.
3
3
 
4
4
  require 'awsudo'
5
5
 
6
+ CONFIG_FILENAME = File.join(ENV['HOME'], '.awsudo')
7
+ ROLES_FILENAME = File.join(ENV['HOME'], '.aws-roles')
8
+ SOCKETNAME = ENV['AWS_AUTH_SOCK']
9
+ SUPPORTED_IDPS = AWSUDO::IdentityProviders.constants
10
+
6
11
  def usage
7
12
  warn <<-EOS
8
13
  Usage:
@@ -12,23 +17,49 @@ Usage:
12
17
  exit 1
13
18
  end
14
19
 
15
- usage if ARGV.size < 2
20
+ def find_role_arn(rolename)
21
+ return nil if rolename =~ /\s/ || rolename.empty?
22
+ line = File.readlines(ROLES_FILENAME).find do |line|
23
+ line =~ /^#{rolename}\s+arn:aws:iam::\d+:role\/\S+\s*$/
24
+ end
25
+ return nil if line.nil?
26
+ arn = line.split(/\s+/)[1]
27
+ arn
28
+ end
16
29
 
17
- config = Hash[*File.read(File.join(ENV['HOME'], '.awsudo')).
18
- scan(/^(\w+)\s*=\s*(.*)$/).flatten]
19
- AWSUDO.config(config['IDP_LOGIN_URL'], config['SAML_PROVIDER_NAME'])
30
+ def cuddle
31
+ begin; yield; rescue; warn $!; end
32
+ end
33
+
34
+ usage if ARGV.size < 2
20
35
 
21
36
  role = ARGV.shift
22
- credentials =
23
- begin
24
- AWSUDO.assume_role(role)
25
- rescue => e
26
- warn e
27
- exit 2
37
+ role_arn = role =~ /^arn:aws:iam::\d+:role\/\S+$/ ? role : find_role_arn(role)
38
+
39
+ if role_arn.nil?
40
+ warn "`#{role}' is not a valid role"
41
+ exit 2
42
+ end
43
+
44
+ keys = cuddle do
45
+ AWSUDO.assume_role_with_agent(role_arn, SOCKETNAME) unless SOCKETNAME.nil?
46
+ end || cuddle do
47
+ config = AWSUDO.load_config(CONFIG_FILENAME)
48
+ idpname = config['IDP'].to_s.capitalize.to_sym
49
+ unless SUPPORTED_IDPS.include?(idpname)
50
+ raise "`#{config['IDP']}' is not a supported identity provider"
28
51
  end
29
52
 
30
- ENV['AWS_ACCESS_KEY_ID'] = credentials['access_key_id'] || credentials[:access_key_id]
31
- ENV['AWS_SECRET_ACCESS_KEY'] = credentials['secret_access_key'] || credentials[:secret_access_key]
32
- ENV['AWS_SESSION_TOKEN'] = credentials['session_token'] || credentials[:session_token]
53
+ username, password = AWSUDO.ask_for_credentials
54
+ idp = AWSUDO::IdentityProviders.new(idpname, config, username, password)
55
+ idp.assume_role(role_arn)
56
+ end || exit(3)
57
+
58
+ %w(access_key_id secret_access_key session_token).each do |keyname|
59
+ ENV['AWS_' + keyname.upcase] = keys[keyname] || keys[keyname.to_sym]
60
+ end
61
+
62
+ # for boto2
63
+ ENV['AWS_SECURITY_TOKEN'] = keys['session_token'] || keys[:session_token]
33
64
 
34
- exec *ARGV if ARGV.size > 0
65
+ cuddle { exec *ARGV if ARGV.size > 0 }
@@ -1,27 +1,35 @@
1
- # Copyright (C) 2015 Electronic Arts Inc. All rights reserved.
1
+ # Copyright (C) 2015-2017 Electronic Arts Inc. All rights reserved.
2
2
 
3
- require 'aws-sdk'
4
3
  require 'io/console'
5
4
  require 'json'
6
- require 'net/http'
7
- require 'net/https'
8
- require 'rexml/document'
5
+ require 'logger'
9
6
  require 'socket'
10
7
  require 'uri'
11
8
 
12
9
  module AWSUDO
13
- AWS_ROLES = File.join(ENV['HOME'], '.aws-roles')
10
+ @logger = Logger.new(STDERR)
11
+ @logger.level = Logger::WARN
14
12
 
15
13
  class << self
16
- attr_reader :idp_login_url, :saml_provider_name
14
+ attr_accessor :logger
17
15
  end
18
16
 
19
- def self.config(idp_login_url, saml_provider_name)
20
- @idp_login_url = idp_login_url
21
- @saml_provider_name = saml_provider_name
17
+ def self.assume_role_with_agent(role_arn, socket_name)
18
+ logger.debug {"role_arn: <#{role_arn}>"}
19
+ logger.debug {"socket_name: <#{socket_name}>"}
20
+ keys = UNIXSocket.open(socket_name) do |client|
21
+ client.puts role_arn
22
+ response = client.gets
23
+ logger.debug {"response: <#{response}>"}
24
+ raise "Connection closed by peer" if response.nil?
25
+ JSON.parse(response.strip)
26
+ end
27
+
28
+ raise keys['error'] unless keys['error'].nil?
29
+ keys
22
30
  end
23
31
 
24
- def self.get_federated_credentials
32
+ def self.ask_for_credentials
25
33
  fd = IO.sysopen("/dev/tty", "w")
26
34
  console = IO.new(fd,"w")
27
35
  console.print "Login: "
@@ -32,70 +40,11 @@ module AWSUDO
32
40
  [username, password]
33
41
  end
34
42
 
35
- def self.assume_role_using_agent(role)
36
- socket_name = ENV['AWS_AUTH_SOCK']
37
- credentials = UNIXSocket.open(socket_name) do |client|
38
- client.puts role
39
- response = client.gets
40
- raise "Connection closed by peer" if response.nil?
41
- JSON.parse(response.strip)
42
- end
43
-
44
- raise credentials['error'] if credentials['error']
45
- credentials
46
- end
47
-
48
- def self.assume_role_using_password(role)
49
- username, password = get_federated_credentials
50
- saml_assertion = get_saml_assertion(username, password)
51
- role_arn = resolve_role(role)
52
- assume_role_with_saml(saml_assertion, role_arn).to_h
53
- end
54
-
55
- def self.assume_role(role)
56
- assume_role_using_agent(role) rescue assume_role_using_password(role)
57
- end
58
-
59
- def self.get_saml_assertion(username, password)
60
- uri = URI.parse(idp_login_url)
61
-
62
- http = Net::HTTP.new(uri.host, uri.port)
63
- http.use_ssl = true
64
- http.verify_mode = OpenSSL::SSL::VERIFY_PEER
65
-
66
- req = Net::HTTP::Post.new(uri.request_uri)
67
- req.set_form_data({'username' => username, 'password' => password})
68
- res = http.request(req)
69
-
70
- raise "Authentication failed" if res['Location'].nil?
71
- uri = URI.parse(res['Location'])
72
- req = Net::HTTP::Get.new(uri.request_uri)
73
- req['Cookie'] = res['Set-Cookie']
74
- http = Net::HTTP.new(uri.host, uri.port)
75
- http.use_ssl = true
76
- http.verify_mode = OpenSSL::SSL::VERIFY_PEER
77
- res = http.request(req)
78
-
79
- doc = REXML::Document.new(res.body)
80
- REXML::XPath.first(doc, '/html/body/form/input[@name = "SAMLResponse"]/@value').to_s
81
- end
82
-
83
- def self.assume_role_with_saml(saml_assertion, role_arn)
84
- principal_arn = "#{role_arn[/^arn:aws:iam::\d+:/]}saml-provider/#{saml_provider_name}"
85
- sts = Aws::STS::Client.new(credentials: Aws::Credentials.new('a', 'b', 'c'), region: 'us-east-1')
86
- sts.assume_role_with_saml(
87
- role_arn: role_arn,
88
- principal_arn: principal_arn,
89
- saml_assertion: saml_assertion).credentials
90
- end
91
-
92
- def self.resolve_role(role, roles_filename = AWS_ROLES)
93
- return role if role =~ /^arn:aws:iam::\d+:role\/\S+$/
94
- raise "`#{role}' is not a valid role" if role =~ /\s/
95
- line = File.readlines(roles_filename).find {|line| line =~ /^#{role}\s+arn:aws:iam::\d+:role\/\S+\s*$/ }
96
- raise "`#{role}' is not a valid role" if line.nil?
97
- role_arn = line.split(/\s+/)[1]
98
- raise "`#{role}' is not a valid role" if role_arn.nil?
99
- role_arn
43
+ def self.load_config(filename)
44
+ config = Hash[*File.read(filename).scan(/^\s*(\w+)\s*=\s*(.*)\s*$/).flatten]
45
+ logger.debug { "config: <#{config.inspect}>" }
46
+ config
100
47
  end
101
48
  end
49
+
50
+ require 'awsudo/identity_providers'
@@ -0,0 +1,91 @@
1
+ # Copyright (C) 2015-2017 Electronic Arts Inc. All rights reserved.
2
+
3
+ require 'aws-sdk'
4
+ require 'base64'
5
+ require 'net/http'
6
+ require 'net/https'
7
+ require 'nokogiri'
8
+ require 'uri'
9
+
10
+ require 'awsudo'
11
+
12
+ module AWSUDO
13
+ class IdentityProvider
14
+ attr_accessor :idp_login_url, :saml_provider_name
15
+ attr_accessor :username, :password, :logger
16
+
17
+ def self.sts
18
+ return @sts unless @sts.nil?
19
+ @sts = Aws::STS::Client.new(
20
+ credentials: Aws::Credentials.new('a', 'b', 'c'),
21
+ region: 'us-east-1')
22
+ end
23
+
24
+ def self.new_from_config(config, username, password)
25
+ new(config['IDP_LOGIN_URL'], config['SAML_PROVIDER_NAME'],
26
+ username, password)
27
+ end
28
+
29
+ def initialize(url, name, username, password)
30
+ @idp_login_url = url
31
+ @saml_provider_name = name
32
+ @username = username
33
+ @password = password
34
+ @logger = AWSUDO.logger
35
+ begin
36
+ URI.parse @idp_login_url
37
+ rescue
38
+ raise "`#{@idp_login_url.inspect}' is not a valid IDP login URL"
39
+ end
40
+ if @saml_provider_name.nil? || @saml_provider_name.strip.empty?
41
+ raise "`#{@saml_provider_name.inspect}' is not a valid SAML provider name"
42
+ end
43
+ end
44
+
45
+ def saml_request
46
+ raise "should be implemented by subclass"
47
+ end
48
+
49
+ def get_saml_response
50
+ req = saml_request
51
+ res = nil
52
+ uri = URI.parse(idp_login_url)
53
+
54
+ loop do
55
+ http = Net::HTTP.new(uri.host, uri.port)
56
+ http.use_ssl = true
57
+ http.verify_mode = OpenSSL::SSL::VERIFY_PEER
58
+
59
+ res = http.request(req)
60
+ logger.debug {"Location: <#{res['Location']}>"}
61
+ logger.debug {"Headers: <#{res.to_hash.inspect}>"}
62
+ logger.debug {"Body: <#{res.body.inspect}>"}
63
+
64
+ break if res['Location'].nil?
65
+
66
+ uri = URI.parse(res['Location'])
67
+ req = Net::HTTP::Get.new(uri.request_uri)
68
+ req['Cookie'] = res['Set-Cookie']
69
+ end
70
+
71
+ doc = Nokogiri::HTML(res.body)
72
+ doc.xpath('/html/body//form/input[@name = "SAMLResponse"]/@value').to_s
73
+ end
74
+
75
+ def assume_role(role_arn)
76
+ logger.debug {"role_arn: <#{role_arn}>"}
77
+ base_arn = role_arn[/^arn:aws:iam::\d+:/]
78
+ principal_arn = "#{base_arn}saml-provider/#{saml_provider_name}"
79
+ logger.debug {"principal_arn: <#{principal_arn}>"}
80
+ saml_assertion = get_saml_response
81
+ logger.debug {"saml_assertion: <#{Base64.decode64 saml_assertion}>"}
82
+ if saml_assertion.empty?
83
+ raise 'Unable to get SAML assertion (failed authentication?)'
84
+ end
85
+ self.class.sts.assume_role_with_saml(
86
+ role_arn: role_arn,
87
+ principal_arn: principal_arn,
88
+ saml_assertion: saml_assertion).credentials.to_h
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,12 @@
1
+ # Copyright (C) 2015-2017 Electronic Arts Inc. All rights reserved.
2
+
3
+ module AWSUDO
4
+ module IdentityProviders
5
+ def self.new(idpname, config, username, password)
6
+ self.const_get(idpname).new_from_config(config, username, password)
7
+ end
8
+ end
9
+ end
10
+
11
+ require 'awsudo/identity_providers/adfs.rb'
12
+ require 'awsudo/identity_providers/okta.rb'
@@ -0,0 +1,16 @@
1
+ # Copyright (C) 2015-2017 Electronic Arts Inc. All rights reserved.
2
+
3
+ require 'awsudo/identity_provider'
4
+
5
+ module AWSUDO
6
+ module IdentityProviders
7
+ class Adfs < IdentityProvider
8
+ def saml_request
9
+ uri = URI.parse(idp_login_url)
10
+ req = Net::HTTP::Post.new(uri.request_uri)
11
+ req.set_form_data({'username' => username, 'password' => password})
12
+ req
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,69 @@
1
+ # Copyright (C) 2015-2017 Electronic Arts Inc. All rights reserved.
2
+
3
+ require 'awsudo/identity_provider'
4
+
5
+ module AWSUDO
6
+ module IdentityProviders
7
+ class Okta < IdentityProvider
8
+ attr_accessor :api_endpoint
9
+
10
+ def self.new_from_config(config, username, password)
11
+ new(config['IDP_LOGIN_URL'], config['SAML_PROVIDER_NAME'],
12
+ config['API_ENDPOINT'], username, password)
13
+ end
14
+
15
+ def initialize(url, name, endpoint, username, password)
16
+ super(url, name, username, password)
17
+ @api_endpoint = endpoint
18
+ logger.debug "api_endpoint: <#{@api_endpoint}>"
19
+ begin
20
+ URI.parse(@api_endpoint)
21
+ rescue
22
+ raise "`#{@api_endpoint.inspect}' is not a valid API endpoint"
23
+ end
24
+ end
25
+
26
+ def authenticate
27
+ payload = {
28
+ 'username' => username,
29
+ 'password' => password,
30
+ 'options' => {
31
+ 'multiOptionalFactorEnroll' => false,
32
+ 'warnBeforePasswordExpired' => false
33
+ }
34
+ }.to_json
35
+ uri = URI.parse(api_endpoint + '/authn')
36
+ http = Net::HTTP.new(uri.host, uri.port)
37
+ http.use_ssl = true
38
+ http.verify_mode = OpenSSL::SSL::VERIFY_PEER
39
+
40
+ req = Net::HTTP::Post.new(uri.request_uri)
41
+ req.content_type = 'application/json'
42
+ req['Accept'] = 'application/json'
43
+ req.body = payload
44
+ logger.debug {"payload: <#{req.body.inspect}>"}
45
+ res = http.request(req)
46
+ logger.debug {"Headers: <#{res.to_hash.inspect}>"}
47
+ logger.debug {"Body: <#{res.body.inspect}>"}
48
+ result = JSON.parse(res.body)
49
+
50
+ case result['status']
51
+ when 'SUCCESS'
52
+ return result['sessionToken']
53
+ when 'MFA_REQUIRED'
54
+ raise 'MFA required'
55
+ else
56
+ raise 'Authentication failed'
57
+ end
58
+ end
59
+
60
+ def saml_request
61
+ session_token = authenticate
62
+ uri = URI.parse(idp_login_url)
63
+ req = Net::HTTP::Post.new(uri.request_uri)
64
+ req.set_form_data({'onetimetoken' => session_token})
65
+ req
66
+ end
67
+ end
68
+ end
69
+ end
metadata CHANGED
@@ -1,29 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: awsudo
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gerardo Santana Gomez Garrido
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-02-12 00:00:00.000000000 Z
11
+ date: 2017-04-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ~>
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
19
  version: '2'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ~>
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '2'
27
+ - !ruby/object:Gem::Dependency
28
+ name: nokogiri
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.7'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.7'
27
41
  description: |
28
42
  awsudo enables users to execute commands that make API calls to AWS under the
29
43
  security context of an IAM role. The IAM role is assumed only upon successful
@@ -39,15 +53,20 @@ executables:
39
53
  extensions: []
40
54
  extra_rdoc_files: []
41
55
  files:
42
- - bin/aws-agent
43
- - bin/awsudo
44
- - lib/awsudo.rb
45
- - LICENSE
46
56
  - CHANGELOG.md
47
57
  - CONTRIBUTING.md
58
+ - LICENSE
48
59
  - README.md
60
+ - bin/aws-agent
61
+ - bin/awsudo
62
+ - lib/awsudo.rb
63
+ - lib/awsudo/identity_provider.rb
64
+ - lib/awsudo/identity_providers.rb
65
+ - lib/awsudo/identity_providers/adfs.rb
66
+ - lib/awsudo/identity_providers/okta.rb
49
67
  homepage: https://github.com/electronicarts/awsudo
50
- licenses: []
68
+ licenses:
69
+ - BSD-3-Clause
51
70
  metadata: {}
52
71
  post_install_message:
53
72
  rdoc_options: []
@@ -55,17 +74,17 @@ require_paths:
55
74
  - lib
56
75
  required_ruby_version: !ruby/object:Gem::Requirement
57
76
  requirements:
58
- - - '>='
77
+ - - ">="
59
78
  - !ruby/object:Gem::Version
60
79
  version: '0'
61
80
  required_rubygems_version: !ruby/object:Gem::Requirement
62
81
  requirements:
63
- - - '>='
82
+ - - ">="
64
83
  - !ruby/object:Gem::Version
65
84
  version: '0'
66
85
  requirements: []
67
86
  rubyforge_project:
68
- rubygems_version: 2.0.14
87
+ rubygems_version: 2.6.11
69
88
  signing_key:
70
89
  specification_version: 4
71
90
  summary: executes a command with the permissions given by an AWS IAM role