grape_oauth2 0.1.1
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.
- checksums.yaml +7 -0
- data/.gitignore +11 -0
- data/.rspec +2 -0
- data/.rubocop.yml +18 -0
- data/.travis.yml +42 -0
- data/Gemfile +23 -0
- data/README.md +820 -0
- data/Rakefile +11 -0
- data/gemfiles/active_record.rb +25 -0
- data/gemfiles/mongoid.rb +14 -0
- data/gemfiles/sequel.rb +24 -0
- data/grape_oauth2.gemspec +27 -0
- data/grape_oauth2.png +0 -0
- data/lib/grape_oauth2.rb +129 -0
- data/lib/grape_oauth2/configuration.rb +143 -0
- data/lib/grape_oauth2/configuration/class_accessors.rb +36 -0
- data/lib/grape_oauth2/configuration/validation.rb +71 -0
- data/lib/grape_oauth2/endpoints/authorize.rb +34 -0
- data/lib/grape_oauth2/endpoints/token.rb +72 -0
- data/lib/grape_oauth2/gem_version.rb +24 -0
- data/lib/grape_oauth2/generators/authorization.rb +44 -0
- data/lib/grape_oauth2/generators/base.rb +26 -0
- data/lib/grape_oauth2/generators/token.rb +62 -0
- data/lib/grape_oauth2/helpers/access_token_helpers.rb +54 -0
- data/lib/grape_oauth2/helpers/oauth_params.rb +41 -0
- data/lib/grape_oauth2/mixins/active_record/access_grant.rb +47 -0
- data/lib/grape_oauth2/mixins/active_record/access_token.rb +75 -0
- data/lib/grape_oauth2/mixins/active_record/client.rb +35 -0
- data/lib/grape_oauth2/mixins/mongoid/access_grant.rb +58 -0
- data/lib/grape_oauth2/mixins/mongoid/access_token.rb +88 -0
- data/lib/grape_oauth2/mixins/mongoid/client.rb +41 -0
- data/lib/grape_oauth2/mixins/sequel/access_grant.rb +68 -0
- data/lib/grape_oauth2/mixins/sequel/access_token.rb +86 -0
- data/lib/grape_oauth2/mixins/sequel/client.rb +46 -0
- data/lib/grape_oauth2/responses/authorization.rb +10 -0
- data/lib/grape_oauth2/responses/base.rb +56 -0
- data/lib/grape_oauth2/responses/token.rb +10 -0
- data/lib/grape_oauth2/scopes.rb +74 -0
- data/lib/grape_oauth2/strategies/authorization_code.rb +38 -0
- data/lib/grape_oauth2/strategies/base.rb +47 -0
- data/lib/grape_oauth2/strategies/client_credentials.rb +20 -0
- data/lib/grape_oauth2/strategies/password.rb +22 -0
- data/lib/grape_oauth2/strategies/refresh_token.rb +47 -0
- data/lib/grape_oauth2/unique_token.rb +20 -0
- data/lib/grape_oauth2/version.rb +14 -0
- data/spec/configuration/config_spec.rb +231 -0
- data/spec/configuration/version_spec.rb +12 -0
- data/spec/dummy/endpoints/custom_authorization.rb +25 -0
- data/spec/dummy/endpoints/custom_token.rb +35 -0
- data/spec/dummy/endpoints/status.rb +25 -0
- data/spec/dummy/grape_oauth2_config.rb +11 -0
- data/spec/dummy/orm/active_record/app/config/db.rb +7 -0
- data/spec/dummy/orm/active_record/app/models/access_code.rb +3 -0
- data/spec/dummy/orm/active_record/app/models/access_token.rb +3 -0
- data/spec/dummy/orm/active_record/app/models/application.rb +3 -0
- data/spec/dummy/orm/active_record/app/models/application_record.rb +3 -0
- data/spec/dummy/orm/active_record/app/models/user.rb +10 -0
- data/spec/dummy/orm/active_record/app/twitter.rb +36 -0
- data/spec/dummy/orm/active_record/config.ru +7 -0
- data/spec/dummy/orm/active_record/db/schema.rb +53 -0
- data/spec/dummy/orm/mongoid/app/config/db.rb +6 -0
- data/spec/dummy/orm/mongoid/app/config/mongoid.yml +21 -0
- data/spec/dummy/orm/mongoid/app/models/access_code.rb +3 -0
- data/spec/dummy/orm/mongoid/app/models/access_token.rb +3 -0
- data/spec/dummy/orm/mongoid/app/models/application.rb +3 -0
- data/spec/dummy/orm/mongoid/app/models/user.rb +11 -0
- data/spec/dummy/orm/mongoid/app/twitter.rb +34 -0
- data/spec/dummy/orm/mongoid/config.ru +5 -0
- data/spec/dummy/orm/sequel/app/config/db.rb +1 -0
- data/spec/dummy/orm/sequel/app/models/access_code.rb +4 -0
- data/spec/dummy/orm/sequel/app/models/access_token.rb +4 -0
- data/spec/dummy/orm/sequel/app/models/application.rb +4 -0
- data/spec/dummy/orm/sequel/app/models/application_record.rb +2 -0
- data/spec/dummy/orm/sequel/app/models/user.rb +11 -0
- data/spec/dummy/orm/sequel/app/twitter.rb +47 -0
- data/spec/dummy/orm/sequel/config.ru +5 -0
- data/spec/dummy/orm/sequel/db/schema.rb +50 -0
- data/spec/lib/scopes_spec.rb +50 -0
- data/spec/mixins/active_record/access_token_spec.rb +185 -0
- data/spec/mixins/active_record/client_spec.rb +95 -0
- data/spec/mixins/mongoid/access_token_spec.rb +185 -0
- data/spec/mixins/mongoid/client_spec.rb +95 -0
- data/spec/mixins/sequel/access_token_spec.rb +185 -0
- data/spec/mixins/sequel/client_spec.rb +96 -0
- data/spec/requests/flows/authorization_code_spec.rb +67 -0
- data/spec/requests/flows/client_credentials_spec.rb +101 -0
- data/spec/requests/flows/password_spec.rb +210 -0
- data/spec/requests/flows/refresh_token_spec.rb +222 -0
- data/spec/requests/flows/revoke_token_spec.rb +103 -0
- data/spec/requests/protected_resources_spec.rb +64 -0
- data/spec/spec_helper.rb +60 -0
- data/spec/support/api_helper.rb +11 -0
- metadata +257 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe 'Grape::OAuth2::Mongoid::Client', skip_if: ENV['ORM'] != 'mongoid' do
|
|
4
|
+
let(:client) { Application.new }
|
|
5
|
+
|
|
6
|
+
let(:key) { SecureRandom.hex(8) }
|
|
7
|
+
let(:secret) { SecureRandom.hex(8) }
|
|
8
|
+
|
|
9
|
+
it 'generates key on create' do
|
|
10
|
+
expect(client.key).to be_nil
|
|
11
|
+
client.save
|
|
12
|
+
expect(client.key).not_to be_nil
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it 'generates key on create if an empty string' do
|
|
16
|
+
client.key = ''
|
|
17
|
+
client.save
|
|
18
|
+
expect(client.key).not_to be_blank
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it 'generates key on create unless one is set' do
|
|
22
|
+
client.key = key
|
|
23
|
+
client.save
|
|
24
|
+
expect(client.key).to eq(key)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it 'is invalid without key' do
|
|
28
|
+
client.save
|
|
29
|
+
client.key = nil
|
|
30
|
+
expect(client).not_to be_valid
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it 'checks uniqueness of key' do
|
|
34
|
+
app1 = Application.create
|
|
35
|
+
app2 = Application.create
|
|
36
|
+
app2.key = app1.key
|
|
37
|
+
expect(app2).not_to be_valid
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it 'expects database to throw an error when keys are the same' do
|
|
41
|
+
app1 = Application.create
|
|
42
|
+
app2 = Application.create
|
|
43
|
+
app2.key = app1.key
|
|
44
|
+
expect { app2.save! }.to raise_error(Mongoid::Errors::Validations)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it 'generate secret on create' do
|
|
48
|
+
expect(client.secret).to be_nil
|
|
49
|
+
client.save
|
|
50
|
+
expect(client.secret).not_to be_nil
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
it 'generate secret on create if is blank string' do
|
|
54
|
+
client.secret = ''
|
|
55
|
+
client.save
|
|
56
|
+
expect(client.secret).not_to be_blank
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it 'generate secret on create unless one is set' do
|
|
60
|
+
client.secret = secret
|
|
61
|
+
client.save
|
|
62
|
+
expect(client.secret).to eq(secret)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
it 'is invalid without secret' do
|
|
66
|
+
client.save
|
|
67
|
+
client.secret = nil
|
|
68
|
+
expect(client).not_to be_valid
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
describe '#authenticate' do
|
|
72
|
+
it 'returns a class instance if authenticated successfully' do
|
|
73
|
+
client.key = key
|
|
74
|
+
client.secret = secret
|
|
75
|
+
client.save
|
|
76
|
+
|
|
77
|
+
expect(Application.authenticate(key, secret)).to eq(client)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
it 'returns a class instance if only key specified' do
|
|
81
|
+
client.key = key
|
|
82
|
+
client.save
|
|
83
|
+
|
|
84
|
+
expect(Application.authenticate(key)).to eq(client)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
it 'returns nil if authentication failed' do
|
|
88
|
+
client.key = key
|
|
89
|
+
client.secret = secret
|
|
90
|
+
client.save
|
|
91
|
+
|
|
92
|
+
expect(Application.authenticate(key, 'invalid-')).to be_nil
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe 'Grape::OAuth2::Sequel::AccessToken', skip_if: ENV['ORM'] != 'sequel' do
|
|
4
|
+
let(:application) { Application.create(name: 'Test') }
|
|
5
|
+
let(:user) { User.create(username: 'test', password: '123123') }
|
|
6
|
+
let(:access_token) { AccessToken.create(client: application, resource_owner: user) }
|
|
7
|
+
|
|
8
|
+
let(:token) { SecureRandom.hex(16) }
|
|
9
|
+
|
|
10
|
+
describe 'validations' do
|
|
11
|
+
it 'validate token uniqueness' do
|
|
12
|
+
another_token = AccessToken.create(client: application)
|
|
13
|
+
token = AccessToken.new(client: application, token: another_token.token)
|
|
14
|
+
|
|
15
|
+
expect(token).not_to be_valid
|
|
16
|
+
expect(token.errors).to include(:token)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
describe '#to_bearer_token' do
|
|
21
|
+
context 'config with refresh token' do
|
|
22
|
+
before do
|
|
23
|
+
Grape::OAuth2.config.issue_refresh_token = true
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
after do
|
|
27
|
+
Grape::OAuth2.config.issue_refresh_token = false
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it 'returns refresh token' do
|
|
31
|
+
expect(access_token.to_bearer_token[:access_token]).not_to be_blank
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
context 'config without refresh token' do
|
|
36
|
+
before do
|
|
37
|
+
Grape::OAuth2.configure do |config|
|
|
38
|
+
config.issue_refresh_token = false
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it 'returns blank refresh token' do
|
|
43
|
+
expect(access_token.to_bearer_token[:refresh_token]).to be_blank
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
describe '#authenticate' do
|
|
49
|
+
it 'returns an instance if authenticated successfully' do
|
|
50
|
+
access_token.token = token
|
|
51
|
+
access_token.save
|
|
52
|
+
|
|
53
|
+
expect(AccessToken.authenticate(token)).to eq(access_token)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
it 'returns nil if authentication failed' do
|
|
57
|
+
access_token.token = token
|
|
58
|
+
access_token.save
|
|
59
|
+
|
|
60
|
+
expect(AccessToken.authenticate("invalid-#{token}")).to be_nil
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
it 'returns an instance by refresh token' do
|
|
64
|
+
refresh_token = SecureRandom.hex(6)
|
|
65
|
+
token = AccessToken.create(client: application, refresh_token: refresh_token)
|
|
66
|
+
|
|
67
|
+
expect(AccessToken.authenticate(refresh_token, type: :refresh_token)).to eq(token)
|
|
68
|
+
expect(AccessToken.authenticate(refresh_token, type: 'refresh_token')).to eq(token)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
describe '#create_for?' do
|
|
73
|
+
it 'creates a record only for Client' do
|
|
74
|
+
token = AccessToken.create_for(application, nil)
|
|
75
|
+
|
|
76
|
+
expect(token.client).not_to be_nil
|
|
77
|
+
expect(token.resource_owner).to be_nil
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
it 'creates a record for Client and Resource Owner' do
|
|
81
|
+
token = AccessToken.create_for(application, user)
|
|
82
|
+
|
|
83
|
+
expect(token.client).to eq(application)
|
|
84
|
+
expect(token.resource_owner).to eq(user)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
it 'creates a record with scopes' do
|
|
88
|
+
scopes = 'write read'
|
|
89
|
+
token = AccessToken.create_for(application, user, scopes)
|
|
90
|
+
|
|
91
|
+
expect(token.client).to eq(application)
|
|
92
|
+
expect(token.resource_owner).to eq(user)
|
|
93
|
+
expect(token.scopes).to eq(scopes)
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
describe '#expired?' do
|
|
98
|
+
it 'return false if expires_at nil' do
|
|
99
|
+
access_token.update_fields({ expires_at: nil }, [:expires_at])
|
|
100
|
+
|
|
101
|
+
expect(access_token.expired?).to be_falsey
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
it 'return false if expires_at < Time.now' do
|
|
105
|
+
expect(access_token.expired?).to be_falsey
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
it 'return false if expires_at > Time.now' do
|
|
109
|
+
expires_at = Time.now.utc - Grape::OAuth2.config.access_token_lifetime + 1
|
|
110
|
+
access_token.update_fields({ expires_at: expires_at }, [:expires_at])
|
|
111
|
+
|
|
112
|
+
expect(access_token.expired?).to be_truthy
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
describe '#revoked?' do
|
|
117
|
+
it 'return false if revoked_at nil' do
|
|
118
|
+
access_token.update_fields({ revoked_at: nil }, [:revoked_at])
|
|
119
|
+
|
|
120
|
+
expect(access_token.revoked?).to be_falsey
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
it 'return false if revoked_at present' do
|
|
124
|
+
access_token.update_fields({ revoked_at: Time.now.utc }, [:revoked_at])
|
|
125
|
+
expect(access_token.revoked?).to be_truthy
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
describe '#revoke!' do
|
|
130
|
+
it 'update :revoked_at attribute' do
|
|
131
|
+
expect { access_token.revoke! }.to change { access_token.revoked? }.from(false).to(true)
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
it 'update :revoked_at attribute with custom value' do
|
|
135
|
+
custom_time = Time.now - 7200
|
|
136
|
+
access_token.revoke!(custom_time)
|
|
137
|
+
|
|
138
|
+
expect(access_token.revoked_at).to eq(custom_time.utc)
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
describe 'token generation' do
|
|
143
|
+
it 'generates a new token before saving if token is blank' do
|
|
144
|
+
token = AccessToken.new(client: application, resource_owner: user)
|
|
145
|
+
|
|
146
|
+
expect(token.token).to be_blank
|
|
147
|
+
|
|
148
|
+
token.save
|
|
149
|
+
|
|
150
|
+
expect(token.token).not_to be_blank
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
it 'does not change token value on saving if token is present' do
|
|
154
|
+
token = AccessToken.new(client: application, resource_owner: user, token: 'abcdef')
|
|
155
|
+
|
|
156
|
+
expect(token.token).not_to be_blank
|
|
157
|
+
|
|
158
|
+
token.save
|
|
159
|
+
|
|
160
|
+
expect(token.token).to eq('abcdef')
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
describe 'expiration' do
|
|
165
|
+
it 'set to nil if configuration option set to nil' do
|
|
166
|
+
Grape::OAuth2.config.access_token_lifetime = nil
|
|
167
|
+
|
|
168
|
+
token = AccessToken.create(client: application, resource_owner: user)
|
|
169
|
+
expect(token.expires_at).to be_nil
|
|
170
|
+
|
|
171
|
+
Grape::OAuth2.config.access_token_lifetime = Grape::OAuth2::Configuration::DEFAULT_TOKEN_LIFETIME
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
it 'set to specific time if configuration option set to some value' do
|
|
175
|
+
current_time = Time.now.utc
|
|
176
|
+
Grape::OAuth2.config.access_token_lifetime = 3500
|
|
177
|
+
|
|
178
|
+
token = AccessToken.create(client: application, resource_owner: user)
|
|
179
|
+
expect(token.expires_at).not_to be_nil
|
|
180
|
+
expect(token.expires_at).to be_within(1).of(current_time + 3500)
|
|
181
|
+
|
|
182
|
+
Grape::OAuth2.config.access_token_lifetime = Grape::OAuth2::Configuration::DEFAULT_TOKEN_LIFETIME
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
end
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe 'Grape::OAuth2::Sequel::Client', skip_if: ENV['ORM'] != 'sequel' do
|
|
4
|
+
let(:client) { Application.new(name: 'Test') }
|
|
5
|
+
|
|
6
|
+
let(:key) { SecureRandom.hex(8) }
|
|
7
|
+
let(:secret) { SecureRandom.hex(8) }
|
|
8
|
+
|
|
9
|
+
it 'generates key on create' do
|
|
10
|
+
expect(client.key).to be_nil
|
|
11
|
+
client.save
|
|
12
|
+
expect(client.key).not_to be_nil
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it 'generates key on create if an empty string' do
|
|
16
|
+
client.key = ''
|
|
17
|
+
client.save
|
|
18
|
+
expect(client.key).not_to be_blank
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it 'generates key on create unless one is set' do
|
|
22
|
+
client.key = key
|
|
23
|
+
client.save
|
|
24
|
+
expect(client.key).to eq(key)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it 'is invalid without key' do
|
|
28
|
+
client.save
|
|
29
|
+
client.key = nil
|
|
30
|
+
expect(client).not_to be_valid
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it 'checks uniqueness of key' do
|
|
34
|
+
app1 = Application.create(name: 'app1')
|
|
35
|
+
app2 = Application.create(name: 'app2')
|
|
36
|
+
app2.key = app1.key
|
|
37
|
+
expect(app2).not_to be_valid
|
|
38
|
+
expect(app2.errors).to include(:key)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it 'expects database to throw an error when keys are the same' do
|
|
42
|
+
app1 = Application.create(name: 'app1')
|
|
43
|
+
app2 = Application.create(name: 'app2')
|
|
44
|
+
app2.key = app1.key
|
|
45
|
+
expect { app2.save }.to raise_error(Sequel::ValidationFailed)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
it 'generate secret on create' do
|
|
49
|
+
expect(client.secret).to be_nil
|
|
50
|
+
client.save
|
|
51
|
+
expect(client.secret).not_to be_nil
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it 'generate secret on create if is blank string' do
|
|
55
|
+
client.secret = ''
|
|
56
|
+
client.save
|
|
57
|
+
expect(client.secret).not_to be_blank
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
it 'generate secret on create unless one is set' do
|
|
61
|
+
client.secret = secret
|
|
62
|
+
client.save
|
|
63
|
+
expect(client.secret).to eq(secret)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
it 'is invalid without secret' do
|
|
67
|
+
client.save
|
|
68
|
+
client.secret = nil
|
|
69
|
+
expect(client).not_to be_valid
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
describe '#authenticate' do
|
|
73
|
+
it 'returns a class instance if authenticated successfully' do
|
|
74
|
+
client.key = key
|
|
75
|
+
client.secret = secret
|
|
76
|
+
client.save
|
|
77
|
+
|
|
78
|
+
expect(Application.authenticate(key, secret)).to eq(client)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
it 'returns a class instance if only key specified' do
|
|
82
|
+
client.key = key
|
|
83
|
+
client.save
|
|
84
|
+
|
|
85
|
+
expect(Application.authenticate(key)).to eq(client)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
it 'returns nil if authentication failed' do
|
|
89
|
+
client.key = key
|
|
90
|
+
client.secret = secret
|
|
91
|
+
client.save
|
|
92
|
+
|
|
93
|
+
expect(Application.authenticate(key, 'invalid-')).to be_nil
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe 'Authorization Code flow' do
|
|
4
|
+
let(:redirect_uri) { 'http://localhost:3000/home' }
|
|
5
|
+
let(:application) { Application.create(name: 'App1', redirect_uri: redirect_uri) }
|
|
6
|
+
|
|
7
|
+
describe 'POST /oauth/authorize' do
|
|
8
|
+
let(:authorize_url) { '/api/v1/oauth/authorize' }
|
|
9
|
+
|
|
10
|
+
context 'with valid params' do
|
|
11
|
+
context 'when response_type is :code' do
|
|
12
|
+
it 'should be success' do
|
|
13
|
+
expect {
|
|
14
|
+
post authorize_url,
|
|
15
|
+
client_id: application.key,
|
|
16
|
+
redirect_uri: redirect_uri,
|
|
17
|
+
response_type: 'code'
|
|
18
|
+
}.to change { AccessCode.count }.from(0).to(1)
|
|
19
|
+
|
|
20
|
+
expect(last_response.status).to eq 302
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
context 'when response_type is :token' do
|
|
25
|
+
it 'should be success' do
|
|
26
|
+
expect {
|
|
27
|
+
post authorize_url,
|
|
28
|
+
client_id: application.key,
|
|
29
|
+
redirect_uri: redirect_uri,
|
|
30
|
+
response_type: 'token'
|
|
31
|
+
}.to change { AccessToken.count }.from(0).to(1)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
context 'with invalid params' do
|
|
37
|
+
it 'should fail without response_type' do
|
|
38
|
+
post authorize_url,
|
|
39
|
+
client_id: application.key
|
|
40
|
+
|
|
41
|
+
expect(last_response.status).to eq 400
|
|
42
|
+
expect(json_body[:error]).to eq('invalid_request')
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it 'should fail with unsupported response_type' do
|
|
46
|
+
post authorize_url,
|
|
47
|
+
client_id: application.key,
|
|
48
|
+
redirect_uri: redirect_uri,
|
|
49
|
+
response_type: 'invalid'
|
|
50
|
+
|
|
51
|
+
expect(last_response.status).to eq 400
|
|
52
|
+
expect(json_body[:error]).to eq('unsupported_response_type')
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
describe 'POST /oauth/custom_authorize' do
|
|
58
|
+
it 'invokes custom block' do
|
|
59
|
+
post '/api/v1/oauth/custom_authorize',
|
|
60
|
+
client_id: application.key,
|
|
61
|
+
redirect_uri: redirect_uri,
|
|
62
|
+
response_type: 'code'
|
|
63
|
+
|
|
64
|
+
expect(last_response.status).to eq(400)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe 'Token Endpoint' do
|
|
4
|
+
describe 'POST /oauth/token' do
|
|
5
|
+
describe 'Client Credentials flow' do
|
|
6
|
+
context 'with valid params' do
|
|
7
|
+
let(:authentication_url) { '/api/v1/oauth/token' }
|
|
8
|
+
let(:application) { Application.create(name: 'App1') }
|
|
9
|
+
let(:user) { User.create(username: 'test', password: '12345678') }
|
|
10
|
+
|
|
11
|
+
context 'when request is invalid' do
|
|
12
|
+
it 'fails without Grant Type' do
|
|
13
|
+
post authentication_url,
|
|
14
|
+
client_id: application.key,
|
|
15
|
+
client_secret: application.secret
|
|
16
|
+
|
|
17
|
+
expect(AccessToken.all).to be_empty
|
|
18
|
+
|
|
19
|
+
expect(json_body[:error]).to eq('invalid_request')
|
|
20
|
+
expect(last_response.status).to eq 400
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it 'fails with invalid Grant Type' do
|
|
24
|
+
post authentication_url,
|
|
25
|
+
grant_type: 'invalid'
|
|
26
|
+
|
|
27
|
+
expect(AccessToken.all).to be_empty
|
|
28
|
+
|
|
29
|
+
expect(json_body[:error]).to eq('unsupported_grant_type')
|
|
30
|
+
expect(last_response.status).to eq 400
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it 'fails without Client Credentials' do
|
|
34
|
+
post authentication_url,
|
|
35
|
+
grant_type: 'client_credentials'
|
|
36
|
+
|
|
37
|
+
expect(AccessToken.all).to be_empty
|
|
38
|
+
|
|
39
|
+
expect(json_body[:error]).to eq('invalid_request')
|
|
40
|
+
expect(last_response.status).to eq 400
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it 'fails with invalid Client Credentials' do
|
|
44
|
+
post authentication_url,
|
|
45
|
+
grant_type: 'client_credentials',
|
|
46
|
+
client_id: 'blah-blah',
|
|
47
|
+
client_secret: application.secret
|
|
48
|
+
|
|
49
|
+
expect(AccessToken.all).to be_empty
|
|
50
|
+
|
|
51
|
+
expect(json_body[:error]).to eq('invalid_client')
|
|
52
|
+
expect(last_response.status).to eq 401
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
context 'with valid data' do
|
|
57
|
+
context 'when scopes requested' do
|
|
58
|
+
it 'returns an Access Token with scopes' do
|
|
59
|
+
post authentication_url,
|
|
60
|
+
grant_type: 'client_credentials',
|
|
61
|
+
scope: 'read write',
|
|
62
|
+
client_id: application.key,
|
|
63
|
+
client_secret: application.secret
|
|
64
|
+
|
|
65
|
+
expect(AccessToken.count).to eq 1
|
|
66
|
+
expect(AccessToken.first.client_id).to eq application.id
|
|
67
|
+
|
|
68
|
+
expect(json_body[:access_token]).to be_present
|
|
69
|
+
expect(json_body[:token_type]).to eq 'bearer'
|
|
70
|
+
expect(json_body[:expires_in]).to eq 7200
|
|
71
|
+
expect(json_body[:refresh_token]).to be_nil
|
|
72
|
+
expect(json_body[:scope]).to eq('read write')
|
|
73
|
+
|
|
74
|
+
expect(last_response.status).to eq 200
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
context 'without scopes' do
|
|
79
|
+
it 'returns an Access Token without scopes' do
|
|
80
|
+
post authentication_url,
|
|
81
|
+
grant_type: 'client_credentials',
|
|
82
|
+
client_id: application.key,
|
|
83
|
+
client_secret: application.secret
|
|
84
|
+
|
|
85
|
+
expect(AccessToken.count).to eq 1
|
|
86
|
+
expect(AccessToken.first.client_id).to eq application.id
|
|
87
|
+
|
|
88
|
+
expect(json_body[:access_token]).to be_present
|
|
89
|
+
expect(json_body[:token_type]).to eq 'bearer'
|
|
90
|
+
expect(json_body[:expires_in]).to eq 7200
|
|
91
|
+
expect(json_body[:refresh_token]).to be_nil
|
|
92
|
+
expect(json_body[:scope]).to be_nil
|
|
93
|
+
|
|
94
|
+
expect(last_response.status).to eq 200
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|