devise 1.0.11 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (176) hide show
  1. data/CHANGELOG.rdoc +59 -13
  2. data/Gemfile +23 -0
  3. data/Gemfile.lock +118 -0
  4. data/README.rdoc +116 -77
  5. data/Rakefile +4 -2
  6. data/TODO +3 -2
  7. data/app/controllers/{confirmations_controller.rb → devise/confirmations_controller.rb} +1 -1
  8. data/app/controllers/{passwords_controller.rb → devise/passwords_controller.rb} +1 -1
  9. data/app/controllers/{registrations_controller.rb → devise/registrations_controller.rb} +12 -8
  10. data/app/controllers/devise/sessions_controller.rb +23 -0
  11. data/app/controllers/{unlocks_controller.rb → devise/unlocks_controller.rb} +1 -8
  12. data/app/helpers/devise_helper.rb +17 -0
  13. data/app/mailers/devise/mailer.rb +71 -0
  14. data/app/views/devise/confirmations/new.html.erb +12 -0
  15. data/app/views/devise/passwords/edit.html.erb +16 -0
  16. data/app/views/devise/passwords/new.html.erb +12 -0
  17. data/app/views/devise/registrations/edit.html.erb +25 -0
  18. data/app/views/devise/registrations/new.html.erb +18 -0
  19. data/app/views/devise/sessions/new.html.erb +17 -0
  20. data/app/views/devise/shared/_links.erb +19 -0
  21. data/app/views/devise/unlocks/new.html.erb +12 -0
  22. data/{lib/devise → config}/locales/en.yml +16 -12
  23. data/lib/devise/controllers/helpers.rb +57 -52
  24. data/lib/devise/controllers/internal_helpers.rb +19 -50
  25. data/lib/devise/controllers/scoped_views.rb +35 -0
  26. data/lib/devise/controllers/url_helpers.rb +1 -1
  27. data/lib/devise/encryptors/authlogic_sha512.rb +0 -2
  28. data/lib/devise/encryptors/base.rb +1 -1
  29. data/lib/devise/encryptors/bcrypt.rb +2 -4
  30. data/lib/devise/encryptors/clearance_sha1.rb +0 -2
  31. data/lib/devise/encryptors/sha1.rb +6 -8
  32. data/lib/devise/encryptors/sha512.rb +6 -8
  33. data/lib/devise/failure_app.rb +76 -41
  34. data/lib/devise/hooks/activatable.rb +6 -10
  35. data/lib/devise/hooks/forgetable.rb +11 -0
  36. data/lib/devise/hooks/rememberable.rb +40 -30
  37. data/lib/devise/hooks/timeoutable.rb +7 -3
  38. data/lib/devise/hooks/trackable.rb +5 -14
  39. data/lib/devise/mapping.rb +35 -62
  40. data/lib/devise/models/authenticatable.rb +126 -0
  41. data/lib/devise/models/confirmable.rb +19 -22
  42. data/lib/devise/models/database_authenticatable.rb +26 -60
  43. data/lib/devise/models/lockable.rb +43 -28
  44. data/lib/devise/models/recoverable.rb +11 -10
  45. data/lib/devise/models/rememberable.rb +56 -26
  46. data/lib/devise/models/timeoutable.rb +1 -3
  47. data/lib/devise/models/token_authenticatable.rb +14 -43
  48. data/lib/devise/models/trackable.rb +14 -0
  49. data/lib/devise/models/validatable.rb +16 -2
  50. data/lib/devise/models.rb +16 -53
  51. data/lib/devise/modules.rb +23 -0
  52. data/lib/devise/orm/active_record.rb +10 -15
  53. data/lib/devise/orm/mongoid.rb +29 -0
  54. data/lib/devise/path_checker.rb +18 -0
  55. data/lib/devise/rails/routes.rb +232 -117
  56. data/lib/devise/rails/warden_compat.rb +17 -41
  57. data/lib/devise/rails.rb +64 -9
  58. data/lib/devise/schema.rb +47 -23
  59. data/lib/devise/strategies/authenticatable.rb +123 -0
  60. data/lib/devise/strategies/base.rb +2 -3
  61. data/lib/devise/strategies/database_authenticatable.rb +7 -22
  62. data/lib/devise/strategies/rememberable.rb +21 -7
  63. data/lib/devise/strategies/token_authenticatable.rb +31 -19
  64. data/lib/devise/test_helpers.rb +6 -6
  65. data/lib/devise/version.rb +1 -1
  66. data/lib/devise.rb +174 -157
  67. data/lib/generators/active_record/devise_generator.rb +28 -0
  68. data/{generators/devise → lib/generators/active_record}/templates/migration.rb +9 -3
  69. data/lib/generators/devise/devise_generator.rb +17 -0
  70. data/lib/generators/devise/install_generator.rb +24 -0
  71. data/lib/generators/devise/orm_helpers.rb +23 -0
  72. data/{generators/devise_install → lib/generators/devise}/templates/README +9 -7
  73. data/lib/generators/devise/templates/devise.rb +142 -0
  74. data/lib/generators/devise/views_generator.rb +63 -0
  75. data/lib/generators/devise_install_generator.rb +4 -0
  76. data/lib/generators/devise_views_generator.rb +4 -0
  77. data/lib/generators/mongoid/devise_generator.rb +17 -0
  78. data/test/controllers/helpers_test.rb +48 -19
  79. data/test/controllers/internal_helpers_test.rb +12 -16
  80. data/test/controllers/url_helpers_test.rb +21 -10
  81. data/test/devise_test.rb +16 -25
  82. data/test/encryptors_test.rb +2 -3
  83. data/test/failure_app_test.rb +106 -27
  84. data/test/integration/authenticatable_test.rb +135 -131
  85. data/test/integration/confirmable_test.rb +22 -15
  86. data/test/integration/database_authenticatable_test.rb +38 -0
  87. data/test/integration/http_authenticatable_test.rb +9 -12
  88. data/test/integration/lockable_test.rb +22 -15
  89. data/test/integration/recoverable_test.rb +6 -6
  90. data/test/integration/registerable_test.rb +42 -33
  91. data/test/integration/rememberable_test.rb +84 -22
  92. data/test/integration/timeoutable_test.rb +16 -4
  93. data/test/integration/token_authenticatable_test.rb +45 -12
  94. data/test/integration/trackable_test.rb +1 -1
  95. data/test/mailers/confirmation_instructions_test.rb +11 -17
  96. data/test/mailers/reset_password_instructions_test.rb +7 -7
  97. data/test/mailers/unlock_instructions_test.rb +7 -7
  98. data/test/mapping_test.rb +22 -95
  99. data/test/models/confirmable_test.rb +12 -19
  100. data/test/models/{authenticatable_test.rb → database_authenticatable_test.rb} +24 -56
  101. data/test/models/lockable_test.rb +32 -46
  102. data/test/models/recoverable_test.rb +7 -7
  103. data/test/models/rememberable_test.rb +118 -35
  104. data/test/models/timeoutable_test.rb +1 -1
  105. data/test/models/token_authenticatable_test.rb +5 -19
  106. data/test/models/trackable_test.rb +1 -1
  107. data/test/models/validatable_test.rb +20 -27
  108. data/test/models_test.rb +12 -5
  109. data/test/orm/active_record.rb +1 -23
  110. data/test/orm/mongoid.rb +10 -0
  111. data/test/rails_app/app/active_record/admin.rb +1 -5
  112. data/test/rails_app/app/active_record/shim.rb +2 -0
  113. data/test/rails_app/app/active_record/user.rb +3 -3
  114. data/test/rails_app/app/controllers/application_controller.rb +2 -5
  115. data/test/rails_app/app/controllers/home_controller.rb +3 -0
  116. data/test/rails_app/app/controllers/publisher/registrations_controller.rb +2 -0
  117. data/test/rails_app/app/controllers/publisher/sessions_controller.rb +2 -0
  118. data/test/rails_app/app/controllers/sessions_controller.rb +6 -0
  119. data/test/rails_app/app/controllers/users_controller.rb +7 -5
  120. data/test/rails_app/app/mongoid/admin.rb +6 -0
  121. data/test/rails_app/app/mongoid/shim.rb +16 -0
  122. data/test/rails_app/app/mongoid/user.rb +10 -0
  123. data/test/rails_app/config/application.rb +35 -0
  124. data/test/rails_app/config/boot.rb +10 -107
  125. data/test/rails_app/config/environment.rb +4 -41
  126. data/test/rails_app/config/environments/development.rb +15 -13
  127. data/test/rails_app/config/environments/production.rb +25 -20
  128. data/test/rails_app/config/environments/test.rb +33 -28
  129. data/test/rails_app/config/initializers/backtrace_silencers.rb +7 -0
  130. data/test/rails_app/config/initializers/devise.rb +95 -38
  131. data/test/rails_app/config/initializers/secret_token.rb +2 -0
  132. data/test/rails_app/config/routes.rb +47 -25
  133. data/test/rails_app/db/migrate/20100401102949_create_tables.rb +27 -0
  134. data/test/rails_app/db/schema.rb +86 -0
  135. data/test/routes_test.rb +62 -47
  136. data/test/support/{assertions_helper.rb → assertions.rb} +2 -15
  137. data/test/support/{tests_helper.rb → helpers.rb} +18 -3
  138. data/test/support/{integration_tests_helper.rb → integration.rb} +24 -7
  139. data/test/support/webrat/integrations/rails.rb +32 -0
  140. data/test/test_helper.rb +11 -11
  141. data/test/test_helpers_test.rb +30 -15
  142. metadata +107 -66
  143. data/app/controllers/sessions_controller.rb +0 -42
  144. data/app/models/devise_mailer.rb +0 -68
  145. data/app/views/confirmations/new.html.erb +0 -12
  146. data/app/views/passwords/edit.html.erb +0 -16
  147. data/app/views/passwords/new.html.erb +0 -12
  148. data/app/views/registrations/edit.html.erb +0 -25
  149. data/app/views/registrations/new.html.erb +0 -17
  150. data/app/views/sessions/new.html.erb +0 -17
  151. data/app/views/shared/_devise_links.erb +0 -19
  152. data/app/views/unlocks/new.html.erb +0 -12
  153. data/generators/devise/USAGE +0 -5
  154. data/generators/devise/devise_generator.rb +0 -15
  155. data/generators/devise/lib/route_devise.rb +0 -32
  156. data/generators/devise/templates/model.rb +0 -9
  157. data/generators/devise_install/USAGE +0 -3
  158. data/generators/devise_install/devise_install_generator.rb +0 -15
  159. data/generators/devise_install/templates/devise.rb +0 -105
  160. data/generators/devise_views/USAGE +0 -3
  161. data/generators/devise_views/devise_views_generator.rb +0 -21
  162. data/lib/devise/models/activatable.rb +0 -16
  163. data/lib/devise/models/http_authenticatable.rb +0 -23
  164. data/lib/devise/orm/data_mapper.rb +0 -83
  165. data/lib/devise/orm/mongo_mapper.rb +0 -52
  166. data/lib/devise/strategies/http_authenticatable.rb +0 -59
  167. data/rails/init.rb +0 -2
  168. data/test/integration/rack_middleware_test.rb +0 -47
  169. data/test/orm/mongo_mapper.rb +0 -20
  170. data/test/rails_app/app/mongo_mapper/admin.rb +0 -13
  171. data/test/rails_app/app/mongo_mapper/user.rb +0 -14
  172. data/test/rails_app/config/initializers/new_rails_defaults.rb +0 -24
  173. data/test/rails_app/config/initializers/session_store.rb +0 -15
  174. /data/app/views/{devise_mailer → devise/mailer}/confirmation_instructions.html.erb +0 -0
  175. /data/app/views/{devise_mailer → devise/mailer}/reset_password_instructions.html.erb +0 -0
  176. /data/app/views/{devise_mailer → devise/mailer}/unlock_instructions.html.erb +0 -0
@@ -0,0 +1,123 @@
1
+ require 'devise/strategies/base'
2
+
3
+ module Devise
4
+ module Strategies
5
+ # This strategy should be used as basis for authentication strategies. It retrieves
6
+ # parameters both from params or from http authorization headers. See database_authenticatable
7
+ # for an example.
8
+ class Authenticatable < Base
9
+ attr_accessor :authentication_hash, :password
10
+
11
+ def valid?
12
+ valid_for_http_auth? || valid_for_params_auth?
13
+ end
14
+
15
+ private
16
+
17
+ # Simply invokes valid_for_authentication? with the given block and deal with the result.
18
+ def validate(resource, &block)
19
+ result = resource && resource.valid_for_authentication?(&block)
20
+
21
+ case result
22
+ when Symbol, String
23
+ fail!(result)
24
+ else
25
+ result
26
+ end
27
+ end
28
+
29
+ # Check if this is strategy is valid for http authentication by:
30
+ #
31
+ # * Validating if the model allows params authentication;
32
+ # * If any of the authorization headers were sent;
33
+ # * If all authentication keys are present;
34
+ #
35
+ def valid_for_http_auth?
36
+ http_authenticatable? && request.authorization && with_authentication_hash(http_auth_hash)
37
+ end
38
+
39
+ # Check if this is strategy is valid for params authentication by:
40
+ #
41
+ # * Validating if the model allows params authentication;
42
+ # * If the request hits the sessions controller through POST;
43
+ # * If the params[scope] returns a hash with credentials;
44
+ # * If all authentication keys are present;
45
+ #
46
+ def valid_for_params_auth?
47
+ params_authenticatable? && valid_request? &&
48
+ valid_params? && with_authentication_hash(params_auth_hash)
49
+ end
50
+
51
+ # Check if the model accepts this strategy as http authenticatable.
52
+ def http_authenticatable?
53
+ mapping.to.http_authenticatable?(authenticatable_name)
54
+ end
55
+
56
+ # Check if the model accepts this strategy as params authenticatable.
57
+ def params_authenticatable?
58
+ mapping.to.params_authenticatable?(authenticatable_name)
59
+ end
60
+
61
+ # Extract the appropriate subhash for authentication from params.
62
+ def params_auth_hash
63
+ params[scope]
64
+ end
65
+
66
+ # Extract a hash with attributes:values from the http params.
67
+ def http_auth_hash
68
+ keys = [authentication_keys.first, :password]
69
+ Hash[*keys.zip(decode_credentials).flatten]
70
+ end
71
+
72
+ # By default, a request is valid if the controller is allowed and the VERB is POST.
73
+ def valid_request?
74
+ valid_controller? && valid_verb?
75
+ end
76
+
77
+ # Check if the controller is the one registered for authentication.
78
+ def valid_controller?
79
+ mapping.controllers[:sessions] == params[:controller]
80
+ end
81
+
82
+ # Check if it was a POST request.
83
+ def valid_verb?
84
+ request.post?
85
+ end
86
+
87
+ # If the request is valid, finally check if params_auth_hash returns a hash.
88
+ def valid_params?
89
+ params_auth_hash.is_a?(Hash)
90
+ end
91
+
92
+ # Check if password is present and is not equal to "X" (default value for token).
93
+ def valid_password?
94
+ password.present? && password != "X"
95
+ end
96
+
97
+ # Helper to decode credentials from HTTP.
98
+ def decode_credentials
99
+ username_and_password = request.authorization.split(' ', 2).last || ''
100
+ ActiveSupport::Base64.decode64(username_and_password).split(/:/, 2)
101
+ end
102
+
103
+ # Sets the authentication hash and the password from params_auth_hash or http_auth_hash.
104
+ def with_authentication_hash(hash)
105
+ self.authentication_hash = hash.slice(*authentication_keys)
106
+ self.password = hash[:password]
107
+ authentication_keys.all?{ |k| authentication_hash[k].present? }
108
+ end
109
+
110
+ # Holds the authentication keys.
111
+ def authentication_keys
112
+ @authentication_keys ||= mapping.to.authentication_keys
113
+ end
114
+
115
+ # Holds the authenticatable name for this class. Devise::Strategies::DatabaseAuthenticatable
116
+ # becomes simply :database.
117
+ def authenticatable_name
118
+ @authenticatable_name ||=
119
+ self.class.name.split("::").last.underscore.sub("_authenticatable", "").to_sym
120
+ end
121
+ end
122
+ end
123
+ end
@@ -2,8 +2,7 @@ module Devise
2
2
  module Strategies
3
3
  # Base strategy for Devise. Responsible for verifying correct scope and mapping.
4
4
  class Base < ::Warden::Strategies::Base
5
- # Checks if a valid scope was given for devise and find mapping based on
6
- # this scope.
5
+ # Checks if a valid scope was given for devise and find mapping based on this scope.
7
6
  def mapping
8
7
  @mapping ||= begin
9
8
  mapping = Devise.mappings[scope]
@@ -13,4 +12,4 @@ module Devise
13
12
  end
14
13
  end
15
14
  end
16
- end
15
+ end
@@ -1,34 +1,19 @@
1
- require 'devise/strategies/base'
1
+ require 'devise/strategies/authenticatable'
2
2
 
3
3
  module Devise
4
4
  module Strategies
5
- # Default strategy for signing in a user, based on his email and password.
6
- # Redirects to sign_in page if it's not authenticated
7
- class DatabaseAuthenticatable < Base
8
- def valid?
9
- valid_controller? && valid_params? && mapping.to.respond_to?(:authenticate)
10
- end
11
-
12
- # Authenticate a user based on email and password params, returning to warden
13
- # success and the authenticated user if everything is okay. Otherwise redirect
14
- # to sign in page.
5
+ # Default strategy for signing in a user, based on his email and password in the database.
6
+ class DatabaseAuthenticatable < Authenticatable
15
7
  def authenticate!
16
- if resource = mapping.to.authenticate(params[scope])
8
+ resource = valid_password? && mapping.to.find_for_database_authentication(authentication_hash)
9
+
10
+ if validate(resource){ resource.valid_password?(password) }
11
+ resource.after_database_authentication
17
12
  success!(resource)
18
13
  else
19
14
  fail(:invalid)
20
15
  end
21
16
  end
22
-
23
- protected
24
-
25
- def valid_controller?
26
- params[:controller] =~ /sessions$/
27
- end
28
-
29
- def valid_params?
30
- params[scope] && params[scope][:password].present?
31
- end
32
17
  end
33
18
  end
34
19
  end
@@ -4,31 +4,45 @@ module Devise
4
4
  module Strategies
5
5
  # Remember the user through the remember token. This strategy is responsible
6
6
  # to verify whether there is a cookie with the remember token, and to
7
- # recreate the user from this cookie if it exists. Must be called *before*
7
+ # recreate the user from this cookie if it exists. Must be called *before*
8
8
  # authenticatable.
9
- class Rememberable < Devise::Strategies::Base
10
-
9
+ class Rememberable < Authenticatable
11
10
  # A valid strategy for rememberable needs a remember token in the cookies.
12
11
  def valid?
13
- remember_me_cookie.present? && mapping.to.respond_to?(:serialize_from_cookie)
12
+ remember_cookie.present?
14
13
  end
15
14
 
16
15
  # To authenticate a user we deserialize the cookie and attempt finding
17
16
  # the record in the database. If the attempt fails, we pass to another
18
17
  # strategy handle the authentication.
19
18
  def authenticate!
20
- if resource = mapping.to.serialize_from_cookie(remember_me_cookie)
19
+ resource = mapping.to.serialize_from_cookie(*remember_cookie)
20
+
21
+ if validate(resource)
21
22
  success!(resource)
22
23
  else
24
+ cookies.delete(remember_key)
23
25
  pass
24
26
  end
25
27
  end
26
28
 
27
29
  private
28
30
 
31
+ def remember_me?
32
+ true
33
+ end
34
+
35
+ def remember_key
36
+ "remember_#{scope}_token"
37
+ end
38
+
39
+ def extend_remember_period?
40
+ mapping.to.extend_remember_period
41
+ end
42
+
29
43
  # Accessor for remember cookie
30
- def remember_me_cookie
31
- @remember_me_cookie ||= request.cookies["remember_#{mapping.name}_token"]
44
+ def remember_cookie
45
+ @remember_cookie ||= cookies.signed[remember_key]
32
46
  end
33
47
  end
34
48
  end
@@ -2,33 +2,45 @@ require 'devise/strategies/base'
2
2
 
3
3
  module Devise
4
4
  module Strategies
5
- # Strategy for signing in a user, based on a authenticatable token.
6
- # Redirects to sign_in page if it's not authenticated.
7
- class TokenAuthenticatable < Base
8
- def valid?
9
- mapping.to.respond_to?(:authenticate_with_token) && authentication_token(scope).present?
10
- end
11
-
12
- # Authenticate a user based on authenticatable token params, returning to warden
13
- # success and the authenticated user if everything is okay. Otherwise redirect
14
- # to sign in page.
5
+ # Strategy for signing in a user, based on a authenticatable token. This works for both params
6
+ # and http. For the former, all you need to do is to pass the params in the URL:
7
+ #
8
+ # http://myapp.example.com/?user_token=SECRET
9
+ #
10
+ # For HTTP, you can pass the token as username and blank password. Since some clients may require
11
+ # a password, you can pass "X" as password and it will simply be ignored.
12
+ class TokenAuthenticatable < Authenticatable
15
13
  def authenticate!
16
- if resource = mapping.to.authenticate_with_token(params[scope] || params)
14
+ resource = mapping.to.find_for_token_authentication(authentication_hash)
15
+
16
+ if validate(resource)
17
+ resource.after_token_authentication
17
18
  success!(resource)
18
19
  else
19
- fail!(:invalid_token)
20
+ fail(:invalid_token)
20
21
  end
21
22
  end
22
23
 
23
24
  private
24
25
 
25
- # Detect authentication token in params: scoped or not.
26
- def authentication_token(scope)
27
- if params[scope]
28
- params[scope][mapping.to.token_authentication_key]
29
- else
30
- params[mapping.to.token_authentication_key]
31
- end
26
+ # TokenAuthenticatable request is valid for any controller and any verb.
27
+ def valid_request?
28
+ true
29
+ end
30
+
31
+ # Do not use remember_me behavir with token.
32
+ def remember_me?
33
+ false
34
+ end
35
+
36
+ # Try both scoped and non scoped keys.
37
+ def params_auth_hash
38
+ params[scope] || params
39
+ end
40
+
41
+ # Overwrite authentication keys to use token_authentication_key.
42
+ def authentication_keys
43
+ @authentication_keys ||= [mapping.to.token_authentication_key]
32
44
  end
33
45
  end
34
46
  end
@@ -15,7 +15,7 @@ module Devise
15
15
  def initialize(controller)
16
16
  @controller = controller
17
17
  manager = Warden::Manager.new(nil) do |config|
18
- Devise.configure_warden(config)
18
+ config.merge! Devise.warden_config
19
19
  end
20
20
  super(controller.request.env, manager)
21
21
  end
@@ -40,7 +40,10 @@ module Devise
40
40
  Warden::Manager._before_failure.each{ |hook| hook.call(env, result) }
41
41
 
42
42
  status, headers, body = Devise::FailureApp.call(env).to_a
43
- @controller.send :redirect_to, headers["Location"]
43
+ @controller.send :render, :status => status, :text => body,
44
+ :content_type => headers["Content-Type"], :location => headers["Location"]
45
+
46
+ nil
44
47
  else
45
48
  result
46
49
  end
@@ -49,10 +52,7 @@ module Devise
49
52
 
50
53
  # We need to setup the environment variables and the response in the controller.
51
54
  def setup_controller_for_warden #:nodoc:
52
- @request.env['action_controller.rescue.request'] = @request
53
- @request.env['action_controller.rescue.response'] = @response
54
- @request.env['rack.session'] = session
55
- @controller.response = @response
55
+ @request.env['action_controller.instance'] = @controller
56
56
  end
57
57
 
58
58
  # Quick access to Warden::Proxy.
@@ -1,3 +1,3 @@
1
1
  module Devise
2
- VERSION = "1.0.11".freeze
2
+ VERSION = "1.1.0".freeze
3
3
  end