cf-uaa-lib 3.14.1 → 4.0.1
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 +5 -5
- data/.github/dependabot.yml +11 -0
- data/.github/workflows/gem-push.yml +29 -0
- data/.github/workflows/ruby.yml +27 -0
- data/README.md +116 -14
- data/cf-uaa-lib.gemspec +9 -9
- data/examples/password_grant_and_decode_token.rb +53 -0
- data/lib/uaa/http.rb +2 -0
- data/lib/uaa/info.rb +2 -10
- data/lib/uaa/scim.rb +11 -11
- data/lib/uaa/token_coder.rb +25 -8
- data/lib/uaa/token_issuer.rb +20 -13
- data/lib/uaa/util.rb +1 -1
- data/lib/uaa/version.rb +1 -1
- data/spec/info_spec.rb +3 -3
- data/spec/integration_spec.rb +19 -19
- data/spec/scim_spec.rb +11 -11
- data/spec/spec_helper.rb +7 -1
- data/spec/token_coder_spec.rb +20 -14
- data/spec/token_issuer_spec.rb +57 -25
- metadata +75 -46
- data/.travis.yml +0 -10
data/lib/uaa/util.rb
CHANGED
@@ -145,7 +145,7 @@ class Util
|
|
145
145
|
|
146
146
|
# Converts +obj+ to nicely formatted JSON
|
147
147
|
# @return [String] obj in formatted json
|
148
|
-
def self.json_pretty(obj) MultiJson.dump(obj, :
|
148
|
+
def self.json_pretty(obj) MultiJson.dump(obj, pretty: true) end
|
149
149
|
|
150
150
|
# Converts +obj+ to a URL-safe base 64 encoded string
|
151
151
|
# @return [String]
|
data/lib/uaa/version.rb
CHANGED
data/spec/info_spec.rb
CHANGED
@@ -34,7 +34,7 @@ module CF::UAA
|
|
34
34
|
end
|
35
35
|
|
36
36
|
describe 'initialize' do
|
37
|
-
let(:options) { {:
|
37
|
+
let(:options) { {skip_ssl_validation: true} }
|
38
38
|
|
39
39
|
it 'sets proxy information' do
|
40
40
|
uaa_info.skip_ssl_validation == true
|
@@ -52,7 +52,7 @@ module CF::UAA
|
|
52
52
|
end
|
53
53
|
|
54
54
|
context 'with symbolize_keys keys true' do
|
55
|
-
let(:options) { {:
|
55
|
+
let(:options) { {symbolize_keys: true} }
|
56
56
|
|
57
57
|
it 'gets server info' do
|
58
58
|
result = uaa_info.server
|
@@ -84,7 +84,7 @@ module CF::UAA
|
|
84
84
|
end
|
85
85
|
|
86
86
|
context 'with symbolize_keys keys true' do
|
87
|
-
let(:options) { {:
|
87
|
+
let(:options) { {symbolize_keys: true} }
|
88
88
|
|
89
89
|
it 'gets UAA target' do
|
90
90
|
result = uaa_info.discover_uaa
|
data/spec/integration_spec.rb
CHANGED
@@ -41,14 +41,14 @@ module CF::UAA
|
|
41
41
|
target = ENV['UAA_CLIENT_TARGET']
|
42
42
|
|
43
43
|
admin_token_issuer = TokenIssuer.new(target, admin_client, admin_secret, options)
|
44
|
-
Scim.new(target, admin_token_issuer.client_credentials_grant.auth_header, options.merge(:
|
44
|
+
Scim.new(target, admin_token_issuer.client_credentials_grant.auth_header, options.merge(symbolize_keys: true))
|
45
45
|
end
|
46
46
|
|
47
47
|
describe 'when UAA does not respond' do
|
48
48
|
let(:http_timeout) { 0.01 }
|
49
49
|
let(:default_http_client_timeout) { 60 }
|
50
|
-
let(:scim) { Scim.new(@target, "", {:
|
51
|
-
let(:token_issuer) { TokenIssuer.new(@target, "", "", {:
|
50
|
+
let(:scim) { Scim.new(@target, "", {http_timeout: http_timeout}) }
|
51
|
+
let(:token_issuer) { TokenIssuer.new(@target, "", "", {http_timeout: http_timeout}) }
|
52
52
|
let(:blackhole_ip) { '10.255.255.1'}
|
53
53
|
|
54
54
|
before do
|
@@ -60,7 +60,7 @@ module CF::UAA
|
|
60
60
|
Timeout.timeout(default_http_client_timeout - 1) do
|
61
61
|
scim.get(:user, "admin")
|
62
62
|
end
|
63
|
-
}.to raise_error
|
63
|
+
}.to raise_error HTTPException
|
64
64
|
end
|
65
65
|
|
66
66
|
it 'times out the connection at the configured time for the token issuer' do
|
@@ -68,7 +68,7 @@ module CF::UAA
|
|
68
68
|
Timeout.timeout(default_http_client_timeout - 1) do
|
69
69
|
token_issuer.client_credentials_grant
|
70
70
|
end
|
71
|
-
}.to raise_error
|
71
|
+
}.to raise_error HTTPException
|
72
72
|
end
|
73
73
|
end
|
74
74
|
|
@@ -77,20 +77,20 @@ module CF::UAA
|
|
77
77
|
|
78
78
|
let(:options) { @options }
|
79
79
|
let(:token_issuer) { TokenIssuer.new(@target, @test_client, @test_secret, options) }
|
80
|
-
let(:scim) { Scim.new(@target, token_issuer.client_credentials_grant.auth_header, options.merge(:
|
80
|
+
let(:scim) { Scim.new(@target, token_issuer.client_credentials_grant.auth_header, options.merge(symbolize_keys: true)) }
|
81
81
|
|
82
82
|
before :all do
|
83
83
|
@options = {}
|
84
84
|
if ENV['SKIP_SSL_VALIDATION']
|
85
|
-
@options = {:
|
85
|
+
@options = {skip_ssl_validation: true}
|
86
86
|
end
|
87
87
|
@target = ENV['UAA_CLIENT_TARGET']
|
88
88
|
@test_client = "test_client_#{Time.now.to_i}"
|
89
89
|
@test_secret = '+=tEsTsEcRet~!@'
|
90
90
|
gids = ['clients.read', 'scim.read', 'scim.write', 'uaa.resource', 'password.write']
|
91
|
-
test_client = CF::UAA::admin_scim(@options).add(:client, :
|
92
|
-
:
|
93
|
-
:
|
91
|
+
test_client = CF::UAA::admin_scim(@options).add(:client, client_id: @test_client, client_secret: @test_secret,
|
92
|
+
authorities: gids, authorized_grant_types: ['client_credentials', 'password'],
|
93
|
+
scope: ['openid', 'password.write'])
|
94
94
|
expect(test_client[:client_id]).to eq(@test_client)
|
95
95
|
end
|
96
96
|
|
@@ -102,7 +102,7 @@ module CF::UAA
|
|
102
102
|
|
103
103
|
if ENV['SKIP_SSL_VALIDATION']
|
104
104
|
context 'when ssl certificate is self-signed' do
|
105
|
-
let(:options) { {:
|
105
|
+
let(:options) { {skip_ssl_validation: false} }
|
106
106
|
|
107
107
|
it 'fails if skip_ssl_validation is false' do
|
108
108
|
expect{ scim }.to raise_exception(CF::UAA::SSLException)
|
@@ -113,7 +113,7 @@ module CF::UAA
|
|
113
113
|
if ENV['SSL_CA_FILE']
|
114
114
|
context 'when you do not skip SSL validation' do
|
115
115
|
context 'when you provide cert' do
|
116
|
-
let(:options) { {:
|
116
|
+
let(:options) { {ssl_ca_file: ENV['SSL_CA_FILE']} }
|
117
117
|
|
118
118
|
it 'works' do
|
119
119
|
expect(token_issuer.prompts).to_not be_nil
|
@@ -139,7 +139,7 @@ module CF::UAA
|
|
139
139
|
cert_store
|
140
140
|
end
|
141
141
|
|
142
|
-
let(:options) { {:
|
142
|
+
let(:options) { {ssl_cert_store: cert_store} }
|
143
143
|
it 'works' do
|
144
144
|
expect(token_issuer.prompts).to_not be_nil
|
145
145
|
end
|
@@ -166,7 +166,7 @@ module CF::UAA
|
|
166
166
|
it 'gets a token with client credentials' do
|
167
167
|
tkn = token_issuer.client_credentials_grant
|
168
168
|
expect(tkn.auth_header).to match(/^bearer\s/i)
|
169
|
-
info = TokenCoder.decode(tkn.info['access_token'], :
|
169
|
+
info = TokenCoder.decode(tkn.info['access_token'], verify: false, symbolize_keys: true)
|
170
170
|
expect(info[:exp]).to be
|
171
171
|
expect(info[:jti]).to be
|
172
172
|
end
|
@@ -179,9 +179,9 @@ module CF::UAA
|
|
179
179
|
before :each do
|
180
180
|
@username = "sam_#{Time.now.to_i}"
|
181
181
|
@user_pwd = "sam's P@55w0rd~!`@\#\$%^&*()_/{}[]\\|:\";',.<>?/"
|
182
|
-
usr = scim.add(:user, :
|
183
|
-
:
|
184
|
-
:
|
182
|
+
usr = scim.add(:user, username: @username, password: @user_pwd,
|
183
|
+
emails: [{value: 'sam@example.com'}],
|
184
|
+
name: {givenname: 'none', familyname: 'none'})
|
185
185
|
@user_id = usr[:id]
|
186
186
|
end
|
187
187
|
|
@@ -222,8 +222,8 @@ module CF::UAA
|
|
222
222
|
|
223
223
|
it 'should get a uri to be sent to the user agent to initiate autologin' do
|
224
224
|
redir_uri = 'http://call.back/uri_path'
|
225
|
-
uri_parts = token_issuer.autologin_uri(redir_uri, :
|
226
|
-
:
|
225
|
+
uri_parts = token_issuer.autologin_uri(redir_uri, username: @username,
|
226
|
+
password: @user_pwd ).split('?')
|
227
227
|
expect(uri_parts[0]).to eq("#{ENV['UAA_CLIENT_TARGET']}/oauth/authorize")
|
228
228
|
params = Util.decode_form(uri_parts[1], :sym)
|
229
229
|
expect(params[:response_type]).to eq('code')
|
data/spec/scim_spec.rb
CHANGED
@@ -39,7 +39,7 @@ describe Scim do
|
|
39
39
|
end
|
40
40
|
|
41
41
|
describe 'initialize' do
|
42
|
-
let(:options) { {:
|
42
|
+
let(:options) { {http_proxy: 'http-proxy.com', https_proxy: 'https-proxy.com', skip_ssl_validation: true} }
|
43
43
|
|
44
44
|
it 'sets skip_ssl_validation' do
|
45
45
|
subject.skip_ssl_validation == true
|
@@ -53,8 +53,8 @@ describe Scim do
|
|
53
53
|
check_headers(headers, :json, :json, nil)
|
54
54
|
[200, '{"ID":"id12345"}', {'content-type' => 'application/json'}]
|
55
55
|
end
|
56
|
-
result = subject.add(:user, :
|
57
|
-
:
|
56
|
+
result = subject.add(:user, hair: 'brown', shoe_size: 'large',
|
57
|
+
eye_color: ['blue', 'green'], name: 'fred')
|
58
58
|
result['id'].should == 'id12345'
|
59
59
|
end
|
60
60
|
|
@@ -71,8 +71,8 @@ describe Scim do
|
|
71
71
|
end
|
72
72
|
|
73
73
|
it 'replaces an object' do
|
74
|
-
obj = {:
|
75
|
-
:
|
74
|
+
obj = {hair: 'black', shoe_size: 'medium', eye_color: ['hazel', 'brown'],
|
75
|
+
name: 'fredrick', meta: {version: 'v567'}, id: 'id12345'}
|
76
76
|
subject.set_request_handler do |url, method, body, headers|
|
77
77
|
url.should == "#{@target}/Users/id12345"
|
78
78
|
method.should == :put
|
@@ -85,8 +85,8 @@ describe Scim do
|
|
85
85
|
end
|
86
86
|
|
87
87
|
it 'modifies an object' do
|
88
|
-
obj = {:
|
89
|
-
:
|
88
|
+
obj = {hair: 'black', shoe_size: 'medium', eye_color: ['hazel', 'brown'],
|
89
|
+
name: 'fredrick', meta: {version: 'v567'}, id: 'id12345'}
|
90
90
|
subject.set_request_handler do |url, method, body, headers|
|
91
91
|
url.should == "#{@target}/Users/id12345"
|
92
92
|
method.should == :patch
|
@@ -122,7 +122,7 @@ describe Scim do
|
|
122
122
|
'{"TotalResults":2,"ItemsPerPage":1,"StartIndex":2,"RESOURCES":[{"id":"id67890"}]}'
|
123
123
|
[200, reply, {'content-type' => 'application/json'}]
|
124
124
|
end
|
125
|
-
result = subject.all_pages(:user, :
|
125
|
+
result = subject.all_pages(:user, attributes: 'id', includeInactive: true)
|
126
126
|
[result[0]['id'], result[1]['id']].to_set.should == ['id12345', 'id67890'].to_set
|
127
127
|
end
|
128
128
|
|
@@ -221,7 +221,7 @@ describe Scim do
|
|
221
221
|
end
|
222
222
|
|
223
223
|
describe 'users in a zone' do
|
224
|
-
let(:options) { {:
|
224
|
+
let(:options) { {http_proxy: 'http-proxy.com', https_proxy: 'https-proxy.com', skip_ssl_validation: true, zone: 'derpzone'} }
|
225
225
|
|
226
226
|
it 'sends zone header' do
|
227
227
|
subject.set_request_handler do |url, method, body, headers|
|
@@ -230,8 +230,8 @@ describe Scim do
|
|
230
230
|
check_headers(headers, :json, :json, 'derpzone')
|
231
231
|
[200, '{"ID":"id12345"}', {'content-type' => 'application/json'}]
|
232
232
|
end
|
233
|
-
result = subject.add(:user, :
|
234
|
-
:
|
233
|
+
result = subject.add(:user, hair: 'brown', shoe_size: 'large',
|
234
|
+
eye_color: ['blue', 'green'], name: 'fred')
|
235
235
|
result['id'].should == 'id12345'
|
236
236
|
end
|
237
237
|
end
|
data/spec/spec_helper.rb
CHANGED
data/spec/token_coder_spec.rb
CHANGED
@@ -18,8 +18,8 @@ module CF::UAA
|
|
18
18
|
|
19
19
|
describe TokenCoder do
|
20
20
|
|
21
|
-
subject { TokenCoder.new(:
|
22
|
-
:
|
21
|
+
subject { TokenCoder.new(audience_ids: "test_resource",
|
22
|
+
skey: "test_secret", pkey: OpenSSL::PKey::RSA.generate(512) ) }
|
23
23
|
|
24
24
|
before :each do
|
25
25
|
@tkn_body = {'foo' => "bar"}
|
@@ -57,7 +57,7 @@ describe TokenCoder do
|
|
57
57
|
2yrlT5h164jGCxqe7++1kIl4ollFCgz6QJ8lcmb/2Q==
|
58
58
|
-----END RSA PRIVATE KEY-----
|
59
59
|
DATA
|
60
|
-
coder = TokenCoder.new(:
|
60
|
+
coder = TokenCoder.new(audience_ids: "test_resource", pkey: pem)
|
61
61
|
tkn = coder.encode(@tkn_body, 'RS256')
|
62
62
|
result = coder.decode("bEaReR #{tkn}")
|
63
63
|
result.should_not be_nil
|
@@ -66,7 +66,7 @@ describe TokenCoder do
|
|
66
66
|
|
67
67
|
it "encodes/decodes with 'none' signature if explicitly accepted" do
|
68
68
|
tkn = subject.encode(@tkn_body, 'none')
|
69
|
-
result = TokenCoder.decode(tkn, :
|
69
|
+
result = TokenCoder.decode(tkn, accept_algorithms: "none")
|
70
70
|
result.should_not be_nil
|
71
71
|
result["foo"].should == "bar"
|
72
72
|
end
|
@@ -86,7 +86,7 @@ describe TokenCoder do
|
|
86
86
|
end
|
87
87
|
|
88
88
|
it "raises an error if the token is signed by an unknown signing key" do
|
89
|
-
other = TokenCoder.new(:
|
89
|
+
other = TokenCoder.new(audience_ids: "test_resource", skey: "other_secret")
|
90
90
|
tkn = other.encode(@tkn_body)
|
91
91
|
expect { subject.decode("bEaReR #{tkn}") }.to raise_exception(InvalidSignature)
|
92
92
|
end
|
@@ -103,8 +103,8 @@ describe TokenCoder do
|
|
103
103
|
2yrlT5h164jGCxqe7++1kIl4ollFCgz6QJ8lcmb/2Q==
|
104
104
|
-----END RSA PRIVATE KEY-----
|
105
105
|
DATA
|
106
|
-
coder = TokenCoder.new(:
|
107
|
-
coder2 = TokenCoder.new(:
|
106
|
+
coder = TokenCoder.new(audience_ids: "test_resource", pkey: pem)
|
107
|
+
coder2 = TokenCoder.new(audience_ids: "test_resource", skey: 'randomness')
|
108
108
|
|
109
109
|
tkn = coder.encode(@tkn_body, 'RS256')
|
110
110
|
|
@@ -123,21 +123,21 @@ describe TokenCoder do
|
|
123
123
|
2yrlT5h164jGCxqe7++1kIl4ollFCgz6QJ8lcmb/2Q==
|
124
124
|
-----END RSA PRIVATE KEY-----
|
125
125
|
DATA
|
126
|
-
coder = TokenCoder.new(:
|
127
|
-
coder2 = TokenCoder.new(:
|
126
|
+
coder = TokenCoder.new(audience_ids: "test_resource", pkey: pem)
|
127
|
+
coder2 = TokenCoder.new(audience_ids: "test_resource", skey: 'randomness')
|
128
128
|
tkn = coder2.encode(@tkn_body)
|
129
129
|
|
130
130
|
expect { coder.decode("bEaReR #{tkn}") }.to raise_exception(InvalidSignature)
|
131
131
|
end
|
132
132
|
|
133
133
|
it "raises an error if the token is an unknown signing algorithm" do
|
134
|
-
segments = [Util.json_encode64(:
|
134
|
+
segments = [Util.json_encode64(typ: "JWT", alg:"BADALGO")]
|
135
135
|
segments << Util.json_encode64(@tkn_body)
|
136
136
|
segments << Util.encode64("BADSIG")
|
137
137
|
tkn = segments.join('.')
|
138
|
-
tc = TokenCoder.new(:
|
139
|
-
:
|
140
|
-
:
|
138
|
+
tc = TokenCoder.new(audience_ids: "test_resource",
|
139
|
+
skey: "test_secret", pkey: OpenSSL::PKey::RSA.generate(512),
|
140
|
+
accept_algorithms: "BADALGO")
|
141
141
|
expect { tc.decode("bEaReR #{tkn}") }.to raise_exception(SignatureNotSupported)
|
142
142
|
end
|
143
143
|
|
@@ -179,10 +179,16 @@ describe TokenCoder do
|
|
179
179
|
|
180
180
|
it "decodes a token without validation" do
|
181
181
|
token = "eyJhbGciOiJIUzI1NiJ9.eyJpZCI6ImY1MTgwMjExLWVkYjItNGQ4OS1hNmQwLThmNGVjMTE0NTE4YSIsInJlc291cmNlX2lkcyI6WyJjbG91ZF9jb250cm9sbGVyIiwicGFzc3dvcmQiXSwiZXhwaXJlc19hdCI6MTMzNjU1MTc2Niwic2NvcGUiOlsicmVhZCJdLCJlbWFpbCI6Im9sZHNAdm13YXJlLmNvbSIsImNsaWVudF9hdXRob3JpdGllcyI6WyJST0xFX1VOVFJVU1RFRCJdLCJleHBpcmVzX2luIjo0MzIwMCwidXNlcl9hdXRob3JpdGllcyI6WyJST0xFX1VTRVIiXSwidXNlcl9pZCI6Im9sZHNAdm13YXJlLmNvbSIsImNsaWVudF9pZCI6InZtYyIsInRva2VuX2lkIjoiZWRlYmYzMTctNWU2Yi00YmYwLWFmM2ItMTA0OWRjNmFlYjc1In0.XoirrePfEujnZ9Vm7SRRnj3vZEfRp2tkjkS_OCVz5Bs"
|
182
|
-
info = TokenCoder.decode(token, :
|
182
|
+
info = TokenCoder.decode(token, verify: false)
|
183
183
|
info["id"].should_not be_nil
|
184
184
|
info["email"].should == "olds@vmware.com"
|
185
185
|
end
|
186
|
+
|
187
|
+
it "decodes only the expiry_at time" do
|
188
|
+
exp = Time.now.to_i + 60
|
189
|
+
tkn = subject.encode({'foo' => "bar", 'exp' => exp })
|
190
|
+
TokenCoder.decode_token_expiry("bEaReR #{tkn}").should == exp
|
191
|
+
end
|
186
192
|
end
|
187
193
|
|
188
194
|
end
|
data/spec/token_issuer_spec.rb
CHANGED
@@ -23,13 +23,16 @@ describe TokenIssuer do
|
|
23
23
|
|
24
24
|
before do
|
25
25
|
#Util.default_logger(:trace)
|
26
|
-
@issuer = TokenIssuer.new('http://test.uaa.target',
|
26
|
+
@issuer = TokenIssuer.new('http://test.uaa.target', client_id, client_secret, options)
|
27
27
|
end
|
28
28
|
|
29
|
+
let(:client_id) { 'test_client' }
|
30
|
+
let(:client_secret) { 'test!secret' }
|
31
|
+
|
29
32
|
subject { @issuer }
|
30
33
|
|
31
34
|
describe 'initialize' do
|
32
|
-
let(:options) { {:
|
35
|
+
let(:options) { {http_proxy: 'http-proxy.com', https_proxy: 'https-proxy.com', skip_ssl_validation: true, basic_auth: false} }
|
33
36
|
|
34
37
|
it 'sets skip_ssl_validation' do
|
35
38
|
subject.skip_ssl_validation == true
|
@@ -42,11 +45,12 @@ describe TokenIssuer do
|
|
42
45
|
subject.set_request_handler do |url, method, body, headers|
|
43
46
|
headers['content-type'].should =~ /application\/x-www-form-urlencoded/
|
44
47
|
headers['accept'].should =~ /application\/json/
|
45
|
-
|
48
|
+
headers['X-CF-ENCODED-CREDENTIALS'].should == 'true'
|
49
|
+
headers['authorization'].should == 'Basic dGVzdF9jbGllbnQ6dGVzdCUyMXNlY3JldA=='
|
46
50
|
url.should == 'http://test.uaa.target/oauth/token'
|
47
51
|
method.should == :post
|
48
|
-
reply = {:
|
49
|
-
:
|
52
|
+
reply = {access_token: 'test_access_token', token_type: 'BEARER',
|
53
|
+
scope: 'logs.read', expires_in: 98765}
|
50
54
|
[200, Util.json(reply), {'content-type' => 'application/json'}]
|
51
55
|
end
|
52
56
|
token = subject.client_credentials_grant('logs.read')
|
@@ -59,8 +63,8 @@ describe TokenIssuer do
|
|
59
63
|
|
60
64
|
it 'gets all granted scopes if none specified' do
|
61
65
|
subject.set_request_handler do |url, method, body, headers|
|
62
|
-
reply = {:
|
63
|
-
:
|
66
|
+
reply = {access_token: 'test_access_token', token_type: 'BEARER',
|
67
|
+
scope: 'openid logs.read', expires_in: 98765}
|
64
68
|
[200, Util.json(reply), {'content-type' => 'application/json'}]
|
65
69
|
end
|
66
70
|
token = subject.client_credentials_grant
|
@@ -89,11 +93,12 @@ describe TokenIssuer do
|
|
89
93
|
subject.set_request_handler do |url, method, body, headers|
|
90
94
|
headers['content-type'].should =~ /application\/x-www-form-urlencoded/
|
91
95
|
headers['accept'].should =~ /application\/json/
|
92
|
-
|
96
|
+
headers['X-CF-ENCODED-CREDENTIALS'].should == 'true'
|
97
|
+
headers['authorization'].should == 'Basic dGVzdF9jbGllbnQ6dGVzdCUyMXNlY3JldA=='
|
93
98
|
url.should == 'http://test.uaa.target/oauth/token'
|
94
99
|
method.should == :post
|
95
|
-
reply = {:
|
96
|
-
:
|
100
|
+
reply = {access_token: 'test_access_token', token_type: 'BEARER',
|
101
|
+
scope: 'openid', expires_in: 98765}
|
97
102
|
[200, Util.json(reply), {'content-type' => 'application/json'}]
|
98
103
|
end
|
99
104
|
token = subject.owner_password_grant('joe+admin', "?joe's%password$@ ", 'openid')
|
@@ -104,17 +109,43 @@ describe TokenIssuer do
|
|
104
109
|
token.info['expires_in'].should == 98765
|
105
110
|
end
|
106
111
|
|
112
|
+
context "when client & client secret are nil" do
|
113
|
+
let(:client_id) { nil }
|
114
|
+
let(:client_secret) { nil }
|
115
|
+
|
116
|
+
it 'does not error' do
|
117
|
+
subject.set_request_handler do |url, method, body, headers|
|
118
|
+
headers['content-type'].should =~ /application\/x-www-form-urlencoded/
|
119
|
+
headers['accept'].should =~ /application\/json/
|
120
|
+
headers['X-CF-ENCODED-CREDENTIALS'].should == 'true'
|
121
|
+
headers['authorization'].should == 'Basic Og=='
|
122
|
+
url.should == 'http://test.uaa.target/oauth/token'
|
123
|
+
method.should == :post
|
124
|
+
reply = {access_token: 'test_access_token', token_type: 'BEARER',
|
125
|
+
scope: 'openid', expires_in: 98765}
|
126
|
+
[200, Util.json(reply), {'content-type' => 'application/json'}]
|
127
|
+
end
|
128
|
+
token = subject.owner_password_grant('joe+admin', "?joe's%password$@ ", 'openid')
|
129
|
+
token.should be_an_instance_of TokenInfo
|
130
|
+
token.info['access_token'].should == 'test_access_token'
|
131
|
+
token.info['token_type'].should =~ /^bearer$/i
|
132
|
+
token.info['scope'].should == 'openid'
|
133
|
+
token.info['expires_in'].should == 98765
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
107
137
|
it 'gets a token with passcode' do
|
108
138
|
subject.set_request_handler do |url, method, body, headers|
|
109
139
|
headers['content-type'].should =~ /application\/x-www-form-urlencoded/
|
110
140
|
headers['accept'].should =~ /application\/json/
|
111
|
-
|
141
|
+
headers['X-CF-ENCODED-CREDENTIALS'].should == 'true'
|
142
|
+
headers['authorization'].should == 'Basic dGVzdF9jbGllbnQ6dGVzdCUyMXNlY3JldA=='
|
112
143
|
url.should == 'http://test.uaa.target/oauth/token'
|
113
144
|
body.should =~ /(^|&)passcode=12345($|&)/
|
114
145
|
body.should =~ /(^|&)grant_type=password($|&)/
|
115
146
|
method.should == :post
|
116
|
-
reply = {:
|
117
|
-
:
|
147
|
+
reply = {access_token: 'test_access_token', token_type: 'BEARER',
|
148
|
+
scope: 'openid', expires_in: 98765}
|
118
149
|
[200, Util.json(reply), {'content-type' => 'application/json'}]
|
119
150
|
end
|
120
151
|
token = subject.passcode_grant('12345')
|
@@ -135,8 +166,8 @@ describe TokenIssuer do
|
|
135
166
|
url.should == 'http://test.uaa.target/oauth/token'
|
136
167
|
method.should == :post
|
137
168
|
body.split('&').should =~ ['passcode=fake-passcode', 'grant_type=password']
|
138
|
-
reply = {:
|
139
|
-
:
|
169
|
+
reply = {access_token: 'test_access_token', token_type: 'BEARER',
|
170
|
+
scope: 'openid', expires_in: 98765}
|
140
171
|
[200, Util.json(reply), {'content-type' => 'application/json'}]
|
141
172
|
end
|
142
173
|
token = subject.owner_password_credentials_grant({passcode: 'fake-passcode'})
|
@@ -153,7 +184,7 @@ describe TokenIssuer do
|
|
153
184
|
|
154
185
|
it 'gets the prompts for credentials used to authenticate implicit grant' do
|
155
186
|
subject.set_request_handler do |url, method, body, headers|
|
156
|
-
info = { :
|
187
|
+
info = { prompts: {username: ['text', 'Username'], password: ['password', 'Password']} }
|
157
188
|
[200, Util.json(info), {'content-type' => 'application/json'}]
|
158
189
|
end
|
159
190
|
result = subject.prompts
|
@@ -182,10 +213,10 @@ describe TokenIssuer do
|
|
182
213
|
end
|
183
214
|
|
184
215
|
expect(subject).to receive(:authorize_path_args).with('token', 'https://uaa.cloudfoundry.com/redirect/test_client', 'logs.read', anything)
|
185
|
-
subject.
|
186
|
-
subject.
|
216
|
+
allow(subject).to receive(:random_state).and_return('1234')
|
217
|
+
allow(subject).to receive(:authorize_path_args).and_return('/oauth/authorize?state=1234&scope=logs.read')
|
187
218
|
|
188
|
-
token = subject.implicit_grant_with_creds({:
|
219
|
+
token = subject.implicit_grant_with_creds({username: 'joe+admin', password: "?joe's%password$@ "}, 'logs.read')
|
189
220
|
token.should be_an_instance_of TokenInfo
|
190
221
|
token.info['access_token'].should == 'test_access_token'
|
191
222
|
token.info['token_type'].should =~ /^bearer$/i
|
@@ -202,7 +233,7 @@ describe TokenIssuer do
|
|
202
233
|
end
|
203
234
|
|
204
235
|
expect(subject).to receive(:authorize_path_args).with('token id_token', 'https://uaa.cloudfoundry.com/redirect/test_client', 'openid logs.read', anything)
|
205
|
-
subject.
|
236
|
+
allow(subject).to receive(:random_state).and_return('1234')
|
206
237
|
subject.implicit_grant_with_creds({:username => 'joe+admin', :password => "?joe's%password$@ "}, 'openid logs.read')
|
207
238
|
end
|
208
239
|
end
|
@@ -214,8 +245,8 @@ describe TokenIssuer do
|
|
214
245
|
'expires_in=98765&scope=openid+logs.read&state=bad_state'
|
215
246
|
[302, nil, {'content-type' => 'application/json', 'location' => location}]
|
216
247
|
end
|
217
|
-
expect {token = subject.implicit_grant_with_creds(:
|
218
|
-
:
|
248
|
+
expect {token = subject.implicit_grant_with_creds(username: 'joe+admin',
|
249
|
+
password: "?joe's%password$@ ")}.to raise_exception BadResponse
|
219
250
|
end
|
220
251
|
|
221
252
|
it 'asks for an id_token with openid scope' do
|
@@ -250,11 +281,12 @@ describe TokenIssuer do
|
|
250
281
|
subject.set_request_handler do |url, method, body, headers|
|
251
282
|
headers['content-type'].should =~ /application\/x-www-form-urlencoded/
|
252
283
|
headers['accept'].should =~ /application\/json/
|
253
|
-
|
284
|
+
headers['X-CF-ENCODED-CREDENTIALS'].should == 'true'
|
285
|
+
headers['authorization'].should == 'Basic dGVzdF9jbGllbnQ6dGVzdCUyMXNlY3JldA=='
|
254
286
|
url.should match 'http://test.uaa.target/oauth/token'
|
255
287
|
method.should == :post
|
256
|
-
reply = {:
|
257
|
-
:
|
288
|
+
reply = {access_token: 'test_access_token', token_type: 'BEARER',
|
289
|
+
scope: 'openid', expires_in: 98765}
|
258
290
|
[200, Util.json(reply), {'content-type' => 'application/json'}]
|
259
291
|
end
|
260
292
|
cburi = 'http://call.back/uri_path'
|