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.

Files changed (92) hide show
  1. data/CHANGELOG.md +13 -0
  2. data/README.md +32 -5
  3. data/app/controllers/doorkeeper/application_controller.rb +4 -11
  4. data/app/controllers/doorkeeper/authorizations_controller.rb +11 -2
  5. data/app/controllers/doorkeeper/tokens_controller.rb +19 -5
  6. data/app/models/doorkeeper/access_grant.rb +1 -8
  7. data/app/models/doorkeeper/access_token.rb +2 -10
  8. data/app/models/doorkeeper/application.rb +4 -0
  9. data/app/views/doorkeeper/authorizations/error.html.erb +1 -1
  10. data/app/views/doorkeeper/authorizations/new.html.erb +1 -1
  11. data/config/locales/en.yml +3 -0
  12. data/doorkeeper.gemspec +2 -1
  13. data/lib/doorkeeper.rb +23 -3
  14. data/lib/doorkeeper/config.rb +73 -12
  15. data/lib/doorkeeper/doorkeeper_for.rb +1 -1
  16. data/lib/doorkeeper/engine.rb +28 -0
  17. data/lib/doorkeeper/models/scopes.rb +13 -0
  18. data/lib/doorkeeper/oauth/access_token_request.rb +5 -16
  19. data/lib/doorkeeper/oauth/authorization/code.rb +1 -1
  20. data/lib/doorkeeper/oauth/authorization/token.rb +1 -1
  21. data/lib/doorkeeper/oauth/authorization_request.rb +18 -23
  22. data/lib/doorkeeper/oauth/client.rb +27 -0
  23. data/lib/doorkeeper/oauth/client/credentials.rb +21 -0
  24. data/lib/doorkeeper/oauth/client/methods.rb +18 -0
  25. data/lib/doorkeeper/oauth/client_credentials/creator.rb +29 -0
  26. data/lib/doorkeeper/oauth/client_credentials/issuer.rb +35 -0
  27. data/lib/doorkeeper/oauth/client_credentials/response.rb +42 -0
  28. data/lib/doorkeeper/oauth/client_credentials/validation.rb +33 -0
  29. data/lib/doorkeeper/oauth/client_credentials_request.rb +46 -0
  30. data/lib/doorkeeper/oauth/error.rb +9 -0
  31. data/lib/doorkeeper/oauth/error_response.rb +30 -0
  32. data/lib/doorkeeper/oauth/helpers/scope_checker.rb +2 -2
  33. data/lib/doorkeeper/oauth/password_access_token_request.rb +130 -0
  34. data/lib/doorkeeper/oauth/scopes.rb +60 -0
  35. data/lib/doorkeeper/version.rb +1 -1
  36. data/lib/generators/doorkeeper/templates/initializer.rb +10 -5
  37. data/lib/generators/doorkeeper/templates/migration.rb +1 -1
  38. data/script/run_all +11 -0
  39. data/spec/controllers/authorizations_controller_spec.rb +3 -3
  40. data/spec/controllers/protected_resources_controller_spec.rb +7 -0
  41. data/spec/controllers/tokens_controller_spec.rb +1 -1
  42. data/spec/dummy/app/controllers/home_controller.rb +1 -1
  43. data/spec/dummy/app/models/user.rb +9 -0
  44. data/spec/dummy/config/application.rb +2 -0
  45. data/spec/dummy/config/initializers/doorkeeper.rb +12 -5
  46. data/spec/dummy/config/locales/doorkeeper.en.yml +5 -0
  47. data/spec/dummy/db/migrate/20120312140401_add_password_to_users.rb +5 -0
  48. data/spec/dummy/db/migrate/{20111206151426_create_doorkeeper_tables.rb → 20120524202412_create_doorkeeper_tables.rb} +10 -1
  49. data/spec/dummy/db/schema.rb +15 -6
  50. data/spec/lib/config_spec.rb +29 -13
  51. data/spec/lib/models/scopes_spec.rb +32 -0
  52. data/spec/lib/oauth/access_token_request_spec.rb +15 -29
  53. data/spec/lib/oauth/authorization_request_spec.rb +22 -72
  54. data/spec/lib/oauth/client/credentials_spec.rb +47 -0
  55. data/spec/lib/oauth/client/methods_spec.rb +54 -0
  56. data/spec/lib/oauth/client_credentials/creator_spec.rb +47 -0
  57. data/spec/lib/oauth/client_credentials/issuer_spec.rb +57 -0
  58. data/spec/lib/oauth/client_credentials/response_spec.rb +58 -0
  59. data/spec/lib/oauth/client_credentials/validation_spec.rb +29 -0
  60. data/spec/lib/oauth/client_credentials_integration_spec.rb +27 -0
  61. data/spec/lib/oauth/client_credentials_request_spec.rb +60 -0
  62. data/spec/lib/oauth/client_spec.rb +42 -0
  63. data/spec/lib/oauth/error_response_spec.rb +40 -0
  64. data/spec/lib/oauth/error_spec.rb +19 -0
  65. data/spec/lib/oauth/helpers/scope_checker_spec.rb +15 -10
  66. data/spec/lib/oauth/password_access_token_request_spec.rb +152 -0
  67. data/spec/lib/oauth/scopes_spec.rb +115 -0
  68. data/spec/models/doorkeeper/access_grant_spec.rb +0 -15
  69. data/spec/models/doorkeeper/access_token_spec.rb +11 -4
  70. data/spec/requests/applications/authorized_applications_spec.rb +2 -2
  71. data/spec/requests/endpoints/authorization_spec.rb +2 -2
  72. data/spec/requests/endpoints/token_spec.rb +7 -0
  73. data/spec/requests/flows/authorization_code_errors_spec.rb +1 -1
  74. data/spec/requests/flows/authorization_code_spec.rb +8 -2
  75. data/spec/requests/flows/client_credentials_spec.rb +56 -0
  76. data/spec/requests/flows/password_spec.rb +52 -0
  77. data/spec/requests/flows/skip_authorization_spec.rb +2 -2
  78. data/spec/requests/protected_resources/private_api_spec.rb +9 -2
  79. data/spec/spec_helper_integration.rb +3 -0
  80. data/spec/support/helpers/authorization_request_helper.rb +7 -5
  81. data/spec/support/helpers/model_helper.rb +3 -3
  82. data/spec/support/helpers/request_spec_helper.rb +1 -1
  83. data/spec/support/helpers/url_helper.rb +12 -0
  84. metadata +65 -30
  85. data/lib/doorkeeper/config/scope.rb +0 -11
  86. data/lib/doorkeeper/config/scopes.rb +0 -61
  87. data/lib/doorkeeper/config/scopes_builder.rb +0 -18
  88. data/spec/dummy/config/initializers/inflections.rb +0 -10
  89. data/spec/dummy/config/initializers/mime_types.rb +0 -5
  90. data/spec/lib/config/scope_spec.rb +0 -45
  91. data/spec/lib/config/scopes_builder_spec.rb +0 -27
  92. 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!(/^Bearer /, '') unless header.nil?
112
+ header.gsub(/^Bearer /, '') if header && header.match(/^Bearer /)
113
113
  end
114
114
 
115
115
  def doorkeeper_unauthorized_render_options
@@ -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
@@ -0,0 +1,13 @@
1
+ module Doorkeeper
2
+ module Models
3
+ module Scopes
4
+ def scopes
5
+ Doorkeeper::OAuth::Scopes.from_string(self[:scopes])
6
+ end
7
+
8
+ def scopes_string
9
+ Doorkeeper::OAuth::Scopes.from_string(self[:scopes]).to_s
10
+ end
11
+ end
12
+ end
13
+ 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.scopes_string
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
@@ -18,7 +18,7 @@ module Doorkeeper
18
18
  :resource_owner_id => authorization.resource_owner.id,
19
19
  :expires_in => DEFAULT_EXPIRATION_TIME,
20
20
  :redirect_uri => authorization.redirect_uri,
21
- :scopes => authorization.scope
21
+ :scopes => authorization.scopes.to_s
22
22
  )
23
23
  end
24
24
 
@@ -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.scope,
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
- @scope ||= Doorkeeper.configuration.default_scope_string
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, scope).present?
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 client
63
- @client ||= Doorkeeper::Application.find_by_uid(client_id)
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 scopes
67
- Doorkeeper.configuration.scopes.with_names(*scope.split(" ")) if has_scope?
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 has_scope?
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