rockoauth 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +7 -0
  2. data/History.txt +5 -0
  3. data/README.rdoc +422 -0
  4. data/example/README.rdoc +11 -0
  5. data/example/application.rb +158 -0
  6. data/example/config.ru +3 -0
  7. data/example/environment.rb +11 -0
  8. data/example/models/connection.rb +9 -0
  9. data/example/models/note.rb +4 -0
  10. data/example/models/user.rb +5 -0
  11. data/example/public/style.css +78 -0
  12. data/example/schema.rb +22 -0
  13. data/example/views/authorize.erb +28 -0
  14. data/example/views/create_user.erb +3 -0
  15. data/example/views/error.erb +6 -0
  16. data/example/views/home.erb +24 -0
  17. data/example/views/layout.erb +24 -0
  18. data/example/views/login.erb +20 -0
  19. data/example/views/new_client.erb +25 -0
  20. data/example/views/new_user.erb +22 -0
  21. data/example/views/show_client.erb +15 -0
  22. data/lib/rockoauth/model/authorization.rb +132 -0
  23. data/lib/rockoauth/model/client.rb +54 -0
  24. data/lib/rockoauth/model/client_owner.rb +13 -0
  25. data/lib/rockoauth/model/hashing.rb +26 -0
  26. data/lib/rockoauth/model/helpers.rb +14 -0
  27. data/lib/rockoauth/model/resource_owner.rb +22 -0
  28. data/lib/rockoauth/model.rb +38 -0
  29. data/lib/rockoauth/provider/access_token.rb +70 -0
  30. data/lib/rockoauth/provider/authorization.rb +185 -0
  31. data/lib/rockoauth/provider/error.rb +19 -0
  32. data/lib/rockoauth/provider/exchange.rb +225 -0
  33. data/lib/rockoauth/provider.rb +133 -0
  34. data/lib/rockoauth/router.rb +75 -0
  35. data/lib/rockoauth/schema/20120828112156_rockoauth_schema_original_schema.rb +35 -0
  36. data/lib/rockoauth/schema/20121024180930_rockoauth_schema_add_authorization_index.rb +13 -0
  37. data/lib/rockoauth/schema/20121025180447_rockoauth_schema_add_unique_indexes.rb +31 -0
  38. data/lib/rockoauth/schema.rb +25 -0
  39. data/lib/rockoauth.rb +1 -0
  40. data/spec/factories.rb +20 -0
  41. data/spec/request_helpers.rb +62 -0
  42. data/spec/rockoauth/model/authorization_spec.rb +237 -0
  43. data/spec/rockoauth/model/client_spec.rb +44 -0
  44. data/spec/rockoauth/model/helpers_spec.rb +25 -0
  45. data/spec/rockoauth/model/resource_owner_spec.rb +87 -0
  46. data/spec/rockoauth/provider/access_token_spec.rb +138 -0
  47. data/spec/rockoauth/provider/authorization_spec.rb +356 -0
  48. data/spec/rockoauth/provider/exchange_spec.rb +361 -0
  49. data/spec/rockoauth/provider_spec.rb +560 -0
  50. data/spec/spec_helper.rb +80 -0
  51. data/spec/test_app/helper.rb +36 -0
  52. data/spec/test_app/provider/application.rb +67 -0
  53. data/spec/test_app/provider/views/authorize.erb +19 -0
  54. metadata +238 -0
@@ -0,0 +1,31 @@
1
+ class RockoauthSchemaAddUniqueIndexes < ActiveRecord::Migration
2
+ FIELDS = [:code, :refresh_token_hash]
3
+
4
+ def self.up
5
+ FIELDS.each do |field|
6
+ remove_index :oauth2_authorizations, :name => "index_oauth2_client_id_and_#{field}"
7
+ add_index :oauth2_authorizations, [:client_id, field], :unique => true, :name => "index_oauth2_client_id_#{field}"
8
+ end
9
+ remove_index :oauth2_authorizations, [:access_token_hash]
10
+ add_index :oauth2_authorizations, [:access_token_hash], :unique => true
11
+
12
+ remove_index :oauth2_clients, [:client_id]
13
+ add_index :oauth2_clients, [:client_id], :unique => true
14
+
15
+ add_index :oauth2_clients, [:name], :unique => true
16
+ end
17
+
18
+ def self.down
19
+ FIELDS.each do |field|
20
+ remove_index :oauth2_authorizations, [:client_id, field]
21
+ add_index :oauth2_authorizations, [:client_id, field]
22
+ end
23
+ remove_index :oauth2_authorizations, [:access_token_hash]
24
+ add_index :oauth2_authorizations, [:access_token_hash]
25
+
26
+ remove_index :oauth2_clients, [:client_id]
27
+ add_index :oauth2_clients, [:client_id]
28
+
29
+ remove_index :oauth2_clients, [:name]
30
+ end
31
+ end
@@ -0,0 +1,25 @@
1
+ module RockOAuth
2
+
3
+ class Schema
4
+ def self.migrate
5
+ ActiveRecord::Base.logger ||= Logger.new(StringIO.new)
6
+ ActiveRecord::Migrator.up(migrations_path)
7
+ end
8
+ class << self
9
+ alias :up :migrate
10
+ end
11
+
12
+ def self.rollback
13
+ ActiveRecord::Base.logger ||= Logger.new(StringIO.new)
14
+ ActiveRecord::Migrator.down(migrations_path)
15
+ end
16
+ class << self
17
+ alias :down :rollback
18
+ end
19
+
20
+ def self.migrations_path
21
+ File.expand_path('../schema', __FILE__)
22
+ end
23
+ end
24
+
25
+ end
data/lib/rockoauth.rb ADDED
@@ -0,0 +1 @@
1
+ require 'rockoauth/provider'
data/spec/factories.rb ADDED
@@ -0,0 +1,20 @@
1
+ require 'factory_girl'
2
+
3
+ Factory.sequence :client_name do |n|
4
+ "Client ##{n}"
5
+ end
6
+
7
+ Factory.sequence :user_name do |n|
8
+ "User ##{n}"
9
+ end
10
+
11
+ Factory.define :owner, :class => TestApp::User do |u|
12
+ u.name { Factory.next :user_name }
13
+ end
14
+
15
+ Factory.define :client, :class => RockOAuth::Model::Client do |c|
16
+ c.client_id { RockOAuth.random_string }
17
+ c.client_secret { RockOAuth.random_string }
18
+ c.name { Factory.next :client_name }
19
+ c.redirect_uri 'https://client.example.com/cb'
20
+ end
@@ -0,0 +1,62 @@
1
+ require "socket"
2
+
3
+ module RequestHelpers
4
+ require "net/http"
5
+
6
+ SERVER_PORT = TCPServer.new(0).addr[1]
7
+
8
+ def querystring(params)
9
+ params.map { |k,v| "#{ CGI.escape k.to_s }=#{ CGI.escape v.to_s }" }.join("&")
10
+ end
11
+
12
+ def get(query_params)
13
+ uri = URI.parse("http://localhost:#{SERVER_PORT}/authorize?" + querystring(query_params))
14
+ Net::HTTP.get_response(uri)
15
+ end
16
+
17
+ def allow_or_deny(query_params)
18
+ Net::HTTP.post_form(URI.parse("http://localhost:#{SERVER_PORT}/allow"), query_params)
19
+ end
20
+
21
+ def post_basic_auth(auth_params, query_params)
22
+ url = "http://#{ auth_params["client_id"] }:#{ auth_params["client_secret"] }@localhost:#{SERVER_PORT}/authorize"
23
+ Net::HTTP.post_form(URI.parse(url), query_params)
24
+ end
25
+
26
+ def post(body_params, query_params = {})
27
+ uri = URI.parse("http://localhost:#{SERVER_PORT}/authorize?" + querystring(query_params))
28
+ Net::HTTP.start(uri.host, uri.port) do |http|
29
+ http.post(uri.path + "?" + uri.query.to_s, querystring(body_params))
30
+ end
31
+ end
32
+
33
+ def validate_response(response, status, body)
34
+ expect(response.code.to_i).to eq(status)
35
+ expect(response.body).to eq(body)
36
+ expect(response["Cache-Control"]).to eq("no-store")
37
+ end
38
+
39
+ def validate_json_response(response, status, body)
40
+ expect(response.code.to_i).to eq(status)
41
+ expect(JSON.parse(response.body)).to eq(body)
42
+ expect(response["Content-Type"]).to eq("application/json")
43
+ expect(response["Cache-Control"]).to eq("no-store")
44
+ end
45
+
46
+ def mock_request(request_class, stubs = {})
47
+ mock_request = double(request_class)
48
+ method_stubs = {
49
+ :redirect? => false,
50
+ :response_body => nil,
51
+ :response_headers => {},
52
+ :response_status => 200
53
+ }.merge(stubs)
54
+
55
+ method_stubs.each do |method, value|
56
+ expect(mock_request).to receive(method).and_return(value)
57
+ end
58
+
59
+ mock_request
60
+ end
61
+ end
62
+
@@ -0,0 +1,237 @@
1
+ require 'spec_helper'
2
+
3
+ describe RockOAuth::Model::Authorization do
4
+ let(:client) { Factory :client }
5
+ let(:impostor) { Factory :client }
6
+ let(:owner) { Factory :owner }
7
+ let(:user) { Factory :owner }
8
+ let(:tester) { Factory(:owner) }
9
+
10
+ let(:authorization) do
11
+ create_authorization(:owner => tester, :client => client)
12
+ end
13
+
14
+ it "is valid" do
15
+ expect(authorization).to be_valid
16
+ end
17
+
18
+ it "is not valid without a client" do
19
+ authorization.client = nil
20
+ expect(authorization).not_to be_valid
21
+ end
22
+
23
+ it "is not valid without an owner" do
24
+ authorization.owner = nil
25
+ expect(authorization).not_to be_valid
26
+ end
27
+
28
+ describe "when there are existing authorizations" do
29
+ before do
30
+ create_authorization(
31
+ :owner => user,
32
+ :client => impostor,
33
+ :access_token => 'existing_access_token')
34
+
35
+ create_authorization(
36
+ :owner => user,
37
+ :client => client,
38
+ :code => 'existing_code')
39
+
40
+ create_authorization(
41
+ :owner => owner,
42
+ :client => client,
43
+ :refresh_token => 'existing_refresh_token')
44
+ end
45
+
46
+ it "is valid if its access_token is unique" do
47
+ expect(authorization).to be_valid
48
+ end
49
+
50
+ it "is valid if both access_tokens are nil" do
51
+ RockOAuth::Model::Authorization.first.update_attribute(:access_token, nil)
52
+ authorization.access_token = nil
53
+ expect(authorization).to be_valid
54
+ end
55
+
56
+ it "is not valid if its access_token is not unique" do
57
+ authorization.access_token = 'existing_access_token'
58
+ expect(authorization).not_to be_valid
59
+ end
60
+
61
+ it "is valid if it has a unique code for its client" do
62
+ authorization.client = impostor
63
+ authorization.code = 'existing_code'
64
+ expect(authorization).to be_valid
65
+ end
66
+
67
+ it "is not valid if it does not have a unique client and code" do
68
+ authorization.code = 'existing_code'
69
+ expect(authorization).not_to be_valid
70
+ end
71
+
72
+ it "is valid if it has a unique refresh_token for its client" do
73
+ authorization.client = impostor
74
+ authorization.refresh_token = 'existing_refresh_token'
75
+ expect(authorization).to be_valid
76
+ end
77
+
78
+ it "is not valid if it does not have a unique client and refresh_token" do
79
+ authorization.refresh_token = 'existing_refresh_token'
80
+ expect(authorization).not_to be_valid
81
+ end
82
+
83
+ describe ".create_code" do
84
+ before { allow(RockOAuth).to receive(:random_string).and_return('existing_code', 'new_code') }
85
+
86
+ it "returns the first code the client has not used" do
87
+ expect(RockOAuth::Model::Authorization.create_code(client)).to eq('new_code')
88
+ end
89
+
90
+ it "returns the first code another client has not used" do
91
+ expect(RockOAuth::Model::Authorization.create_code(impostor)).to eq('existing_code')
92
+ end
93
+ end
94
+
95
+ describe ".create_access_token" do
96
+ before { allow(RockOAuth).to receive(:random_string).and_return('existing_access_token', 'new_access_token') }
97
+
98
+ it "returns the first unused token it can find" do
99
+ expect(RockOAuth::Model::Authorization.create_access_token).to eq('new_access_token')
100
+ end
101
+ end
102
+
103
+ describe ".create_refresh_token" do
104
+ before { allow(RockOAuth).to receive(:random_string).and_return('existing_refresh_token', 'new_refresh_token') }
105
+
106
+ it "returns the first refresh_token the client has not used" do
107
+ expect(RockOAuth::Model::Authorization.create_refresh_token(client)).to eq('new_refresh_token')
108
+ end
109
+
110
+ it "returns the first refresh_token another client has not used" do
111
+ expect(RockOAuth::Model::Authorization.create_refresh_token(impostor)).to eq('existing_refresh_token')
112
+ end
113
+ end
114
+
115
+ describe "duplicate records" do
116
+ it "raises an error if a duplicate authorization is created" do
117
+ expect {
118
+ authorization = RockOAuth::Model::Authorization.__send__(:new)
119
+ authorization.owner = user
120
+ authorization.client = client
121
+ authorization.save
122
+ }.to raise_error
123
+ end
124
+
125
+ it "finds an existing record after a race" do
126
+ allow(user).to receive(:oauth2_authorization_for) do
127
+ allow(user).to receive(:oauth2_authorization_for).and_call_original
128
+ raise TypeError, 'Mysql::Error: Duplicate entry'
129
+ end
130
+ authorization = RockOAuth::Model::Authorization.for(user, client)
131
+ expect(authorization.owner).to eq(user)
132
+ expect(authorization.client).to eq(client)
133
+ end
134
+ end
135
+ end
136
+
137
+ describe "#exchange!" do
138
+ it "saves the record" do
139
+ expect(authorization).to receive(:save!)
140
+ authorization.exchange!
141
+ end
142
+
143
+ it "uses its helpers to find unique tokens" do
144
+ expect(RockOAuth::Model::Authorization).to receive(:create_access_token).and_return('access_token')
145
+ authorization.exchange!
146
+ expect(authorization.access_token).to eq('access_token')
147
+ end
148
+
149
+ it "updates the tokens correctly" do
150
+ authorization.exchange!
151
+ expect(authorization).to be_valid
152
+ expect(authorization.code).to be_nil
153
+ expect(authorization.refresh_token).to be_nil
154
+ end
155
+ end
156
+
157
+ describe "#expired?" do
158
+ it "returns false when not expiry is set" do
159
+ expect(authorization).not_to be_expired
160
+ end
161
+
162
+ it "returns false when expiry is in the future" do
163
+ authorization.expires_at = 2.days.from_now
164
+ expect(authorization).not_to be_expired
165
+ end
166
+
167
+ it "returns true when expiry is in the past" do
168
+ authorization.expires_at = 2.days.ago
169
+ expect(authorization).to be_expired
170
+ end
171
+ end
172
+
173
+ describe "#grants_access?" do
174
+ it "returns true given the right user" do
175
+ expect(authorization.grants_access?(tester)).to eq(true)
176
+ end
177
+
178
+ it "returns false given the wrong user" do
179
+ expect(authorization.grants_access?(user)).to eq(false)
180
+ end
181
+
182
+ describe "when the authorization is expired" do
183
+ before { authorization.expires_at = 2.days.ago }
184
+
185
+ it "returns false in all cases" do
186
+ expect(authorization.grants_access?(tester)).to eq(false)
187
+ expect(authorization.grants_access?(user)).to eq(false)
188
+ end
189
+ end
190
+ end
191
+
192
+ describe "with a scope" do
193
+ before { authorization.scope = 'foo bar' }
194
+
195
+ describe "#in_scope?" do
196
+ it "returns true for authorized scopes" do
197
+ expect(authorization).to be_in_scope('foo')
198
+ expect(authorization).to be_in_scope('bar')
199
+ end
200
+
201
+ it "returns false for unauthorized scopes" do
202
+ expect(authorization).not_to be_in_scope('qux')
203
+ expect(authorization).not_to be_in_scope('fo')
204
+ end
205
+ end
206
+
207
+ describe "#grants_access?" do
208
+ it "returns true given the right user and all authorization scopes" do
209
+ expect(authorization.grants_access?(tester, 'foo', 'bar')).to eq(true)
210
+ end
211
+
212
+ it "returns true given the right user and some authorization scopes" do
213
+ expect(authorization.grants_access?(tester, 'bar')).to eq(true)
214
+ end
215
+
216
+ it "returns false given the right user and some unauthorization scopes" do
217
+ expect(authorization.grants_access?(tester, 'foo', 'bar', 'qux')).to eq(false)
218
+ end
219
+
220
+ it "returns false given an unauthorized scope" do
221
+ expect(authorization.grants_access?(tester, 'qux')).to eq(false)
222
+ end
223
+
224
+ it "returns true given the right user" do
225
+ expect(authorization.grants_access?(tester)).to eq(true)
226
+ end
227
+
228
+ it "returns false given the wrong user" do
229
+ expect(authorization.grants_access?(user)).to eq(false)
230
+ end
231
+
232
+ it "returns false given the wrong user and an authorized scope" do
233
+ expect(authorization.grants_access?(user, 'foo')).to eq(false)
234
+ end
235
+ end
236
+ end
237
+ end
@@ -0,0 +1,44 @@
1
+ require 'spec_helper'
2
+
3
+ describe RockOAuth::Model::Client do
4
+ before do
5
+ @client = RockOAuth::Model::Client.create(:name => 'App', :redirect_uri => 'http://example.com/cb')
6
+ @owner = Factory(:owner)
7
+ RockOAuth::Model::Authorization.for(@owner, @client)
8
+ end
9
+
10
+ it "is valid" do
11
+ expect(@client).to be_valid
12
+ end
13
+
14
+ it "is invalid without a name" do
15
+ @client.name = nil
16
+ expect(@client).not_to be_valid
17
+ end
18
+
19
+ it "is invalid without a redirect_uri" do
20
+ @client.redirect_uri = nil
21
+ expect(@client).not_to be_valid
22
+ end
23
+
24
+ it "is invalid with a non-URI redirect_uri" do
25
+ @client.redirect_uri = 'foo'
26
+ expect(@client).not_to be_valid
27
+ end
28
+
29
+ # http://en.wikipedia.org/wiki/HTTP_response_splitting
30
+ it "is invalid if the URI contains HTTP line breaks" do
31
+ @client.redirect_uri = "http://example.com/c\r\nb"
32
+ expect(@client).not_to be_valid
33
+ end
34
+
35
+ it "has client_id and client_secret filled in" do
36
+ expect(@client.client_id).not_to be_nil
37
+ expect(@client.client_secret).not_to be_nil
38
+ end
39
+
40
+ it "destroys its authorizations on destroy" do
41
+ @client.destroy
42
+ expect(RockOAuth::Model::Authorization.count).to be_zero
43
+ end
44
+ end
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ describe RockOAuth::Model::Helpers do
4
+ subject { RockOAuth::Model::Helpers }
5
+
6
+ describe '.count' do
7
+ let(:owner) { Factory(:owner) }
8
+
9
+ before do
10
+ 3.times { Factory(:client, :owner => owner) }
11
+ end
12
+
13
+ context 'when conditions are not passed' do
14
+ it 'returns count of total rows' do
15
+ expect(subject.count(owner.oauth2_clients)).to eq(3)
16
+ end
17
+ end
18
+
19
+ context 'when conditions are passed' do
20
+ it 'returns count of rows satisfying supplied conditions' do
21
+ expect(subject.count(RockOAuth::Model::Client, :client_id => RockOAuth::Model::Client.first.client_id)).to eq(1)
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,87 @@
1
+ require 'spec_helper'
2
+
3
+ describe RockOAuth::Model::ResourceOwner do
4
+ before do
5
+ @owner = Factory(:owner)
6
+ @client = Factory(:client)
7
+ end
8
+
9
+ describe "#grant_access!" do
10
+ it "raises an error when passed an invalid client argument" do
11
+ expect{ @owner.grant_access!('client') }.to raise_error(ArgumentError)
12
+ end
13
+
14
+ it "creates an authorization between the owner and the client" do
15
+ authorization = RockOAuth::Model::Authorization.__send__(:new)
16
+ expect(RockOAuth::Model::Authorization).to receive(:new).and_return(authorization)
17
+ @owner.grant_access!(@client)
18
+ end
19
+
20
+ # This is hacky, but doubleing ActiveRecord turns out to get messy
21
+ it "creates an Authorization" do
22
+ expect(RockOAuth::Model::Authorization.count).to eq(0)
23
+ @owner.grant_access!(@client)
24
+ expect(RockOAuth::Model::Authorization.count).to eq(1)
25
+ end
26
+
27
+ it "returns the authorization" do
28
+ expect(@owner.grant_access!(@client)).to be_kind_of(RockOAuth::Model::Authorization)
29
+ end
30
+
31
+ # This method must return the same owner object, since the assertion
32
+ # handler may modify it -- either by changing its attributes or by extending
33
+ # it with new methods. These changes must be returned to the app calling the
34
+ # Provider interface.
35
+ it "sets the receiver as the authorization's owner" do
36
+ authorization = @owner.grant_access!(@client)
37
+ expect(authorization.owner).to be_equal(@owner)
38
+ end
39
+
40
+ it "sets the duration of the authorization" do
41
+ authorization = @owner.grant_access!(@client, :duration => 5.hours)
42
+ expect(authorization.expires_at.to_i).to eq((Time.now + 5.hours.to_i).to_i)
43
+ end
44
+ end
45
+
46
+ describe "when there is an existing authorization" do
47
+ before do
48
+ @authorization = create_authorization(:owner => @owner, :client => @client)
49
+ end
50
+
51
+ it "does not create a new one" do
52
+ expect(RockOAuth::Model::Authorization).not_to receive(:new)
53
+ @owner.grant_access!(@client)
54
+ end
55
+
56
+ it "updates the authorization with scopes" do
57
+ @owner.grant_access!(@client, :scopes => ['foo', 'bar'])
58
+ @authorization.reload
59
+ expect(@authorization.scopes).to eq(Set.new(['foo', 'bar']))
60
+ end
61
+
62
+ describe "with scopes" do
63
+ before do
64
+ @authorization.update_attribute(:scope, 'foo bar')
65
+ end
66
+
67
+ it "merges the new scopes with the existing ones" do
68
+ @owner.grant_access!(@client, :scopes => ['qux'])
69
+ @authorization.reload
70
+ expect(@authorization.scopes).to eq(Set.new(['foo', 'bar', 'qux']))
71
+ end
72
+
73
+ it "does not add duplicate scopes to the list" do
74
+ @owner.grant_access!(@client, :scopes => ['qux'])
75
+ @owner.grant_access!(@client, :scopes => ['qux'])
76
+ @authorization.reload
77
+ expect(@authorization.scopes).to eq(Set.new(['foo', 'bar', 'qux']))
78
+ end
79
+ end
80
+ end
81
+
82
+ it "destroys its authorizations on destroy" do
83
+ RockOAuth::Model::Authorization.for(@owner, @client)
84
+ @owner.destroy
85
+ expect(RockOAuth::Model::Authorization.count).to be_zero
86
+ end
87
+ end
@@ -0,0 +1,138 @@
1
+ require 'spec_helper'
2
+
3
+ describe RockOAuth::Provider::AccessToken do
4
+ before do
5
+ @alice = TestApp::User['Alice']
6
+ @bob = TestApp::User['Bob']
7
+
8
+ create_authorization(
9
+ :owner => @alice,
10
+ :client => Factory(:client),
11
+ :scope => 'profile',
12
+ :access_token => 'sesame')
13
+
14
+ @authorization = create_authorization(
15
+ :owner => @bob,
16
+ :client => Factory(:client),
17
+ :scope => 'profile',
18
+ :access_token => 'magic-key')
19
+
20
+ RockOAuth::Provider.realm = 'Demo App'
21
+ end
22
+
23
+ let :token do
24
+ RockOAuth::Provider::AccessToken.new(@bob, ['profile'], 'magic-key')
25
+ end
26
+
27
+ shared_examples_for "valid token" do
28
+ it "is valid" do
29
+ expect(token).to be_valid
30
+ end
31
+ it "does not add headers" do
32
+ expect(token.response_headers).to eq({})
33
+ end
34
+ it "has an OK status code" do
35
+ expect(token.response_status).to eq(200)
36
+ end
37
+ it "returns the owner who granted the authorization" do
38
+ expect(token.owner).to eq(@bob)
39
+ end
40
+ end
41
+
42
+ shared_examples_for "invalid token" do
43
+ it "is not valid" do
44
+ expect(token).not_to be_valid
45
+ end
46
+ it "does not return the owner" do
47
+ expect(token.owner).to be_nil
48
+ end
49
+ end
50
+
51
+ describe "with the right user, scope and token" do
52
+ it_should_behave_like "valid token"
53
+ end
54
+
55
+ describe "with an implicit user" do
56
+ let :token do
57
+ RockOAuth::Provider::AccessToken.new(:implicit, ['profile'], 'magic-key')
58
+ end
59
+ it_should_behave_like "valid token"
60
+ end
61
+
62
+ describe "with no user" do
63
+ let :token do
64
+ RockOAuth::Provider::AccessToken.new(nil, ['profile'], 'magic-key')
65
+ end
66
+ it_should_behave_like "invalid token"
67
+
68
+ it "returns an error response" do
69
+ expect(token.response_headers['WWW-Authenticate']).to eq("OAuth realm='Demo App', error='invalid_token'")
70
+ expect(token.response_status).to eq(401)
71
+ end
72
+ end
73
+
74
+ describe "with less scope than was granted" do
75
+ let :token do
76
+ RockOAuth::Provider::AccessToken.new(@bob, [], 'magic-key')
77
+ end
78
+ it_should_behave_like "valid token"
79
+ end
80
+
81
+ describe "when the authorization has expired" do
82
+ before { @authorization.update_attribute(:expires_at, 1.hour.ago) }
83
+ it_should_behave_like "invalid token"
84
+
85
+ it "returns an error response" do
86
+ expect(token.response_headers['WWW-Authenticate']).to eq("OAuth realm='Demo App', error='expired_token'")
87
+ expect(token.response_status).to eq(401)
88
+ end
89
+ end
90
+
91
+ describe "with a non-existent token" do
92
+ let :token do
93
+ RockOAuth::Provider::AccessToken.new(@bob, ['profile'], 'is-the-password-books')
94
+ end
95
+ it_should_behave_like "invalid token"
96
+
97
+ it "returns an error response" do
98
+ expect(token.response_headers['WWW-Authenticate']).to eq("OAuth realm='Demo App', error='invalid_token'")
99
+ expect(token.response_status).to eq(401)
100
+ end
101
+ end
102
+
103
+ describe "with a token for the wrong user" do
104
+ let :token do
105
+ RockOAuth::Provider::AccessToken.new(@bob, ['profile'], 'sesame')
106
+ end
107
+ it_should_behave_like "invalid token"
108
+
109
+ it "returns an error response" do
110
+ expect(token.response_headers['WWW-Authenticate']).to eq("OAuth realm='Demo App', error='insufficient_scope'")
111
+ expect(token.response_status).to eq(403)
112
+ end
113
+ end
114
+
115
+ describe "with a token for an ungranted scope" do
116
+ let :token do
117
+ RockOAuth::Provider::AccessToken.new(@bob, ['offline_access'], 'magic-key')
118
+ end
119
+ it_should_behave_like "invalid token"
120
+
121
+ it "returns an error response" do
122
+ expect(token.response_headers['WWW-Authenticate']).to eq("OAuth realm='Demo App', error='insufficient_scope'")
123
+ expect(token.response_status).to eq(403)
124
+ end
125
+ end
126
+
127
+ describe "with no token string" do
128
+ let :token do
129
+ RockOAuth::Provider::AccessToken.new(@bob, ['profile'], nil)
130
+ end
131
+ it_should_behave_like "invalid token"
132
+
133
+ it "returns an error response" do
134
+ expect(token.response_headers['WWW-Authenticate']).to eq("OAuth realm='Demo App'")
135
+ expect(token.response_status).to eq(401)
136
+ end
137
+ end
138
+ end