cf-uaa-lib 4.0.2 → 4.0.3
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/.github/workflows/gem-push.yml +1 -1
- data/.github/workflows/ruby.yml +1 -1
- data/examples/authorization_grant_public_pkce.rb +42 -0
- data/lib/uaa/token_issuer.rb +41 -4
- data/lib/uaa/version.rb +1 -1
- data/spec/token_issuer_spec.rb +35 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9eebcd4d0b7e5068266fceab3b4686335b5446bb18a6bf4f0a68139ee958dcf6
|
4
|
+
data.tar.gz: d010ba705cca4e1c78c87b782e17faab10f3c3f1008a5337ff2345634053e0bc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fedcc696e77cd58fb6a53b24d1eb24482c487e239bbf3e1c6470c66480f5e7f29fc8bd4ab178deb13c010cac2284a21a191c8025870961c4182ffcf212c03c03
|
7
|
+
data.tar.gz: 10a6ca261845b1d773b941da11fc1abffa37ee910fe1175bc5fa9a716a213ab38c70056e44d3d73e2a891ce9c3747243f00342d0a8c3ff8076e373ebeceb3b42
|
data/.github/workflows/ruby.yml
CHANGED
@@ -0,0 +1,42 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# Start a develop UAA with default profile or add client with allowpublic=true
|
4
|
+
# uaac client add login -s loginsecret \
|
5
|
+
# --authorized_grant_types authorization_code,refresh_token \
|
6
|
+
# --scope "openid" \
|
7
|
+
# --authorities uaa.none \
|
8
|
+
# --allowpublic true \
|
9
|
+
# --redirect_uri=http://localhost:7000/callback
|
10
|
+
|
11
|
+
require 'uaa'
|
12
|
+
require 'cgi'
|
13
|
+
|
14
|
+
url = ENV["UAA_URL"] || 'http://localhost:8080/uaa'
|
15
|
+
client = "login"
|
16
|
+
secret = nil
|
17
|
+
|
18
|
+
def show(title, object)
|
19
|
+
puts "#{title}: #{object.inspect}"
|
20
|
+
puts
|
21
|
+
end
|
22
|
+
|
23
|
+
uaa_options = { skip_ssl_validation: true, use_pkce:true, client_auth_method: 'none'}
|
24
|
+
uaa_options[:ssl_ca_file] = ENV["UAA_CA_CERT_FILE"] if ENV["UAA_CA_CERT_FILE"]
|
25
|
+
show "uaa_options", uaa_options
|
26
|
+
|
27
|
+
uaa_info = CF::UAA::Info.new(url, uaa_options)
|
28
|
+
show "UAA server info", uaa_info.server
|
29
|
+
|
30
|
+
token_issuer = CF::UAA::TokenIssuer.new(url, client, secret, uaa_options)
|
31
|
+
auth_uri = token_issuer.authcode_uri("http://localhost:7000/callback", nil)
|
32
|
+
show "UAA authorization URL", auth_uri
|
33
|
+
|
34
|
+
puts "Enter Callback URL: "
|
35
|
+
callback_url = gets
|
36
|
+
show "Perform Token Request with: ", callback_url
|
37
|
+
|
38
|
+
token = token_issuer.authcode_grant(auth_uri, URI.parse(callback_url).query.to_s)
|
39
|
+
show "User authorization grant", token
|
40
|
+
|
41
|
+
token_info = CF::UAA::TokenCoder.decode(token.info["access_token"], nil, nil, false) #token signature not verified
|
42
|
+
show "Decoded access token", token_info
|
data/lib/uaa/token_issuer.rb
CHANGED
@@ -12,6 +12,7 @@
|
|
12
12
|
#++
|
13
13
|
|
14
14
|
require 'securerandom'
|
15
|
+
require "digest"
|
15
16
|
require 'uaa/http'
|
16
17
|
require 'cgi'
|
17
18
|
|
@@ -53,6 +54,7 @@ class TokenIssuer
|
|
53
54
|
include Http
|
54
55
|
|
55
56
|
private
|
57
|
+
@client_auth_method = 'client_secret_basic'
|
56
58
|
|
57
59
|
def random_state; SecureRandom.hex end
|
58
60
|
|
@@ -74,8 +76,15 @@ class TokenIssuer
|
|
74
76
|
params[:scope] = Util.strlist(scope)
|
75
77
|
end
|
76
78
|
headers = {'content-type' => FORM_UTF8, 'accept' => JSON_UTF8}
|
77
|
-
if @
|
78
|
-
|
79
|
+
if @client_auth_method == 'client_secret_basic' && @client_secret && @client_id
|
80
|
+
if @basic_auth
|
81
|
+
headers['authorization'] = Http.basic_auth(@client_id, @client_secret)
|
82
|
+
else
|
83
|
+
headers['X-CF-ENCODED-CREDENTIALS'] = 'true'
|
84
|
+
headers['authorization'] = Http.basic_auth(CGI.escape(@client_id), CGI.escape(@client_secret))
|
85
|
+
end
|
86
|
+
elsif @client_id && params[:code_verifier]
|
87
|
+
params[:client_id] = @client_id
|
79
88
|
else
|
80
89
|
headers['X-CF-ENCODED-CREDENTIALS'] = 'true'
|
81
90
|
headers['authorization'] = Http.basic_auth(CGI.escape(@client_id || ''), CGI.escape(@client_secret || ''))
|
@@ -91,6 +100,10 @@ class TokenIssuer
|
|
91
100
|
redirect_uri: redirect_uri, state: state)
|
92
101
|
params[:scope] = scope = Util.strlist(scope) if scope = Util.arglist(scope)
|
93
102
|
params[:nonce] = state
|
103
|
+
if not @code_verifier.nil?
|
104
|
+
params[:code_challenge] = get_challenge
|
105
|
+
params[:code_challenge_method] = 'S256'
|
106
|
+
end
|
94
107
|
"/oauth/authorize?#{Util.encode_form(params)}"
|
95
108
|
end
|
96
109
|
|
@@ -116,6 +129,11 @@ class TokenIssuer
|
|
116
129
|
@token_target = options[:token_target] || target
|
117
130
|
@key_style = options[:symbolize_keys] ? :sym : nil
|
118
131
|
@basic_auth = options[:basic_auth] == true ? true : false
|
132
|
+
@client_auth_method = options[:client_auth_method] || 'client_secret_basic'
|
133
|
+
@code_verifier = options[:code_verifier] || nil
|
134
|
+
if @code_verifier.nil? && options[:use_pkce] && options[:use_pkce] == true
|
135
|
+
@code_verifier = get_verifier
|
136
|
+
end
|
119
137
|
initialize_http_options(options)
|
120
138
|
end
|
121
139
|
|
@@ -235,8 +253,27 @@ class TokenIssuer
|
|
235
253
|
rescue URI::InvalidURIError, ArgumentError, BadResponse
|
236
254
|
raise BadResponse, "received invalid response from target #{@target}"
|
237
255
|
end
|
238
|
-
|
239
|
-
|
256
|
+
if not @code_verifier.nil?
|
257
|
+
request_token(grant_type: 'authorization_code', code: authcode,
|
258
|
+
redirect_uri: ac_params['redirect_uri'], code_verifier: @code_verifier)
|
259
|
+
else
|
260
|
+
request_token(grant_type: 'authorization_code', code: authcode,
|
261
|
+
redirect_uri: ac_params['redirect_uri'])
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
# Generates a random verifier for PKCE usage
|
266
|
+
def get_verifier
|
267
|
+
if not @code_verifier.nil?
|
268
|
+
@verifier = @code_verifier
|
269
|
+
else
|
270
|
+
@verifier ||= SecureRandom.base64(96).tr("+/", "-_").tr("=", "")
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
# Calculates the challenge from code_verifier
|
275
|
+
def get_challenge
|
276
|
+
@challenge ||= Digest::SHA256.base64digest(get_verifier).tr("+/", "-_").tr("=", "")
|
240
277
|
end
|
241
278
|
|
242
279
|
# Uses the instance client credentials in addition to the +username+
|
data/lib/uaa/version.rb
CHANGED
data/spec/token_issuer_spec.rb
CHANGED
@@ -264,6 +264,7 @@ describe TokenIssuer do
|
|
264
264
|
end
|
265
265
|
|
266
266
|
context 'with auth code grant' do
|
267
|
+
let(:options) { {use_pkce: true} }
|
267
268
|
|
268
269
|
it 'gets the authcode uri to be sent to the user agent for an authcode' do
|
269
270
|
redir_uri = 'http://call.back/uri_path'
|
@@ -275,6 +276,8 @@ describe TokenIssuer do
|
|
275
276
|
params['scope'].should == 'openid'
|
276
277
|
params['redirect_uri'].should == redir_uri
|
277
278
|
params['state'].should_not be_nil
|
279
|
+
params['code_challenge'].should =~ /^[0-9A-Za-z_-]{43}$/i
|
280
|
+
params['code_challenge_method'].should == 'S256'
|
278
281
|
end
|
279
282
|
|
280
283
|
it 'gets an access token with an authorization code' do
|
@@ -292,6 +295,10 @@ describe TokenIssuer do
|
|
292
295
|
cburi = 'http://call.back/uri_path'
|
293
296
|
redir_uri = subject.authcode_uri(cburi)
|
294
297
|
state = /state=([^&]+)/.match(redir_uri)[1]
|
298
|
+
challenge = /code_challenge=([^&]+)/.match(redir_uri)[1]
|
299
|
+
challenge.should =~ /^[0-9A-Za-z_-]{43}$/i
|
300
|
+
challenge_method = /code_challenge_method=([^&]+)/.match(redir_uri)[1]
|
301
|
+
challenge_method.should == 'S256'
|
295
302
|
reply_query = "state=#{state}&code=kz8%2F5gQZ2pc%3D"
|
296
303
|
token = subject.authcode_grant(redir_uri, reply_query)
|
297
304
|
token.should be_an_instance_of TokenInfo
|
@@ -303,6 +310,34 @@ describe TokenIssuer do
|
|
303
310
|
|
304
311
|
end
|
305
312
|
|
313
|
+
context 'pkce with own code verifier' do
|
314
|
+
let(:options) { {basic_auth: false, code_verifier: 'umoq1e_4XMYXvfHlaO9mSlSI17OKfxnwfR5ZD-oYreFxyn8yQZ-ZHPZfUZ4n3WjY_tkOB_MAisSy4ddqsa6aoTU5ZOcX4ps3de933PczYlC8pZpKL8EQWaDZOnpOyB2W'} }
|
315
|
+
|
316
|
+
it 'calculate code_challenge on existing verifier' do
|
317
|
+
redir_uri = 'http://call.back/uri_path'
|
318
|
+
uri_parts = subject.authcode_uri(redir_uri, 'openid').split('?')
|
319
|
+
code_challenge = subject.get_challenge
|
320
|
+
code_verifier = subject.get_verifier
|
321
|
+
params = Util.decode_form(uri_parts[1])
|
322
|
+
params['code_challenge'].should == code_challenge
|
323
|
+
params['code_challenge_method'].should == 'S256'
|
324
|
+
code_verifier.should == options[:code_verifier]
|
325
|
+
code_challenge.should == 'TAnM2AKGgiQKOC16cRpMdF_55qwmz3B333cq6T18z0s'
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
context 'no pkce active as this is the default' do
|
330
|
+
#let(:options) { {use_pkce: false} }
|
331
|
+
# by default PKCE is off
|
332
|
+
it 'no code pkce generation with an authorization code' do
|
333
|
+
redir_uri = 'http://call.back/uri_path'
|
334
|
+
uri_parts = subject.authcode_uri(redir_uri, 'openid').split('?')
|
335
|
+
params = Util.decode_form(uri_parts[1])
|
336
|
+
params['code_challenge'].should_not
|
337
|
+
params['code_challenge_method'].should_not
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
306
341
|
end
|
307
342
|
|
308
343
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cf-uaa-lib
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.0.
|
4
|
+
version: 4.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dave Syer
|
@@ -12,7 +12,7 @@ authors:
|
|
12
12
|
autorequire:
|
13
13
|
bindir: bin
|
14
14
|
cert_chain: []
|
15
|
-
date: 2023-
|
15
|
+
date: 2023-09-08 00:00:00.000000000 Z
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
18
18
|
name: multi_json
|
@@ -237,6 +237,7 @@ files:
|
|
237
237
|
- README.md
|
238
238
|
- Rakefile
|
239
239
|
- cf-uaa-lib.gemspec
|
240
|
+
- examples/authorization_grant_public_pkce.rb
|
240
241
|
- examples/password_grant_and_decode_token.rb
|
241
242
|
- lib/uaa.rb
|
242
243
|
- lib/uaa/http.rb
|