openid_connect 0.0.11 → 0.0.12

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- openid_connect (0.0.10)
4
+ openid_connect (0.0.11)
5
5
  activemodel (>= 3)
6
6
  attr_required (>= 0.0.3)
7
7
  json (>= 1.4.3)
@@ -62,8 +62,8 @@ GEM
62
62
  mail (>= 2.2.5)
63
63
  validate_url (0.2.0)
64
64
  activemodel (>= 3.0.0)
65
- webmock (1.7.2)
66
- addressable (> 2.2.5, ~> 2.2)
65
+ webmock (1.7.4)
66
+ addressable (~> 2.2, > 2.2.5)
67
67
  crack (>= 0.1.7)
68
68
 
69
69
  PLATFORMS
data/README.rdoc CHANGED
@@ -8,8 +8,9 @@ OpenID Connect Server & Client Library
8
8
 
9
9
  == Resources
10
10
 
11
- * View Source on GitHub (http://github.com/nov/openid_connect)
12
- * Report Issues on GitHub (http://github.com/nov/openid_connect/issues)
11
+ * View Source on GitHub (https://github.com/nov/openid_connect)
12
+ * Report Issues on GitHub (https://github.com/nov/openid_connect/issues)
13
+ * Subscribe Update Info (https://www.facebook.com/pages/OpenID-Connect/134681459957370)
13
14
 
14
15
  == Examples
15
16
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.11
1
+ 0.0.12
@@ -9,36 +9,44 @@ module OpenIDConnect
9
9
  class ResponseObject
10
10
  include ActiveModel::Validations, AttrRequired, AttrOptional
11
11
 
12
+ class ValidationFailed < Exception
13
+ attr_reader :errors
14
+
15
+ def initialize(errors)
16
+ super errors.full_messages.to_sentence
17
+ @errors = errors
18
+ end
19
+ end
20
+
12
21
  def initialize(attributes = {})
13
- all_attriutes.each do |_attr_|
22
+ all_attributes.each do |_attr_|
14
23
  self.send :"#{_attr_}=", attributes[_attr_]
15
24
  end
16
25
  attr_missing!
17
26
  end
18
27
 
19
- def all_attriutes
28
+ def all_attributes
20
29
  required_attributes + optional_attributes
21
30
  end
22
31
 
23
32
  def require_at_least_one_attributes
24
- all_blank = all_attriutes.all? do |key|
33
+ all_blank = all_attributes.all? do |key|
25
34
  self.send(key).blank?
26
35
  end
27
36
  errors.add :base, 'At least one attribute is required' if all_blank
28
37
  end
29
38
 
30
39
  def as_json(options = {})
31
- (all_attriutes - Array(hidden_attributes)).inject({}) do |hash, _attr_|
40
+ validate!
41
+ all_attributes.inject({}) do |hash, _attr_|
32
42
  hash.merge! _attr_ => self.send(_attr_)
33
43
  end.delete_if do |key, value|
34
44
  value.nil?
35
45
  end
36
46
  end
37
47
 
38
- private
39
-
40
- def hidden_attributes
41
- nil
48
+ def validate!
49
+ raise ValidationFailed.new(errors) unless valid?
42
50
  end
43
51
  end
44
52
  end
@@ -6,10 +6,13 @@ module OpenIDConnect
6
6
  class InvalidToken < Exception; end
7
7
 
8
8
  attr_required :iss, :user_id, :aud, :exp
9
- attr_optional :iso29115, :nonce, :issued_to, :secret
9
+ attr_optional :iso29115, :nonce, :issued_to
10
10
 
11
11
  def initialize(attributes = {})
12
12
  super
13
+ (all_attributes - [:exp]).each do |key|
14
+ self.send "#{key}=", self.send(key).try(:to_s)
15
+ end
13
16
  @exp = @exp.to_i
14
17
  end
15
18
 
@@ -18,19 +21,12 @@ module OpenIDConnect
18
21
  raise InvalidToken.new('Invalid audience or expired')
19
22
  end
20
23
 
21
- def to_jwt
22
- raise Exception.new('Secret Required') unless secret
23
- JWT.encode as_json, secret
24
+ def to_jwt(key, algorithm = 'RS256')
25
+ JWT.encode as_json, key, algorithm
24
26
  end
25
27
 
26
- def self.from_jwt(jwt, secret)
27
- new JWT.decode(jwt, secret).with_indifferent_access.merge(:secret => secret)
28
- end
29
-
30
- private
31
-
32
- def hidden_attributes
33
- :secret
28
+ def self.from_jwt(jwt_string, key)
29
+ new JWT.decode(jwt_string, key).with_indifferent_access
34
30
  end
35
31
  end
36
32
  end
@@ -7,9 +7,9 @@ module OpenIDConnect
7
7
  attr_optional :phone_number
8
8
 
9
9
  attr_optional :verified, :gender, :zoneinfo, :locale
10
- validates_inclusion_of :verified, :in => [true, false], :allow_nil => true
11
- validates_inclusion_of :gender, :in => [:male, :female], :allow_nil => true
12
- validates_inclusion_of :zoneinfo, :in => TZInfo::TimezoneProxy.all.collect(&:name), :allow_nil => true
10
+ validates :verified, :inclusion => {:in => [true, false]}, :allow_nil => true
11
+ validates :gender, :inclusion => {:in => ['male', 'female']}, :allow_nil => true
12
+ validates :zoneinfo, :inclusion => {:in => TZInfo::TimezoneProxy.all.collect(&:name)}, :allow_nil => true
13
13
  # TODO: validate locale
14
14
 
15
15
  attr_optional :birthday, :updated_time
@@ -25,6 +25,13 @@ module OpenIDConnect
25
25
 
26
26
  validate :require_at_least_one_attributes
27
27
 
28
+ def initialize(attributes = {})
29
+ super
30
+ (all_attributes - [:verified, :address]).each do |key|
31
+ self.send "#{key}=", self.send(key).try(:to_s)
32
+ end
33
+ end
34
+
28
35
  def validate_address
29
36
  errors.add :address, 'cannot be blank' unless address.blank? || address.valid?
30
37
  end
@@ -1,11 +1,21 @@
1
1
  module Rack::OAuth2::Server
2
2
  module IdTokenResponse
3
3
  def self.included(klass)
4
- klass.send :attr_optional, :id_token
4
+ klass.send :attr_optional, :id_token, :private_key
5
5
  klass.class_eval do
6
+ def jwt_string
7
+ case id_token
8
+ when String
9
+ id_token
10
+ when OpenIDConnect::ResponseObject::IdToken
11
+ raise AttrRequired::AttrMissing.new('private_key is required') unless private_key
12
+ id_token.to_jwt private_key
13
+ end
14
+ end
15
+
6
16
  def protocol_params_with_id_token
7
17
  protocol_params_without_id_token.merge(
8
- :id_token => id_token.try(:to_jwt)
18
+ :id_token => jwt_string
9
19
  )
10
20
  end
11
21
  alias_method_chain :protocol_params, :id_token
@@ -1,10 +1,10 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe OpenIDConnect::ResponseObject::IdToken do
4
- let(:klass) { OpenIDConnect::ResponseObject::IdToken }
5
- let(:id_token) { klass.new attributes }
6
- let(:attributes) { required_attributes }
7
- let(:ext) { 10.minutes.from_now }
4
+ let(:klass) { OpenIDConnect::ResponseObject::IdToken }
5
+ let(:id_token) { klass.new attributes }
6
+ let(:attributes) { required_attributes }
7
+ let(:ext) { 10.minutes.from_now }
8
8
  let :required_attributes do
9
9
  {
10
10
  :iss => 'https://server.example.com',
@@ -17,7 +17,7 @@ describe OpenIDConnect::ResponseObject::IdToken do
17
17
  describe 'attributes' do
18
18
  subject { klass }
19
19
  its(:required_attributes) { should == [:iss, :user_id, :aud, :exp] }
20
- its(:optional_attributes) { should == [:iso29115, :nonce, :issued_to, :secret] }
20
+ its(:optional_attributes) { should == [:iso29115, :nonce, :issued_to] }
21
21
  end
22
22
 
23
23
  describe '#verify!' do
@@ -40,31 +40,21 @@ describe OpenIDConnect::ResponseObject::IdToken do
40
40
  end
41
41
 
42
42
  describe '#to_jwt' do
43
- subject { id_token.to_jwt }
44
-
45
- context 'when secret is given' do
46
- let(:attributes) { required_attributes.merge(:secret => 'secret') }
47
- it { should be_a String }
48
- end
49
-
50
- context 'otherwise' do
51
- it do
52
- expect { id_token.to_jwt }.should raise_error OpenIDConnect::Exception, 'Secret Required'
53
- end
54
- end
43
+ subject { id_token.to_jwt private_key }
44
+ it { should be_a String }
55
45
  end
56
46
 
57
47
  describe '#as_json' do
58
48
  subject { id_token.as_json }
59
- let(:attributes) { required_attributes.merge(:secret => 'secret') }
49
+ let(:attributes) { required_attributes }
60
50
  it { should_not include :secret }
61
51
  end
62
52
 
63
53
  describe '.from_jwt' do
64
- subject { klass.from_jwt id_token.to_jwt, 'secret' }
65
- let(:attributes) { required_attributes.merge(:secret => 'secret') }
54
+ subject { klass.from_jwt id_token.to_jwt(private_key), public_key }
55
+ let(:attributes) { required_attributes }
66
56
  it { should be_a klass }
67
- [:iss, :user_id, :aud, :secret].each do |key|
57
+ [:iss, :user_id, :aud].each do |key|
68
58
  its(key) { should == attributes[key] }
69
59
  end
70
60
  its(:exp) { should == attributes[:exp].to_i }
@@ -4,16 +4,17 @@ describe OpenIDConnect::ResponseObject do
4
4
  class OpenIDConnect::ResponseObject::SubClass < OpenIDConnect::ResponseObject
5
5
  attr_required :required
6
6
  attr_optional :optional
7
+ validates :required, :inclusion => {:in => ['Required', 'required']}, :length => 1..10
7
8
  end
8
9
 
9
- let(:klass) { OpenIDConnect::ResponseObject::SubClass }
10
10
  subject { klass.new attributes }
11
+ let(:klass) { OpenIDConnect::ResponseObject::SubClass }
12
+ let :attributes do
13
+ {:required => 'Required', :optional => 'Optional'}
14
+ end
11
15
 
12
16
  context 'when required attributes are given' do
13
17
  context 'when optional attributes are given' do
14
- let :attributes do
15
- {:required => 'Required', :optional => 'Optional'}
16
- end
17
18
  its(:required) { should == 'Required' }
18
19
  its(:optional) { should == 'Optional' }
19
20
  end
@@ -45,11 +46,24 @@ describe OpenIDConnect::ResponseObject do
45
46
  end
46
47
 
47
48
  describe '#as_json' do
48
- let :attributes do
49
- {:required => 'Required', :optional => 'Optional'}
50
- end
51
49
  its(:as_json) do
52
50
  should == {:required => 'Required', :optional => 'Optional'}
53
51
  end
54
52
  end
53
+
54
+ describe '#validate!' do
55
+ let(:invalid) do
56
+ instance = klass.new attributes
57
+ instance.required = 'Out of List and Too Long'
58
+ instance
59
+ end
60
+
61
+ it 'should raise OpenIDConnect::ResponseObject::ValidationFailed with ActiveModel::Errors' do
62
+ expect { invalid.validate! }.should raise_error(OpenIDConnect::ResponseObject::ValidationFailed) { |e|
63
+ e.message.should include 'Required is not included in the list'
64
+ e.message.should include 'Required is too long (maximum is 10 characters)'
65
+ e.errors.should be_a ActiveModel::Errors
66
+ }
67
+ end
68
+ end
55
69
  end
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper.rb'
2
2
 
3
3
  describe OpenIDConnect::Server::IdToken do
4
- let(:request) { Rack::MockRequest.new app }
4
+ let(:request) { Rack::MockRequest.new app }
5
5
  let :app do
6
6
  OpenIDConnect::Server::IdToken.new do |req, res|
7
7
  res.id_token = id_token
@@ -14,7 +14,7 @@ describe OpenIDConnect::Server::IdToken do
14
14
  )
15
15
  end
16
16
  let :params do
17
- {:id_token => id_token.to_jwt}
17
+ {:id_token => id_token.to_jwt(private_key) }
18
18
  end
19
19
  let :id_token do
20
20
  OpenIDConnect::ResponseObject::IdToken.new(
@@ -24,11 +24,32 @@ describe Rack::OAuth2::Server::Authorize::Extension::CodeAndToken do
24
24
  response.code = 'code'
25
25
  response.access_token = bearer_token
26
26
  response.id_token = id_token
27
+ response.private_key = private_key
27
28
  response.approve!
28
29
  end
29
30
  end
30
31
  its(:status) { should == 302 }
31
- its(:location) { should == "#{redirect_uri}?code=code#access_token=access_token&id_token=#{id_token.to_jwt}&token_type=bearer" }
32
+ its(:location) { should == "#{redirect_uri}?code=code#access_token=access_token&id_token=#{id_token.to_jwt(private_key)}&token_type=bearer" }
33
+
34
+ context 'when id_token is String' do
35
+ let(:id_token) { 'id_token' }
36
+ its(:location) { should == "#{redirect_uri}?code=code#access_token=access_token&id_token=id_token&token_type=bearer" }
37
+ end
38
+
39
+ context 'when private_key is missing' do
40
+ let :app do
41
+ Rack::OAuth2::Server::Authorize.new do |request, response|
42
+ response.redirect_uri = redirect_uri
43
+ response.code = 'code'
44
+ response.access_token = bearer_token
45
+ response.id_token = id_token
46
+ response.approve!
47
+ end
48
+ end
49
+ it do
50
+ expect { response }.should raise_error AttrRequired::AttrMissing, 'private_key is required'
51
+ end
52
+ end
32
53
  end
33
54
 
34
55
  context "otherwise" do
@@ -22,11 +22,31 @@ describe Rack::OAuth2::Server::Authorize::Token do
22
22
  response.redirect_uri = redirect_uri
23
23
  response.access_token = bearer_token
24
24
  response.id_token = id_token
25
+ response.private_key = private_key
25
26
  response.approve!
26
27
  end
27
28
  end
28
29
  its(:status) { should == 302 }
29
- its(:location) { should == "#{redirect_uri}#access_token=access_token&id_token=#{id_token.to_jwt}&token_type=bearer" }
30
+ its(:location) { should == "#{redirect_uri}#access_token=access_token&id_token=#{id_token.to_jwt(private_key)}&token_type=bearer" }
31
+
32
+ context 'when id_token is String' do
33
+ let(:id_token) { 'id_token' }
34
+ its(:location) { should == "#{redirect_uri}#access_token=access_token&id_token=id_token&token_type=bearer" }
35
+ end
36
+
37
+ context 'when private_key is missing' do
38
+ let :app do
39
+ Rack::OAuth2::Server::Authorize.new do |request, response|
40
+ response.redirect_uri = redirect_uri
41
+ response.access_token = bearer_token
42
+ response.id_token = id_token
43
+ response.approve!
44
+ end
45
+ end
46
+ it do
47
+ expect { response }.should raise_error AttrRequired::AttrMissing, 'private_key is required'
48
+ end
49
+ end
30
50
  end
31
51
 
32
52
  context "otherwise" do
@@ -26,10 +26,28 @@ describe Rack::OAuth2::Server::Token::AuthorizationCode do
26
26
  Rack::OAuth2::Server::Token.new do |request, response|
27
27
  response.access_token = Rack::OAuth2::AccessToken::Bearer.new(:access_token => 'access_token')
28
28
  response.id_token = id_token
29
+ response.private_key = private_key
29
30
  end
30
31
  end
31
32
  its(:status) { should == 200 }
32
- its(:body) { should include "\"id_token\":\"#{id_token.to_jwt}\"" }
33
+ its(:body) { should include "\"id_token\":\"#{id_token.to_jwt(private_key)}\"" }
34
+
35
+ context 'when id_token is String' do
36
+ let(:id_token) { 'id_token' }
37
+ its(:body) { should include "\"id_token\":\"id_token\"" }
38
+ end
39
+
40
+ context 'when private_key is missing' do
41
+ let :app do
42
+ Rack::OAuth2::Server::Token.new do |request, response|
43
+ response.access_token = Rack::OAuth2::AccessToken::Bearer.new(:access_token => 'access_token')
44
+ response.id_token = id_token
45
+ end
46
+ end
47
+ it do
48
+ expect { response }.should raise_error AttrRequired::AttrMissing, 'private_key is required'
49
+ end
50
+ end
33
51
  end
34
52
 
35
53
  context "otherwise" do
@@ -25,10 +25,28 @@ describe Rack::OAuth2::Server::Token::RefreshToken do
25
25
  Rack::OAuth2::Server::Token.new do |request, response|
26
26
  response.access_token = Rack::OAuth2::AccessToken::Bearer.new(:access_token => 'access_token')
27
27
  response.id_token = id_token
28
+ response.private_key = private_key
28
29
  end
29
30
  end
30
31
  its(:status) { should == 200 }
31
- its(:body) { should include "\"id_token\":\"#{id_token.to_jwt}\"" }
32
+ its(:body) { should include "\"id_token\":\"#{id_token.to_jwt(private_key)}\"" }
33
+
34
+ context 'when id_token is String' do
35
+ let(:id_token) { 'id_token' }
36
+ its(:body) { should include "\"id_token\":\"id_token\"" }
37
+ end
38
+
39
+ context 'when private_key is missing' do
40
+ let :app do
41
+ Rack::OAuth2::Server::Token.new do |request, response|
42
+ response.access_token = Rack::OAuth2::AccessToken::Bearer.new(:access_token => 'access_token')
43
+ response.id_token = id_token
44
+ end
45
+ end
46
+ it do
47
+ expect { response }.should raise_error AttrRequired::AttrMissing, 'private_key is required'
48
+ end
49
+ end
32
50
  end
33
51
 
34
52
  context "otherwise" do
data/spec/spec_helper.rb CHANGED
@@ -1,4 +1,16 @@
1
1
  require 'rspec'
2
2
  require 'openid_connect'
3
3
 
4
- require 'helpers/webmock_helper'
4
+ require 'helpers/webmock_helper'
5
+
6
+ def rsa
7
+ @rsa ||= OpenSSL::PKey::RSA.generate 2048
8
+ end
9
+
10
+ def public_key
11
+ @public_key ||= rsa.public_key
12
+ end
13
+
14
+ def private_key
15
+ @private_key ||= OpenSSL::PKey::RSA.new rsa.export(OpenSSL::Cipher::Cipher.new('aes256'), 'pass-phrase'), 'pass-phrase'
16
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: openid_connect
3
3
  version: !ruby/object:Gem::Version
4
- hash: 9
4
+ hash: 7
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 11
10
- version: 0.0.11
9
+ - 12
10
+ version: 0.0.12
11
11
  platform: ruby
12
12
  authors:
13
13
  - nov matake
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-08-17 00:00:00 Z
18
+ date: 2011-08-18 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: activemodel