openid_connect 0.3.6 → 0.3.7
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.
- data/Gemfile.lock +3 -2
- data/VERSION +1 -1
- data/lib/openid_connect/request_object.rb +2 -2
- data/lib/openid_connect/response_object/id_token.rb +19 -7
- data/spec/helpers/crypto_spec_helper.rb +31 -0
- data/spec/mock_response/request_object/signed.jwt +1 -0
- data/spec/openid_connect/discovery/provider/config/resource_spec.rb +20 -0
- data/spec/openid_connect/discovery/provider/config_spec.rb +10 -0
- data/spec/openid_connect/request_object_spec.rb +10 -0
- data/spec/openid_connect/response_object/id_token_spec.rb +55 -0
- data/spec/rack/oauth2/server/authorize/extension/id_token_spec.rb +20 -1
- data/spec/spec_helper.rb +2 -13
- metadata +10 -4
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
openid_connect (0.3.
|
|
4
|
+
openid_connect (0.3.7)
|
|
5
5
|
activemodel (>= 3)
|
|
6
6
|
attr_required (>= 0.0.5)
|
|
7
7
|
json (>= 1.4.3)
|
|
@@ -35,6 +35,7 @@ GEM
|
|
|
35
35
|
httpclient (2.3.0.1)
|
|
36
36
|
i18n (0.6.1)
|
|
37
37
|
json (1.7.5)
|
|
38
|
+
json (1.7.5-java)
|
|
38
39
|
json-jwt (0.3.3)
|
|
39
40
|
activesupport (>= 2.3)
|
|
40
41
|
i18n
|
|
@@ -73,7 +74,7 @@ GEM
|
|
|
73
74
|
treetop (1.4.11)
|
|
74
75
|
polyglot
|
|
75
76
|
polyglot (>= 0.3.1)
|
|
76
|
-
tzinfo (0.3.
|
|
77
|
+
tzinfo (0.3.34)
|
|
77
78
|
url_safe_base64 (0.2.1)
|
|
78
79
|
validate_email (0.1.6)
|
|
79
80
|
activemodel (>= 3.0)
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.3.
|
|
1
|
+
0.3.7
|
|
@@ -28,11 +28,11 @@ module OpenIDConnect
|
|
|
28
28
|
include JWTnizable
|
|
29
29
|
|
|
30
30
|
class << self
|
|
31
|
-
def decode(jwt_string, key)
|
|
31
|
+
def decode(jwt_string, key = nil)
|
|
32
32
|
new JSON::JWT.decode(jwt_string, key)
|
|
33
33
|
end
|
|
34
34
|
|
|
35
|
-
def fetch(request_uri, key)
|
|
35
|
+
def fetch(request_uri, key = nil)
|
|
36
36
|
jwt_string = OpenIDConnect.http_client.get_content(request_uri)
|
|
37
37
|
decode jwt_string, key
|
|
38
38
|
end
|
|
@@ -63,20 +63,32 @@ module OpenIDConnect
|
|
|
63
63
|
jwt = JSON::JWT.decode jwt_string, :skip_verification
|
|
64
64
|
jwk = jwt[:user_jwk]
|
|
65
65
|
raise InvalidToken.new('Missing user_jwk') if jwk.blank?
|
|
66
|
+
raise InvalidToken.new('Invalid user_id') unless jwt[:user_id] == self_issued_user_id(jwk)
|
|
66
67
|
public_key = JSON::JWK.decode jwk
|
|
67
|
-
|
|
68
|
-
|
|
68
|
+
jwt = JSON::JWT.decode jwt_string, public_key
|
|
69
|
+
new jwt
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def self_issued(attributes = {})
|
|
73
|
+
attributes[:user_jwk] ||= JSON::JWK.new attributes.delete(:public_key)
|
|
74
|
+
_attributes_ = {
|
|
75
|
+
iss: 'https://self-issued.me',
|
|
76
|
+
user_id: self_issued_user_id(attributes[:user_jwk])
|
|
77
|
+
}.merge(attributes)
|
|
78
|
+
new _attributes_
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def self_issued_user_id(jwk)
|
|
82
|
+
user_id_base_string = case jwk[:alg].to_s
|
|
83
|
+
when 'RSA'
|
|
69
84
|
[jwk[:mod], jwk[:xpo]].join
|
|
70
|
-
when
|
|
85
|
+
when 'EC'
|
|
71
86
|
raise NotImplementedError.new('Not Implemented Yet')
|
|
72
87
|
else
|
|
73
88
|
# Shouldn't reach here. All unknown algorithm error should occurs when decoding JWK
|
|
74
89
|
raise InvalidToken.new('Unknown Algorithm')
|
|
75
90
|
end
|
|
76
|
-
|
|
77
|
-
raise InvalidToken.new('Invalid user_id') unless jwt[:user_id] == expected_user_id
|
|
78
|
-
jwt = JSON::JWT.decode jwt_string, public_key
|
|
79
|
-
new jwt
|
|
91
|
+
UrlSafeBase64.encode64 OpenSSL::Digest::SHA256.digest(user_id_base_string)
|
|
80
92
|
end
|
|
81
93
|
end
|
|
82
94
|
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
module CryptoSpecHelper
|
|
2
|
+
def rsa_key
|
|
3
|
+
@rsa_key ||= OpenSSL::PKey::RSA.generate 2048
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
def public_key
|
|
7
|
+
@public_key ||= rsa_key.public_key
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def private_key
|
|
11
|
+
@private_key ||= OpenSSL::PKey::RSA.new rsa_key.export(OpenSSL::Cipher::Cipher.new('DES-EDE3-CBC'), 'pass-phrase'), 'pass-phrase'
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def ec_key
|
|
15
|
+
@ec_key ||= OpenSSL::PKey::EC.new('secp256k1').generate_key
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def ec_public_key
|
|
19
|
+
unless @ec_public_key
|
|
20
|
+
@ec_public_key = OpenSSL::PKey::EC.new ec_key
|
|
21
|
+
@ec_public_key.private_key = nil
|
|
22
|
+
end
|
|
23
|
+
@ec_public_key
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def ec_private_key
|
|
27
|
+
ec_key
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
include CryptoSpecHelper
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJjbGllbnRfaWQiOiJjbGllbnRfaWQiLCJyZXNwb25zZV90eXBlIjoidG9rZW4gaWRfdG9rZW4iLCJyZWRpcmVjdF91cmkiOiJodHRwczovL2NsaWVudC5leGFtcGxlLmNvbSIsInNjb3BlIjoib3BlbmlkIGVtYWlsIiwic3RhdGUiOiJzdGF0ZTEyMzQiLCJub25jZSI6Im5vbmNlMTIzNCIsImRpc3BsYXkiOiJ0b3VjaCIsInByb21wdCI6Im5vbmUiLCJpZF90b2tlbiI6eyJjbGFpbXMiOnsiYWNyIjp7InZhbHVlcyI6WyIyIiwiMyIsIjQiXX19LCJtYXhfYWdlIjoxMH0sInVzZXJpbmZvIjp7ImNsYWltcyI6eyJuYW1lIjp7ImVzc2VudGlhbCI6dHJ1ZX0sImVtYWlsIjp7ImVzc2VudGlhbCI6ZmFsc2V9fX19.MLTDQVPdhAdkJhboM06IRtjHJrvamJ_H2vFGRupXmTA
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe OpenIDConnect::Discovery::Provider::Config::Resource do
|
|
4
|
+
let(:resource) do
|
|
5
|
+
uri = URI.parse 'http://server.example.com'
|
|
6
|
+
OpenIDConnect::Discovery::Provider::Config::Resource.new uri
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
describe '#endpoint' do
|
|
10
|
+
context 'when invalid host' do
|
|
11
|
+
before do
|
|
12
|
+
resource.host = 'hoge*hoge'
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it do
|
|
16
|
+
expect { resource.endpoint }.to raise_error SWD::Exception
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -25,6 +25,16 @@ describe OpenIDConnect::Discovery::Provider::Config do
|
|
|
25
25
|
config.user_id_types_supported.should == ["public", "pairwise"]
|
|
26
26
|
end
|
|
27
27
|
end
|
|
28
|
+
|
|
29
|
+
context 'when SWD::Exception raised' do
|
|
30
|
+
it do
|
|
31
|
+
expect do
|
|
32
|
+
mock_json :get, endpoint, 'errors/unknown', status: [404, 'Not Found'] do
|
|
33
|
+
OpenIDConnect::Discovery::Provider::Config.discover! provider
|
|
34
|
+
end
|
|
35
|
+
end.to raise_error OpenIDConnect::Discovery::DiscoveryFailed
|
|
36
|
+
end
|
|
37
|
+
end
|
|
28
38
|
end
|
|
29
39
|
|
|
30
40
|
context 'when OP identifier includes custom port' do
|
|
@@ -81,6 +81,16 @@ describe OpenIDConnect::RequestObject do
|
|
|
81
81
|
end
|
|
82
82
|
end
|
|
83
83
|
|
|
84
|
+
describe '.fetch' do
|
|
85
|
+
let(:endpoint) { 'https://client.example.com/request.jwk' }
|
|
86
|
+
it do
|
|
87
|
+
mock_json :get, endpoint, 'request_object/signed', format: :jwt do
|
|
88
|
+
request_object = OpenIDConnect::RequestObject.fetch endpoint, 'secret'
|
|
89
|
+
request_object.as_json.should == jsonized.with_indifferent_access
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
84
94
|
describe '#required?' do
|
|
85
95
|
it do
|
|
86
96
|
request_object.user_info.required?(:name).should be_true
|
|
@@ -270,4 +270,59 @@ describe OpenIDConnect::ResponseObject::IdToken do
|
|
|
270
270
|
end
|
|
271
271
|
end
|
|
272
272
|
end
|
|
273
|
+
|
|
274
|
+
describe '.self_issued' do
|
|
275
|
+
subject { self_issued }
|
|
276
|
+
let(:user_jwk) { JSON::JWK.new(public_key) }
|
|
277
|
+
let(:self_issued) do
|
|
278
|
+
klass.self_issued(
|
|
279
|
+
public_key: public_key,
|
|
280
|
+
aud: 'client.example.com',
|
|
281
|
+
exp: 1.week.from_now,
|
|
282
|
+
iat: Time.now
|
|
283
|
+
)
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
[:iss, :user_id, :aud, :exp, :iat, :user_jwk].each do |attribute|
|
|
287
|
+
its(attribute) { should be_present }
|
|
288
|
+
end
|
|
289
|
+
its(:iss) { should == 'https://self-issued.me' }
|
|
290
|
+
its(:user_jwk) { should == user_jwk }
|
|
291
|
+
its(:user_id) { should == OpenIDConnect::ResponseObject::IdToken.self_issued_user_id(user_jwk) }
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
describe '.self_issued_user_id' do
|
|
295
|
+
context 'when RSA key given' do
|
|
296
|
+
let(:jwk) { JSON::JWK.new(public_key) }
|
|
297
|
+
it do
|
|
298
|
+
user_id = klass.self_issued_user_id jwk
|
|
299
|
+
user_id.should == UrlSafeBase64.encode64(
|
|
300
|
+
OpenSSL::Digest::SHA256.digest([jwk[:mod], jwk[:xpo]].join)
|
|
301
|
+
)
|
|
302
|
+
end
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
context 'when EC key given' do
|
|
306
|
+
let(:jwk) { JSON::JWK.new(ec_public_key) }
|
|
307
|
+
it do
|
|
308
|
+
expect do
|
|
309
|
+
user_id = klass.self_issued_user_id jwk
|
|
310
|
+
end.to raise_error NotImplementedError
|
|
311
|
+
end
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
context 'when unknown algorithm JWK given' do
|
|
315
|
+
let(:jwk) do
|
|
316
|
+
{
|
|
317
|
+
alg: 'unknown'
|
|
318
|
+
}
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
it do
|
|
322
|
+
expect do
|
|
323
|
+
user_id = klass.self_issued_user_id jwk
|
|
324
|
+
end.to raise_error OpenIDConnect::ResponseObject::IdToken::InvalidToken
|
|
325
|
+
end
|
|
326
|
+
end
|
|
327
|
+
end
|
|
273
328
|
end
|
|
@@ -35,7 +35,7 @@ describe Rack::OAuth2::Server::Authorize::Extension::IdToken do
|
|
|
35
35
|
end
|
|
36
36
|
end
|
|
37
37
|
|
|
38
|
-
context '
|
|
38
|
+
context 'when id_token is missing' do
|
|
39
39
|
let :app do
|
|
40
40
|
Rack::OAuth2::Server::Authorize.new do |request, response|
|
|
41
41
|
response.redirect_uri = redirect_uri
|
|
@@ -46,4 +46,23 @@ describe Rack::OAuth2::Server::Authorize::Extension::IdToken do
|
|
|
46
46
|
expect { response }.to raise_error AttrRequired::AttrMissing, "'id_token' required."
|
|
47
47
|
end
|
|
48
48
|
end
|
|
49
|
+
|
|
50
|
+
context 'when error response' do
|
|
51
|
+
let(:env) { Rack::MockRequest.env_for("/authorize?client_id=client_id") }
|
|
52
|
+
let(:request) { Rack::OAuth2::Server::Authorize::Extension::IdToken::Request.new env }
|
|
53
|
+
|
|
54
|
+
it 'should set protocol_params_location = :fragment' do
|
|
55
|
+
expect { request.bad_request! }.to raise_error(Rack::OAuth2::Server::Authorize::BadRequest) { |e|
|
|
56
|
+
e.protocol_params_location.should == :fragment
|
|
57
|
+
}
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
context 'when openid scope given' do
|
|
62
|
+
let(:env) { Rack::MockRequest.env_for("/authorize?client_id=client_id&scope=openid") }
|
|
63
|
+
let(:request) { Rack::OAuth2::Server::Authorize::Extension::IdToken::Request.new env }
|
|
64
|
+
it do
|
|
65
|
+
request.openid_connect_request?.should be_true
|
|
66
|
+
end
|
|
67
|
+
end
|
|
49
68
|
end
|
data/spec/spec_helper.rb
CHANGED
|
@@ -3,16 +3,5 @@ require 'cover_me'
|
|
|
3
3
|
require 'rspec'
|
|
4
4
|
require 'openid_connect'
|
|
5
5
|
|
|
6
|
-
require 'helpers/
|
|
7
|
-
|
|
8
|
-
def rsa
|
|
9
|
-
@rsa ||= OpenSSL::PKey::RSA.generate 2048
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
def public_key
|
|
13
|
-
@public_key ||= rsa.public_key
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def private_key
|
|
17
|
-
@private_key ||= OpenSSL::PKey::RSA.new rsa.export(OpenSSL::Cipher::Cipher.new('DES-EDE3-CBC'), 'pass-phrase'), 'pass-phrase'
|
|
18
|
-
end
|
|
6
|
+
require 'helpers/crypto_spec_helper'
|
|
7
|
+
require 'helpers/webmock_helper'
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: openid_connect
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.3.
|
|
4
|
+
version: 0.3.7
|
|
5
5
|
prerelease:
|
|
6
6
|
platform: ruby
|
|
7
7
|
authors:
|
|
@@ -9,7 +9,7 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date: 2012-10-
|
|
12
|
+
date: 2012-10-29 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: json
|
|
@@ -270,6 +270,7 @@ files:
|
|
|
270
270
|
- lib/rack/oauth2/server/id_token_response.rb
|
|
271
271
|
- lib/rack/oauth2/server/resource/error_with_connect_ext.rb
|
|
272
272
|
- openid_connect.gemspec
|
|
273
|
+
- spec/helpers/crypto_spec_helper.rb
|
|
273
274
|
- spec/helpers/webmock_helper.rb
|
|
274
275
|
- spec/mock_response/access_token/bearer.json
|
|
275
276
|
- spec/mock_response/access_token/bearer_with_id_token.json
|
|
@@ -287,6 +288,7 @@ files:
|
|
|
287
288
|
- spec/mock_response/id_token.json
|
|
288
289
|
- spec/mock_response/public_keys/jwk.json
|
|
289
290
|
- spec/mock_response/public_keys/x509.pem
|
|
291
|
+
- spec/mock_response/request_object/signed.jwt
|
|
290
292
|
- spec/mock_response/user_info/openid.json
|
|
291
293
|
- spec/openid_connect/access_token_spec.rb
|
|
292
294
|
- spec/openid_connect/client/registrar_spec.rb
|
|
@@ -296,6 +298,7 @@ files:
|
|
|
296
298
|
- spec/openid_connect/discovery/principal/email_spec.rb
|
|
297
299
|
- spec/openid_connect/discovery/principal/uri_spec.rb
|
|
298
300
|
- spec/openid_connect/discovery/principal_spec.rb
|
|
301
|
+
- spec/openid_connect/discovery/provider/config/resource_spec.rb
|
|
299
302
|
- spec/openid_connect/discovery/provider/config/response_spec.rb
|
|
300
303
|
- spec/openid_connect/discovery/provider/config_spec.rb
|
|
301
304
|
- spec/openid_connect/discovery/provider_spec.rb
|
|
@@ -327,7 +330,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
327
330
|
version: '0'
|
|
328
331
|
segments:
|
|
329
332
|
- 0
|
|
330
|
-
hash:
|
|
333
|
+
hash: 4253340027617054014
|
|
331
334
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
332
335
|
none: false
|
|
333
336
|
requirements:
|
|
@@ -336,7 +339,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
336
339
|
version: '0'
|
|
337
340
|
segments:
|
|
338
341
|
- 0
|
|
339
|
-
hash:
|
|
342
|
+
hash: 4253340027617054014
|
|
340
343
|
requirements: []
|
|
341
344
|
rubyforge_project:
|
|
342
345
|
rubygems_version: 1.8.24
|
|
@@ -344,6 +347,7 @@ signing_key:
|
|
|
344
347
|
specification_version: 3
|
|
345
348
|
summary: OpenID Connect Server & Client Library
|
|
346
349
|
test_files:
|
|
350
|
+
- spec/helpers/crypto_spec_helper.rb
|
|
347
351
|
- spec/helpers/webmock_helper.rb
|
|
348
352
|
- spec/mock_response/access_token/bearer.json
|
|
349
353
|
- spec/mock_response/access_token/bearer_with_id_token.json
|
|
@@ -361,6 +365,7 @@ test_files:
|
|
|
361
365
|
- spec/mock_response/id_token.json
|
|
362
366
|
- spec/mock_response/public_keys/jwk.json
|
|
363
367
|
- spec/mock_response/public_keys/x509.pem
|
|
368
|
+
- spec/mock_response/request_object/signed.jwt
|
|
364
369
|
- spec/mock_response/user_info/openid.json
|
|
365
370
|
- spec/openid_connect/access_token_spec.rb
|
|
366
371
|
- spec/openid_connect/client/registrar_spec.rb
|
|
@@ -370,6 +375,7 @@ test_files:
|
|
|
370
375
|
- spec/openid_connect/discovery/principal/email_spec.rb
|
|
371
376
|
- spec/openid_connect/discovery/principal/uri_spec.rb
|
|
372
377
|
- spec/openid_connect/discovery/principal_spec.rb
|
|
378
|
+
- spec/openid_connect/discovery/provider/config/resource_spec.rb
|
|
373
379
|
- spec/openid_connect/discovery/provider/config/response_spec.rb
|
|
374
380
|
- spec/openid_connect/discovery/provider/config_spec.rb
|
|
375
381
|
- spec/openid_connect/discovery/provider_spec.rb
|