awsudo 1.0.1 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
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