cf-uaa-lib 4.0.9 → 4.0.10

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: b1bef252c395d0a9dfbd30cb9b4e60be278d01ae09b496d97d7f8665ff273ba5
4
- data.tar.gz: 0bfd4b2af11ca2261e399bf2c73e4710ba49de67fed16766e22ac110cac19ad9
3
+ metadata.gz: 749fd6ab4d2b12f32a72cd0b15a573c051c42c779676c9c4a0f9582a74d13836
4
+ data.tar.gz: acbdddc308c40af517a356ffa492160ca39c5b97c84da512b2be966f184c329c
5
5
  SHA512:
6
- metadata.gz: c7ebce508854b456f17ca0980cbaa10326cc472c81008d0956d5c70401bd671a17a959ab41e6e3d1a4829819985daa9076f4a627c399726249fad9104aa9c787
7
- data.tar.gz: 0d2a4528589995a7e5b9cf4badef1e8612232fdc07fa1af02bc5ee8d7211ad2e94489af2332f2a4e7271ea0d2bb0e8000361d6f8a446596c070618cc7e8974c9
6
+ metadata.gz: 8f1f81e5eff52915a9cb233b56dc00ead5ff773c4311f76434e516cce33277afa13c3956212686e43e781333451085a259c5fa7a816d2eb6e8c5b439c57e8868
7
+ data.tar.gz: 451e6cb18fdd7226f320bca418a5e243c6c6e9768dafa57063f6236217178d23f775fb72a176dfa7f750469a0e25c7c4524ff7598c2a5f50f0b113aad31b1497
@@ -13,7 +13,7 @@ jobs:
13
13
 
14
14
  steps:
15
15
  # Set up
16
- - uses: actions/checkout@v4
16
+ - uses: actions/checkout@v7
17
17
  - name: Set up Ruby
18
18
  uses: ruby/setup-ruby@v1
19
19
  with:
@@ -11,11 +11,12 @@ jobs:
11
11
 
12
12
  runs-on: ubuntu-latest
13
13
  strategy:
14
+ fail-fast: false
14
15
  matrix:
15
- ruby-version: ['2.5', '2.7', '3.1', '3.2', '3.3', '3.4']
16
+ ruby-version: ['3.3', '3.4', '4.0']
16
17
 
17
18
  steps:
18
- - uses: actions/checkout@v4
19
+ - uses: actions/checkout@v7
19
20
  - name: Set up Ruby
20
21
  uses: ruby/setup-ruby@v1
21
22
  with:
data/cf-uaa-lib.gemspec CHANGED
@@ -25,6 +25,7 @@ Gem::Specification.new do |s|
25
25
  s.description = %q{Client library for interacting with the CloudFoundry User Account and Authorization (UAA) server. The UAA is an OAuth2 Authorization Server so it can be used by webapps and command line apps to obtain access tokens to act on behalf of users. The tokens can then be used to access protected resources in a Resource Server. This library is for use by UAA client applications or resource servers.}
26
26
 
27
27
  s.license = "Apache-2.0"
28
+ s.required_ruby_version = '>= 3.3'
28
29
  s.files = `git ls-files`.split("\n")
29
30
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
30
31
  s.executables = `git ls-files -- bin/*`.split('\n').map{ |f| File.basename(f) }
@@ -34,10 +35,11 @@ Gem::Specification.new do |s|
34
35
  s.add_dependency 'json', '~>2.7'
35
36
  s.add_dependency 'mutex_m'
36
37
  s.add_dependency 'base64'
38
+ s.add_dependency 'logger'
37
39
  s.add_dependency 'httpclient', '~> 2.8', '>= 2.8.2.4'
38
40
  s.add_dependency 'addressable', '~> 2.8', '>= 2.8.0'
39
41
 
40
- s.add_development_dependency 'bundler', '~> 2.2'
42
+ s.add_development_dependency 'bundler', '>= 2.2'
41
43
  s.add_development_dependency 'rake', '>= 10.3.2', '~> 13.0'
42
44
  s.add_development_dependency 'rspec', '>= 2.14.1', '~> 3.9'
43
45
  s.add_development_dependency 'simplecov', '~> 0.22.0'
data/lib/uaa/http.rb CHANGED
@@ -184,7 +184,7 @@ module Http
184
184
  raise SSLException, "Invalid SSL Cert for #{url}. Use '--skip-ssl-validation' to continue with an insecure target"
185
185
  rescue URI::Error, SocketError, SystemCallError => e
186
186
  raise BadTarget, "error: #{e.message}"
187
- rescue HTTPClient::ConnectTimeoutError => e
187
+ rescue HTTPClient::ConnectTimeoutError, HTTPClient::ReceiveTimeoutError
188
188
  raise HTTPException.new "http timeout"
189
189
  end
190
190
 
@@ -75,6 +75,8 @@ class TokenIssuer
75
75
  if scope = Util.arglist(params.delete(:scope))
76
76
  params[:scope] = Util.strlist(scope)
77
77
  end
78
+ client_assertion = params[:client_assertion]
79
+ params.delete(:client_assertion)
78
80
  headers = {'content-type' => FORM_UTF8, 'accept' => JSON_UTF8}
79
81
  if @client_auth_method == 'client_secret_basic' && @client_secret && @client_id
80
82
  if @basic_auth
@@ -88,6 +90,10 @@ class TokenIssuer
88
90
  params[:client_secret] = @client_secret
89
91
  elsif @client_id && params[:code_verifier]
90
92
  params[:client_id] = @client_id
93
+ elsif client_assertion && @client_id && @client_secret.nil?
94
+ params[:client_id] = @client_id
95
+ params[:client_assertion] = client_assertion
96
+ params[:client_assertion_type] = 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer'
91
97
  else
92
98
  headers['X-CF-ENCODED-CREDENTIALS'] = 'true'
93
99
  headers['authorization'] = Http.basic_auth(CGI.escape(@client_id || ''), CGI.escape(@client_secret || ''))
@@ -129,6 +135,7 @@ class TokenIssuer
129
135
  # * +:symbolize_keys+, if true, returned hash keys are symbols.
130
136
  def initialize(target, client_id, client_secret = nil, options = {})
131
137
  @target, @client_id, @client_secret = target, client_id, client_secret
138
+ @client_assertion = options[:client_assertion] || nil
132
139
  @token_target = options[:token_target] || target
133
140
  @key_style = options[:symbolize_keys] ? :sym : nil
134
141
  @basic_auth = options[:basic_auth] == true ? true : false
@@ -310,8 +317,8 @@ class TokenIssuer
310
317
  # Uses the instance client credentials to get a token with a client
311
318
  # credentials grant. See http://tools.ietf.org/html/rfc6749#section-4.4
312
319
  # @return [TokenInfo]
313
- def client_credentials_grant(scope = nil)
314
- request_token(grant_type: 'client_credentials', scope: scope)
320
+ def client_credentials_grant(scope = nil, client_assertion = nil)
321
+ request_token(grant_type: 'client_credentials', scope: scope, client_assertion: client_assertion)
315
322
  end
316
323
 
317
324
  # Uses the instance client credentials and the given +refresh_token+ to get
@@ -321,6 +328,15 @@ class TokenIssuer
321
328
  request_token(grant_type: 'refresh_token', refresh_token: refresh_token, scope: scope)
322
329
  end
323
330
 
331
+ # Gets an access token with the user assertion used for authentication
332
+ # via the jwt bearer authorization grant.
333
+ # See {http://tools.ietf.org/html/rfc7523#section-2.1}.
334
+ # @param assertion should be an id_token from a previous IdP token request
335
+ # @return [TokenInfo]
336
+ def jwt_bearer_grant(assertion, scope = nil, client_assertion = nil)
337
+ request_token(grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer', assertion: assertion, scope: scope, client_assertion: client_assertion)
338
+ end
339
+
324
340
  end
325
341
 
326
342
  end
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.9'
17
+ VERSION = '4.0.10'
18
18
  end
19
19
  end
data/spec/scim_spec.rb CHANGED
@@ -297,9 +297,9 @@ describe Scim do
297
297
  method.should == :get
298
298
  check_headers(headers, nil, :json, nil)
299
299
 
300
- query_params = CGI::parse(URI.parse(url).query)
301
- start_index = query_params['startIndex'].first
302
- count = query_params['count'].first
300
+ query_params = URI.decode_www_form(URI.parse(url).query).to_h
301
+ start_index = query_params['startIndex']
302
+ count = query_params['count']
303
303
 
304
304
  start_index.should == '3'
305
305
  count.should == '10'
@@ -345,6 +345,37 @@ describe TokenIssuer do
345
345
  end
346
346
  end
347
347
 
348
+ context 'with client_assertion using client credentials grant' do
349
+ let(:client_id) { 'test_client' }
350
+ let(:client_secret) { nil }
351
+
352
+ it 'use client_secret_post in authorization code and expect client_id and secret in body' do
353
+ subject.set_request_handler do |url, method, body, headers|
354
+ headers['content-type'].should =~ /application\/x-www-form-urlencoded/
355
+ headers['accept'].should =~ /application\/json/
356
+ headers['X-CF-ENCODED-CREDENTIALS'].should_not
357
+ headers['authorization'].should_not
358
+ params = Util.decode_form(body)
359
+ params['grant_type'].should == 'client_credentials'
360
+ params['client_id'].should == 'test_client'
361
+ params['client_assertion'].should == 'any-jwt-token'
362
+ params['client_assertion_type'].should == 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer'
363
+ params['client_secret'].should_not
364
+ url.should match 'http://test.uaa.target/oauth/token'
365
+ method.should == :post
366
+ reply = {access_token: 'test_access_token', token_type: 'BEARER',
367
+ scope: 'logs.read', expires_in: 98765}
368
+ [200, Util.json(reply), {'content-type' => 'application/json'}]
369
+ end
370
+ token = subject.client_credentials_grant('logs.read', 'any-jwt-token')
371
+ token.should be_an_instance_of TokenInfo
372
+ token.info['access_token'].should == 'test_access_token'
373
+ token.info['token_type'].should =~ /^bearer$/i
374
+ token.info['scope'].should == 'logs.read'
375
+ token.info['expires_in'].should == 98765
376
+ end
377
+ end
378
+
348
379
  context 'pkce with own code verifier' do
349
380
  let(:options) { {basic_auth: false, code_verifier: 'umoq1e_4XMYXvfHlaO9mSlSI17OKfxnwfR5ZD-oYreFxyn8yQZ-ZHPZfUZ4n3WjY_tkOB_MAisSy4ddqsa6aoTU5ZOcX4ps3de933PczYlC8pZpKL8EQWaDZOnpOyB2W'} }
350
381
 
@@ -439,6 +470,55 @@ describe TokenIssuer do
439
470
  end
440
471
  end
441
472
 
473
+ context 'with jwt bearer grant' do
474
+
475
+ it 'gets a token with jwt bearer' do
476
+ subject.set_request_handler do |url, method, body, headers|
477
+ headers['content-type'].should =~ /application\/x-www-form-urlencoded/
478
+ headers['accept'].should =~ /application\/json/
479
+ headers['X-CF-ENCODED-CREDENTIALS'].should == 'true'
480
+ headers['authorization'].should == 'Basic dGVzdF9jbGllbnQ6dGVzdCUyMXNlY3JldA=='
481
+ url.should == 'http://test.uaa.target/oauth/token'
482
+ method.should == :post
483
+ reply = {access_token: 'test_access_token', token_type: 'BEARER',
484
+ scope: 'openid', expires_in: 98765}
485
+ [200, Util.json(reply), {'content-type' => 'application/json'}]
486
+ end
487
+ token = subject.jwt_bearer_grant('assertion', 'openid')
488
+ token.should be_an_instance_of TokenInfo
489
+ token.info['access_token'].should == 'test_access_token'
490
+ token.info['token_type'].should =~ /^bearer$/i
491
+ token.info['scope'].should == 'openid'
492
+ token.info['expires_in'].should == 98765
493
+ end
494
+
495
+ context "when client & client secret are nil" do
496
+ let(:client_id) { nil }
497
+ let(:client_secret) { nil }
498
+
499
+ it 'does not error' do
500
+ subject.set_request_handler do |url, method, body, headers|
501
+ headers['content-type'].should =~ /application\/x-www-form-urlencoded/
502
+ headers['accept'].should =~ /application\/json/
503
+ headers['X-CF-ENCODED-CREDENTIALS'].should == 'true'
504
+ headers['authorization'].should == 'Basic Og=='
505
+ url.should == 'http://test.uaa.target/oauth/token'
506
+ method.should == :post
507
+ reply = {access_token: 'test_access_token', token_type: 'BEARER',
508
+ scope: 'openid', expires_in: 98765}
509
+ [200, Util.json(reply), {'content-type' => 'application/json'}]
510
+ end
511
+ token = subject.jwt_bearer_grant('assertion', 'openid')
512
+ token.should be_an_instance_of TokenInfo
513
+ token.info['access_token'].should == 'test_access_token'
514
+ token.info['token_type'].should =~ /^bearer$/i
515
+ token.info['scope'].should == 'openid'
516
+ token.info['expires_in'].should == 98765
517
+ end
518
+ end
519
+
520
+ end
521
+
442
522
  end
443
523
 
444
524
  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.9
4
+ version: 4.0.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dave Syer
@@ -11,7 +11,7 @@ authors:
11
11
  - Luke Taylor
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2025-02-19 00:00:00.000000000 Z
14
+ date: 1980-01-02 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: json
@@ -55,6 +55,20 @@ dependencies:
55
55
  - - ">="
56
56
  - !ruby/object:Gem::Version
57
57
  version: '0'
58
+ - !ruby/object:Gem::Dependency
59
+ name: logger
60
+ requirement: !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: '0'
65
+ type: :runtime
66
+ prerelease: false
67
+ version_requirements: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: '0'
58
72
  - !ruby/object:Gem::Dependency
59
73
  name: httpclient
60
74
  requirement: !ruby/object:Gem::Requirement
@@ -99,14 +113,14 @@ dependencies:
99
113
  name: bundler
100
114
  requirement: !ruby/object:Gem::Requirement
101
115
  requirements:
102
- - - "~>"
116
+ - - ">="
103
117
  - !ruby/object:Gem::Version
104
118
  version: '2.2'
105
119
  type: :development
106
120
  prerelease: false
107
121
  version_requirements: !ruby/object:Gem::Requirement
108
122
  requirements:
109
- - - "~>"
123
+ - - ">="
110
124
  - !ruby/object:Gem::Version
111
125
  version: '2.2'
112
126
  - !ruby/object:Gem::Dependency
@@ -266,14 +280,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
266
280
  requirements:
267
281
  - - ">="
268
282
  - !ruby/object:Gem::Version
269
- version: '0'
283
+ version: '3.3'
270
284
  required_rubygems_version: !ruby/object:Gem::Requirement
271
285
  requirements:
272
286
  - - ">="
273
287
  - !ruby/object:Gem::Version
274
288
  version: '0'
275
289
  requirements: []
276
- rubygems_version: 3.6.2
290
+ rubygems_version: 4.0.10
277
291
  specification_version: 4
278
292
  summary: Client library for CloudFoundry UAA
279
293
  test_files: []