cf-uaa-lib 4.0.0 → 4.0.1

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
2
  SHA256:
3
- metadata.gz: e8a741ef102742885eff043d198628e3bc05f0bcc98c752a57ce5f6b3c18bf43
4
- data.tar.gz: 6ffc61520e49b04d65bd0404f577727986e3f625e6ef095fc8a0d361c50be5ab
3
+ metadata.gz: 283326148ca7b9df992d6ea50b3e0161ef74d07626147979c83a5c6e63daec86
4
+ data.tar.gz: b643f26e60fa73ccdee7e9fc7b89b3b3c010e9c9007be12e98e2f7493cc53a6d
5
5
  SHA512:
6
- metadata.gz: 75d8062f4bdc94bc7375a18124f72b3664a2d4074a63699c4e55f52ae085375ae587e7c113859b345bd7476878d744ceb66320cd42ccc9ef3e02f0315e591f78
7
- data.tar.gz: 223a89a483dfe638062240e4326e8c8e485b62a1e07108ed87feb5fff67ce1f5a705923939f23d6135bd4eeb6f8638cd60ae7638cc62ff2e1376aafe94720051
6
+ metadata.gz: 110d6d2259dcce0a7e1cac4ffbf24625a32c6a265fc5329adf4d2cc3ade2803aed54012021d8ad2238cd0aeb5259d3b973173671c7ca1b54fe6cc775146a5001
7
+ data.tar.gz: d217c50866d14c2eac62b03dbe406f572398f9f1d747b0a079c26236662474143d6d252b609df03c228123c677b299d1f3b8e700f49af7f0651561d3e715f647
data/README.md CHANGED
@@ -8,31 +8,133 @@ For documentation see: https://rubygems.org/gems/cf-uaa-lib
8
8
 
9
9
  ## Install from rubygems
10
10
 
11
- $ gem install cf-uaa-lib
11
+ ```plain
12
+ gem install cf-uaa-lib
13
+ ```
12
14
 
13
15
  ## Build from source
14
16
 
15
- $ bundle install
16
- $ gem build cf-uaa-lib.gemspec
17
- $ gem install cf-uaa-lib<version>.gem
17
+ ```plain
18
+ bundle install
19
+ rake install
20
+ ```
18
21
 
19
22
  ## Use the gem
20
23
 
21
- #!/usr/bin/env ruby
22
- require 'uaa'
23
- token_issuer = CF::UAA::TokenIssuer.new("https://uaa.cloudfoundry.com", "vmc")
24
- puts token_issuer.prompts.inspect
25
- token = token_issuer.implicit_grant_with_creds(username: "<your_username>", password: "<your_password>")
26
- token_info = CF::UAA::TokenCoder.decode(token.info["access_token"], nil, nil, false) #token signature not verified
27
- puts token_info["user_name"]
24
+ Create a UAA client that allows users to authenticate with username/password and allow client application to use `openid` scope to invoke `/userinfo` endpoint for the user.
25
+
26
+ ```plain
27
+ uaa create-client decode-token-demo -s decode-token-demo -v \
28
+ --authorized_grant_types password,refresh_token \
29
+ --scope "openid" \
30
+ --authorities uaa.none
31
+ ```
32
+
33
+ Create a user with which to authorize our `decode-token-demo` client application.
34
+
35
+ ```plain
36
+ uaa create-user myuser \
37
+ --email myuser@example.com \
38
+ --givenName "My" \
39
+ --familyName "User" \
40
+ --password myuser_secret
41
+ ```
42
+
43
+ Create this Ruby script (script is available at `examples/password_grant_and_decode_token.rb`):
44
+
45
+ ```ruby
46
+ #!/usr/bin/env ruby
47
+
48
+ require 'uaa'
49
+
50
+ url = ENV["UAA_URL"]
51
+ client, secret = "decode-token-demo", "decode-token-demo"
52
+ username, password = ENV["UAA_USERNAME"], ENV["UAA_PASSWORD"]
53
+
54
+ def show(title, object)
55
+ puts "#{title}: #{object.inspect}"
56
+ puts
57
+ end
58
+
59
+ uaa_options = {}
60
+ uaa_options[:ssl_ca_file] = ENV["UAA_CA_CERT_FILE"] if ENV["UAA_CA_CERT_FILE"]
61
+ show "uaa_options", uaa_options
62
+
63
+ uaa_info = CF::UAA::Info.new(url, uaa_options)
64
+ show "UAA server info", uaa_info.server
65
+
66
+ token_keys = uaa_info.validation_keys_hash
67
+ show "Signing keys for access tokens", token_keys
68
+
69
+ token_issuer = CF::UAA::TokenIssuer.new(url, client, secret, uaa_options)
70
+ show "Login prompts", token_issuer.prompts
71
+
72
+ token = token_issuer.owner_password_grant(username, password, "openid")
73
+ show "User '#{username}' password grant", token
74
+
75
+ auth_header = "bearer #{token.info["access_token"]}"
76
+ show "Auth header for resource server API calls", auth_header
77
+
78
+ userinfo = uaa_info.whoami(auth_header)
79
+ show "User info", userinfo
80
+
81
+ last_exception = nil
82
+ token_keys.each_pair do |keyname, token_key|
83
+ begin
84
+ token_coder = CF::UAA::TokenCoder.new(uaa_options.merge(pkey: token_key["value"], verify: true))
85
+ token_info = token_coder.decode(auth_header)
86
+ show "Decoded access token", token_info
87
+ last_exception = nil
88
+ rescue CF::UAA::Decode => e
89
+ last_exception = e
90
+ end
91
+ end
92
+ raise last_exception if last_exception
93
+ ```
94
+
95
+ To run the script, setup the env vars for your UAA and run the ruby script:
96
+
97
+ ```bash
98
+ export UAA_URL=https://192.168.50.6:8443
99
+ export UAA_CA_CERT_FILE=/path/to/ca.pem
100
+ export UAA_USERNAME=myuser
101
+ export UAA_PASSWORD=myuser_secret
102
+ ruby examples/password_grant_and_decode_token.rb
103
+ ```
104
+
105
+ The output will look similar to:
106
+
107
+ ```plain
108
+ uaa_options: {:ssl_ca_file=>"/var/folders/wd/xnncwqp96rj0v1y2nms64mq80000gn/T/tmp.R6wpXYdC/ca.pem"}
109
+
110
+ UAA server info: {"app"=>{"version"=>"4.19.0"}, "links"=>{"uaa"=>"https://192.168.50.6:8443", "passwd"=>"/forgot_password", "login"=>"https://192.168.50.6:8443", "register"=>"/create_account"}, "zone_name"=>"uaa", "entityID"=>"192.168.50.6:8443", "commit_id"=>"7897100", "idpDefinitions"=>{}, "prompts"=>{"username"=>["text", "Email"], "password"=>["password", "Password"]}, "timestamp"=>"2018-06-13T12:02:09-0700"}
111
+
112
+ Cookie#domain returns dot-less domain name now. Use Cookie#dot_domain if you need "." at the beginning.
113
+ Signing keys for access tokens: {"uaa-jwt-key-1"=>{"kty"=>"RSA", "e"=>"AQAB", "use"=>"sig", "kid"=>"uaa-jwt-key-1", "alg"=>"RS256", "value"=>"-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8UNioYHjhyi1qSHrnBZ9\nKE96/1jLBOX2UTShGBo8jP7eDD6zUh5DNHNPAwD1V8gNI4wvNAm+zL1MrSEDWzn2\nPvCANd+XydoNVZU1zhqxvGhoxHmgAA3JbgSS3oLLNDG/HH8wEnjAxb+G1uh2EVSF\nAe/euQ/fEmY4e7uOG34h9WMX84tD1Sf/xvVoNGAL8bTwotzBLFZ12M3P70hrKDi5\n9wEBbY5bllvvNFyjZTYwMbw97RIOdg3FQkOABu8ENCqbPks5gqSpNV33ekaX4rAd\nwYdEX5iUzDBdMyD8jqUopuqTXqBKg2/ealGitXdbSIEAvcBgZWnn1j2vFp6OEYBB\n7wIDAQAB\n-----END PUBLIC KEY-----", "n"=>"APFDYqGB44cotakh65wWfShPev9YywTl9lE0oRgaPIz-3gw-s1IeQzRzTwMA9VfIDSOMLzQJvsy9TK0hA1s59j7wgDXfl8naDVWVNc4asbxoaMR5oAANyW4Ekt6CyzQxvxx_MBJ4wMW_htbodhFUhQHv3rkP3xJmOHu7jht-IfVjF_OLQ9Un_8b1aDRgC_G08KLcwSxWddjNz-9Iayg4ufcBAW2OW5Zb7zRco2U2MDG8Pe0SDnYNxUJDgAbvBDQqmz5LOYKkqTVd93pGl-KwHcGHRF-YlMwwXTMg_I6lKKbqk16gSoNv3mpRorV3W0iBAL3AYGVp59Y9rxaejhGAQe8"}}
114
+
115
+ Login prompts: {"username"=>["text", "Email"], "password"=>["password", "Password"]}
116
+
117
+ User 'myuser' password grant: #<CF::UAA::TokenInfo:0x00007fbad5a12c18 @info={"access_token"=>"eyJhbGciOiJSUzI1NiIsImtpZCI6InVhYS1qd3Qta2V5LTEiLCJ0eXAiOiJKV1QifQ.eyJqdGkiOiJlMTFlZmMwNjI1OGQ0MzA0YTc4ZGIyNzliYjJjMzQ1OCIsInN1YiI6IjM5NzhmZjRkLWQ3MzgtNGI4Yi05OTA4LTdhZTE0N2YzYzNiZSIsInNjb3BlIjpbIm9wZW5pZCJdLCJjbGllbnRfaWQiOiJkZWNvZGUtdG9rZW4tZGVtbyIsImNpZCI6ImRlY29kZS10b2tlbi1kZW1vIiwiYXpwIjoiZGVjb2RlLXRva2VuLWRlbW8iLCJncmFudF90eXBlIjoicGFzc3dvcmQiLCJ1c2VyX2lkIjoiMzk3OGZmNGQtZDczOC00YjhiLTk5MDgtN2FlMTQ3ZjNjM2JlIiwib3JpZ2luIjoidWFhIiwidXNlcl9uYW1lIjoibXl1c2VyIiwiZW1haWwiOiJteXVzZXJAZXhhbXBsZS5jb20iLCJhdXRoX3RpbWUiOjE1MzE2MzAxNDgsInJldl9zaWciOiI5M2E2NzkwNCIsImlhdCI6MTUzMTYzMDE0OCwiZXhwIjoxNTMxNjczMzQ4LCJpc3MiOiJodHRwczovLzE5Mi4xNjguNTAuNjo4NDQzL29hdXRoL3Rva2VuIiwiemlkIjoidWFhIiwiYXVkIjpbIm9wZW5pZCIsImRlY29kZS10b2tlbi1kZW1vIl19.qtbzxCOW5bebTgMLK-71_zxaT7l5PSmxhXcDtCeA64dZZ6-wXXmJivopm5PFEHnHiZwRpVe43jyEsbJGzBdl8GEsYQ9YIy51-4noby7ClziJv-6rSBYZnZuU5A234QRWclATGksOcz8Ft9PTIKGKLScyLhncwas7W0uiNJ87MFBGWY6Ovvl3Ac5-jHCqiRBXD6vUhzpfmy6_OUr53i9zJgtcQQWgDrOHxnFcRABZcDnhnWdcxh-Hbagtt9dQU46QgpqLJiUvAg-7ypZPGrxnr9UQEO2Q9GrolkbrSeUcfUOkgppxaA_0b6RYpgBR1qg-Ns6jGUxFgPs6Jj8pysfVmA", "token_type"=>"bearer", "refresh_token"=>"6701ddb9397840a1bd339e9f4314448f-r", "expires_in"=>43199, "scope"=>"openid", "jti"=>"e11efc06258d4304a78db279bb2c3458"}>
118
+
119
+ Auth header for resource server API calls: "bearer eyJhbGciOiJSUzI1NiIsImtpZCI6InVhYS1qd3Qta2V5LTEiLCJ0eXAiOiJKV1QifQ.eyJqdGkiOiJlMTFlZmMwNjI1OGQ0MzA0YTc4ZGIyNzliYjJjMzQ1OCIsInN1YiI6IjM5NzhmZjRkLWQ3MzgtNGI4Yi05OTA4LTdhZTE0N2YzYzNiZSIsInNjb3BlIjpbIm9wZW5pZCJdLCJjbGllbnRfaWQiOiJkZWNvZGUtdG9rZW4tZGVtbyIsImNpZCI6ImRlY29kZS10b2tlbi1kZW1vIiwiYXpwIjoiZGVjb2RlLXRva2VuLWRlbW8iLCJncmFudF90eXBlIjoicGFzc3dvcmQiLCJ1c2VyX2lkIjoiMzk3OGZmNGQtZDczOC00YjhiLTk5MDgtN2FlMTQ3ZjNjM2JlIiwib3JpZ2luIjoidWFhIiwidXNlcl9uYW1lIjoibXl1c2VyIiwiZW1haWwiOiJteXVzZXJAZXhhbXBsZS5jb20iLCJhdXRoX3RpbWUiOjE1MzE2MzAxNDgsInJldl9zaWciOiI5M2E2NzkwNCIsImlhdCI6MTUzMTYzMDE0OCwiZXhwIjoxNTMxNjczMzQ4LCJpc3MiOiJodHRwczovLzE5Mi4xNjguNTAuNjo4NDQzL29hdXRoL3Rva2VuIiwiemlkIjoidWFhIiwiYXVkIjpbIm9wZW5pZCIsImRlY29kZS10b2tlbi1kZW1vIl19.qtbzxCOW5bebTgMLK-71_zxaT7l5PSmxhXcDtCeA64dZZ6-wXXmJivopm5PFEHnHiZwRpVe43jyEsbJGzBdl8GEsYQ9YIy51-4noby7ClziJv-6rSBYZnZuU5A234QRWclATGksOcz8Ft9PTIKGKLScyLhncwas7W0uiNJ87MFBGWY6Ovvl3Ac5-jHCqiRBXD6vUhzpfmy6_OUr53i9zJgtcQQWgDrOHxnFcRABZcDnhnWdcxh-Hbagtt9dQU46QgpqLJiUvAg-7ypZPGrxnr9UQEO2Q9GrolkbrSeUcfUOkgppxaA_0b6RYpgBR1qg-Ns6jGUxFgPs6Jj8pysfVmA"
120
+
121
+ User info: {"user_id"=>"3978ff4d-d738-4b8b-9908-7ae147f3c3be", "user_name"=>"myuser", "name"=>"My User", "given_name"=>"My", "family_name"=>"User", "email"=>"myuser@example.com", "email_verified"=>true, "previous_logon_time"=>nil, "sub"=>"3978ff4d-d738-4b8b-9908-7ae147f3c3be"}
122
+
123
+ Decoded access token: {"jti"=>"e11efc06258d4304a78db279bb2c3458", "sub"=>"3978ff4d-d738-4b8b-9908-7ae147f3c3be", "scope"=>["openid"], "client_id"=>"decode-token-demo", "cid"=>"decode-token-demo", "azp"=>"decode-token-demo", "grant_type"=>"password", "user_id"=>"3978ff4d-d738-4b8b-9908-7ae147f3c3be", "origin"=>"uaa", "user_name"=>"myuser", "email"=>"myuser@example.com", "auth_time"=>1531630148, "rev_sig"=>"93a67904", "iat"=>1531630148, "exp"=>1531673348, "iss"=>"https://192.168.50.6:8443/oauth/token", "zid"=>"uaa", "aud"=>["openid", "decode-token-demo"]}
124
+ >>>>>>> 21ae635... new example script - password grant + decode using token keys
125
+ ```
28
126
 
29
127
  ## Tests
30
128
 
31
129
  Run the tests with rake:
32
130
 
33
- $ bundle exec rake test
131
+ ```plain
132
+ bundle exec rake test
133
+ ```
34
134
 
35
135
  Run the tests and see a fancy coverage report:
36
136
 
37
- $ bundle exec rake cov
137
+ ```plain
138
+ bundle exec rake cov
139
+ ```
38
140
 
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # uaa create-client decode-token-demo -s decode-token-demo -v \
4
+ # --authorized_grant_types password,refresh_token \
5
+ # --scope "openid" \
6
+ # --authorities uaa.none
7
+
8
+ require 'uaa'
9
+
10
+ url = ENV["UAA_URL"]
11
+ client, secret = "decode-token-demo", "decode-token-demo"
12
+ username, password = ENV["UAA_USERNAME"], ENV["UAA_PASSWORD"]
13
+
14
+ def show(title, object)
15
+ puts "#{title}: #{object.inspect}"
16
+ puts
17
+ end
18
+
19
+ uaa_options = {}
20
+ uaa_options[:ssl_ca_file] = ENV["UAA_CA_CERT_FILE"] if ENV["UAA_CA_CERT_FILE"]
21
+ show "uaa_options", uaa_options
22
+
23
+ uaa_info = CF::UAA::Info.new(url, uaa_options)
24
+ show "UAA server info", uaa_info.server
25
+
26
+ token_keys = uaa_info.validation_keys_hash
27
+ show "Signing keys for access tokens", token_keys
28
+
29
+ token_issuer = CF::UAA::TokenIssuer.new(url, client, secret, uaa_options)
30
+ show "Login prompts", token_issuer.prompts
31
+
32
+ token = token_issuer.owner_password_grant(username, password, "openid")
33
+ show "User '#{username}' password grant", token
34
+
35
+ auth_header = "bearer #{token.info["access_token"]}"
36
+ show "Auth header for resource server API calls", auth_header
37
+
38
+ userinfo = uaa_info.whoami(auth_header)
39
+ show "User info", userinfo
40
+
41
+ last_exception = nil
42
+ token_keys.each_pair do |keyname, token_key|
43
+ begin
44
+ token_coder = CF::UAA::TokenCoder.new(uaa_options.merge(pkey: token_key["value"], verify: true))
45
+ token_info = token_coder.decode(auth_header)
46
+ show "Decoded access token", token_info
47
+ last_exception = nil
48
+ rescue CF::UAA::Decode => e
49
+ last_exception = e
50
+ end
51
+ end
52
+ raise last_exception if last_exception
53
+
@@ -64,8 +64,8 @@ class TokenCoder
64
64
  def self.encode(token_body, options = {}, obsolete1 = nil, obsolete2 = nil)
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
- warn "#{self.class}##{__method__} is deprecated with these parameters. Please use options hash."
68
- options = {skey: options }
67
+ warn "WARNING: #{self.class}##{__method__} is deprecated with these parameters. Please use options hash."
68
+ options = {skey: options}
69
69
  options[:pkey], options[:algorithm] = obsolete1, obsolete2
70
70
  end
71
71
  options = normalize_options(options)
@@ -95,8 +95,8 @@ class TokenCoder
95
95
  def self.decode(token, options = {}, obsolete1 = nil, obsolete2 = nil)
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
- warn "#{self.class}##{__method__} is deprecated with these parameters. Please use options hash."
99
- options = {skey: options }
98
+ warn "WARNING: #{self.class}##{__method__} is deprecated with these parameters. Please use options hash."
99
+ options = {skey: options}
100
100
  options[:pkey], options[:verify] = obsolete1, obsolete2
101
101
  end
102
102
  options = normalize_options(options)
@@ -106,10 +106,16 @@ class TokenCoder
106
106
  signing_input = [header_segment, payload_segment].join('.')
107
107
  header = Util.json_decode64(header_segment)
108
108
  payload = Util.json_decode64(payload_segment, (:sym if options[:symbolize_keys]))
109
- return payload unless options[:verify]
109
+ unless options[:verify]
110
+ warn "WARNING: Decoding token without verifying it was signed by its authoring UAA"
111
+ return payload
112
+ end
110
113
  raise SignatureNotAccepted, "Signature algorithm not accepted" unless
111
114
  options[:accept_algorithms].include?(algo = header["alg"])
112
- return payload if algo == 'none'
115
+ if algo == 'none'
116
+ warn "WARNING: Decoding token that explicitly states it has not been signed by an authoring UAA"
117
+ return payload
118
+ end
113
119
  signature = Util.decode64(crypto_segment)
114
120
  if ["HS256", "HS384", "HS512"].include?(algo)
115
121
  raise InvalidSignature, "Signature verification failed" unless
@@ -123,6 +129,17 @@ class TokenCoder
123
129
  payload
124
130
  end
125
131
 
132
+ # Decodes a JWT token to extract its expiry time
133
+ # @param [String] token A JWT token as returned by {TokenCoder.encode}
134
+ # @return [Integer] exp expiry timestamp
135
+ def self.decode_token_expiry(token)
136
+ segments = token.split('.')
137
+ raise InvalidTokenFormat, "Not enough or too many segments" unless [2,3].include? segments.length
138
+ header_segment, payload_segment, crypto_segment = segments
139
+ payload = Util.json_decode64(payload_segment, :sym)
140
+ payload[:exp]
141
+ end
142
+
126
143
  # Takes constant time to compare 2 strings (HMAC digests in this case)
127
144
  # to avoid timing attacks while comparing the HMAC digests
128
145
  # @param [String] a: the first digest to compare
@@ -78,7 +78,7 @@ class TokenIssuer
78
78
  headers['authorization'] = Http.basic_auth(@client_id, @client_secret)
79
79
  else
80
80
  headers['X-CF-ENCODED-CREDENTIALS'] = 'true'
81
- headers['authorization'] = Http.basic_auth(CGI.escape(@client_id), CGI.escape(@client_secret))
81
+ headers['authorization'] = Http.basic_auth(CGI.escape(@client_id || ''), CGI.escape(@client_secret || ''))
82
82
  end
83
83
  reply = json_parse_reply(@key_style, *request(@token_target, :post,
84
84
  '/oauth/token', Util.encode_form(params), headers))
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.0'
17
+ VERSION = '4.0.1'
18
18
  end
19
19
  end
@@ -183,6 +183,12 @@ describe TokenCoder do
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
@@ -23,9 +23,12 @@ 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', 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
@@ -106,6 +109,31 @@ describe TokenIssuer do
106
109
  token.info['expires_in'].should == 98765
107
110
  end
108
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
+
109
137
  it 'gets a token with passcode' do
110
138
  subject.set_request_handler do |url, method, body, headers|
111
139
  headers['content-type'].should =~ /application\/x-www-form-urlencoded/
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.0
4
+ version: 4.0.1
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: 2022-01-21 00:00:00.000000000 Z
15
+ date: 2022-01-28 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/password_grant_and_decode_token.rb
240
241
  - lib/uaa.rb
241
242
  - lib/uaa/http.rb
242
243
  - lib/uaa/info.rb