doorkeeper 0.3.4 → 0.4.0
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.
- data/CHANGELOG.md +13 -0
- data/README.md +32 -5
- data/app/controllers/doorkeeper/application_controller.rb +4 -11
- data/app/controllers/doorkeeper/authorizations_controller.rb +11 -2
- data/app/controllers/doorkeeper/tokens_controller.rb +19 -5
- data/app/models/doorkeeper/access_grant.rb +1 -8
- data/app/models/doorkeeper/access_token.rb +2 -10
- data/app/models/doorkeeper/application.rb +4 -0
- data/app/views/doorkeeper/authorizations/error.html.erb +1 -1
- data/app/views/doorkeeper/authorizations/new.html.erb +1 -1
- data/config/locales/en.yml +3 -0
- data/doorkeeper.gemspec +2 -1
- data/lib/doorkeeper.rb +23 -3
- data/lib/doorkeeper/config.rb +73 -12
- data/lib/doorkeeper/doorkeeper_for.rb +1 -1
- data/lib/doorkeeper/engine.rb +28 -0
- data/lib/doorkeeper/models/scopes.rb +13 -0
- data/lib/doorkeeper/oauth/access_token_request.rb +5 -16
- data/lib/doorkeeper/oauth/authorization/code.rb +1 -1
- data/lib/doorkeeper/oauth/authorization/token.rb +1 -1
- data/lib/doorkeeper/oauth/authorization_request.rb +18 -23
- data/lib/doorkeeper/oauth/client.rb +27 -0
- data/lib/doorkeeper/oauth/client/credentials.rb +21 -0
- data/lib/doorkeeper/oauth/client/methods.rb +18 -0
- data/lib/doorkeeper/oauth/client_credentials/creator.rb +29 -0
- data/lib/doorkeeper/oauth/client_credentials/issuer.rb +35 -0
- data/lib/doorkeeper/oauth/client_credentials/response.rb +42 -0
- data/lib/doorkeeper/oauth/client_credentials/validation.rb +33 -0
- data/lib/doorkeeper/oauth/client_credentials_request.rb +46 -0
- data/lib/doorkeeper/oauth/error.rb +9 -0
- data/lib/doorkeeper/oauth/error_response.rb +30 -0
- data/lib/doorkeeper/oauth/helpers/scope_checker.rb +2 -2
- data/lib/doorkeeper/oauth/password_access_token_request.rb +130 -0
- data/lib/doorkeeper/oauth/scopes.rb +60 -0
- data/lib/doorkeeper/version.rb +1 -1
- data/lib/generators/doorkeeper/templates/initializer.rb +10 -5
- data/lib/generators/doorkeeper/templates/migration.rb +1 -1
- data/script/run_all +11 -0
- data/spec/controllers/authorizations_controller_spec.rb +3 -3
- data/spec/controllers/protected_resources_controller_spec.rb +7 -0
- data/spec/controllers/tokens_controller_spec.rb +1 -1
- data/spec/dummy/app/controllers/home_controller.rb +1 -1
- data/spec/dummy/app/models/user.rb +9 -0
- data/spec/dummy/config/application.rb +2 -0
- data/spec/dummy/config/initializers/doorkeeper.rb +12 -5
- data/spec/dummy/config/locales/doorkeeper.en.yml +5 -0
- data/spec/dummy/db/migrate/20120312140401_add_password_to_users.rb +5 -0
- data/spec/dummy/db/migrate/{20111206151426_create_doorkeeper_tables.rb → 20120524202412_create_doorkeeper_tables.rb} +10 -1
- data/spec/dummy/db/schema.rb +15 -6
- data/spec/lib/config_spec.rb +29 -13
- data/spec/lib/models/scopes_spec.rb +32 -0
- data/spec/lib/oauth/access_token_request_spec.rb +15 -29
- data/spec/lib/oauth/authorization_request_spec.rb +22 -72
- data/spec/lib/oauth/client/credentials_spec.rb +47 -0
- data/spec/lib/oauth/client/methods_spec.rb +54 -0
- data/spec/lib/oauth/client_credentials/creator_spec.rb +47 -0
- data/spec/lib/oauth/client_credentials/issuer_spec.rb +57 -0
- data/spec/lib/oauth/client_credentials/response_spec.rb +58 -0
- data/spec/lib/oauth/client_credentials/validation_spec.rb +29 -0
- data/spec/lib/oauth/client_credentials_integration_spec.rb +27 -0
- data/spec/lib/oauth/client_credentials_request_spec.rb +60 -0
- data/spec/lib/oauth/client_spec.rb +42 -0
- data/spec/lib/oauth/error_response_spec.rb +40 -0
- data/spec/lib/oauth/error_spec.rb +19 -0
- data/spec/lib/oauth/helpers/scope_checker_spec.rb +15 -10
- data/spec/lib/oauth/password_access_token_request_spec.rb +152 -0
- data/spec/lib/oauth/scopes_spec.rb +115 -0
- data/spec/models/doorkeeper/access_grant_spec.rb +0 -15
- data/spec/models/doorkeeper/access_token_spec.rb +11 -4
- data/spec/requests/applications/authorized_applications_spec.rb +2 -2
- data/spec/requests/endpoints/authorization_spec.rb +2 -2
- data/spec/requests/endpoints/token_spec.rb +7 -0
- data/spec/requests/flows/authorization_code_errors_spec.rb +1 -1
- data/spec/requests/flows/authorization_code_spec.rb +8 -2
- data/spec/requests/flows/client_credentials_spec.rb +56 -0
- data/spec/requests/flows/password_spec.rb +52 -0
- data/spec/requests/flows/skip_authorization_spec.rb +2 -2
- data/spec/requests/protected_resources/private_api_spec.rb +9 -2
- data/spec/spec_helper_integration.rb +3 -0
- data/spec/support/helpers/authorization_request_helper.rb +7 -5
- data/spec/support/helpers/model_helper.rb +3 -3
- data/spec/support/helpers/request_spec_helper.rb +1 -1
- data/spec/support/helpers/url_helper.rb +12 -0
- metadata +65 -30
- data/lib/doorkeeper/config/scope.rb +0 -11
- data/lib/doorkeeper/config/scopes.rb +0 -61
- data/lib/doorkeeper/config/scopes_builder.rb +0 -18
- data/spec/dummy/config/initializers/inflections.rb +0 -10
- data/spec/dummy/config/initializers/mime_types.rb +0 -5
- data/spec/lib/config/scope_spec.rb +0 -45
- data/spec/lib/config/scopes_builder_spec.rb +0 -27
- data/spec/lib/config/scopes_spec.rb +0 -180
@@ -109,7 +109,7 @@ module Doorkeeper
|
|
109
109
|
|
110
110
|
def authorization_bearer_token
|
111
111
|
header = request.env['HTTP_AUTHORIZATION']
|
112
|
-
header.gsub
|
112
|
+
header.gsub(/^Bearer /, '') if header && header.match(/^Bearer /)
|
113
113
|
end
|
114
114
|
|
115
115
|
def doorkeeper_unauthorized_render_options
|
data/lib/doorkeeper/engine.rb
CHANGED
@@ -5,5 +5,33 @@ module Doorkeeper
|
|
5
5
|
config.generators do |g|
|
6
6
|
g.test_framework :rspec, :view_specs => false
|
7
7
|
end
|
8
|
+
|
9
|
+
initializer "doorkeeper.deprecations" do
|
10
|
+
if Doorkeeper.installed?
|
11
|
+
if Doorkeeper.configuration.authorization_scopes.present?
|
12
|
+
warning = <<-WARN
|
13
|
+
[DOORKEEPER]
|
14
|
+
Configuration for `authorization_scopes` will no longer be supported. Use default_scopes/optional_scopes instead.
|
15
|
+
ATTENTION: The :description option could not be migrated because doorkeeper now uses localization files.
|
16
|
+
Place this in your config/locales/en.yml
|
17
|
+
en:
|
18
|
+
doorkeeper:
|
19
|
+
scopes:
|
20
|
+
WARN
|
21
|
+
puts warning
|
22
|
+
Doorkeeper.configuration.authorization_scopes.translations.each do |scope, translation|
|
23
|
+
puts " #{scope}: #{translation}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
if Doorkeeper::AccessToken.columns_hash["resource_owner_id"].null == false
|
28
|
+
warn <<-WARN
|
29
|
+
[DOORKEEPER]
|
30
|
+
In order to use the Client Credentials flow, you have to migrate the oauth_access_tokens table:
|
31
|
+
change_column :oauth_access_tokens, :resource_owner_id, :integer, :null => true
|
32
|
+
WARN
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
8
36
|
end
|
9
37
|
end
|
@@ -3,8 +3,6 @@ module Doorkeeper::OAuth
|
|
3
3
|
include Doorkeeper::Validations
|
4
4
|
|
5
5
|
ATTRIBUTES = [
|
6
|
-
:client_id,
|
7
|
-
:client_secret,
|
8
6
|
:grant_type,
|
9
7
|
:code,
|
10
8
|
:redirect_uri,
|
@@ -18,9 +16,11 @@ module Doorkeeper::OAuth
|
|
18
16
|
validate :redirect_uri, :error => :invalid_grant
|
19
17
|
|
20
18
|
attr_accessor *ATTRIBUTES
|
19
|
+
attr_accessor :client
|
21
20
|
|
22
|
-
def initialize(attributes = {})
|
21
|
+
def initialize(client, attributes = {})
|
23
22
|
ATTRIBUTES.each { |attr| instance_variable_set("@#{attr}", attributes[attr]) }
|
23
|
+
@client = client
|
24
24
|
validate
|
25
25
|
end
|
26
26
|
|
@@ -46,7 +46,7 @@ module Doorkeeper::OAuth
|
|
46
46
|
end
|
47
47
|
|
48
48
|
def access_token
|
49
|
-
@access_token ||= Doorkeeper::AccessToken.matching_token_for client, base_token.resource_owner_id, base_token.
|
49
|
+
@access_token ||= Doorkeeper::AccessToken.matching_token_for client, base_token.resource_owner_id, base_token.scopes
|
50
50
|
end
|
51
51
|
|
52
52
|
def token_type
|
@@ -54,10 +54,7 @@ module Doorkeeper::OAuth
|
|
54
54
|
end
|
55
55
|
|
56
56
|
def error_response
|
57
|
-
|
58
|
-
'error' => error.to_s,
|
59
|
-
'error_description' => error_description
|
60
|
-
}
|
57
|
+
Doorkeeper::OAuth::ErrorResponse.from_request(self)
|
61
58
|
end
|
62
59
|
|
63
60
|
private
|
@@ -79,10 +76,6 @@ module Doorkeeper::OAuth
|
|
79
76
|
base_token.revoke
|
80
77
|
end
|
81
78
|
|
82
|
-
def client
|
83
|
-
@client ||= Doorkeeper::Application.find_by_uid_and_secret(@client_id, @client_secret)
|
84
|
-
end
|
85
|
-
|
86
79
|
def base_token
|
87
80
|
@base_token ||= refresh_token? ? token_via_refresh_token : token_via_authorization_code
|
88
81
|
end
|
@@ -139,10 +132,6 @@ module Doorkeeper::OAuth
|
|
139
132
|
%w(authorization_code refresh_token).include? grant_type
|
140
133
|
end
|
141
134
|
|
142
|
-
def error_description
|
143
|
-
I18n.translate error, :scope => [:doorkeeper, :errors, :messages]
|
144
|
-
end
|
145
|
-
|
146
135
|
def configuration
|
147
136
|
Doorkeeper.configuration
|
148
137
|
end
|
@@ -23,7 +23,7 @@ module Doorkeeper
|
|
23
23
|
@access_token ||= AccessToken.create!({
|
24
24
|
:application_id => authorization.client.id,
|
25
25
|
:resource_owner_id => authorization.resource_owner.id,
|
26
|
-
:scopes => authorization.
|
26
|
+
:scopes => authorization.scopes.to_s,
|
27
27
|
:expires_in => configuration.access_token_expires_in,
|
28
28
|
:use_refresh_token => false
|
29
29
|
})
|
@@ -6,7 +6,6 @@ module Doorkeeper::OAuth
|
|
6
6
|
|
7
7
|
ATTRIBUTES = [
|
8
8
|
:response_type,
|
9
|
-
:client_id,
|
10
9
|
:redirect_uri,
|
11
10
|
:scope,
|
12
11
|
:state
|
@@ -19,12 +18,12 @@ module Doorkeeper::OAuth
|
|
19
18
|
validate :scope, :error => :invalid_scope
|
20
19
|
|
21
20
|
attr_accessor *ATTRIBUTES
|
22
|
-
attr_accessor :resource_owner, :error
|
21
|
+
attr_accessor :resource_owner, :client, :error
|
23
22
|
|
24
|
-
def initialize(resource_owner, attributes)
|
23
|
+
def initialize(client, resource_owner, attributes)
|
25
24
|
ATTRIBUTES.each { |attr| instance_variable_set("@#{attr}", attributes[attr]) }
|
26
25
|
@resource_owner = resource_owner
|
27
|
-
@
|
26
|
+
@client = client
|
28
27
|
validate
|
29
28
|
end
|
30
29
|
|
@@ -35,44 +34,44 @@ module Doorkeeper::OAuth
|
|
35
34
|
end
|
36
35
|
|
37
36
|
def access_token_exists?
|
38
|
-
Doorkeeper::AccessToken.matching_token_for(client, resource_owner,
|
37
|
+
Doorkeeper::AccessToken.matching_token_for(client, resource_owner, scopes).present?
|
39
38
|
end
|
40
39
|
|
41
40
|
def deny
|
42
41
|
self.error = :access_denied
|
43
42
|
end
|
44
43
|
|
44
|
+
def error_response
|
45
|
+
Doorkeeper::OAuth::ErrorResponse.from_request(self)
|
46
|
+
end
|
47
|
+
|
45
48
|
def success_redirect_uri
|
46
49
|
@authorization.callback
|
47
50
|
end
|
48
51
|
|
49
52
|
def invalid_redirect_uri
|
50
53
|
uri_builder = is_token_request? ? :uri_with_fragment : :uri_with_query
|
51
|
-
send(uri_builder, redirect_uri,
|
52
|
-
:error => error,
|
53
|
-
:error_description => error_description,
|
54
|
-
:state => state
|
55
|
-
})
|
54
|
+
send(uri_builder, redirect_uri, error_response.attributes)
|
56
55
|
end
|
57
56
|
|
58
57
|
def redirect_on_error?
|
59
58
|
(error != :invalid_redirect_uri) && (error != :invalid_client)
|
60
59
|
end
|
61
60
|
|
62
|
-
def
|
63
|
-
@
|
61
|
+
def scopes
|
62
|
+
@scopes ||= if scope.present?
|
63
|
+
Doorkeeper::OAuth::Scopes.from_string(scope)
|
64
|
+
else
|
65
|
+
Doorkeeper.configuration.default_scopes
|
66
|
+
end
|
64
67
|
end
|
65
68
|
|
66
|
-
def
|
67
|
-
|
69
|
+
def client_id
|
70
|
+
client.uid
|
68
71
|
end
|
69
72
|
|
70
73
|
private
|
71
74
|
|
72
|
-
def has_scope?
|
73
|
-
Doorkeeper.configuration.scopes.all.present?
|
74
|
-
end
|
75
|
-
|
76
75
|
def validate_attributes
|
77
76
|
response_type.present?
|
78
77
|
end
|
@@ -91,7 +90,7 @@ module Doorkeeper::OAuth
|
|
91
90
|
end
|
92
91
|
|
93
92
|
def validate_scope
|
94
|
-
return true unless
|
93
|
+
return true unless scope.present?
|
95
94
|
ScopeChecker.valid?(scope, configuration.scopes)
|
96
95
|
end
|
97
96
|
|
@@ -103,10 +102,6 @@ module Doorkeeper::OAuth
|
|
103
102
|
response_type == "token"
|
104
103
|
end
|
105
104
|
|
106
|
-
def error_description
|
107
|
-
I18n.translate error, :scope => [:doorkeeper, :errors, :messages]
|
108
|
-
end
|
109
|
-
|
110
105
|
def configuration
|
111
106
|
Doorkeeper.configuration
|
112
107
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'doorkeeper/oauth/client/methods'
|
2
|
+
require 'doorkeeper/oauth/client/credentials'
|
3
|
+
|
4
|
+
module Doorkeeper
|
5
|
+
module OAuth
|
6
|
+
class Client
|
7
|
+
def self.find(uid)
|
8
|
+
if application = Doorkeeper::Application.find_by_uid(uid)
|
9
|
+
new(application)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.authenticate(credentials, method = Doorkeeper::Application.method(:authenticate))
|
14
|
+
return false if credentials.blank?
|
15
|
+
if application = method.call(credentials.uid, credentials.secret)
|
16
|
+
new(application)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
delegate :id, :name, :uid, :redirect_uri, :to => :@application
|
21
|
+
|
22
|
+
def initialize(application)
|
23
|
+
@application = application
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Doorkeeper
|
2
|
+
module OAuth
|
3
|
+
class Client
|
4
|
+
class Credentials < Struct.new(:uid, :secret)
|
5
|
+
extend Methods
|
6
|
+
|
7
|
+
def self.from_request(request, *credentials_methods)
|
8
|
+
credentials_methods.inject(nil) do |credentials, method|
|
9
|
+
method = self.method(method) if method.is_a?(Symbol)
|
10
|
+
credentials = Credentials.new *method.call(request)
|
11
|
+
break credentials unless credentials.blank?
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def blank?
|
16
|
+
uid.blank? || secret.blank?
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Doorkeeper
|
2
|
+
module OAuth
|
3
|
+
class Client
|
4
|
+
module Methods
|
5
|
+
def from_params(request)
|
6
|
+
request.parameters.values_at(:client_id, :client_secret)
|
7
|
+
end
|
8
|
+
|
9
|
+
def from_basic(request)
|
10
|
+
authorization = request.authorization
|
11
|
+
if authorization.present? && authorization =~ /^Basic (.*)/m
|
12
|
+
Base64.decode64($1).split(/:/, 2)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Doorkeeper
|
2
|
+
module OAuth
|
3
|
+
class ClientCredentialsRequest
|
4
|
+
class Creator
|
5
|
+
def call(client, scopes, attributes = {})
|
6
|
+
existing_token = existing_token_for(client, scopes)
|
7
|
+
if existing_token
|
8
|
+
return existing_token if existing_token.accessible?
|
9
|
+
existing_token.revoke
|
10
|
+
end
|
11
|
+
create(client, scopes, attributes)
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def existing_token_for(client, scopes)
|
17
|
+
Doorkeeper::AccessToken.matching_token_for client, nil, scopes
|
18
|
+
end
|
19
|
+
|
20
|
+
def create(client, scopes, attributes = {})
|
21
|
+
Doorkeeper::AccessToken.create(attributes.merge({
|
22
|
+
:application_id => client.id,
|
23
|
+
:scopes => scopes.to_s
|
24
|
+
}))
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'doorkeeper/oauth/client_credentials/validation'
|
2
|
+
|
3
|
+
module Doorkeeper
|
4
|
+
module OAuth
|
5
|
+
class ClientCredentialsRequest
|
6
|
+
class Issuer
|
7
|
+
attr_accessor :token, :validation, :error
|
8
|
+
|
9
|
+
def initialize(server, validation)
|
10
|
+
@server, @validation = server, validation
|
11
|
+
end
|
12
|
+
|
13
|
+
def create(client, scopes, creator = Creator.new)
|
14
|
+
if validation.valid?
|
15
|
+
@token = create_token(client, scopes, creator)
|
16
|
+
@error = :server_error unless @token
|
17
|
+
else
|
18
|
+
@token = false
|
19
|
+
@error = validation.error
|
20
|
+
end
|
21
|
+
@token
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def create_token(client, scopes, creator)
|
27
|
+
creator.call(client, scopes, {
|
28
|
+
:use_refresh_token => false,
|
29
|
+
:expires_in => @server.access_token_expires_in
|
30
|
+
})
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'active_model'
|
2
|
+
|
3
|
+
module Doorkeeper
|
4
|
+
module OAuth
|
5
|
+
class ClientCredentialsRequest
|
6
|
+
class Response
|
7
|
+
include ActiveModel::Serializers::JSON
|
8
|
+
|
9
|
+
self.include_root_in_json = false
|
10
|
+
|
11
|
+
delegate :token, :expires_in, :scopes_string, :to => :@token
|
12
|
+
alias :access_token :token
|
13
|
+
alias :scope :scopes_string
|
14
|
+
|
15
|
+
def initialize(token)
|
16
|
+
@token = token
|
17
|
+
end
|
18
|
+
|
19
|
+
def attributes
|
20
|
+
{
|
21
|
+
'access_token' => token,
|
22
|
+
'token_type' => token_type,
|
23
|
+
'expires_in' => expires_in,
|
24
|
+
'scope' => scopes_string
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
def status
|
29
|
+
:success
|
30
|
+
end
|
31
|
+
|
32
|
+
def token_type
|
33
|
+
'bearer'
|
34
|
+
end
|
35
|
+
|
36
|
+
def headers
|
37
|
+
{ 'Cache-Control' => 'no-store', 'Pragma' => 'no-cache' }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'doorkeeper/validations'
|
2
|
+
require 'doorkeeper/oauth/scopes'
|
3
|
+
require 'doorkeeper/oauth/helpers/scope_checker'
|
4
|
+
|
5
|
+
module Doorkeeper
|
6
|
+
module OAuth
|
7
|
+
class ClientCredentialsRequest
|
8
|
+
class Validation
|
9
|
+
include Doorkeeper::Validations
|
10
|
+
include Doorkeeper::OAuth::Helpers
|
11
|
+
|
12
|
+
validate :client, :error => :invalid_client
|
13
|
+
validate :scopes, :error => :invalid_scope
|
14
|
+
|
15
|
+
def initialize(server, request)
|
16
|
+
@server, @request = server, request
|
17
|
+
validate
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def validate_client
|
23
|
+
@request.client.present?
|
24
|
+
end
|
25
|
+
|
26
|
+
def validate_scopes
|
27
|
+
return true unless @request.original_scopes.present?
|
28
|
+
ScopeChecker.valid?(@request.original_scopes, @server.scopes)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|