doorkeeper 0.5.0 → 0.6.0.rc1

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 (105) hide show
  1. data/.travis.yml +15 -6
  2. data/CHANGELOG.md +19 -1
  3. data/Gemfile +23 -7
  4. data/README.md +62 -27
  5. data/app/controllers/doorkeeper/application_controller.rb +1 -1
  6. data/app/controllers/doorkeeper/authorizations_controller.rb +45 -35
  7. data/app/controllers/doorkeeper/token_info_controller.rb +10 -9
  8. data/app/controllers/doorkeeper/tokens_controller.rb +13 -32
  9. data/app/validators/redirect_uri_validator.rb +11 -0
  10. data/app/views/doorkeeper/applications/_form.html.erb +6 -1
  11. data/app/views/doorkeeper/applications/edit.html.erb +2 -2
  12. data/app/views/doorkeeper/applications/new.html.erb +2 -2
  13. data/app/views/doorkeeper/applications/show.html.erb +4 -1
  14. data/app/views/doorkeeper/authorizations/error.html.erb +1 -1
  15. data/app/views/doorkeeper/authorizations/new.html.erb +17 -17
  16. data/app/views/doorkeeper/authorizations/show.html.erb +4 -0
  17. data/config/locales/en.yml +10 -0
  18. data/doorkeeper.gemspec +3 -3
  19. data/lib/doorkeeper.rb +11 -2
  20. data/lib/doorkeeper/config.rb +6 -1
  21. data/lib/doorkeeper/errors.rb +15 -0
  22. data/lib/doorkeeper/helpers/controller.rb +24 -0
  23. data/lib/doorkeeper/models/access_grant.rb +1 -1
  24. data/lib/doorkeeper/models/access_token.rb +2 -3
  25. data/lib/doorkeeper/models/active_record/access_token.rb +6 -0
  26. data/lib/doorkeeper/models/mongo_mapper/access_grant.rb +28 -0
  27. data/lib/doorkeeper/models/mongo_mapper/access_token.rb +51 -0
  28. data/lib/doorkeeper/models/mongo_mapper/application.rb +30 -0
  29. data/lib/doorkeeper/models/mongo_mapper/revocable.rb +15 -0
  30. data/lib/doorkeeper/models/{mongoid → mongoid2}/access_grant.rb +1 -1
  31. data/lib/doorkeeper/models/{mongoid → mongoid2}/access_token.rb +6 -0
  32. data/lib/doorkeeper/models/{mongoid → mongoid2}/application.rb +2 -2
  33. data/lib/doorkeeper/models/mongoid3/access_grant.rb +22 -0
  34. data/lib/doorkeeper/models/mongoid3/access_token.rb +41 -0
  35. data/lib/doorkeeper/models/mongoid3/application.rb +22 -0
  36. data/lib/doorkeeper/oauth/authorization/code.rb +9 -17
  37. data/lib/doorkeeper/oauth/authorization/token.rb +8 -18
  38. data/lib/doorkeeper/oauth/authorization/uri_builder.rb +2 -0
  39. data/lib/doorkeeper/oauth/authorization_code_request.rb +82 -0
  40. data/lib/doorkeeper/oauth/client_credentials_request.rb +2 -4
  41. data/lib/doorkeeper/oauth/code_request.rb +28 -0
  42. data/lib/doorkeeper/oauth/code_response.rb +37 -0
  43. data/lib/doorkeeper/oauth/error_response.rb +23 -9
  44. data/lib/doorkeeper/oauth/helpers/uri_checker.rb +4 -0
  45. data/lib/doorkeeper/oauth/password_access_token_request.rb +21 -65
  46. data/lib/doorkeeper/oauth/pre_authorization.rb +62 -0
  47. data/lib/doorkeeper/oauth/refresh_token_request.rb +58 -0
  48. data/lib/doorkeeper/oauth/token_request.rb +28 -0
  49. data/lib/doorkeeper/oauth/token_response.rb +29 -0
  50. data/lib/doorkeeper/rails/routes.rb +4 -3
  51. data/lib/doorkeeper/request.rb +33 -0
  52. data/lib/doorkeeper/request/authorization_code.rb +23 -0
  53. data/lib/doorkeeper/request/client_credentials.rb +23 -0
  54. data/lib/doorkeeper/request/code.rb +24 -0
  55. data/lib/doorkeeper/request/password.rb +23 -0
  56. data/lib/doorkeeper/request/refresh_token.rb +23 -0
  57. data/lib/doorkeeper/request/token.rb +24 -0
  58. data/lib/doorkeeper/server.rb +54 -0
  59. data/lib/doorkeeper/validations.rb +1 -0
  60. data/lib/doorkeeper/version.rb +1 -1
  61. data/lib/generators/doorkeeper/mongo_mapper/indexes_generator.rb +12 -0
  62. data/lib/generators/doorkeeper/templates/README +15 -1
  63. data/lib/generators/doorkeeper/templates/indexes.rb +3 -0
  64. data/lib/generators/doorkeeper/templates/initializer.rb +8 -1
  65. data/script/run_all +9 -9
  66. data/spec/controllers/authorizations_controller_spec.rb +8 -19
  67. data/spec/controllers/token_info_controller_spec.rb +9 -9
  68. data/spec/controllers/tokens_controller_spec.rb +2 -1
  69. data/spec/dummy/app/models/user.rb +11 -4
  70. data/spec/dummy/config/application.rb +8 -1
  71. data/spec/dummy/config/boot.rb +1 -1
  72. data/spec/dummy/config/initializers/doorkeeper.rb +9 -1
  73. data/spec/dummy/config/mongo.yml +11 -0
  74. data/spec/dummy/config/{mongoid.yml → mongoid2.yml} +3 -1
  75. data/spec/dummy/config/mongoid3.yml +18 -0
  76. data/spec/generators/install_generator_spec.rb +1 -0
  77. data/spec/lib/oauth/authorization_code_request_spec.rb +80 -0
  78. data/spec/lib/oauth/client_credentials_request_spec.rb +1 -3
  79. data/spec/lib/oauth/code_request_spec.rb +44 -0
  80. data/spec/lib/oauth/error_response_spec.rb +7 -7
  81. data/spec/lib/oauth/password_access_token_request_spec.rb +30 -143
  82. data/spec/lib/oauth/pre_authorization_spec.rb +80 -0
  83. data/spec/lib/oauth/refresh_token_request_spec.rb +56 -0
  84. data/spec/lib/oauth/token_request_spec.rb +46 -0
  85. data/spec/lib/oauth/{client_credentials/response_spec.rb → token_response_spec.rb} +13 -19
  86. data/spec/lib/server_spec.rb +24 -0
  87. data/spec/requests/endpoints/authorization_spec.rb +11 -27
  88. data/spec/requests/endpoints/token_spec.rb +17 -0
  89. data/spec/requests/flows/authorization_code_errors_spec.rb +0 -45
  90. data/spec/requests/flows/authorization_code_spec.rb +12 -2
  91. data/spec/requests/flows/client_credentials_spec.rb +1 -1
  92. data/spec/requests/flows/password_spec.rb +1 -0
  93. data/spec/requests/flows/refresh_token_spec.rb +6 -4
  94. data/spec/spec_helper_integration.rb +4 -2
  95. data/spec/support/orm/mongo_mapper.rb +26 -0
  96. data/spec/support/orm/mongoid.rb +7 -2
  97. data/spec/validators/redirect_uri_validator_spec.rb +11 -4
  98. metadata +67 -42
  99. data/gemfiles/gemfile.rails-3.1.x +0 -17
  100. data/gemfiles/gemfile.rails-3.2.x +0 -17
  101. data/lib/doorkeeper/oauth/access_token_request.rb +0 -139
  102. data/lib/doorkeeper/oauth/authorization_request.rb +0 -114
  103. data/lib/doorkeeper/oauth/client_credentials/response.rb +0 -42
  104. data/spec/lib/oauth/access_token_request_spec.rb +0 -246
  105. data/spec/lib/oauth/authorization_request_spec.rb +0 -287
@@ -18,6 +18,12 @@ module Doorkeeper
18
18
  index :token, :unique => true
19
19
  index :refresh_token, :unique => true, :sparse => true
20
20
 
21
+ def self.delete_all_for(application_id, resource_owner)
22
+ where(:application_id => application_id,
23
+ :resource_owner_id => resource_owner.id).delete_all
24
+ end
25
+ private_class_method :delete_all_for
26
+
21
27
  def self.last_authorized_token_for(application, resource_owner_id)
22
28
  where(:application_id => application.id,
23
29
  :resource_owner_id => resource_owner_id,
@@ -5,8 +5,6 @@ module Doorkeeper
5
5
 
6
6
  self.store_in :oauth_applications
7
7
 
8
- has_many :authorized_tokens, :class_name => "Doorkeeper::AccessToken"
9
-
10
8
  field :name, :type => String
11
9
  field :uid, :type => String
12
10
  field :secret, :type => String
@@ -14,6 +12,8 @@ module Doorkeeper
14
12
 
15
13
  index :uid, :unique => true
16
14
 
15
+ has_many :authorized_tokens, :class_name => "Doorkeeper::AccessToken"
16
+
17
17
  def self.authorized_for(resource_owner)
18
18
  ids = AccessToken.where(:resource_owner_id => resource_owner.id, :revoked_at => nil).map(&:application_id)
19
19
  find(ids)
@@ -0,0 +1,22 @@
1
+ require 'doorkeeper/models/mongoid/revocable'
2
+ require 'doorkeeper/models/mongoid/scopes'
3
+
4
+ module Doorkeeper
5
+ class AccessGrant
6
+ include Mongoid::Document
7
+ include Mongoid::Timestamps
8
+ include Doorkeeper::Models::Mongoid::Revocable
9
+ include Doorkeeper::Models::Mongoid::Scopes
10
+
11
+ self.store_in collection: :oauth_access_grants
12
+
13
+ field :resource_owner_id, :type => Moped::BSON::ObjectId
14
+ field :application_id, :type => Hash
15
+ field :token, :type => String
16
+ field :expires_in, :type => Integer
17
+ field :redirect_uri, :type => String
18
+ field :revoked_at, :type => DateTime
19
+
20
+ index({ token: 1 }, { unique: true })
21
+ end
22
+ end
@@ -0,0 +1,41 @@
1
+ require 'doorkeeper/models/mongoid/revocable'
2
+ require 'doorkeeper/models/mongoid/scopes'
3
+
4
+ module Doorkeeper
5
+ class AccessToken
6
+ include Mongoid::Document
7
+ include Mongoid::Timestamps
8
+ include Doorkeeper::Models::Mongoid::Revocable
9
+ include Doorkeeper::Models::Mongoid::Scopes
10
+
11
+ self.store_in collection: :oauth_access_tokens
12
+
13
+ field :resource_owner_id, :type => Moped::BSON::ObjectId
14
+ field :token, :type => String
15
+ field :expires_in, :type => Integer
16
+ field :revoked_at, :type => DateTime
17
+
18
+ index({ token: 1 }, { unique: true })
19
+ index({ refresh_token: 1 }, { unique: true, sparse: true })
20
+
21
+ def self.delete_all_for(application_id, resource_owner)
22
+ where(:application_id => application_id,
23
+ :resource_owner_id => resource_owner.id).delete_all
24
+ end
25
+ private_class_method :delete_all_for
26
+
27
+ def self.last_authorized_token_for(application, resource_owner_id)
28
+ where(:application_id => application.id,
29
+ :resource_owner_id => resource_owner_id,
30
+ :revoked_at => nil).
31
+ order_by([:created_at, :desc]).
32
+ limit(1).
33
+ first
34
+ end
35
+ private_class_method :last_authorized_token_for
36
+
37
+ def refresh_token
38
+ self[:refresh_token]
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,22 @@
1
+ module Doorkeeper
2
+ class Application
3
+ include Mongoid::Document
4
+ include Mongoid::Timestamps
5
+
6
+ self.store_in collection: :oauth_applications
7
+
8
+ field :name, :type => String
9
+ field :uid, :type => String
10
+ field :secret, :type => String
11
+ field :redirect_uri, :type => String
12
+
13
+ index({ uid: 1 }, { unique: true })
14
+
15
+ has_many :authorized_tokens, :class_name => "Doorkeeper::AccessToken"
16
+
17
+ def self.authorized_for(resource_owner)
18
+ ids = AccessToken.where(:resource_owner_id => resource_owner.id, :revoked_at => nil).map(&:application_id)
19
+ find(ids)
20
+ end
21
+ end
22
+ end
@@ -2,31 +2,23 @@ module Doorkeeper
2
2
  module OAuth
3
3
  module Authorization
4
4
  class Code
5
- include URIBuilder
5
+ attr_accessor :pre_auth, :resource_owner, :token
6
6
 
7
- attr_accessor :authorization, :grant
8
-
9
- def initialize(authorization)
10
- @authorization = authorization
7
+ def initialize(pre_auth, resource_owner)
8
+ @pre_auth = pre_auth
9
+ @resource_owner = resource_owner
11
10
  end
12
11
 
13
12
  def issue_token
14
- @grant ||= AccessGrant.create!(
15
- :application_id => authorization.client.id,
16
- :resource_owner_id => authorization.resource_owner.id,
13
+ @token ||= AccessGrant.create!(
14
+ :application_id => pre_auth.client.id,
15
+ :resource_owner_id => resource_owner.id,
17
16
  :expires_in => configuration.authorization_code_expires_in,
18
- :redirect_uri => authorization.redirect_uri,
19
- :scopes => authorization.scopes.to_s
17
+ :redirect_uri => pre_auth.redirect_uri,
18
+ :scopes => pre_auth.scopes.to_s
20
19
  )
21
20
  end
22
21
 
23
- def callback
24
- uri_with_query(authorization.redirect_uri, {
25
- :code => grant.token,
26
- :state => authorization.state
27
- })
28
- end
29
-
30
22
  def configuration
31
23
  Doorkeeper.configuration
32
24
  end
@@ -2,28 +2,18 @@ module Doorkeeper
2
2
  module OAuth
3
3
  module Authorization
4
4
  class Token
5
- include URIBuilder
5
+ attr_accessor :pre_auth, :resource_owner, :token
6
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.expires_in,
18
- :state => authorization.state
19
- })
7
+ def initialize(pre_auth, resource_owner)
8
+ @pre_auth = pre_auth
9
+ @resource_owner = resource_owner
20
10
  end
21
11
 
22
12
  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.scopes.to_s,
13
+ @token ||= AccessToken.create!({
14
+ :application_id => pre_auth.client.id,
15
+ :resource_owner_id => resource_owner.id,
16
+ :scopes => pre_auth.scopes.to_s,
27
17
  :expires_in => configuration.access_token_expires_in,
28
18
  :use_refresh_token => false
29
19
  })
@@ -4,6 +4,8 @@ module Doorkeeper
4
4
  module URIBuilder
5
5
  include Rack::Utils
6
6
 
7
+ extend self
8
+
7
9
  def uri_with_query(url, parameters = {})
8
10
  uri = URI.parse(url)
9
11
  original_query = parse_query(uri.query)
@@ -0,0 +1,82 @@
1
+ module Doorkeeper
2
+ module OAuth
3
+ class AuthorizationCodeRequest
4
+ include Doorkeeper::Validations
5
+
6
+ validate :attributes, :error => :invalid_request
7
+ validate :client, :error => :invalid_client
8
+ validate :grant, :error => :invalid_grant
9
+ validate :redirect_uri, :error => :invalid_grant
10
+
11
+ attr_accessor :server, :grant, :client, :redirect_uri
12
+
13
+ def initialize(server, grant, client, parameters = {})
14
+ @server = server
15
+ @client = client
16
+ @grant = grant
17
+ @redirect_uri = parameters[:redirect_uri]
18
+ end
19
+
20
+ def authorize
21
+ validate
22
+ @response = if valid?
23
+ grant.revoke
24
+ find_or_create_access_token
25
+ TokenResponse.new access_token
26
+ else
27
+ ErrorResponse.from_request self
28
+ end
29
+ end
30
+
31
+ def valid?
32
+ self.error.nil?
33
+ end
34
+
35
+ def access_token
36
+ @access_token ||= Doorkeeper::AccessToken.matching_token_for client, grant.resource_owner_id, grant.scopes
37
+ end
38
+
39
+ private
40
+
41
+ def find_or_create_access_token
42
+ if access_token
43
+ access_token.expired? ? revoke_and_create_access_token : access_token
44
+ else
45
+ create_access_token
46
+ end
47
+ end
48
+
49
+ def revoke_and_create_access_token
50
+ access_token.revoke
51
+ create_access_token
52
+ end
53
+
54
+ def create_access_token
55
+ @access_token = Doorkeeper::AccessToken.create!({
56
+ :application_id => grant.application_id,
57
+ :resource_owner_id => grant.resource_owner_id,
58
+ :scopes => grant.scopes_string,
59
+ :expires_in => server.access_token_expires_in,
60
+ :use_refresh_token => server.refresh_token_enabled?
61
+ })
62
+ end
63
+
64
+ def validate_attributes
65
+ redirect_uri.present?
66
+ end
67
+
68
+ def validate_client
69
+ !!client
70
+ end
71
+
72
+ def validate_grant
73
+ return false unless grant && grant.application_id == client.id
74
+ grant.accessible?
75
+ end
76
+
77
+ def validate_redirect_uri
78
+ grant.redirect_uri == redirect_uri
79
+ end
80
+ end
81
+ end
82
+ end
@@ -1,9 +1,9 @@
1
1
  require 'doorkeeper/oauth/error'
2
2
  require 'doorkeeper/oauth/error_response'
3
3
  require 'doorkeeper/oauth/scopes'
4
+ require 'doorkeeper/oauth/token_response'
4
5
  require 'doorkeeper/oauth/client_credentials/creator'
5
6
  require 'doorkeeper/oauth/client_credentials/issuer'
6
- require 'doorkeeper/oauth/client_credentials/response'
7
7
  require 'doorkeeper/oauth/client_credentials/validation'
8
8
 
9
9
  module Doorkeeper
@@ -11,7 +11,6 @@ module Doorkeeper
11
11
  class ClientCredentialsRequest
12
12
  attr_accessor :issuer, :server, :client, :original_scopes, :scopes
13
13
  attr_reader :response
14
- alias :authorization :response # Remove this when API is consistent
15
14
  alias :error_response :response
16
15
 
17
16
  delegate :error, :to => :issuer
@@ -29,11 +28,10 @@ module Doorkeeper
29
28
  def authorize
30
29
  status = issuer.create(client, scopes)
31
30
  @response = if status
32
- Response.new(issuer.token)
31
+ TokenResponse.new(issuer.token)
33
32
  else
34
33
  ErrorResponse.from_request(self)
35
34
  end
36
- status
37
35
  end
38
36
 
39
37
  # TODO: duplicated code in all flows
@@ -0,0 +1,28 @@
1
+ module Doorkeeper
2
+ module OAuth
3
+ class CodeRequest
4
+ attr_accessor :pre_auth, :resource_owner, :client
5
+
6
+ def initialize(pre_auth, resource_owner)
7
+ @pre_auth = pre_auth
8
+ @client = pre_auth.client
9
+ @resource_owner = resource_owner
10
+ end
11
+
12
+ def authorize
13
+ @response = if pre_auth.authorizable?
14
+ auth = Authorization::Code.new(pre_auth, resource_owner)
15
+ auth.issue_token
16
+ CodeResponse.new pre_auth, auth
17
+ else
18
+ ErrorResponse.from_request pre_auth
19
+ end
20
+ end
21
+
22
+ def deny
23
+ pre_auth.error = :access_denied
24
+ ErrorResponse.from_request(pre_auth, :redirect_uri => pre_auth.redirect_uri)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,37 @@
1
+ module Doorkeeper
2
+ module OAuth
3
+ class CodeResponse
4
+ include Doorkeeper::OAuth::Authorization::URIBuilder
5
+ include Doorkeeper::OAuth::Helpers
6
+
7
+ attr_accessor :pre_auth, :auth, :response_on_fragment
8
+
9
+ def initialize(pre_auth, auth, options = {})
10
+ @pre_auth, @auth = pre_auth, auth
11
+ @response_on_fragment = options[:response_on_fragment]
12
+ end
13
+
14
+ def redirectable?
15
+ true
16
+ end
17
+
18
+ # TODO: configure the test oauth path?
19
+ def redirect_uri
20
+ if URIChecker.test_uri? pre_auth.redirect_uri
21
+ "/oauth/authorize/#{auth.token.token}"
22
+ else
23
+ if response_on_fragment
24
+ uri_with_fragment(pre_auth.redirect_uri, {
25
+ :access_token => auth.token.token,
26
+ :token_type => auth.token.token_type,
27
+ :expires_in => auth.token.expires_in,
28
+ :state => pre_auth.state
29
+ })
30
+ else
31
+ uri_with_query pre_auth.redirect_uri, :code => auth.token.token, :state => pre_auth.state
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -1,30 +1,44 @@
1
1
  module Doorkeeper
2
2
  module OAuth
3
3
  class ErrorResponse
4
- include ActiveModel::Serializers::JSON
4
+ include Doorkeeper::OAuth::Authorization::URIBuilder
5
5
 
6
- self.include_root_in_json = false
7
-
8
- def self.from_request(request)
6
+ def self.from_request(request, attributes = {})
9
7
  state = request.state if request.respond_to?(:state)
10
- new(:name => request.error, :state => state)
8
+ new(attributes.merge(:name => request.error, :state => state))
11
9
  end
12
10
 
13
11
  delegate :name, :description, :state, :to => :@error
14
- alias :error :name
15
- alias :error_description :description
16
12
 
17
13
  def initialize(attributes = {})
18
14
  @error = Doorkeeper::OAuth::Error.new(*attributes.values_at(:name, :state))
15
+ @redirect_uri = attributes[:redirect_uri]
16
+ @response_on_fragment = attributes[:response_on_fragment]
19
17
  end
20
18
 
21
- def attributes
22
- { 'error' => name, 'error_description' => description, 'state' => state }.reject { |k, v| v.blank? }
19
+ def body
20
+ { :error => name, :error_description => description, :state => state }.reject { |k, v| v.blank? }
23
21
  end
24
22
 
25
23
  def status
26
24
  :unauthorized
27
25
  end
26
+
27
+ def redirectable?
28
+ (name != :invalid_redirect_uri) && (name != :invalid_client)
29
+ end
30
+
31
+ def redirect_uri
32
+ if @response_on_fragment
33
+ uri_with_fragment @redirect_uri, body
34
+ else
35
+ uri_with_query @redirect_uri, body
36
+ end
37
+ end
38
+
39
+ def headers
40
+ { 'Cache-Control' => 'no-store', 'Pragma' => 'no-cache' }
41
+ end
28
42
  end
29
43
  end
30
44
  end