devise 0.1.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of devise might be problematic. Click here for more details.

Files changed (74) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.rdoc +220 -0
  3. data/Rakefile +45 -0
  4. data/TODO +37 -0
  5. data/app/controllers/confirmations_controller.rb +32 -0
  6. data/app/controllers/passwords_controller.rb +38 -0
  7. data/app/controllers/sessions_controller.rb +35 -0
  8. data/app/models/notifier.rb +47 -0
  9. data/app/views/confirmations/new.html.erb +16 -0
  10. data/app/views/notifier/confirmation_instructions.html.erb +5 -0
  11. data/app/views/notifier/reset_password_instructions.html.erb +8 -0
  12. data/app/views/passwords/edit.html.erb +20 -0
  13. data/app/views/passwords/new.html.erb +16 -0
  14. data/app/views/sessions/new.html.erb +23 -0
  15. data/config/locales/en.yml +16 -0
  16. data/init.rb +2 -0
  17. data/lib/devise.rb +48 -0
  18. data/lib/devise/active_record.rb +86 -0
  19. data/lib/devise/controllers/filters.rb +109 -0
  20. data/lib/devise/controllers/helpers.rb +91 -0
  21. data/lib/devise/controllers/url_helpers.rb +47 -0
  22. data/lib/devise/hooks/rememberable.rb +24 -0
  23. data/lib/devise/mapping.rb +95 -0
  24. data/lib/devise/migrations.rb +50 -0
  25. data/lib/devise/models/authenticable.rb +98 -0
  26. data/lib/devise/models/confirmable.rb +125 -0
  27. data/lib/devise/models/recoverable.rb +88 -0
  28. data/lib/devise/models/rememberable.rb +71 -0
  29. data/lib/devise/models/validatable.rb +36 -0
  30. data/lib/devise/routes.rb +95 -0
  31. data/lib/devise/strategies/authenticable.rb +45 -0
  32. data/lib/devise/strategies/base.rb +24 -0
  33. data/lib/devise/strategies/rememberable.rb +33 -0
  34. data/lib/devise/version.rb +3 -0
  35. data/lib/devise/warden.rb +64 -0
  36. data/test/active_record_test.rb +96 -0
  37. data/test/controllers/filters_test.rb +97 -0
  38. data/test/controllers/helpers_test.rb +40 -0
  39. data/test/controllers/url_helpers_test.rb +47 -0
  40. data/test/integration/authenticable_test.rb +191 -0
  41. data/test/integration/confirmable_test.rb +60 -0
  42. data/test/integration/recoverable_test.rb +131 -0
  43. data/test/integration/rememberable_test.rb +56 -0
  44. data/test/mailers/confirmation_instructions_test.rb +59 -0
  45. data/test/mailers/reset_password_instructions_test.rb +62 -0
  46. data/test/mapping_test.rb +71 -0
  47. data/test/models/authenticable_test.rb +138 -0
  48. data/test/models/confirmable_test.rb +206 -0
  49. data/test/models/recoverable_test.rb +145 -0
  50. data/test/models/rememberable_test.rb +68 -0
  51. data/test/models/validatable_test.rb +99 -0
  52. data/test/rails_app/app/controllers/admins_controller.rb +6 -0
  53. data/test/rails_app/app/controllers/application_controller.rb +10 -0
  54. data/test/rails_app/app/controllers/home_controller.rb +4 -0
  55. data/test/rails_app/app/controllers/users_controller.rb +7 -0
  56. data/test/rails_app/app/helpers/application_helper.rb +3 -0
  57. data/test/rails_app/app/models/account.rb +3 -0
  58. data/test/rails_app/app/models/admin.rb +3 -0
  59. data/test/rails_app/app/models/organizer.rb +3 -0
  60. data/test/rails_app/app/models/user.rb +3 -0
  61. data/test/rails_app/config/boot.rb +110 -0
  62. data/test/rails_app/config/environment.rb +41 -0
  63. data/test/rails_app/config/environments/development.rb +17 -0
  64. data/test/rails_app/config/environments/production.rb +28 -0
  65. data/test/rails_app/config/environments/test.rb +28 -0
  66. data/test/rails_app/config/initializers/new_rails_defaults.rb +21 -0
  67. data/test/rails_app/config/initializers/session_store.rb +15 -0
  68. data/test/rails_app/config/routes.rb +18 -0
  69. data/test/routes_test.rb +75 -0
  70. data/test/support/assertions_helper.rb +22 -0
  71. data/test/support/integration_tests_helper.rb +66 -0
  72. data/test/support/model_tests_helper.rb +40 -0
  73. data/test/test_helper.rb +39 -0
  74. metadata +136 -0
@@ -0,0 +1,71 @@
1
+ require 'digest/sha1'
2
+
3
+ module Devise
4
+ module Models
5
+
6
+ # Rememberable manages generating and clearing token for remember the user
7
+ # from a saved cookie. Rememberable also has utility methods for dealing
8
+ # with serializing the user into the cookie and back from the cookie, trying
9
+ # to lookup the record based on the saved information.
10
+ # You probably wouldn't use rememberable methods directly, they are used
11
+ # mostly internally for handling the remember token.
12
+ # Examples:
13
+ #
14
+ # User.find(1).remember_me! # regenerating the token
15
+ # User.find(1).forget_me! # clearing the token
16
+ #
17
+ # # generating info to put into cookies
18
+ # User.serialize_into_cookie(user)
19
+ #
20
+ # # lookup the user based on the incoming cookie information
21
+ # User.serialize_from_cookie(cookie_string)
22
+ module Rememberable
23
+
24
+ def self.included(base)
25
+ base.class_eval do
26
+ extend ClassMethods
27
+
28
+ # Remember me option available in after_authentication hook.
29
+ attr_accessor :remember_me
30
+ attr_accessible :remember_me
31
+ end
32
+ end
33
+
34
+ # Generate a new remember token and save the record without validations.
35
+ def remember_me!
36
+ self.remember_token = friendly_token
37
+ save(false)
38
+ end
39
+
40
+ # Removes the remember token only if it exists, and save the record
41
+ # without validations.
42
+ def forget_me!
43
+ if remember_token?
44
+ self.remember_token = nil
45
+ save(false)
46
+ end
47
+ end
48
+
49
+ # Checks whether the incoming token matches or not with the record token.
50
+ def valid_remember_token?(token)
51
+ remember_token.present? && remember_token == token
52
+ end
53
+
54
+ module ClassMethods
55
+
56
+ # Create the cookie key using the record id and remember_token
57
+ def serialize_into_cookie(record)
58
+ "#{record.id}::#{record.remember_token}"
59
+ end
60
+
61
+ # Recreate the user based on the stored cookie
62
+ def serialize_from_cookie(cookie)
63
+ record_id, remember_token = cookie.split('::')
64
+ record = find_by_id(record_id)
65
+ record if record.try(:valid_remember_token?, remember_token)
66
+ end
67
+
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,36 @@
1
+ module Devise
2
+ module Models
3
+
4
+ # Validatable creates all needed validations for a user email and password.
5
+ # It's optional, given you may want to create the validations by yourself.
6
+ # Automatically validate if the email is present, unique and it's format is
7
+ # valid. Also tests presence of password, confirmation and length
8
+ module Validatable
9
+
10
+ # Email regex used to validate email formats. Retrieved from authlogic.
11
+ EMAIL_REGEX = /\A[\w\.%\+\-]+@(?:[A-Z0-9\-]+\.)+(?:[A-Z]{2,4}|museum|travel)\z/i
12
+
13
+ def self.included(base)
14
+ base.class_eval do
15
+
16
+ validates_presence_of :email
17
+ validates_uniqueness_of :email, :allow_blank => true
18
+ validates_format_of :email, :with => EMAIL_REGEX, :allow_blank => true
19
+
20
+ validates_presence_of :password, :if => :password_required?
21
+ validates_confirmation_of :password, :if => :password_required?
22
+ validates_length_of :password, :within => 6..20, :allow_blank => true, :if => :password_required?
23
+ end
24
+ end
25
+
26
+ protected
27
+
28
+ # Checks whether a password is needed or not. For validations only.
29
+ # Passwords are always required if it's a new record, or if the password
30
+ # or confirmation are being set somewhere.
31
+ def password_required?
32
+ new_record? || !password.nil? || !password_confirmation.nil?
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,95 @@
1
+ module ActionController::Routing
2
+ class RouteSet #:nodoc:
3
+
4
+ # Ensure Devise modules are included only after loading routes, because we
5
+ # need devise_for mappings already declared to create magic filters and
6
+ # helpers.
7
+ def load_routes_with_devise!
8
+ load_routes_without_devise!
9
+
10
+ ActionController::Base.send :include, Devise::Controllers::Filters
11
+ ActionController::Base.send :include, Devise::Controllers::Helpers
12
+ ActionController::Base.send :include, Devise::Controllers::UrlHelpers
13
+
14
+ ActionView::Base.send :include, Devise::Controllers::UrlHelpers
15
+ end
16
+ alias_method_chain :load_routes!, :devise
17
+
18
+ class Mapper #:doc:
19
+ # Includes devise_for method for routes. This method is responsible to
20
+ # generate all needed routes for devise, based on what modules you have
21
+ # defined in your model.
22
+ # Examples: Let's say you have an User model configured to use
23
+ # authenticable, confirmable and recoverable modules. After creating this
24
+ # inside your routes:
25
+ #
26
+ # map.devise_for :users
27
+ #
28
+ # this method is going to look inside your User model and create the
29
+ # needed routes:
30
+ #
31
+ # # Session routes for Authenticable (default)
32
+ # new_user_session GET /users/sign_in {:controller=>"sessions", :action=>"new"}
33
+ # user_session POST /users/sign_in {:controller=>"sessions", :action=>"create"}
34
+ # destroy_user_session GET /users/sign_out {:controller=>"sessions", :action=>"destroy"}
35
+ #
36
+ # # Password routes for Recoverable, if User model has :recoverable configured
37
+ # new_user_password GET /users/password/new(.:format) {:controller=>"passwords", :action=>"new"}
38
+ # edit_user_password GET /users/password/edit(.:format) {:controller=>"passwords", :action=>"edit"}
39
+ # user_password PUT /users/password(.:format) {:controller=>"passwords", :action=>"update"}
40
+ # POST /users/password(.:format) {:controller=>"passwords", :action=>"create"}
41
+ #
42
+ # # Confirmation routes for Confirmable, if User model has :confirmable configured
43
+ # new_user_confirmation GET /users/confirmation/new(.:format) {:controller=>"confirmations", :action=>"new"}
44
+ # user_confirmation GET /users/confirmation(.:format) {:controller=>"confirmations", :action=>"show"}
45
+ # POST /users/confirmation(.:format) {:controller=>"confirmations", :action=>"create"}
46
+ #
47
+ # You can configure your routes with some options:
48
+ # * :class_name => setup a different class to be looked up by devise, if it cannot be correctly find by the route name.
49
+ #
50
+ # map.devise_for :users, :class_name => 'Account'
51
+ #
52
+ # * :as => allows you to setup path name that will be used, as rails routes does. The following route configuration would setup your route as /accounts instead of /users:
53
+ #
54
+ # map.devise_for :users, :as => 'accounts'
55
+ #
56
+ # * :singular => setup the name used to create named routes. By default, for a :users key, it is going to be the singularized version, :user. To configure a named route like account_session_path instead of user_session_path just do:
57
+ #
58
+ # map.devise_for :users, :singular => :account
59
+ #
60
+ # * :path_names => configure different path names to overwrite defaults :sign_in, :sign_out, :password and :confirmation.
61
+ #
62
+ # map.devise_for :users, :path_names => { :sign_in => 'login', :sign_out => 'logout', :password => 'secret', :confirmation => 'verification' }
63
+ def devise_for(*resources)
64
+ options = resources.extract_options!
65
+
66
+ resources.map!(&:to_sym)
67
+ options.assert_valid_keys(:class_name, :as, :path_names, :singular)
68
+
69
+ resources.each do |resource|
70
+ mapping = Devise::Mapping.new(resource, options)
71
+ Devise.mappings[mapping.name] = mapping
72
+
73
+ if mapping.authenticable?
74
+ with_options(:controller => 'sessions', :path_prefix => mapping.as) do |session|
75
+ session.send(:"new_#{mapping.name}_session", mapping.path_names[:sign_in], :action => 'new', :conditions => { :method => :get })
76
+ session.send(:"#{mapping.name}_session", mapping.path_names[:sign_in], :action => 'create', :conditions => { :method => :post })
77
+ session.send(:"destroy_#{mapping.name}_session", mapping.path_names[:sign_out], :action => 'destroy', :conditions => { :method => :get })
78
+ end
79
+ end
80
+
81
+ namespace mapping.name, :namespace => nil, :path_prefix => mapping.as do |m|
82
+ if mapping.recoverable?
83
+ m.resource :password, :only => [:new, :create, :edit, :update], :as => mapping.path_names[:password]
84
+ end
85
+
86
+ if mapping.confirmable?
87
+ m.resource :confirmation, :only => [:new, :create, :show], :as => mapping.path_names[:confirmation]
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
93
+
94
+ end
95
+ end
@@ -0,0 +1,45 @@
1
+ module Devise
2
+ module Strategies
3
+ # Default strategy for signing in a user, based on his email and password.
4
+ # Redirects to sign_in page if it's not authenticated
5
+ class Authenticable < Devise::Strategies::Base
6
+
7
+ # Authenticate a user based on email and password params, returning to warden
8
+ # success and the authenticated user if everything is okay. Otherwise redirect
9
+ # to sign in page.
10
+ def authenticate!
11
+ if valid_attributes? && resource = mapping.to.authenticate(attributes)
12
+ success!(resource)
13
+ else
14
+ store_location
15
+ redirect!(sign_in_path, :unauthenticated => true)
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ # Find the attributes for the current mapping.
22
+ def attributes
23
+ @attributes ||= params[scope]
24
+ end
25
+
26
+ # Check for the right keys.
27
+ def valid_attributes?
28
+ attributes && attributes[:email].present? && attributes[:password].present?
29
+ end
30
+
31
+ # Stores requested uri to redirect the user after signing in. We cannot use
32
+ # scoped session provided by warden here, since the user is not authenticated
33
+ # yet, but we still need to store the uri based on scope, so different scopes
34
+ # would never use the same uri to redirect.
35
+ def store_location
36
+ session[:"#{mapping.name}.return_to"] = request.request_uri if request.get?
37
+ end
38
+
39
+ # Create path to sign in the resource
40
+ def sign_in_path
41
+ "/#{mapping.as}/#{mapping.path_names[:sign_in]}"
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,24 @@
1
+ module Devise
2
+ module Strategies
3
+ # Base strategy for Devise. Responsible for verifying correct scope and
4
+ # mapping.
5
+ class Base < Warden::Strategies::Base
6
+
7
+ # Validate strategy. By default will raise an error if no scope or an
8
+ # invalid mapping is found.
9
+ def valid?
10
+ mapping.for.include?(self.class.name.split("::").last.underscore.to_sym)
11
+ end
12
+
13
+ # Checks if a valid scope was given for devise and find mapping based on
14
+ # this scope.
15
+ def mapping
16
+ @mapping ||= begin
17
+ raise "You need to give a scope for Devise authentication" unless scope
18
+ raise "You need to give a valid Devise mapping" unless mapping = Devise.mappings[scope]
19
+ mapping
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,33 @@
1
+ module Devise
2
+ module Strategies
3
+ # Remember the user through the remember token. This strategy is responsible
4
+ # to verify whether there is a cookie with the remember token, and to
5
+ # recreate the user from this cookie if it exists. Must be called *before*
6
+ # authenticable.
7
+ class Rememberable < Devise::Strategies::Base
8
+
9
+ # A valid strategy for rememberable needs a remember token in the cookies.
10
+ def valid?
11
+ super && remember_me_cookie.present?
12
+ end
13
+
14
+ # To authenticate a user we deserialize the cookie and attempt finding
15
+ # the record in the database. If the attempt fails, we pass to another
16
+ # strategy handle the authentication.
17
+ def authenticate!
18
+ if resource = mapping.to.serialize_from_cookie(remember_me_cookie)
19
+ success!(resource)
20
+ else
21
+ pass
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ # Accessor for remember cookie
28
+ def remember_me_cookie
29
+ cookies['remember_token']
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,3 @@
1
+ module Devise
2
+ VERSION = "0.1.0".freeze
3
+ end
@@ -0,0 +1,64 @@
1
+ begin
2
+ require 'warden'
3
+ rescue
4
+ gem 'warden'
5
+ require 'warden'
6
+ end
7
+
8
+ # Taken from RailsWarden, thanks to Hassox. http://github.com/hassox/rails_warden
9
+ module Warden::Mixins::Common
10
+ # Gets the rails request object by default if it's available
11
+ def request
12
+ return @request if @request
13
+ if env['action_controller.rescue.request']
14
+ @request = env['action_controller.rescue.request']
15
+ else
16
+ Rack::Request.new(env)
17
+ end
18
+ end
19
+
20
+ def raw_session
21
+ request.session
22
+ end
23
+
24
+ def reset_session!
25
+ raw_session.inspect # why do I have to inspect it to get it to clear?
26
+ raw_session.clear
27
+ end
28
+
29
+ # Proxy to request cookies
30
+ def cookies
31
+ request.cookies
32
+ end
33
+ end
34
+
35
+ # Session Serialization in. This block determines how the user will be stored
36
+ # in the session. If you're using a complex object like an ActiveRecord model,
37
+ # it is not a good idea to store the complete object. An ID is sufficient.
38
+ Warden::Manager.serialize_into_session{ |user| [user.class, user.id] }
39
+
40
+ # Session Serialization out. This block gets the user out of the session.
41
+ # It should be the reverse of serializing the object into the session
42
+ Warden::Manager.serialize_from_session do |klass, id|
43
+ klass.find(id)
44
+ end
45
+
46
+ # Be a good citizen and always set the controller action, even if Devise is
47
+ # never calling the failure app through warden.
48
+ Warden::Manager.before_failure do |env, opts|
49
+ env['warden'].request.params['action'] = 'new'
50
+ end
51
+
52
+ # Adds Warden Manager to Rails middleware stack, configuring default devise
53
+ # strategy and also the controller who will manage not authenticated users.
54
+ Rails.configuration.middleware.use Warden::Manager do |manager|
55
+ manager.default_strategies :rememberable, :authenticable
56
+ manager.failure_app = SessionsController
57
+ end
58
+
59
+ # Setup devise strategies for Warden
60
+ Warden::Strategies.add(:rememberable, Devise::Strategies::Rememberable)
61
+ Warden::Strategies.add(:authenticable, Devise::Strategies::Authenticable)
62
+
63
+ # Require rememberable hooks
64
+ require 'devise/hooks/rememberable'
@@ -0,0 +1,96 @@
1
+ require 'test/test_helper'
2
+
3
+ class Authenticable < User
4
+ devise
5
+ end
6
+
7
+ class Confirmable < User
8
+ devise :confirmable
9
+ end
10
+
11
+ class Recoverable < User
12
+ devise :recoverable
13
+ end
14
+
15
+ class Rememberable < User
16
+ devise :rememberable
17
+ end
18
+
19
+ class Validatable < User
20
+ devise :validatable
21
+ end
22
+
23
+ class Devisable < User
24
+ devise :all
25
+ end
26
+
27
+ class Exceptable < User
28
+ devise :all, :except => [:recoverable, :rememberable, :validatable]
29
+ end
30
+
31
+ class Configurable < User
32
+ devise :all, :stretches => 15, :pepper => 'abcdef'
33
+ end
34
+
35
+ class ActiveRecordTest < ActiveSupport::TestCase
36
+
37
+ def include_module?(klass, mod)
38
+ klass.devise_modules.include?(mod) &&
39
+ klass.included_modules.include?(Devise::Models::const_get(mod.to_s.classify))
40
+ end
41
+
42
+ def assert_include_modules(klass, *modules)
43
+ modules.each do |mod|
44
+ assert include_module?(klass, mod)
45
+ end
46
+ end
47
+
48
+ def assert_not_include_modules(klass, *modules)
49
+ modules.each do |mod|
50
+ assert_not include_module?(klass, mod)
51
+ end
52
+ end
53
+
54
+ test 'include by default authenticable only' do
55
+ assert_include_modules Authenticable, :authenticable
56
+ assert_not_include_modules Authenticable, :confirmable, :recoverable, :rememberable, :validatable
57
+ end
58
+
59
+ test 'add confirmable module only' do
60
+ assert_include_modules Confirmable, :authenticable, :confirmable
61
+ assert_not_include_modules Confirmable, :recoverable, :rememberable, :validatable
62
+ end
63
+
64
+ test 'add recoverable module only' do
65
+ assert_include_modules Recoverable, :authenticable, :recoverable
66
+ assert_not_include_modules Recoverable, :confirmable, :rememberable, :validatable
67
+ end
68
+
69
+ test 'add rememberable module only' do
70
+ assert_include_modules Rememberable, :authenticable, :rememberable
71
+ assert_not_include_modules Rememberable, :confirmable, :recoverable, :validatable
72
+ end
73
+
74
+ test 'add validatable module only' do
75
+ assert_include_modules Validatable, :authenticable, :validatable
76
+ assert_not_include_modules Validatable, :confirmable, :recoverable, :rememberable
77
+ end
78
+
79
+ test 'add all modules' do
80
+ assert_include_modules Devisable,
81
+ :authenticable, :confirmable, :recoverable, :rememberable, :validatable
82
+ end
83
+
84
+ test 'configure modules with except option' do
85
+ assert_include_modules Exceptable, :authenticable, :confirmable
86
+ assert_not_include_modules Exceptable, :recoverable, :rememberable, :validatable
87
+ end
88
+
89
+ test 'set a default value for stretches' do
90
+ assert_equal 15, Configurable.new.send(:stretches)
91
+ end
92
+
93
+ test 'set a default value for pepper' do
94
+ assert_equal 'abcdef', Configurable.new.send(:pepper)
95
+ end
96
+ end