class CredSummoner::Okta::User
Attributes
username[R]
Public Class Methods
new(username, &blk)
click to toggle source
# File lib/credsummoner/okta/user.rb, line 10 def initialize(username, &blk) @username = username @get_creds = blk.to_proc end
Public Instance Methods
assume_role(role, duration, region)
click to toggle source
# File lib/credsummoner/okta/user.rb, line 110 def assume_role(role, duration, region) role.assume(saml_assertion, duration, region) end
role_map()
click to toggle source
# File lib/credsummoner/okta/user.rb, line 40 def role_map @role_map ||= begin # Two things can happen on this sign-in page: # # 1) The user only has access to a single role in a single # account, in which case they are redirected straight to the # console for that account + role # # 2) The user has access to more than one role in one or more # accounts, in which case they are presented with a page that # lists all accounts and roles for them to choose from. # # For case #1, the response body will be the empty string and # the set-cookie header will contain the account + role # information and we will parse that. # # For case #2, the response body will be scraped for all the # account + role information. # # In both cases we return a hash table mapping accounts to # roles. response = Web.post_form('https://signin.aws.amazon.com/saml', SAMLResponse: saml_assertion.response, RelayState: '') if response.body.empty? cookie = response.get_fields('set-cookie').each_with_object({}) do |field, h| key, value = field.split('; ')[0].split('=') h[key] = value end user_info = JSON.parse(URI.unescape(cookie['aws-userInfo'])) split_arn = user_info['arn'].split('/') role_name = split_arn[1] account_id = split_arn[0].split(':')[4] role_arn = "arn:aws:iam::#{account_id}:role/#{role_name}" account = Account.new(user_info['alias'], account_id) role = Role.new( name: role_name, arn: role_arn, principal_arn: saml_assertion.principal_arn_map[role_arn] ) { account => [role] } else # Time for a little web scraping. Create an account -> roles mapping # so that we can present the user with a list of roles to choose from. role_page = response.body html = Nokogiri::HTML(role_page) accounts = html.css('div[class=saml-account-name]').map do |node| # example account text we are parsing: # Account: maestro-staging (774082247212) parts = node.text.split(' ') name = parts[1] id = parts[2][1..-2] # account name is in parens, trim those off Account.new(name, id) end roles = html.css('div[class=saml-account] div[class=saml-account]').map do |node| node.css('input[name=roleIndex]').map do |field| id = field['id'] arn = field['value'] # Extract the human readable role name. name = node.css("label[for='#{id}']").text Role.new(name: name, arn: arn, principal_arn: saml_assertion.principal_arn_map[arn]) end end accounts.zip(roles).to_h end end end
saml_assertion()
click to toggle source
# File lib/credsummoner/okta/user.rb, line 19 def saml_assertion @saml_assertion ||= begin response = nil while true # Get the base64 encoded SAML assertion that we will need to # send along to AWS. response = Web.get(session.saml_url, cookie: session.cookie) if response.code == '200' break else # Cookie expired! Clear session and try again. The # user will be prompted for credentials again. session.clear! end end saml_page = response.body SAMLAssertion.new(Nokogiri::HTML(saml_page).at_css('form input[name=SAMLResponse]')['value']) end end
session()
click to toggle source
# File lib/credsummoner/okta/user.rb, line 15 def session @session ||= Session.new(username, @get_creds) end