cf-uaa-lib 3.14.1 → 4.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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'
|