aptible-auth 0.11.3 → 0.11.5

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: 93d75943842f3e5ed625c2da64dc0c7ee83ffd69
4
- data.tar.gz: 84e6d466d82a90fb85060294a5b93f1a9702925d
3
+ metadata.gz: f84b4c267178de22880242466b3cf1094be20fb6
4
+ data.tar.gz: f77b05461a7db6598902a9bdfbb8140691e493b9
5
5
  SHA512:
6
- metadata.gz: 73d27eeac4954a579d97e8148f23f1a96316825e7b95c6641870db5296b6a5bdbf789e0ff12a587fc3e7cb0536c6a4d457ca2fb8a58b15f9e7950f47657a8a86
7
- data.tar.gz: bd1bf9f3fd30a2d2196807507a754c9183d85a9fc0f6cdf424f465caf837b30958e13a6793fc7fcf94b5dc0fa28024fb98361e2f4ccac5b878624c6eb40a8412
6
+ metadata.gz: 8a373677f9e0aadfae4220f181ceb31eea72ad3b756960bdf56b2e6039ee99156470101b4f256dca089345d13dbabdc0cc9e9e0c052d8074adbbdc4be83572d5
7
+ data.tar.gz: 2a187d5ad9ded64e5d2a0689c43bf49f429230eff390425af7136507172edab58ef129b4bb3a679e96ebad851838c3fc6138b6fbecf2383418769dbd2175cc33
@@ -3,44 +3,70 @@ require 'oauth2'
3
3
  module Aptible
4
4
  module Auth
5
5
  class Token < Resource
6
- attr_accessor :access_token, :refresh_token, :expires_at
6
+ # Unlike other resources, tokens aren't created in a REST fashion.
7
+ # Instead, they're created via OAuth grants. This means we need to
8
+ # override the way HyperResource / aptible-resource normally do things
9
+ # and plug in an OAuth library.
10
+ #
11
+ # To do so, we take control of the creation arguments and feed them into
12
+ # the OAuth2 library (in Token.create!), and then feed the response back
13
+ # to HyperResource (in Token#apply_oauth_response).
14
+ belongs_to :user
15
+ belongs_to :actor
16
+
17
+ field :access_token
18
+ field :refresh_token
19
+ field :expires_at
7
20
 
8
21
  def self.create(options)
22
+ # For backwards compatibility: we used to throw in .create (which isn't
23
+ # consistent with other resources), and we probably need to continue
24
+ # doing this. We also need to continue throwing a OAuth2::Error.
9
25
  token = new
10
26
  token.process_options(options)
11
27
  token
12
28
  end
13
29
 
30
+ def self.create!(options)
31
+ Token.create(options)
32
+ rescue OAuth2::Error => e
33
+ # Rethrow OAuth2::Error as HyperResource::ResponseError for
34
+ # aptible-resource to handle
35
+ raise HyperResource::ResponseError.new(e.code, response: e.response,
36
+ cause: e)
37
+ end
38
+
14
39
  def authenticate_user(email, password, options = {})
15
40
  options[:scope] ||= 'manage'
16
- response = oauth.password.get_token(email, password, options)
17
- parse_oauth_response(response)
41
+ oauth_token = oauth.password.get_token(email, password, options)
42
+ apply_oauth_response(oauth_token)
18
43
  end
19
44
 
20
45
  def authenticate_client(id, secret, subject, options = {})
21
46
  options[:scope] ||= 'manage'
22
- response = oauth.assertion.get_token({
47
+ oauth_token = oauth.assertion.get_token({
23
48
  iss: id,
24
49
  sub: subject
25
50
  }.merge(signing_params_from_secret(secret).merge(options)))
26
- parse_oauth_response(response)
51
+ apply_oauth_response(oauth_token)
27
52
  end
28
53
 
29
54
  def authenticate_impersonate(subject_token, subject_token_type, options)
30
55
  # TODO: This duplicates aptible-resource, is it worth extracting?
31
- token = case token = options.delete(:token)
32
- when Aptible::Resource::Base then token.access_token
33
- when Fridge::AccessToken then token.to_s
34
- when String then token
35
- else bearer_token
36
- end
56
+ actor_token = \
57
+ case actor_token = options.delete(:token)
58
+ when Aptible::Resource::Base then actor_token.access_token
59
+ when Fridge::AccessToken then actor_token.to_s
60
+ when String then actor_token
61
+ else bearer_token
62
+ end
37
63
 
38
64
  # TODO: Do we want to check whether the token is non-nil at this stage?
39
65
  options[:scope] ||= 'manage'
40
- response = oauth.token_exchange.get_token(
41
- token, 'urn:ietf:params:oauth:token-type:jwt',
66
+ oauth_token = oauth.token_exchange.get_token(
67
+ actor_token, 'urn:ietf:params:oauth:token-type:jwt',
42
68
  subject_token, subject_token_type, options)
43
- parse_oauth_response(response)
69
+ apply_oauth_response(oauth_token)
44
70
  end
45
71
 
46
72
  def oauth
@@ -68,12 +94,34 @@ module Aptible
68
94
  end
69
95
  end
70
96
 
97
+ def token
98
+ # If the user set an arbitrary token, then we'll return that one,
99
+ # otherwise we'll fall back to the Token itself, which makes it
100
+ # possible to create a token and immediately access it #user or #actor
101
+ # methods.
102
+ # NOTE: Setting the token after the fact probably doesn't work anyway,
103
+ # since the Authorization header won't be updated.
104
+ @token || access_token
105
+ end
106
+
107
+ def expires_at
108
+ # The Auth API returns the expiry as a timestamp (i.e. an Integer), but
109
+ # our API client knows only to handle times as strings. This overrides
110
+ # the field method for expires_at to return a Time despite the
111
+ # underlying API field being an Integer.
112
+ Time.at(attributes[:expires_at])
113
+ end
114
+
71
115
  private
72
116
 
73
- def parse_oauth_response(response)
74
- @access_token = response.token
75
- @refresh_token = response.refresh_token
76
- @expires_at = Time.at(response.expires_at)
117
+ def apply_oauth_response(oauth_token)
118
+ # apply() + loaded is what HyperResource normally does after
119
+ # deserializing a response back from the API. On top of that, we need
120
+ # to set the Authorization header so that the token can be used to make
121
+ # further API requests (e.g. accessing token#user or token#actor).
122
+ adapter.apply(oauth_token.to_hash, self)
123
+ self.loaded = true
124
+ headers['Authorization'] = "Bearer #{bearer_token}"
77
125
  self
78
126
  end
79
127
 
@@ -1,5 +1,5 @@
1
1
  module Aptible
2
2
  module Auth
3
- VERSION = '0.11.3'
3
+ VERSION = '0.11.5'
4
4
  end
5
5
  end
@@ -5,9 +5,16 @@ describe Aptible::Auth::Token do
5
5
  let(:response) { double OAuth2::AccessToken }
6
6
 
7
7
  before { subject.stub(:oauth) { oauth } }
8
- before { response.stub(:token) }
9
- before { response.stub(:refresh_token) }
10
- before { response.stub(:expires_at) { Time.now.to_i } }
8
+ let(:expires_at) { Time.now - Random.rand(1000) }
9
+ before do
10
+ response.stub(:to_hash) do
11
+ {
12
+ access_token: 'access_token',
13
+ refresh_token: nil,
14
+ expires_at: expires_at.to_i
15
+ }
16
+ end
17
+ end
11
18
 
12
19
  describe '.create' do
13
20
  it 'should call #authenticate_user if passed :email and :password' do
@@ -60,10 +67,20 @@ describe Aptible::Auth::Token do
60
67
  end
61
68
 
62
69
  it 'should set the access_token' do
63
- oauth.stub_chain(:password, :get_token, :token) { 'access_token' }
64
70
  subject.authenticate_user(*args)
65
71
  expect(subject.access_token).to eq 'access_token'
66
72
  end
73
+
74
+ it 'should set the Authorization header' do
75
+ subject.authenticate_user(*args)
76
+ expect(subject.headers['Authorization']).to eq 'Bearer access_token'
77
+ end
78
+
79
+ it 'should set the expires_at property' do
80
+ subject.authenticate_user(*args)
81
+ expect(subject.expires_at).to be_a Time
82
+ expect(subject.expires_at.to_i).to eq expires_at.to_i
83
+ end
67
84
  end
68
85
 
69
86
  describe '#authenticate_client' do
@@ -96,10 +113,29 @@ describe Aptible::Auth::Token do
96
113
  end
97
114
 
98
115
  it 'should set the access_token' do
99
- oauth.stub_chain(:assertion, :get_token, :token) { 'access_token' }
100
116
  subject.authenticate_client(*args)
101
117
  expect(subject.access_token).to eq 'access_token'
102
118
  end
119
+
120
+ it 'should set the Authorization header' do
121
+ subject.authenticate_client(*args)
122
+ expect(subject.headers['Authorization']).to eq 'Bearer access_token'
123
+ end
124
+ end
125
+
126
+ describe '#authenticate_impersonate' do
127
+ let(:args) { ['foo@bar.com', 'aptible:user:email', {}] }
128
+ before { oauth.stub_chain(:token_exchange, :get_token) { response } }
129
+
130
+ it 'should set the access_token' do
131
+ subject.authenticate_impersonate(*args)
132
+ expect(subject.access_token).to eq 'access_token'
133
+ end
134
+
135
+ it 'should set the Authorization header' do
136
+ subject.authenticate_impersonate(*args)
137
+ expect(subject.headers['Authorization']).to eq 'Bearer access_token'
138
+ end
103
139
  end
104
140
 
105
141
  describe '#signing_params_from_secret' do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aptible-auth
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.3
4
+ version: 0.11.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Frank Macreery
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-05-06 00:00:00.000000000 Z
11
+ date: 2016-06-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aptible-billing