openid_connect 0.0.4 → 0.0.5

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/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format=documentation
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- openid_connect (0.0.3)
4
+ openid_connect (0.0.4)
5
5
  activemodel (>= 3)
6
6
  attr_required (>= 0.0.3)
7
7
  json (>= 1.4.3)
@@ -14,16 +14,18 @@ PATH
14
14
  GEM
15
15
  remote: http://rubygems.org/
16
16
  specs:
17
- activemodel (3.0.5)
18
- activesupport (= 3.0.5)
17
+ activemodel (3.0.9)
18
+ activesupport (= 3.0.9)
19
19
  builder (~> 2.1.2)
20
- i18n (~> 0.4)
21
- activesupport (3.0.5)
20
+ i18n (~> 0.5.0)
21
+ activesupport (3.0.9)
22
+ addressable (2.2.6)
22
23
  attr_required (0.0.3)
23
24
  builder (2.1.2)
25
+ crack (0.1.8)
24
26
  diff-lcs (1.1.2)
25
27
  httpclient (2.2.1)
26
- i18n (0.6.0)
28
+ i18n (0.5.0)
27
29
  json (1.5.3)
28
30
  jwt (0.1.3)
29
31
  json (>= 1.2.4)
@@ -60,6 +62,9 @@ GEM
60
62
  mail (>= 2.2.5)
61
63
  validate_url (0.2.0)
62
64
  activemodel (>= 3.0.0)
65
+ webmock (1.6.4)
66
+ addressable (> 2.2.5, ~> 2.2)
67
+ crack (>= 0.1.7)
63
68
 
64
69
  PLATFORMS
65
70
  ruby
@@ -69,3 +74,4 @@ DEPENDENCIES
69
74
  rake (>= 0.8)
70
75
  rcov (>= 0.9)
71
76
  rspec (>= 2)
77
+ webmock (>= 1.6.2)
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.4
1
+ 0.0.5
@@ -2,17 +2,16 @@ module OpenIDConnect
2
2
  class AccessToken < Rack::OAuth2::AccessToken::Bearer
3
3
  attr_required :client
4
4
 
5
+ def initialize(attributes = {})
6
+ super
7
+ @token_type = :bearer
8
+ end
9
+
5
10
  def user_info!(scheme = :openid)
6
- klass = case scheme
7
- when :openid
8
- ResponseObject::UserInfo::OpenID
9
- else
10
- raise "Unknown Scheme: #{scheme}"
11
- end
12
11
  hash = resource_request do
13
12
  get client.user_info_uri
14
13
  end
15
- klass.new hash
14
+ ResponseObject::UserInfo::OpenID.new hash
16
15
  end
17
16
 
18
17
  def id_token!
@@ -29,10 +28,14 @@ module OpenIDConnect
29
28
  case res.status
30
29
  when 200
31
30
  JSON.parse(res.body).with_indifferent_access
31
+ when 400
32
+ raise BadRequest.new('API Access Faild')
32
33
  when 401
33
- raise OpenIDConnect::Unauthorized.new('Access Token Invalid or Expired')
34
+ raise Unauthorized.new('Access Token Invalid or Expired')
35
+ when 403
36
+ raise Forbidden.new('Insufficient Scope')
34
37
  else
35
- raise OpenIDConnect::BadRequest.new('API Access Faild')
38
+ raise HttpError.new(res.status, 'Unknown HttpError')
36
39
  end
37
40
  end
38
41
  end
@@ -19,6 +19,7 @@ module OpenIDConnect
19
19
 
20
20
  def access_token!
21
21
  token = super
22
+ raise Exception.new("Unexpected Token Type: #{token.token_type}") unless token.token_type == :bearer
22
23
  AccessToken.new token.token_response.merge(:client => self)
23
24
  end
24
25
 
@@ -4,26 +4,26 @@ module OpenIDConnect
4
4
  class HttpError < Exception
5
5
  attr_accessor :status, :response
6
6
  def initialize(status, message, response = nil)
7
+ super message
7
8
  @status = status
8
- @message = message
9
9
  @response = response
10
10
  end
11
11
  end
12
12
 
13
13
  class BadRequest < HttpError
14
- def initialize(message, response = nil)
14
+ def initialize(message = nil, response = nil)
15
15
  super 400, message, response
16
16
  end
17
17
  end
18
18
 
19
19
  class Unauthorized < HttpError
20
- def initialize(message, response = nil)
20
+ def initialize(message = nil, response = nil)
21
21
  super 401, message, response
22
22
  end
23
23
  end
24
24
 
25
25
  class Forbidden < HttpError
26
- def initialize(message, response = nil)
26
+ def initialize(message = nil, response = nil)
27
27
  super 403, message, response
28
28
  end
29
29
  end
@@ -20,10 +20,6 @@ module OpenIDConnect
20
20
  required_attributes + optional_attributes
21
21
  end
22
22
 
23
- def hidden_attributes
24
- nil
25
- end
26
-
27
23
  def require_at_least_one_attributes
28
24
  all_blank = all_attriutes.all? do |key|
29
25
  self.send(key).blank?
@@ -38,6 +34,12 @@ module OpenIDConnect
38
34
  value.nil?
39
35
  end
40
36
  end
37
+
38
+ private
39
+
40
+ def hidden_attributes
41
+ nil
42
+ end
41
43
  end
42
44
  end
43
45
 
@@ -6,17 +6,20 @@ module OpenIDConnect
6
6
  attr_required :iss, :user_id, :aud, :exp
7
7
  attr_optional :iso29115, :nonce, :issued_to, :secret
8
8
 
9
- def hidden_attributes
10
- :secret
11
- end
12
-
13
9
  def to_jwt
10
+ raise Exception.new('Secret Required') unless secret
14
11
  JWT.encode as_json, secret
15
12
  end
16
13
 
17
14
  def self.from_jwt(jwt, secret)
18
15
  new JWT.decode(jwt, secret).with_indifferent_access.merge(:secret => secret)
19
16
  end
17
+
18
+ private
19
+
20
+ def hidden_attributes
21
+ :secret
22
+ end
20
23
  end
21
24
  end
22
25
  end
@@ -21,4 +21,5 @@ Gem::Specification.new do |s|
21
21
  s.add_development_dependency "rake", ">= 0.8"
22
22
  s.add_development_dependency "rcov", ">= 0.9"
23
23
  s.add_development_dependency "rspec", ">= 2"
24
+ s.add_development_dependency "webmock", ">= 1.6.2"
24
25
  end
@@ -0,0 +1,42 @@
1
+ require 'webmock/rspec'
2
+
3
+ module WebMockHelper
4
+ def mock_json(method, endpoint, response_file, options = {})
5
+ stub_request(method, endpoint).with(
6
+ request_for(method, options)
7
+ ).to_return(
8
+ response_for(response_file, options)
9
+ )
10
+ yield
11
+ a_request(method, endpoint).with(
12
+ request_for(method, options)
13
+ ).should have_been_made.once
14
+ end
15
+
16
+ private
17
+
18
+ def request_for(method, options = {})
19
+ request = {}
20
+ if options[:params]
21
+ case method
22
+ when :post, :put
23
+ request[:body] = options[:params]
24
+ else
25
+ request[:query] = options[:params]
26
+ end
27
+ end
28
+ request
29
+ end
30
+
31
+ def response_for(response_file, options = {})
32
+ response = {}
33
+ response[:body] = File.new(File.join(File.dirname(__FILE__), '../mock_response', "#{response_file}.#{options[:format] || :json}"))
34
+ if options[:status]
35
+ response[:status] = options[:status]
36
+ end
37
+ response
38
+ end
39
+ end
40
+
41
+ include WebMockHelper
42
+ WebMock.disable_net_connect!
@@ -0,0 +1,6 @@
1
+ {
2
+ "access_token":"access_token",
3
+ "refresh_token":"refresh_token",
4
+ "token_type":"bearer",
5
+ "expires_in":3600
6
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "token_type": "mac",
3
+ "mac_algorithm": "hmac-sha-256",
4
+ "expires_in": 3600,
5
+ "mac_key": "secret",
6
+ "refresh_token": "refresh_token",
7
+ "access_token": "access_token"
8
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "error": "insufficient_scope"
3
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "error": "invalid_access_token"
3
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "error": "invalid_request"
3
+ }
@@ -0,0 +1 @@
1
+ Fuckin Unknown Error
@@ -0,0 +1,7 @@
1
+ {
2
+ "iss": "http://server.example.com",
3
+ "client_id": "http://client.example.com",
4
+ "aud": "http://client.example.com",
5
+ "user_id": "user_328723",
6
+ "exp": 1303852880
7
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "id": "90125",
3
+ "name": "Jonathan Q. Doe",
4
+ "given_name": "Jonathan",
5
+ "middle_name": "Q.",
6
+ "family_name": "Doe",
7
+ "nickname": "John",
8
+ "email": "johndoe@example.com",
9
+ "verified": true,
10
+ "profile": "http://example.com/johndoe/",
11
+ "picture": "http://example.com/johndoe/me.jpg",
12
+ "website": "http://john.doe.blogs.example.net/",
13
+ "gender": "male",
14
+ "birthday": "05/02/0000",
15
+ "zoneinfo": "America/Los_Angeles",
16
+ "locale": "en_US",
17
+ "phone_number": "+1 (425) 555-1212",
18
+ "address": {
19
+ "region": "WA",
20
+ "country": "United States"
21
+ },
22
+ "last_updated": "2011-06-29T21:10:22+0000"
23
+ }
@@ -0,0 +1,68 @@
1
+ require 'spec_helper'
2
+
3
+ describe OpenIDConnect::AccessToken do
4
+ subject { token }
5
+ let :client do
6
+ OpenIDConnect::Client.new(
7
+ :identifier => 'client_id',
8
+ :host => 'server.example.com'
9
+ )
10
+ end
11
+ let :token do
12
+ OpenIDConnect::AccessToken.new(
13
+ :access_token => 'access_token',
14
+ :client => client
15
+ )
16
+ end
17
+ its(:token_type) { should == :bearer }
18
+
19
+ describe '#user_info!' do
20
+ it 'should return OpenIDConnect::ResponseObject::UserInfo::OpenID' do
21
+ mock_json :get, client.user_info_uri, 'user_info/openid', :HTTP_AUTHORIZATION => 'Bearer access_token' do
22
+ token.user_info!.should be_a OpenIDConnect::ResponseObject::UserInfo::OpenID
23
+ end
24
+ end
25
+
26
+ describe 'error handling' do
27
+ context 'when bad_request' do
28
+ it 'should raise OpenIDConnect::Forbidden' do
29
+ mock_json :get, client.user_info_uri, 'errors/invalid_request', :HTTP_AUTHORIZATION => 'Bearer access_token', :status => 400 do
30
+ expect { token.user_info! }.should raise_error OpenIDConnect::BadRequest
31
+ end
32
+ end
33
+ end
34
+
35
+ context 'when unauthorized' do
36
+ it 'should raise OpenIDConnect::Unauthorized' do
37
+ mock_json :get, client.user_info_uri, 'errors/invalid_access_token', :HTTP_AUTHORIZATION => 'Bearer access_token', :status => 401 do
38
+ expect { token.user_info! }.should raise_error OpenIDConnect::Unauthorized
39
+ end
40
+ end
41
+ end
42
+
43
+ context 'when forbidden' do
44
+ it 'should raise OpenIDConnect::Forbidden' do
45
+ mock_json :get, client.user_info_uri, 'errors/insufficient_scope', :HTTP_AUTHORIZATION => 'Bearer access_token', :status => 403 do
46
+ expect { token.user_info! }.should raise_error OpenIDConnect::Forbidden
47
+ end
48
+ end
49
+ end
50
+
51
+ context 'when unknown' do
52
+ it 'should raise OpenIDConnect::HttpError' do
53
+ mock_json :get, client.user_info_uri, 'errors/unknown', :HTTP_AUTHORIZATION => 'Bearer access_token', :status => 500 do
54
+ expect { token.user_info! }.should raise_error OpenIDConnect::HttpError
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+
61
+ describe '#id_token!' do
62
+ it 'should return OpenIDConnect::ResponseObject::IdToken' do
63
+ mock_json :get, client.introspection_uri, 'id_token', :HTTP_AUTHORIZATION => 'Bearer access_token' do
64
+ token.id_token!.should be_a OpenIDConnect::ResponseObject::IdToken
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,102 @@
1
+ require 'spec_helper'
2
+
3
+ describe OpenIDConnect::Client do
4
+ subject { client }
5
+ let(:client) { OpenIDConnect::Client.new attributes }
6
+ let(:attributes) { required_attributes }
7
+ let :required_attributes do
8
+ {
9
+ :identifier => 'client_id'
10
+ }
11
+ end
12
+
13
+ describe 'endpoints' do
14
+ context 'when host info is given' do
15
+ let :attributes do
16
+ required_attributes.merge(
17
+ :host => 'server.example.com'
18
+ )
19
+ end
20
+ its(:authorization_uri) { should include 'https://server.example.com/oauth2/authorize' }
21
+ its(:authorization_uri) { should include 'scope=openid' }
22
+ its(:introspection_uri) { should == 'https://server.example.com/id_tokens' }
23
+ its(:user_info_uri) { should == 'https://server.example.com/user_info' }
24
+ end
25
+
26
+ context 'otherwise' do
27
+ [:authorization_uri, :introspection_uri, :user_info_uri].each do |endpoint|
28
+ describe endpoint do
29
+ it do
30
+ expect { client.send endpoint }.should raise_error 'No Host Info'
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ describe '#authorization_uri' do
38
+ describe 'scope' do
39
+ subject do
40
+ query = URI.parse(client.authorization_uri :scope => scope).query
41
+ Rack::Utils.parse_query(query).with_indifferent_access[:scope]
42
+ end
43
+ let(:scope) { nil }
44
+ let :attributes do
45
+ required_attributes.merge(
46
+ :host => 'server.example.com'
47
+ )
48
+ end
49
+
50
+ context 'when scope is given' do
51
+ context 'when openid scope is included' do
52
+ let(:scope) { [:openid, :email] }
53
+ it { should == 'openid email' }
54
+ end
55
+
56
+ context 'otherwise' do
57
+ let(:scope) { :email }
58
+ it { should == 'email openid' }
59
+ end
60
+ end
61
+
62
+ context 'otherwise' do
63
+ it { should == 'openid' }
64
+ end
65
+ end
66
+ end
67
+
68
+ describe '#access_token!' do
69
+ let :attributes do
70
+ required_attributes.merge(
71
+ :secret => 'client_secret',
72
+ :token_endpoint => 'http://server.example.com/access_tokens'
73
+ )
74
+ end
75
+ let :protocol_params do
76
+ {
77
+ :client_id => 'client_id',
78
+ :client_secret => 'client_secret',
79
+ :grant_type => 'authorization_code',
80
+ :code => 'code'
81
+ }
82
+ end
83
+
84
+ context 'when bearer token is returned' do
85
+ it 'should return OpenIDConnect::AccessToken' do
86
+ mock_json :post, client.token_endpoint, 'access_token/bearer', :params => protocol_params do
87
+ client.authorization_code = 'code'
88
+ client.access_token!.should be_a OpenIDConnect::AccessToken
89
+ end
90
+ end
91
+ end
92
+
93
+ context 'otherwise' do
94
+ it 'should raise Unexpected Token Type exception' do
95
+ mock_json :post, client.token_endpoint, 'access_token/mac', :params => protocol_params do
96
+ client.authorization_code = 'code'
97
+ expect { client.access_token! }.should raise_error OpenIDConnect::Exception, 'Unexpected Token Type: mac'
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ describe OpenIDConnect::HttpError do
4
+ subject do
5
+ OpenIDConnect::HttpError.new 400, 'Bad Request'
6
+ end
7
+ its(:status) { should == 400 }
8
+ its(:message) { should == 'Bad Request' }
9
+ its(:response) { should be_nil }
10
+ end
11
+
12
+ describe OpenIDConnect::BadRequest do
13
+ its(:status) { should == 400 }
14
+ its(:message) { should == 'OpenIDConnect::BadRequest' }
15
+ end
16
+
17
+ describe OpenIDConnect::Unauthorized do
18
+ its(:status) { should == 401 }
19
+ its(:message) { should == 'OpenIDConnect::Unauthorized' }
20
+ end
21
+
22
+ describe OpenIDConnect::Forbidden do
23
+ its(:status) { should == 403 }
24
+ its(:message) { should == 'OpenIDConnect::Forbidden' }
25
+ end
@@ -2,10 +2,50 @@ require 'spec_helper'
2
2
 
3
3
  describe OpenIDConnect::ResponseObject::IdToken do
4
4
  let(:klass) { OpenIDConnect::ResponseObject::IdToken }
5
+ let(:id_token) { klass.new attributes }
6
+ let :required_attributes do
7
+ {
8
+ :iss => 'https://server.example.com',
9
+ :user_id => 'user_id',
10
+ :aud => 'client_id',
11
+ :exp => 1313424327
12
+ }
13
+ end
5
14
 
6
15
  describe 'attributes' do
7
16
  subject { klass }
8
17
  its(:required_attributes) { should == [:iss, :user_id, :aud, :exp] }
9
18
  its(:optional_attributes) { should == [:iso29115, :nonce, :issued_to, :secret] }
10
19
  end
20
+
21
+ describe '#to_jwt' do
22
+ subject { id_token.to_jwt }
23
+
24
+ context 'when secret is given' do
25
+ let(:attributes) { required_attributes.merge(:secret => 'secret') }
26
+ it { should be_a String }
27
+ end
28
+
29
+ context 'otherwise' do
30
+ let(:attributes) { required_attributes }
31
+ it do
32
+ expect { id_token.to_jwt }.should raise_error OpenIDConnect::Exception, 'Secret Required'
33
+ end
34
+ end
35
+ end
36
+
37
+ describe '#as_json' do
38
+ subject { id_token.as_json }
39
+ let(:attributes) { required_attributes.merge(:secret => 'secret') }
40
+ it { should_not include :secret }
41
+ end
42
+
43
+ describe '.from_jwt' do
44
+ subject { klass.from_jwt id_token.to_jwt, 'secret' }
45
+ let(:attributes) { required_attributes.merge(:secret => 'secret') }
46
+ it { should be_a klass }
47
+ [:iss, :user_id, :aud, :exp, :secret].each do |key|
48
+ its(key) { should == attributes[key] }
49
+ end
50
+ end
11
51
  end
data/spec/spec_helper.rb CHANGED
@@ -1,2 +1,4 @@
1
1
  require 'rspec'
2
2
  require 'openid_connect'
3
+
4
+ require 'helpers/webmock_helper'
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: openid_connect
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.0.4
5
+ version: 0.0.5
6
6
  platform: ruby
7
7
  authors:
8
8
  - nov matake
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-08-15 00:00:00 Z
13
+ date: 2011-08-16 00:00:00 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activemodel
@@ -133,6 +133,17 @@ dependencies:
133
133
  version: "2"
134
134
  type: :development
135
135
  version_requirements: *id011
136
+ - !ruby/object:Gem::Dependency
137
+ name: webmock
138
+ prerelease: false
139
+ requirement: &id012 !ruby/object:Gem::Requirement
140
+ none: false
141
+ requirements:
142
+ - - ">="
143
+ - !ruby/object:Gem::Version
144
+ version: 1.6.2
145
+ type: :development
146
+ version_requirements: *id012
136
147
  description: OpenID Connect Server & Client Library
137
148
  email:
138
149
  - nov@matake.jp
@@ -144,6 +155,7 @@ extra_rdoc_files: []
144
155
 
145
156
  files:
146
157
  - .gitignore
158
+ - .rspec
147
159
  - Gemfile
148
160
  - Gemfile.lock
149
161
  - LICENSE
@@ -162,6 +174,18 @@ files:
162
174
  - lib/rack/oauth2/server/authorize/extension/id_token.rb
163
175
  - lib/rack/oauth2/server/authorize/extension/id_token_and_token.rb
164
176
  - openid_connect.gemspec
177
+ - spec/helpers/webmock_helper.rb
178
+ - spec/mock_response/access_token/bearer.json
179
+ - spec/mock_response/access_token/mac.json
180
+ - spec/mock_response/errors/insufficient_scope.json
181
+ - spec/mock_response/errors/invalid_access_token.json
182
+ - spec/mock_response/errors/invalid_request.json
183
+ - spec/mock_response/errors/unknown.json
184
+ - spec/mock_response/id_token.json
185
+ - spec/mock_response/user_info/openid.json
186
+ - spec/openid_connect/access_token_spec.rb
187
+ - spec/openid_connect/client_spec.rb
188
+ - spec/openid_connect/exception_spec.rb
165
189
  - spec/openid_connect/response_object/id_token_spec.rb
166
190
  - spec/openid_connect/response_object/user_info/open_id/address_spec.rb
167
191
  - spec/openid_connect/response_object/user_info/open_id_spec.rb
@@ -197,6 +221,18 @@ signing_key:
197
221
  specification_version: 3
198
222
  summary: OpenID Connect Server & Client Library
199
223
  test_files:
224
+ - spec/helpers/webmock_helper.rb
225
+ - spec/mock_response/access_token/bearer.json
226
+ - spec/mock_response/access_token/mac.json
227
+ - spec/mock_response/errors/insufficient_scope.json
228
+ - spec/mock_response/errors/invalid_access_token.json
229
+ - spec/mock_response/errors/invalid_request.json
230
+ - spec/mock_response/errors/unknown.json
231
+ - spec/mock_response/id_token.json
232
+ - spec/mock_response/user_info/openid.json
233
+ - spec/openid_connect/access_token_spec.rb
234
+ - spec/openid_connect/client_spec.rb
235
+ - spec/openid_connect/exception_spec.rb
200
236
  - spec/openid_connect/response_object/id_token_spec.rb
201
237
  - spec/openid_connect/response_object/user_info/open_id/address_spec.rb
202
238
  - spec/openid_connect/response_object/user_info/open_id_spec.rb