doorkeeper 0.2.0 → 0.3.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/README.md +5 -1
- data/app/controllers/doorkeeper/application_controller.rb +11 -0
- data/app/controllers/doorkeeper/authorizations_controller.rb +4 -0
- data/app/controllers/doorkeeper/authorized_applications_controller.rb +1 -2
- data/app/controllers/doorkeeper/tokens_controller.rb +3 -0
- data/app/models/access_grant.rb +6 -20
- data/app/models/access_token.rb +23 -16
- data/app/models/application.rb +23 -5
- data/app/views/doorkeeper/authorizations/error.html.erb +6 -1
- data/app/views/doorkeeper/authorizations/new.html.erb +0 -2
- data/config/locales/en.yml +20 -0
- data/lib/doorkeeper.rb +10 -5
- data/lib/doorkeeper/config/scopes.rb +4 -0
- data/lib/doorkeeper/doorkeeper_for.rb +15 -20
- data/lib/doorkeeper/models/expirable.rb +18 -0
- data/lib/doorkeeper/models/revocable.rb +13 -0
- data/lib/doorkeeper/oauth/access_token_request.rb +24 -4
- data/lib/doorkeeper/oauth/authorization.rb +9 -0
- data/lib/doorkeeper/oauth/authorization/code.rb +34 -0
- data/lib/doorkeeper/oauth/authorization/token.rb +38 -0
- data/lib/doorkeeper/oauth/authorization/uri_builder.rb +27 -0
- data/lib/doorkeeper/oauth/authorization_request.rb +40 -48
- data/lib/doorkeeper/oauth/helpers/scope_checker.rb +18 -0
- data/lib/doorkeeper/oauth/helpers/unique_token.rb +16 -0
- data/lib/doorkeeper/oauth/helpers/uri_checker.rb +28 -0
- data/lib/doorkeeper/version.rb +1 -1
- data/lib/generators/doorkeeper/install_generator.rb +1 -0
- data/lib/generators/doorkeeper/templates/migration.rb +9 -0
- metadata +47 -38
- data/lib/doorkeeper/oauth/random_string.rb +0 -15
data/README.md
CHANGED
@@ -13,7 +13,7 @@ For more information about the supported features, check out the related [page i
|
|
13
13
|
Put this in your Gemfile:
|
14
14
|
|
15
15
|
``` ruby
|
16
|
-
gem 'doorkeeper'
|
16
|
+
gem 'doorkeeper', '~> 0.3.0'
|
17
17
|
```
|
18
18
|
|
19
19
|
Run the installation generator with:
|
@@ -144,6 +144,10 @@ All supported ruby versions are [listed here](https://github.com/applicake/doork
|
|
144
144
|
- Felipe Elias Philipp ([github.com/felipeelias](https://github.com/felipeelias))
|
145
145
|
- Piotr Jakubowski ([github.com/piotrj](https://github.com/piotrj))
|
146
146
|
|
147
|
+
### Contributors
|
148
|
+
|
149
|
+
Thanks to all our [awesome contributors](https://github.com/applicake/doorkeeper/contributors)!
|
150
|
+
|
147
151
|
### License
|
148
152
|
|
149
153
|
MIT License. Copyright 2011 Applicake. [http://applicake.com](http://applicake.com)
|
@@ -2,6 +2,17 @@ module Doorkeeper
|
|
2
2
|
class ApplicationController < ActionController::Base
|
3
3
|
private
|
4
4
|
|
5
|
+
def parse_client_info_from_basic_auth
|
6
|
+
auth_header = request.env['HTTP_AUTHORIZATION']
|
7
|
+
return unless auth_header && auth_header =~ /^Basic (.*)/m
|
8
|
+
client_info = Base64.decode64($1).split(/:/, 2)
|
9
|
+
client_id = client_info[0]
|
10
|
+
client_secret = client_info[1]
|
11
|
+
return if client_id.nil? || client_secret.nil?
|
12
|
+
params[:client_id] = client_id
|
13
|
+
params[:client_secret] = client_secret
|
14
|
+
end
|
15
|
+
|
5
16
|
def authenticate_resource_owner!
|
6
17
|
current_resource_owner
|
7
18
|
end
|
@@ -7,6 +7,8 @@ class Doorkeeper::AuthorizationsController < Doorkeeper::ApplicationController
|
|
7
7
|
authorization.authorize
|
8
8
|
redirect_to authorization.success_redirect_uri
|
9
9
|
end
|
10
|
+
elsif authorization.redirect_on_error?
|
11
|
+
redirect_to authorization.invalid_redirect_uri
|
10
12
|
else
|
11
13
|
render :error
|
12
14
|
end
|
@@ -15,6 +17,8 @@ class Doorkeeper::AuthorizationsController < Doorkeeper::ApplicationController
|
|
15
17
|
def create
|
16
18
|
if authorization.authorize
|
17
19
|
redirect_to authorization.success_redirect_uri
|
20
|
+
elsif authorization.redirect_on_error?
|
21
|
+
redirect_to authorization.invalid_redirect_uri
|
18
22
|
else
|
19
23
|
render :error
|
20
24
|
end
|
@@ -6,8 +6,7 @@ class Doorkeeper::AuthorizedApplicationsController < Doorkeeper::ApplicationCont
|
|
6
6
|
end
|
7
7
|
|
8
8
|
def destroy
|
9
|
-
|
10
|
-
token.revoke
|
9
|
+
AccessToken.revoke_all_for params[:id], current_resource_owner
|
11
10
|
redirect_to authorized_applications_path, :notice => "Application revoked."
|
12
11
|
end
|
13
12
|
end
|
data/app/models/access_grant.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
class AccessGrant < ActiveRecord::Base
|
2
|
-
include Doorkeeper::OAuth::
|
2
|
+
include Doorkeeper::OAuth::Helpers
|
3
|
+
include Doorkeeper::Models::Expirable
|
4
|
+
include Doorkeeper::Models::Revocable
|
3
5
|
|
4
|
-
|
6
|
+
self.table_name = :oauth_access_grants
|
5
7
|
|
6
8
|
belongs_to :application
|
7
9
|
|
@@ -9,24 +11,12 @@ class AccessGrant < ActiveRecord::Base
|
|
9
11
|
|
10
12
|
before_validation :generate_token, :on => :create
|
11
13
|
|
12
|
-
def expired?
|
13
|
-
expires_in.present? && Time.now > expired_time
|
14
|
-
end
|
15
|
-
|
16
14
|
def accessible?
|
17
15
|
!expired? && !revoked?
|
18
16
|
end
|
19
17
|
|
20
|
-
def revoke
|
21
|
-
update_attribute :revoked_at, DateTime.now
|
22
|
-
end
|
23
|
-
|
24
|
-
def revoked?
|
25
|
-
revoked_at.present?
|
26
|
-
end
|
27
|
-
|
28
18
|
def scopes
|
29
|
-
self[:scopes].split(" ").map(&:to_sym)
|
19
|
+
self[:scopes].split(" ").map(&:to_sym) if self[:scopes]
|
30
20
|
end
|
31
21
|
|
32
22
|
def scopes_string
|
@@ -35,11 +25,7 @@ class AccessGrant < ActiveRecord::Base
|
|
35
25
|
|
36
26
|
private
|
37
27
|
|
38
|
-
def expired_time
|
39
|
-
self.created_at + expires_in.seconds
|
40
|
-
end
|
41
|
-
|
42
28
|
def generate_token
|
43
|
-
self.token =
|
29
|
+
self.token = UniqueToken.generate_for :token, self.class
|
44
30
|
end
|
45
31
|
end
|
data/app/models/access_token.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
class AccessToken < ActiveRecord::Base
|
2
|
-
include Doorkeeper::OAuth::
|
2
|
+
include Doorkeeper::OAuth::Helpers
|
3
|
+
include Doorkeeper::Models::Expirable
|
4
|
+
include Doorkeeper::Models::Revocable
|
3
5
|
|
4
|
-
|
6
|
+
self.table_name = :oauth_access_tokens
|
5
7
|
|
6
8
|
belongs_to :application
|
7
9
|
|
@@ -14,20 +16,29 @@ class AccessToken < ActiveRecord::Base
|
|
14
16
|
before_validation :generate_token, :on => :create
|
15
17
|
before_validation :generate_refresh_token, :on => :create, :if => :use_refresh_token?
|
16
18
|
|
17
|
-
def self.
|
18
|
-
|
19
|
+
def self.revoke_all_for(application_id, resource_owner)
|
20
|
+
where(:application_id => application_id,
|
21
|
+
:resource_owner_id => resource_owner.id).delete_all
|
19
22
|
end
|
20
23
|
|
21
|
-
def
|
22
|
-
|
24
|
+
def self.matching_token_for(application, resource_owner_or_id, scopes)
|
25
|
+
token = last_authorized_token_for(application, resource_owner_or_id)
|
26
|
+
token if token && ScopeChecker.matches?(token.scopes, scopes)
|
23
27
|
end
|
24
28
|
|
25
|
-
def
|
26
|
-
|
29
|
+
def self.last_authorized_token_for(application, resource_owner_or_id)
|
30
|
+
resource_owner_id = resource_owner_or_id.kind_of?(ActiveRecord::Base) ? resource_owner_or_id.id : resource_owner_or_id
|
31
|
+
accessible.
|
32
|
+
where(:application_id => application.id,
|
33
|
+
:resource_owner_id => resource_owner_id).
|
34
|
+
order("created_at desc").
|
35
|
+
limit(1).
|
36
|
+
first
|
27
37
|
end
|
38
|
+
private_class_method :last_authorized_token_for
|
28
39
|
|
29
|
-
def
|
30
|
-
|
40
|
+
def token_type
|
41
|
+
"bearer"
|
31
42
|
end
|
32
43
|
|
33
44
|
def accessible?
|
@@ -49,15 +60,11 @@ class AccessToken < ActiveRecord::Base
|
|
49
60
|
|
50
61
|
private
|
51
62
|
|
52
|
-
def expired_time
|
53
|
-
self.created_at + expires_in.seconds
|
54
|
-
end
|
55
|
-
|
56
63
|
def generate_refresh_token
|
57
|
-
self.refresh_token =
|
64
|
+
self.refresh_token = UniqueToken.generate_for :refresh_token, self.class
|
58
65
|
end
|
59
66
|
|
60
67
|
def generate_token
|
61
|
-
self.token =
|
68
|
+
self.token = UniqueToken.generate_for :token, self.class
|
62
69
|
end
|
63
70
|
end
|
data/app/models/application.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
class Application < ActiveRecord::Base
|
2
|
-
include Doorkeeper::OAuth::
|
2
|
+
include Doorkeeper::OAuth::Helpers
|
3
3
|
|
4
|
-
|
4
|
+
self.table_name = :oauth_applications
|
5
5
|
|
6
6
|
has_many :access_grants
|
7
7
|
has_many :authorized_tokens, :class_name => "AccessToken", :conditions => { :revoked_at => nil }
|
@@ -9,19 +9,37 @@ class Application < ActiveRecord::Base
|
|
9
9
|
|
10
10
|
validates :name, :secret, :redirect_uri, :presence => true
|
11
11
|
validates :uid, :presence => true, :uniqueness => true
|
12
|
+
validate :validate_redirect_uri
|
12
13
|
|
13
14
|
before_validation :generate_uid, :generate_secret, :on => :create
|
14
15
|
|
16
|
+
def self.column_names_with_table
|
17
|
+
self.column_names.map { |c| "oauth_applications.#{c}" }
|
18
|
+
end
|
19
|
+
|
15
20
|
def self.authorized_for(resource_owner)
|
16
|
-
joins(:authorized_applications).
|
21
|
+
joins(:authorized_applications).
|
22
|
+
where(:oauth_access_tokens => { :resource_owner_id => resource_owner.id }).
|
23
|
+
group(column_names_with_table.join(','))
|
24
|
+
end
|
25
|
+
|
26
|
+
def validate_redirect_uri
|
27
|
+
return unless redirect_uri
|
28
|
+
uri = URI.parse(redirect_uri)
|
29
|
+
errors.add(:redirect_uri, "cannot contain a fragment.") unless uri.fragment.nil?
|
30
|
+
errors.add(:redirect_uri, "must be an absolute URL.") if uri.scheme.nil? || uri.host.nil?
|
31
|
+
errors.add(:redirect_uri, "cannot contain a query parameter.") unless uri.query.nil?
|
32
|
+
rescue URI::InvalidURIError => e
|
33
|
+
errors.add(:redirect_uri, "must be a valid URI.")
|
17
34
|
end
|
18
35
|
|
19
36
|
private
|
37
|
+
|
20
38
|
def generate_uid
|
21
|
-
self.uid =
|
39
|
+
self.uid = UniqueToken.generate_for :uid, self.class
|
22
40
|
end
|
23
41
|
|
24
42
|
def generate_secret
|
25
|
-
self.secret =
|
43
|
+
self.secret = UniqueToken.generate_for :secret, self.class
|
26
44
|
end
|
27
45
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
en:
|
2
|
+
doorkeeper:
|
3
|
+
errors:
|
4
|
+
messages:
|
5
|
+
# Common error messages
|
6
|
+
invalid_request: 'The request is missing a required parameter, includes an unsupported parameter value, or is otherwise malformed.'
|
7
|
+
invalid_redirect_uri: 'The redirect uri included is not valid.'
|
8
|
+
unauthorized_client: 'The client is not authorized to perform this request using this method.'
|
9
|
+
access_denied: 'The resource owner or authorization server denied the request.'
|
10
|
+
invalid_scope: 'The requested scope is invalid, unknown, or malformed.'
|
11
|
+
server_error: 'The authorization server encountered an unexpected condition which prevented it from fulfilling the request.'
|
12
|
+
temporarily_unavailable: 'The authorization server is currently unable to handle the request due to a temporary overloading or maintenance of the server.'
|
13
|
+
|
14
|
+
# Access grant errors
|
15
|
+
unsupported_response_type: 'The authorization server does not support this response type.'
|
16
|
+
|
17
|
+
# Access token errors
|
18
|
+
invalid_client: 'Client authentication failed due to unknown client, no client authentication included, or unsupported authentication method.'
|
19
|
+
invalid_grant: 'The provided authorization grant is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client.'
|
20
|
+
unsupported_grant_type: 'The authorization grant type is not supported by the authorization server.'
|
data/lib/doorkeeper.rb
CHANGED
@@ -6,14 +6,19 @@ module Doorkeeper
|
|
6
6
|
autoload :Validations, "doorkeeper/validations"
|
7
7
|
|
8
8
|
module OAuth
|
9
|
-
class MismatchRedirectURI < StandardError; end
|
10
|
-
|
11
|
-
autoload :RandomString, "doorkeeper/oauth/random_string"
|
12
9
|
autoload :AuthorizationRequest, "doorkeeper/oauth/authorization_request"
|
13
10
|
autoload :AccessTokenRequest, "doorkeeper/oauth/access_token_request"
|
11
|
+
autoload :Authorization, "doorkeeper/oauth/authorization"
|
12
|
+
|
13
|
+
module Helpers
|
14
|
+
autoload :ScopeChecker, "doorkeeper/oauth/helpers/scope_checker"
|
15
|
+
autoload :URIChecker, "doorkeeper/oauth/helpers/uri_checker"
|
16
|
+
autoload :UniqueToken, "doorkeeper/oauth/helpers/unique_token"
|
17
|
+
end
|
14
18
|
end
|
15
19
|
|
16
|
-
|
17
|
-
|
20
|
+
module Models
|
21
|
+
autoload :Expirable, "doorkeeper/models/expirable"
|
22
|
+
autoload :Revocable, "doorkeeper/models/revocable"
|
18
23
|
end
|
19
24
|
end
|
@@ -64,29 +64,12 @@ module Doorkeeper
|
|
64
64
|
case args.first
|
65
65
|
when :all
|
66
66
|
AllDoorkeeperFor.new(args[1] || {})
|
67
|
-
when Hash
|
68
|
-
handle_hash(args.first)
|
69
|
-
when nil
|
67
|
+
when Hash, nil
|
70
68
|
raise InvalidSyntax
|
71
69
|
else
|
72
70
|
SelectedDoorkeeperFor.new(*args)
|
73
71
|
end
|
74
72
|
end
|
75
|
-
|
76
|
-
def self.handle_hash(hash)
|
77
|
-
if hash.has_key?(:only)
|
78
|
-
warn "DEPRECATED: :only option. Put the actions you want doorkeeper to take care of after doorkeeper_for eg: doorkeeper_for :index, :new"
|
79
|
-
args = [hash[:only], hash.except(:only)]
|
80
|
-
return create_doorkeeper_for(*args)
|
81
|
-
end
|
82
|
-
|
83
|
-
if hash.has_key?(:except)
|
84
|
-
warn "DEPRECATED: :except option. Use in connection with :all -> doorkeeper_for :all, :except => "
|
85
|
-
return create_doorkeeper_for(:all, hash)
|
86
|
-
end
|
87
|
-
|
88
|
-
raise InvalidSyntax
|
89
|
-
end
|
90
73
|
end
|
91
74
|
|
92
75
|
module Controller
|
@@ -95,7 +78,15 @@ module Doorkeeper
|
|
95
78
|
doorkeeper_for = DoorkeeperForBuilder.create_doorkeeper_for(*args)
|
96
79
|
|
97
80
|
before_filter doorkeeper_for.filter_options do
|
98
|
-
|
81
|
+
return if doorkeeper_for.validate_token(doorkeeper_token)
|
82
|
+
render_options = doorkeeper_unauthorized_render_options
|
83
|
+
if render_options.nil? || render_options.empty?
|
84
|
+
head :unauthorized
|
85
|
+
else
|
86
|
+
render_options[:status] = :unauthorized
|
87
|
+
render_options[:layout] = false if render_options[:layout].nil?
|
88
|
+
render render_options
|
89
|
+
end
|
99
90
|
end
|
100
91
|
end
|
101
92
|
end
|
@@ -113,8 +104,12 @@ module Doorkeeper
|
|
113
104
|
token = params[:access_token] || params[:bearer_token] || request.env['HTTP_AUTHORIZATION']
|
114
105
|
if token
|
115
106
|
token.gsub!(/Bearer /, '')
|
107
|
+
AccessToken.find_by_token(token)
|
116
108
|
end
|
117
|
-
|
109
|
+
end
|
110
|
+
|
111
|
+
def doorkeeper_unauthorized_render_options
|
112
|
+
nil
|
118
113
|
end
|
119
114
|
end
|
120
115
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Doorkeeper
|
2
|
+
module Models
|
3
|
+
module Expirable
|
4
|
+
def expired?
|
5
|
+
expires_in && Time.now > expired_time
|
6
|
+
end
|
7
|
+
|
8
|
+
def time_left
|
9
|
+
expired? ? 0 : expired_time - Time.now
|
10
|
+
end
|
11
|
+
|
12
|
+
def expired_time
|
13
|
+
created_at + expires_in.seconds
|
14
|
+
end
|
15
|
+
private :expired_time
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -27,14 +27,14 @@ module Doorkeeper::OAuth
|
|
27
27
|
def authorize
|
28
28
|
if valid?
|
29
29
|
revoke_base_token
|
30
|
-
|
30
|
+
find_or_create_access_token
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
34
34
|
def authorization
|
35
35
|
auth = {
|
36
36
|
'access_token' => access_token.token,
|
37
|
-
'token_type' => token_type,
|
37
|
+
'token_type' => access_token.token_type,
|
38
38
|
'expires_in' => access_token.expires_in,
|
39
39
|
}
|
40
40
|
auth.merge!({'refresh_token' => access_token.refresh_token}) if refresh_token_enabled?
|
@@ -46,7 +46,7 @@ module Doorkeeper::OAuth
|
|
46
46
|
end
|
47
47
|
|
48
48
|
def access_token
|
49
|
-
@access_token
|
49
|
+
@access_token ||= AccessToken.matching_token_for client, base_token.resource_owner_id, base_token.scopes_string
|
50
50
|
end
|
51
51
|
|
52
52
|
def token_type
|
@@ -54,11 +54,27 @@ module Doorkeeper::OAuth
|
|
54
54
|
end
|
55
55
|
|
56
56
|
def error_response
|
57
|
-
{
|
57
|
+
{
|
58
|
+
'error' => error.to_s,
|
59
|
+
'error_description' => error_description
|
60
|
+
}
|
58
61
|
end
|
59
62
|
|
60
63
|
private
|
61
64
|
|
65
|
+
def find_or_create_access_token
|
66
|
+
if access_token
|
67
|
+
access_token.expired? ? revoke_and_create_access_token : access_token
|
68
|
+
else
|
69
|
+
create_access_token
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def revoke_and_create_access_token
|
74
|
+
access_token.revoke
|
75
|
+
create_access_token
|
76
|
+
end
|
77
|
+
|
62
78
|
def revoke_base_token
|
63
79
|
base_token.revoke
|
64
80
|
end
|
@@ -123,6 +139,10 @@ module Doorkeeper::OAuth
|
|
123
139
|
%w(authorization_code refresh_token).include? grant_type
|
124
140
|
end
|
125
141
|
|
142
|
+
def error_description
|
143
|
+
I18n.translate error, :scope => [:doorkeeper, :errors, :messages]
|
144
|
+
end
|
145
|
+
|
126
146
|
def configuration
|
127
147
|
Doorkeeper.configuration
|
128
148
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Doorkeeper
|
2
|
+
module OAuth
|
3
|
+
module Authorization
|
4
|
+
class Code
|
5
|
+
include URIBuilder
|
6
|
+
|
7
|
+
DEFAULT_EXPIRATION_TIME = 600
|
8
|
+
|
9
|
+
attr_accessor :authorization, :grant
|
10
|
+
|
11
|
+
def initialize(authorization)
|
12
|
+
@authorization = authorization
|
13
|
+
end
|
14
|
+
|
15
|
+
def issue_token
|
16
|
+
@grant ||= AccessGrant.create!(
|
17
|
+
:application_id => authorization.client.id,
|
18
|
+
:resource_owner_id => authorization.resource_owner.id,
|
19
|
+
:expires_in => DEFAULT_EXPIRATION_TIME,
|
20
|
+
:redirect_uri => authorization.redirect_uri,
|
21
|
+
:scopes => authorization.scope
|
22
|
+
)
|
23
|
+
end
|
24
|
+
|
25
|
+
def callback
|
26
|
+
uri_with_query(authorization.redirect_uri, {
|
27
|
+
:code => grant.token,
|
28
|
+
:state => authorization.state
|
29
|
+
})
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Doorkeeper
|
2
|
+
module OAuth
|
3
|
+
module Authorization
|
4
|
+
class Token
|
5
|
+
include URIBuilder
|
6
|
+
|
7
|
+
attr_accessor :authorization, :access_token
|
8
|
+
|
9
|
+
def initialize(authorization)
|
10
|
+
@authorization = authorization
|
11
|
+
end
|
12
|
+
|
13
|
+
def callback
|
14
|
+
uri_with_fragment(authorization.redirect_uri, {
|
15
|
+
:access_token => access_token.token,
|
16
|
+
:token_type => access_token.token_type,
|
17
|
+
:expires_in => access_token.time_left,
|
18
|
+
:state => authorization.state
|
19
|
+
})
|
20
|
+
end
|
21
|
+
|
22
|
+
def issue_token
|
23
|
+
@access_token ||= AccessToken.create!({
|
24
|
+
:application_id => authorization.client.id,
|
25
|
+
:resource_owner_id => authorization.resource_owner.id,
|
26
|
+
:scopes => authorization.scope,
|
27
|
+
:expires_in => configuration.access_token_expires_in,
|
28
|
+
:use_refresh_token => false
|
29
|
+
})
|
30
|
+
end
|
31
|
+
|
32
|
+
def configuration
|
33
|
+
Doorkeeper.configuration
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Doorkeeper
|
2
|
+
module OAuth
|
3
|
+
module Authorization
|
4
|
+
module URIBuilder
|
5
|
+
include Rack::Utils
|
6
|
+
|
7
|
+
def uri_with_query(url, parameters = {})
|
8
|
+
uri = URI.parse(url)
|
9
|
+
original_query = parse_query(uri.query)
|
10
|
+
uri.query = build_query(original_query.merge(parameters))
|
11
|
+
uri.to_s
|
12
|
+
end
|
13
|
+
|
14
|
+
def uri_with_fragment(url, parameters = {})
|
15
|
+
uri = URI.parse(url)
|
16
|
+
uri.fragment = build_query(parameters)
|
17
|
+
uri.to_s
|
18
|
+
end
|
19
|
+
|
20
|
+
def build_query(parameters = {})
|
21
|
+
parameters = parameters.reject { |k, v| v.blank? }
|
22
|
+
super parameters
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -1,8 +1,8 @@
|
|
1
1
|
module Doorkeeper::OAuth
|
2
2
|
class AuthorizationRequest
|
3
3
|
include Doorkeeper::Validations
|
4
|
-
|
5
|
-
|
4
|
+
include Doorkeeper::OAuth::Authorization::URIBuilder
|
5
|
+
include Doorkeeper::OAuth::Helpers
|
6
6
|
|
7
7
|
ATTRIBUTES = [
|
8
8
|
:response_type,
|
@@ -12,9 +12,9 @@ module Doorkeeper::OAuth
|
|
12
12
|
:state
|
13
13
|
]
|
14
14
|
|
15
|
-
validate :attributes, :error => :invalid_request
|
16
15
|
validate :client, :error => :invalid_client
|
17
16
|
validate :redirect_uri, :error => :invalid_redirect_uri
|
17
|
+
validate :attributes, :error => :invalid_request
|
18
18
|
validate :response_type, :error => :unsupported_response_type
|
19
19
|
validate :scope, :error => :invalid_scope
|
20
20
|
|
@@ -24,17 +24,18 @@ module Doorkeeper::OAuth
|
|
24
24
|
def initialize(resource_owner, attributes)
|
25
25
|
ATTRIBUTES.each { |attr| instance_variable_set("@#{attr}", attributes[attr]) }
|
26
26
|
@resource_owner = resource_owner
|
27
|
-
@grant = nil
|
28
27
|
@scope ||= Doorkeeper.configuration.default_scope_string
|
29
28
|
validate
|
30
29
|
end
|
31
30
|
|
32
31
|
def authorize
|
33
|
-
|
32
|
+
return false unless valid?
|
33
|
+
@authorization = authorization_method.new(self)
|
34
|
+
@authorization.issue_token
|
34
35
|
end
|
35
36
|
|
36
37
|
def access_token_exists?
|
37
|
-
|
38
|
+
AccessToken.matching_token_for(client, resource_owner, scope).present?
|
38
39
|
end
|
39
40
|
|
40
41
|
def deny
|
@@ -42,19 +43,20 @@ module Doorkeeper::OAuth
|
|
42
43
|
end
|
43
44
|
|
44
45
|
def success_redirect_uri
|
45
|
-
|
46
|
-
query = "code=#{token}"
|
47
|
-
query << "&state=#{state}" if has_state?
|
48
|
-
uri.query = query
|
49
|
-
end
|
46
|
+
@authorization.callback
|
50
47
|
end
|
51
48
|
|
52
49
|
def invalid_redirect_uri
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
50
|
+
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
|
+
})
|
56
|
+
end
|
57
|
+
|
58
|
+
def redirect_on_error?
|
59
|
+
(error != :invalid_redirect_uri) && (error != :invalid_client)
|
58
60
|
end
|
59
61
|
|
60
62
|
def client
|
@@ -67,36 +69,12 @@ module Doorkeeper::OAuth
|
|
67
69
|
|
68
70
|
private
|
69
71
|
|
70
|
-
def create_authorization
|
71
|
-
@grant = AccessGrant.create!(
|
72
|
-
:application_id => client.id,
|
73
|
-
:resource_owner_id => resource_owner.id,
|
74
|
-
:expires_in => DEFAULT_EXPIRATION_TIME,
|
75
|
-
:redirect_uri => redirect_uri,
|
76
|
-
:scopes => scope
|
77
|
-
)
|
78
|
-
end
|
79
|
-
|
80
|
-
def has_state?
|
81
|
-
state.present?
|
82
|
-
end
|
83
|
-
|
84
72
|
def has_scope?
|
85
73
|
Doorkeeper.configuration.scopes.all.present?
|
86
74
|
end
|
87
75
|
|
88
|
-
def token
|
89
|
-
@grant.token
|
90
|
-
end
|
91
|
-
|
92
|
-
def build_uri
|
93
|
-
uri = URI.parse(client.redirect_uri)
|
94
|
-
yield uri
|
95
|
-
uri.to_s
|
96
|
-
end
|
97
|
-
|
98
76
|
def validate_attributes
|
99
|
-
|
77
|
+
response_type.present?
|
100
78
|
end
|
101
79
|
|
102
80
|
def validate_client
|
@@ -104,24 +82,38 @@ module Doorkeeper::OAuth
|
|
104
82
|
end
|
105
83
|
|
106
84
|
def validate_redirect_uri
|
107
|
-
|
85
|
+
return false unless redirect_uri
|
86
|
+
URIChecker.valid_for_authorization?(redirect_uri, client.redirect_uri)
|
108
87
|
end
|
109
88
|
|
110
89
|
def validate_response_type
|
111
|
-
|
90
|
+
is_code_request? || is_token_request?
|
112
91
|
end
|
113
92
|
|
114
93
|
def validate_scope
|
115
94
|
return true unless has_scope?
|
116
|
-
|
95
|
+
ScopeChecker.valid?(scope, configuration.scopes)
|
96
|
+
end
|
97
|
+
|
98
|
+
def is_code_request?
|
99
|
+
response_type == "code"
|
100
|
+
end
|
101
|
+
|
102
|
+
def is_token_request?
|
103
|
+
response_type == "token"
|
104
|
+
end
|
105
|
+
|
106
|
+
def error_description
|
107
|
+
I18n.translate error, :scope => [:doorkeeper, :errors, :messages]
|
117
108
|
end
|
118
109
|
|
119
|
-
def
|
120
|
-
|
110
|
+
def configuration
|
111
|
+
Doorkeeper.configuration
|
121
112
|
end
|
122
113
|
|
123
|
-
def
|
124
|
-
|
114
|
+
def authorization_method
|
115
|
+
klass = is_code_request? ? "Code" : "Token"
|
116
|
+
"Doorkeeper::OAuth::Authorization::#{klass}".constantize
|
125
117
|
end
|
126
118
|
end
|
127
119
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Doorkeeper
|
2
|
+
module OAuth
|
3
|
+
module Helpers
|
4
|
+
module ScopeChecker
|
5
|
+
def self.matches?(current_scopes, scopes)
|
6
|
+
return false if current_scopes.nil? || scopes.nil?
|
7
|
+
current_scopes.map(&:to_s).sort == scopes.split(" ").sort
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.valid?(scope, server_scopes)
|
11
|
+
scope.present? &&
|
12
|
+
scope !~ /[\n|\r|\t]/ &&
|
13
|
+
server_scopes.all_included?(scope)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Doorkeeper
|
2
|
+
module OAuth
|
3
|
+
module Helpers
|
4
|
+
module UniqueToken
|
5
|
+
def self.generate_for(attribute, klass, options = {})
|
6
|
+
generator_method = options.delete(:generator) || SecureRandom.method(:hex)
|
7
|
+
token_size = options.delete(:size) || 32
|
8
|
+
loop do
|
9
|
+
token = generator_method.call(token_size)
|
10
|
+
break token unless klass.send("find_by_#{attribute}", token)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Doorkeeper
|
2
|
+
module OAuth
|
3
|
+
module Helpers
|
4
|
+
module URIChecker
|
5
|
+
def self.valid?(url)
|
6
|
+
uri = as_uri(url)
|
7
|
+
uri.fragment.nil? && !uri.host.nil? && !uri.scheme.nil?
|
8
|
+
rescue URI::InvalidURIError
|
9
|
+
false
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.matches?(url, client_url)
|
13
|
+
url, client_url = as_uri(url), as_uri(client_url)
|
14
|
+
url.query = nil
|
15
|
+
url == client_url
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.valid_for_authorization?(url, client_url)
|
19
|
+
valid?(url) && matches?(url, client_url)
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.as_uri(url)
|
23
|
+
URI.parse(url)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/doorkeeper/version.rb
CHANGED
@@ -7,6 +7,7 @@ class Doorkeeper::InstallGenerator < Rails::Generators::Base
|
|
7
7
|
def install
|
8
8
|
migration_template 'migration.rb', 'db/migrate/create_doorkeeper_tables.rb'
|
9
9
|
template "initializer.rb", "config/initializers/doorkeeper.rb"
|
10
|
+
copy_file "../../../../config/locales/en.yml", "config/locales/doorkeeper.en.yml"
|
10
11
|
route "mount Doorkeeper::Engine => '/oauth'"
|
11
12
|
readme "README"
|
12
13
|
end
|
@@ -8,6 +8,8 @@ class CreateDoorkeeperTables < ActiveRecord::Migration
|
|
8
8
|
t.timestamps
|
9
9
|
end
|
10
10
|
|
11
|
+
add_index :oauth_applications, :uid, :unique => true
|
12
|
+
|
11
13
|
create_table :oauth_access_grants do |t|
|
12
14
|
t.integer :resource_owner_id, :null => false
|
13
15
|
t.integer :application_id, :null => false
|
@@ -19,6 +21,8 @@ class CreateDoorkeeperTables < ActiveRecord::Migration
|
|
19
21
|
t.string :scopes
|
20
22
|
end
|
21
23
|
|
24
|
+
add_index :oauth_access_grants, :token, :unique => true
|
25
|
+
|
22
26
|
create_table :oauth_access_tokens do |t|
|
23
27
|
t.integer :resource_owner_id, :null => false
|
24
28
|
t.integer :application_id, :null => false
|
@@ -29,5 +33,10 @@ class CreateDoorkeeperTables < ActiveRecord::Migration
|
|
29
33
|
t.datetime :created_at, :null => false
|
30
34
|
t.string :scopes
|
31
35
|
end
|
36
|
+
|
37
|
+
add_index :oauth_access_tokens, :token, :unique => true
|
38
|
+
add_index :oauth_access_tokens, :resource_owner_id
|
39
|
+
add_index :oauth_access_tokens, :refresh_token, :unique => true
|
40
|
+
|
32
41
|
end
|
33
42
|
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: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,96 +10,96 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date:
|
13
|
+
date: 2012-02-11 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
|
-
name:
|
17
|
-
requirement: &
|
16
|
+
name: railties
|
17
|
+
requirement: &70362054833440 !ruby/object:Gem::Requirement
|
18
18
|
none: false
|
19
19
|
requirements:
|
20
20
|
- - ~>
|
21
21
|
- !ruby/object:Gem::Version
|
22
|
-
version: 3.1
|
22
|
+
version: '3.1'
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
|
-
version_requirements: *
|
25
|
+
version_requirements: *70362054833440
|
26
26
|
- !ruby/object:Gem::Dependency
|
27
27
|
name: sqlite3
|
28
|
-
requirement: &
|
28
|
+
requirement: &70362054832720 !ruby/object:Gem::Requirement
|
29
29
|
none: false
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - ~>
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
33
|
+
version: 1.3.5
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
|
-
version_requirements: *
|
36
|
+
version_requirements: *70362054832720
|
37
37
|
- !ruby/object:Gem::Dependency
|
38
38
|
name: rspec-rails
|
39
|
-
requirement: &
|
39
|
+
requirement: &70362054831840 !ruby/object:Gem::Requirement
|
40
40
|
none: false
|
41
41
|
requirements:
|
42
|
-
- -
|
42
|
+
- - ~>
|
43
43
|
- !ruby/object:Gem::Version
|
44
|
-
version:
|
44
|
+
version: 2.8.1
|
45
45
|
type: :development
|
46
46
|
prerelease: false
|
47
|
-
version_requirements: *
|
47
|
+
version_requirements: *70362054831840
|
48
48
|
- !ruby/object:Gem::Dependency
|
49
49
|
name: capybara
|
50
|
-
requirement: &
|
50
|
+
requirement: &70362054831180 !ruby/object:Gem::Requirement
|
51
51
|
none: false
|
52
52
|
requirements:
|
53
|
-
- -
|
53
|
+
- - ~>
|
54
54
|
- !ruby/object:Gem::Version
|
55
|
-
version:
|
55
|
+
version: 1.1.2
|
56
56
|
type: :development
|
57
57
|
prerelease: false
|
58
|
-
version_requirements: *
|
58
|
+
version_requirements: *70362054831180
|
59
59
|
- !ruby/object:Gem::Dependency
|
60
60
|
name: generator_spec
|
61
|
-
requirement: &
|
61
|
+
requirement: &70362054830420 !ruby/object:Gem::Requirement
|
62
62
|
none: false
|
63
63
|
requirements:
|
64
|
-
- -
|
64
|
+
- - ~>
|
65
65
|
- !ruby/object:Gem::Version
|
66
|
-
version:
|
66
|
+
version: 0.8.5
|
67
67
|
type: :development
|
68
68
|
prerelease: false
|
69
|
-
version_requirements: *
|
69
|
+
version_requirements: *70362054830420
|
70
70
|
- !ruby/object:Gem::Dependency
|
71
71
|
name: factory_girl_rails
|
72
|
-
requirement: &
|
72
|
+
requirement: &70362054829800 !ruby/object:Gem::Requirement
|
73
73
|
none: false
|
74
74
|
requirements:
|
75
|
-
- -
|
75
|
+
- - ~>
|
76
76
|
- !ruby/object:Gem::Version
|
77
|
-
version:
|
77
|
+
version: 1.4.0
|
78
78
|
type: :development
|
79
79
|
prerelease: false
|
80
|
-
version_requirements: *
|
80
|
+
version_requirements: *70362054829800
|
81
81
|
- !ruby/object:Gem::Dependency
|
82
82
|
name: timecop
|
83
|
-
requirement: &
|
83
|
+
requirement: &70362054829180 !ruby/object:Gem::Requirement
|
84
84
|
none: false
|
85
85
|
requirements:
|
86
|
-
- -
|
86
|
+
- - ~>
|
87
87
|
- !ruby/object:Gem::Version
|
88
|
-
version:
|
88
|
+
version: 0.3.5
|
89
89
|
type: :development
|
90
90
|
prerelease: false
|
91
|
-
version_requirements: *
|
91
|
+
version_requirements: *70362054829180
|
92
92
|
- !ruby/object:Gem::Dependency
|
93
93
|
name: database_cleaner
|
94
|
-
requirement: &
|
94
|
+
requirement: &70362054828560 !ruby/object:Gem::Requirement
|
95
95
|
none: false
|
96
96
|
requirements:
|
97
|
-
- -
|
97
|
+
- - ~>
|
98
98
|
- !ruby/object:Gem::Version
|
99
|
-
version:
|
99
|
+
version: 0.7.1
|
100
100
|
type: :development
|
101
101
|
prerelease: false
|
102
|
-
version_requirements: *
|
102
|
+
version_requirements: *70362054828560
|
103
103
|
description: Doorkeeper is an OAuth 2 provider for Rails.
|
104
104
|
email:
|
105
105
|
- felipe@applicake.com
|
@@ -140,6 +140,7 @@ files:
|
|
140
140
|
- app/views/layouts/doorkeeper/application.html.erb
|
141
141
|
- config/initializers/form_errors.rb
|
142
142
|
- config/initializers/form_errors.rbc
|
143
|
+
- config/locales/en.yml
|
143
144
|
- config/routes.rb
|
144
145
|
- config/routes.rbc
|
145
146
|
- lib/doorkeeper/config/scope.rb
|
@@ -151,11 +152,19 @@ files:
|
|
151
152
|
- lib/doorkeeper/doorkeeper_for.rbc
|
152
153
|
- lib/doorkeeper/engine.rb
|
153
154
|
- lib/doorkeeper/engine.rbc
|
155
|
+
- lib/doorkeeper/models/expirable.rb
|
156
|
+
- lib/doorkeeper/models/revocable.rb
|
154
157
|
- lib/doorkeeper/oauth/access_token_request.rb
|
155
158
|
- lib/doorkeeper/oauth/access_token_request.rbc
|
159
|
+
- lib/doorkeeper/oauth/authorization/code.rb
|
160
|
+
- lib/doorkeeper/oauth/authorization/token.rb
|
161
|
+
- lib/doorkeeper/oauth/authorization/uri_builder.rb
|
162
|
+
- lib/doorkeeper/oauth/authorization.rb
|
156
163
|
- lib/doorkeeper/oauth/authorization_request.rb
|
157
164
|
- lib/doorkeeper/oauth/authorization_request.rbc
|
158
|
-
- lib/doorkeeper/oauth/
|
165
|
+
- lib/doorkeeper/oauth/helpers/scope_checker.rb
|
166
|
+
- lib/doorkeeper/oauth/helpers/unique_token.rb
|
167
|
+
- lib/doorkeeper/oauth/helpers/uri_checker.rb
|
159
168
|
- lib/doorkeeper/oauth/random_string.rbc
|
160
169
|
- lib/doorkeeper/validations.rb
|
161
170
|
- lib/doorkeeper/validations.rbc
|
@@ -187,7 +196,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
187
196
|
version: '0'
|
188
197
|
segments:
|
189
198
|
- 0
|
190
|
-
hash:
|
199
|
+
hash: 2535613111185415722
|
191
200
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
192
201
|
none: false
|
193
202
|
requirements:
|
@@ -196,10 +205,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
196
205
|
version: '0'
|
197
206
|
segments:
|
198
207
|
- 0
|
199
|
-
hash:
|
208
|
+
hash: 2535613111185415722
|
200
209
|
requirements: []
|
201
210
|
rubyforge_project:
|
202
|
-
rubygems_version: 1.8.
|
211
|
+
rubygems_version: 1.8.12
|
203
212
|
signing_key:
|
204
213
|
specification_version: 3
|
205
214
|
summary: Doorkeeper is an OAuth 2 provider for Rails.
|
@@ -1,15 +0,0 @@
|
|
1
|
-
module Doorkeeper::OAuth
|
2
|
-
module RandomString
|
3
|
-
def random_string
|
4
|
-
SecureRandom.hex(32)
|
5
|
-
end
|
6
|
-
|
7
|
-
def unique_random_string_for(attribute)
|
8
|
-
loop do
|
9
|
-
token = random_string
|
10
|
-
break token unless self.class.send("find_by_#{attribute}", token)
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|