aptible-auth 0.11.3 → 0.11.5
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 +4 -4
- data/lib/aptible/auth/token.rb +66 -18
- data/lib/aptible/auth/version.rb +1 -1
- data/spec/aptible/auth/token_spec.rb +41 -5
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f84b4c267178de22880242466b3cf1094be20fb6
|
4
|
+
data.tar.gz: f77b05461a7db6598902a9bdfbb8140691e493b9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8a373677f9e0aadfae4220f181ceb31eea72ad3b756960bdf56b2e6039ee99156470101b4f256dca089345d13dbabdc0cc9e9e0c052d8074adbbdc4be83572d5
|
7
|
+
data.tar.gz: 2a187d5ad9ded64e5d2a0689c43bf49f429230eff390425af7136507172edab58ef129b4bb3a679e96ebad851838c3fc6138b6fbecf2383418769dbd2175cc33
|
data/lib/aptible/auth/token.rb
CHANGED
@@ -3,44 +3,70 @@ require 'oauth2'
|
|
3
3
|
module Aptible
|
4
4
|
module Auth
|
5
5
|
class Token < Resource
|
6
|
-
|
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
|
-
|
17
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
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
|
-
|
41
|
-
|
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
|
-
|
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
|
74
|
-
|
75
|
-
|
76
|
-
|
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
|
|
data/lib/aptible/auth/version.rb
CHANGED
@@ -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
|
-
|
9
|
-
before
|
10
|
-
|
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.
|
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-
|
11
|
+
date: 2016-06-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: aptible-billing
|