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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7b74dffd99890350b0ed57b02a6a79343e47967be405bf6fc48e0630f534e6d3
4
- data.tar.gz: 229fb7742d1503f18bb6a9097741c11b4de378e68e9ea66f198645031d92d381
3
+ metadata.gz: 9eebcd4d0b7e5068266fceab3b4686335b5446bb18a6bf4f0a68139ee958dcf6
4
+ data.tar.gz: d010ba705cca4e1c78c87b782e17faab10f3c3f1008a5337ff2345634053e0bc
5
5
  SHA512:
6
- metadata.gz: 0d2b41fbb96a3fbf94aa5e27ea7f5f408bd7c23c7555736a01750970b5a52672ae9318376a7615141ab2a777def229d587a431f887be67247747bc230b18a2fd
7
- data.tar.gz: 5ccb01cb63301c8abf33a11a1fbb3bba8e3ccc40d200e8b7ae12106cb8a6320c4ba5be912858cbfa25dadde377e2b859aaad8c60dcd27673d046801b40be4564
6
+ metadata.gz: fedcc696e77cd58fb6a53b24d1eb24482c487e239bbf3e1c6470c66480f5e7f29fc8bd4ab178deb13c010cac2284a21a191c8025870961c4182ffcf212c03c03
7
+ data.tar.gz: 10a6ca261845b1d773b941da11fc1abffa37ee910fe1175bc5fa9a716a213ab38c70056e44d3d73e2a891ce9c3747243f00342d0a8c3ff8076e373ebeceb3b42
@@ -11,7 +11,7 @@ jobs:
11
11
  packages: write
12
12
 
13
13
  steps:
14
- - uses: actions/checkout@v3
14
+ - uses: actions/checkout@v4
15
15
  - name: Set up Ruby 2.6
16
16
  uses: ruby/setup-ruby@v1
17
17
  with:
@@ -15,7 +15,7 @@ jobs:
15
15
  ruby-version: ['2.5', '2.7', '3.0', '3.1', '3.2']
16
16
 
17
17
  steps:
18
- - uses: actions/checkout@v3
18
+ - uses: actions/checkout@v4
19
19
  - name: Set up Ruby
20
20
  uses: ruby/setup-ruby@v1
21
21
  with:
@@ -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
@@ -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 @basic_auth
78
- headers['authorization'] = Http.basic_auth(@client_id, @client_secret)
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
- request_token(grant_type: 'authorization_code', code: authcode,
239
- redirect_uri: ac_params['redirect_uri'])
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
@@ -14,6 +14,6 @@
14
14
  # Cloud Foundry namespace
15
15
  module CF
16
16
  module UAA
17
- VERSION = '4.0.2'
17
+ VERSION = '4.0.3'
18
18
  end
19
19
  end
@@ -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.2
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-05-10 00:00:00.000000000 Z
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