authentication-zero 2.9.1 → 2.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/Gemfile.lock +1 -1
- data/README.md +7 -2
- data/lib/authentication_zero/version.rb +1 -1
- data/lib/generators/authentication/authentication_generator.rb +36 -67
- data/lib/generators/authentication/templates/controllers/api/application_controller.rb.tt +26 -0
- data/lib/generators/authentication/templates/controllers/api/identity/password_resets_controller.rb.tt +4 -4
- data/lib/generators/authentication/templates/controllers/html/application_controller.rb.tt +24 -0
- data/lib/generators/authentication/templates/controllers/html/identity/password_resets_controller.rb.tt +4 -4
- data/lib/generators/authentication/templates/controllers/html/sessions/sudos_controller.rb.tt +3 -3
- data/lib/generators/authentication/templates/controllers/html/sessions_controller_two_factor.rb.tt +41 -0
- data/lib/generators/authentication/templates/controllers/html/two_factor_authentication/challenges_controller.rb.tt +28 -0
- data/lib/generators/authentication/templates/controllers/html/two_factor_authentication/totps_controller.rb.tt +26 -0
- data/lib/generators/authentication/templates/erb/identity/password_resets/edit.html.erb.tt +3 -3
- data/lib/generators/authentication/templates/erb/passwords/edit.html.erb.tt +4 -4
- data/lib/generators/authentication/templates/erb/registrations/new.html.erb.tt +2 -2
- data/lib/generators/authentication/templates/erb/sessions/sudos/new.html.erb.tt +2 -2
- data/lib/generators/authentication/templates/erb/two_factor_authentication/challenges/new.html.erb.tt +16 -0
- data/lib/generators/authentication/templates/erb/two_factor_authentication/totps/new.html.erb.tt +28 -0
- data/lib/generators/authentication/templates/migrations/create_table_migration.rb.tt +7 -4
- data/lib/generators/authentication/templates/models/model.rb.tt +8 -8
- data/lib/generators/authentication/templates/models/session.rb.tt +2 -2
- data/lib/generators/authentication/templates/test_unit/application_system_test_case.rb.tt +15 -0
- data/lib/generators/authentication/templates/test_unit/controllers/api/identity/email_verifications_controller_test.rb.tt +0 -4
- data/lib/generators/authentication/templates/test_unit/controllers/api/identity/emails_controller_test.rb.tt +0 -4
- data/lib/generators/authentication/templates/test_unit/controllers/api/identity/password_resets_controller_test.rb.tt +2 -2
- data/lib/generators/authentication/templates/test_unit/controllers/api/passwords_controller_test.rb.tt +0 -4
- data/lib/generators/authentication/templates/test_unit/controllers/api/sessions/sudos_controller_test.rb.tt +0 -4
- data/lib/generators/authentication/templates/test_unit/controllers/api/sessions_controller_test.rb.tt +0 -4
- data/lib/generators/authentication/templates/test_unit/controllers/html/identity/email_verifications_controller_test.rb.tt +0 -4
- data/lib/generators/authentication/templates/test_unit/controllers/html/identity/emails_controller_test.rb.tt +0 -4
- data/lib/generators/authentication/templates/test_unit/controllers/html/identity/password_resets_controller_test.rb.tt +2 -2
- data/lib/generators/authentication/templates/test_unit/controllers/html/passwords_controller_test.rb.tt +0 -4
- data/lib/generators/authentication/templates/test_unit/controllers/html/sessions/sudos_controller_test.rb.tt +0 -4
- data/lib/generators/authentication/templates/test_unit/controllers/html/sessions_controller_test.rb.tt +0 -4
- data/lib/generators/authentication/templates/test_unit/system/identity/emails_test.rb.tt +0 -10
- data/lib/generators/authentication/templates/test_unit/system/identity/password_resets_test.rb.tt +2 -2
- data/lib/generators/authentication/templates/test_unit/system/passwords_test.rb.tt +0 -10
- data/lib/generators/authentication/templates/test_unit/system/sessions/sudos_test.rb.tt +0 -10
- data/lib/generators/authentication/templates/test_unit/system/sessions_test.rb.tt +4 -7
- data/lib/generators/authentication/templates/test_unit/test_helper.rb.tt +22 -0
- metadata +11 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c0ad4048d0c9df83173acebd1bbf770f519a7bb2a8b5b45c7e9af3c268904052
|
4
|
+
data.tar.gz: 06a897ebfc48122cfaf151a49b7412ef13b098069eb3bc7a2a4c088bcc711c90
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fd26a42853d553616f366e1ddc57439ce91ba039f2cf25a5d3c80be48a6b0f0e7fee6816ead70587780ebc8a358e74e53543c0b6438eb39d7baf818aacc5191c
|
7
|
+
data.tar.gz: 657bb45b7e9edfd6a036e9df9a2df41a2b2001199e65586d82548d7bd4ade28946be06ec3dbb28ba6fba100e275881c1a02dbb3de29b8546899393829b4cdc97
|
data/CHANGELOG.md
CHANGED
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -11,6 +11,7 @@ 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
16
|
- Ask password before sensitive data changes, aka: sudo
|
16
17
|
- Reset the user password and send reset instructions
|
@@ -53,7 +54,7 @@ root "home#index"
|
|
53
54
|
```
|
54
55
|
|
55
56
|
```
|
56
|
-
|
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
|
-
|
101
|
+
rails generate authentication user
|
97
102
|
```
|
98
103
|
|
99
104
|
Then run `bundle install` again!
|
@@ -9,6 +9,7 @@ class AuthenticationGenerator < Rails::Generators::NamedBase
|
|
9
9
|
class_option :ratelimit, type: :boolean, desc: "Add request rate limiting"
|
10
10
|
class_option :omniauthable, type: :boolean, desc: "Add social login support"
|
11
11
|
class_option :trackable, type: :boolean, desc: "Add activity log support"
|
12
|
+
class_option :two_factor, type: :boolean, desc: "Add two factor authentication"
|
12
13
|
|
13
14
|
source_root File.expand_path("templates", __dir__)
|
14
15
|
|
@@ -29,15 +30,20 @@ class AuthenticationGenerator < Rails::Generators::NamedBase
|
|
29
30
|
gem "omniauth", comment: "Use OmniAuth to support multi-provider authentication [https://github.com/omniauth/omniauth]"
|
30
31
|
gem "omniauth-rails_csrf_protection", comment: "Provides a mitigation against CVE-2015-9284 [https://github.com/cookpad/omniauth-rails_csrf_protection]"
|
31
32
|
end
|
33
|
+
|
34
|
+
if two_factor?
|
35
|
+
gem "rotp", comment: "Use rotp for generating and validating one time passwords [https://github.com/mdp/rotp]"
|
36
|
+
gem "rqrcode", comment: "Use rqrcode for creating and rendering QR codes into various formats [https://github.com/whomwah/rqrcode]"
|
37
|
+
end
|
32
38
|
end
|
33
39
|
|
34
40
|
def create_configuration_files
|
35
|
-
|
36
|
-
|
41
|
+
copy_file "config/redis/shared.yml", "config/redis/shared.yml" if options.lockable?
|
42
|
+
copy_file "config/initializers/omniauth.rb", "config/initializers/omniauth.rb" if omniauthable?
|
37
43
|
end
|
38
44
|
|
39
45
|
def add_environment_configurations
|
40
|
-
|
46
|
+
ratelimit_code = <<~CODE
|
41
47
|
# Rate limit general requests by IP address in a rate of 1000 requests per hour
|
42
48
|
config.middleware.use(Rack::Ratelimit, name: "General", rate: [1000, 1.hour], redis: Redis.new, logger: Rails.logger) { |env| ActionDispatch::Request.new(env).ip }
|
43
49
|
CODE
|
@@ -63,68 +69,19 @@ class AuthenticationGenerator < Rails::Generators::NamedBase
|
|
63
69
|
template "test_unit/fixtures.yml", "test/fixtures/#{fixture_file_name}.yml"
|
64
70
|
end
|
65
71
|
|
66
|
-
def
|
67
|
-
|
68
|
-
include ActionController::HttpAuthentication::Token::ControllerMethods
|
69
|
-
|
70
|
-
before_action :set_current_request_details
|
71
|
-
before_action :authenticate
|
72
|
-
|
73
|
-
def require_sudo
|
74
|
-
if Current.session.sudo_at < 30.minutes.ago
|
75
|
-
render json: { error: "Enter your password to continue" }, status: :forbidden
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
private
|
80
|
-
def authenticate
|
81
|
-
if session = authenticate_with_http_token { |token, _| Session.find_signed(token) }
|
82
|
-
Current.session = session
|
83
|
-
else
|
84
|
-
request_http_token_authentication
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
def set_current_request_details
|
89
|
-
Current.user_agent = request.user_agent
|
90
|
-
Current.ip_address = request.ip
|
91
|
-
end
|
92
|
-
CODE
|
93
|
-
|
94
|
-
html_code = <<~CODE
|
95
|
-
before_action :set_current_request_details
|
96
|
-
before_action :authenticate
|
97
|
-
|
98
|
-
def require_sudo
|
99
|
-
if Current.session.sudo_at < 30.minutes.ago
|
100
|
-
redirect_to new_sessions_sudo_path(proceed_to_url: request.url)
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
private
|
105
|
-
def authenticate
|
106
|
-
if session = Session.find_by_id(cookies.signed[:session_token])
|
107
|
-
Current.session = session
|
108
|
-
else
|
109
|
-
redirect_to sign_in_path
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
def set_current_request_details
|
114
|
-
Current.user_agent = request.user_agent
|
115
|
-
Current.ip_address = request.ip
|
116
|
-
end
|
117
|
-
CODE
|
72
|
+
def create_controllers
|
73
|
+
template "controllers/#{format_folder}/application_controller.rb", "app/controllers/application_controller.rb", force: true
|
118
74
|
|
119
|
-
|
120
|
-
|
121
|
-
|
75
|
+
if two_factor?
|
76
|
+
directory "controllers/#{format_folder}/two_factor_authentication", "app/controllers/two_factor_authentication"
|
77
|
+
template "controllers/#{format_folder}/sessions_controller_two_factor.rb", "app/controllers/sessions_controller.rb"
|
78
|
+
else
|
79
|
+
template "controllers/#{format_folder}/sessions_controller.rb", "app/controllers/sessions_controller.rb"
|
80
|
+
end
|
122
81
|
|
123
|
-
def create_controllers
|
124
82
|
directory "controllers/#{format_folder}/identity", "app/controllers/identity"
|
125
83
|
template "controllers/#{format_folder}/passwords_controller.rb", "app/controllers/passwords_controller.rb"
|
126
84
|
template "controllers/#{format_folder}/registrations_controller.rb", "app/controllers/registrations_controller.rb"
|
127
|
-
template "controllers/#{format_folder}/sessions_controller.rb", "app/controllers/sessions_controller.rb"
|
128
85
|
template "controllers/#{format_folder}/sessions/sudos_controller.rb", "app/controllers/sessions/sudos_controller.rb"
|
129
86
|
template "controllers/#{format_folder}/sessions/omniauth_controller.rb", "app/controllers/sessions/omniauth_controller.rb" if omniauthable?
|
130
87
|
template "controllers/#{format_folder}/authentications/events_controller.rb", "app/controllers/authentications/events_controller.rb" if options.trackable?
|
@@ -142,6 +99,7 @@ class AuthenticationGenerator < Rails::Generators::NamedBase
|
|
142
99
|
directory "erb/passwords", "app/views/passwords"
|
143
100
|
directory "erb/registrations", "app/views/registrations"
|
144
101
|
directory "erb/sessions", "app/views/sessions"
|
102
|
+
directory "erb/two_factor_authentication", "app/views/two_factor_authentication" if two_factor?
|
145
103
|
directory "erb/authentications/events", "app/views/authentications/events" if options.trackable?
|
146
104
|
end
|
147
105
|
end
|
@@ -153,29 +111,36 @@ class AuthenticationGenerator < Rails::Generators::NamedBase
|
|
153
111
|
def add_routes
|
154
112
|
if omniauthable?
|
155
113
|
route "post '/auth/:provider/callback', to: 'sessions/omniauth#create'"
|
156
|
-
route "get
|
157
|
-
route "get
|
114
|
+
route "get '/auth/:provider/callback', to: 'sessions/omniauth#create'"
|
115
|
+
route "get '/auth/failure', to: 'sessions/omniauth#failure'"
|
116
|
+
end
|
117
|
+
|
118
|
+
if two_factor?
|
119
|
+
route "resource :totp, only: [:new, :create]", namespace: :two_factor_authentication
|
120
|
+
route "resource :challenge, only: [:new, :create]", namespace: :two_factor_authentication
|
158
121
|
end
|
159
122
|
|
160
123
|
if options.trackable?
|
161
124
|
route "resources :events, only: :index", namespace: :authentications
|
162
125
|
end
|
163
126
|
|
164
|
-
route "resource :password_reset,
|
127
|
+
route "resource :password_reset, only: [:new, :edit, :create, :update]", namespace: :identity
|
165
128
|
route "resource :email_verification, only: [:edit, :create]", namespace: :identity
|
166
|
-
route "resource :email,
|
129
|
+
route "resource :email, only: [:edit, :update]", namespace: :identity
|
167
130
|
route "resource :sudo, only: [:new, :create]", namespace: :sessions
|
131
|
+
route "resource :password, only: [:edit, :update]"
|
168
132
|
route "resources :sessions, only: [:index, :show, :destroy]"
|
169
|
-
route "resource :password, only: [:edit, :update]"
|
170
133
|
route "post 'sign_up', to: 'registrations#create'"
|
171
|
-
route "get
|
134
|
+
route "get 'sign_up', to: 'registrations#new'" unless options.api?
|
172
135
|
route "post 'sign_in', to: 'sessions#create'"
|
173
|
-
route "get
|
136
|
+
route "get 'sign_in', to: 'sessions#new'" unless options.api?
|
174
137
|
end
|
175
138
|
|
176
139
|
def create_test_files
|
177
140
|
directory "test_unit/controllers/#{format_folder}", "test/controllers"
|
178
141
|
directory "test_unit/system", "test/system" unless options.api?
|
142
|
+
template "test_unit/test_helper.rb", "test/test_helper.rb", force: true
|
143
|
+
template "test_unit/application_system_test_case.rb", "test/application_system_test_case.rb", force: true unless options.api?
|
179
144
|
end
|
180
145
|
|
181
146
|
private
|
@@ -186,4 +151,8 @@ class AuthenticationGenerator < Rails::Generators::NamedBase
|
|
186
151
|
def omniauthable?
|
187
152
|
options.omniauthable? && !options.api?
|
188
153
|
end
|
154
|
+
|
155
|
+
def two_factor?
|
156
|
+
options.two_factor? && !options.api?
|
157
|
+
end
|
189
158
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class ApplicationController < ActionController::API
|
2
|
+
include ActionController::HttpAuthentication::Token::ControllerMethods
|
3
|
+
|
4
|
+
before_action :set_current_request_details
|
5
|
+
before_action :authenticate
|
6
|
+
|
7
|
+
def require_sudo
|
8
|
+
if Current.session.sudo_at < 30.minutes.ago
|
9
|
+
render json: { error: "Enter your password to continue" }, status: :forbidden
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
def authenticate
|
15
|
+
if session = authenticate_with_http_token { |token, _| Session.find_signed(token) }
|
16
|
+
Current.session = session
|
17
|
+
else
|
18
|
+
request_http_token_authentication
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def set_current_request_details
|
23
|
+
Current.user_agent = request.user_agent
|
24
|
+
Current.ip_address = request.ip
|
25
|
+
end
|
26
|
+
end
|
@@ -1,9 +1,9 @@
|
|
1
1
|
class Identity::PasswordResetsController < ApplicationController
|
2
2
|
skip_before_action :authenticate
|
3
3
|
|
4
|
-
|
4
|
+
<%- if options.lockable? -%>
|
5
5
|
before_action :require_locking, only: :create
|
6
|
-
|
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
|
-
|
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
|
-
|
41
|
+
<%- end -%>
|
42
42
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class ApplicationController < ActionController::Base
|
2
|
+
before_action :set_current_request_details
|
3
|
+
before_action :authenticate
|
4
|
+
|
5
|
+
def require_sudo
|
6
|
+
if Current.session.sudo_at < 30.minutes.ago
|
7
|
+
redirect_to new_sessions_sudo_path(proceed_to_url: request.url)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
def authenticate
|
13
|
+
if session = Session.find_by_id(cookies.signed[:session_token])
|
14
|
+
Current.session = session
|
15
|
+
else
|
16
|
+
redirect_to sign_in_path
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def set_current_request_details
|
21
|
+
Current.user_agent = request.user_agent
|
22
|
+
Current.ip_address = request.ip
|
23
|
+
end
|
24
|
+
end
|
@@ -1,9 +1,9 @@
|
|
1
1
|
class Identity::PasswordResetsController < ApplicationController
|
2
2
|
skip_before_action :authenticate
|
3
3
|
|
4
|
-
|
4
|
+
<%- if options.lockable? -%>
|
5
5
|
before_action :require_locking, only: :create
|
6
|
-
|
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
|
-
|
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
|
-
|
48
|
+
<%- end -%>
|
49
49
|
end
|
data/lib/generators/authentication/templates/controllers/html/sessions/sudos_controller.rb.tt
CHANGED
@@ -5,11 +5,11 @@ class Sessions::SudosController < ApplicationController
|
|
5
5
|
def create
|
6
6
|
session = Current.session
|
7
7
|
|
8
|
-
|
8
|
+
<%- if omniauthable? -%>
|
9
9
|
if session.<%= singular_table_name %>.authenticate(params[:password]) || session.<%= singular_table_name %>.provider
|
10
|
-
|
10
|
+
<%- else -%>
|
11
11
|
if session.<%= singular_table_name %>.authenticate(params[:password])
|
12
|
-
|
12
|
+
<%- end -%>
|
13
13
|
session.update!(sudo_at: Time.current); 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"
|
data/lib/generators/authentication/templates/controllers/html/sessions_controller_two_factor.rb.tt
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
class SessionsController < ApplicationController
|
2
|
+
skip_before_action :authenticate, only: %i[ new create ]
|
3
|
+
|
4
|
+
before_action :set_session, only: :destroy
|
5
|
+
|
6
|
+
def index
|
7
|
+
@sessions = Current.<%= singular_table_name %>.sessions.order(created_at: :desc)
|
8
|
+
end
|
9
|
+
|
10
|
+
def new
|
11
|
+
@<%= singular_table_name %> = <%= class_name %>.new
|
12
|
+
end
|
13
|
+
|
14
|
+
def create
|
15
|
+
<%= singular_table_name %> = <%= class_name %>.find_by(email: params[:email])
|
16
|
+
|
17
|
+
if <%= singular_table_name %> && <%= singular_table_name %>.authenticate(params[:password])
|
18
|
+
if <%= singular_table_name %>.otp_secret
|
19
|
+
signed_id = <%= singular_table_name %>.signed_id(purpose: :authentication_challenge, expires_in: 20.minutes)
|
20
|
+
|
21
|
+
redirect_to new_two_factor_authentication_challenge_path(token: signed_id)
|
22
|
+
else
|
23
|
+
@session = <%= singular_table_name %>.sessions.create!
|
24
|
+
cookies.signed.permanent[:session_token] = { value: @session.id, httponly: true }
|
25
|
+
|
26
|
+
redirect_to root_path, notice: "Signed in successfully"
|
27
|
+
end
|
28
|
+
else
|
29
|
+
redirect_to sign_in_path(email_hint: params[:email]), alert: "That email or password is incorrect"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def destroy
|
34
|
+
@session.destroy; redirect_to(sessions_path, notice: "That session has been logged out")
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
def set_session
|
39
|
+
@session = Current.<%= singular_table_name %>.sessions.find(params[:id])
|
40
|
+
end
|
41
|
+
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,26 @@
|
|
1
|
+
class TwoFactorAuthentication::TotpsController < ApplicationController
|
2
|
+
before_action :require_sudo
|
3
|
+
before_action :set_<%= singular_table_name %>
|
4
|
+
before_action :set_totp
|
5
|
+
|
6
|
+
def new
|
7
|
+
@qr_code = RQRCode::QRCode.new(@totp.provisioning_uri(@<%= singular_table_name %>.email))
|
8
|
+
end
|
9
|
+
|
10
|
+
def create
|
11
|
+
if @totp.verify(params[:code], drift_behind: 15)
|
12
|
+
@<%= singular_table_name %>.update! otp_secret: params[:secret]
|
13
|
+
redirect_to root_path, notice: "2FA is enabled on your account"
|
14
|
+
else
|
15
|
+
redirect_to two_factor_authentication_totp_path, alert: "That code didn't work. Please try again"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def set_<%= singular_table_name %>
|
20
|
+
@<%= singular_table_name %> = Current.<%= singular_table_name %>
|
21
|
+
end
|
22
|
+
|
23
|
+
def set_totp
|
24
|
+
@totp = ROTP::TOTP.new(params[:secret] || ROTP::Base32.random, issuer: "YourAppName")
|
25
|
+
end
|
26
|
+
end
|
@@ -13,17 +13,17 @@
|
|
13
13
|
</div>
|
14
14
|
<%% end %>
|
15
15
|
|
16
|
-
<%%=
|
16
|
+
<%%= form.hidden_field :token, value: params[:token] %>
|
17
17
|
|
18
18
|
<div>
|
19
19
|
<%%= form.label :password, "New password", style: "display: block" %>
|
20
|
-
<%%= form.password_field :password, autofocus: true, autocomplete: "new-password" %>
|
20
|
+
<%%= form.password_field :password, required: true, autofocus: true, autocomplete: "new-password" %>
|
21
21
|
<div>12 characters minimum.</div>
|
22
22
|
</div>
|
23
23
|
|
24
24
|
<div>
|
25
25
|
<%%= form.label :password_confirmation, "Confirm new password", style: "display: block" %>
|
26
|
-
<%%= form.password_field :password_confirmation, autocomplete: "new-password" %>
|
26
|
+
<%%= form.password_field :password_confirmation, required: true, autocomplete: "new-password" %>
|
27
27
|
</div>
|
28
28
|
|
29
29
|
<div>
|
@@ -16,19 +16,19 @@
|
|
16
16
|
<%% end %>
|
17
17
|
|
18
18
|
<div>
|
19
|
-
<%%=
|
20
|
-
<%%=
|
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>
|
24
24
|
<%%= form.label :password, "New password", style: "display: block" %>
|
25
|
-
<%%= form.password_field :password, autocomplete: "new-password" %>
|
25
|
+
<%%= form.password_field :password, required: true, autocomplete: "new-password" %>
|
26
26
|
<div>12 characters minimum.</div>
|
27
27
|
</div>
|
28
28
|
|
29
29
|
<div>
|
30
30
|
<%%= form.label :password_confirmation, "Confirm new password", style: "display: block" %>
|
31
|
-
<%%= form.password_field :password_confirmation, autocomplete: "new-password" %>
|
31
|
+
<%%= form.password_field :password_confirmation, required: true, autocomplete: "new-password" %>
|
32
32
|
</div>
|
33
33
|
|
34
34
|
<div>
|
@@ -20,13 +20,13 @@
|
|
20
20
|
|
21
21
|
<div>
|
22
22
|
<%%= form.label :password, style: "display: block" %>
|
23
|
-
<%%= form.password_field :password, autocomplete: "new-password" %>
|
23
|
+
<%%= form.password_field :password, required: true, autocomplete: "new-password" %>
|
24
24
|
<div>12 characters minimum.</div>
|
25
25
|
</div>
|
26
26
|
|
27
27
|
<div>
|
28
28
|
<%%= form.label :password_confirmation, style: "display: block" %>
|
29
|
-
<%%= form.password_field :password_confirmation, autocomplete: "new-password" %>
|
29
|
+
<%%= form.password_field :password_confirmation, required: true, autocomplete: "new-password" %>
|
30
30
|
</div>
|
31
31
|
|
32
32
|
<div>
|
@@ -4,10 +4,10 @@
|
|
4
4
|
|
5
5
|
<%%= form_with(url: sessions_sudo_path) do |form| %>
|
6
6
|
|
7
|
-
<%%=
|
7
|
+
<%%= form.hidden_field :proceed_to_url, value: params[:proceed_to_url] %>
|
8
8
|
|
9
9
|
<div>
|
10
|
-
<%%=
|
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 %>
|
data/lib/generators/authentication/templates/erb/two_factor_authentication/totps/new.html.erb.tt
ADDED
@@ -0,0 +1,28 @@
|
|
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 :code, "After scanning with your camera, the app will generate a six-digit code. Enter it here:", style: "display: block" %>
|
22
|
+
<%%= form.text_field :code, autofocus: true, required: true, autocomplete: :off %>
|
23
|
+
</div>
|
24
|
+
|
25
|
+
<div>
|
26
|
+
<%%= form.submit "Verify and active" %>
|
27
|
+
</div>
|
28
|
+
<%% 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
|
-
|
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
|
-
|
14
|
+
<%- end -%>
|
12
15
|
|
13
16
|
t.timestamps
|
14
17
|
end
|
15
18
|
|
16
19
|
add_index :<%= table_name %>, :email, unique: true
|
17
|
-
|
20
|
+
<%- if omniauthable? -%>
|
18
21
|
add_index :<%= table_name %>, [:provider, :uid], unique: true
|
19
|
-
|
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
|
-
|
5
|
+
<%- if options.trackable? -%>
|
6
6
|
has_many :events, dependent: :destroy
|
7
|
-
|
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
|
-
validates_length_of :password, minimum: 12,
|
13
|
-
validates_format_of :password, with: /(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])/,
|
14
|
-
|
12
|
+
validates_length_of :password, minimum: 12, allow_nil: true
|
13
|
+
validates_format_of :password, with: /(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])/, allow_nil: true, message: "might easily be guessed"
|
14
|
+
<%- if options.pwned? -%>
|
15
15
|
validates :password, not_pwned: { message: "might easily be guessed" }
|
16
|
-
|
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
|
-
|
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
|
-
|
45
|
+
<%- end -%>
|
46
46
|
end
|
@@ -10,7 +10,7 @@ class Session < ApplicationRecord
|
|
10
10
|
after_create_commit do
|
11
11
|
SessionMailer.with(session: self).signed_in_notification.deliver_later
|
12
12
|
end
|
13
|
-
|
13
|
+
<%- if options.trackable? %>
|
14
14
|
after_create do
|
15
15
|
<%= singular_table_name %>.events.create! action: "signed_in"
|
16
16
|
end
|
@@ -18,5 +18,5 @@ class Session < ApplicationRecord
|
|
18
18
|
after_destroy do
|
19
19
|
<%= singular_table_name %>.events.create! action: "signed_out"
|
20
20
|
end
|
21
|
-
|
21
|
+
<%- end -%>
|
22
22
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
|
4
|
+
driven_by :selenium, using: :chrome, screen_size: [1400, 1400]
|
5
|
+
|
6
|
+
def sign_in_as(<%= singular_table_name %>)
|
7
|
+
visit sign_in_url
|
8
|
+
fill_in :email, with: <%= singular_table_name %>.email
|
9
|
+
fill_in :password, with: "Secret1*3*5*"
|
10
|
+
click_on "Sign in"
|
11
|
+
|
12
|
+
assert_current_path root_url
|
13
|
+
return <%= singular_table_name %>
|
14
|
+
end
|
15
|
+
end
|
@@ -37,8 +37,4 @@ class Identity::EmailVerificationsControllerTest < ActionDispatch::IntegrationTe
|
|
37
37
|
assert_response :bad_request
|
38
38
|
assert_equal "That email verification link is invalid", response.parsed_body["error"]
|
39
39
|
end
|
40
|
-
|
41
|
-
def sign_in_as(<%= singular_table_name %>)
|
42
|
-
post(sign_in_url, params: { email: <%= singular_table_name %>.email, password: "Secret1*3*5*" }); [<%= singular_table_name %>, response.headers["X-Session-Token"]]
|
43
|
-
end
|
44
40
|
end
|
@@ -18,8 +18,4 @@ class Identity::EmailsControllerTest < ActionDispatch::IntegrationTest
|
|
18
18
|
assert_response :forbidden
|
19
19
|
assert_equal "Enter your password to continue", response.parsed_body["error"]
|
20
20
|
end
|
21
|
-
|
22
|
-
def sign_in_as(<%= singular_table_name %>)
|
23
|
-
post(sign_in_url, params: { email: <%= singular_table_name %>.email, password: "Secret1*3*5*" }); [<%= singular_table_name %>, response.headers["X-Session-Token"]]
|
24
|
-
end
|
25
21
|
end
|
@@ -6,9 +6,9 @@ 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
|
-
|
9
|
+
<%- if options.lockable? %>
|
10
10
|
teardown { Kredis.clear_all }
|
11
|
-
|
11
|
+
<%- end -%>
|
12
12
|
|
13
13
|
test "should send a password reset email" do
|
14
14
|
assert_enqueued_email_with IdentityMailer, :password_reset_provision, args: { <%= singular_table_name %>: @<%= singular_table_name %> } do
|
@@ -16,8 +16,4 @@ class PasswordsControllerTest < ActionDispatch::IntegrationTest
|
|
16
16
|
assert_response :bad_request
|
17
17
|
assert_equal "The current password you entered is incorrect", response.parsed_body["error"]
|
18
18
|
end
|
19
|
-
|
20
|
-
def sign_in_as(<%= singular_table_name %>)
|
21
|
-
post(sign_in_url, params: { email: <%= singular_table_name %>.email, password: "Secret1*3*5*" }); [<%= singular_table_name %>, response.headers["X-Session-Token"]]
|
22
|
-
end
|
23
19
|
end
|
@@ -17,8 +17,4 @@ class Sessions::SudosControllerTest < ActionDispatch::IntegrationTest
|
|
17
17
|
assert_response :bad_request
|
18
18
|
assert_equal "The password you entered is incorrect", response.parsed_body["error"]
|
19
19
|
end
|
20
|
-
|
21
|
-
def sign_in_as(<%= singular_table_name %>)
|
22
|
-
post(sign_in_url, params: { email: <%= singular_table_name %>.email, password: "Secret1*3*5*" }); [<%= singular_table_name %>, response.headers["X-Session-Token"]]
|
23
|
-
end
|
24
20
|
end
|
@@ -31,8 +31,4 @@ class SessionsControllerTest < ActionDispatch::IntegrationTest
|
|
31
31
|
delete session_url(@<%= singular_table_name %>.sessions.last), headers: { "Authorization" => "Bearer #{@token}" }
|
32
32
|
assert_response :no_content
|
33
33
|
end
|
34
|
-
|
35
|
-
def sign_in_as(<%= singular_table_name %>)
|
36
|
-
post(sign_in_url, params: { email: <%= singular_table_name %>.email, password: "Secret1*3*5*" }); [<%= singular_table_name %>, response.headers["X-Session-Token"]]
|
37
|
-
end
|
38
34
|
end
|
@@ -37,8 +37,4 @@ class Identity::EmailVerificationsControllerTest < ActionDispatch::IntegrationTe
|
|
37
37
|
assert_redirected_to edit_identity_email_url
|
38
38
|
assert_equal "That email verification link is invalid", flash[:alert]
|
39
39
|
end
|
40
|
-
|
41
|
-
def sign_in_as(<%= singular_table_name %>)
|
42
|
-
post(sign_in_url, params: { email: <%= singular_table_name %>.email, password: "Secret1*3*5*" }); <%= singular_table_name %>
|
43
|
-
end
|
44
40
|
end
|
@@ -28,8 +28,4 @@ class Identity::EmailsControllerTest < ActionDispatch::IntegrationTest
|
|
28
28
|
patch identity_email_url, params: { email: "new_email@hey.com" }
|
29
29
|
assert_redirected_to new_sessions_sudo_url(proceed_to_url: identity_email_url)
|
30
30
|
end
|
31
|
-
|
32
|
-
def sign_in_as(<%= singular_table_name %>)
|
33
|
-
post(sign_in_url, params: { email: <%= singular_table_name %>.email, password: "Secret1*3*5*" }); <%= singular_table_name %>
|
34
|
-
end
|
35
31
|
end
|
@@ -6,9 +6,9 @@ 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
|
-
|
9
|
+
<%- if options.lockable? %>
|
10
10
|
teardown { Kredis.clear_all }
|
11
|
-
|
11
|
+
<%- end -%>
|
12
12
|
|
13
13
|
test "should get new" do
|
14
14
|
get new_identity_password_reset_url
|
@@ -21,8 +21,4 @@ class PasswordsControllerTest < ActionDispatch::IntegrationTest
|
|
21
21
|
assert_redirected_to edit_password_url
|
22
22
|
assert_equal "The current password you entered is incorrect", flash[:alert]
|
23
23
|
end
|
24
|
-
|
25
|
-
def sign_in_as(<%= singular_table_name %>)
|
26
|
-
post(sign_in_url, params: { email: <%= singular_table_name %>.email, password: "Secret1*3*5*" }); <%= singular_table_name %>
|
27
|
-
end
|
28
24
|
end
|
@@ -19,8 +19,4 @@ class Sessions::SudosControllerTest < ActionDispatch::IntegrationTest
|
|
19
19
|
post sessions_sudo_url, params: { password: "SecretWrong1*3", proceed_to_url: edit_password_url }
|
20
20
|
assert_redirected_to new_sessions_sudo_url(proceed_to_url: edit_password_url)
|
21
21
|
end
|
22
|
-
|
23
|
-
def sign_in_as(<%= singular_table_name %>)
|
24
|
-
post(sign_in_url, params: { email: <%= singular_table_name %>.email, password: "Secret1*3*5*" }); [<%= singular_table_name %>, response.headers["X-Session-Token"]]
|
25
|
-
end
|
26
22
|
end
|
@@ -45,8 +45,4 @@ class SessionsControllerTest < ActionDispatch::IntegrationTest
|
|
45
45
|
follow_redirect!
|
46
46
|
assert_redirected_to sign_in_url
|
47
47
|
end
|
48
|
-
|
49
|
-
def sign_in_as(<%= singular_table_name %>)
|
50
|
-
post(sign_in_url, params: { email: <%= singular_table_name %>.email, password: "Secret1*3*5*" }); <%= singular_table_name %>
|
51
|
-
end
|
52
48
|
end
|
@@ -22,14 +22,4 @@ class Identity::EmailsTest < ApplicationSystemTestCase
|
|
22
22
|
|
23
23
|
assert_text "We sent a verification email to your email address"
|
24
24
|
end
|
25
|
-
|
26
|
-
def sign_in_as(<%= singular_table_name %>)
|
27
|
-
visit sign_in_url
|
28
|
-
fill_in :email, with: <%= singular_table_name %>.email
|
29
|
-
fill_in :password, with: "Secret1*3*5*"
|
30
|
-
click_on "Sign in"
|
31
|
-
|
32
|
-
assert_current_path root_url
|
33
|
-
return <%= singular_table_name %>
|
34
|
-
end
|
35
25
|
end
|
data/lib/generators/authentication/templates/test_unit/system/identity/password_resets_test.rb.tt
CHANGED
@@ -5,9 +5,9 @@ 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
|
-
|
8
|
+
<%- if options.lockable? %>
|
9
9
|
teardown { Kredis.clear_all }
|
10
|
-
|
10
|
+
<%- end -%>
|
11
11
|
|
12
12
|
test "sending a password reset email" do
|
13
13
|
visit sign_in_url
|
@@ -15,14 +15,4 @@ class PasswordsTest < ApplicationSystemTestCase
|
|
15
15
|
|
16
16
|
assert_text "Your password has been changed"
|
17
17
|
end
|
18
|
-
|
19
|
-
def sign_in_as(<%= singular_table_name %>)
|
20
|
-
visit sign_in_url
|
21
|
-
fill_in :email, with: <%= singular_table_name %>.email
|
22
|
-
fill_in :password, with: "Secret1*3*5*"
|
23
|
-
click_on "Sign in"
|
24
|
-
|
25
|
-
assert_current_path root_url
|
26
|
-
return <%= singular_table_name %>
|
27
|
-
end
|
28
18
|
end
|
@@ -12,14 +12,4 @@ class Sessions::SudosTest < ApplicationSystemTestCase
|
|
12
12
|
|
13
13
|
assert_selector "h1", text: "Change your password"
|
14
14
|
end
|
15
|
-
|
16
|
-
def sign_in_as(<%= singular_table_name %>)
|
17
|
-
visit sign_in_url
|
18
|
-
fill_in :email, with: <%= singular_table_name %>.email
|
19
|
-
fill_in :password, with: "Secret1*3*5*"
|
20
|
-
click_on "Sign in"
|
21
|
-
|
22
|
-
assert_current_path root_url
|
23
|
-
return <%= singular_table_name %>
|
24
|
-
end
|
25
15
|
end
|
@@ -21,13 +21,10 @@ class SessionsTest < ApplicationSystemTestCase
|
|
21
21
|
assert_text "Signed in successfully"
|
22
22
|
end
|
23
23
|
|
24
|
-
|
25
|
-
|
26
|
-
fill_in :email, with: <%= singular_table_name %>.email
|
27
|
-
fill_in :password, with: "Secret1*3*5*"
|
28
|
-
click_on "Sign in"
|
24
|
+
test "signing out" do
|
25
|
+
sign_in_as @<%= singular_table_name %>
|
29
26
|
|
30
|
-
|
31
|
-
|
27
|
+
click_on "Log out"
|
28
|
+
assert_text "That session has been logged out"
|
32
29
|
end
|
33
30
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
ENV["RAILS_ENV"] ||= "test"
|
2
|
+
require_relative "../config/environment"
|
3
|
+
require "rails/test_help"
|
4
|
+
|
5
|
+
class ActiveSupport::TestCase
|
6
|
+
# Run tests in parallel with specified workers
|
7
|
+
parallelize(workers: :number_of_processors)
|
8
|
+
|
9
|
+
# Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
|
10
|
+
fixtures :all
|
11
|
+
|
12
|
+
# Add more helper methods to be used by all tests here...
|
13
|
+
<%- if options.api? -%>
|
14
|
+
def sign_in_as(<%= singular_table_name %>)
|
15
|
+
post(sign_in_url, params: { email: <%= singular_table_name %>.email, password: "Secret1*3*5*" }); [<%= singular_table_name %>, response.headers["X-Session-Token"]]
|
16
|
+
end
|
17
|
+
<%- else -%>
|
18
|
+
def sign_in_as(<%= singular_table_name %>)
|
19
|
+
post(sign_in_url, params: { email: <%= singular_table_name %>.email, password: "Secret1*3*5*" }); <%= singular_table_name %>
|
20
|
+
end
|
21
|
+
<%- end -%>
|
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.
|
4
|
+
version: 2.10.0
|
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-
|
11
|
+
date: 2022-03-14 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description:
|
14
14
|
email:
|
@@ -35,6 +35,7 @@ files:
|
|
35
35
|
- lib/generators/authentication/authentication_generator.rb
|
36
36
|
- lib/generators/authentication/templates/config/initializers/omniauth.rb
|
37
37
|
- lib/generators/authentication/templates/config/redis/shared.yml
|
38
|
+
- lib/generators/authentication/templates/controllers/api/application_controller.rb.tt
|
38
39
|
- lib/generators/authentication/templates/controllers/api/authentications/events_controller.rb.tt
|
39
40
|
- lib/generators/authentication/templates/controllers/api/identity/email_verifications_controller.rb.tt
|
40
41
|
- lib/generators/authentication/templates/controllers/api/identity/emails_controller.rb.tt
|
@@ -43,6 +44,7 @@ files:
|
|
43
44
|
- lib/generators/authentication/templates/controllers/api/registrations_controller.rb.tt
|
44
45
|
- lib/generators/authentication/templates/controllers/api/sessions/sudos_controller.rb.tt
|
45
46
|
- lib/generators/authentication/templates/controllers/api/sessions_controller.rb.tt
|
47
|
+
- lib/generators/authentication/templates/controllers/html/application_controller.rb.tt
|
46
48
|
- lib/generators/authentication/templates/controllers/html/authentications/events_controller.rb.tt
|
47
49
|
- lib/generators/authentication/templates/controllers/html/identity/email_verifications_controller.rb.tt
|
48
50
|
- lib/generators/authentication/templates/controllers/html/identity/emails_controller.rb.tt
|
@@ -52,6 +54,9 @@ files:
|
|
52
54
|
- lib/generators/authentication/templates/controllers/html/sessions/omniauth_controller.rb.tt
|
53
55
|
- lib/generators/authentication/templates/controllers/html/sessions/sudos_controller.rb.tt
|
54
56
|
- lib/generators/authentication/templates/controllers/html/sessions_controller.rb.tt
|
57
|
+
- lib/generators/authentication/templates/controllers/html/sessions_controller_two_factor.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
|
55
60
|
- lib/generators/authentication/templates/erb/authentications/events/index.html.erb
|
56
61
|
- lib/generators/authentication/templates/erb/identity/emails/edit.html.erb.tt
|
57
62
|
- lib/generators/authentication/templates/erb/identity/password_resets/edit.html.erb.tt
|
@@ -67,6 +72,8 @@ files:
|
|
67
72
|
- lib/generators/authentication/templates/erb/sessions/index.html.erb.tt
|
68
73
|
- lib/generators/authentication/templates/erb/sessions/new.html.erb.tt
|
69
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
|
70
77
|
- lib/generators/authentication/templates/mailers/identity_mailer.rb.tt
|
71
78
|
- lib/generators/authentication/templates/mailers/session_mailer.rb.tt
|
72
79
|
- lib/generators/authentication/templates/migrations/create_events_migration.rb.tt
|
@@ -77,6 +84,7 @@ files:
|
|
77
84
|
- lib/generators/authentication/templates/models/locking.rb.tt
|
78
85
|
- lib/generators/authentication/templates/models/model.rb.tt
|
79
86
|
- lib/generators/authentication/templates/models/session.rb.tt
|
87
|
+
- lib/generators/authentication/templates/test_unit/application_system_test_case.rb.tt
|
80
88
|
- lib/generators/authentication/templates/test_unit/controllers/api/identity/email_verifications_controller_test.rb.tt
|
81
89
|
- lib/generators/authentication/templates/test_unit/controllers/api/identity/emails_controller_test.rb.tt
|
82
90
|
- lib/generators/authentication/templates/test_unit/controllers/api/identity/password_resets_controller_test.rb.tt
|
@@ -98,6 +106,7 @@ files:
|
|
98
106
|
- lib/generators/authentication/templates/test_unit/system/registrations_test.rb.tt
|
99
107
|
- lib/generators/authentication/templates/test_unit/system/sessions/sudos_test.rb.tt
|
100
108
|
- lib/generators/authentication/templates/test_unit/system/sessions_test.rb.tt
|
109
|
+
- lib/generators/authentication/templates/test_unit/test_helper.rb.tt
|
101
110
|
homepage: https://github.com/lazaronixon/authentication-zero
|
102
111
|
licenses:
|
103
112
|
- MIT
|