authenticate 0.2.3 → 0.3.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.
- checksums.yaml +4 -4
 - data/.gitignore +4 -4
 - data/CHANGELOG.md +12 -0
 - data/Gemfile +1 -0
 - data/Gemfile.lock +21 -6
 - data/app/controllers/authenticate/passwords_controller.rb +1 -1
 - data/authenticate.gemspec +7 -3
 - data/config/locales/authenticate.en.yml +1 -1
 - data/gemfiles/rails42.gemfile +6 -1
 - data/lib/authenticate/callbacks/brute_force.rb +3 -4
 - data/lib/authenticate/configuration.rb +2 -2
 - data/lib/authenticate/controller.rb +1 -2
 - data/lib/authenticate/model/brute_force.rb +2 -2
 - data/lib/authenticate/model/db_password.rb +2 -3
 - data/lib/authenticate/model/email.rb +3 -6
 - data/lib/authenticate/model/lifetimed.rb +1 -1
 - data/lib/authenticate/model/password_reset.rb +1 -1
 - data/lib/authenticate/model/timeoutable.rb +2 -2
 - data/lib/authenticate/model/trackable.rb +1 -1
 - data/lib/authenticate/model/username.rb +1 -1
 - data/lib/authenticate/session.rb +0 -4
 - data/lib/authenticate/user.rb +12 -0
 - data/lib/authenticate/version.rb +1 -1
 - data/spec/controllers/passwords_controller_spec.rb +119 -0
 - data/spec/controllers/secured_controller_spec.rb +70 -0
 - data/spec/controllers/sessions_controller_spec.rb +86 -0
 - data/spec/controllers/users_controller_spec.rb +82 -0
 - data/spec/dummy/app/controllers/application_controller.rb +2 -0
 - data/spec/dummy/app/controllers/welcome_controller.rb +4 -0
 - data/spec/dummy/app/views/layouts/application.html.erb +14 -0
 - data/spec/dummy/app/views/welcome/index.html.erb +4 -0
 - data/spec/dummy/config/application.rb +2 -0
 - data/spec/dummy/config/environments/production.rb +12 -0
 - data/spec/dummy/config/initializers/authenticate.rb +4 -11
 - data/spec/dummy/config/routes.rb +3 -0
 - data/spec/dummy/db/test.sqlite3 +0 -0
 - data/spec/factories/users.rb +2 -4
 - data/spec/features/brute_force_spec.rb +49 -0
 - data/spec/features/max_session_lifetime_spec.rb +30 -0
 - data/spec/features/password_reset_spec.rb +69 -0
 - data/spec/features/password_update_spec.rb +41 -0
 - data/spec/features/sign_in_spec.rb +29 -0
 - data/spec/features/sign_out_spec.rb +22 -0
 - data/spec/features/sign_up_spec.rb +42 -0
 - data/spec/features/timeoutable_spec.rb +30 -0
 - data/spec/model/brute_force_spec.rb +26 -29
 - data/spec/model/configuration_spec.rb +61 -0
 - data/spec/model/db_password_spec.rb +8 -9
 - data/spec/model/email_spec.rb +0 -1
 - data/spec/model/lifetimed_spec.rb +6 -18
 - data/spec/model/password_reset_spec.rb +2 -9
 - data/spec/model/session_spec.rb +16 -23
 - data/spec/model/timeoutable_spec.rb +8 -7
 - data/spec/model/trackable_spec.rb +0 -1
 - data/spec/model/user_spec.rb +1 -2
 - data/spec/spec_helper.rb +33 -131
 - data/spec/support/controllers/controller_helpers.rb +24 -0
 - data/spec/support/features/feature_helpers.rb +36 -0
 - metadata +80 -8
 - data/spec/configuration_spec.rb +0 -60
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA1:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: 314ba694f7183f9f3a7ed5c239c1ec1dc7e45298
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: dabffa423ced67c1f8bf767befdee51979ef3989
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: 9e3cc55ad8b83ab460966a9bfd9000c7799ed5792cc0402c8ce90eb22d3f055b0b3dadf146038c46c844f5278e4a233c6237992febf2679ddc95838c0ad0d4b8
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: 24f500d3c8917867c2a16c7b3ba2f0bcf44c47dfe5ea83ffb949c9bb03c864f880a30ccab3f7e7f755cb4fa7039f12926b42cd01d30fbab9482a7c0851c8ff1a
         
     | 
    
        data/.gitignore
    CHANGED
    
    | 
         @@ -2,9 +2,9 @@ 
     | 
|
| 
       2 
2 
     | 
    
         
             
            authenticate-*.gem
         
     | 
| 
       3 
3 
     | 
    
         
             
            log/*.log
         
     | 
| 
       4 
4 
     | 
    
         
             
            pkg/
         
     | 
| 
       5 
     | 
    
         
            -
             
     | 
| 
       6 
     | 
    
         
            -
             
     | 
| 
       7 
     | 
    
         
            -
             
     | 
| 
       8 
     | 
    
         
            -
             
     | 
| 
      
 5 
     | 
    
         
            +
            spec/dummy/db/*.sqlite3
         
     | 
| 
      
 6 
     | 
    
         
            +
            spec/dummy/db/*.sqlite3-journal
         
     | 
| 
      
 7 
     | 
    
         
            +
            spec/dummy/log/*.log
         
     | 
| 
      
 8 
     | 
    
         
            +
            spec/dummy/tmp/
         
     | 
| 
       9 
9 
     | 
    
         
             
            spec/dummy/log/test.log
         
     | 
| 
       10 
10 
     | 
    
         
             
            spec/dummy/log/development.log
         
     | 
    
        data/CHANGELOG.md
    CHANGED
    
    | 
         @@ -1,5 +1,17 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # Authenticate Changelog
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
      
 3 
     | 
    
         
            +
            ## [0.3.0] - February 24, 2016
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            Moved normalize_email and find_normalized_email methods to base User module.
         
     | 
| 
      
 6 
     | 
    
         
            +
            Added full suite of controller and feature tests.
         
     | 
| 
      
 7 
     | 
    
         
            +
            Bug fixes: 
         
     | 
| 
      
 8 
     | 
    
         
            +
            * failed login count fix was off by one.
         
     | 
| 
      
 9 
     | 
    
         
            +
            * password validation now done only in correct circumstances
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            [0.3.0]: https://github.com/tomichj/authenticate/compare/v0.2.2...v0.3.0
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
       3 
15 
     | 
    
         
             
            ## [0.2.3] - February 13, 2016
         
     | 
| 
       4 
16 
     | 
    
         | 
| 
       5 
17 
     | 
    
         
             
            Small bugfix for :username authentication.
         
     | 
    
        data/Gemfile
    CHANGED
    
    
    
        data/Gemfile.lock
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            PATH
         
     | 
| 
       2 
2 
     | 
    
         
             
              remote: .
         
     | 
| 
       3 
3 
     | 
    
         
             
              specs:
         
     | 
| 
       4 
     | 
    
         
            -
                authenticate (0. 
     | 
| 
      
 4 
     | 
    
         
            +
                authenticate (0.3.0)
         
     | 
| 
       5 
5 
     | 
    
         
             
                  bcrypt
         
     | 
| 
       6 
6 
     | 
    
         
             
                  email_validator (~> 1.6)
         
     | 
| 
       7 
7 
     | 
    
         
             
                  rails (>= 4.0, < 5.1)
         
     | 
| 
         @@ -44,20 +44,26 @@ GEM 
     | 
|
| 
       44 
44 
     | 
    
         
             
                  minitest (~> 5.1)
         
     | 
| 
       45 
45 
     | 
    
         
             
                  thread_safe (~> 0.3, >= 0.3.4)
         
     | 
| 
       46 
46 
     | 
    
         
             
                  tzinfo (~> 1.1)
         
     | 
| 
      
 47 
     | 
    
         
            +
                addressable (2.4.0)
         
     | 
| 
       47 
48 
     | 
    
         
             
                arel (6.0.3)
         
     | 
| 
       48 
49 
     | 
    
         
             
                bcrypt (3.1.10)
         
     | 
| 
       49 
50 
     | 
    
         
             
                builder (3.2.2)
         
     | 
| 
      
 51 
     | 
    
         
            +
                capybara (2.6.2)
         
     | 
| 
      
 52 
     | 
    
         
            +
                  addressable
         
     | 
| 
      
 53 
     | 
    
         
            +
                  mime-types (>= 1.16)
         
     | 
| 
      
 54 
     | 
    
         
            +
                  nokogiri (>= 1.3.3)
         
     | 
| 
      
 55 
     | 
    
         
            +
                  rack (>= 1.0.0)
         
     | 
| 
      
 56 
     | 
    
         
            +
                  rack-test (>= 0.5.4)
         
     | 
| 
      
 57 
     | 
    
         
            +
                  xpath (~> 2.0)
         
     | 
| 
       50 
58 
     | 
    
         
             
                coderay (1.1.0)
         
     | 
| 
       51 
59 
     | 
    
         
             
                concurrent-ruby (1.0.0)
         
     | 
| 
      
 60 
     | 
    
         
            +
                database_cleaner (1.5.1)
         
     | 
| 
       52 
61 
     | 
    
         
             
                diff-lcs (1.2.5)
         
     | 
| 
       53 
62 
     | 
    
         
             
                email_validator (1.6.0)
         
     | 
| 
       54 
63 
     | 
    
         
             
                  activemodel
         
     | 
| 
       55 
64 
     | 
    
         
             
                erubis (2.7.0)
         
     | 
| 
       56 
65 
     | 
    
         
             
                factory_girl (4.4.0)
         
     | 
| 
       57 
66 
     | 
    
         
             
                  activesupport (>= 3.0.0)
         
     | 
| 
       58 
     | 
    
         
            -
                factory_girl_rails (4.4.1)
         
     | 
| 
       59 
     | 
    
         
            -
                  factory_girl (~> 4.4.0)
         
     | 
| 
       60 
     | 
    
         
            -
                  railties (>= 3.0.0)
         
     | 
| 
       61 
67 
     | 
    
         
             
                globalid (0.3.6)
         
     | 
| 
       62 
68 
     | 
    
         
             
                  activesupport (>= 4.1.0)
         
     | 
| 
       63 
69 
     | 
    
         
             
                i18n (0.7.0)
         
     | 
| 
         @@ -120,6 +126,8 @@ GEM 
     | 
|
| 
       120 
126 
     | 
    
         
             
                  rspec-mocks (~> 3.1.0)
         
     | 
| 
       121 
127 
     | 
    
         
             
                  rspec-support (~> 3.1.0)
         
     | 
| 
       122 
128 
     | 
    
         
             
                rspec-support (3.1.2)
         
     | 
| 
      
 129 
     | 
    
         
            +
                shoulda-matchers (2.8.0)
         
     | 
| 
      
 130 
     | 
    
         
            +
                  activesupport (>= 3.0.0)
         
     | 
| 
       123 
131 
     | 
    
         
             
                slop (3.6.0)
         
     | 
| 
       124 
132 
     | 
    
         
             
                sprockets (3.5.2)
         
     | 
| 
       125 
133 
     | 
    
         
             
                  concurrent-ruby (~> 1.0)
         
     | 
| 
         @@ -131,18 +139,25 @@ GEM 
     | 
|
| 
       131 
139 
     | 
    
         
             
                sqlite3 (1.3.11)
         
     | 
| 
       132 
140 
     | 
    
         
             
                thor (0.19.1)
         
     | 
| 
       133 
141 
     | 
    
         
             
                thread_safe (0.3.5)
         
     | 
| 
      
 142 
     | 
    
         
            +
                timecop (0.8.0)
         
     | 
| 
       134 
143 
     | 
    
         
             
                tzinfo (1.2.2)
         
     | 
| 
       135 
144 
     | 
    
         
             
                  thread_safe (~> 0.1)
         
     | 
| 
      
 145 
     | 
    
         
            +
                xpath (2.0.0)
         
     | 
| 
      
 146 
     | 
    
         
            +
                  nokogiri (~> 1.3)
         
     | 
| 
       136 
147 
     | 
    
         | 
| 
       137 
148 
     | 
    
         
             
            PLATFORMS
         
     | 
| 
       138 
149 
     | 
    
         
             
              ruby
         
     | 
| 
       139 
150 
     | 
    
         | 
| 
       140 
151 
     | 
    
         
             
            DEPENDENCIES
         
     | 
| 
       141 
152 
     | 
    
         
             
              authenticate!
         
     | 
| 
       142 
     | 
    
         
            -
               
     | 
| 
      
 153 
     | 
    
         
            +
              capybara (~> 2.6.2)
         
     | 
| 
      
 154 
     | 
    
         
            +
              database_cleaner (~> 1.5.1)
         
     | 
| 
      
 155 
     | 
    
         
            +
              factory_girl
         
     | 
| 
       143 
156 
     | 
    
         
             
              pry
         
     | 
| 
       144 
     | 
    
         
            -
              rspec-rails
         
     | 
| 
      
 157 
     | 
    
         
            +
              rspec-rails (~> 3.1.0)
         
     | 
| 
      
 158 
     | 
    
         
            +
              shoulda-matchers (~> 2.8)
         
     | 
| 
       145 
159 
     | 
    
         
             
              sqlite3
         
     | 
| 
      
 160 
     | 
    
         
            +
              timecop (~> 0.8.0)
         
     | 
| 
       146 
161 
     | 
    
         | 
| 
       147 
162 
     | 
    
         
             
            BUNDLED WITH
         
     | 
| 
       148 
163 
     | 
    
         
             
               1.11.2
         
     | 
| 
         @@ -68,7 +68,7 @@ class Authenticate::PasswordsController < Authenticate::AuthenticateController 
     | 
|
| 
       68 
68 
     | 
    
         
             
              end
         
     | 
| 
       69 
69 
     | 
    
         | 
| 
       70 
70 
     | 
    
         
             
              def find_user_for_create
         
     | 
| 
       71 
     | 
    
         
            -
                Authenticate.configuration.user_model_class. 
     | 
| 
      
 71 
     | 
    
         
            +
                Authenticate.configuration.user_model_class.find_by_normalized_email params[:password][:email]
         
     | 
| 
       72 
72 
     | 
    
         
             
              end
         
     | 
| 
       73 
73 
     | 
    
         | 
| 
       74 
74 
     | 
    
         
             
              def find_user_for_edit
         
     | 
    
        data/authenticate.gemspec
    CHANGED
    
    | 
         @@ -25,11 +25,15 @@ Gem::Specification.new do |s| 
     | 
|
| 
       25 
25 
     | 
    
         
             
              s.add_dependency 'email_validator', '~> 1.6'
         
     | 
| 
       26 
26 
     | 
    
         
             
              s.add_dependency 'rails', '>= 4.0', '< 5.1'
         
     | 
| 
       27 
27 
     | 
    
         | 
| 
       28 
     | 
    
         
            -
              # s.add_development_dependency ' 
     | 
| 
       29 
     | 
    
         
            -
              s.add_development_dependency ' 
     | 
| 
       30 
     | 
    
         
            -
              s.add_development_dependency 'rspec-rails'
         
     | 
| 
      
 28 
     | 
    
         
            +
              # s.add_development_dependency 'factory_girl_rails', '~> 4.4.1'
         
     | 
| 
      
 29 
     | 
    
         
            +
              s.add_development_dependency 'factory_girl'
         
     | 
| 
      
 30 
     | 
    
         
            +
              s.add_development_dependency 'rspec-rails', '~> 3.1.0'
         
     | 
| 
       31 
31 
     | 
    
         
             
              s.add_development_dependency 'pry'
         
     | 
| 
       32 
32 
     | 
    
         
             
              s.add_development_dependency 'sqlite3'
         
     | 
| 
      
 33 
     | 
    
         
            +
              s.add_development_dependency 'shoulda-matchers', '~> 2.8'
         
     | 
| 
      
 34 
     | 
    
         
            +
              s.add_development_dependency 'capybara', '~> 2.6.2'
         
     | 
| 
      
 35 
     | 
    
         
            +
              s.add_development_dependency 'database_cleaner', '~> 1.5.1'
         
     | 
| 
      
 36 
     | 
    
         
            +
              s.add_development_dependency 'timecop', '~> 0.8.0'
         
     | 
| 
       33 
37 
     | 
    
         | 
| 
       34 
38 
     | 
    
         
             
              s.required_ruby_version = Gem::Requirement.new('>= 2.0')
         
     | 
| 
       35 
39 
     | 
    
         
             
            end
         
     | 
    
        data/gemfiles/rails42.gemfile
    CHANGED
    
    | 
         @@ -2,8 +2,13 @@ 
     | 
|
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            source "https://rubygems.org"
         
     | 
| 
       4 
4 
     | 
    
         | 
| 
      
 5 
     | 
    
         
            +
            gem 'shoulda-matchers', '~> 2.8'
         
     | 
| 
      
 6 
     | 
    
         
            +
            gem 'capybara', '~> 2.6.2'
         
     | 
| 
      
 7 
     | 
    
         
            +
            gem 'database_cleaner', '~> 1.5.1'
         
     | 
| 
      
 8 
     | 
    
         
            +
            gem 'timecop', '~> 0.8.0'
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
       5 
10 
     | 
    
         
             
            gem "bundler", "~> 1.3"
         
     | 
| 
       6 
     | 
    
         
            -
            gem " 
     | 
| 
      
 11 
     | 
    
         
            +
            gem "factory_girl", "~> 4.4"
         
     | 
| 
       7 
12 
     | 
    
         
             
            gem "rspec-rails", "~> 3.1"
         
     | 
| 
       8 
13 
     | 
    
         
             
            gem "sqlite3", "~> 1.3"
         
     | 
| 
       9 
14 
     | 
    
         
             
            gem "pry", :require => false
         
     | 
| 
         @@ -6,7 +6,7 @@ Authenticate.lifecycle.prepend_after_authentication name: 'brute force protectio 
     | 
|
| 
       6 
6 
     | 
    
         
             
              unless session.authenticated? || Authenticate.configuration.max_consecutive_bad_logins_allowed.nil?
         
     | 
| 
       7 
7 
     | 
    
         
             
                user_credentials = User.credentials(session.request.params)
         
     | 
| 
       8 
8 
     | 
    
         
             
                user ||= User.find_by_credentials(user_credentials)
         
     | 
| 
       9 
     | 
    
         
            -
                if user
         
     | 
| 
      
 9 
     | 
    
         
            +
                if user && user.respond_to?(:register_failed_login!)
         
     | 
| 
       10 
10 
     | 
    
         
             
                  user.register_failed_login!
         
     | 
| 
       11 
11 
     | 
    
         
             
                  user.save!
         
     | 
| 
       12 
12 
     | 
    
         
             
                end
         
     | 
| 
         @@ -14,14 +14,13 @@ Authenticate.lifecycle.prepend_after_authentication name: 'brute force protectio 
     | 
|
| 
       14 
14 
     | 
    
         | 
| 
       15 
15 
     | 
    
         
             
              # if user is locked, and we allow a lockout period, then unlock the user if they've waited
         
     | 
| 
       16 
16 
     | 
    
         
             
              # longer than the lockout period.
         
     | 
| 
       17 
     | 
    
         
            -
              if user && !Authenticate.configuration.bad_login_lockout_period.nil? 
     | 
| 
      
 17 
     | 
    
         
            +
              if user && user.respond_to?(:locked?) && user.locked? && !Authenticate.configuration.bad_login_lockout_period.nil?
         
     | 
| 
       18 
18 
     | 
    
         
             
                user.unlock! if user.lock_expires_at <= Time.now.utc
         
     | 
| 
       19 
19 
     | 
    
         
             
              end
         
     | 
| 
       20 
20 
     | 
    
         | 
| 
       21 
21 
     | 
    
         
             
              # if the user is still locked, let them know how long they are locked for.
         
     | 
| 
       22 
     | 
    
         
            -
              if user && user.locked?
         
     | 
| 
      
 22 
     | 
    
         
            +
              if user && user.respond_to?(:locked?) && user.locked?
         
     | 
| 
       23 
23 
     | 
    
         
             
                remaining = time_ago_in_words(user.lock_expires_at)
         
     | 
| 
       24 
     | 
    
         
            -
                # throw(:failure, "Your account is locked, will unlock in #{remaining.to_s}")
         
     | 
| 
       25 
24 
     | 
    
         
             
                throw(:failure, I18n.t('callbacks.brute_force.failure', time_remaining: remaining.to_s))
         
     | 
| 
       26 
25 
     | 
    
         
             
              end
         
     | 
| 
       27 
26 
     | 
    
         | 
| 
         @@ -206,12 +206,12 @@ module Authenticate 
     | 
|
| 
       206 
206 
     | 
    
         | 
| 
       207 
207 
     | 
    
         
             
                def user_model_route_key
         
     | 
| 
       208 
208 
     | 
    
         
             
                  return :users if @user_model == '::User' # avoid nil in generator
         
     | 
| 
       209 
     | 
    
         
            -
                   
     | 
| 
      
 209 
     | 
    
         
            +
                  user_model_class.model_name.route_key
         
     | 
| 
       210 
210 
     | 
    
         
             
                end
         
     | 
| 
       211 
211 
     | 
    
         | 
| 
       212 
212 
     | 
    
         
             
                def user_model_param_key
         
     | 
| 
       213 
213 
     | 
    
         
             
                  return :user if @user_model == '::User' # avoid nil in generator
         
     | 
| 
       214 
     | 
    
         
            -
                   
     | 
| 
      
 214 
     | 
    
         
            +
                  user_model_class.model_name.param_key
         
     | 
| 
       215 
215 
     | 
    
         
             
                end
         
     | 
| 
       216 
216 
     | 
    
         | 
| 
       217 
217 
     | 
    
         
             
                # The name of foreign key parameter for the configured user model.
         
     | 
| 
         @@ -12,9 +12,7 @@ module Authenticate 
     | 
|
| 
       12 
12 
     | 
    
         
             
                # Validate a user's identity with (typically) email/ID & password, and return the User if valid, or nil.
         
     | 
| 
       13 
13 
     | 
    
         
             
                # After calling this, call login(user) to complete the process.
         
     | 
| 
       14 
14 
     | 
    
         
             
                def authenticate(params)
         
     | 
| 
       15 
     | 
    
         
            -
                  # todo: get params from User model
         
     | 
| 
       16 
15 
     | 
    
         
             
                  credentials = Authenticate.configuration.user_model_class.credentials(params)
         
     | 
| 
       17 
     | 
    
         
            -
                  debug "Controller::credentials: #{credentials.inspect}"
         
     | 
| 
       18 
16 
     | 
    
         
             
                  Authenticate.configuration.user_model_class.authenticate(credentials)
         
     | 
| 
       19 
17 
     | 
    
         
             
                end
         
     | 
| 
       20 
18 
     | 
    
         | 
| 
         @@ -102,6 +100,7 @@ module Authenticate 
     | 
|
| 
       102 
100 
     | 
    
         | 
| 
       103 
101 
     | 
    
         
             
                # User is not authorized, bounce 'em to sign in
         
     | 
| 
       104 
102 
     | 
    
         
             
                def unauthorized(msg = t('flashes.failure_when_not_signed_in'))
         
     | 
| 
      
 103 
     | 
    
         
            +
                  authenticate_session.deauthenticate
         
     | 
| 
       105 
104 
     | 
    
         
             
                  respond_to do |format|
         
     | 
| 
       106 
105 
     | 
    
         
             
                    format.any(:js, :json, :xml) { head :unauthorized }
         
     | 
| 
       107 
106 
     | 
    
         
             
                    format.any {
         
     | 
| 
         @@ -33,7 +33,7 @@ module Authenticate 
     | 
|
| 
       33 
33 
     | 
    
         
             
                module BruteForce
         
     | 
| 
       34 
34 
     | 
    
         
             
                  extend ActiveSupport::Concern
         
     | 
| 
       35 
35 
     | 
    
         | 
| 
       36 
     | 
    
         
            -
                  def self.required_fields( 
     | 
| 
      
 36 
     | 
    
         
            +
                  def self.required_fields(_klass)
         
     | 
| 
       37 
37 
     | 
    
         
             
                    [:failed_logins_count, :lock_expires_at]
         
     | 
| 
       38 
38 
     | 
    
         
             
                  end
         
     | 
| 
       39 
39 
     | 
    
         | 
| 
         @@ -41,7 +41,7 @@ module Authenticate 
     | 
|
| 
       41 
41 
     | 
    
         
             
                  def register_failed_login!
         
     | 
| 
       42 
42 
     | 
    
         
             
                    self.failed_logins_count ||= 0
         
     | 
| 
       43 
43 
     | 
    
         
             
                    self.failed_logins_count += 1
         
     | 
| 
       44 
     | 
    
         
            -
                    lock! if self.failed_logins_count  
     | 
| 
      
 44 
     | 
    
         
            +
                    lock! if self.failed_logins_count > max_bad_logins
         
     | 
| 
       45 
45 
     | 
    
         
             
                  end
         
     | 
| 
       46 
46 
     | 
    
         | 
| 
       47 
47 
     | 
    
         
             
                  def lock!
         
     | 
| 
         @@ -26,7 +26,7 @@ module Authenticate 
     | 
|
| 
       26 
26 
     | 
    
         
             
                module DbPassword
         
     | 
| 
       27 
27 
     | 
    
         
             
                  extend ActiveSupport::Concern
         
     | 
| 
       28 
28 
     | 
    
         | 
| 
       29 
     | 
    
         
            -
                  def self.required_fields( 
     | 
| 
      
 29 
     | 
    
         
            +
                  def self.required_fields(_klass)
         
     | 
| 
       30 
30 
     | 
    
         
             
                    [:encrypted_password]
         
     | 
| 
       31 
31 
     | 
    
         
             
                  end
         
     | 
| 
       32 
32 
     | 
    
         | 
| 
         @@ -72,8 +72,7 @@ module Authenticate 
     | 
|
| 
       72 
72 
     | 
    
         | 
| 
       73 
73 
     | 
    
         
             
                  # If we already have an encrypted password and it's not changing, skip the validation.
         
     | 
| 
       74 
74 
     | 
    
         
             
                  def skip_password_validation?
         
     | 
| 
       75 
     | 
    
         
            -
                     
     | 
| 
       76 
     | 
    
         
            -
                    false
         
     | 
| 
      
 75 
     | 
    
         
            +
                    encrypted_password.present? && !password_changing
         
     | 
| 
       77 
76 
     | 
    
         
             
                  end
         
     | 
| 
       78 
77 
     | 
    
         | 
| 
       79 
78 
     | 
    
         
             
                end
         
     | 
| 
         @@ -25,7 +25,7 @@ module Authenticate 
     | 
|
| 
       25 
25 
     | 
    
         
             
                module Email
         
     | 
| 
       26 
26 
     | 
    
         
             
                  extend ActiveSupport::Concern
         
     | 
| 
       27 
27 
     | 
    
         | 
| 
       28 
     | 
    
         
            -
                  def self.required_fields( 
     | 
| 
      
 28 
     | 
    
         
            +
                  def self.required_fields(_klass)
         
     | 
| 
       29 
29 
     | 
    
         
             
                    [:email]
         
     | 
| 
       30 
30 
     | 
    
         
             
                  end
         
     | 
| 
       31 
31 
     | 
    
         | 
| 
         @@ -41,6 +41,7 @@ module Authenticate 
     | 
|
| 
       41 
41 
     | 
    
         
             
                  module ClassMethods
         
     | 
| 
       42 
42 
     | 
    
         | 
| 
       43 
43 
     | 
    
         
             
                    def credentials(params)
         
     | 
| 
      
 44 
     | 
    
         
            +
                      return [] if params.nil? || params[:session].nil?
         
     | 
| 
       44 
45 
     | 
    
         
             
                      [params[:session][:email], params[:session][:password]]
         
     | 
| 
       45 
46 
     | 
    
         
             
                    end
         
     | 
| 
       46 
47 
     | 
    
         | 
| 
         @@ -51,11 +52,7 @@ module Authenticate 
     | 
|
| 
       51 
52 
     | 
    
         | 
| 
       52 
53 
     | 
    
         
             
                    def find_by_credentials(credentials)
         
     | 
| 
       53 
54 
     | 
    
         
             
                      email = credentials[0]
         
     | 
| 
       54 
     | 
    
         
            -
                       
     | 
| 
       55 
     | 
    
         
            -
                    end
         
     | 
| 
       56 
     | 
    
         
            -
             
     | 
| 
       57 
     | 
    
         
            -
                    def normalize_email(email)
         
     | 
| 
       58 
     | 
    
         
            -
                      email.to_s.downcase.gsub(/\s+/, '')
         
     | 
| 
      
 55 
     | 
    
         
            +
                      find_by_normalized_email(email)
         
     | 
| 
       59 
56 
     | 
    
         
             
                    end
         
     | 
| 
       60 
57 
     | 
    
         | 
| 
       61 
58 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -29,7 +29,7 @@ module Authenticate 
     | 
|
| 
       29 
29 
     | 
    
         
             
                module Timeoutable
         
     | 
| 
       30 
30 
     | 
    
         
             
                    extend ActiveSupport::Concern
         
     | 
| 
       31 
31 
     | 
    
         | 
| 
       32 
     | 
    
         
            -
                    def self.required_fields( 
     | 
| 
      
 32 
     | 
    
         
            +
                    def self.required_fields(_klass)
         
     | 
| 
       33 
33 
     | 
    
         
             
                      [:last_access_at]
         
     | 
| 
       34 
34 
     | 
    
         
             
                    end
         
     | 
| 
       35 
35 
     | 
    
         | 
| 
         @@ -45,6 +45,6 @@ module Authenticate 
     | 
|
| 
       45 
45 
     | 
    
         
             
                    def timeout_in
         
     | 
| 
       46 
46 
     | 
    
         
             
                      Authenticate.configuration.timeout_in
         
     | 
| 
       47 
47 
     | 
    
         
             
                    end
         
     | 
| 
       48 
     | 
    
         
            -
             
     | 
| 
      
 48 
     | 
    
         
            +
                end
         
     | 
| 
       49 
49 
     | 
    
         
             
              end
         
     | 
| 
       50 
50 
     | 
    
         
             
            end
         
     | 
    
        data/lib/authenticate/session.rb
    CHANGED
    
    | 
         @@ -21,8 +21,6 @@ module Authenticate 
     | 
|
| 
       21 
21 
     | 
    
         
             
                def login(user, &block)
         
     | 
| 
       22 
22 
     | 
    
         
             
                  debug 'session.login()'
         
     | 
| 
       23 
23 
     | 
    
         
             
                  @current_user = user
         
     | 
| 
       24 
     | 
    
         
            -
                  debug "session.login @current_user: #{@current_user.inspect}"
         
     | 
| 
       25 
     | 
    
         
            -
                  # todo extract token gen to two different strategies
         
     | 
| 
       26 
24 
     | 
    
         
             
                  @current_user.generate_session_token if user.present?
         
     | 
| 
       27 
25 
     | 
    
         | 
| 
       28 
26 
     | 
    
         
             
                  message = catch(:failure) do
         
     | 
| 
         @@ -44,7 +42,6 @@ module Authenticate 
     | 
|
| 
       44 
42 
     | 
    
         
             
                  end
         
     | 
| 
       45 
43 
     | 
    
         
             
                end
         
     | 
| 
       46 
44 
     | 
    
         | 
| 
       47 
     | 
    
         
            -
             
     | 
| 
       48 
45 
     | 
    
         
             
                # Get the user represented by this session.
         
     | 
| 
       49 
46 
     | 
    
         
             
                #
         
     | 
| 
       50 
47 
     | 
    
         
             
                # @return [User]
         
     | 
| 
         @@ -64,7 +61,6 @@ module Authenticate 
     | 
|
| 
       64 
61 
     | 
    
         
             
                  current_user.present?
         
     | 
| 
       65 
62 
     | 
    
         
             
                end
         
     | 
| 
       66 
63 
     | 
    
         | 
| 
       67 
     | 
    
         
            -
             
     | 
| 
       68 
64 
     | 
    
         
             
                # Invalidate the session token, unset the current user and remove the cookie.
         
     | 
| 
       69 
65 
     | 
    
         
             
                #
         
     | 
| 
       70 
66 
     | 
    
         
             
                # @return [void]
         
     | 
    
        data/lib/authenticate/user.rb
    CHANGED
    
    | 
         @@ -49,6 +49,18 @@ module Authenticate 
     | 
|
| 
       49 
49 
     | 
    
         
             
                  save validate: false
         
     | 
| 
       50 
50 
     | 
    
         
             
                end
         
     | 
| 
       51 
51 
     | 
    
         | 
| 
      
 52 
     | 
    
         
            +
                module ClassMethods
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                  def normalize_email(email)
         
     | 
| 
      
 55 
     | 
    
         
            +
                    email.to_s.downcase.gsub(/\s+/, '')
         
     | 
| 
      
 56 
     | 
    
         
            +
                  end
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
                  # We need to find users by email even if they don't use email to log in
         
     | 
| 
      
 59 
     | 
    
         
            +
                  def find_by_normalized_email(email)
         
     | 
| 
      
 60 
     | 
    
         
            +
                    find_by_email normalize_email(email)
         
     | 
| 
      
 61 
     | 
    
         
            +
                  end
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
                  end
         
     | 
| 
       52 
64 
     | 
    
         | 
| 
       53 
65 
     | 
    
         
             
              end
         
     | 
| 
       54 
66 
     | 
    
         
             
            end
         
     | 
    
        data/lib/authenticate/version.rb
    CHANGED
    
    
| 
         @@ -0,0 +1,119 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'support/controllers/controller_helpers'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            describe Authenticate::PasswordsController, type: :controller do
         
     | 
| 
      
 5 
     | 
    
         
            +
              it { is_expected.to be_a Authenticate::Controller }
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
              describe 'get to #new' do
         
     | 
| 
      
 8 
     | 
    
         
            +
                it 'renders the new form' do
         
     | 
| 
      
 9 
     | 
    
         
            +
                  get :new
         
     | 
| 
      
 10 
     | 
    
         
            +
                  expect(response).to be_success
         
     | 
| 
      
 11 
     | 
    
         
            +
                  expect(response).to render_template(:new)
         
     | 
| 
      
 12 
     | 
    
         
            +
                end
         
     | 
| 
      
 13 
     | 
    
         
            +
              end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
              describe 'post to #create' do
         
     | 
| 
      
 16 
     | 
    
         
            +
                context 'with email for an existing user' do
         
     | 
| 
      
 17 
     | 
    
         
            +
                  it 'generates a password_reset_token' do
         
     | 
| 
      
 18 
     | 
    
         
            +
                    user = create(:user)
         
     | 
| 
      
 19 
     | 
    
         
            +
                    post :create, password: { email: user.email.upcase }
         
     | 
| 
      
 20 
     | 
    
         
            +
                    expect(user.reload.password_reset_token).not_to be_nil
         
     | 
| 
      
 21 
     | 
    
         
            +
                  end
         
     | 
| 
      
 22 
     | 
    
         
            +
                  it 'sends a password reset email' do
         
     | 
| 
      
 23 
     | 
    
         
            +
                    ActionMailer::Base.deliveries.clear
         
     | 
| 
      
 24 
     | 
    
         
            +
                    user = create(:user)
         
     | 
| 
      
 25 
     | 
    
         
            +
                    post :create, password: { email: user.email }
         
     | 
| 
      
 26 
     | 
    
         
            +
                    email = ActionMailer::Base.deliveries.last
         
     | 
| 
      
 27 
     | 
    
         
            +
                    expect(email.subject).to match(/change your password/i)
         
     | 
| 
      
 28 
     | 
    
         
            +
                  end
         
     | 
| 
      
 29 
     | 
    
         
            +
                end
         
     | 
| 
      
 30 
     | 
    
         
            +
                context 'with email that does not belong to an existing user' do
         
     | 
| 
      
 31 
     | 
    
         
            +
                  bad_email = 'bunk_email_address@non_existent_domain.com'
         
     | 
| 
      
 32 
     | 
    
         
            +
                  it 'does not send an email' do
         
     | 
| 
      
 33 
     | 
    
         
            +
                    ActionMailer::Base.deliveries.clear
         
     | 
| 
      
 34 
     | 
    
         
            +
                    post :create, password: { email: bad_email}
         
     | 
| 
      
 35 
     | 
    
         
            +
                    expect(ActionMailer::Base.deliveries).to be_empty
         
     | 
| 
      
 36 
     | 
    
         
            +
                  end
         
     | 
| 
      
 37 
     | 
    
         
            +
                  it 'always responds with redirect to avoid leaking user information' do
         
     | 
| 
      
 38 
     | 
    
         
            +
                    post :create, password: { email: bad_email }
         
     | 
| 
      
 39 
     | 
    
         
            +
                    expect(response).to be_redirect
         
     | 
| 
      
 40 
     | 
    
         
            +
                  end
         
     | 
| 
      
 41 
     | 
    
         
            +
                end
         
     | 
| 
      
 42 
     | 
    
         
            +
              end
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
              describe 'get to #edit' do
         
     | 
| 
      
 45 
     | 
    
         
            +
                context 'with a valid password_reset_token and timestamp' do
         
     | 
| 
      
 46 
     | 
    
         
            +
                  it 'renders password update form' do
         
     | 
| 
      
 47 
     | 
    
         
            +
                    user = create(:user, :with_password_reset_token_and_timestamp)
         
     | 
| 
      
 48 
     | 
    
         
            +
                    get :edit, id: user.id, token: user.password_reset_token
         
     | 
| 
      
 49 
     | 
    
         
            +
                    expect(response).to be_success
         
     | 
| 
      
 50 
     | 
    
         
            +
                    expect(response).to render_template(:edit)
         
     | 
| 
      
 51 
     | 
    
         
            +
                    expect(assigns(:user)).to eq user
         
     | 
| 
      
 52 
     | 
    
         
            +
                  end
         
     | 
| 
      
 53 
     | 
    
         
            +
                end
         
     | 
| 
      
 54 
     | 
    
         
            +
                context 'with a valid timestamp but invalid password_reset_token' do
         
     | 
| 
      
 55 
     | 
    
         
            +
                  it 'renders #new password form with notice' do
         
     | 
| 
      
 56 
     | 
    
         
            +
                    user = create(:user, :with_password_reset_token_and_timestamp)
         
     | 
| 
      
 57 
     | 
    
         
            +
                    get :edit, id: user.id, token: 'bad token'
         
     | 
| 
      
 58 
     | 
    
         
            +
                    expect(response).to be_success
         
     | 
| 
      
 59 
     | 
    
         
            +
                    expect(response).to render_template(:new)
         
     | 
| 
      
 60 
     | 
    
         
            +
                  end
         
     | 
| 
      
 61 
     | 
    
         
            +
                end
         
     | 
| 
      
 62 
     | 
    
         
            +
                context 'with a valid password_reset_token but invalid timestamp' do
         
     | 
| 
      
 63 
     | 
    
         
            +
                  it 'renders #new password form with notice' do
         
     | 
| 
      
 64 
     | 
    
         
            +
                    user = create(:user, :with_password_reset_token_and_timestamp, password_reset_sent_at: 2.years.ago)
         
     | 
| 
      
 65 
     | 
    
         
            +
                    get :edit, id: user.id, token: user.password_reset_token
         
     | 
| 
      
 66 
     | 
    
         
            +
                    expect(response).to be_redirect
         
     | 
| 
      
 67 
     | 
    
         
            +
                    expect(flash[:notice]).to match /password change request has expired/
         
     | 
| 
      
 68 
     | 
    
         
            +
                  end
         
     | 
| 
      
 69 
     | 
    
         
            +
                end
         
     | 
| 
      
 70 
     | 
    
         
            +
                context 'with a blank password_reset_token' do
         
     | 
| 
      
 71 
     | 
    
         
            +
                  it 'renders #new password form with notice' do
         
     | 
| 
      
 72 
     | 
    
         
            +
                    user = create(:user)
         
     | 
| 
      
 73 
     | 
    
         
            +
                    get :edit, id: user.id, token: nil
         
     | 
| 
      
 74 
     | 
    
         
            +
                    expect(response).to be_success
         
     | 
| 
      
 75 
     | 
    
         
            +
                    expect(response).to render_template(:new)
         
     | 
| 
      
 76 
     | 
    
         
            +
                  end
         
     | 
| 
      
 77 
     | 
    
         
            +
                end
         
     | 
| 
      
 78 
     | 
    
         
            +
              end
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
              describe 'put to #update' do
         
     | 
| 
      
 81 
     | 
    
         
            +
                context 'with valid password_reset_token and new password' do
         
     | 
| 
      
 82 
     | 
    
         
            +
                  it 'updates the user password' do
         
     | 
| 
      
 83 
     | 
    
         
            +
                    user = create(:user, :with_password_reset_token_and_timestamp)
         
     | 
| 
      
 84 
     | 
    
         
            +
                    old_encrypted_password = user.encrypted_password
         
     | 
| 
      
 85 
     | 
    
         
            +
                    put :update, update_params(user, new_password: 'new_password')
         
     | 
| 
      
 86 
     | 
    
         
            +
                    expect(user.reload.encrypted_password).not_to eq old_encrypted_password
         
     | 
| 
      
 87 
     | 
    
         
            +
                  end
         
     | 
| 
      
 88 
     | 
    
         
            +
                  it 'signs in the user' do
         
     | 
| 
      
 89 
     | 
    
         
            +
                    user = create(:user, :with_password_reset_token_and_timestamp)
         
     | 
| 
      
 90 
     | 
    
         
            +
                    put :update, update_params(user, new_password: 'new_password')
         
     | 
| 
      
 91 
     | 
    
         
            +
                    expect(cookies[:authenticate_session_token]).to be_present
         
     | 
| 
      
 92 
     | 
    
         
            +
                    expect(cookies[:authenticate_session_token]).to eq user.reload.session_token
         
     | 
| 
      
 93 
     | 
    
         
            +
                  end
         
     | 
| 
      
 94 
     | 
    
         
            +
                  it 'redirects user' do
         
     | 
| 
      
 95 
     | 
    
         
            +
                    user = create(:user, :with_password_reset_token_and_timestamp)
         
     | 
| 
      
 96 
     | 
    
         
            +
                    put :update, update_params(user, new_password: 'new_password')
         
     | 
| 
      
 97 
     | 
    
         
            +
                    expect(response).to redirect_to(Authenticate.configuration.redirect_url)
         
     | 
| 
      
 98 
     | 
    
         
            +
                  end
         
     | 
| 
      
 99 
     | 
    
         
            +
                end
         
     | 
| 
      
 100 
     | 
    
         
            +
                context 'with invalid new password' do
         
     | 
| 
      
 101 
     | 
    
         
            +
                  it 're-renders password edit form' do
         
     | 
| 
      
 102 
     | 
    
         
            +
                    user = create(:user, :with_password_reset_token_and_timestamp)
         
     | 
| 
      
 103 
     | 
    
         
            +
                    put :update, update_params(user, new_password: 'short')
         
     | 
| 
      
 104 
     | 
    
         
            +
                    expect(response).to render_template(:edit)
         
     | 
| 
      
 105 
     | 
    
         
            +
                  end
         
     | 
| 
      
 106 
     | 
    
         
            +
                end
         
     | 
| 
      
 107 
     | 
    
         
            +
             
     | 
| 
      
 108 
     | 
    
         
            +
              end
         
     | 
| 
      
 109 
     | 
    
         
            +
             
     | 
| 
      
 110 
     | 
    
         
            +
              def update_params(user, options = {})
         
     | 
| 
      
 111 
     | 
    
         
            +
                new_password = options.fetch(:new_password)
         
     | 
| 
      
 112 
     | 
    
         
            +
                {
         
     | 
| 
      
 113 
     | 
    
         
            +
                    id: user,
         
     | 
| 
      
 114 
     | 
    
         
            +
                    token: user.password_reset_token,
         
     | 
| 
      
 115 
     | 
    
         
            +
                    password_reset: { password: new_password }
         
     | 
| 
      
 116 
     | 
    
         
            +
                }
         
     | 
| 
      
 117 
     | 
    
         
            +
              end
         
     | 
| 
      
 118 
     | 
    
         
            +
             
     | 
| 
      
 119 
     | 
    
         
            +
            end
         
     |