authentication-zero 2.9.3 → 2.11.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +15 -0
  3. data/CHANGELOG.md +10 -0
  4. data/Gemfile.lock +1 -1
  5. data/README.md +8 -3
  6. data/authentication-zero-api.md +0 -3
  7. data/lib/authentication_zero/version.rb +1 -1
  8. data/lib/generators/authentication/authentication_generator.rb +34 -7
  9. data/lib/generators/authentication/templates/controllers/api/application_controller.rb.tt +3 -2
  10. data/lib/generators/authentication/templates/controllers/api/identity/emails_controller.rb.tt +3 -2
  11. data/lib/generators/authentication/templates/controllers/api/identity/password_resets_controller.rb.tt +4 -4
  12. data/lib/generators/authentication/templates/controllers/api/sessions/sudos_controller.rb.tt +1 -1
  13. data/lib/generators/authentication/templates/controllers/html/application_controller.rb.tt +3 -2
  14. data/lib/generators/authentication/templates/controllers/html/identity/emails_controller.rb.tt +3 -2
  15. data/lib/generators/authentication/templates/controllers/html/identity/password_resets_controller.rb.tt +4 -4
  16. data/lib/generators/authentication/templates/controllers/html/sessions/sudos_controller.rb.tt +4 -4
  17. data/lib/generators/authentication/templates/controllers/html/sessions_controller.rb.tt +13 -0
  18. data/lib/generators/authentication/templates/controllers/html/two_factor_authentication/challenges_controller.rb.tt +28 -0
  19. data/lib/generators/authentication/templates/controllers/html/two_factor_authentication/totps_controller.rb.tt +27 -0
  20. data/lib/generators/authentication/templates/erb/identity/emails/edit.html.erb.tt +5 -0
  21. data/lib/generators/authentication/templates/erb/identity/password_resets/edit.html.erb.tt +1 -1
  22. data/lib/generators/authentication/templates/erb/passwords/edit.html.erb.tt +2 -2
  23. data/lib/generators/authentication/templates/erb/sessions/sudos/new.html.erb.tt +2 -2
  24. data/lib/generators/authentication/templates/erb/two_factor_authentication/challenges/new.html.erb.tt +16 -0
  25. data/lib/generators/authentication/templates/erb/two_factor_authentication/totps/new.html.erb.tt +33 -0
  26. data/lib/generators/authentication/templates/migrations/create_sessions_migration.rb.tt +0 -3
  27. data/lib/generators/authentication/templates/migrations/create_table_migration.rb.tt +7 -4
  28. data/lib/generators/authentication/templates/models/model.rb.tt +6 -6
  29. data/lib/generators/authentication/templates/models/session.rb.tt +10 -3
  30. data/lib/generators/authentication/templates/test_unit/application_system_test_case.rb.tt +1 -1
  31. data/lib/generators/authentication/templates/test_unit/controllers/api/identity/email_verifications_controller_test.rb.tt +8 -4
  32. data/lib/generators/authentication/templates/test_unit/controllers/api/identity/emails_controller_test.rb.tt +9 -7
  33. data/lib/generators/authentication/templates/test_unit/controllers/api/identity/password_resets_controller_test.rb.tt +0 -3
  34. data/lib/generators/authentication/templates/test_unit/controllers/api/passwords_controller_test.rb.tt +6 -2
  35. data/lib/generators/authentication/templates/test_unit/controllers/api/sessions_controller_test.rb.tt +7 -3
  36. data/lib/generators/authentication/templates/test_unit/controllers/html/identity/emails_controller_test.rb.tt +5 -12
  37. data/lib/generators/authentication/templates/test_unit/controllers/html/identity/password_resets_controller_test.rb.tt +0 -3
  38. data/lib/generators/authentication/templates/test_unit/system/identity/emails_test.rb.tt +1 -0
  39. data/lib/generators/authentication/templates/test_unit/system/identity/password_resets_test.rb.tt +0 -3
  40. data/lib/generators/authentication/templates/test_unit/test_helper.rb.tt +3 -3
  41. metadata +7 -5
  42. data/lib/generators/authentication/templates/test_unit/controllers/api/sessions/sudos_controller_test.rb.tt +0 -20
  43. data/lib/generators/authentication/templates/test_unit/controllers/html/sessions/sudos_controller_test.rb.tt +0 -22
  44. data/lib/generators/authentication/templates/test_unit/system/sessions/sudos_test.rb.tt +0 -15
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d8173a1510dfbe78180ce29cbb83b5f79b84b0ed4ecacf0569344905c28f2a01
4
- data.tar.gz: 9d89bc1c96a4b59b7c7bf2437bd038036e747f4e78c0a7d5a81f1c0ae4c86f28
3
+ metadata.gz: 26344aaefae4e99ea2048950089e5927a62d473f85d94596456006d6edbbc8ee
4
+ data.tar.gz: eebff7007c4754244993ac76b022081ccbd0201dac5cd1611ec84f8845e7a5d0
5
5
  SHA512:
6
- metadata.gz: 34a5ed73cbd7f5e35cd9a1e16ae0e4880a677ffa94f3892c0c6292abb436b3fded01c4664dd5e77d5b8025718b60ea8507bdbd968243d94ef191980615b02ea4
7
- data.tar.gz: 2afb2c4fbc2bef0c7e06fab12cf783f04c6bc811d7150ed58f4a73f430c23925f4e790c6e3477729e04f2ade59b80dd30220667952d7b41cc98a4106fc4e064e
6
+ metadata.gz: 6ccd04a438745b60d071c9203c5e36588b01333a17e37a5ee1067c7007824d52fb2a3be0c5e4864868c393f9dec04e2284487651f7d7b0f908c238dcbf4a9dd2
7
+ data.tar.gz: 51b53ff133cdf9a69e42f29cadd19127646d6c98a6d476c1565c5e6151708b57f4076e1f19af4f4335b8bd6a08ac90b9328b6fe393f85d702dd7d415621a9c8a
data/.rubocop.yml ADDED
@@ -0,0 +1,15 @@
1
+ inherit_from: https://raw.githubusercontent.com/rails/rails/master/.rubocop.yml
2
+
3
+ Performance:
4
+ Exclude:
5
+ - 'test/**/*'
6
+
7
+ Style/FrozenStringLiteralComment:
8
+ Enabled: false
9
+
10
+ Style/StringLiterals:
11
+ Enabled: true
12
+ EnforcedStyle: double_quotes
13
+ Include:
14
+ - 'app/**/*'
15
+ - 'test/**/*'
data/CHANGELOG.md CHANGED
@@ -1,3 +1,13 @@
1
+ ## Authentication Zero 2.11.0 (March 27, 2022) ##
2
+
3
+ * Remove sudo from default generator
4
+ * Remove sudo_at from database
5
+ * Implement sudoable using redis
6
+
7
+ ## Authentication Zero 2.10.0 (March 2, 2022) ##
8
+
9
+ * Implement two-factor
10
+
1
11
  ## Authentication Zero 2.9.0 (March 2, 2022) ##
2
12
 
3
13
  * Implement trackable
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- authentication-zero (2.9.3)
4
+ authentication-zero (2.11.1)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -11,8 +11,9 @@ The purpose of authentication zero is to generate a pre-built authentication sys
11
11
  - Checks if a password has been found in any data breach (--pwned)
12
12
  - Authentication by cookie
13
13
  - Authentication by token (--api)
14
+ - Two factor authentication (--two-factor)
14
15
  - Social Login with OmniAuth (--omniauthable)
15
- - Ask password before sensitive data changes, aka: sudo
16
+ - Ask password before sensitive data changes, aka: sudo (--sudoable)
16
17
  - Reset the user password and send reset instructions
17
18
  - Reset the user password only from verified emails
18
19
  - Lock sending reset password email after many attempts (--lockable)
@@ -53,7 +54,7 @@ root "home#index"
53
54
  ```
54
55
 
55
56
  ```
56
- $ rails generate controller home index
57
+ rails generate controller home index
57
58
  ```
58
59
 
59
60
  Add these lines to your `app/views/home/index.html.erb`:
@@ -79,6 +80,10 @@ Add these lines to your `app/views/home/index.html.erb`:
79
80
  <%# link_to "Activity Log", authentications_events_path %>
80
81
  </div>
81
82
 
83
+ <div>
84
+ <%# link_to "Two-Factor Authentication", new_two_factor_authentication_totp_path %>
85
+ </div>
86
+
82
87
  <br>
83
88
 
84
89
  <%= button_to "Log out", Current.session, method: :delete %>
@@ -93,7 +98,7 @@ config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
93
98
  ## Usage
94
99
 
95
100
  ```
96
- $ rails generate authentication user
101
+ rails generate authentication user
97
102
  ```
98
103
 
99
104
  Then run `bundle install` again!
@@ -78,7 +78,6 @@ This endpoint will return `201 Created` with the current JSON representation of
78
78
  "user_id": 1,
79
79
  "user_agent": "insomnia/2022.1.0",
80
80
  "ip_address": "127.0.0.1",
81
- "sudo_at": "2022-03-04T17:20:33.632Z",
82
81
  "created_at": "2022-03-04T17:20:33.632Z",
83
82
  "updated_at": "2022-03-04T17:20:33.632Z"
84
83
  },
@@ -87,7 +86,6 @@ This endpoint will return `201 Created` with the current JSON representation of
87
86
  "user_id": 1,
88
87
  "user_agent": "insomnia/2022.1.0",
89
88
  "ip_address": "127.0.0.1",
90
- "sudo_at": "2022-03-04T17:14:03.386Z",
91
89
  "created_at": "2022-03-04T17:14:03.386Z",
92
90
  "updated_at": "2022-03-04T17:14:03.386Z"
93
91
  }
@@ -106,7 +104,6 @@ This endpoint will return `201 Created` with the current JSON representation of
106
104
  "user_id": 1,
107
105
  "user_agent": "insomnia/2022.1.0",
108
106
  "ip_address": "127.0.0.1",
109
- "sudo_at": "2022-03-04T17:14:03.386Z",
110
107
  "created_at": "2022-03-04T17:14:03.386Z",
111
108
  "updated_at": "2022-03-04T17:14:03.386Z"
112
109
  }
@@ -1,3 +1,3 @@
1
1
  module AuthenticationZero
2
- VERSION = "2.9.3"
2
+ VERSION = "2.11.1"
3
3
  end
@@ -5,17 +5,19 @@ class AuthenticationGenerator < Rails::Generators::NamedBase
5
5
 
6
6
  class_option :api, type: :boolean, desc: "Generates API authentication"
7
7
  class_option :pwned, type: :boolean, desc: "Add pwned password validation"
8
+ class_option :sudoable, type: :boolean, desc: "Add password request before sensitive data changes"
8
9
  class_option :lockable, type: :boolean, desc: "Add password reset locking"
9
10
  class_option :ratelimit, type: :boolean, desc: "Add request rate limiting"
10
11
  class_option :omniauthable, type: :boolean, desc: "Add social login support"
11
12
  class_option :trackable, type: :boolean, desc: "Add activity log support"
13
+ class_option :two_factor, type: :boolean, desc: "Add two factor authentication"
12
14
 
13
15
  source_root File.expand_path("templates", __dir__)
14
16
 
15
17
  def add_gems
16
18
  uncomment_lines "Gemfile", /"bcrypt"/
17
- uncomment_lines "Gemfile", /"redis"/ if options.lockable?
18
- uncomment_lines "Gemfile", /"kredis"/ if options.lockable?
19
+ uncomment_lines "Gemfile", /"redis"/ if redis?
20
+ uncomment_lines "Gemfile", /"kredis"/ if redis?
19
21
 
20
22
  if options.pwned?
21
23
  gem "pwned", comment: "Use Pwned to check if a password has been found in any of the huge data breaches [https://github.com/philnash/pwned]"
@@ -29,10 +31,15 @@ class AuthenticationGenerator < Rails::Generators::NamedBase
29
31
  gem "omniauth", comment: "Use OmniAuth to support multi-provider authentication [https://github.com/omniauth/omniauth]"
30
32
  gem "omniauth-rails_csrf_protection", comment: "Provides a mitigation against CVE-2015-9284 [https://github.com/cookpad/omniauth-rails_csrf_protection]"
31
33
  end
34
+
35
+ if two_factor?
36
+ gem "rotp", comment: "Use rotp for generating and validating one time passwords [https://github.com/mdp/rotp]"
37
+ gem "rqrcode", comment: "Use rqrcode for creating and rendering QR codes into various formats [https://github.com/whomwah/rqrcode]"
38
+ end
32
39
  end
33
40
 
34
41
  def create_configuration_files
35
- copy_file "config/redis/shared.yml", "config/redis/shared.yml" if options.lockable?
42
+ copy_file "config/redis/shared.yml", "config/redis/shared.yml" if redis?
36
43
  copy_file "config/initializers/omniauth.rb", "config/initializers/omniauth.rb" if omniauthable?
37
44
  end
38
45
 
@@ -67,10 +74,11 @@ class AuthenticationGenerator < Rails::Generators::NamedBase
67
74
  template "controllers/#{format_folder}/application_controller.rb", "app/controllers/application_controller.rb", force: true
68
75
 
69
76
  directory "controllers/#{format_folder}/identity", "app/controllers/identity"
77
+ directory "controllers/#{format_folder}/two_factor_authentication", "app/controllers/two_factor_authentication" if two_factor?
78
+ template "controllers/#{format_folder}/sessions_controller.rb", "app/controllers/sessions_controller.rb"
70
79
  template "controllers/#{format_folder}/passwords_controller.rb", "app/controllers/passwords_controller.rb"
71
80
  template "controllers/#{format_folder}/registrations_controller.rb", "app/controllers/registrations_controller.rb"
72
- template "controllers/#{format_folder}/sessions_controller.rb", "app/controllers/sessions_controller.rb"
73
- template "controllers/#{format_folder}/sessions/sudos_controller.rb", "app/controllers/sessions/sudos_controller.rb"
81
+ template "controllers/#{format_folder}/sessions/sudos_controller.rb", "app/controllers/sessions/sudos_controller.rb" if options.sudoable?
74
82
  template "controllers/#{format_folder}/sessions/omniauth_controller.rb", "app/controllers/sessions/omniauth_controller.rb" if omniauthable?
75
83
  template "controllers/#{format_folder}/authentications/events_controller.rb", "app/controllers/authentications/events_controller.rb" if options.trackable?
76
84
  end
@@ -86,7 +94,13 @@ class AuthenticationGenerator < Rails::Generators::NamedBase
86
94
  directory "erb/identity", "app/views/identity"
87
95
  directory "erb/passwords", "app/views/passwords"
88
96
  directory "erb/registrations", "app/views/registrations"
89
- directory "erb/sessions", "app/views/sessions"
97
+
98
+ template "erb/sessions/index.html.erb", "app/views/sessions/index.html.erb"
99
+ template "erb/sessions/new.html.erb", "app/views/sessions/new.html.erb"
100
+
101
+ directory "erb/sessions/sudos", "app/views/sessions/sudos" if options.sudoable?
102
+
103
+ directory "erb/two_factor_authentication", "app/views/two_factor_authentication" if two_factor?
90
104
  directory "erb/authentications/events", "app/views/authentications/events" if options.trackable?
91
105
  end
92
106
  end
@@ -102,6 +116,11 @@ class AuthenticationGenerator < Rails::Generators::NamedBase
102
116
  route "get '/auth/failure', to: 'sessions/omniauth#failure'"
103
117
  end
104
118
 
119
+ if two_factor?
120
+ route "resource :totp, only: [:new, :create]", namespace: :two_factor_authentication
121
+ route "resource :challenge, only: [:new, :create]", namespace: :two_factor_authentication
122
+ end
123
+
105
124
  if options.trackable?
106
125
  route "resources :events, only: :index", namespace: :authentications
107
126
  end
@@ -109,7 +128,7 @@ class AuthenticationGenerator < Rails::Generators::NamedBase
109
128
  route "resource :password_reset, only: [:new, :edit, :create, :update]", namespace: :identity
110
129
  route "resource :email_verification, only: [:edit, :create]", namespace: :identity
111
130
  route "resource :email, only: [:edit, :update]", namespace: :identity
112
- route "resource :sudo, only: [:new, :create]", namespace: :sessions
131
+ route "resource :sudo, only: [:new, :create]", namespace: :sessions if options.sudoable?
113
132
  route "resource :password, only: [:edit, :update]"
114
133
  route "resources :sessions, only: [:index, :show, :destroy]"
115
134
  route "post 'sign_up', to: 'registrations#create'"
@@ -133,4 +152,12 @@ class AuthenticationGenerator < Rails::Generators::NamedBase
133
152
  def omniauthable?
134
153
  options.omniauthable? && !options.api?
135
154
  end
155
+
156
+ def two_factor?
157
+ options.two_factor? && !options.api?
158
+ end
159
+
160
+ def redis?
161
+ options.lockable? || options.sudoable?
162
+ end
136
163
  end
@@ -3,12 +3,13 @@ class ApplicationController < ActionController::API
3
3
 
4
4
  before_action :set_current_request_details
5
5
  before_action :authenticate
6
-
6
+ <%- if options.sudoable? %>
7
7
  def require_sudo
8
- if Current.session.sudo_at < 30.minutes.ago
8
+ unless Current.session.sudo?
9
9
  render json: { error: "Enter your password to continue" }, status: :forbidden
10
10
  end
11
11
  end
12
+ <%- end -%>
12
13
 
13
14
  private
14
15
  def authenticate
@@ -1,9 +1,10 @@
1
1
  class Identity::EmailsController < ApplicationController
2
- before_action :require_sudo
3
2
  before_action :set_<%= singular_table_name %>
4
3
 
5
4
  def update
6
- if @<%= singular_table_name %>.update(<%= "#{singular_table_name}_params" %>)
5
+ if !@<%= singular_table_name %>.authenticate(params[:current_password])
6
+ render json: { error: "The password you entered is incorrect" }, status: :bad_request
7
+ elsif @<%= singular_table_name %>.update(<%= "#{singular_table_name}_params" %>)
7
8
  render json: @<%= singular_table_name %>
8
9
  else
9
10
  render json: @<%= singular_table_name %>.errors, status: :unprocessable_entity
@@ -1,9 +1,9 @@
1
1
  class Identity::PasswordResetsController < ApplicationController
2
2
  skip_before_action :authenticate
3
3
 
4
- <% if options.lockable? -%>
4
+ <%- if options.lockable? -%>
5
5
  before_action :require_locking, only: :create
6
- <% end -%>
6
+ <%- end -%>
7
7
  before_action :set_<%= singular_table_name %>, only: :update
8
8
 
9
9
  def create
@@ -32,11 +32,11 @@ class Identity::PasswordResetsController < ApplicationController
32
32
  def <%= "#{singular_table_name}_params" %>
33
33
  params.permit(:password, :password_confirmation)
34
34
  end
35
- <% if options.lockable? %>
35
+ <%- if options.lockable? %>
36
36
  def require_locking
37
37
  Locking.lock_on("password_reset_lock:#{request.remote_ip}", wait: 1.hour, attempts: 10) do
38
38
  render json: { error: "You've exceeded the maximum number of attempts" }, status: :too_many_requests
39
39
  end
40
40
  end
41
- <% end -%>
41
+ <%- end -%>
42
42
  end
@@ -3,7 +3,7 @@ class Sessions::SudosController < ApplicationController
3
3
  session = Current.session
4
4
 
5
5
  if session.<%= singular_table_name %>.authenticate(params[:password])
6
- session.update! sudo_at: Time.current
6
+ session.sudo.mark
7
7
  else
8
8
  render json: { error: "The password you entered is incorrect" }, status: :bad_request
9
9
  end
@@ -1,12 +1,13 @@
1
1
  class ApplicationController < ActionController::Base
2
2
  before_action :set_current_request_details
3
3
  before_action :authenticate
4
-
4
+ <%- if options.sudoable? %>
5
5
  def require_sudo
6
- if Current.session.sudo_at < 30.minutes.ago
6
+ unless Current.session.sudo?
7
7
  redirect_to new_sessions_sudo_path(proceed_to_url: request.url)
8
8
  end
9
9
  end
10
+ <%- end -%>
10
11
 
11
12
  private
12
13
  def authenticate
@@ -1,12 +1,13 @@
1
1
  class Identity::EmailsController < ApplicationController
2
- before_action :require_sudo
3
2
  before_action :set_<%= singular_table_name %>
4
3
 
5
4
  def edit
6
5
  end
7
6
 
8
7
  def update
9
- if @<%= singular_table_name %>.update(<%= "#{singular_table_name}_params" %>)
8
+ if !@<%= singular_table_name %>.authenticate(params[:current_password])
9
+ redirect_to edit_identity_email_path, alert: "The password you entered is incorrect"
10
+ elsif @<%= singular_table_name %>.update(<%= "#{singular_table_name}_params" %>)
10
11
  redirect_to root_path, notice: "Your email has been changed"
11
12
  else
12
13
  render :edit, status: :unprocessable_entity
@@ -1,9 +1,9 @@
1
1
  class Identity::PasswordResetsController < ApplicationController
2
2
  skip_before_action :authenticate
3
3
 
4
- <% if options.lockable? -%>
4
+ <%- if options.lockable? -%>
5
5
  before_action :require_locking, only: :create
6
- <% end -%>
6
+ <%- end -%>
7
7
  before_action :set_<%= singular_table_name %>, only: %i[ edit update ]
8
8
 
9
9
  def new
@@ -39,11 +39,11 @@ class Identity::PasswordResetsController < ApplicationController
39
39
  def <%= "#{singular_table_name}_params" %>
40
40
  params.permit(:password, :password_confirmation)
41
41
  end
42
- <% if options.lockable? %>
42
+ <%- if options.lockable? %>
43
43
  def require_locking
44
44
  Locking.lock_on("password_reset_lock:#{request.remote_ip}", wait: 1.hour, attempts: 10) do
45
45
  redirect_to new_identity_password_reset_path, alert: "You've exceeded the maximum number of attempts"
46
46
  end
47
47
  end
48
- <% end -%>
48
+ <%- end -%>
49
49
  end
@@ -5,12 +5,12 @@ class Sessions::SudosController < ApplicationController
5
5
  def create
6
6
  session = Current.session
7
7
 
8
- <% if omniauthable? -%>
8
+ <%- if omniauthable? -%>
9
9
  if session.<%= singular_table_name %>.authenticate(params[:password]) || session.<%= singular_table_name %>.provider
10
- <% else -%>
10
+ <%- else -%>
11
11
  if session.<%= singular_table_name %>.authenticate(params[:password])
12
- <% end -%>
13
- session.update!(sudo_at: Time.current); redirect_to(params[:proceed_to_url])
12
+ <%- end -%>
13
+ session.sudo.mark; redirect_to(params[:proceed_to_url])
14
14
  else
15
15
  redirect_to new_sessions_sudo_path(proceed_to_url: params[:proceed_to_url]), alert: "The password you entered is incorrect"
16
16
  end
@@ -15,10 +15,23 @@ class SessionsController < ApplicationController
15
15
  <%= singular_table_name %> = <%= class_name %>.find_by(email: params[:email])
16
16
 
17
17
  if <%= singular_table_name %> && <%= singular_table_name %>.authenticate(params[:password])
18
+ <%- if two_factor? -%>
19
+ if <%= singular_table_name %>.otp_secret
20
+ signed_id = <%= singular_table_name %>.signed_id(purpose: :authentication_challenge, expires_in: 20.minutes)
21
+
22
+ redirect_to new_two_factor_authentication_challenge_path(token: signed_id)
23
+ else
24
+ @session = <%= singular_table_name %>.sessions.create!
25
+ cookies.signed.permanent[:session_token] = { value: @session.id, httponly: true }
26
+
27
+ redirect_to root_path, notice: "Signed in successfully"
28
+ end
29
+ <%- else -%>
18
30
  @session = <%= singular_table_name %>.sessions.create!
19
31
  cookies.signed.permanent[:session_token] = { value: @session.id, httponly: true }
20
32
 
21
33
  redirect_to root_path, notice: "Signed in successfully"
34
+ <%- end -%>
22
35
  else
23
36
  redirect_to sign_in_path(email_hint: params[:email]), alert: "That email or password is incorrect"
24
37
  end
@@ -0,0 +1,28 @@
1
+ class TwoFactorAuthentication::ChallengesController < ApplicationController
2
+ skip_before_action :authenticate
3
+
4
+ before_action :set_<%= singular_table_name %>
5
+
6
+ def new
7
+ end
8
+
9
+ def create
10
+ @totp = ROTP::TOTP.new(@<%= singular_table_name %>.otp_secret, issuer: "YourAppName")
11
+
12
+ if @totp.verify(params[:code], drift_behind: 15)
13
+ session = @<%= singular_table_name %>.sessions.create!
14
+ cookies.signed.permanent[:session_token] = { value: session.id, httponly: true }
15
+
16
+ redirect_to root_path, notice: "Signed in successfully"
17
+ else
18
+ redirect_to new_two_factor_authentication_challenge_path(token: params[:token]), alert: "That code didn't work. Please try again"
19
+ end
20
+ end
21
+
22
+ private
23
+ def set_<%= singular_table_name %>
24
+ @<%= singular_table_name %> = <%= class_name %>.find_signed!(params[:token], purpose: :authentication_challenge)
25
+ rescue
26
+ redirect_to sign_in_path, alert: "That's taking too long. Please re-enter your password and try again"
27
+ end
28
+ end
@@ -0,0 +1,27 @@
1
+ class TwoFactorAuthentication::TotpsController < ApplicationController
2
+ before_action :set_<%= singular_table_name %>
3
+ before_action :set_totp
4
+
5
+ def new
6
+ @qr_code = RQRCode::QRCode.new(@totp.provisioning_uri(@<%= singular_table_name %>.email))
7
+ end
8
+
9
+ def create
10
+ if !@<%= singular_table_name %>.authenticate(params[:current_password])
11
+ redirect_to two_factor_authentication_totp_path, alert: "The password you entered is incorrect"
12
+ elsif @totp.verify(params[:code], drift_behind: 15)
13
+ @<%= singular_table_name %>.update! otp_secret: params[:secret]
14
+ redirect_to root_path, notice: "2FA is enabled on your account"
15
+ else
16
+ redirect_to two_factor_authentication_totp_path, alert: "That code didn't work. Please try again"
17
+ end
18
+ end
19
+
20
+ def set_<%= singular_table_name %>
21
+ @<%= singular_table_name %> = Current.<%= singular_table_name %>
22
+ end
23
+
24
+ def set_totp
25
+ @totp = ROTP::TOTP.new(params[:secret] || ROTP::Base32.random, issuer: "YourAppName")
26
+ end
27
+ end
@@ -21,6 +21,11 @@
21
21
  </div>
22
22
  <%% end %>
23
23
 
24
+ <div>
25
+ <%%= form.label :current_password, style: "display: block" %>
26
+ <%%= form.password_field :current_password, required: true, autofocus: true, autocomplete: "current-password" %>
27
+ </div>
28
+
24
29
  <div>
25
30
  <%%= form.label :email, "New email", style: "display: block" %>
26
31
  <%%= form.email_field :email %>
@@ -13,7 +13,7 @@
13
13
  </div>
14
14
  <%% end %>
15
15
 
16
- <%%= hidden_field_tag :token, params[:token] %>
16
+ <%%= form.hidden_field :token, value: params[:token] %>
17
17
 
18
18
  <div>
19
19
  <%%= form.label :password, "New password", style: "display: block" %>
@@ -16,8 +16,8 @@
16
16
  <%% end %>
17
17
 
18
18
  <div>
19
- <%%= label_tag :current_password, nil, style: "display: block" %>
20
- <%%= password_field_tag :current_password, nil, required: true, autofocus: true, autocomplete: "current-password" %>
19
+ <%%= form.label :current_password, style: "display: block" %>
20
+ <%%= form.password_field :current_password, required: true, autofocus: true, autocomplete: "current-password" %>
21
21
  </div>
22
22
 
23
23
  <div>
@@ -4,10 +4,10 @@
4
4
 
5
5
  <%%= form_with(url: sessions_sudo_path) do |form| %>
6
6
 
7
- <%%= hidden_field_tag :proceed_to_url, params[:proceed_to_url] %>
7
+ <%%= form.hidden_field :proceed_to_url, value: params[:proceed_to_url] %>
8
8
 
9
9
  <div>
10
- <%%= password_field_tag :password, nil, required: true, autofocus: true, autocomplete: "current-password" %>
10
+ <%%= form.password_field :password, required: true, autofocus: true, autocomplete: "current-password" %>
11
11
  </div>
12
12
 
13
13
  <div>
@@ -0,0 +1,16 @@
1
+ <p style="color: red"><%%= alert %></p>
2
+
3
+ <%%= form_with(url: two_factor_authentication_challenge_path) do |form| %>
4
+ <%%= form.hidden_field :token, value: params[:token] %>
5
+
6
+ <div>
7
+ <%%= form.label :code do %>
8
+ <h1>Next, open the 2FA authenticator app on your phone and type the six digit code below:</h1>
9
+ <%% end %>
10
+ <%%= form.text_field :code, autofocus: true, required: true, autocomplete: :off %>
11
+ </div>
12
+
13
+ <div>
14
+ <%%= form.submit "Verify" %>
15
+ </div>
16
+ <%% end %>
@@ -0,0 +1,33 @@
1
+ <p style="color: red"><%%= alert %></p>
2
+
3
+ <h1>Upgrade your security with 2FA</h1>
4
+
5
+ <h2>Step 1: Get an Authenticator App</h2>
6
+ <p>First, you'll need a 2FA authenticator app on your phone. <strong>If you already have one, skip to step 2.</strong></p>
7
+ <p><strong>If you don't have one, or you aren't sure, we recommend Microsoft Authenticator</strong>. You can download it free on the Apple App Store for iPhone, or Google Play Store for Android. Please grab your phone, search the store, and install it now.</p>
8
+
9
+ <h2>Step 2: Scan + Enter the Code</h2>
10
+ <p>Next, open the authenticator app, tap "Scan QR code" or "+", and, when it asks, point your phone's camera at this QR code picture below.</p>
11
+
12
+ <figure>
13
+ <%%= image_tag @qr_code.as_png(resize_exactly_to: 200).to_data_url%>
14
+ <figcaption>Point your camera here</figcaption>
15
+ </figure>
16
+
17
+ <%%= form_with(url: two_factor_authentication_totp_path) do |form| %>
18
+ <%%= form.hidden_field :secret, value: @totp.secret %>
19
+
20
+ <div>
21
+ <%%= form.label :current_password, style: "display: block" %>
22
+ <%%= form.password_field :current_password, required: true, autofocus: true, autocomplete: "current-password" %>
23
+ </div>
24
+
25
+ <div>
26
+ <%%= form.label :code, "After scanning with your camera, the app will generate a six-digit code. Enter it here:", style: "display: block" %>
27
+ <%%= form.text_field :code, autofocus: true, required: true, autocomplete: :off %>
28
+ </div>
29
+
30
+ <div>
31
+ <%%= form.submit "Verify and active" %>
32
+ </div>
33
+ <%% end %>
@@ -2,12 +2,9 @@ class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Mi
2
2
  def change
3
3
  create_table :sessions do |t|
4
4
  t.references :<%= singular_table_name %>, null: false, foreign_key: true
5
-
6
5
  t.string :user_agent
7
6
  t.string :ip_address
8
7
 
9
- t.datetime :sudo_at, null: false
10
-
11
8
  t.timestamps
12
9
  end
13
10
  end
@@ -5,17 +5,20 @@ class <%= migration_class_name %> < ActiveRecord::Migration[<%= ActiveRecord::Mi
5
5
  t.string :password_digest, null: false
6
6
 
7
7
  t.boolean :verified, null: false, default: false
8
- <% if omniauthable? %>
8
+ <%- if two_factor? %>
9
+ t.string :otp_secret
10
+ <%- end -%>
11
+ <%- if omniauthable? %>
9
12
  t.string :provider
10
13
  t.string :uid
11
- <% end -%>
14
+ <%- end -%>
12
15
 
13
16
  t.timestamps
14
17
  end
15
18
 
16
19
  add_index :<%= table_name %>, :email, unique: true
17
- <% if omniauthable? -%>
20
+ <%- if omniauthable? -%>
18
21
  add_index :<%= table_name %>, [:provider, :uid], unique: true
19
- <% end -%>
22
+ <%- end -%>
20
23
  end
21
24
  end
@@ -2,18 +2,18 @@ class <%= class_name %> < ApplicationRecord
2
2
  has_secure_password
3
3
 
4
4
  has_many :sessions, dependent: :destroy
5
- <% if options.trackable? -%>
5
+ <%- if options.trackable? -%>
6
6
  has_many :events, dependent: :destroy
7
- <% end -%>
7
+ <%- end -%>
8
8
 
9
9
  validates :email, presence: true, uniqueness: true
10
10
  validates_format_of :email, with: /\A[^@\s]+@[^@\s]+\z/
11
11
 
12
12
  validates_length_of :password, minimum: 12, allow_nil: true
13
13
  validates_format_of :password, with: /(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])/, allow_nil: true, message: "might easily be guessed"
14
- <% if options.pwned? -%>
14
+ <%- if options.pwned? -%>
15
15
  validates :password, not_pwned: { message: "might easily be guessed" }
16
- <% end -%>
16
+ <%- end -%>
17
17
 
18
18
  before_validation do
19
19
  self.email = email.downcase.strip
@@ -30,7 +30,7 @@ class <%= class_name %> < ApplicationRecord
30
30
  after_save_commit if: :email_previously_changed? do
31
31
  IdentityMailer.with(user: self).email_verify_confirmation.deliver_later
32
32
  end
33
- <% if options.trackable? %>
33
+ <%- if options.trackable? %>
34
34
  after_save_commit if: :email_previously_changed? do
35
35
  events.create! action: "email_verification_requested"
36
36
  end
@@ -42,5 +42,5 @@ class <%= class_name %> < ApplicationRecord
42
42
  after_update if: :verified_previously_changed? do
43
43
  events.create! action: "email_verified" if verified?
44
44
  end
45
- <% end -%>
45
+ <%- end -%>
46
46
  end
@@ -1,16 +1,23 @@
1
1
  class Session < ApplicationRecord
2
2
  belongs_to :<%= singular_table_name %>
3
+ <%- if options.sudoable? %>
4
+ kredis_flag :sudo, expires_in: 30.minutes
5
+ <%- end -%>
3
6
 
4
7
  before_create do
5
8
  self.user_agent = Current.user_agent
6
9
  self.ip_address = Current.ip_address
7
- self.sudo_at = Time.current
8
10
  end
11
+ <%- if options.sudoable? %>
12
+ after_create_commit do
13
+ self.sudo.mark
14
+ end
15
+ <%- end -%>
9
16
 
10
17
  after_create_commit do
11
18
  SessionMailer.with(session: self).signed_in_notification.deliver_later
12
19
  end
13
- <% if options.trackable? %>
20
+ <%- if options.trackable? %>
14
21
  after_create do
15
22
  <%= singular_table_name %>.events.create! action: "signed_in"
16
23
  end
@@ -18,5 +25,5 @@ class Session < ApplicationRecord
18
25
  after_destroy do
19
26
  <%= singular_table_name %>.events.create! action: "signed_out"
20
27
  end
21
- <% end -%>
28
+ <%- end -%>
22
29
  end
@@ -10,6 +10,6 @@ class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
10
10
  click_on "Sign in"
11
11
 
12
12
  assert_current_path root_url
13
- return <%= singular_table_name %>
13
+ <%= singular_table_name %>
14
14
  end
15
15
  end
@@ -9,21 +9,25 @@ class Identity::EmailVerificationsControllerTest < ActionDispatch::IntegrationTe
9
9
  @<%= singular_table_name %>.update! verified: false
10
10
  end
11
11
 
12
+ def default_headers
13
+ { "Authorization" => "Bearer #{@token}" }
14
+ end
15
+
12
16
  test "should send a verification email" do
13
17
  assert_enqueued_email_with IdentityMailer, :email_verify_confirmation, args: { <%= singular_table_name %>: @<%= singular_table_name %> } do
14
- post identity_email_verification_url, headers: { "Authorization" => "Bearer #{@token}" }
18
+ post identity_email_verification_url, headers: default_headers
15
19
  end
16
20
 
17
21
  assert_response :no_content
18
22
  end
19
23
 
20
24
  test "should verify email" do
21
- get edit_identity_email_verification_url, params: { token: @sid, email: @<%= singular_table_name %>.email }, headers: { "Authorization" => "Bearer #{@token}" }
25
+ get edit_identity_email_verification_url, params: { token: @sid, email: @<%= singular_table_name %>.email }, headers: default_headers
22
26
  assert_response :no_content
23
27
  end
24
28
 
25
29
  test "should not verify email with expired token" do
26
- get edit_identity_email_verification_url, params: { token: @sid_exp, email: @<%= singular_table_name %>.email }, headers: { "Authorization" => "Bearer #{@token}" }
30
+ get edit_identity_email_verification_url, params: { token: @sid_exp, email: @<%= singular_table_name %>.email }, headers: default_headers
27
31
 
28
32
  assert_response :bad_request
29
33
  assert_equal "That email verification link is invalid", response.parsed_body["error"]
@@ -32,7 +36,7 @@ class Identity::EmailVerificationsControllerTest < ActionDispatch::IntegrationTe
32
36
  test "should not verify email with previous token" do
33
37
  @<%= singular_table_name %>.update! email: "other_email@hey.com"
34
38
 
35
- get edit_identity_email_verification_url, params: { token: @sid, email: @<%= singular_table_name %>.email_previously_was }, headers: { "Authorization" => "Bearer #{@token}" }
39
+ get edit_identity_email_verification_url, params: { token: @sid, email: @<%= singular_table_name %>.email_previously_was }, headers: default_headers
36
40
 
37
41
  assert_response :bad_request
38
42
  assert_equal "That email verification link is invalid", response.parsed_body["error"]
@@ -5,17 +5,19 @@ class Identity::EmailsControllerTest < ActionDispatch::IntegrationTest
5
5
  @<%= singular_table_name %>, @token = sign_in_as(<%= table_name %>(:lazaro_nixon))
6
6
  end
7
7
 
8
+ def default_headers
9
+ { "Authorization" => "Bearer #{@token}" }
10
+ end
11
+
8
12
  test "should update email" do
9
- patch identity_email_url, params: { email: "new_email@hey.com" }, headers: { "Authorization" => "Bearer #{@token}" }
13
+ patch identity_email_url, params: { email: "new_email@hey.com", current_password: "Secret1*3*5*" }, headers: default_headers
10
14
  assert_response :success
11
15
  end
12
16
 
13
- test "should not update email without sudo" do
14
- @<%= singular_table_name %>.sessions.last.update! sudo_at: 1.day.ago
15
-
16
- patch identity_email_url, params: { email: "new_email@hey.com" }, headers: { "Authorization" => "Bearer #{@token}" }
17
+ test "should not update email with wrong current password" do
18
+ patch identity_email_url, params: { email: "new_email@hey.com", current_password: "SecretWrong1*3" }, headers: default_headers
17
19
 
18
- assert_response :forbidden
19
- assert_equal "Enter your password to continue", response.parsed_body["error"]
20
+ assert_response :bad_request
21
+ assert_equal "The password you entered is incorrect", response.parsed_body["error"]
20
22
  end
21
23
  end
@@ -6,9 +6,6 @@ class Identity::PasswordResetsControllerTest < ActionDispatch::IntegrationTest
6
6
  @sid = @<%= singular_table_name %>.signed_id(purpose: :password_reset, expires_in: 20.minutes)
7
7
  @sid_exp = @<%= singular_table_name %>.signed_id(purpose: :password_reset, expires_in: 0.minutes)
8
8
  end
9
- <% if options.lockable? %>
10
- teardown { Kredis.clear_all }
11
- <% end -%>
12
9
 
13
10
  test "should send a password reset email" do
14
11
  assert_enqueued_email_with IdentityMailer, :password_reset_provision, args: { <%= singular_table_name %>: @<%= singular_table_name %> } do
@@ -5,13 +5,17 @@ class PasswordsControllerTest < ActionDispatch::IntegrationTest
5
5
  @<%= singular_table_name %>, @token = sign_in_as(<%= table_name %>(:lazaro_nixon))
6
6
  end
7
7
 
8
+ def default_headers
9
+ { "Authorization" => "Bearer #{@token}" }
10
+ end
11
+
8
12
  test "should update password" do
9
- patch password_url, params: { current_password: "Secret1*3*5*", password: "Secret6*4*2*", password_confirmation: "Secret6*4*2*" }, headers: { "Authorization" => "Bearer #{@token}" }
13
+ patch password_url, params: { current_password: "Secret1*3*5*", password: "Secret6*4*2*", password_confirmation: "Secret6*4*2*" }, headers: default_headers
10
14
  assert_response :success
11
15
  end
12
16
 
13
17
  test "should not update password with wrong current password" do
14
- patch password_url, params: { current_password: "SecretWrong1*3", password: "Secret6*4*2*", password_confirmation: "Secret6*4*2*" }, headers: { "Authorization" => "Bearer #{@token}" }
18
+ patch password_url, params: { current_password: "SecretWrong1*3", password: "Secret6*4*2*", password_confirmation: "Secret6*4*2*" }, headers: default_headers
15
19
 
16
20
  assert_response :bad_request
17
21
  assert_equal "The current password you entered is incorrect", response.parsed_body["error"]
@@ -5,13 +5,17 @@ class SessionsControllerTest < ActionDispatch::IntegrationTest
5
5
  @<%= singular_table_name %>, @token = sign_in_as(<%= table_name %>(:lazaro_nixon))
6
6
  end
7
7
 
8
+ def default_headers
9
+ { "Authorization" => "Bearer #{@token}" }
10
+ end
11
+
8
12
  test "should get index" do
9
- get sessions_url, headers: { "Authorization" => "Bearer #{@token}" }
13
+ get sessions_url, headers: default_headers
10
14
  assert_response :success
11
15
  end
12
16
 
13
17
  test "should show session" do
14
- get session_url(@<%= singular_table_name %>.sessions.last), headers: { "Authorization" => "Bearer #{@token}" }
18
+ get session_url(@<%= singular_table_name %>.sessions.last), headers: default_headers
15
19
  assert_response :success
16
20
  end
17
21
 
@@ -28,7 +32,7 @@ class SessionsControllerTest < ActionDispatch::IntegrationTest
28
32
  end
29
33
 
30
34
  test "should sign out" do
31
- delete session_url(@<%= singular_table_name %>.sessions.last), headers: { "Authorization" => "Bearer #{@token}" }
35
+ delete session_url(@<%= singular_table_name %>.sessions.last), headers: default_headers
32
36
  assert_response :no_content
33
37
  end
34
38
  end
@@ -10,22 +10,15 @@ class Identity::EmailsControllerTest < ActionDispatch::IntegrationTest
10
10
  assert_response :success
11
11
  end
12
12
 
13
- test "should not get edit without sudo" do
14
- @<%= singular_table_name %>.sessions.last.update! sudo_at: 1.day.ago
15
-
16
- get edit_identity_email_url
17
- assert_redirected_to new_sessions_sudo_url(proceed_to_url: edit_identity_email_url)
18
- end
19
-
20
13
  test "should update email" do
21
- patch identity_email_url, params: { email: "new_email@hey.com" }
14
+ patch identity_email_url, params: { email: "new_email@hey.com", current_password: "Secret1*3*5*" }
22
15
  assert_redirected_to root_url
23
16
  end
24
17
 
25
- test "should not update email without sudo" do
26
- @<%= singular_table_name %>.sessions.last.update! sudo_at: 1.day.ago
18
+ test "should not update email with wrong current password" do
19
+ patch identity_email_url, params: { email: "new_email@hey.com", current_password: "SecretWrong1*3" }
27
20
 
28
- patch identity_email_url, params: { email: "new_email@hey.com" }
29
- assert_redirected_to new_sessions_sudo_url(proceed_to_url: identity_email_url)
21
+ assert_redirected_to edit_identity_email_url
22
+ assert_equal "The password you entered is incorrect", flash[:alert]
30
23
  end
31
24
  end
@@ -6,9 +6,6 @@ class Identity::PasswordResetsControllerTest < ActionDispatch::IntegrationTest
6
6
  @sid = @<%= singular_table_name %>.signed_id(purpose: :password_reset, expires_in: 20.minutes)
7
7
  @sid_exp = @<%= singular_table_name %>.signed_id(purpose: :password_reset, expires_in: 0.minutes)
8
8
  end
9
- <% if options.lockable? %>
10
- teardown { Kredis.clear_all }
11
- <% end -%>
12
9
 
13
10
  test "should get new" do
14
11
  get new_identity_password_reset_url
@@ -8,6 +8,7 @@ class Identity::EmailsTest < ApplicationSystemTestCase
8
8
  test "updating the email" do
9
9
  click_on "Change email address"
10
10
 
11
+ fill_in "Current password", with: "Secret1*3*5*"
11
12
  fill_in "New email", with: "new_email@hey.com"
12
13
  click_on "Save changes"
13
14
 
@@ -5,9 +5,6 @@ class Identity::PasswordResetsTest < ApplicationSystemTestCase
5
5
  @<%= singular_table_name %> = <%= table_name %>(:lazaro_nixon)
6
6
  @sid = @<%= singular_table_name %>.signed_id(purpose: :password_reset, expires_in: 20.minutes)
7
7
  end
8
- <% if options.lockable? %>
9
- teardown { Kredis.clear_all }
10
- <% end -%>
11
8
 
12
9
  test "sending a password reset email" do
13
10
  visit sign_in_url
@@ -10,13 +10,13 @@ class ActiveSupport::TestCase
10
10
  fixtures :all
11
11
 
12
12
  # Add more helper methods to be used by all tests here...
13
- <% if options.api? -%>
13
+ <%- if options.api? -%>
14
14
  def sign_in_as(<%= singular_table_name %>)
15
15
  post(sign_in_url, params: { email: <%= singular_table_name %>.email, password: "Secret1*3*5*" }); [<%= singular_table_name %>, response.headers["X-Session-Token"]]
16
16
  end
17
- <% else -%>
17
+ <%- else -%>
18
18
  def sign_in_as(<%= singular_table_name %>)
19
19
  post(sign_in_url, params: { email: <%= singular_table_name %>.email, password: "Secret1*3*5*" }); <%= singular_table_name %>
20
20
  end
21
- <% end -%>
21
+ <%- end -%>
22
22
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: authentication-zero
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.9.3
4
+ version: 2.11.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nixon
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-03-08 00:00:00.000000000 Z
11
+ date: 2022-03-27 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description:
14
14
  email:
@@ -19,6 +19,7 @@ extra_rdoc_files: []
19
19
  files:
20
20
  - ".github/FUNDING.yml"
21
21
  - ".gitignore"
22
+ - ".rubocop.yml"
22
23
  - CHANGELOG.md
23
24
  - CODE_OF_CONDUCT.md
24
25
  - Gemfile
@@ -54,6 +55,8 @@ files:
54
55
  - lib/generators/authentication/templates/controllers/html/sessions/omniauth_controller.rb.tt
55
56
  - lib/generators/authentication/templates/controllers/html/sessions/sudos_controller.rb.tt
56
57
  - lib/generators/authentication/templates/controllers/html/sessions_controller.rb.tt
58
+ - lib/generators/authentication/templates/controllers/html/two_factor_authentication/challenges_controller.rb.tt
59
+ - lib/generators/authentication/templates/controllers/html/two_factor_authentication/totps_controller.rb.tt
57
60
  - lib/generators/authentication/templates/erb/authentications/events/index.html.erb
58
61
  - lib/generators/authentication/templates/erb/identity/emails/edit.html.erb.tt
59
62
  - lib/generators/authentication/templates/erb/identity/password_resets/edit.html.erb.tt
@@ -69,6 +72,8 @@ files:
69
72
  - lib/generators/authentication/templates/erb/sessions/index.html.erb.tt
70
73
  - lib/generators/authentication/templates/erb/sessions/new.html.erb.tt
71
74
  - lib/generators/authentication/templates/erb/sessions/sudos/new.html.erb.tt
75
+ - lib/generators/authentication/templates/erb/two_factor_authentication/challenges/new.html.erb.tt
76
+ - lib/generators/authentication/templates/erb/two_factor_authentication/totps/new.html.erb.tt
72
77
  - lib/generators/authentication/templates/mailers/identity_mailer.rb.tt
73
78
  - lib/generators/authentication/templates/mailers/session_mailer.rb.tt
74
79
  - lib/generators/authentication/templates/migrations/create_events_migration.rb.tt
@@ -85,21 +90,18 @@ files:
85
90
  - lib/generators/authentication/templates/test_unit/controllers/api/identity/password_resets_controller_test.rb.tt
86
91
  - lib/generators/authentication/templates/test_unit/controllers/api/passwords_controller_test.rb.tt
87
92
  - lib/generators/authentication/templates/test_unit/controllers/api/registrations_controller_test.rb.tt
88
- - lib/generators/authentication/templates/test_unit/controllers/api/sessions/sudos_controller_test.rb.tt
89
93
  - lib/generators/authentication/templates/test_unit/controllers/api/sessions_controller_test.rb.tt
90
94
  - lib/generators/authentication/templates/test_unit/controllers/html/identity/email_verifications_controller_test.rb.tt
91
95
  - lib/generators/authentication/templates/test_unit/controllers/html/identity/emails_controller_test.rb.tt
92
96
  - lib/generators/authentication/templates/test_unit/controllers/html/identity/password_resets_controller_test.rb.tt
93
97
  - lib/generators/authentication/templates/test_unit/controllers/html/passwords_controller_test.rb.tt
94
98
  - lib/generators/authentication/templates/test_unit/controllers/html/registrations_controller_test.rb.tt
95
- - lib/generators/authentication/templates/test_unit/controllers/html/sessions/sudos_controller_test.rb.tt
96
99
  - lib/generators/authentication/templates/test_unit/controllers/html/sessions_controller_test.rb.tt
97
100
  - lib/generators/authentication/templates/test_unit/fixtures.yml.tt
98
101
  - lib/generators/authentication/templates/test_unit/system/identity/emails_test.rb.tt
99
102
  - lib/generators/authentication/templates/test_unit/system/identity/password_resets_test.rb.tt
100
103
  - lib/generators/authentication/templates/test_unit/system/passwords_test.rb.tt
101
104
  - lib/generators/authentication/templates/test_unit/system/registrations_test.rb.tt
102
- - lib/generators/authentication/templates/test_unit/system/sessions/sudos_test.rb.tt
103
105
  - lib/generators/authentication/templates/test_unit/system/sessions_test.rb.tt
104
106
  - lib/generators/authentication/templates/test_unit/test_helper.rb.tt
105
107
  homepage: https://github.com/lazaronixon/authentication-zero
@@ -1,20 +0,0 @@
1
- require "test_helper"
2
-
3
- class Sessions::SudosControllerTest < ActionDispatch::IntegrationTest
4
- setup do
5
- @<%= singular_table_name %>, @token = sign_in_as(<%= table_name %>(:lazaro_nixon))
6
- @<%= singular_table_name %>.sessions.last.update! sudo_at: 1.day.ago
7
- end
8
-
9
- test "should sudo" do
10
- post sessions_sudo_url, params: { password: "Secret1*3*5*" }, headers: { "Authorization" => "Bearer #{@token}" }
11
- assert_response :no_content
12
- end
13
-
14
- test "should not sudo with wrong password" do
15
- post sessions_sudo_url, params: { password: "SecretWrong1*3" }, headers: { "Authorization" => "Bearer #{@token}" }
16
-
17
- assert_response :bad_request
18
- assert_equal "The password you entered is incorrect", response.parsed_body["error"]
19
- end
20
- end
@@ -1,22 +0,0 @@
1
- require "test_helper"
2
-
3
- class Sessions::SudosControllerTest < ActionDispatch::IntegrationTest
4
- setup do
5
- @<%= singular_table_name %> = sign_in_as(<%= table_name %>(:lazaro_nixon))
6
- end
7
-
8
- test "should get new" do
9
- get new_sessions_sudo_url(proceed_to_url: edit_password_url)
10
- assert_response :success
11
- end
12
-
13
- test "should sudo" do
14
- post sessions_sudo_url, params: { password: "Secret1*3*5*", proceed_to_url: edit_password_url }
15
- assert_redirected_to edit_password_url
16
- end
17
-
18
- test "should not sudo with wrong password" do
19
- post sessions_sudo_url, params: { password: "SecretWrong1*3", proceed_to_url: edit_password_url }
20
- assert_redirected_to new_sessions_sudo_url(proceed_to_url: edit_password_url)
21
- end
22
- end
@@ -1,15 +0,0 @@
1
- require "application_system_test_case"
2
-
3
- class Sessions::SudosTest < ApplicationSystemTestCase
4
- setup do
5
- @<%= singular_table_name %> = sign_in_as(<%= table_name %>(:lazaro_nixon))
6
- end
7
-
8
- test "executing sudo" do
9
- visit new_sessions_sudo_url(proceed_to_url: edit_password_url)
10
- fill_in :password, with: "Secret1*3*5*"
11
- click_on "Continue"
12
-
13
- assert_selector "h1", text: "Change your password"
14
- end
15
- end