Class: Aptible::Auth::Token

Inherits:
Resource
  • Object
show all
Defined in:
lib/aptible/auth/token.rb

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Resource

#namespace, #root_url

Class Method Details

.create(options) ⇒ Object



24
25
26
27
28
29
30
31
# File 'lib/aptible/auth/token.rb', line 24

def self.create(options)
  # For backwards compatibility: we used to throw in .create (which isn't
  # consistent with other resources), and we probably need to continue
  # doing this. We also need to continue throwing a OAuth2::Error.
  token = new
  token.process_options(options)
  token
end

.create!(options) ⇒ Object



33
34
35
36
37
38
39
40
# File 'lib/aptible/auth/token.rb', line 33

def self.create!(options)
  Token.create(options)
rescue OAuth2::Error => e
  # Rethrow OAuth2::Error as HyperResource::ResponseError for
  # aptible-resource to handle
  raise HyperResource::ResponseError.new(e.code, response: e.response,
                                                 cause: e)
end

Instance Method Details

#authenticate_client(id, secret, subject, options = {}) ⇒ Object



48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/aptible/auth/token.rb', line 48

def authenticate_client(id, secret, subject, options = {})
  options[:scope] ||= 'manage'
  # Unlike other methods, the assertion token grant requirs an "exp"
  # parameter rather than expires_in, but since we'd like to expose a
  # consistent API to consumers, we override it here
  expires_in = options.delete(:expires_in)
  options[:exp] = Time.now.utc.to_i + expires_in if expires_in
  oauth_token = oauth.assertion.get_token({
    iss: id,
    sub: subject
  }.merge(signing_params_from_secret(secret).merge(options)))
  apply_oauth_response(oauth_token)
end

#authenticate_impersonate(subject_token, subject_token_type, options) ⇒ Object



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/aptible/auth/token.rb', line 62

def authenticate_impersonate(subject_token, subject_token_type, options)
  # TODO: This duplicates aptible-resource, is it worth extracting?
  actor_token = \
    case actor_token = options.delete(:token)
    when Aptible::Resource::Base then actor_token.access_token
    when Fridge::AccessToken then actor_token.to_s
    when String then actor_token
    else bearer_token
    end

  # TODO: Do we want to check whether the token is non-nil at this stage?
  options[:scope] ||= 'manage'
  oauth_token = oauth.token_exchange.get_token(
    actor_token, 'urn:ietf:params:oauth:token-type:jwt',
    subject_token, subject_token_type, options
  )
  apply_oauth_response(oauth_token)
end

#authenticate_user(email, password, options = {}) ⇒ Object



42
43
44
45
46
# File 'lib/aptible/auth/token.rb', line 42

def authenticate_user(email, password, options = {})
  options[:scope] ||= 'manage'
  oauth_token = oauth.password.get_token(email, password, options)
  apply_oauth_response(oauth_token)
end

#expires_atObject



126
127
128
129
130
131
132
# File 'lib/aptible/auth/token.rb', line 126

def expires_at
  # The Auth API returns the expiry as a timestamp (i.e. an Integer), but
  # our API client knows only to handle times as strings. This overrides
  # the field method for expires_at to return a Time despite the
  # underlying API field being an Integer.
  Time.at(attributes[:expires_at])
end

#oauthObject



81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/aptible/auth/token.rb', line 81

def oauth
  options = {
    site: root_url,
    token_url: '/tokens',
    connection_opts: {
      headers: {
        'User-Agent' => Aptible::Resource.configuration.user_agent
      }
    }
  }
  @oauth ||= OAuth2::Client.new(nil, nil, options)
end

#process_options(options) ⇒ Object



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/aptible/auth/token.rb', line 94

def process_options(options)
  options = options.dup
  if (email = options.delete(:email)) &&
     (password = options.delete(:password))
    authenticate_user(email, password, options)
  elsif (client_id = options.delete(:client_id)) &&
        (client_secret = options.delete(:client_secret)) &&
        (subject = options.delete(:subject))
    authenticate_client(client_id, client_secret, subject, options)
  elsif (href = options.delete(:user_href))
    authenticate_impersonate(href, 'aptible:user:href', options)
  elsif (href = options.delete(:organization_href))
    authenticate_impersonate(href, 'aptible:organization:href', options)
  elsif (email = options.delete(:user_email))
    authenticate_impersonate(email, 'aptible:user:email', options)
  else
    # rubocop:disable Style/SignalException
    fail 'Unrecognized options'
    # rubocop:enable Style/SignalException
  end
end

#tokenObject



116
117
118
119
120
121
122
123
124
# File 'lib/aptible/auth/token.rb', line 116

def token
  # If the user set an arbitrary token, then we'll return that one,
  # otherwise we'll fall back to the Token itself, which makes it
  # possible to create a token and immediately access it #user or #actor
  # methods.
  # NOTE: Setting the token after the fact probably doesn't work anyway,
  # since the Authorization header won't be updated.
  @token || access_token
end