openid_connect 0.3.6 → 0.3.7
Sign up to get free protection for your applications and to get access to all the features.
- 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
|