grape_oauth2 0.1.1 → 0.2.0
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 +4 -4
- data/.gitignore +11 -11
- data/Gemfile +23 -23
- data/Rakefile +11 -11
- data/grape_oauth2.gemspec +26 -27
- data/lib/grape_oauth2.rb +129 -129
- data/lib/grape_oauth2/configuration.rb +143 -143
- data/lib/grape_oauth2/configuration/class_accessors.rb +36 -36
- data/lib/grape_oauth2/configuration/validation.rb +71 -71
- data/lib/grape_oauth2/endpoints/authorize.rb +34 -34
- data/lib/grape_oauth2/endpoints/token.rb +72 -72
- data/lib/grape_oauth2/gem_version.rb +24 -24
- data/lib/grape_oauth2/generators/authorization.rb +44 -44
- data/lib/grape_oauth2/generators/base.rb +26 -26
- data/lib/grape_oauth2/generators/token.rb +62 -62
- data/lib/grape_oauth2/helpers/access_token_helpers.rb +52 -54
- data/lib/grape_oauth2/helpers/oauth_params.rb +41 -41
- data/lib/grape_oauth2/mixins/active_record/access_grant.rb +47 -47
- data/lib/grape_oauth2/mixins/active_record/access_token.rb +75 -75
- data/lib/grape_oauth2/mixins/active_record/client.rb +36 -35
- data/lib/grape_oauth2/mixins/mongoid/access_grant.rb +58 -58
- data/lib/grape_oauth2/mixins/mongoid/access_token.rb +88 -88
- data/lib/grape_oauth2/mixins/mongoid/client.rb +44 -41
- data/lib/grape_oauth2/mixins/sequel/access_grant.rb +68 -68
- data/lib/grape_oauth2/mixins/sequel/access_token.rb +86 -86
- data/lib/grape_oauth2/mixins/sequel/client.rb +54 -46
- data/lib/grape_oauth2/responses/authorization.rb +11 -10
- data/lib/grape_oauth2/responses/base.rb +56 -56
- data/lib/grape_oauth2/responses/token.rb +10 -10
- data/lib/grape_oauth2/scopes.rb +74 -74
- data/lib/grape_oauth2/strategies/authorization_code.rb +38 -38
- data/lib/grape_oauth2/strategies/base.rb +47 -47
- data/lib/grape_oauth2/strategies/client_credentials.rb +20 -20
- data/lib/grape_oauth2/strategies/password.rb +22 -22
- data/lib/grape_oauth2/strategies/refresh_token.rb +47 -47
- data/lib/grape_oauth2/unique_token.rb +20 -20
- data/lib/grape_oauth2/version.rb +14 -14
- data/spec/configuration/config_spec.rb +231 -231
- data/spec/configuration/version_spec.rb +12 -12
- data/spec/dummy/endpoints/custom_authorization.rb +25 -25
- data/spec/dummy/endpoints/custom_token.rb +35 -35
- data/spec/dummy/endpoints/status.rb +25 -25
- data/spec/dummy/grape_oauth2_config.rb +11 -11
- data/spec/dummy/orm/active_record/app/config/db.rb +7 -7
- data/spec/dummy/orm/active_record/app/models/access_code.rb +3 -3
- data/spec/dummy/orm/active_record/app/models/access_token.rb +3 -3
- data/spec/dummy/orm/active_record/app/models/application.rb +3 -3
- data/spec/dummy/orm/active_record/app/models/application_record.rb +3 -3
- data/spec/dummy/orm/active_record/app/models/user.rb +10 -10
- data/spec/dummy/orm/active_record/app/twitter.rb +36 -36
- data/spec/dummy/orm/active_record/config.ru +7 -7
- data/spec/dummy/orm/active_record/db/schema.rb +53 -53
- data/spec/dummy/orm/mongoid/app/config/db.rb +6 -6
- data/spec/dummy/orm/mongoid/app/config/mongoid.yml +21 -21
- data/spec/dummy/orm/mongoid/app/models/access_code.rb +3 -3
- data/spec/dummy/orm/mongoid/app/models/access_token.rb +3 -3
- data/spec/dummy/orm/mongoid/app/models/application.rb +3 -3
- data/spec/dummy/orm/mongoid/app/models/user.rb +11 -11
- data/spec/dummy/orm/mongoid/app/twitter.rb +34 -34
- data/spec/dummy/orm/mongoid/config.ru +5 -5
- data/spec/dummy/orm/sequel/app/config/db.rb +1 -1
- data/spec/dummy/orm/sequel/app/models/access_code.rb +4 -4
- data/spec/dummy/orm/sequel/app/models/access_token.rb +4 -4
- data/spec/dummy/orm/sequel/app/models/application.rb +4 -4
- data/spec/dummy/orm/sequel/app/models/application_record.rb +2 -2
- data/spec/dummy/orm/sequel/app/models/user.rb +11 -11
- data/spec/dummy/orm/sequel/app/twitter.rb +47 -47
- data/spec/dummy/orm/sequel/config.ru +5 -5
- data/spec/dummy/orm/sequel/db/schema.rb +50 -50
- data/spec/lib/scopes_spec.rb +50 -50
- data/spec/mixins/active_record/access_token_spec.rb +185 -185
- data/spec/mixins/active_record/client_spec.rb +104 -95
- data/spec/mixins/mongoid/access_token_spec.rb +185 -185
- data/spec/mixins/mongoid/client_spec.rb +104 -95
- data/spec/mixins/sequel/access_token_spec.rb +185 -185
- data/spec/mixins/sequel/client_spec.rb +105 -96
- data/spec/requests/flows/authorization_code_spec.rb +67 -67
- data/spec/requests/flows/client_credentials_spec.rb +101 -101
- data/spec/requests/flows/password_spec.rb +210 -210
- data/spec/requests/flows/refresh_token_spec.rb +222 -222
- data/spec/requests/flows/revoke_token_spec.rb +103 -103
- data/spec/requests/protected_resources_spec.rb +64 -64
- data/spec/spec_helper.rb +60 -60
- data/spec/support/api_helper.rb +11 -11
- metadata +50 -52
- data/.rspec +0 -2
- data/.rubocop.yml +0 -18
- data/.travis.yml +0 -42
- data/README.md +0 -820
- data/gemfiles/active_record.rb +0 -25
- data/gemfiles/mongoid.rb +0 -14
- data/gemfiles/sequel.rb +0 -24
- data/grape_oauth2.png +0 -0
@@ -1,20 +1,20 @@
|
|
1
|
-
module Grape
|
2
|
-
module OAuth2
|
3
|
-
module Strategies
|
4
|
-
# Client Credentials strategy class.
|
5
|
-
# Processes request and respond with Access Token.
|
6
|
-
class ClientCredentials < Base
|
7
|
-
class << self
|
8
|
-
# Processes Client Credentials request.
|
9
|
-
def process(request)
|
10
|
-
client = authenticate_client(request)
|
11
|
-
request.invalid_client! if client.nil?
|
12
|
-
|
13
|
-
token = config.access_token_class.create_for(client, nil, scopes_from(request))
|
14
|
-
expose_to_bearer_token(token)
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
1
|
+
module Grape
|
2
|
+
module OAuth2
|
3
|
+
module Strategies
|
4
|
+
# Client Credentials strategy class.
|
5
|
+
# Processes request and respond with Access Token.
|
6
|
+
class ClientCredentials < Base
|
7
|
+
class << self
|
8
|
+
# Processes Client Credentials request.
|
9
|
+
def process(request)
|
10
|
+
client = authenticate_client(request)
|
11
|
+
request.invalid_client! if client.nil?
|
12
|
+
|
13
|
+
token = config.access_token_class.create_for(client, nil, scopes_from(request))
|
14
|
+
expose_to_bearer_token(token)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -1,22 +1,22 @@
|
|
1
|
-
module Grape
|
2
|
-
module OAuth2
|
3
|
-
module Strategies
|
4
|
-
# Resource Owner Password Credentials strategy class.
|
5
|
-
# Processes request and respond with Access Token.
|
6
|
-
class Password < Base
|
7
|
-
class << self
|
8
|
-
# Processes Password request.
|
9
|
-
def process(request)
|
10
|
-
client = authenticate_client(request) || request.invalid_client!
|
11
|
-
resource_owner = authenticate_resource_owner(client, request)
|
12
|
-
|
13
|
-
request.invalid_grant! if resource_owner.nil?
|
14
|
-
|
15
|
-
token = config.access_token_class.create_for(client, resource_owner, scopes_from(request))
|
16
|
-
expose_to_bearer_token(token)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
1
|
+
module Grape
|
2
|
+
module OAuth2
|
3
|
+
module Strategies
|
4
|
+
# Resource Owner Password Credentials strategy class.
|
5
|
+
# Processes request and respond with Access Token.
|
6
|
+
class Password < Base
|
7
|
+
class << self
|
8
|
+
# Processes Password request.
|
9
|
+
def process(request)
|
10
|
+
client = authenticate_client(request) || request.invalid_client!
|
11
|
+
resource_owner = authenticate_resource_owner(client, request)
|
12
|
+
|
13
|
+
request.invalid_grant! if resource_owner.nil?
|
14
|
+
|
15
|
+
token = config.access_token_class.create_for(client, resource_owner, scopes_from(request))
|
16
|
+
expose_to_bearer_token(token)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -1,47 +1,47 @@
|
|
1
|
-
module Grape
|
2
|
-
module OAuth2
|
3
|
-
module Strategies
|
4
|
-
# Refresh Token strategy class.
|
5
|
-
# Processes request and respond with Access Token.
|
6
|
-
class RefreshToken < Base
|
7
|
-
class << self
|
8
|
-
# Processes Refresh Token request.
|
9
|
-
def process(request)
|
10
|
-
client = authenticate_client(request)
|
11
|
-
|
12
|
-
request.invalid_client! if client.nil?
|
13
|
-
|
14
|
-
refresh_token = config.access_token_class.authenticate(request.refresh_token, type: :refresh_token)
|
15
|
-
request.invalid_grant! if refresh_token.nil?
|
16
|
-
request.unauthorized_client! if refresh_token && refresh_token.client != client
|
17
|
-
|
18
|
-
token = config.access_token_class.create_for(client, refresh_token.resource_owner)
|
19
|
-
run_on_refresh_callback(refresh_token) if config.on_refresh_runnable?
|
20
|
-
|
21
|
-
expose_to_bearer_token(token)
|
22
|
-
end
|
23
|
-
|
24
|
-
private
|
25
|
-
|
26
|
-
# Invokes custom callback on Access Token refresh.
|
27
|
-
# If callback is a proc, then call it with token.
|
28
|
-
# If access token responds to callback value (symbol for example), then call it from the token.
|
29
|
-
#
|
30
|
-
# @param access_token [Object] Access Token instance
|
31
|
-
#
|
32
|
-
def run_on_refresh_callback(access_token)
|
33
|
-
callback = config.on_refresh
|
34
|
-
|
35
|
-
if callback.respond_to?(:call)
|
36
|
-
callback.call(access_token)
|
37
|
-
elsif access_token.respond_to?(callback)
|
38
|
-
access_token.send(callback)
|
39
|
-
else
|
40
|
-
raise ArgumentError, ":on_refresh is not a block and Access Token class doesn't respond to #{callback}!"
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
1
|
+
module Grape
|
2
|
+
module OAuth2
|
3
|
+
module Strategies
|
4
|
+
# Refresh Token strategy class.
|
5
|
+
# Processes request and respond with Access Token.
|
6
|
+
class RefreshToken < Base
|
7
|
+
class << self
|
8
|
+
# Processes Refresh Token request.
|
9
|
+
def process(request)
|
10
|
+
client = authenticate_client(request)
|
11
|
+
|
12
|
+
request.invalid_client! if client.nil?
|
13
|
+
|
14
|
+
refresh_token = config.access_token_class.authenticate(request.refresh_token, type: :refresh_token)
|
15
|
+
request.invalid_grant! if refresh_token.nil?
|
16
|
+
request.unauthorized_client! if refresh_token && refresh_token.client != client
|
17
|
+
|
18
|
+
token = config.access_token_class.create_for(client, refresh_token.resource_owner)
|
19
|
+
run_on_refresh_callback(refresh_token) if config.on_refresh_runnable?
|
20
|
+
|
21
|
+
expose_to_bearer_token(token)
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
# Invokes custom callback on Access Token refresh.
|
27
|
+
# If callback is a proc, then call it with token.
|
28
|
+
# If access token responds to callback value (symbol for example), then call it from the token.
|
29
|
+
#
|
30
|
+
# @param access_token [Object] Access Token instance
|
31
|
+
#
|
32
|
+
def run_on_refresh_callback(access_token)
|
33
|
+
callback = config.on_refresh
|
34
|
+
|
35
|
+
if callback.respond_to?(:call)
|
36
|
+
callback.call(access_token)
|
37
|
+
elsif access_token.respond_to?(callback)
|
38
|
+
access_token.send(callback)
|
39
|
+
else
|
40
|
+
raise ArgumentError, ":on_refresh is not a block and Access Token class doesn't respond to #{callback}!"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -1,20 +1,20 @@
|
|
1
|
-
module Grape
|
2
|
-
module OAuth2
|
3
|
-
# OAuth2 helper for generation of unique token values.
|
4
|
-
# Can process custom payload and options.
|
5
|
-
module UniqueToken
|
6
|
-
# Generates unique token value.
|
7
|
-
#
|
8
|
-
# @param _payload [Hash]
|
9
|
-
# payload
|
10
|
-
# @param options [Hash]
|
11
|
-
# options for generator
|
12
|
-
#
|
13
|
-
# @return [String]
|
14
|
-
# unique token value
|
15
|
-
def self.generate(_payload = {}, options = {})
|
16
|
-
SecureRandom.hex(options.delete(:size) || 32)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
1
|
+
module Grape
|
2
|
+
module OAuth2
|
3
|
+
# OAuth2 helper for generation of unique token values.
|
4
|
+
# Can process custom payload and options.
|
5
|
+
module UniqueToken
|
6
|
+
# Generates unique token value.
|
7
|
+
#
|
8
|
+
# @param _payload [Hash]
|
9
|
+
# payload
|
10
|
+
# @param options [Hash]
|
11
|
+
# options for generator
|
12
|
+
#
|
13
|
+
# @return [String]
|
14
|
+
# unique token value
|
15
|
+
def self.generate(_payload = {}, options = {})
|
16
|
+
SecureRandom.hex(options.delete(:size) || 32)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/grape_oauth2/version.rb
CHANGED
@@ -1,14 +1,14 @@
|
|
1
|
-
require_relative 'gem_version'
|
2
|
-
|
3
|
-
module Grape
|
4
|
-
module OAuth2
|
5
|
-
# Grape::OAuth2 gem version.
|
6
|
-
#
|
7
|
-
# @return [Gem::Version]
|
8
|
-
# version value
|
9
|
-
#
|
10
|
-
def self.version
|
11
|
-
gem_version
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
1
|
+
require_relative 'gem_version'
|
2
|
+
|
3
|
+
module Grape
|
4
|
+
module OAuth2
|
5
|
+
# Grape::OAuth2 gem version.
|
6
|
+
#
|
7
|
+
# @return [Gem::Version]
|
8
|
+
# version value
|
9
|
+
#
|
10
|
+
def self.version
|
11
|
+
gem_version
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -1,231 +1,231 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Grape::OAuth2::Configuration do
|
4
|
-
let(:config) { described_class.new }
|
5
|
-
|
6
|
-
# Refactor: Mock it
|
7
|
-
class CustomClient
|
8
|
-
def self.authenticate(key, secret = nil)
|
9
|
-
'Test'
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
class CustomAccessToken
|
14
|
-
def self.create_for(client, resource_owner, scopes = nil)
|
15
|
-
end
|
16
|
-
|
17
|
-
def self.authenticate(token, type: :access_token)
|
18
|
-
'Test'
|
19
|
-
end
|
20
|
-
|
21
|
-
def client
|
22
|
-
end
|
23
|
-
|
24
|
-
def resource_owner
|
25
|
-
end
|
26
|
-
|
27
|
-
def expired?
|
28
|
-
end
|
29
|
-
|
30
|
-
def revoked?
|
31
|
-
end
|
32
|
-
|
33
|
-
def revoke!(revoked_at = Time.now)
|
34
|
-
end
|
35
|
-
|
36
|
-
def to_bearer_token
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
class CustomResourceOwner
|
41
|
-
def self.oauth_authenticate(client, username, password)
|
42
|
-
'Test'
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
context 'default config' do
|
47
|
-
it 'setup config with default values' do
|
48
|
-
expect(config.access_token_lifetime).to eq(7200)
|
49
|
-
expect(config.authorization_code_lifetime).to eq(1800)
|
50
|
-
|
51
|
-
expect(config.realm).to eq(Grape::OAuth2::Configuration::DEFAULT_REALM)
|
52
|
-
expect(config.allowed_grant_types).to eq(%w
|
53
|
-
|
54
|
-
expect(config.issue_refresh_token).to be_falsey
|
55
|
-
expect(config.on_refresh).to eq(:nothing)
|
56
|
-
|
57
|
-
expect(config.scopes_validator_class_name).to eq(Grape::OAuth2::Scopes.name)
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
context 'custom config' do
|
62
|
-
class CustomScopesValidator
|
63
|
-
def initialize(scopes)
|
64
|
-
@scopes = scopes
|
65
|
-
end
|
66
|
-
|
67
|
-
def valid_for?(
|
68
|
-
false
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
class CustomTokenGenerator
|
73
|
-
def self.generate(options = {})
|
74
|
-
if options[:custom]
|
75
|
-
'custom_token'
|
76
|
-
else
|
77
|
-
'default_token'
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
before do
|
83
|
-
config.access_token_class_name = 'CustomAccessToken'
|
84
|
-
config.resource_owner_class_name = 'CustomResourceOwner'
|
85
|
-
config.client_class_name = 'CustomClient'
|
86
|
-
config.access_grant_class_name = 'Object'
|
87
|
-
config.scopes_validator_class_name = 'CustomScopesValidator'
|
88
|
-
end
|
89
|
-
|
90
|
-
it 'invokes custom scopes validator' do
|
91
|
-
expect(config.scopes_validator.new([]).valid_for?(nil)).to be_falsey
|
92
|
-
end
|
93
|
-
|
94
|
-
it 'works with custom Access Token class' do
|
95
|
-
expect(config.access_token_class.authenticate('')).to eq('Test')
|
96
|
-
end
|
97
|
-
|
98
|
-
it 'works with custom Client class' do
|
99
|
-
expect(config.client_class.authenticate('')).to eq('Test')
|
100
|
-
end
|
101
|
-
|
102
|
-
it 'works with custom Resource Owner class' do
|
103
|
-
expect(config.resource_owner_class.oauth_authenticate('', '', '')).to eq('Test')
|
104
|
-
end
|
105
|
-
|
106
|
-
it 'works with custom token authenticator' do
|
107
|
-
# before
|
108
|
-
Grape::OAuth2.configure do |config|
|
109
|
-
config.token_authenticator do |request|
|
110
|
-
raise ArgumentError, 'Test'
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
expect { config.token_authenticator.call }.to raise_error(ArgumentError)
|
115
|
-
|
116
|
-
# after
|
117
|
-
Grape::OAuth2.configure do |config|
|
118
|
-
config.token_authenticator = config.default_token_authenticator
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
it 'works with custom token generator' do
|
123
|
-
# before
|
124
|
-
Grape::OAuth2.configure do |config|
|
125
|
-
config.token_generator_class_name = 'CustomTokenGenerator'
|
126
|
-
end
|
127
|
-
|
128
|
-
expect(Grape::OAuth2.config.token_generator.generate).to eq('default_token')
|
129
|
-
expect(Grape::OAuth2.config.token_generator.generate(custom: true)).to eq('custom_token')
|
130
|
-
|
131
|
-
# after
|
132
|
-
Grape::OAuth2.configure do |config|
|
133
|
-
config.token_generator_class_name = Grape::OAuth2::UniqueToken.name
|
134
|
-
end
|
135
|
-
end
|
136
|
-
|
137
|
-
it 'works with custom on_refresh callback' do
|
138
|
-
token = AccessToken.create
|
139
|
-
|
140
|
-
# before
|
141
|
-
Grape::OAuth2.configure do |config|
|
142
|
-
config.on_refresh do |access_token|
|
143
|
-
access_token.update(scopes: 'test')
|
144
|
-
end
|
145
|
-
end
|
146
|
-
|
147
|
-
expect {
|
148
|
-
Grape::OAuth2::Strategies::RefreshToken.send(:run_on_refresh_callback, token)
|
149
|
-
}.to change { token.scopes }.to('test')
|
150
|
-
|
151
|
-
# after
|
152
|
-
Grape::OAuth2.configure do |config|
|
153
|
-
config.on_refresh = :nothing
|
154
|
-
end
|
155
|
-
end
|
156
|
-
|
157
|
-
it 'raises an error with invalid on_refresh callback' do
|
158
|
-
# before
|
159
|
-
Grape::OAuth2.configure do |config|
|
160
|
-
config.on_refresh = 'invalid'
|
161
|
-
end
|
162
|
-
|
163
|
-
expect {
|
164
|
-
Grape::OAuth2::Strategies::RefreshToken.send(:run_on_refresh_callback, nil)
|
165
|
-
}.to raise_error(ArgumentError)
|
166
|
-
|
167
|
-
# after
|
168
|
-
Grape::OAuth2.configure do |config|
|
169
|
-
config.on_refresh = :nothing
|
170
|
-
end
|
171
|
-
end
|
172
|
-
end
|
173
|
-
|
174
|
-
context 'validation' do
|
175
|
-
context 'with invalid config options' do
|
176
|
-
it 'raises an error for default configuration' do
|
177
|
-
expect { config.check! }.to raise_error(Grape::OAuth2::Configuration::Error)
|
178
|
-
end
|
179
|
-
|
180
|
-
it "raises an error if configured classes doesn't have an instance methods" do
|
181
|
-
class InvalidAccessToken
|
182
|
-
# Only class methods
|
183
|
-
def self.create_for(client, resource_owner, scopes = nil)
|
184
|
-
end
|
185
|
-
|
186
|
-
def self.authenticate(token, type: :access_token)
|
187
|
-
'Test'
|
188
|
-
end
|
189
|
-
end
|
190
|
-
|
191
|
-
config.access_token_class_name = 'InvalidAccessToken'
|
192
|
-
config.resource_owner_class_name = 'CustomResourceOwner'
|
193
|
-
config.client_class_name = 'CustomClient'
|
194
|
-
config.access_grant_class_name = 'Object'
|
195
|
-
|
196
|
-
expect { config.check! }.to raise_error(Grape::OAuth2::Configuration::APIMissing) do |error|
|
197
|
-
expect(error.message).to include('access_token_class')
|
198
|
-
expect(error.message).to include('Instance method')
|
199
|
-
end
|
200
|
-
end
|
201
|
-
|
202
|
-
it "raises an error if configured classes doesn't have a class methods" do
|
203
|
-
class InvalidClient
|
204
|
-
end
|
205
|
-
|
206
|
-
config.access_token_class_name = 'CustomAccessToken'
|
207
|
-
config.resource_owner_class_name = 'CustomResourceOwner'
|
208
|
-
config.client_class_name = 'InvalidClient'
|
209
|
-
config.access_grant_class_name = 'Object'
|
210
|
-
|
211
|
-
expect { config.check! }.to raise_error(Grape::OAuth2::Configuration::APIMissing) do |error|
|
212
|
-
expect(error.message).to include('client_class')
|
213
|
-
expect(error.message).to include('Class method')
|
214
|
-
end
|
215
|
-
end
|
216
|
-
end
|
217
|
-
|
218
|
-
context 'with valid config options' do
|
219
|
-
before do
|
220
|
-
config.access_token_class_name = 'CustomAccessToken'
|
221
|
-
config.resource_owner_class_name = 'CustomResourceOwner'
|
222
|
-
config.client_class_name = 'CustomClient'
|
223
|
-
config.access_grant_class_name = 'Object'
|
224
|
-
end
|
225
|
-
|
226
|
-
it 'successfully pass' do
|
227
|
-
expect { config.check! }.not_to raise_error
|
228
|
-
end
|
229
|
-
end
|
230
|
-
end
|
231
|
-
end
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Grape::OAuth2::Configuration do
|
4
|
+
let(:config) { described_class.new }
|
5
|
+
|
6
|
+
# Refactor: Mock it
|
7
|
+
class CustomClient
|
8
|
+
def self.authenticate(key, secret = nil)
|
9
|
+
'Test'
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class CustomAccessToken
|
14
|
+
def self.create_for(client, resource_owner, scopes = nil)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.authenticate(token, type: :access_token)
|
18
|
+
'Test'
|
19
|
+
end
|
20
|
+
|
21
|
+
def client
|
22
|
+
end
|
23
|
+
|
24
|
+
def resource_owner
|
25
|
+
end
|
26
|
+
|
27
|
+
def expired?
|
28
|
+
end
|
29
|
+
|
30
|
+
def revoked?
|
31
|
+
end
|
32
|
+
|
33
|
+
def revoke!(revoked_at = Time.now)
|
34
|
+
end
|
35
|
+
|
36
|
+
def to_bearer_token
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class CustomResourceOwner
|
41
|
+
def self.oauth_authenticate(client, username, password)
|
42
|
+
'Test'
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context 'default config' do
|
47
|
+
it 'setup config with default values' do
|
48
|
+
expect(config.access_token_lifetime).to eq(7200)
|
49
|
+
expect(config.authorization_code_lifetime).to eq(1800)
|
50
|
+
|
51
|
+
expect(config.realm).to eq(Grape::OAuth2::Configuration::DEFAULT_REALM)
|
52
|
+
expect(config.allowed_grant_types).to eq(%w[password client_credentials])
|
53
|
+
|
54
|
+
expect(config.issue_refresh_token).to be_falsey
|
55
|
+
expect(config.on_refresh).to eq(:nothing)
|
56
|
+
|
57
|
+
expect(config.scopes_validator_class_name).to eq(Grape::OAuth2::Scopes.name)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context 'custom config' do
|
62
|
+
class CustomScopesValidator
|
63
|
+
def initialize(scopes)
|
64
|
+
@scopes = scopes
|
65
|
+
end
|
66
|
+
|
67
|
+
def valid_for?(*)
|
68
|
+
false
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
class CustomTokenGenerator
|
73
|
+
def self.generate(options = {})
|
74
|
+
if options[:custom]
|
75
|
+
'custom_token'
|
76
|
+
else
|
77
|
+
'default_token'
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
before do
|
83
|
+
config.access_token_class_name = 'CustomAccessToken'
|
84
|
+
config.resource_owner_class_name = 'CustomResourceOwner'
|
85
|
+
config.client_class_name = 'CustomClient'
|
86
|
+
config.access_grant_class_name = 'Object'
|
87
|
+
config.scopes_validator_class_name = 'CustomScopesValidator'
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'invokes custom scopes validator' do
|
91
|
+
expect(config.scopes_validator.new([]).valid_for?(nil)).to be_falsey
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'works with custom Access Token class' do
|
95
|
+
expect(config.access_token_class.authenticate('')).to eq('Test')
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'works with custom Client class' do
|
99
|
+
expect(config.client_class.authenticate('')).to eq('Test')
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'works with custom Resource Owner class' do
|
103
|
+
expect(config.resource_owner_class.oauth_authenticate('', '', '')).to eq('Test')
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'works with custom token authenticator' do
|
107
|
+
# before
|
108
|
+
Grape::OAuth2.configure do |config|
|
109
|
+
config.token_authenticator do |request|
|
110
|
+
raise ArgumentError, 'Test'
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
expect { config.token_authenticator.call }.to raise_error(ArgumentError)
|
115
|
+
|
116
|
+
# after
|
117
|
+
Grape::OAuth2.configure do |config|
|
118
|
+
config.token_authenticator = config.default_token_authenticator
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
it 'works with custom token generator' do
|
123
|
+
# before
|
124
|
+
Grape::OAuth2.configure do |config|
|
125
|
+
config.token_generator_class_name = 'CustomTokenGenerator'
|
126
|
+
end
|
127
|
+
|
128
|
+
expect(Grape::OAuth2.config.token_generator.generate).to eq('default_token')
|
129
|
+
expect(Grape::OAuth2.config.token_generator.generate(custom: true)).to eq('custom_token')
|
130
|
+
|
131
|
+
# after
|
132
|
+
Grape::OAuth2.configure do |config|
|
133
|
+
config.token_generator_class_name = Grape::OAuth2::UniqueToken.name
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
it 'works with custom on_refresh callback' do
|
138
|
+
token = AccessToken.create
|
139
|
+
|
140
|
+
# before
|
141
|
+
Grape::OAuth2.configure do |config|
|
142
|
+
config.on_refresh do |access_token|
|
143
|
+
access_token.update(scopes: 'test')
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
expect {
|
148
|
+
Grape::OAuth2::Strategies::RefreshToken.send(:run_on_refresh_callback, token)
|
149
|
+
}.to change { token.scopes }.to('test')
|
150
|
+
|
151
|
+
# after
|
152
|
+
Grape::OAuth2.configure do |config|
|
153
|
+
config.on_refresh = :nothing
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
it 'raises an error with invalid on_refresh callback' do
|
158
|
+
# before
|
159
|
+
Grape::OAuth2.configure do |config|
|
160
|
+
config.on_refresh = 'invalid'
|
161
|
+
end
|
162
|
+
|
163
|
+
expect {
|
164
|
+
Grape::OAuth2::Strategies::RefreshToken.send(:run_on_refresh_callback, nil)
|
165
|
+
}.to raise_error(ArgumentError)
|
166
|
+
|
167
|
+
# after
|
168
|
+
Grape::OAuth2.configure do |config|
|
169
|
+
config.on_refresh = :nothing
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
context 'validation' do
|
175
|
+
context 'with invalid config options' do
|
176
|
+
it 'raises an error for default configuration' do
|
177
|
+
expect { config.check! }.to raise_error(Grape::OAuth2::Configuration::Error)
|
178
|
+
end
|
179
|
+
|
180
|
+
it "raises an error if configured classes doesn't have an instance methods" do
|
181
|
+
class InvalidAccessToken
|
182
|
+
# Only class methods
|
183
|
+
def self.create_for(client, resource_owner, scopes = nil)
|
184
|
+
end
|
185
|
+
|
186
|
+
def self.authenticate(token, type: :access_token)
|
187
|
+
'Test'
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
config.access_token_class_name = 'InvalidAccessToken'
|
192
|
+
config.resource_owner_class_name = 'CustomResourceOwner'
|
193
|
+
config.client_class_name = 'CustomClient'
|
194
|
+
config.access_grant_class_name = 'Object'
|
195
|
+
|
196
|
+
expect { config.check! }.to raise_error(Grape::OAuth2::Configuration::APIMissing) do |error|
|
197
|
+
expect(error.message).to include('access_token_class')
|
198
|
+
expect(error.message).to include('Instance method')
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
it "raises an error if configured classes doesn't have a class methods" do
|
203
|
+
class InvalidClient
|
204
|
+
end
|
205
|
+
|
206
|
+
config.access_token_class_name = 'CustomAccessToken'
|
207
|
+
config.resource_owner_class_name = 'CustomResourceOwner'
|
208
|
+
config.client_class_name = 'InvalidClient'
|
209
|
+
config.access_grant_class_name = 'Object'
|
210
|
+
|
211
|
+
expect { config.check! }.to raise_error(Grape::OAuth2::Configuration::APIMissing) do |error|
|
212
|
+
expect(error.message).to include('client_class')
|
213
|
+
expect(error.message).to include('Class method')
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
context 'with valid config options' do
|
219
|
+
before do
|
220
|
+
config.access_token_class_name = 'CustomAccessToken'
|
221
|
+
config.resource_owner_class_name = 'CustomResourceOwner'
|
222
|
+
config.client_class_name = 'CustomClient'
|
223
|
+
config.access_grant_class_name = 'Object'
|
224
|
+
end
|
225
|
+
|
226
|
+
it 'successfully pass' do
|
227
|
+
expect { config.check! }.not_to raise_error
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|