doorkeeper 5.0.0.rc1 → 5.0.0.rc2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of doorkeeper might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.gitlab-ci.yml +16 -0
- data/NEWS.md +23 -2
- data/README.md +7 -6
- data/UPGRADE.md +2 -0
- data/app/controllers/doorkeeper/authorizations_controller.rb +1 -1
- data/app/controllers/doorkeeper/authorized_applications_controller.rb +4 -1
- data/app/controllers/doorkeeper/tokens_controller.rb +9 -10
- data/app/views/doorkeeper/applications/index.html.erb +1 -1
- data/config/locales/en.yml +1 -0
- data/doorkeeper.gemspec +1 -1
- data/gemfiles/rails_master.gemfile +4 -1
- data/lib/doorkeeper.rb +15 -0
- data/lib/doorkeeper/config.rb +18 -5
- data/lib/doorkeeper/models/access_grant_mixin.rb +15 -0
- data/lib/doorkeeper/models/access_token_mixin.rb +2 -2
- data/lib/doorkeeper/oauth/authorization/token.rb +26 -19
- data/lib/doorkeeper/oauth/base_request.rb +3 -2
- data/lib/doorkeeper/oauth/client.rb +0 -2
- data/lib/doorkeeper/oauth/client_credentials/issuer.rb +2 -4
- data/lib/doorkeeper/oauth/client_credentials/validation.rb +0 -4
- data/lib/doorkeeper/oauth/client_credentials_request.rb +0 -4
- data/lib/doorkeeper/oauth/refresh_token_request.rb +2 -2
- data/lib/doorkeeper/orm/active_record/application.rb +11 -0
- data/lib/doorkeeper/request.rb +0 -7
- data/lib/doorkeeper/request/authorization_code.rb +0 -2
- data/lib/doorkeeper/request/client_credentials.rb +0 -2
- data/lib/doorkeeper/request/code.rb +0 -2
- data/lib/doorkeeper/request/password.rb +0 -2
- data/lib/doorkeeper/request/refresh_token.rb +0 -2
- data/lib/doorkeeper/request/token.rb +0 -2
- data/lib/doorkeeper/version.rb +1 -1
- data/lib/generators/doorkeeper/templates/initializer.rb +18 -4
- data/spec/controllers/authorizations_controller_spec.rb +27 -0
- data/spec/controllers/tokens_controller_spec.rb +59 -7
- data/spec/dummy/config/initializers/doorkeeper.rb +5 -1
- data/spec/lib/config_spec.rb +29 -0
- data/spec/lib/oauth/base_request_spec.rb +24 -0
- data/spec/models/doorkeeper/access_grant_spec.rb +43 -0
- data/spec/models/doorkeeper/access_token_spec.rb +16 -6
- data/spec/models/doorkeeper/application_spec.rb +13 -0
- data/spec/requests/applications/applications_request_spec.rb +45 -0
- data/spec/support/helpers/request_spec_helper.rb +8 -0
- metadata +8 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f9a6bf0cb64c84923dedcc19d31136a03cb7fab0
|
4
|
+
data.tar.gz: ee93150982920fc8fb654b2e447d755e42191d9c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d66636e7818c25feab19f577ee2d344f0fac658906253c18c33e884ff063bc75f0461aa0a2ddb6305404501d58b321916fc64d48be5da4917e0fe1bfb1f1c600
|
7
|
+
data.tar.gz: f439482a6a560f1e70453e0a69fd1b468c640f2287fe0d2e5a90fad315214eeef01731235931d57aba3ed29ac85eaed2165e6e072a8c9e5b3792f2c4b7cc4392
|
data/.gitlab-ci.yml
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
dependency_scanning:
|
2
|
+
image: docker:stable
|
3
|
+
variables:
|
4
|
+
DOCKER_DRIVER: overlay2
|
5
|
+
allow_failure: true
|
6
|
+
services:
|
7
|
+
- docker:stable-dind
|
8
|
+
script:
|
9
|
+
- export SP_VERSION=$(echo "$CI_SERVER_VERSION" | sed 's/^\([0-9]*\)\.\([0-9]*\).*/\1-\2-stable/')
|
10
|
+
- docker run
|
11
|
+
--env DEP_SCAN_DISABLE_REMOTE_CHECKS="${DEP_SCAN_DISABLE_REMOTE_CHECKS:-false}"
|
12
|
+
--volume "$PWD:/code"
|
13
|
+
--volume /var/run/docker.sock:/var/run/docker.sock
|
14
|
+
"registry.gitlab.com/gitlab-org/security-products/dependency-scanning:$SP_VERSION" /code
|
15
|
+
artifacts:
|
16
|
+
paths: [gl-dependency-scanning-report.json]
|
data/NEWS.md
CHANGED
@@ -6,12 +6,29 @@ upgrade guides.
|
|
6
6
|
User-visible changes worth mentioning.
|
7
7
|
|
8
8
|
## master
|
9
|
+
|
10
|
+
- [#] Add description here
|
11
|
+
|
12
|
+
## 5.0.0.rc2
|
13
|
+
|
14
|
+
- [#1106] Restrict access to AdminController with 'Forbidden 403' if admin_authenticator is not
|
15
|
+
configured by developers..
|
16
|
+
- [#1108] Simple formating of callback URLs when listing oauth applications
|
17
|
+
- [#1116] `AccessGrant`s will now be revoked along with `AccessToken`s when
|
18
|
+
hitting the `AuthorizedApplicationController#destroy` route.
|
19
|
+
- [#1114] Make token info endpoint's attributes consistent with token creation
|
20
|
+
- [#1119] Fix token revocation for OAuth apps using "implicit" grant flow
|
21
|
+
- [#1122] Fix AuthorizationsController#new error response to be in JSON format
|
22
|
+
|
23
|
+
## 5.0.0.rc1
|
24
|
+
|
25
|
+
- [#1103] Allow customizing use_refresh_token
|
9
26
|
- [#1089] Removed enable_pkce_without_secret configuration option
|
10
27
|
- [#1102] Expiration time based on scopes
|
11
28
|
- [#1099] All the configuration variables in `Doorkeeper.configuration` now
|
12
|
-
|
29
|
+
always return a non-nil value (`true` or `false`)
|
13
30
|
- [#1099] ORM / Query optimization: Do not revoke the refresh token if it is not enabled
|
14
|
-
|
31
|
+
in `doorkeeper.rb`
|
15
32
|
- [#996] Expiration Time Base On Grant Type
|
16
33
|
- [#997] Allow PKCE authorization_code flow as specified in RFC7636
|
17
34
|
- [#907] Fix lookup for matching tokens in certain edge-cases
|
@@ -39,6 +56,10 @@ User-visible changes worth mentioning.
|
|
39
56
|
- [#1076] Add config to enforce content type to application/x-www-form-urlencoded
|
40
57
|
- Fix bug with `force_ssl_in_redirect_uri` when it breaks existing applications with an
|
41
58
|
SSL redirect_uri.
|
59
|
+
|
60
|
+
## 4.4.0
|
61
|
+
|
62
|
+
- [#1120] Backport security fix from 5.x for token revocation when using public clients
|
42
63
|
|
43
64
|
## 4.3.2
|
44
65
|
|
data/README.md
CHANGED
@@ -1,14 +1,13 @@
|
|
1
|
-
# Doorkeeper
|
1
|
+
# Doorkeeper — awesome OAuth 2 provider for your Rails / Grape app.
|
2
2
|
|
3
3
|
[![Gem Version](https://badge.fury.io/rb/doorkeeper.svg)](https://rubygems.org/gems/doorkeeper)
|
4
4
|
[![Build Status](https://travis-ci.org/doorkeeper-gem/doorkeeper.svg?branch=master)](https://travis-ci.org/doorkeeper-gem/doorkeeper)
|
5
|
-
[![Dependency Status](https://gemnasium.com/doorkeeper-gem/doorkeeper.svg?travis)](https://gemnasium.com/doorkeeper-gem/doorkeeper)
|
6
5
|
[![Code Climate](https://codeclimate.com/github/doorkeeper-gem/doorkeeper.svg)](https://codeclimate.com/github/doorkeeper-gem/doorkeeper)
|
7
6
|
[![Coverage Status](https://coveralls.io/repos/github/doorkeeper-gem/doorkeeper/badge.svg?branch=master)](https://coveralls.io/github/doorkeeper-gem/doorkeeper?branch=master)
|
8
7
|
[![Security](https://hakiri.io/github/doorkeeper-gem/doorkeeper/master.svg)](https://hakiri.io/github/doorkeeper-gem/doorkeeper/master)
|
9
8
|
|
10
|
-
Doorkeeper is a gem that makes it easy to introduce OAuth 2 provider
|
11
|
-
functionality to your Rails or Grape application.
|
9
|
+
Doorkeeper is a gem (Rails engine) that makes it easy to introduce OAuth 2 provider
|
10
|
+
functionality to your Ruby on Rails or Grape application.
|
12
11
|
|
13
12
|
Supported features:
|
14
13
|
|
@@ -28,7 +27,7 @@ Supported features:
|
|
28
27
|
Please check the documentation for the version of doorkeeper you are using in:
|
29
28
|
https://github.com/doorkeeper-gem/doorkeeper/releases
|
30
29
|
|
31
|
-
- See the [
|
30
|
+
- See the [Wiki](https://github.com/doorkeeper-gem/doorkeeper/wiki)
|
32
31
|
- See [upgrade guides](https://github.com/doorkeeper-gem/doorkeeper/wiki/Migration-from-old-versions)
|
33
32
|
- For general questions, please post in [Stack Overflow](http://stackoverflow.com/questions/tagged/doorkeeper)
|
34
33
|
- See [SECURITY.md](SECURITY.md) for this project's security disclose
|
@@ -276,7 +275,9 @@ protect. For example:
|
|
276
275
|
|
277
276
|
``` ruby
|
278
277
|
class Api::V1::ProductsController < Api::V1::ApiController
|
279
|
-
before_action :doorkeeper_authorize! #
|
278
|
+
before_action :doorkeeper_authorize! # Requires access token for all actions
|
279
|
+
|
280
|
+
# before_action -> { doorkeeper_authorize! :read, :write }
|
280
281
|
|
281
282
|
# your actions
|
282
283
|
end
|
data/UPGRADE.md
ADDED
@@ -56,16 +56,15 @@ module Doorkeeper
|
|
56
56
|
# https://tools.ietf.org/html/rfc6749#section-2.1
|
57
57
|
# https://tools.ietf.org/html/rfc7009
|
58
58
|
def authorized?
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
end
|
59
|
+
return unless token.present?
|
60
|
+
# Client is confidential, therefore client authentication & authorization
|
61
|
+
# is required
|
62
|
+
if token.application_id? && token.application.confidential?
|
63
|
+
# We authorize client by checking token's application
|
64
|
+
server.client && server.client.application == token.application
|
65
|
+
else
|
66
|
+
# Client is public, authentication unnecessary
|
67
|
+
true
|
69
68
|
end
|
70
69
|
end
|
71
70
|
|
@@ -21,7 +21,7 @@
|
|
21
21
|
<%= link_to application.name, oauth_application_path(application) %>
|
22
22
|
</td>
|
23
23
|
<td class="align-middle">
|
24
|
-
<%= application.redirect_uri %>
|
24
|
+
<%= simple_format(application.redirect_uri) %>
|
25
25
|
</td>
|
26
26
|
<td class="align-middle">
|
27
27
|
<%= application.confidential? ? t('doorkeeper.applications.index.confidentiality.yes') : t('doorkeeper.applications.index.confidentiality.no') %>
|
data/config/locales/en.yml
CHANGED
@@ -99,6 +99,7 @@ en:
|
|
99
99
|
# Configuration error messages
|
100
100
|
credential_flow_not_configured: 'Resource Owner Password Credentials flow failed due to Doorkeeper.configure.resource_owner_from_credentials being unconfigured.'
|
101
101
|
resource_owner_authenticator_not_configured: 'Resource Owner find failed due to Doorkeeper.configure.resource_owner_authenticator being unconfigured.'
|
102
|
+
admin_authenticator_not_configured: 'Access to admin panel is forbidden due to Doorkeeper.configure.admin_authenticator being unconfigured.'
|
102
103
|
|
103
104
|
# Access grant errors
|
104
105
|
unsupported_response_type: 'The authorization server does not support this response type.'
|
data/doorkeeper.gemspec
CHANGED
@@ -19,7 +19,7 @@ Gem::Specification.new do |s|
|
|
19
19
|
s.add_dependency "railties", ">= 4.2"
|
20
20
|
s.required_ruby_version = ">= 2.1"
|
21
21
|
|
22
|
-
s.add_development_dependency "capybara"
|
22
|
+
s.add_development_dependency "capybara", '~> 2.18'
|
23
23
|
s.add_development_dependency "coveralls"
|
24
24
|
s.add_development_dependency "grape"
|
25
25
|
s.add_development_dependency "database_cleaner", "~> 1.6"
|
@@ -9,6 +9,9 @@ gem "appraisal"
|
|
9
9
|
gem "activerecord-jdbcsqlite3-adapter", platform: :jruby
|
10
10
|
gem "sqlite3", platform: [:ruby, :mswin, :mingw, :x64_mingw]
|
11
11
|
gem "tzinfo-data", platforms: [:mingw, :mswin, :x64_mingw]
|
12
|
-
|
12
|
+
|
13
|
+
%w[rspec-core rspec-expectations rspec-mocks rspec-rails rspec-support].each do |lib|
|
14
|
+
gem lib, git: "https://github.com/rspec/#{lib}.git", branch: 'master'
|
15
|
+
end
|
13
16
|
|
14
17
|
gemspec path: "../"
|
data/lib/doorkeeper.rb
CHANGED
@@ -2,6 +2,14 @@ require 'doorkeeper/version'
|
|
2
2
|
require 'doorkeeper/engine'
|
3
3
|
require 'doorkeeper/config'
|
4
4
|
|
5
|
+
require 'doorkeeper/request/strategy'
|
6
|
+
require 'doorkeeper/request/authorization_code'
|
7
|
+
require 'doorkeeper/request/client_credentials'
|
8
|
+
require 'doorkeeper/request/code'
|
9
|
+
require 'doorkeeper/request/password'
|
10
|
+
require 'doorkeeper/request/refresh_token'
|
11
|
+
require 'doorkeeper/request/token'
|
12
|
+
|
5
13
|
require 'doorkeeper/errors'
|
6
14
|
require 'doorkeeper/server'
|
7
15
|
require 'doorkeeper/request'
|
@@ -27,6 +35,13 @@ require 'doorkeeper/oauth/base_request'
|
|
27
35
|
require 'doorkeeper/oauth/authorization_code_request'
|
28
36
|
require 'doorkeeper/oauth/refresh_token_request'
|
29
37
|
require 'doorkeeper/oauth/password_access_token_request'
|
38
|
+
|
39
|
+
require 'doorkeeper/oauth/client_credentials/validation'
|
40
|
+
require 'doorkeeper/oauth/client_credentials/creator'
|
41
|
+
require 'doorkeeper/oauth/client_credentials/issuer'
|
42
|
+
require 'doorkeeper/oauth/client_credentials/validation'
|
43
|
+
require 'doorkeeper/oauth/client/credentials'
|
44
|
+
|
30
45
|
require 'doorkeeper/oauth/client_credentials_request'
|
31
46
|
require 'doorkeeper/oauth/code_request'
|
32
47
|
require 'doorkeeper/oauth/token_request'
|
data/lib/doorkeeper/config.rb
CHANGED
@@ -103,9 +103,12 @@ module Doorkeeper
|
|
103
103
|
@config.instance_variable_set(:@access_token_methods, methods)
|
104
104
|
end
|
105
105
|
|
106
|
-
# Issue access tokens with refresh token (disabled
|
107
|
-
def use_refresh_token
|
108
|
-
@config.instance_variable_set(
|
106
|
+
# Issue access tokens with refresh token (disabled if not set)
|
107
|
+
def use_refresh_token(enabled = true, &block)
|
108
|
+
@config.instance_variable_set(
|
109
|
+
:@refresh_token_enabled,
|
110
|
+
block ? block : enabled
|
111
|
+
)
|
109
112
|
end
|
110
113
|
|
111
114
|
# Reuse access token for the same resource owner within an application
|
@@ -207,7 +210,13 @@ module Doorkeeper
|
|
207
210
|
|
208
211
|
option :admin_authenticator,
|
209
212
|
as: :authenticate_admin,
|
210
|
-
default:
|
213
|
+
default: (lambda do |_routes|
|
214
|
+
::Rails.logger.warn(
|
215
|
+
I18n.t('doorkeeper.errors.messages.admin_authenticator_not_configured')
|
216
|
+
)
|
217
|
+
|
218
|
+
head :forbidden
|
219
|
+
end)
|
211
220
|
|
212
221
|
option :resource_owner_from_credentials,
|
213
222
|
default: (lambda do |_routes|
|
@@ -289,7 +298,11 @@ module Doorkeeper
|
|
289
298
|
end
|
290
299
|
|
291
300
|
def refresh_token_enabled?
|
292
|
-
|
301
|
+
if defined?(@refresh_token_enabled)
|
302
|
+
@refresh_token_enabled
|
303
|
+
else
|
304
|
+
false
|
305
|
+
end
|
293
306
|
end
|
294
307
|
|
295
308
|
def enforce_configured_scopes?
|
@@ -31,6 +31,21 @@ module Doorkeeper
|
|
31
31
|
find_by(token: token.to_s)
|
32
32
|
end
|
33
33
|
|
34
|
+
# Revokes AccessGrant records that have not been revoked and associated
|
35
|
+
# with the specific Application and Resource Owner.
|
36
|
+
#
|
37
|
+
# @param application_id [Integer]
|
38
|
+
# ID of the Application
|
39
|
+
# @param resource_owner [ActiveRecord::Base]
|
40
|
+
# instance of the Resource Owner model
|
41
|
+
#
|
42
|
+
def revoke_all_for(application_id, resource_owner, clock = Time)
|
43
|
+
where(application_id: application_id,
|
44
|
+
resource_owner_id: resource_owner.id,
|
45
|
+
revoked_at: nil).
|
46
|
+
update_all(revoked_at: clock.now.utc)
|
47
|
+
end
|
48
|
+
|
34
49
|
# Implements PKCE code_challenge encoding without base64 padding as described in the spec.
|
35
50
|
# https://tools.ietf.org/html/rfc7636#appendix-A
|
36
51
|
# Appendix A. Notes on Implementing Base64url Encoding without Padding
|
@@ -187,8 +187,8 @@ module Doorkeeper
|
|
187
187
|
def as_json(_options = {})
|
188
188
|
{
|
189
189
|
resource_owner_id: resource_owner_id,
|
190
|
-
|
191
|
-
|
190
|
+
scope: scopes,
|
191
|
+
expires_in: expires_in_seconds,
|
192
192
|
application: { uid: application.try(:uid) },
|
193
193
|
created_at: created_at.to_i
|
194
194
|
}
|
@@ -5,30 +5,37 @@ module Doorkeeper
|
|
5
5
|
attr_accessor :pre_auth, :resource_owner, :token
|
6
6
|
|
7
7
|
class << self
|
8
|
-
def
|
9
|
-
if (expiration = custom_expiration(server, pre_auth_or_oauth_client, grant_type, scopes))
|
10
|
-
expiration
|
11
|
-
else
|
12
|
-
server.access_token_expires_in
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
private
|
17
|
-
|
18
|
-
def custom_expiration(server, pre_auth_or_oauth_client, grant_type, scopes)
|
8
|
+
def build_context(pre_auth_or_oauth_client, grant_type, scopes)
|
19
9
|
oauth_client = if pre_auth_or_oauth_client.respond_to?(:client)
|
20
10
|
pre_auth_or_oauth_client.client
|
21
11
|
else
|
22
12
|
pre_auth_or_oauth_client
|
23
13
|
end
|
24
|
-
|
14
|
+
|
15
|
+
Doorkeeper::OAuth::Authorization::Context.new(
|
25
16
|
oauth_client,
|
26
17
|
grant_type,
|
27
18
|
scopes
|
28
19
|
)
|
20
|
+
end
|
21
|
+
|
22
|
+
def access_token_expires_in(server, context)
|
23
|
+
if (expiration = server.custom_access_token_expires_in.call(context))
|
24
|
+
expiration
|
25
|
+
else
|
26
|
+
server.access_token_expires_in
|
27
|
+
end
|
28
|
+
end
|
29
29
|
|
30
|
-
|
30
|
+
def refresh_token_enabled?(server, context)
|
31
|
+
if server.refresh_token_enabled?.respond_to? :call
|
32
|
+
server.refresh_token_enabled?.call(context)
|
33
|
+
else
|
34
|
+
!!server.refresh_token_enabled?
|
35
|
+
end
|
31
36
|
end
|
37
|
+
|
38
|
+
private
|
32
39
|
end
|
33
40
|
|
34
41
|
def initialize(pre_auth, resource_owner)
|
@@ -37,16 +44,16 @@ module Doorkeeper
|
|
37
44
|
end
|
38
45
|
|
39
46
|
def issue_token
|
47
|
+
context = self.class.build_context(
|
48
|
+
pre_auth.client,
|
49
|
+
Doorkeeper::OAuth::IMPLICIT,
|
50
|
+
pre_auth.scopes
|
51
|
+
)
|
40
52
|
@token ||= AccessToken.find_or_create_for(
|
41
53
|
pre_auth.client,
|
42
54
|
resource_owner.id,
|
43
55
|
pre_auth.scopes,
|
44
|
-
self.class.access_token_expires_in(
|
45
|
-
configuration,
|
46
|
-
pre_auth,
|
47
|
-
Doorkeeper::OAuth::IMPLICIT,
|
48
|
-
pre_auth.scopes
|
49
|
-
),
|
56
|
+
self.class.access_token_expires_in(configuration, context),
|
50
57
|
false
|
51
58
|
)
|
52
59
|
end
|
@@ -31,12 +31,13 @@ module Doorkeeper
|
|
31
31
|
end
|
32
32
|
|
33
33
|
def find_or_create_access_token(client, resource_owner_id, scopes, server)
|
34
|
+
context = Authorization::Token.build_context(client, grant_type, scopes)
|
34
35
|
@access_token = AccessToken.find_or_create_for(
|
35
36
|
client,
|
36
37
|
resource_owner_id,
|
37
38
|
scopes,
|
38
|
-
Authorization::Token.access_token_expires_in(server,
|
39
|
-
|
39
|
+
Authorization::Token.access_token_expires_in(server, context),
|
40
|
+
Authorization::Token.refresh_token_enabled?(server, context)
|
40
41
|
)
|
41
42
|
end
|
42
43
|
|
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'doorkeeper/oauth/client_credentials/validation'
|
2
|
-
|
3
1
|
module Doorkeeper
|
4
2
|
module OAuth
|
5
3
|
class ClientCredentialsRequest < BaseRequest
|
@@ -25,12 +23,12 @@ module Doorkeeper
|
|
25
23
|
private
|
26
24
|
|
27
25
|
def create_token(client, scopes, creator)
|
28
|
-
|
29
|
-
@server,
|
26
|
+
context = Authorization::Token.build_context(
|
30
27
|
client,
|
31
28
|
Doorkeeper::OAuth::CLIENT_CREDENTIALS,
|
32
29
|
scopes
|
33
30
|
)
|
31
|
+
ttl = Authorization::Token.access_token_expires_in(@server, context)
|
34
32
|
|
35
33
|
creator.call(
|
36
34
|
client,
|
@@ -65,12 +65,12 @@ module Doorkeeper
|
|
65
65
|
end
|
66
66
|
|
67
67
|
def access_token_expires_in
|
68
|
-
Authorization::Token.
|
69
|
-
server,
|
68
|
+
context = Authorization::Token.build_context(
|
70
69
|
client,
|
71
70
|
Doorkeeper::OAuth::REFRESH_TOKEN,
|
72
71
|
scopes
|
73
72
|
)
|
73
|
+
Authorization::Token.access_token_expires_in(server, context)
|
74
74
|
end
|
75
75
|
|
76
76
|
def validate_token_presence
|
@@ -34,6 +34,17 @@ module Doorkeeper
|
|
34
34
|
where(id: resource_access_tokens.select(:application_id).distinct)
|
35
35
|
end
|
36
36
|
|
37
|
+
# Revokes AccessToken and AccessGrant records that have not been revoked and
|
38
|
+
# associated with the specific Application and Resource Owner.
|
39
|
+
#
|
40
|
+
# @param resource_owner [ActiveRecord::Base]
|
41
|
+
# instance of the Resource Owner model
|
42
|
+
#
|
43
|
+
def self.revoke_tokens_and_grants_for(id, resource_owner)
|
44
|
+
AccessToken.revoke_all_for(id, resource_owner)
|
45
|
+
AccessGrant.revoke_all_for(id, resource_owner)
|
46
|
+
end
|
47
|
+
|
37
48
|
private
|
38
49
|
|
39
50
|
def generate_uid
|
data/lib/doorkeeper/request.rb
CHANGED
@@ -1,10 +1,3 @@
|
|
1
|
-
require 'doorkeeper/request/authorization_code'
|
2
|
-
require 'doorkeeper/request/client_credentials'
|
3
|
-
require 'doorkeeper/request/code'
|
4
|
-
require 'doorkeeper/request/password'
|
5
|
-
require 'doorkeeper/request/refresh_token'
|
6
|
-
require 'doorkeeper/request/token'
|
7
|
-
|
8
1
|
module Doorkeeper
|
9
2
|
module Request
|
10
3
|
class << self
|
data/lib/doorkeeper/version.rb
CHANGED
@@ -10,13 +10,20 @@ Doorkeeper.configure do
|
|
10
10
|
# User.find_by_id(session[:user_id]) || redirect_to(new_user_session_url)
|
11
11
|
end
|
12
12
|
|
13
|
-
# If you
|
14
|
-
# you need to declare
|
13
|
+
# If you didn't skip applications controller from Doorkeeper routes in your application routes.rb
|
14
|
+
# file then you need to declare this block in order to restrict access to the web interface for
|
15
|
+
# adding oauth authorized applications. In other case it will return 403 Forbidden response
|
16
|
+
# every time somebody will try to access the admin web interface.
|
15
17
|
#
|
16
18
|
# admin_authenticator do
|
17
19
|
# # Put your admin authentication logic here.
|
18
20
|
# # Example implementation:
|
19
|
-
#
|
21
|
+
#
|
22
|
+
# if current_user
|
23
|
+
# head :forbidden unless current_user.admin?
|
24
|
+
# else
|
25
|
+
# redirect_to sign_in_url
|
26
|
+
# end
|
20
27
|
# end
|
21
28
|
|
22
29
|
# If you are planning to use Doorkeeper in Rails 5 API-only application, then you might
|
@@ -66,7 +73,14 @@ Doorkeeper.configure do
|
|
66
73
|
#
|
67
74
|
# reuse_access_token
|
68
75
|
|
69
|
-
# Issue access tokens with refresh token (disabled by default)
|
76
|
+
# Issue access tokens with refresh token (disabled by default), you may also
|
77
|
+
# pass a block which accepts `context` to customize when to give a refresh
|
78
|
+
# token or not. Similar to `custom_access_token_expires_in`, `context` has
|
79
|
+
# the properties:
|
80
|
+
#
|
81
|
+
# `client` - the OAuth client application (see Doorkeeper::OAuth::Client)
|
82
|
+
# `grant_type` - the grant type of the request (see Doorkeeper::OAuth)
|
83
|
+
# `scopes` - the requested scopes (see Doorkeeper::OAuth::Scopes)
|
70
84
|
#
|
71
85
|
# use_refresh_token
|
72
86
|
|
@@ -387,6 +387,33 @@ describe Doorkeeper::AuthorizationsController, 'implicit grant flow' do
|
|
387
387
|
end
|
388
388
|
end
|
389
389
|
|
390
|
+
describe 'GET #new in API mode with errors' do
|
391
|
+
let(:response_json_body) { JSON.parse(response.body) }
|
392
|
+
|
393
|
+
before do
|
394
|
+
default_scopes_exist :public
|
395
|
+
allow(Doorkeeper.configuration).to receive(:api_only).and_return(true)
|
396
|
+
get :new, params: { an_invalid: 'request' }
|
397
|
+
end
|
398
|
+
|
399
|
+
it 'should render bad request' do
|
400
|
+
expect(response).to have_http_status(:bad_request)
|
401
|
+
end
|
402
|
+
|
403
|
+
it 'includes error in body' do
|
404
|
+
expect(response_json_body['error']).to eq('unsupported_response_type')
|
405
|
+
end
|
406
|
+
|
407
|
+
it 'includes error description in body' do
|
408
|
+
expect(response_json_body['error_description']).to eq(translated_error_message(:unsupported_response_type))
|
409
|
+
end
|
410
|
+
|
411
|
+
it 'does not issue any token' do
|
412
|
+
expect(Doorkeeper::AccessGrant.count).to eq 0
|
413
|
+
expect(Doorkeeper::AccessToken.count).to eq 0
|
414
|
+
end
|
415
|
+
end
|
416
|
+
|
390
417
|
describe 'GET #new with callbacks' do
|
391
418
|
after do
|
392
419
|
client.update_attribute :redirect_uri, 'urn:ietf:wg:oauth:2.0:oob'
|
@@ -56,15 +56,67 @@ describe Doorkeeper::TokensController do
|
|
56
56
|
end
|
57
57
|
end
|
58
58
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
59
|
+
# http://tools.ietf.org/html/rfc7009#section-2.2
|
60
|
+
describe 'revoking tokens' do
|
61
|
+
let(:client) { FactoryBot.create(:application) }
|
62
|
+
let(:access_token) { FactoryBot.create(:access_token, application: client) }
|
63
|
+
|
64
|
+
before(:each) do
|
65
|
+
allow(controller).to receive(:token) { access_token }
|
66
|
+
end
|
67
|
+
|
68
|
+
context 'when associated app is public' do
|
69
|
+
let(:client) { FactoryBot.create(:application, confidential: false) }
|
70
|
+
|
71
|
+
it 'returns 200' do
|
72
|
+
post :revoke
|
73
|
+
|
74
|
+
expect(response.status).to eq 200
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'revokes the access token' do
|
78
|
+
post :revoke
|
79
|
+
|
80
|
+
expect(access_token.reload).to have_attributes(revoked?: true)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
context 'when associated app is confidential' do
|
85
|
+
let(:client) { FactoryBot.create(:application, confidential: true) }
|
86
|
+
let(:oauth_client) { Doorkeeper::OAuth::Client.new(client) }
|
64
87
|
|
65
|
-
|
88
|
+
before(:each) do
|
89
|
+
allow_any_instance_of(Doorkeeper::Server).to receive(:client) { oauth_client }
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'returns 200' do
|
93
|
+
post :revoke
|
94
|
+
|
95
|
+
expect(response.status).to eq 200
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'revokes the access token' do
|
99
|
+
post :revoke
|
100
|
+
|
101
|
+
expect(access_token.reload).to have_attributes(revoked?: true)
|
102
|
+
end
|
103
|
+
|
104
|
+
context 'when authorization fails' do
|
105
|
+
let(:some_other_client) { FactoryBot.create(:application, confidential: true) }
|
106
|
+
let(:oauth_client) { Doorkeeper::OAuth::Client.new(some_other_client) }
|
107
|
+
|
108
|
+
it 'returns 200' do
|
109
|
+
post :revoke
|
66
110
|
|
67
|
-
|
111
|
+
expect(response.status).to eq 200
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'does not revoke the access token' do
|
115
|
+
post :revoke
|
116
|
+
|
117
|
+
expect(access_token.reload).to have_attributes(revoked?: false)
|
118
|
+
end
|
119
|
+
end
|
68
120
|
end
|
69
121
|
end
|
70
122
|
|
@@ -8,7 +8,11 @@ Doorkeeper.configure do
|
|
8
8
|
User.where(id: session[:user_id]).first || redirect_to(root_url, alert: 'Needs sign in.')
|
9
9
|
end
|
10
10
|
|
11
|
-
# If you
|
11
|
+
# If you didn't skip applications controller from Doorkeeper routes in your application routes.rb
|
12
|
+
# file then you need to declare this block in order to restrict access to the web interface for
|
13
|
+
# adding oauth authorized applications. In other case it will return 403 Forbidden response
|
14
|
+
# every time somebody will try to access the admin web interface.
|
15
|
+
#
|
12
16
|
# admin_authenticator do
|
13
17
|
# # Put your admin authentication logic here.
|
14
18
|
# # Example implementation:
|
data/spec/lib/config_spec.rb
CHANGED
@@ -66,6 +66,17 @@ describe Doorkeeper, 'configuration' do
|
|
66
66
|
end
|
67
67
|
|
68
68
|
describe 'admin_authenticator' do
|
69
|
+
it 'sets the block that is accessible via authenticate_admin' do
|
70
|
+
default_behaviour = 'default behaviour'
|
71
|
+
allow(Doorkeeper::Config).to receive(:head).and_return(default_behaviour)
|
72
|
+
|
73
|
+
Doorkeeper.configure do
|
74
|
+
orm DOORKEEPER_ORM
|
75
|
+
end
|
76
|
+
|
77
|
+
expect(subject.authenticate_admin.call({})).to eq(default_behaviour)
|
78
|
+
end
|
79
|
+
|
69
80
|
it 'sets the block that is accessible via authenticate_admin' do
|
70
81
|
block = proc {}
|
71
82
|
Doorkeeper.configure do
|
@@ -144,6 +155,24 @@ describe Doorkeeper, 'configuration' do
|
|
144
155
|
expect(subject.refresh_token_enabled?).to eq(true)
|
145
156
|
end
|
146
157
|
|
158
|
+
it 'can accept a boolean parameter' do
|
159
|
+
Doorkeeper.configure do
|
160
|
+
orm DOORKEEPER_ORM
|
161
|
+
use_refresh_token false
|
162
|
+
end
|
163
|
+
|
164
|
+
expect(subject.refresh_token_enabled?).to eq(false)
|
165
|
+
end
|
166
|
+
|
167
|
+
it 'can accept a block parameter' do
|
168
|
+
Doorkeeper.configure do
|
169
|
+
orm DOORKEEPER_ORM
|
170
|
+
use_refresh_token { |_context| nil }
|
171
|
+
end
|
172
|
+
|
173
|
+
expect(subject.refresh_token_enabled?).to be_a(Proc)
|
174
|
+
end
|
175
|
+
|
147
176
|
it "does not includes 'refresh_token' in authorization_response_types" do
|
148
177
|
expect(subject.token_grant_types).not_to include 'refresh_token'
|
149
178
|
end
|
@@ -119,6 +119,30 @@ module Doorkeeper::OAuth
|
|
119
119
|
)
|
120
120
|
expect(result.expires_in).to eql(500)
|
121
121
|
end
|
122
|
+
|
123
|
+
it "respects use_refresh_token with a block" do
|
124
|
+
server = double(:server,
|
125
|
+
access_token_expires_in: 100,
|
126
|
+
custom_access_token_expires_in: ->(_context) { nil },
|
127
|
+
refresh_token_enabled?: lambda { |context|
|
128
|
+
context.scopes == "public"
|
129
|
+
})
|
130
|
+
result = subject.find_or_create_access_token(
|
131
|
+
client,
|
132
|
+
"1",
|
133
|
+
"public",
|
134
|
+
server
|
135
|
+
)
|
136
|
+
expect(result.refresh_token).to_not be_nil
|
137
|
+
|
138
|
+
result = subject.find_or_create_access_token(
|
139
|
+
client,
|
140
|
+
"1",
|
141
|
+
"private",
|
142
|
+
server
|
143
|
+
)
|
144
|
+
expect(result.refresh_token).to be_nil
|
145
|
+
end
|
122
146
|
end
|
123
147
|
|
124
148
|
describe "#scopes" do
|
@@ -33,4 +33,47 @@ describe Doorkeeper::AccessGrant do
|
|
33
33
|
expect(subject).not_to be_valid
|
34
34
|
end
|
35
35
|
end
|
36
|
+
|
37
|
+
describe '.revoke_all_for' do
|
38
|
+
let(:resource_owner) { double(id: 100) }
|
39
|
+
let(:application) { FactoryBot.create :application }
|
40
|
+
let(:default_attributes) do
|
41
|
+
{
|
42
|
+
application: application,
|
43
|
+
resource_owner_id: resource_owner.id
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'revokes all tokens for given application and resource owner' do
|
48
|
+
FactoryBot.create :access_grant, default_attributes
|
49
|
+
|
50
|
+
described_class.revoke_all_for(application.id, resource_owner)
|
51
|
+
|
52
|
+
described_class.all.each do |token|
|
53
|
+
expect(token).to be_revoked
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'matches application' do
|
58
|
+
access_grant_for_different_app = FactoryBot.create(
|
59
|
+
:access_grant,
|
60
|
+
default_attributes.merge(application: FactoryBot.create(:application))
|
61
|
+
)
|
62
|
+
|
63
|
+
described_class.revoke_all_for(application.id, resource_owner)
|
64
|
+
|
65
|
+
expect(access_grant_for_different_app.reload).not_to be_revoked
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'matches resource owner' do
|
69
|
+
access_grant_for_different_owner = FactoryBot.create(
|
70
|
+
:access_grant,
|
71
|
+
default_attributes.merge(resource_owner_id: 90)
|
72
|
+
)
|
73
|
+
|
74
|
+
described_class.revoke_all_for application.id, resource_owner
|
75
|
+
|
76
|
+
expect(access_grant_for_different_owner.reload).not_to be_revoked
|
77
|
+
end
|
78
|
+
end
|
36
79
|
end
|
@@ -306,15 +306,25 @@ module Doorkeeper
|
|
306
306
|
end
|
307
307
|
|
308
308
|
it 'matches application' do
|
309
|
-
|
309
|
+
access_token_for_different_app = FactoryBot.create(
|
310
|
+
:access_token,
|
311
|
+
default_attributes.merge(application: FactoryBot.create(:application))
|
312
|
+
)
|
313
|
+
|
310
314
|
AccessToken.revoke_all_for application.id, resource_owner
|
311
|
-
|
315
|
+
|
316
|
+
expect(access_token_for_different_app.reload).not_to be_revoked
|
312
317
|
end
|
313
318
|
|
314
319
|
it 'matches resource owner' do
|
315
|
-
FactoryBot.create
|
320
|
+
access_token_for_different_owner = FactoryBot.create(
|
321
|
+
:access_token,
|
322
|
+
default_attributes.merge(resource_owner_id: 90)
|
323
|
+
)
|
324
|
+
|
316
325
|
AccessToken.revoke_all_for application.id, resource_owner
|
317
|
-
|
326
|
+
|
327
|
+
expect(access_token_for_different_owner.reload).not_to be_revoked
|
318
328
|
end
|
319
329
|
end
|
320
330
|
|
@@ -440,8 +450,8 @@ module Doorkeeper
|
|
440
450
|
token = FactoryBot.create :access_token
|
441
451
|
token_hash = {
|
442
452
|
resource_owner_id: token.resource_owner_id,
|
443
|
-
|
444
|
-
|
453
|
+
scope: token.scopes,
|
454
|
+
expires_in: token.expires_in_seconds,
|
445
455
|
application: { uid: token.application.uid },
|
446
456
|
created_at: token.created_at.to_i
|
447
457
|
}
|
@@ -206,6 +206,19 @@ module Doorkeeper
|
|
206
206
|
end
|
207
207
|
end
|
208
208
|
|
209
|
+
describe :revoke_tokens_and_grants_for do
|
210
|
+
it 'revokes all access tokens and access grants' do
|
211
|
+
application_id = 42
|
212
|
+
resource_owner = double
|
213
|
+
expect(Doorkeeper::AccessToken).
|
214
|
+
to receive(:revoke_all_for).with(application_id, resource_owner)
|
215
|
+
expect(Doorkeeper::AccessGrant).
|
216
|
+
to receive(:revoke_all_for).with(application_id, resource_owner)
|
217
|
+
|
218
|
+
Application.revoke_tokens_and_grants_for(application_id, resource_owner)
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
209
222
|
describe :by_uid_and_secret do
|
210
223
|
context "when application is private/confidential" do
|
211
224
|
it "finds the application via uid/secret" do
|
@@ -3,6 +3,7 @@ require 'spec_helper'
|
|
3
3
|
feature 'Adding applications' do
|
4
4
|
context 'in application form' do
|
5
5
|
background do
|
6
|
+
i_am_logged_in
|
6
7
|
visit '/oauth/applications/new'
|
7
8
|
end
|
8
9
|
|
@@ -96,12 +97,15 @@ end
|
|
96
97
|
|
97
98
|
feature 'Listing applications' do
|
98
99
|
background do
|
100
|
+
i_am_logged_in
|
101
|
+
|
99
102
|
FactoryBot.create :application, name: 'Oauth Dude'
|
100
103
|
FactoryBot.create :application, name: 'Awesome App'
|
101
104
|
end
|
102
105
|
|
103
106
|
scenario 'application list' do
|
104
107
|
visit '/oauth/applications'
|
108
|
+
|
105
109
|
i_should_see 'Awesome App'
|
106
110
|
i_should_see 'Oauth Dude'
|
107
111
|
end
|
@@ -126,11 +130,14 @@ end
|
|
126
130
|
|
127
131
|
feature 'Show application' do
|
128
132
|
given :app do
|
133
|
+
i_am_logged_in
|
134
|
+
|
129
135
|
FactoryBot.create :application, name: 'Just another oauth app'
|
130
136
|
end
|
131
137
|
|
132
138
|
scenario 'visiting application page' do
|
133
139
|
visit "/oauth/applications/#{app.id}"
|
140
|
+
|
134
141
|
i_should_see 'Just another oauth app'
|
135
142
|
end
|
136
143
|
end
|
@@ -141,12 +148,15 @@ feature 'Edit application' do
|
|
141
148
|
end
|
142
149
|
|
143
150
|
background do
|
151
|
+
i_am_logged_in
|
152
|
+
|
144
153
|
visit "/oauth/applications/#{app.id}/edit"
|
145
154
|
end
|
146
155
|
|
147
156
|
scenario 'updating a valid app' do
|
148
157
|
fill_in 'doorkeeper_application[name]', with: 'Serious app'
|
149
158
|
click_button 'Submit'
|
159
|
+
|
150
160
|
i_should_see 'Application updated'
|
151
161
|
i_should_see 'Serious app'
|
152
162
|
i_should_not_see 'OMG my app'
|
@@ -155,21 +165,27 @@ feature 'Edit application' do
|
|
155
165
|
scenario 'updating an invalid app' do
|
156
166
|
fill_in 'doorkeeper_application[name]', with: ''
|
157
167
|
click_button 'Submit'
|
168
|
+
|
158
169
|
i_should_see 'Whoops! Check your form for possible errors'
|
159
170
|
end
|
160
171
|
end
|
161
172
|
|
162
173
|
feature 'Remove application' do
|
163
174
|
background do
|
175
|
+
i_am_logged_in
|
176
|
+
|
164
177
|
@app = FactoryBot.create :application
|
165
178
|
end
|
166
179
|
|
167
180
|
scenario 'deleting an application from list' do
|
168
181
|
visit '/oauth/applications'
|
182
|
+
|
169
183
|
i_should_see @app.name
|
184
|
+
|
170
185
|
within(:css, "tr#application_#{@app.id}") do
|
171
186
|
click_button 'Destroy'
|
172
187
|
end
|
188
|
+
|
173
189
|
i_should_see 'Application deleted'
|
174
190
|
i_should_not_see @app.name
|
175
191
|
end
|
@@ -177,6 +193,35 @@ feature 'Remove application' do
|
|
177
193
|
scenario 'deleting an application from show' do
|
178
194
|
visit "/oauth/applications/#{@app.id}"
|
179
195
|
click_button 'Destroy'
|
196
|
+
|
180
197
|
i_should_see 'Application deleted'
|
181
198
|
end
|
182
199
|
end
|
200
|
+
|
201
|
+
context 'when admin authenticator block is default' do
|
202
|
+
let(:app) { FactoryBot.create :application, name: 'app' }
|
203
|
+
|
204
|
+
feature 'application list' do
|
205
|
+
scenario 'fails with forbidden' do
|
206
|
+
visit '/oauth/applications'
|
207
|
+
|
208
|
+
should_have_status 403
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
feature 'adding an app' do
|
213
|
+
scenario 'fails with forbidden' do
|
214
|
+
visit '/oauth/applications/new'
|
215
|
+
|
216
|
+
should_have_status 403
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
feature 'editing an app' do
|
221
|
+
scenario 'fails with forbidden' do
|
222
|
+
visit "/oauth/applications/#{app.id}/edit"
|
223
|
+
|
224
|
+
should_have_status 403
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
@@ -1,4 +1,8 @@
|
|
1
1
|
module RequestSpecHelper
|
2
|
+
def i_am_logged_in
|
3
|
+
allow(Doorkeeper.configuration).to receive(:authenticate_admin).and_return(->(*) {})
|
4
|
+
end
|
5
|
+
|
2
6
|
def i_should_see(content)
|
3
7
|
expect(page).to have_content(content)
|
4
8
|
end
|
@@ -39,6 +43,10 @@ module RequestSpecHelper
|
|
39
43
|
expect(headers[header]).to eq(value)
|
40
44
|
end
|
41
45
|
|
46
|
+
def should_have_status(status)
|
47
|
+
expect(page.driver.response.status).to eq(status)
|
48
|
+
end
|
49
|
+
|
42
50
|
def with_access_token_header(token)
|
43
51
|
with_header 'Authorization', "Bearer #{token}"
|
44
52
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: doorkeeper
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.0.0.
|
4
|
+
version: 5.0.0.rc2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Felipe Elias Philipp
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2018-
|
14
|
+
date: 2018-07-17 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: railties
|
@@ -31,16 +31,16 @@ dependencies:
|
|
31
31
|
name: capybara
|
32
32
|
requirement: !ruby/object:Gem::Requirement
|
33
33
|
requirements:
|
34
|
-
- - "
|
34
|
+
- - "~>"
|
35
35
|
- !ruby/object:Gem::Version
|
36
|
-
version: '
|
36
|
+
version: '2.18'
|
37
37
|
type: :development
|
38
38
|
prerelease: false
|
39
39
|
version_requirements: !ruby/object:Gem::Requirement
|
40
40
|
requirements:
|
41
|
-
- - "
|
41
|
+
- - "~>"
|
42
42
|
- !ruby/object:Gem::Version
|
43
|
-
version: '
|
43
|
+
version: '2.18'
|
44
44
|
- !ruby/object:Gem::Dependency
|
45
45
|
name: coveralls
|
46
46
|
requirement: !ruby/object:Gem::Requirement
|
@@ -150,6 +150,7 @@ files:
|
|
150
150
|
- ".github/ISSUE_TEMPLATE.md"
|
151
151
|
- ".github/PULL_REQUEST_TEMPLATE.md"
|
152
152
|
- ".gitignore"
|
153
|
+
- ".gitlab-ci.yml"
|
153
154
|
- ".hound.yml"
|
154
155
|
- ".rspec"
|
155
156
|
- ".rubocop.yml"
|
@@ -164,6 +165,7 @@ files:
|
|
164
165
|
- RELEASING.md
|
165
166
|
- Rakefile
|
166
167
|
- SECURITY.md
|
168
|
+
- UPGRADE.md
|
167
169
|
- app/assets/stylesheets/doorkeeper/admin/application.css
|
168
170
|
- app/assets/stylesheets/doorkeeper/application.css
|
169
171
|
- app/controllers/doorkeeper/application_controller.rb
|