openid_connect 0.0.4 → 0.0.5

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