authentication-zero 2.10.0 → 2.11.2
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/.rubocop.yml +15 -0
- data/CHANGELOG.md +6 -0
- data/Gemfile.lock +1 -1
- data/README.md +3 -1
- data/authentication-zero-api.md +0 -3
- data/lib/authentication_zero/version.rb +1 -1
- data/lib/generators/authentication/authentication_generator.rb +30 -20
- data/lib/generators/authentication/templates/controllers/api/application_controller.rb.tt +3 -2
- data/lib/generators/authentication/templates/controllers/api/identity/email_verifications_controller.rb.tt +9 -1
- data/lib/generators/authentication/templates/controllers/api/identity/emails_controller.rb.tt +3 -2
- data/lib/generators/authentication/templates/controllers/api/sessions/sudos_controller.rb.tt +1 -1
- data/lib/generators/authentication/templates/controllers/html/application_controller.rb.tt +3 -2
- data/lib/generators/authentication/templates/controllers/html/identity/emails_controller.rb.tt +3 -2
- data/lib/generators/authentication/templates/controllers/html/sessions/sudos_controller.rb.tt +1 -1
- data/lib/generators/authentication/templates/controllers/html/sessions_controller.rb.tt +13 -0
- data/lib/generators/authentication/templates/controllers/html/two_factor_authentication/totps_controller.rb.tt +3 -2
- data/lib/generators/authentication/templates/erb/identity/emails/edit.html.erb.tt +5 -0
- data/lib/generators/authentication/templates/erb/identity_mailer/email_verify_confirmation.html.erb.tt +5 -1
- data/lib/generators/authentication/templates/erb/identity_mailer/email_verify_confirmation.text.erb.tt +5 -1
- data/lib/generators/authentication/templates/erb/two_factor_authentication/totps/new.html.erb.tt +5 -0
- data/lib/generators/authentication/templates/mailers/identity_mailer.rb.tt +4 -0
- data/lib/generators/authentication/templates/migrations/create_sessions_migration.rb.tt +0 -3
- data/lib/generators/authentication/templates/models/model.rb.tt +3 -0
- data/lib/generators/authentication/templates/models/session.rb.tt +8 -1
- data/lib/generators/authentication/templates/test_unit/application_system_test_case.rb.tt +1 -1
- data/lib/generators/authentication/templates/test_unit/controllers/api/identity/email_verifications_controller_test.rb.tt +8 -4
- data/lib/generators/authentication/templates/test_unit/controllers/api/identity/emails_controller_test.rb.tt +9 -7
- data/lib/generators/authentication/templates/test_unit/controllers/api/identity/password_resets_controller_test.rb.tt +0 -3
- data/lib/generators/authentication/templates/test_unit/controllers/api/passwords_controller_test.rb.tt +6 -2
- data/lib/generators/authentication/templates/test_unit/controllers/api/sessions_controller_test.rb.tt +7 -3
- data/lib/generators/authentication/templates/test_unit/controllers/html/identity/emails_controller_test.rb.tt +5 -12
- data/lib/generators/authentication/templates/test_unit/controllers/html/identity/password_resets_controller_test.rb.tt +0 -3
- data/lib/generators/authentication/templates/test_unit/system/identity/emails_test.rb.tt +1 -0
- data/lib/generators/authentication/templates/test_unit/system/identity/password_resets_test.rb.tt +0 -3
- metadata +3 -6
- data/lib/generators/authentication/templates/controllers/html/sessions_controller_two_factor.rb.tt +0 -41
- data/lib/generators/authentication/templates/test_unit/controllers/api/sessions/sudos_controller_test.rb.tt +0 -20
- data/lib/generators/authentication/templates/test_unit/controllers/html/sessions/sudos_controller_test.rb.tt +0 -22
- 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:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 650afdee62e14e099849af5cc58536c67b0cbdc0164e69d02a085c5e556cdfa1
|
4
|
+
data.tar.gz: 3435f8fc73fe7c7ff04a18b1dacd27b6d24c72d58ac2d98966d69228fd177a55
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cbec3a074fa00aa2f492c58b6940266de7e61502e7957e4f096d479a74f5a0663e5160e82289888fa7cff7b2138b3bd4472f6dd0e41ca48e4f5592b3dfd89e08
|
7
|
+
data.tar.gz: b2d51d9c1b6b562893d1a324c7904a9450dfa85858ecc3a6a18a8bf4f7230b3c8943e18b7f899312b0acd7e0b70f2464ce645144682d9cb73cbc9c62bc6f838a
|
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
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -13,7 +13,9 @@ The purpose of authentication zero is to generate a pre-built authentication sys
|
|
13
13
|
- Authentication by token (--api)
|
14
14
|
- Two factor authentication (--two-factor)
|
15
15
|
- Social Login with OmniAuth (--omniauthable)
|
16
|
-
-
|
16
|
+
- Verify email using a link with token
|
17
|
+
- Verify email using a six random digits code for api (--code-verifiable)
|
18
|
+
- Ask password before sensitive data changes, aka: sudo (--sudoable)
|
17
19
|
- Reset the user password and send reset instructions
|
18
20
|
- Reset the user password only from verified emails
|
19
21
|
- Lock sending reset password email after many attempts (--lockable)
|
data/authentication-zero-api.md
CHANGED
@@ -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
|
}
|
@@ -3,20 +3,22 @@ require "rails/generators/active_record"
|
|
3
3
|
class AuthenticationGenerator < Rails::Generators::NamedBase
|
4
4
|
include ActiveRecord::Generators::Migration
|
5
5
|
|
6
|
-
class_option :api,
|
7
|
-
class_option :pwned,
|
8
|
-
class_option :
|
9
|
-
class_option :
|
10
|
-
class_option :
|
11
|
-
class_option :
|
12
|
-
class_option :
|
6
|
+
class_option :api, type: :boolean, desc: "Generates API authentication"
|
7
|
+
class_option :pwned, type: :boolean, desc: "Add pwned password validation"
|
8
|
+
class_option :code_verifiable, type: :boolean, desc: "Add email verification using a code for api"
|
9
|
+
class_option :sudoable, type: :boolean, desc: "Add password request before sensitive data changes"
|
10
|
+
class_option :lockable, type: :boolean, desc: "Add password reset locking"
|
11
|
+
class_option :ratelimit, type: :boolean, desc: "Add request rate limiting"
|
12
|
+
class_option :omniauthable, type: :boolean, desc: "Add social login support"
|
13
|
+
class_option :trackable, type: :boolean, desc: "Add activity log support"
|
14
|
+
class_option :two_factor, type: :boolean, desc: "Add two factor authentication"
|
13
15
|
|
14
16
|
source_root File.expand_path("templates", __dir__)
|
15
17
|
|
16
18
|
def add_gems
|
17
19
|
uncomment_lines "Gemfile", /"bcrypt"/
|
18
|
-
uncomment_lines "Gemfile", /"redis"/ if
|
19
|
-
uncomment_lines "Gemfile", /"kredis"/ if
|
20
|
+
uncomment_lines "Gemfile", /"redis"/ if redis?
|
21
|
+
uncomment_lines "Gemfile", /"kredis"/ if redis?
|
20
22
|
|
21
23
|
if options.pwned?
|
22
24
|
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]"
|
@@ -38,7 +40,7 @@ class AuthenticationGenerator < Rails::Generators::NamedBase
|
|
38
40
|
end
|
39
41
|
|
40
42
|
def create_configuration_files
|
41
|
-
copy_file "config/redis/shared.yml", "config/redis/shared.yml" if
|
43
|
+
copy_file "config/redis/shared.yml", "config/redis/shared.yml" if redis?
|
42
44
|
copy_file "config/initializers/omniauth.rb", "config/initializers/omniauth.rb" if omniauthable?
|
43
45
|
end
|
44
46
|
|
@@ -72,17 +74,12 @@ class AuthenticationGenerator < Rails::Generators::NamedBase
|
|
72
74
|
def create_controllers
|
73
75
|
template "controllers/#{format_folder}/application_controller.rb", "app/controllers/application_controller.rb", force: true
|
74
76
|
|
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
|
81
|
-
|
82
77
|
directory "controllers/#{format_folder}/identity", "app/controllers/identity"
|
78
|
+
directory "controllers/#{format_folder}/two_factor_authentication", "app/controllers/two_factor_authentication" if two_factor?
|
79
|
+
template "controllers/#{format_folder}/sessions_controller.rb", "app/controllers/sessions_controller.rb"
|
83
80
|
template "controllers/#{format_folder}/passwords_controller.rb", "app/controllers/passwords_controller.rb"
|
84
81
|
template "controllers/#{format_folder}/registrations_controller.rb", "app/controllers/registrations_controller.rb"
|
85
|
-
template "controllers/#{format_folder}/sessions/sudos_controller.rb", "app/controllers/sessions/sudos_controller.rb"
|
82
|
+
template "controllers/#{format_folder}/sessions/sudos_controller.rb", "app/controllers/sessions/sudos_controller.rb" if options.sudoable?
|
86
83
|
template "controllers/#{format_folder}/sessions/omniauth_controller.rb", "app/controllers/sessions/omniauth_controller.rb" if omniauthable?
|
87
84
|
template "controllers/#{format_folder}/authentications/events_controller.rb", "app/controllers/authentications/events_controller.rb" if options.trackable?
|
88
85
|
end
|
@@ -98,7 +95,12 @@ class AuthenticationGenerator < Rails::Generators::NamedBase
|
|
98
95
|
directory "erb/identity", "app/views/identity"
|
99
96
|
directory "erb/passwords", "app/views/passwords"
|
100
97
|
directory "erb/registrations", "app/views/registrations"
|
101
|
-
|
98
|
+
|
99
|
+
template "erb/sessions/index.html.erb", "app/views/sessions/index.html.erb"
|
100
|
+
template "erb/sessions/new.html.erb", "app/views/sessions/new.html.erb"
|
101
|
+
|
102
|
+
directory "erb/sessions/sudos", "app/views/sessions/sudos" if options.sudoable?
|
103
|
+
|
102
104
|
directory "erb/two_factor_authentication", "app/views/two_factor_authentication" if two_factor?
|
103
105
|
directory "erb/authentications/events", "app/views/authentications/events" if options.trackable?
|
104
106
|
end
|
@@ -127,7 +129,7 @@ class AuthenticationGenerator < Rails::Generators::NamedBase
|
|
127
129
|
route "resource :password_reset, only: [:new, :edit, :create, :update]", namespace: :identity
|
128
130
|
route "resource :email_verification, only: [:edit, :create]", namespace: :identity
|
129
131
|
route "resource :email, only: [:edit, :update]", namespace: :identity
|
130
|
-
route "resource :sudo, only: [:new, :create]", namespace: :sessions
|
132
|
+
route "resource :sudo, only: [:new, :create]", namespace: :sessions if options.sudoable?
|
131
133
|
route "resource :password, only: [:edit, :update]"
|
132
134
|
route "resources :sessions, only: [:index, :show, :destroy]"
|
133
135
|
route "post 'sign_up', to: 'registrations#create'"
|
@@ -155,4 +157,12 @@ class AuthenticationGenerator < Rails::Generators::NamedBase
|
|
155
157
|
def two_factor?
|
156
158
|
options.two_factor? && !options.api?
|
157
159
|
end
|
160
|
+
|
161
|
+
def code_verifiable?
|
162
|
+
options.code_verifiable? && options.api?
|
163
|
+
end
|
164
|
+
|
165
|
+
def redis?
|
166
|
+
options.lockable? || options.sudoable? || code_verifiable?
|
167
|
+
end
|
158
168
|
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
|
-
|
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
|
@@ -13,8 +13,16 @@ class Identity::EmailVerificationsController < ApplicationController
|
|
13
13
|
|
14
14
|
private
|
15
15
|
def set_<%= singular_table_name %>
|
16
|
+
<%- if code_verifiable? -%>
|
17
|
+
@<%= singular_table_name %> = <%= class_name %>.find_by(email: params[:email])
|
18
|
+
|
19
|
+
unless @<%= singular_table_name %> && @<%= singular_table_name %>.verification_code.value == params[:token]
|
20
|
+
render json: { error: "That email verification code is invalid" }, status: :bad_request
|
21
|
+
end
|
22
|
+
<%- else -%>
|
16
23
|
@<%= singular_table_name %> = <%= class_name %>.where(email: params[:email]).find_signed!(params[:token], purpose: params[:email])
|
17
24
|
rescue
|
18
25
|
render json: { error: "That email verification link is invalid" }, status: :bad_request
|
19
|
-
end
|
26
|
+
<%- end -%>
|
27
|
+
end
|
20
28
|
end
|
data/lib/generators/authentication/templates/controllers/api/identity/emails_controller.rb.tt
CHANGED
@@ -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
|
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
|
data/lib/generators/authentication/templates/controllers/api/sessions/sudos_controller.rb.tt
CHANGED
@@ -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.
|
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
|
-
|
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
|
data/lib/generators/authentication/templates/controllers/html/identity/emails_controller.rb.tt
CHANGED
@@ -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
|
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
|
data/lib/generators/authentication/templates/controllers/html/sessions/sudos_controller.rb.tt
CHANGED
@@ -10,7 +10,7 @@ class Sessions::SudosController < ApplicationController
|
|
10
10
|
<%- else -%>
|
11
11
|
if session.<%= singular_table_name %>.authenticate(params[:password])
|
12
12
|
<%- end -%>
|
13
|
-
session.
|
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
|
@@ -1,5 +1,4 @@
|
|
1
1
|
class TwoFactorAuthentication::TotpsController < ApplicationController
|
2
|
-
before_action :require_sudo
|
3
2
|
before_action :set_<%= singular_table_name %>
|
4
3
|
before_action :set_totp
|
5
4
|
|
@@ -8,7 +7,9 @@ class TwoFactorAuthentication::TotpsController < ApplicationController
|
|
8
7
|
end
|
9
8
|
|
10
9
|
def create
|
11
|
-
if
|
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)
|
12
13
|
@<%= singular_table_name %>.update! otp_secret: params[:secret]
|
13
14
|
redirect_to root_path, notice: "2FA is enabled on your account"
|
14
15
|
else
|
@@ -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 %>
|
@@ -2,9 +2,13 @@
|
|
2
2
|
|
3
3
|
<p>This is to confirm that <%%= @<%= singular_table_name %>.email %> is the email you want to use on your account. If you ever lose your password, that's where we'll email a reset link.</p>
|
4
4
|
|
5
|
-
<p><strong>You must hit the link below to confirm that you received this email.</strong></p>
|
5
|
+
<p><strong>You must <%= code_verifiable? ? "put the code" : "hit the link" %> below to confirm that you received this email.</strong></p>
|
6
6
|
|
7
|
+
<%- if code_verifiable? -%>
|
8
|
+
<strong><%%= @user.verification_code.value %></strong>
|
9
|
+
<%- else -%>
|
7
10
|
<%%= link_to "Yes, use this email for my account", edit_identity_email_verification_url(token: @signed_id, email: @<%= singular_table_name %>.email) %>
|
11
|
+
<%- end -%>
|
8
12
|
|
9
13
|
<hr>
|
10
14
|
|
@@ -2,8 +2,12 @@ Hey there,
|
|
2
2
|
|
3
3
|
This is to confirm that <%%= @<%= singular_table_name %>.email %> is the email you want to use on your account. If you ever lose your password, that's where we'll email a reset link.
|
4
4
|
|
5
|
-
You must hit the link below to confirm that you received this email.
|
5
|
+
You must <%= code_verifiable? ? "put the code" : "hit the link" %> below to confirm that you received this email.
|
6
6
|
|
7
|
+
<%- if code_verifiable? -%>
|
8
|
+
<%%= @user.verification_code.value %>
|
9
|
+
<%- else -%>
|
7
10
|
[Yes, use this email for my account]<%%= edit_identity_email_verification_url(token: @signed_id, email: @<%= singular_table_name %>.email) %>
|
11
|
+
<%- end -%>
|
8
12
|
|
9
13
|
Have questions or need help? Just reply to this email and our support team will help you sort it out.
|
data/lib/generators/authentication/templates/erb/two_factor_authentication/totps/new.html.erb.tt
CHANGED
@@ -17,6 +17,11 @@
|
|
17
17
|
<%%= form_with(url: two_factor_authentication_totp_path) do |form| %>
|
18
18
|
<%%= form.hidden_field :secret, value: @totp.secret %>
|
19
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
|
+
|
20
25
|
<div>
|
21
26
|
<%%= form.label :code, "After scanning with your camera, the app will generate a six-digit code. Enter it here:", style: "display: block" %>
|
22
27
|
<%%= form.text_field :code, autofocus: true, required: true, autocomplete: :off %>
|
@@ -8,7 +8,11 @@ class IdentityMailer < ApplicationMailer
|
|
8
8
|
|
9
9
|
def email_verify_confirmation
|
10
10
|
@<%= singular_table_name %> = params[:<%= singular_table_name %>]
|
11
|
+
<%- if code_verifiable? -%>
|
12
|
+
@<%= singular_table_name %>.verification_code.value = rand.to_s[2..7]
|
13
|
+
<%- else -%>
|
11
14
|
@signed_id = @<%= singular_table_name %>.signed_id(purpose: @<%= singular_table_name %>.email, expires_in: 2.days)
|
15
|
+
<%- end -%>
|
12
16
|
|
13
17
|
mail to: @<%= singular_table_name %>.email, subject: "Verify your email"
|
14
18
|
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,6 +5,9 @@ class <%= class_name %> < ApplicationRecord
|
|
5
5
|
<%- if options.trackable? -%>
|
6
6
|
has_many :events, dependent: :destroy
|
7
7
|
<%- end -%>
|
8
|
+
<%- if code_verifiable? %>
|
9
|
+
kredis_string :verification_code, expires_in: 2.days
|
10
|
+
<%- end -%>
|
8
11
|
|
9
12
|
validates :email, presence: true, uniqueness: true
|
10
13
|
validates_format_of :email, with: /\A[^@\s]+@[^@\s]+\z/
|
@@ -1,11 +1,18 @@
|
|
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
|
@@ -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:
|
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:
|
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:
|
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:
|
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"
|
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
|
14
|
-
|
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 :
|
19
|
-
assert_equal "
|
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:
|
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:
|
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:
|
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:
|
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:
|
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
|
26
|
-
|
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
|
-
|
29
|
-
|
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
|
data/lib/generators/authentication/templates/test_unit/system/identity/password_resets_test.rb.tt
CHANGED
@@ -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
|
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.11.2
|
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-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,7 +55,6 @@ 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
|
57
|
-
- lib/generators/authentication/templates/controllers/html/sessions_controller_two_factor.rb.tt
|
58
58
|
- lib/generators/authentication/templates/controllers/html/two_factor_authentication/challenges_controller.rb.tt
|
59
59
|
- lib/generators/authentication/templates/controllers/html/two_factor_authentication/totps_controller.rb.tt
|
60
60
|
- lib/generators/authentication/templates/erb/authentications/events/index.html.erb
|
@@ -90,21 +90,18 @@ files:
|
|
90
90
|
- lib/generators/authentication/templates/test_unit/controllers/api/identity/password_resets_controller_test.rb.tt
|
91
91
|
- lib/generators/authentication/templates/test_unit/controllers/api/passwords_controller_test.rb.tt
|
92
92
|
- lib/generators/authentication/templates/test_unit/controllers/api/registrations_controller_test.rb.tt
|
93
|
-
- lib/generators/authentication/templates/test_unit/controllers/api/sessions/sudos_controller_test.rb.tt
|
94
93
|
- lib/generators/authentication/templates/test_unit/controllers/api/sessions_controller_test.rb.tt
|
95
94
|
- lib/generators/authentication/templates/test_unit/controllers/html/identity/email_verifications_controller_test.rb.tt
|
96
95
|
- lib/generators/authentication/templates/test_unit/controllers/html/identity/emails_controller_test.rb.tt
|
97
96
|
- lib/generators/authentication/templates/test_unit/controllers/html/identity/password_resets_controller_test.rb.tt
|
98
97
|
- lib/generators/authentication/templates/test_unit/controllers/html/passwords_controller_test.rb.tt
|
99
98
|
- lib/generators/authentication/templates/test_unit/controllers/html/registrations_controller_test.rb.tt
|
100
|
-
- lib/generators/authentication/templates/test_unit/controllers/html/sessions/sudos_controller_test.rb.tt
|
101
99
|
- lib/generators/authentication/templates/test_unit/controllers/html/sessions_controller_test.rb.tt
|
102
100
|
- lib/generators/authentication/templates/test_unit/fixtures.yml.tt
|
103
101
|
- lib/generators/authentication/templates/test_unit/system/identity/emails_test.rb.tt
|
104
102
|
- lib/generators/authentication/templates/test_unit/system/identity/password_resets_test.rb.tt
|
105
103
|
- lib/generators/authentication/templates/test_unit/system/passwords_test.rb.tt
|
106
104
|
- lib/generators/authentication/templates/test_unit/system/registrations_test.rb.tt
|
107
|
-
- lib/generators/authentication/templates/test_unit/system/sessions/sudos_test.rb.tt
|
108
105
|
- lib/generators/authentication/templates/test_unit/system/sessions_test.rb.tt
|
109
106
|
- lib/generators/authentication/templates/test_unit/test_helper.rb.tt
|
110
107
|
homepage: https://github.com/lazaronixon/authentication-zero
|
data/lib/generators/authentication/templates/controllers/html/sessions_controller_two_factor.rb.tt
DELETED
@@ -1,41 +0,0 @@
|
|
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
|
@@ -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
|