authentication-zero 2.9.3 → 2.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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