Skip to content

Commit

Permalink
Merge pull request #1103 from thatsmydoing/configurable-refresh-token
Browse files Browse the repository at this point in the history
Implement custom use_refresh_token
  • Loading branch information
nbulaj authored Jun 9, 2018
2 parents 4174e5d + e42ee06 commit bf36149
Show file tree
Hide file tree
Showing 9 changed files with 95 additions and 30 deletions.
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ upgrade guides.
User-visible changes worth mentioning.

## master
- [#1103] Allow customizing use_refresh_token
- [#1089] Removed enable_pkce_without_secret configuration option
- [#1102] Expiration time based on scopes
- [#1099] All the configuration variables in `Doorkeeper.configuration` now
Expand Down
15 changes: 11 additions & 4 deletions lib/doorkeeper/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,12 @@ def access_token_methods(*methods)
@config.instance_variable_set(:@access_token_methods, methods)
end

# Issue access tokens with refresh token (disabled by default)
def use_refresh_token
@config.instance_variable_set(:@refresh_token_enabled, true)
# Issue access tokens with refresh token (disabled if not set)
def use_refresh_token(enabled = true, &block)
@config.instance_variable_set(
:@refresh_token_enabled,
block ? block : enabled
)
end

# Reuse access token for the same resource owner within an application
Expand Down Expand Up @@ -289,7 +292,11 @@ def enforce_content_type
end

def refresh_token_enabled?
!!(defined?(@refresh_token_enabled) && @refresh_token_enabled)
if defined?(@refresh_token_enabled)
@refresh_token_enabled
else
false
end
end

def enforce_configured_scopes?
Expand Down
45 changes: 26 additions & 19 deletions lib/doorkeeper/oauth/authorization/token.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,37 @@ class Token
attr_accessor :pre_auth, :resource_owner, :token

class << self
def access_token_expires_in(server, pre_auth_or_oauth_client, grant_type, scopes)
if (expiration = custom_expiration(server, pre_auth_or_oauth_client, grant_type, scopes))
expiration
else
server.access_token_expires_in
end
end

private

def custom_expiration(server, pre_auth_or_oauth_client, grant_type, scopes)
def build_context(pre_auth_or_oauth_client, grant_type, scopes)
oauth_client = if pre_auth_or_oauth_client.respond_to?(:client)
pre_auth_or_oauth_client.client
else
pre_auth_or_oauth_client
end
context = Doorkeeper::OAuth::Authorization::Context.new(

Doorkeeper::OAuth::Authorization::Context.new(
oauth_client,
grant_type,
scopes
)
end

def access_token_expires_in(server, context)
if (expiration = server.custom_access_token_expires_in.call(context))
expiration
else
server.access_token_expires_in
end
end

server.custom_access_token_expires_in.call(context)
def refresh_token_enabled?(server, context)
if server.refresh_token_enabled?.respond_to? :call
server.refresh_token_enabled?.call(context)
else
!!server.refresh_token_enabled?
end
end

private
end

def initialize(pre_auth, resource_owner)
Expand All @@ -37,16 +44,16 @@ def initialize(pre_auth, resource_owner)
end

def issue_token
context = self.class.build_context(
pre_auth.client,
Doorkeeper::OAuth::IMPLICIT,
pre_auth.scopes
)
@token ||= AccessToken.find_or_create_for(
pre_auth.client,
resource_owner.id,
pre_auth.scopes,
self.class.access_token_expires_in(
configuration,
pre_auth,
Doorkeeper::OAuth::IMPLICIT,
pre_auth.scopes
),
self.class.access_token_expires_in(configuration, context),
false
)
end
Expand Down
5 changes: 3 additions & 2 deletions lib/doorkeeper/oauth/base_request.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,13 @@ def valid?
end

def find_or_create_access_token(client, resource_owner_id, scopes, server)
context = Authorization::Token.build_context(client, grant_type, scopes)
@access_token = AccessToken.find_or_create_for(
client,
resource_owner_id,
scopes,
Authorization::Token.access_token_expires_in(server, client, grant_type, scopes),
server.refresh_token_enabled?
Authorization::Token.access_token_expires_in(server, context),
Authorization::Token.refresh_token_enabled?(server, context)
)
end

Expand Down
4 changes: 2 additions & 2 deletions lib/doorkeeper/oauth/client_credentials/issuer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@ def create(client, scopes, creator = Creator.new)
private

def create_token(client, scopes, creator)
ttl = Authorization::Token.access_token_expires_in(
@server,
context = Authorization::Token.build_context(
client,
Doorkeeper::OAuth::CLIENT_CREDENTIALS,
scopes
)
ttl = Authorization::Token.access_token_expires_in(@server, context)

creator.call(
client,
Expand Down
4 changes: 2 additions & 2 deletions lib/doorkeeper/oauth/refresh_token_request.rb
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,12 @@ def access_token_attributes
end

def access_token_expires_in
Authorization::Token.access_token_expires_in(
server,
context = Authorization::Token.build_context(
client,
Doorkeeper::OAuth::REFRESH_TOKEN,
scopes
)
Authorization::Token.access_token_expires_in(server, context)
end

def validate_token_presence
Expand Down
9 changes: 8 additions & 1 deletion lib/generators/doorkeeper/templates/initializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,14 @@
#
# reuse_access_token

# Issue access tokens with refresh token (disabled by default)
# Issue access tokens with refresh token (disabled by default), you may also
# pass a block which accepts `context` to customize when to give a refresh
# token or not. Similar to `custom_access_token_expires_in`, `context` has
# the properties:
#
# `client` - the OAuth client application (see Doorkeeper::OAuth::Client)
# `grant_type` - the grant type of the request (see Doorkeeper::OAuth)
# `scopes` - the requested scopes (see Doorkeeper::OAuth::Scopes)
#
# use_refresh_token

Expand Down
18 changes: 18 additions & 0 deletions spec/lib/config_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,24 @@
expect(subject.refresh_token_enabled?).to eq(true)
end

it 'can accept a boolean parameter' do
Doorkeeper.configure do
orm DOORKEEPER_ORM
use_refresh_token false
end

expect(subject.refresh_token_enabled?).to eq(false)
end

it 'can accept a block parameter' do
Doorkeeper.configure do
orm DOORKEEPER_ORM
use_refresh_token { |_context| nil }
end

expect(subject.refresh_token_enabled?).to be_a(Proc)
end

it "does not includes 'refresh_token' in authorization_response_types" do
expect(subject.token_grant_types).not_to include 'refresh_token'
end
Expand Down
24 changes: 24 additions & 0 deletions spec/lib/oauth/base_request_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,30 @@ module Doorkeeper::OAuth
)
expect(result.expires_in).to eql(500)
end

it "respects use_refresh_token with a block" do
server = double(:server,
access_token_expires_in: 100,
custom_access_token_expires_in: ->(_context) { nil },
refresh_token_enabled?: lambda { |context|
context.scopes == "public"
})
result = subject.find_or_create_access_token(
client,
"1",
"public",
server
)
expect(result.refresh_token).to_not be_nil

result = subject.find_or_create_access_token(
client,
"1",
"private",
server
)
expect(result.refresh_token).to be_nil
end
end

describe "#scopes" do
Expand Down

0 comments on commit bf36149

Please sign in to comment.