cf-uaa-lib 3.13.0 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 4d3d4edc855be886efe312cfb0665894dffaf332
4
- data.tar.gz: 6d07a2957fc5efbfa31f810a1b693dca77abf871
2
+ SHA256:
3
+ metadata.gz: e8a741ef102742885eff043d198628e3bc05f0bcc98c752a57ce5f6b3c18bf43
4
+ data.tar.gz: 6ffc61520e49b04d65bd0404f577727986e3f625e6ef095fc8a0d361c50be5ab
5
5
  SHA512:
6
- metadata.gz: 546a2c90f033dd94bee5dd3fd8fa0db9d6877bc32e6e3eed25f967a0d8dafa80f27ac4ff9008a6cbd90bfb62c1e3df15cf4e9a90c5329da830ca379fb06436c0
7
- data.tar.gz: e172dbce6c01966def32c6a2cf8cad737a43b61a94b97abfbc500ee38859689a02fec76f8d8ec4ada5c001ff11d40c2d32476e3ee72725633cad701427211693
6
+ metadata.gz: 75d8062f4bdc94bc7375a18124f72b3664a2d4074a63699c4e55f52ae085375ae587e7c113859b345bd7476878d744ceb66320cd42ccc9ef3e02f0315e591f78
7
+ data.tar.gz: 223a89a483dfe638062240e4326e8c8e485b62a1e07108ed87feb5fff67ce1f5a705923939f23d6135bd4eeb6f8638cd60ae7638cc62ff2e1376aafe94720051
@@ -0,0 +1,11 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: bundler
4
+ directory: "/"
5
+ schedule:
6
+ interval: daily
7
+ time: "11:00"
8
+ open-pull-requests-limit: 10
9
+ allow:
10
+ - dependency-type: direct
11
+ - dependency-type: indirect
@@ -0,0 +1,29 @@
1
+ name: Ruby Gem
2
+
3
+ on: workflow_dispatch
4
+
5
+ jobs:
6
+ build:
7
+ name: Build + Publish
8
+ runs-on: ubuntu-latest
9
+ permissions:
10
+ contents: read
11
+ packages: write
12
+
13
+ steps:
14
+ - uses: actions/checkout@v2
15
+ - name: Set up Ruby 2.6
16
+ uses: actions/setup-ruby@v1
17
+ with:
18
+ ruby-version: 2.6.x
19
+
20
+ - name: Publish to RubyGems
21
+ run: |
22
+ mkdir -p $HOME/.gem
23
+ touch $HOME/.gem/credentials
24
+ chmod 0600 $HOME/.gem/credentials
25
+ printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
26
+ gem build *.gemspec
27
+ gem push *.gem
28
+ env:
29
+ GEM_HOST_API_KEY: "${{ secrets.RUBYGEMS_AUTH_TOKEN }}"
@@ -0,0 +1,27 @@
1
+ name: Ruby
2
+
3
+ on:
4
+ push:
5
+ branches: [ master ]
6
+ pull_request:
7
+ branches: [ master ]
8
+
9
+ jobs:
10
+ test:
11
+
12
+ runs-on: ubuntu-latest
13
+ strategy:
14
+ matrix:
15
+ ruby-version: ['2.5', '2.7', '3.0', '3.1']
16
+
17
+ steps:
18
+ - uses: actions/checkout@v2
19
+ - name: Set up Ruby
20
+ uses: ruby/setup-ruby@v1
21
+ with:
22
+ ruby-version: ${{ matrix.ruby-version }}
23
+ bundler-cache: true # runs 'bundle install' and caches installed gems automatically
24
+ - name: Run tests
25
+ run: bundle exec rake
26
+ - name: Run coverage
27
+ run: bundle exec rake cov
data/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  # CloudFoundry UAA Gem
2
- [![Build Status](https://travis-ci.org/cloudfoundry/cf-uaa-lib.png)](https://travis-ci.org/cloudfoundry/cf-uaa-lib)
2
+ ![Build status](https://github.com/cloudfoundry/cf-uaa-lib/actions/workflows/ruby.yml/badge.svg?branch=master)
3
3
  [![Gem Version](https://badge.fury.io/rb/cf-uaa-lib.png)](http://badge.fury.io/rb/cf-uaa-lib)
4
4
 
5
5
  Client gem for interacting with the [CloudFoundry UAA server](https://github.com/cloudfoundry/uaa)
data/cf-uaa-lib.gemspec CHANGED
@@ -24,8 +24,6 @@ Gem::Specification.new do |s|
24
24
  s.summary = %q{Client library for CloudFoundry UAA}
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
- s.rubyforge_project = "cf-uaa-lib"
28
-
29
27
  s.license = "Apache-2.0"
30
28
  s.files = `git ls-files`.split("\n")
31
29
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
@@ -33,15 +31,17 @@ Gem::Specification.new do |s|
33
31
  s.require_paths = ['lib']
34
32
 
35
33
  # dependencies
36
- s.add_dependency 'multi_json', '~> 1.12.0', '>= 1.12.1'
34
+ s.add_dependency 'multi_json', '>= 1.12.1', '< 1.16'
37
35
  s.add_dependency 'httpclient', '~> 2.8', '>= 2.8.2.4'
36
+ s.add_dependency 'addressable', '~> 2.8', '>= 2.8.0'
38
37
 
39
- s.add_development_dependency 'bundler', '~> 1.14'
40
- s.add_development_dependency 'rake', '~> 10.3', '>= 10.3.2'
41
- s.add_development_dependency 'rspec', '~> 2.14', '>= 2.14.1'
42
- s.add_development_dependency 'simplecov', '~> 0.8.2'
38
+ s.add_development_dependency 'bundler', '~> 2.2'
39
+ s.add_development_dependency 'rake', '>= 10.3.2', '~> 13.0'
40
+ s.add_development_dependency 'rspec', '>= 2.14.1', '~> 3.9'
41
+ s.add_development_dependency 'simplecov', '~> 0.21.2'
43
42
  s.add_development_dependency 'simplecov-rcov', '~> 0.2.3'
44
- s.add_development_dependency 'ci_reporter', '~> 1.9', '>= 1.9.2'
45
- s.add_development_dependency 'json_pure', '~> 1.8', '>= 1.8.1'
43
+ s.add_development_dependency 'ci_reporter', '>= 1.9.2', '~> 2.0'
44
+ s.add_development_dependency 'json_pure', '>= 1.8.1', '~> 2.5'
45
+ s.add_development_dependency 'ci_reporter_rspec', '~> 1.0'
46
46
 
47
47
  end
data/lib/uaa/http.rb CHANGED
@@ -48,10 +48,17 @@ module Http
48
48
 
49
49
  def self.included(base)
50
50
  base.class_eval do
51
- attr_accessor :skip_ssl_validation, :ssl_ca_file, :ssl_cert_store, :zone
51
+ attr_reader :skip_ssl_validation, :ssl_ca_file, :ssl_cert_store, :http_timeout
52
52
  end
53
53
  end
54
54
 
55
+ def initialize_http_options(options)
56
+ @skip_ssl_validation = options[:skip_ssl_validation]
57
+ @ssl_ca_file = options[:ssl_ca_file]
58
+ @ssl_cert_store = options[:ssl_cert_store]
59
+ @http_timeout = options[:http_timeout]
60
+ end
61
+
55
62
  # Sets the current logger instance to recieve error messages.
56
63
  # @param [Logger] logr
57
64
  # @return [Logger]
@@ -176,6 +183,8 @@ module Http
176
183
  raise SSLException, "Invalid SSL Cert for #{url}. Use '--skip-ssl-validation' to continue with an insecure target"
177
184
  rescue URI::Error, SocketError, SystemCallError => e
178
185
  raise BadTarget, "error: #{e.message}"
186
+ rescue HTTPClient::ConnectTimeoutError => e
187
+ raise HTTPException.new "http timeout"
179
188
  end
180
189
 
181
190
  def http_request(uri)
@@ -201,6 +210,12 @@ module Http
201
210
  http = HTTPClient.new
202
211
  end
203
212
 
213
+ if http_timeout
214
+ http.connect_timeout = http_timeout
215
+ http.send_timeout = http_timeout
216
+ http.receive_timeout = http_timeout
217
+ end
218
+
204
219
  @http_cache[cache_key] = http
205
220
  end
206
221
 
data/lib/uaa/info.rb CHANGED
@@ -31,10 +31,8 @@ class Info
31
31
  # string keys are returned.
32
32
  def initialize(target, options = {})
33
33
  self.target = target
34
- self.skip_ssl_validation = options[:skip_ssl_validation]
35
- self.ssl_ca_file = options[:ssl_ca_file]
36
- self.ssl_cert_store = options[:ssl_cert_store]
37
34
  self.symbolize_keys = options[:symbolize_keys]
35
+ initialize_http_options(options)
38
36
  end
39
37
 
40
38
  # sets whether the keys in returned hashes should be symbols.
@@ -56,14 +54,6 @@ class Info
56
54
  json_get(target, "/userinfo?schema=openid", key_style, "authorization" => auth_header)
57
55
  end
58
56
 
59
- # Gets various monitoring and status variables from the server.
60
- # Authenticates using +name+ and +pwd+ for basic authentication.
61
- # @param (see Misc.server)
62
- # @return [Hash]
63
- def varz(name, pwd)
64
- json_get(target, "/varz", key_style, "authorization" => Http.basic_auth(name, pwd))
65
- end
66
-
67
57
  # Gets basic information about the target server, including version number,
68
58
  # commit ID, and links to API endpoints.
69
59
  # @return [Hash]
@@ -131,7 +121,7 @@ class Info
131
121
  # @return [Hash] contents of the token
132
122
  def decode_token(client_id, client_secret, token, token_type = "bearer", audience_ids = nil)
133
123
  reply = json_parse_reply(key_style, *request(target, :post, '/check_token',
134
- Util.encode_form(:token => token),
124
+ Util.encode_form(token: token),
135
125
  "authorization" => Http.basic_auth(client_id, client_secret),
136
126
  "content-type" => Http::FORM_UTF8,"accept" => Http::JSON_UTF8))
137
127
 
@@ -148,7 +138,7 @@ class Info
148
138
  # @return [Hash]
149
139
  def password_strength(password)
150
140
  json_parse_reply(key_style, *request(target, :post, '/password/score',
151
- Util.encode_form(:password => password), "content-type" => Http::FORM_UTF8,
141
+ Util.encode_form(password: password), "content-type" => Http::FORM_UTF8,
152
142
  "accept" => Http::JSON_UTF8))
153
143
  end
154
144
 
data/lib/uaa/scim.rb CHANGED
@@ -12,7 +12,7 @@
12
12
  #++
13
13
 
14
14
  require 'uaa/http'
15
- require 'uri'
15
+ require 'addressable/uri'
16
16
 
17
17
  module CF::UAA
18
18
 
@@ -149,10 +149,8 @@ class Scim
149
149
  def initialize(target, auth_header, options = {})
150
150
  @target, @auth_header = target, auth_header
151
151
  @key_style = options[:symbolize_keys] ? :downsym : :down
152
- self.skip_ssl_validation = options[:skip_ssl_validation]
153
- self.ssl_ca_file = options[:ssl_ca_file]
154
- self.ssl_cert_store = options[:ssl_cert_store]
155
152
  @zone = options[:zone]
153
+ initialize_http_options(options)
156
154
  end
157
155
 
158
156
  # Convenience method to get the naming attribute, e.g. userName for user,
@@ -179,7 +177,7 @@ class Scim
179
177
  # @param [String] id the id attribute of the SCIM object
180
178
  # @return [nil]
181
179
  def delete(type, id)
182
- http_delete @target, "#{type_info(type, :path)}/#{URI.encode(id)}", @auth_header, @zone
180
+ http_delete @target, "#{type_info(type, :path)}/#{Addressable::URI.encode(id)}", @auth_header, @zone
183
181
  end
184
182
 
185
183
  # Replaces the contents of a SCIM object.
@@ -194,7 +192,7 @@ class Scim
194
192
  hdrs.merge!('if-match' => etag)
195
193
  end
196
194
  reply = json_parse_reply(@key_style,
197
- *json_put(@target, "#{path}/#{URI.encode(id)}", info, hdrs))
195
+ *json_put(@target, "#{path}/#{Addressable::URI.encode(id)}", info, hdrs))
198
196
 
199
197
  # hide client endpoints that are not quite scim compatible
200
198
  type == :client && !reply ? get(type, info['client_id']): reply
@@ -212,7 +210,7 @@ class Scim
212
210
  hdrs.merge!('if-match' => etag)
213
211
  end
214
212
  reply = json_parse_reply(@key_style,
215
- *json_patch(@target, "#{path}/#{URI.encode(id)}", info, hdrs))
213
+ *json_patch(@target, "#{path}/#{Addressable::URI.encode(id)}", info, hdrs))
216
214
 
217
215
  # hide client endpoints that are not quite scim compatible
218
216
  type == :client && !reply ? get(type, info['client_id']): reply
@@ -260,7 +258,7 @@ class Scim
260
258
  # @param (see #delete)
261
259
  # @return (see #add)
262
260
  def get(type, id)
263
- info = json_get(@target, "#{type_info(type, :path)}/#{URI.encode(id)}",
261
+ info = json_get(@target, "#{type_info(type, :path)}/#{Addressable::URI.encode(id)}",
264
262
  @key_style, headers)
265
263
 
266
264
  fake_client_id(info) if type == :client # hide client reply, not quite scim
@@ -272,7 +270,7 @@ class Scim
272
270
  # @return (client meta)
273
271
  def get_client_meta(client_id)
274
272
  path = type_info(:client, :path)
275
- json_get(@target, "#{path}/#{URI.encode(client_id)}/meta", @key_style, headers)
273
+ json_get(@target, "#{path}/#{Addressable::URI.encode(client_id)}/meta", @key_style, headers)
276
274
  end
277
275
 
278
276
  # Collects all pages of entries from a query
@@ -352,7 +350,7 @@ class Scim
352
350
  req = {"password" => new_password}
353
351
  req["oldPassword"] = old_password if old_password
354
352
  json_parse_reply(@key_style, *json_put(@target,
355
- "#{type_info(:user, :path)}/#{URI.encode(user_id)}/password", req, headers))
353
+ "#{type_info(:user, :path)}/#{Addressable::URI.encode(user_id)}/password", req, headers))
356
354
  end
357
355
 
358
356
  # Change client secret.
@@ -368,18 +366,18 @@ class Scim
368
366
  req = {"secret" => new_secret }
369
367
  req["oldSecret"] = old_secret if old_secret
370
368
  json_parse_reply(@key_style, *json_put(@target,
371
- "#{type_info(:client, :path)}/#{URI.encode(client_id)}/secret", req, headers))
369
+ "#{type_info(:client, :path)}/#{Addressable::URI.encode(client_id)}/secret", req, headers))
372
370
  end
373
371
 
374
372
  def unlock_user(user_id)
375
373
  req = {"locked" => false}
376
374
  json_parse_reply(@key_style, *json_patch(@target,
377
- "#{type_info(:user, :path)}/#{URI.encode(user_id)}/status", req, headers))
375
+ "#{type_info(:user, :path)}/#{Addressable::URI.encode(user_id)}/status", req, headers))
378
376
  end
379
377
 
380
378
  def map_group(group, is_id, external_group, origin = "ldap")
381
379
  key_name = is_id ? :groupId : :displayName
382
- request = {key_name => group, :externalGroup => external_group, :schemas => ["urn:scim:schemas:core:1.0"], :origin => origin }
380
+ request = {key_name => group, externalGroup: external_group, schemas: ["urn:scim:schemas:core:1.0"], origin: origin }
383
381
  result = json_parse_reply(@key_style, *json_post(@target,
384
382
  "#{type_info(:group_mapping, :path)}", request,
385
383
  headers))
@@ -387,7 +385,7 @@ class Scim
387
385
  end
388
386
 
389
387
  def unmap_group(group_id, external_group, origin = "ldap")
390
- http_delete(@target, "#{type_info(:group_mapping, :path)}/groupId/#{group_id}/externalGroup/#{URI.encode(external_group)}/origin/#{origin}",
388
+ http_delete(@target, "#{type_info(:group_mapping, :path)}/groupId/#{group_id}/externalGroup/#{Addressable::URI.encode(external_group)}/origin/#{origin}",
391
389
  @auth_header, @zone)
392
390
  end
393
391
 
@@ -65,7 +65,7 @@ class TokenCoder
65
65
  unless options.is_a?(Hash) && obsolete1.nil? && obsolete2.nil?
66
66
  # deprecated: def self.encode(token_body, skey, pkey = nil, algo = 'HS256')
67
67
  warn "#{self.class}##{__method__} is deprecated with these parameters. Please use options hash."
68
- options = {:skey => options }
68
+ options = {skey: options }
69
69
  options[:pkey], options[:algorithm] = obsolete1, obsolete2
70
70
  end
71
71
  options = normalize_options(options)
@@ -96,7 +96,7 @@ class TokenCoder
96
96
  unless options.is_a?(Hash) && obsolete1.nil? && obsolete2.nil?
97
97
  # deprecated: def self.decode(token, skey = nil, pkey = nil, verify = true)
98
98
  warn "#{self.class}##{__method__} is deprecated with these parameters. Please use options hash."
99
- options = {:skey => options }
99
+ options = {skey: options }
100
100
  options[:pkey], options[:verify] = obsolete1, obsolete2
101
101
  end
102
102
  options = normalize_options(options)
@@ -170,7 +170,7 @@ class TokenCoder
170
170
  unless options.is_a?(Hash) && obsolete1.nil? && obsolete2.nil?
171
171
  # deprecated: def initialize(audience_ids, skey, pkey = nil)
172
172
  warn "#{self.class}##{__method__} is deprecated with these parameters. Please use options hash."
173
- options = {:audience_ids => options }
173
+ options = {audience_ids: options }
174
174
  options[:skey], options[:pkey] = obsolete1, obsolete2
175
175
  end
176
176
  @options = self.class.normalize_options(options)
@@ -184,7 +184,7 @@ class TokenCoder
184
184
  def encode(token_body = {}, algorithm = nil)
185
185
  token_body[:aud] = @options[:audience_ids] if @options[:audience_ids] && !token_body[:aud] && !token_body['aud']
186
186
  token_body[:exp] = Time.now.to_i + 7 * 24 * 60 * 60 unless token_body[:exp] || token_body['exp']
187
- self.class.encode(token_body, algorithm ? @options.merge(:algorithm => algorithm) : @options)
187
+ self.class.encode(token_body, algorithm ? @options.merge(algorithm: algorithm) : @options)
188
188
  end
189
189
 
190
190
  # Returns hash of values decoded from the token contents. If the
@@ -13,6 +13,7 @@
13
13
 
14
14
  require 'securerandom'
15
15
  require 'uaa/http'
16
+ require 'cgi'
16
17
 
17
18
  module CF::UAA
18
19
 
@@ -72,8 +73,13 @@ class TokenIssuer
72
73
  if scope = Util.arglist(params.delete(:scope))
73
74
  params[:scope] = Util.strlist(scope)
74
75
  end
75
- headers = {'content-type' => FORM_UTF8, 'accept' => JSON_UTF8,
76
- 'authorization' => Http.basic_auth(@client_id, @client_secret) }
76
+ headers = {'content-type' => FORM_UTF8, 'accept' => JSON_UTF8}
77
+ if @basic_auth
78
+ headers['authorization'] = Http.basic_auth(@client_id, @client_secret)
79
+ else
80
+ headers['X-CF-ENCODED-CREDENTIALS'] = 'true'
81
+ headers['authorization'] = Http.basic_auth(CGI.escape(@client_id), CGI.escape(@client_secret))
82
+ end
77
83
  reply = json_parse_reply(@key_style, *request(@token_target, :post,
78
84
  '/oauth/token', Util.encode_form(params), headers))
79
85
  raise BadResponse unless reply[jkey :token_type] && reply[jkey :access_token]
@@ -81,8 +87,8 @@ class TokenIssuer
81
87
  end
82
88
 
83
89
  def authorize_path_args(response_type, redirect_uri, scope, state = random_state, args = {})
84
- params = args.merge(:client_id => @client_id, :response_type => response_type,
85
- :redirect_uri => redirect_uri, :state => state)
90
+ params = args.merge(client_id: @client_id, response_type: response_type,
91
+ redirect_uri: redirect_uri, state: state)
86
92
  params[:scope] = scope = Util.strlist(scope) if scope = Util.arglist(scope)
87
93
  params[:nonce] = state
88
94
  "/oauth/authorize?#{Util.encode_form(params)}"
@@ -109,9 +115,8 @@ class TokenIssuer
109
115
  @target, @client_id, @client_secret = target, client_id, client_secret
110
116
  @token_target = options[:token_target] || target
111
117
  @key_style = options[:symbolize_keys] ? :sym : nil
112
- self.skip_ssl_validation = options[:skip_ssl_validation]
113
- self.ssl_ca_file = options[:ssl_ca_file]
114
- self.ssl_cert_store = options[:ssl_cert_store]
118
+ @basic_auth = options[:basic_auth] == true ? true : false
119
+ initialize_http_options(options)
115
120
  end
116
121
 
117
122
  # Allows an app to discover what credentials are required for
@@ -139,7 +144,7 @@ class TokenIssuer
139
144
 
140
145
  # the accept header is only here so the uaa will issue error replies in json to aid debugging
141
146
  headers = {'content-type' => FORM_UTF8, 'accept' => JSON_UTF8 }
142
- body = Util.encode_form(credentials.merge(:source => 'credentials'))
147
+ body = Util.encode_form(credentials.merge(source: 'credentials'))
143
148
  status, body, headers = request(@target, :post, uri, body, headers)
144
149
  raise BadResponse, "status #{status}" unless status == 302
145
150
  req_uri, reply_uri = URI.parse(redir_uri), URI.parse(headers['location'])
@@ -196,7 +201,7 @@ class TokenIssuer
196
201
  reply = json_parse_reply(nil, *request(@target, :post, "/autologin", body, headers))
197
202
  raise BadResponse, "no autologin code in reply" unless reply['code']
198
203
  @target + authorize_path_args('code', redirect_uri, scope,
199
- random_state, :code => reply['code'])
204
+ random_state, code: reply['code'])
200
205
  end
201
206
 
202
207
  # Constructs a uri that the client is to return to the browser to direct
@@ -230,8 +235,8 @@ class TokenIssuer
230
235
  rescue URI::InvalidURIError, ArgumentError, BadResponse
231
236
  raise BadResponse, "received invalid response from target #{@target}"
232
237
  end
233
- request_token(:grant_type => 'authorization_code', :code => authcode,
234
- :redirect_uri => ac_params['redirect_uri'])
238
+ request_token(grant_type: 'authorization_code', code: authcode,
239
+ redirect_uri: ac_params['redirect_uri'])
235
240
  end
236
241
 
237
242
  # Uses the instance client credentials in addition to the +username+
@@ -239,15 +244,15 @@ class TokenIssuer
239
244
  # See {http://tools.ietf.org/html/rfc6749#section-4.3}.
240
245
  # @return [TokenInfo]
241
246
  def owner_password_grant(username, password, scope = nil)
242
- request_token(:grant_type => 'password', :username => username,
243
- :password => password, :scope => scope)
247
+ request_token(grant_type: 'password', username: username,
248
+ password: password, scope: scope)
244
249
  end
245
250
 
246
251
  # Uses a one-time passcode obtained from the UAA to get a
247
252
  # token.
248
253
  # @return [TokenInfo]
249
254
  def passcode_grant(passcode, scope = nil)
250
- request_token(:grant_type => 'password', :passcode => passcode, :scope => scope)
255
+ request_token(grant_type: 'password', passcode: passcode, scope: scope)
251
256
  end
252
257
 
253
258
  # Gets an access token with the user credentials used for authentication
@@ -266,14 +271,14 @@ class TokenIssuer
266
271
  # credentials grant. See http://tools.ietf.org/html/rfc6749#section-4.4
267
272
  # @return [TokenInfo]
268
273
  def client_credentials_grant(scope = nil)
269
- request_token(:grant_type => 'client_credentials', :scope => scope)
274
+ request_token(grant_type: 'client_credentials', scope: scope)
270
275
  end
271
276
 
272
277
  # Uses the instance client credentials and the given +refresh_token+ to get
273
278
  # a new access token. See http://tools.ietf.org/html/rfc6749#section-6
274
279
  # @return [TokenInfo] which may include a new refresh token as well as an access token.
275
280
  def refresh_token_grant(refresh_token, scope = nil)
276
- request_token(:grant_type => 'refresh_token', :refresh_token => refresh_token, :scope => scope)
281
+ request_token(grant_type: 'refresh_token', refresh_token: refresh_token, scope: scope)
277
282
  end
278
283
 
279
284
  end
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, :pretty => true) end
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
@@ -14,6 +14,6 @@
14
14
  # Cloud Foundry namespace
15
15
  module CF
16
16
  module UAA
17
- VERSION = '3.13.0'
17
+ VERSION = '4.0.0'
18
18
  end
19
19
  end
data/spec/http_spec.rb CHANGED
@@ -69,7 +69,7 @@ describe CF::UAA::Http do
69
69
  let(:ssl_config) { double('ssl_config') }
70
70
 
71
71
  it 'sets verify mode to VERIFY_NONE' do
72
- http_instance.skip_ssl_validation = true
72
+ http_instance.initialize_http_options({skip_ssl_validation: true})
73
73
 
74
74
  expect(http_double).to receive(:ssl_config).and_return(ssl_config)
75
75
  expect(ssl_config).to receive(:verify_mode=).with(OpenSSL::SSL::VERIFY_NONE)
@@ -91,7 +91,7 @@ describe CF::UAA::Http do
91
91
  let(:ssl_config) { double('ssl_config') }
92
92
 
93
93
  it 'passes it' do
94
- http_instance.ssl_ca_file = '/fake-ca-file'
94
+ http_instance.initialize_http_options({ssl_ca_file: '/fake-ca-file'})
95
95
 
96
96
  expect(http_double).to receive(:ssl_config).and_return(ssl_config).twice
97
97
  expect(ssl_config).to receive(:set_trust_ca).with('/fake-ca-file')
@@ -105,7 +105,7 @@ describe CF::UAA::Http do
105
105
  let(:ssl_config) { double('ssl_config') }
106
106
 
107
107
  it 'passes it' do
108
- http_instance.ssl_cert_store = cert_store
108
+ http_instance.initialize_http_options({ssl_cert_store: cert_store})
109
109
 
110
110
  expect(http_double).to receive(:ssl_config).and_return(ssl_config).twice
111
111
  expect(ssl_config).to receive(:cert_store=).with(cert_store)
@@ -114,5 +114,29 @@ describe CF::UAA::Http do
114
114
  http_instance.http_get('https://uncached.example.com')
115
115
  end
116
116
  end
117
+
118
+ context 'when an http request timeout is provided' do
119
+ it 'sets all timeouts on the http clien to the http_timeout' do
120
+ http_instance.initialize_http_options({http_timeout: 10})
121
+
122
+ expect(http_double).to receive(:connect_timeout=).with(10)
123
+ expect(http_double).to receive(:send_timeout=).with(10)
124
+ expect(http_double).to receive(:receive_timeout=).with(10)
125
+
126
+ http_instance.http_get('https://uncached.example.com')
127
+ end
128
+ end
129
+
130
+ context 'when an http request timeout is not provided' do
131
+ it 'does not override the default' do
132
+ http_instance.initialize_http_options({})
133
+
134
+ expect(http_double).not_to receive(:connect_timeout=)
135
+ expect(http_double).not_to receive(:send_timeout=)
136
+ expect(http_double).not_to receive(:receive_timeout=)
137
+
138
+ http_instance.http_get('https://uncached.example.com')
139
+ end
140
+ end
117
141
  end
118
- end
142
+ end
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) { {:skip_ssl_validation => true} }
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) { {:symbolize_keys => true} }
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) { {:symbolize_keys => true} }
87
+ let(:options) { {symbolize_keys: true} }
88
88
 
89
89
  it 'gets UAA target' do
90
90
  result = uaa_info.discover_uaa
@@ -41,7 +41,35 @@ 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(:symbolize_keys => true))
44
+ Scim.new(target, admin_token_issuer.client_credentials_grant.auth_header, options.merge(symbolize_keys: true))
45
+ end
46
+
47
+ describe 'when UAA does not respond' do
48
+ let(:http_timeout) { 0.01 }
49
+ let(:default_http_client_timeout) { 60 }
50
+ let(:scim) { Scim.new(@target, "", {http_timeout: http_timeout}) }
51
+ let(:token_issuer) { TokenIssuer.new(@target, "", "", {http_timeout: http_timeout}) }
52
+ let(:blackhole_ip) { '10.255.255.1'}
53
+
54
+ before do
55
+ @target = "http://#{blackhole_ip}"
56
+ end
57
+
58
+ it 'times out the connection at the configured time for the scim' do
59
+ expect {
60
+ Timeout.timeout(default_http_client_timeout - 1) do
61
+ scim.get(:user, "admin")
62
+ end
63
+ }.to raise_error HTTPException
64
+ end
65
+
66
+ it 'times out the connection at the configured time for the token issuer' do
67
+ expect {
68
+ Timeout.timeout(default_http_client_timeout - 1) do
69
+ token_issuer.client_credentials_grant
70
+ end
71
+ }.to raise_error HTTPException
72
+ end
45
73
  end
46
74
 
47
75
  if ENV['UAA_CLIENT_TARGET']
@@ -49,20 +77,20 @@ module CF::UAA
49
77
 
50
78
  let(:options) { @options }
51
79
  let(:token_issuer) { TokenIssuer.new(@target, @test_client, @test_secret, options) }
52
- let(:scim) { Scim.new(@target, token_issuer.client_credentials_grant.auth_header, options.merge(:symbolize_keys => true)) }
80
+ let(:scim) { Scim.new(@target, token_issuer.client_credentials_grant.auth_header, options.merge(symbolize_keys: true)) }
53
81
 
54
82
  before :all do
55
83
  @options = {}
56
84
  if ENV['SKIP_SSL_VALIDATION']
57
- @options = {:skip_ssl_validation => true}
85
+ @options = {skip_ssl_validation: true}
58
86
  end
59
87
  @target = ENV['UAA_CLIENT_TARGET']
60
88
  @test_client = "test_client_#{Time.now.to_i}"
61
89
  @test_secret = '+=tEsTsEcRet~!@'
62
90
  gids = ['clients.read', 'scim.read', 'scim.write', 'uaa.resource', 'password.write']
63
- test_client = CF::UAA::admin_scim(@options).add(:client, :client_id => @test_client, :client_secret => @test_secret,
64
- :authorities => gids, :authorized_grant_types => ['client_credentials', 'password'],
65
- :scope => ['openid', 'password.write'])
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'])
66
94
  expect(test_client[:client_id]).to eq(@test_client)
67
95
  end
68
96
 
@@ -74,7 +102,7 @@ module CF::UAA
74
102
 
75
103
  if ENV['SKIP_SSL_VALIDATION']
76
104
  context 'when ssl certificate is self-signed' do
77
- let(:options) { {:skip_ssl_validation => false} }
105
+ let(:options) { {skip_ssl_validation: false} }
78
106
 
79
107
  it 'fails if skip_ssl_validation is false' do
80
108
  expect{ scim }.to raise_exception(CF::UAA::SSLException)
@@ -85,7 +113,7 @@ module CF::UAA
85
113
  if ENV['SSL_CA_FILE']
86
114
  context 'when you do not skip SSL validation' do
87
115
  context 'when you provide cert' do
88
- let(:options) { {:ssl_ca_file => ENV['SSL_CA_FILE']} }
116
+ let(:options) { {ssl_ca_file: ENV['SSL_CA_FILE']} }
89
117
 
90
118
  it 'works' do
91
119
  expect(token_issuer.prompts).to_not be_nil
@@ -111,7 +139,7 @@ module CF::UAA
111
139
  cert_store
112
140
  end
113
141
 
114
- let(:options) { {:ssl_cert_store => cert_store} }
142
+ let(:options) { {ssl_cert_store: cert_store} }
115
143
  it 'works' do
116
144
  expect(token_issuer.prompts).to_not be_nil
117
145
  end
@@ -128,7 +156,7 @@ module CF::UAA
128
156
  end
129
157
 
130
158
  it 'should report the uaa client version' do
131
- expect(VERSION).to match(/\d.\d.\d/)
159
+ expect(VERSION).to match(/\d+.\d+.\d+/)
132
160
  end
133
161
 
134
162
  it 'makes sure the server is there by getting the prompts for an implicit grant' do
@@ -138,7 +166,7 @@ module CF::UAA
138
166
  it 'gets a token with client credentials' do
139
167
  tkn = token_issuer.client_credentials_grant
140
168
  expect(tkn.auth_header).to match(/^bearer\s/i)
141
- info = TokenCoder.decode(tkn.info['access_token'], :verify => false, :symbolize_keys => true)
169
+ info = TokenCoder.decode(tkn.info['access_token'], verify: false, symbolize_keys: true)
142
170
  expect(info[:exp]).to be
143
171
  expect(info[:jti]).to be
144
172
  end
@@ -151,9 +179,9 @@ module CF::UAA
151
179
  before :each do
152
180
  @username = "sam_#{Time.now.to_i}"
153
181
  @user_pwd = "sam's P@55w0rd~!`@\#\$%^&*()_/{}[]\\|:\";',.<>?/"
154
- usr = scim.add(:user, :username => @username, :password => @user_pwd,
155
- :emails => [{:value => 'sam@example.com'}],
156
- :name => {:givenname => 'none', :familyname => 'none'})
182
+ usr = scim.add(:user, username: @username, password: @user_pwd,
183
+ emails: [{value: 'sam@example.com'}],
184
+ name: {givenname: 'none', familyname: 'none'})
157
185
  @user_id = usr[:id]
158
186
  end
159
187
 
@@ -194,8 +222,8 @@ module CF::UAA
194
222
 
195
223
  it 'should get a uri to be sent to the user agent to initiate autologin' do
196
224
  redir_uri = 'http://call.back/uri_path'
197
- uri_parts = token_issuer.autologin_uri(redir_uri, :username => @username,
198
- :password =>@user_pwd ).split('?')
225
+ uri_parts = token_issuer.autologin_uri(redir_uri, username: @username,
226
+ password: @user_pwd ).split('?')
199
227
  expect(uri_parts[0]).to eq("#{ENV['UAA_CLIENT_TARGET']}/oauth/authorize")
200
228
  params = Util.decode_form(uri_parts[1], :sym)
201
229
  expect(params[:response_type]).to eq('code')
@@ -209,4 +237,4 @@ module CF::UAA
209
237
  end
210
238
  end
211
239
  end
212
- end
240
+ end
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) { {:http_proxy => 'http-proxy.com', :https_proxy => 'https-proxy.com', :skip_ssl_validation => true} }
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, :hair => 'brown', :shoe_size => 'large',
57
- :eye_color => ['blue', 'green'], :name => 'fred')
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 = {:hair => 'black', :shoe_size => 'medium', :eye_color => ['hazel', 'brown'],
75
- :name => 'fredrick', :meta => {:version => 'v567'}, :id => 'id12345'}
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 = {:hair => 'black', :shoe_size => 'medium', :eye_color => ['hazel', 'brown'],
89
- :name => 'fredrick', :meta => {:version => 'v567'}, :id => 'id12345'}
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, :attributes => 'id', :includeInactive => true)
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) { {:http_proxy => 'http-proxy.com', :https_proxy => 'https-proxy.com', :skip_ssl_validation => true, :zone => 'derpzone'} }
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, :hair => 'brown', :shoe_size => 'large',
234
- :eye_color => ['blue', 'green'], :name => 'fred')
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
@@ -22,4 +22,10 @@ if ENV['COVERAGE']
22
22
  SimpleCov.start
23
23
  end
24
24
 
25
- require 'rspec'
25
+ require 'rspec'
26
+
27
+ RSpec.configure do |config|
28
+ config.expect_with :rspec do |expectations|
29
+ expectations.syntax = [:expect, :should]
30
+ end
31
+ end
@@ -18,8 +18,8 @@ module CF::UAA
18
18
 
19
19
  describe TokenCoder do
20
20
 
21
- subject { TokenCoder.new(:audience_ids => "test_resource",
22
- :skey => "test_secret", :pkey => OpenSSL::PKey::RSA.generate(512) ) }
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(:audience_ids => "test_resource", :pkey => pem)
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, :accept_algorithms => "none")
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(:audience_ids => "test_resource", :skey => "other_secret")
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(:audience_ids => "test_resource", :pkey => pem)
107
- coder2 = TokenCoder.new(:audience_ids => "test_resource", :skey => 'randomness')
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(:audience_ids => "test_resource", :pkey => pem)
127
- coder2 = TokenCoder.new(:audience_ids => "test_resource", :skey => 'randomness')
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(:typ => "JWT", :alg =>"BADALGO")]
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(:audience_ids => "test_resource",
139
- :skey => "test_secret", :pkey => OpenSSL::PKey::RSA.generate(512),
140
- :accept_algorithms => "BADALGO")
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,7 +179,7 @@ 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, :verify => false)
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
@@ -23,13 +23,13 @@ describe TokenIssuer do
23
23
 
24
24
  before do
25
25
  #Util.default_logger(:trace)
26
- @issuer = TokenIssuer.new('http://test.uaa.target', 'test_client', 'test_secret', options)
26
+ @issuer = TokenIssuer.new('http://test.uaa.target', 'test_client', 'test!secret', options)
27
27
  end
28
28
 
29
29
  subject { @issuer }
30
30
 
31
31
  describe 'initialize' do
32
- let(:options) { {:http_proxy => 'http-proxy.com', :https_proxy => 'https-proxy.com', :skip_ssl_validation => true} }
32
+ let(:options) { {http_proxy: 'http-proxy.com', https_proxy: 'https-proxy.com', skip_ssl_validation: true, basic_auth: false} }
33
33
 
34
34
  it 'sets skip_ssl_validation' do
35
35
  subject.skip_ssl_validation == true
@@ -42,11 +42,12 @@ describe TokenIssuer do
42
42
  subject.set_request_handler do |url, method, body, headers|
43
43
  headers['content-type'].should =~ /application\/x-www-form-urlencoded/
44
44
  headers['accept'].should =~ /application\/json/
45
- # TODO check basic auth header
45
+ headers['X-CF-ENCODED-CREDENTIALS'].should == 'true'
46
+ headers['authorization'].should == 'Basic dGVzdF9jbGllbnQ6dGVzdCUyMXNlY3JldA=='
46
47
  url.should == 'http://test.uaa.target/oauth/token'
47
48
  method.should == :post
48
- reply = {:access_token => 'test_access_token', :token_type => 'BEARER',
49
- :scope => 'logs.read', :expires_in => 98765}
49
+ reply = {access_token: 'test_access_token', token_type: 'BEARER',
50
+ scope: 'logs.read', expires_in: 98765}
50
51
  [200, Util.json(reply), {'content-type' => 'application/json'}]
51
52
  end
52
53
  token = subject.client_credentials_grant('logs.read')
@@ -59,8 +60,8 @@ describe TokenIssuer do
59
60
 
60
61
  it 'gets all granted scopes if none specified' do
61
62
  subject.set_request_handler do |url, method, body, headers|
62
- reply = {:access_token => 'test_access_token', :token_type => 'BEARER',
63
- :scope => 'openid logs.read', :expires_in => 98765}
63
+ reply = {access_token: 'test_access_token', token_type: 'BEARER',
64
+ scope: 'openid logs.read', expires_in: 98765}
64
65
  [200, Util.json(reply), {'content-type' => 'application/json'}]
65
66
  end
66
67
  token = subject.client_credentials_grant
@@ -89,11 +90,12 @@ describe TokenIssuer do
89
90
  subject.set_request_handler do |url, method, body, headers|
90
91
  headers['content-type'].should =~ /application\/x-www-form-urlencoded/
91
92
  headers['accept'].should =~ /application\/json/
92
- # TODO check basic auth header
93
+ headers['X-CF-ENCODED-CREDENTIALS'].should == 'true'
94
+ headers['authorization'].should == 'Basic dGVzdF9jbGllbnQ6dGVzdCUyMXNlY3JldA=='
93
95
  url.should == 'http://test.uaa.target/oauth/token'
94
96
  method.should == :post
95
- reply = {:access_token => 'test_access_token', :token_type => 'BEARER',
96
- :scope => 'openid', :expires_in => 98765}
97
+ reply = {access_token: 'test_access_token', token_type: 'BEARER',
98
+ scope: 'openid', expires_in: 98765}
97
99
  [200, Util.json(reply), {'content-type' => 'application/json'}]
98
100
  end
99
101
  token = subject.owner_password_grant('joe+admin', "?joe's%password$@ ", 'openid')
@@ -108,13 +110,14 @@ describe TokenIssuer do
108
110
  subject.set_request_handler do |url, method, body, headers|
109
111
  headers['content-type'].should =~ /application\/x-www-form-urlencoded/
110
112
  headers['accept'].should =~ /application\/json/
111
- # TODO check basic auth header
113
+ headers['X-CF-ENCODED-CREDENTIALS'].should == 'true'
114
+ headers['authorization'].should == 'Basic dGVzdF9jbGllbnQ6dGVzdCUyMXNlY3JldA=='
112
115
  url.should == 'http://test.uaa.target/oauth/token'
113
116
  body.should =~ /(^|&)passcode=12345($|&)/
114
117
  body.should =~ /(^|&)grant_type=password($|&)/
115
118
  method.should == :post
116
- reply = {:access_token => 'test_access_token', :token_type => 'BEARER',
117
- :scope => 'openid', :expires_in => 98765}
119
+ reply = {access_token: 'test_access_token', token_type: 'BEARER',
120
+ scope: 'openid', expires_in: 98765}
118
121
  [200, Util.json(reply), {'content-type' => 'application/json'}]
119
122
  end
120
123
  token = subject.passcode_grant('12345')
@@ -135,8 +138,8 @@ describe TokenIssuer do
135
138
  url.should == 'http://test.uaa.target/oauth/token'
136
139
  method.should == :post
137
140
  body.split('&').should =~ ['passcode=fake-passcode', 'grant_type=password']
138
- reply = {:access_token => 'test_access_token', :token_type => 'BEARER',
139
- :scope => 'openid', :expires_in => 98765}
141
+ reply = {access_token: 'test_access_token', token_type: 'BEARER',
142
+ scope: 'openid', expires_in: 98765}
140
143
  [200, Util.json(reply), {'content-type' => 'application/json'}]
141
144
  end
142
145
  token = subject.owner_password_credentials_grant({passcode: 'fake-passcode'})
@@ -153,7 +156,7 @@ describe TokenIssuer do
153
156
 
154
157
  it 'gets the prompts for credentials used to authenticate implicit grant' do
155
158
  subject.set_request_handler do |url, method, body, headers|
156
- info = { :prompts => {:username => ['text', 'Username'], :password => ['password', 'Password']} }
159
+ info = { prompts: {username: ['text', 'Username'], password: ['password', 'Password']} }
157
160
  [200, Util.json(info), {'content-type' => 'application/json'}]
158
161
  end
159
162
  result = subject.prompts
@@ -182,10 +185,10 @@ describe TokenIssuer do
182
185
  end
183
186
 
184
187
  expect(subject).to receive(:authorize_path_args).with('token', 'https://uaa.cloudfoundry.com/redirect/test_client', 'logs.read', anything)
185
- subject.stub(:random_state).and_return('1234')
186
- subject.stub(:authorize_path_args).and_return('/oauth/authorize?state=1234&scope=logs.read')
188
+ allow(subject).to receive(:random_state).and_return('1234')
189
+ allow(subject).to receive(:authorize_path_args).and_return('/oauth/authorize?state=1234&scope=logs.read')
187
190
 
188
- token = subject.implicit_grant_with_creds({:username => 'joe+admin', :password => "?joe's%password$@ "}, 'logs.read')
191
+ token = subject.implicit_grant_with_creds({username: 'joe+admin', password: "?joe's%password$@ "}, 'logs.read')
189
192
  token.should be_an_instance_of TokenInfo
190
193
  token.info['access_token'].should == 'test_access_token'
191
194
  token.info['token_type'].should =~ /^bearer$/i
@@ -202,7 +205,7 @@ describe TokenIssuer do
202
205
  end
203
206
 
204
207
  expect(subject).to receive(:authorize_path_args).with('token id_token', 'https://uaa.cloudfoundry.com/redirect/test_client', 'openid logs.read', anything)
205
- subject.stub(:random_state).and_return('1234')
208
+ allow(subject).to receive(:random_state).and_return('1234')
206
209
  subject.implicit_grant_with_creds({:username => 'joe+admin', :password => "?joe's%password$@ "}, 'openid logs.read')
207
210
  end
208
211
  end
@@ -214,8 +217,8 @@ describe TokenIssuer do
214
217
  'expires_in=98765&scope=openid+logs.read&state=bad_state'
215
218
  [302, nil, {'content-type' => 'application/json', 'location' => location}]
216
219
  end
217
- expect {token = subject.implicit_grant_with_creds(:username => 'joe+admin',
218
- :password => "?joe's%password$@ ")}.to raise_exception BadResponse
220
+ expect {token = subject.implicit_grant_with_creds(username: 'joe+admin',
221
+ password: "?joe's%password$@ ")}.to raise_exception BadResponse
219
222
  end
220
223
 
221
224
  it 'asks for an id_token with openid scope' do
@@ -250,11 +253,12 @@ describe TokenIssuer do
250
253
  subject.set_request_handler do |url, method, body, headers|
251
254
  headers['content-type'].should =~ /application\/x-www-form-urlencoded/
252
255
  headers['accept'].should =~ /application\/json/
253
- # TODO check basic auth header
256
+ headers['X-CF-ENCODED-CREDENTIALS'].should == 'true'
257
+ headers['authorization'].should == 'Basic dGVzdF9jbGllbnQ6dGVzdCUyMXNlY3JldA=='
254
258
  url.should match 'http://test.uaa.target/oauth/token'
255
259
  method.should == :post
256
- reply = {:access_token => 'test_access_token', :token_type => 'BEARER',
257
- :scope => 'openid', :expires_in => 98765}
260
+ reply = {access_token: 'test_access_token', token_type: 'BEARER',
261
+ scope: 'openid', expires_in: 98765}
258
262
  [200, Util.json(reply), {'content-type' => 'application/json'}]
259
263
  end
260
264
  cburi = 'http://call.back/uri_path'
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: 3.13.0
4
+ version: 4.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dave Syer
@@ -12,28 +12,28 @@ authors:
12
12
  autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
- date: 2017-10-26 00:00:00.000000000 Z
15
+ date: 2022-01-21 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: multi_json
19
19
  requirement: !ruby/object:Gem::Requirement
20
20
  requirements:
21
- - - "~>"
22
- - !ruby/object:Gem::Version
23
- version: 1.12.0
24
21
  - - ">="
25
22
  - !ruby/object:Gem::Version
26
23
  version: 1.12.1
24
+ - - "<"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.16'
27
27
  type: :runtime
28
28
  prerelease: false
29
29
  version_requirements: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: 1.12.0
34
31
  - - ">="
35
32
  - !ruby/object:Gem::Version
36
33
  version: 1.12.1
34
+ - - "<"
35
+ - !ruby/object:Gem::Version
36
+ version: '1.16'
37
37
  - !ruby/object:Gem::Dependency
38
38
  name: httpclient
39
39
  requirement: !ruby/object:Gem::Requirement
@@ -54,74 +54,94 @@ dependencies:
54
54
  - - ">="
55
55
  - !ruby/object:Gem::Version
56
56
  version: 2.8.2.4
57
+ - !ruby/object:Gem::Dependency
58
+ name: addressable
59
+ requirement: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: 2.8.0
64
+ - - "~>"
65
+ - !ruby/object:Gem::Version
66
+ version: '2.8'
67
+ type: :runtime
68
+ prerelease: false
69
+ version_requirements: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: 2.8.0
74
+ - - "~>"
75
+ - !ruby/object:Gem::Version
76
+ version: '2.8'
57
77
  - !ruby/object:Gem::Dependency
58
78
  name: bundler
59
79
  requirement: !ruby/object:Gem::Requirement
60
80
  requirements:
61
81
  - - "~>"
62
82
  - !ruby/object:Gem::Version
63
- version: '1.14'
83
+ version: '2.2'
64
84
  type: :development
65
85
  prerelease: false
66
86
  version_requirements: !ruby/object:Gem::Requirement
67
87
  requirements:
68
88
  - - "~>"
69
89
  - !ruby/object:Gem::Version
70
- version: '1.14'
90
+ version: '2.2'
71
91
  - !ruby/object:Gem::Dependency
72
92
  name: rake
73
93
  requirement: !ruby/object:Gem::Requirement
74
94
  requirements:
75
- - - "~>"
76
- - !ruby/object:Gem::Version
77
- version: '10.3'
78
95
  - - ">="
79
96
  - !ruby/object:Gem::Version
80
97
  version: 10.3.2
98
+ - - "~>"
99
+ - !ruby/object:Gem::Version
100
+ version: '13.0'
81
101
  type: :development
82
102
  prerelease: false
83
103
  version_requirements: !ruby/object:Gem::Requirement
84
104
  requirements:
85
- - - "~>"
86
- - !ruby/object:Gem::Version
87
- version: '10.3'
88
105
  - - ">="
89
106
  - !ruby/object:Gem::Version
90
107
  version: 10.3.2
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '13.0'
91
111
  - !ruby/object:Gem::Dependency
92
112
  name: rspec
93
113
  requirement: !ruby/object:Gem::Requirement
94
114
  requirements:
95
- - - "~>"
96
- - !ruby/object:Gem::Version
97
- version: '2.14'
98
115
  - - ">="
99
116
  - !ruby/object:Gem::Version
100
117
  version: 2.14.1
118
+ - - "~>"
119
+ - !ruby/object:Gem::Version
120
+ version: '3.9'
101
121
  type: :development
102
122
  prerelease: false
103
123
  version_requirements: !ruby/object:Gem::Requirement
104
124
  requirements:
105
- - - "~>"
106
- - !ruby/object:Gem::Version
107
- version: '2.14'
108
125
  - - ">="
109
126
  - !ruby/object:Gem::Version
110
127
  version: 2.14.1
128
+ - - "~>"
129
+ - !ruby/object:Gem::Version
130
+ version: '3.9'
111
131
  - !ruby/object:Gem::Dependency
112
132
  name: simplecov
113
133
  requirement: !ruby/object:Gem::Requirement
114
134
  requirements:
115
135
  - - "~>"
116
136
  - !ruby/object:Gem::Version
117
- version: 0.8.2
137
+ version: 0.21.2
118
138
  type: :development
119
139
  prerelease: false
120
140
  version_requirements: !ruby/object:Gem::Requirement
121
141
  requirements:
122
142
  - - "~>"
123
143
  - !ruby/object:Gem::Version
124
- version: 0.8.2
144
+ version: 0.21.2
125
145
  - !ruby/object:Gem::Dependency
126
146
  name: simplecov-rcov
127
147
  requirement: !ruby/object:Gem::Requirement
@@ -140,42 +160,56 @@ dependencies:
140
160
  name: ci_reporter
141
161
  requirement: !ruby/object:Gem::Requirement
142
162
  requirements:
143
- - - "~>"
144
- - !ruby/object:Gem::Version
145
- version: '1.9'
146
163
  - - ">="
147
164
  - !ruby/object:Gem::Version
148
165
  version: 1.9.2
166
+ - - "~>"
167
+ - !ruby/object:Gem::Version
168
+ version: '2.0'
149
169
  type: :development
150
170
  prerelease: false
151
171
  version_requirements: !ruby/object:Gem::Requirement
152
172
  requirements:
153
- - - "~>"
154
- - !ruby/object:Gem::Version
155
- version: '1.9'
156
173
  - - ">="
157
174
  - !ruby/object:Gem::Version
158
175
  version: 1.9.2
176
+ - - "~>"
177
+ - !ruby/object:Gem::Version
178
+ version: '2.0'
159
179
  - !ruby/object:Gem::Dependency
160
180
  name: json_pure
161
181
  requirement: !ruby/object:Gem::Requirement
162
182
  requirements:
183
+ - - ">="
184
+ - !ruby/object:Gem::Version
185
+ version: 1.8.1
163
186
  - - "~>"
164
187
  - !ruby/object:Gem::Version
165
- version: '1.8'
188
+ version: '2.5'
189
+ type: :development
190
+ prerelease: false
191
+ version_requirements: !ruby/object:Gem::Requirement
192
+ requirements:
166
193
  - - ">="
167
194
  - !ruby/object:Gem::Version
168
195
  version: 1.8.1
196
+ - - "~>"
197
+ - !ruby/object:Gem::Version
198
+ version: '2.5'
199
+ - !ruby/object:Gem::Dependency
200
+ name: ci_reporter_rspec
201
+ requirement: !ruby/object:Gem::Requirement
202
+ requirements:
203
+ - - "~>"
204
+ - !ruby/object:Gem::Version
205
+ version: '1.0'
169
206
  type: :development
170
207
  prerelease: false
171
208
  version_requirements: !ruby/object:Gem::Requirement
172
209
  requirements:
173
210
  - - "~>"
174
211
  - !ruby/object:Gem::Version
175
- version: '1.8'
176
- - - ">="
177
- - !ruby/object:Gem::Version
178
- version: 1.8.1
212
+ version: '1.0'
179
213
  description: Client library for interacting with the CloudFoundry User Account and
180
214
  Authorization (UAA) server. The UAA is an OAuth2 Authorization Server so it can
181
215
  be used by webapps and command line apps to obtain access tokens to act on behalf
@@ -191,8 +225,10 @@ executables: []
191
225
  extensions: []
192
226
  extra_rdoc_files: []
193
227
  files:
228
+ - ".github/dependabot.yml"
229
+ - ".github/workflows/gem-push.yml"
230
+ - ".github/workflows/ruby.yml"
194
231
  - ".gitignore"
195
- - ".travis.yml"
196
232
  - ".yardopts"
197
233
  - CHANGELOG.md
198
234
  - Gemfile
@@ -235,16 +271,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
235
271
  - !ruby/object:Gem::Version
236
272
  version: '0'
237
273
  requirements: []
238
- rubyforge_project: cf-uaa-lib
239
- rubygems_version: 2.6.13
274
+ rubygems_version: 3.0.3.1
240
275
  signing_key:
241
276
  specification_version: 4
242
277
  summary: Client library for CloudFoundry UAA
243
- test_files:
244
- - spec/http_spec.rb
245
- - spec/info_spec.rb
246
- - spec/integration_spec.rb
247
- - spec/scim_spec.rb
248
- - spec/spec_helper.rb
249
- - spec/token_coder_spec.rb
250
- - spec/token_issuer_spec.rb
278
+ test_files: []
data/.travis.yml DELETED
@@ -1,10 +0,0 @@
1
- language: ruby
2
-
3
- before_install:
4
- - gem update
5
- - gem install bundler
6
-
7
- rvm:
8
- - 2.2.7
9
- - 2.3.4
10
- - 2.4.1