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,34 @@
|
|
|
1
|
+
module Grape
|
|
2
|
+
module OAuth2
|
|
3
|
+
# Grape::OAuth2 endpoints namespace
|
|
4
|
+
module Endpoints
|
|
5
|
+
# OAuth2 Grape authorization endpoint.
|
|
6
|
+
class Authorize < ::Grape::API
|
|
7
|
+
helpers Grape::OAuth2::Helpers::OAuthParams
|
|
8
|
+
|
|
9
|
+
namespace :oauth do
|
|
10
|
+
desc 'OAuth 2.0 Authorization Endpoint'
|
|
11
|
+
|
|
12
|
+
params do
|
|
13
|
+
use :oauth_authorization_params
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
post :authorize do
|
|
17
|
+
response = Grape::OAuth2::Generators::Authorization.generate_for(env)
|
|
18
|
+
|
|
19
|
+
# Status
|
|
20
|
+
status response.status
|
|
21
|
+
|
|
22
|
+
# Headers
|
|
23
|
+
response.headers.each do |key, value|
|
|
24
|
+
header key, value
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Body
|
|
28
|
+
body response.body
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
module Grape
|
|
2
|
+
module OAuth2
|
|
3
|
+
# Grape::OAuth2 endpoints namespace
|
|
4
|
+
module Endpoints
|
|
5
|
+
# OAuth2 Grape token endpoint.
|
|
6
|
+
class Token < ::Grape::API
|
|
7
|
+
helpers Grape::OAuth2::Helpers::OAuthParams
|
|
8
|
+
|
|
9
|
+
namespace :oauth do
|
|
10
|
+
# @see https://tools.ietf.org/html/rfc6749#section-3.2
|
|
11
|
+
#
|
|
12
|
+
desc 'OAuth 2.0 Token Endpoint'
|
|
13
|
+
|
|
14
|
+
params do
|
|
15
|
+
use :oauth_token_params
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
post :token do
|
|
19
|
+
token_response = Grape::OAuth2::Generators::Token.generate_for(env)
|
|
20
|
+
|
|
21
|
+
# Status
|
|
22
|
+
status token_response.status
|
|
23
|
+
|
|
24
|
+
# Headers
|
|
25
|
+
token_response.headers.each do |key, value|
|
|
26
|
+
header key, value
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Body
|
|
30
|
+
body token_response.body
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
desc 'OAuth 2.0 Token Revocation'
|
|
34
|
+
|
|
35
|
+
params do
|
|
36
|
+
use :oauth_token_revocation_params
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
post :revoke do
|
|
40
|
+
access_token = Grape::OAuth2.config.access_token_class.authenticate(params[:token],
|
|
41
|
+
type: params[:token_type_hint])
|
|
42
|
+
|
|
43
|
+
if access_token
|
|
44
|
+
if access_token.client
|
|
45
|
+
request = Rack::OAuth2::Server::Token::Request.new(env)
|
|
46
|
+
|
|
47
|
+
# The authorization server, if applicable, first authenticates the client
|
|
48
|
+
# and checks its ownership of the provided token.
|
|
49
|
+
client = Grape::OAuth2::Strategies::Base.authenticate_client(request)
|
|
50
|
+
request.invalid_client! if client.nil?
|
|
51
|
+
|
|
52
|
+
access_token.revoke! if client && client == access_token.client
|
|
53
|
+
else
|
|
54
|
+
# Access token is public
|
|
55
|
+
access_token.revoke!
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# The authorization server responds with HTTP status code 200 if the token
|
|
60
|
+
# has been revoked successfully or if the client submitted an invalid
|
|
61
|
+
# token.
|
|
62
|
+
#
|
|
63
|
+
# @see https://tools.ietf.org/html/rfc7009#section-2.2 Revocation Response
|
|
64
|
+
#
|
|
65
|
+
status 200
|
|
66
|
+
{}
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module Grape
|
|
2
|
+
module OAuth2
|
|
3
|
+
# Grape::OAuth2 version.
|
|
4
|
+
# @return [Gem::Version] version of the gem
|
|
5
|
+
#
|
|
6
|
+
def self.gem_version
|
|
7
|
+
Gem::Version.new VERSION::STRING
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# Grape::OAuth2 semantic versioning module.
|
|
11
|
+
# Contains detailed info about gem version.
|
|
12
|
+
module VERSION
|
|
13
|
+
# Major version of the gem
|
|
14
|
+
MAJOR = 0
|
|
15
|
+
# Minor version of the gem
|
|
16
|
+
MINOR = 1
|
|
17
|
+
# Tiny version of the gem
|
|
18
|
+
TINY = 1
|
|
19
|
+
|
|
20
|
+
# Full gem version string
|
|
21
|
+
STRING = [MAJOR, MINOR, TINY].compact.join('.')
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
module Grape
|
|
2
|
+
module OAuth2
|
|
3
|
+
module Generators
|
|
4
|
+
# OAuth2 Authorization generator class.
|
|
5
|
+
# Processes the request and builds the response.
|
|
6
|
+
class Authorization < Base
|
|
7
|
+
class << self
|
|
8
|
+
# Generates Authorization Response based on the request.
|
|
9
|
+
#
|
|
10
|
+
# @return [Grape::OAuth2::Responses::Authorization] response
|
|
11
|
+
#
|
|
12
|
+
def generate_for(env, &_block)
|
|
13
|
+
authorization = Rack::OAuth2::Server::Authorize.new do |request, response|
|
|
14
|
+
if block_given?
|
|
15
|
+
yield request, response
|
|
16
|
+
else
|
|
17
|
+
execute_default(request, response)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
Grape::OAuth2::Responses::Authorization.new(authorization.call(env))
|
|
22
|
+
rescue Rack::OAuth2::Server::Authorize::BadRequest => error
|
|
23
|
+
error_response(error)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
def error_response(error)
|
|
29
|
+
response = Rack::Response.new
|
|
30
|
+
response.status = error.status
|
|
31
|
+
response.header['Content-Type'] = 'application/json'
|
|
32
|
+
response.write(JSON.dump(Rack::OAuth2::Util.compact_hash(error.protocol_params)))
|
|
33
|
+
|
|
34
|
+
Grape::OAuth2::Responses::Authorization.new(response.finish)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def execute_default(request, response)
|
|
38
|
+
Grape::OAuth2::Strategies::AuthorizationCode.process(request, response)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module Grape
|
|
2
|
+
module OAuth2
|
|
3
|
+
module Generators
|
|
4
|
+
# Base class for Grape::OAuth2 generators.
|
|
5
|
+
# Grape::OAuth2 generators processes the requests and
|
|
6
|
+
# generates responses with Access Token or Authorization Code.
|
|
7
|
+
class Base
|
|
8
|
+
class << self
|
|
9
|
+
# Allowed grant types from the Grape::OAuth2 configuration.
|
|
10
|
+
#
|
|
11
|
+
# @return [Array]
|
|
12
|
+
# allowed grant types
|
|
13
|
+
#
|
|
14
|
+
def allowed_grants
|
|
15
|
+
config.allowed_grant_types
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Short getter for Grape::OAuth2 configuration.
|
|
19
|
+
def config
|
|
20
|
+
Grape::OAuth2.config
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
module Grape
|
|
2
|
+
module OAuth2
|
|
3
|
+
module Generators
|
|
4
|
+
# OAuth2 Token generator class.
|
|
5
|
+
# Processes the request by required Grant Type and builds the response.
|
|
6
|
+
class Token < Base
|
|
7
|
+
# Grant type => OAuth2 strategy class
|
|
8
|
+
STRATEGY_CLASSES = {
|
|
9
|
+
password: Grape::OAuth2::Strategies::Password,
|
|
10
|
+
client_credentials: Grape::OAuth2::Strategies::ClientCredentials,
|
|
11
|
+
refresh_token: Grape::OAuth2::Strategies::RefreshToken
|
|
12
|
+
}.freeze
|
|
13
|
+
|
|
14
|
+
class << self
|
|
15
|
+
# Generates Token Response based on the request.
|
|
16
|
+
#
|
|
17
|
+
# @return [Grape::OAuth2::Responses::Token] response
|
|
18
|
+
#
|
|
19
|
+
def generate_for(env, &_block)
|
|
20
|
+
token = Rack::OAuth2::Server::Token.new do |request, response|
|
|
21
|
+
request.unsupported_grant_type! unless allowed_grants.include?(request.grant_type.to_s)
|
|
22
|
+
|
|
23
|
+
if block_given?
|
|
24
|
+
yield request, response
|
|
25
|
+
else
|
|
26
|
+
execute_default(request, response)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
Grape::OAuth2::Responses::Token.new(token.call(env))
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
protected
|
|
34
|
+
|
|
35
|
+
# Runs default Grape::OAuth2 functionality for Token endpoint.
|
|
36
|
+
# In common it authenticates client (or/and any other objects) and
|
|
37
|
+
# grants the Access Token or Auth Code.
|
|
38
|
+
#
|
|
39
|
+
# @param request [Rack::Request] request object
|
|
40
|
+
# @param response [Rack::Response] response object
|
|
41
|
+
#
|
|
42
|
+
def execute_default(request, response)
|
|
43
|
+
strategy = find_strategy(request.grant_type) || request.invalid_grant!
|
|
44
|
+
response.access_token = strategy.process(request)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Returns Grape::OAuth2 strategy class by Grant Type.
|
|
48
|
+
#
|
|
49
|
+
# @param grant_type [Symbol]
|
|
50
|
+
# grant type value
|
|
51
|
+
#
|
|
52
|
+
# @return [Password, ClientCredentials, RefreshToken]
|
|
53
|
+
# strategy class
|
|
54
|
+
#
|
|
55
|
+
def find_strategy(grant_type)
|
|
56
|
+
STRATEGY_CLASSES[grant_type]
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
module Grape
|
|
2
|
+
module OAuth2
|
|
3
|
+
module Helpers
|
|
4
|
+
# Set of Grape OAuth2 helpers.
|
|
5
|
+
module AccessTokenHelpers
|
|
6
|
+
extend ::Grape::API::Helpers
|
|
7
|
+
|
|
8
|
+
# Adds OAuth2 Access Token protection for Grape routes.
|
|
9
|
+
#
|
|
10
|
+
# @param scopes [Array]
|
|
11
|
+
# set of scopes required to access the endpoint
|
|
12
|
+
#
|
|
13
|
+
# @raise [Rack::OAuth2::Server::Resource::Bearer::Unauthorized]
|
|
14
|
+
# invalid Access Token value
|
|
15
|
+
# @raise [Rack::OAuth2::Server::Resource::Bearer::Forbidden]
|
|
16
|
+
# Access Token expired, revoked or does't have required scopes
|
|
17
|
+
#
|
|
18
|
+
def access_token_required!(*scopes)
|
|
19
|
+
endpoint_scopes = env['api.endpoint'].options[:route_options][:scopes]
|
|
20
|
+
required_scopes = endpoint_scopes.presence || scopes
|
|
21
|
+
|
|
22
|
+
raise Rack::OAuth2::Server::Resource::Bearer::Unauthorized if current_access_token.nil?
|
|
23
|
+
raise Rack::OAuth2::Server::Resource::Bearer::Forbidden unless valid_access_token?(required_scopes)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Returns Resource Owner from the Access Token
|
|
27
|
+
# found by access_token value passed with the request.
|
|
28
|
+
def current_resource_owner
|
|
29
|
+
@_current_resource_owner ||= current_access_token.resource_owner
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Returns Access Token instance found by
|
|
33
|
+
# access_token value passed with the request.
|
|
34
|
+
def current_access_token
|
|
35
|
+
@_current_access_token ||= request.env[Rack::OAuth2::Server::Resource::ACCESS_TOKEN]
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
# Validate current access token not to be expired or revoked
|
|
41
|
+
# and has all the requested scopes.
|
|
42
|
+
#
|
|
43
|
+
# @return [Boolean]
|
|
44
|
+
# true if current Access Token not expired, not revoked and scopes match
|
|
45
|
+
# false in other cases.
|
|
46
|
+
#
|
|
47
|
+
def valid_access_token?(scopes)
|
|
48
|
+
!current_access_token.revoked? && !current_access_token.expired? &&
|
|
49
|
+
Grape::OAuth2.config.scopes_validator.new(scopes).valid_for?(current_access_token)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
module Grape
|
|
2
|
+
module OAuth2
|
|
3
|
+
module Helpers
|
|
4
|
+
# Grape Helper object for OAuth2 requests params.
|
|
5
|
+
# Used fin default Grape::OAuth2 gem endpoints and can be used
|
|
6
|
+
# for custom one.
|
|
7
|
+
module OAuthParams
|
|
8
|
+
extend ::Grape::API::Helpers
|
|
9
|
+
|
|
10
|
+
# Params are optional in order to process them correctly in accordance
|
|
11
|
+
# with the RFC 6749 (invalid_client, unsupported_grant_type, etc.)
|
|
12
|
+
params :oauth_token_params do
|
|
13
|
+
optional :grant_type, type: String, desc: 'Grant type'
|
|
14
|
+
optional :client_id, type: String, desc: 'Client ID'
|
|
15
|
+
optional :client_secret, type: String, desc: 'Client secret'
|
|
16
|
+
optional :refresh_token, type: String, desc: 'Refresh Token'
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Params for authorization request.
|
|
20
|
+
# @see https://tools.ietf.org/html/draft-ietf-oauth-v2-22#section-4.1.1 Authorization Request
|
|
21
|
+
params :oauth_authorization_params do
|
|
22
|
+
optional :response_type, type: String, desc: 'Response type'
|
|
23
|
+
optional :client_id, type: String, desc: 'Client ID'
|
|
24
|
+
optional :redirect_uri, type: String, desc: 'Redirect URI'
|
|
25
|
+
optional :scope, type: String, desc: 'Authorization scopes'
|
|
26
|
+
optional :state, type: String, desc: 'State'
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Params for token revocation.
|
|
30
|
+
# @see https://tools.ietf.org/html/rfc7009#section-2.1 OAuth 2.0 Token Revocation
|
|
31
|
+
params :oauth_token_revocation_params do
|
|
32
|
+
requires :token, type: String, desc: 'The token that the client wants to get revoked'
|
|
33
|
+
optional :token_type_hint, type: String,
|
|
34
|
+
values: %w(access_token refresh_token),
|
|
35
|
+
default: 'access_token',
|
|
36
|
+
desc: 'A hint about the type of the token submitted for revocation'
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
module Grape
|
|
2
|
+
module OAuth2
|
|
3
|
+
module ActiveRecord
|
|
4
|
+
# Grape::OAuth2 Authorization Grant role mixin for ActiveRecord.
|
|
5
|
+
# Includes all the required API, associations, validations and callbacks.
|
|
6
|
+
module AccessGrant
|
|
7
|
+
extend ActiveSupport::Concern
|
|
8
|
+
|
|
9
|
+
included do
|
|
10
|
+
belongs_to :client, class_name: Grape::OAuth2.config.client_class_name,
|
|
11
|
+
foreign_key: :client_id
|
|
12
|
+
|
|
13
|
+
belongs_to :resource_owner, class_name: Grape::OAuth2.config.resource_owner_class_name,
|
|
14
|
+
foreign_key: :resource_owner_id
|
|
15
|
+
|
|
16
|
+
# resource_owner_id - required!
|
|
17
|
+
validates :client_id, :redirect_uri, presence: true
|
|
18
|
+
validates :token, presence: true, uniqueness: true
|
|
19
|
+
|
|
20
|
+
before_validation :generate_token, on: :create
|
|
21
|
+
before_validation :setup_expiration, on: :create
|
|
22
|
+
|
|
23
|
+
class << self
|
|
24
|
+
def create_for(client, resource_owner, redirect_uri, scopes = nil)
|
|
25
|
+
create(
|
|
26
|
+
client_id: client.id,
|
|
27
|
+
resource_owner_id: resource_owner && resource_owner.id,
|
|
28
|
+
redirect_uri: redirect_uri,
|
|
29
|
+
scopes: scopes.to_s
|
|
30
|
+
)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
protected
|
|
35
|
+
|
|
36
|
+
def generate_token
|
|
37
|
+
self.token = Grape::OAuth2.config.token_generator.generate(attributes)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def setup_expiration
|
|
41
|
+
self.expires_at = Time.now.utc + Grape::OAuth2.config.authorization_code_lifetime if expires_at.nil?
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
module Grape
|
|
2
|
+
module OAuth2
|
|
3
|
+
module ActiveRecord
|
|
4
|
+
# Grape::OAuth2 Access Token role mixin for ActiveRecord.
|
|
5
|
+
# Includes all the required API, associations, validations and callbacks.
|
|
6
|
+
module AccessToken
|
|
7
|
+
extend ActiveSupport::Concern
|
|
8
|
+
|
|
9
|
+
included do
|
|
10
|
+
belongs_to :client, class_name: Grape::OAuth2.config.client_class_name,
|
|
11
|
+
foreign_key: :client_id
|
|
12
|
+
|
|
13
|
+
belongs_to :resource_owner, class_name: Grape::OAuth2.config.resource_owner_class_name,
|
|
14
|
+
foreign_key: :resource_owner_id
|
|
15
|
+
|
|
16
|
+
validates :token, presence: true, uniqueness: true
|
|
17
|
+
|
|
18
|
+
before_validation :setup_expiration, on: :create
|
|
19
|
+
before_validation :generate_tokens, on: :create
|
|
20
|
+
|
|
21
|
+
class << self
|
|
22
|
+
def create_for(client, resource_owner, scopes = nil)
|
|
23
|
+
create(
|
|
24
|
+
client: client,
|
|
25
|
+
resource_owner: resource_owner,
|
|
26
|
+
scopes: scopes.to_s
|
|
27
|
+
)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def authenticate(token, type: :access_token)
|
|
31
|
+
if type && type.to_sym == :refresh_token
|
|
32
|
+
find_by(refresh_token: token.to_s)
|
|
33
|
+
else
|
|
34
|
+
find_by(token: token.to_s)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def expired?
|
|
40
|
+
!expires_at.nil? && Time.now.utc > expires_at
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def revoked?
|
|
44
|
+
!revoked_at.nil? && revoked_at <= Time.now.utc
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def revoke!(revoked_at = Time.now)
|
|
48
|
+
update_column :revoked_at, revoked_at.utc
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def to_bearer_token
|
|
52
|
+
{
|
|
53
|
+
access_token: token,
|
|
54
|
+
expires_in: expires_at && Grape::OAuth2.config.access_token_lifetime.to_i,
|
|
55
|
+
refresh_token: refresh_token,
|
|
56
|
+
scope: scopes
|
|
57
|
+
}
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
protected
|
|
61
|
+
|
|
62
|
+
def generate_tokens
|
|
63
|
+
self.token = Grape::OAuth2.config.token_generator.generate(attributes) if token.blank?
|
|
64
|
+
self.refresh_token = Grape::OAuth2::UniqueToken.generate if Grape::OAuth2.config.issue_refresh_token
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def setup_expiration
|
|
68
|
+
expires_in = Grape::OAuth2.config.access_token_lifetime
|
|
69
|
+
self.expires_at = Time.now + expires_in if expires_at.nil? && !expires_in.nil?
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|