quo_vadis 1.3.1 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitignore +11 -8
- data/CHANGELOG.md +26 -0
- data/Gemfile +14 -1
- data/Gemfile.lock +178 -0
- data/LICENSE.txt +21 -0
- data/README.md +435 -127
- data/Rakefile +14 -16
- data/app/controllers/quo_vadis/confirmations_controller.rb +56 -0
- data/app/controllers/quo_vadis/logs_controller.rb +20 -0
- data/app/controllers/quo_vadis/password_resets_controller.rb +65 -0
- data/app/controllers/quo_vadis/passwords_controller.rb +26 -0
- data/app/controllers/quo_vadis/recovery_codes_controller.rb +54 -0
- data/app/controllers/quo_vadis/sessions_controller.rb +50 -132
- data/app/controllers/quo_vadis/totps_controller.rb +72 -0
- data/app/controllers/quo_vadis/twofas_controller.rb +26 -0
- data/app/mailers/quo_vadis/mailer.rb +73 -0
- data/app/models/quo_vadis/account.rb +59 -0
- data/app/models/quo_vadis/account_confirmation_token.rb +17 -0
- data/app/models/quo_vadis/log.rb +57 -0
- data/app/models/quo_vadis/password.rb +52 -0
- data/app/models/quo_vadis/password_reset_token.rb +17 -0
- data/app/models/quo_vadis/recovery_code.rb +26 -0
- data/app/models/quo_vadis/session.rb +55 -0
- data/app/models/quo_vadis/token.rb +42 -0
- data/app/models/quo_vadis/totp.rb +56 -0
- data/bin/console +15 -0
- data/bin/rails +21 -0
- data/bin/setup +8 -0
- data/config/locales/quo_vadis.en.yml +51 -18
- data/config/routes.rb +40 -12
- data/db/migrate/202102150904_setup.rb +48 -0
- data/lib/generators/quo_vadis/install_generator.rb +4 -23
- data/lib/quo_vadis.rb +100 -106
- data/lib/quo_vadis/controller.rb +227 -0
- data/lib/quo_vadis/crypt.rb +43 -0
- data/lib/quo_vadis/current_request_details.rb +11 -0
- data/lib/quo_vadis/defaults.rb +18 -0
- data/lib/quo_vadis/encrypted_type.rb +17 -0
- data/lib/quo_vadis/engine.rb +9 -11
- data/lib/quo_vadis/hmacable.rb +26 -0
- data/lib/quo_vadis/ip_masking.rb +31 -0
- data/lib/quo_vadis/model.rb +86 -0
- data/lib/quo_vadis/version.rb +3 -1
- data/quo_vadis.gemspec +18 -24
- metadata +49 -229
- data/app/controllers/controller_mixin.rb +0 -109
- data/app/mailers/quo_vadis/notifier.rb +0 -30
- data/app/models/model_mixin.rb +0 -128
- data/lib/generators/quo_vadis/templates/migration.rb.erb +0 -18
- data/lib/generators/quo_vadis/templates/quo_vadis.rb.erb +0 -96
- data/test/dummy/.gitignore +0 -2
- data/test/dummy/Rakefile +0 -7
- data/test/dummy/app/controllers/application_controller.rb +0 -3
- data/test/dummy/app/controllers/articles_controller.rb +0 -20
- data/test/dummy/app/controllers/users_controller.rb +0 -17
- data/test/dummy/app/helpers/application_helper.rb +0 -2
- data/test/dummy/app/helpers/articles_helper.rb +0 -2
- data/test/dummy/app/models/article.rb +0 -2
- data/test/dummy/app/models/person.rb +0 -3
- data/test/dummy/app/models/user.rb +0 -3
- data/test/dummy/app/views/articles/index.html.erb +0 -1
- data/test/dummy/app/views/articles/new.html.erb +0 -11
- data/test/dummy/app/views/layouts/application.html.erb +0 -30
- data/test/dummy/app/views/layouts/sessions.html.erb +0 -3
- data/test/dummy/app/views/quo_vadis/notifier/change_password.text.erb +0 -9
- data/test/dummy/app/views/quo_vadis/notifier/invite.text.erb +0 -8
- data/test/dummy/app/views/sessions/edit.html.erb +0 -11
- data/test/dummy/app/views/sessions/forgotten.html.erb +0 -13
- data/test/dummy/app/views/sessions/invite.html.erb +0 -31
- data/test/dummy/app/views/sessions/new.html.erb +0 -15
- data/test/dummy/app/views/users/new.html.erb +0 -14
- data/test/dummy/config.ru +0 -4
- data/test/dummy/config/application.rb +0 -21
- data/test/dummy/config/boot.rb +0 -10
- data/test/dummy/config/database.yml +0 -22
- data/test/dummy/config/environment.rb +0 -5
- data/test/dummy/config/environments/development.rb +0 -26
- data/test/dummy/config/environments/production.rb +0 -49
- data/test/dummy/config/environments/test.rb +0 -37
- data/test/dummy/config/initializers/backtrace_silencers.rb +0 -7
- data/test/dummy/config/initializers/inflections.rb +0 -10
- data/test/dummy/config/initializers/mime_types.rb +0 -5
- data/test/dummy/config/initializers/quo_vadis.rb +0 -84
- data/test/dummy/config/initializers/rack_patch.rb +0 -16
- data/test/dummy/config/initializers/secret_token.rb +0 -7
- data/test/dummy/config/initializers/session_store.rb +0 -8
- data/test/dummy/config/locales/en.yml +0 -5
- data/test/dummy/config/locales/quo_vadis.en.yml +0 -21
- data/test/dummy/config/routes.rb +0 -5
- data/test/dummy/db/migrate/20110124125037_create_users.rb +0 -13
- data/test/dummy/db/migrate/20110124131535_create_articles.rb +0 -14
- data/test/dummy/db/migrate/20110127094709_add_authentication_to_users.rb +0 -18
- data/test/dummy/db/migrate/20111004112209_create_people.rb +0 -13
- data/test/dummy/db/migrate/20111004132342_add_authentication_to_people.rb +0 -18
- data/test/dummy/db/schema.rb +0 -33
- data/test/dummy/public/404.html +0 -26
- data/test/dummy/public/422.html +0 -26
- data/test/dummy/public/500.html +0 -26
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/public/javascripts/application.js +0 -2
- data/test/dummy/public/javascripts/controls.js +0 -965
- data/test/dummy/public/javascripts/dragdrop.js +0 -974
- data/test/dummy/public/javascripts/effects.js +0 -1123
- data/test/dummy/public/javascripts/prototype.js +0 -6001
- data/test/dummy/public/javascripts/rails.js +0 -175
- data/test/dummy/public/stylesheets/.gitkeep +0 -0
- data/test/dummy/script/rails +0 -6
- data/test/integration/activation_test.rb +0 -108
- data/test/integration/authenticate_test.rb +0 -39
- data/test/integration/blocked_test.rb +0 -23
- data/test/integration/config_test.rb +0 -132
- data/test/integration/cookie_test.rb +0 -67
- data/test/integration/csrf_test.rb +0 -41
- data/test/integration/forgotten_test.rb +0 -93
- data/test/integration/helper_test.rb +0 -18
- data/test/integration/locale_test.rb +0 -197
- data/test/integration/navigation_test.rb +0 -7
- data/test/integration/sign_in_person_test.rb +0 -26
- data/test/integration/sign_in_test.rb +0 -24
- data/test/integration/sign_out_test.rb +0 -20
- data/test/integration/sign_up_test.rb +0 -21
- data/test/quo_vadis_test.rb +0 -7
- data/test/support/integration_case.rb +0 -11
- data/test/test_helper.rb +0 -88
- data/test/unit/user_test.rb +0 -75
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: db2382851913e7455425f7014c13fe2f88eeb19209077c042507b948bef37426
|
4
|
+
data.tar.gz: da813baac8751b9cbc998c403b824c40eb7b2bf5e9710cde7c88fef0c0a0255f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 837432b39ed54b1150d6982bf0385a923a908fe089a8c20b8753a256764d4d76c47da8588c14a99ae76622508cc7f727d1c4589f9a2f6f9870420310283ac6fd
|
7
|
+
data.tar.gz: 3c90dbeac8aea06b5eef1cd1afd51097e6228e15a5bdd9984e030d27888ff63fdb61721b4f40d41fc0dad3a91f9f044052fbecca598795395891581880c7f9dd
|
data/.gitignore
CHANGED
@@ -1,8 +1,11 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
1
|
+
/.bundle/
|
2
|
+
/.yardoc
|
3
|
+
/_yardoc/
|
4
|
+
/coverage/
|
5
|
+
/doc/
|
6
|
+
/pkg/
|
7
|
+
/spec/reports/
|
8
|
+
/tmp/
|
9
|
+
/test/dummy/log/
|
10
|
+
/test/dummy/tmp/
|
11
|
+
/test/dummy/db/*.sqlite3
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,32 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
3
|
|
4
|
+
## 2.0.0 (14 May 2021)
|
5
|
+
|
6
|
+
* Total rewrite from scratch.
|
7
|
+
|
8
|
+
|
9
|
+
## 1.4.0 (12 October 2016)
|
10
|
+
|
11
|
+
* Internationalise emails' subject lines.
|
12
|
+
|
13
|
+
|
14
|
+
## 1.3.2 (22 July 2015)
|
15
|
+
|
16
|
+
* Loosen Rails dependency.
|
17
|
+
* Remove unnecessary code from test app.
|
18
|
+
|
19
|
+
|
20
|
+
## 1.3.1 (22 July 2015)
|
21
|
+
|
22
|
+
* Prefer an instance method to prepare for activation.
|
23
|
+
|
24
|
+
|
25
|
+
## 1.3.0 (23 May 2013)
|
26
|
+
|
27
|
+
* Validate username's uniqueness case-insensitively.
|
28
|
+
|
29
|
+
|
4
30
|
## 1.2.3 (21 March 2013)
|
5
31
|
|
6
32
|
* Ability to override the activation email's from and subject.
|
data/Gemfile
CHANGED
@@ -1,3 +1,16 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
+
source "https://rubygems.org"
|
4
|
+
|
5
|
+
# Specify your gem's dependencies in quo_vadis.gemspec
|
3
6
|
gemspec
|
7
|
+
|
8
|
+
gem "rake", "~> 13.0"
|
9
|
+
|
10
|
+
gem "rails", ">= 6" # from rodauth-rails
|
11
|
+
gem 'sqlite3'
|
12
|
+
gem 'capybara'
|
13
|
+
gem 'rotp'
|
14
|
+
gem 'rqrcode'
|
15
|
+
|
16
|
+
# gem "minitest", "~> 5.0"
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,178 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
quo_vadis (2.0.0)
|
5
|
+
bcrypt (~> 3.1.7)
|
6
|
+
rails (>= 6)
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: https://rubygems.org/
|
10
|
+
specs:
|
11
|
+
actioncable (6.1.1)
|
12
|
+
actionpack (= 6.1.1)
|
13
|
+
activesupport (= 6.1.1)
|
14
|
+
nio4r (~> 2.0)
|
15
|
+
websocket-driver (>= 0.6.1)
|
16
|
+
actionmailbox (6.1.1)
|
17
|
+
actionpack (= 6.1.1)
|
18
|
+
activejob (= 6.1.1)
|
19
|
+
activerecord (= 6.1.1)
|
20
|
+
activestorage (= 6.1.1)
|
21
|
+
activesupport (= 6.1.1)
|
22
|
+
mail (>= 2.7.1)
|
23
|
+
actionmailer (6.1.1)
|
24
|
+
actionpack (= 6.1.1)
|
25
|
+
actionview (= 6.1.1)
|
26
|
+
activejob (= 6.1.1)
|
27
|
+
activesupport (= 6.1.1)
|
28
|
+
mail (~> 2.5, >= 2.5.4)
|
29
|
+
rails-dom-testing (~> 2.0)
|
30
|
+
actionpack (6.1.1)
|
31
|
+
actionview (= 6.1.1)
|
32
|
+
activesupport (= 6.1.1)
|
33
|
+
rack (~> 2.0, >= 2.0.9)
|
34
|
+
rack-test (>= 0.6.3)
|
35
|
+
rails-dom-testing (~> 2.0)
|
36
|
+
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
37
|
+
actiontext (6.1.1)
|
38
|
+
actionpack (= 6.1.1)
|
39
|
+
activerecord (= 6.1.1)
|
40
|
+
activestorage (= 6.1.1)
|
41
|
+
activesupport (= 6.1.1)
|
42
|
+
nokogiri (>= 1.8.5)
|
43
|
+
actionview (6.1.1)
|
44
|
+
activesupport (= 6.1.1)
|
45
|
+
builder (~> 3.1)
|
46
|
+
erubi (~> 1.4)
|
47
|
+
rails-dom-testing (~> 2.0)
|
48
|
+
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
49
|
+
activejob (6.1.1)
|
50
|
+
activesupport (= 6.1.1)
|
51
|
+
globalid (>= 0.3.6)
|
52
|
+
activemodel (6.1.1)
|
53
|
+
activesupport (= 6.1.1)
|
54
|
+
activerecord (6.1.1)
|
55
|
+
activemodel (= 6.1.1)
|
56
|
+
activesupport (= 6.1.1)
|
57
|
+
activestorage (6.1.1)
|
58
|
+
actionpack (= 6.1.1)
|
59
|
+
activejob (= 6.1.1)
|
60
|
+
activerecord (= 6.1.1)
|
61
|
+
activesupport (= 6.1.1)
|
62
|
+
marcel (~> 0.3.1)
|
63
|
+
mimemagic (~> 0.3.2)
|
64
|
+
activesupport (6.1.1)
|
65
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
66
|
+
i18n (>= 1.6, < 2)
|
67
|
+
minitest (>= 5.1)
|
68
|
+
tzinfo (~> 2.0)
|
69
|
+
zeitwerk (~> 2.3)
|
70
|
+
addressable (2.7.0)
|
71
|
+
public_suffix (>= 2.0.2, < 5.0)
|
72
|
+
bcrypt (3.1.16)
|
73
|
+
builder (3.2.4)
|
74
|
+
capybara (3.35.3)
|
75
|
+
addressable
|
76
|
+
mini_mime (>= 0.1.3)
|
77
|
+
nokogiri (~> 1.8)
|
78
|
+
rack (>= 1.6.0)
|
79
|
+
rack-test (>= 0.6.3)
|
80
|
+
regexp_parser (>= 1.5, < 3.0)
|
81
|
+
xpath (~> 3.2)
|
82
|
+
chunky_png (1.4.0)
|
83
|
+
concurrent-ruby (1.1.8)
|
84
|
+
crass (1.0.6)
|
85
|
+
erubi (1.10.0)
|
86
|
+
globalid (0.4.2)
|
87
|
+
activesupport (>= 4.2.0)
|
88
|
+
i18n (1.8.8)
|
89
|
+
concurrent-ruby (~> 1.0)
|
90
|
+
loofah (2.9.0)
|
91
|
+
crass (~> 1.0.2)
|
92
|
+
nokogiri (>= 1.5.9)
|
93
|
+
mail (2.7.1)
|
94
|
+
mini_mime (>= 0.1.1)
|
95
|
+
marcel (0.3.3)
|
96
|
+
mimemagic (~> 0.3.2)
|
97
|
+
method_source (1.0.0)
|
98
|
+
mimemagic (0.3.5)
|
99
|
+
mini_mime (1.0.2)
|
100
|
+
mini_portile2 (2.5.0)
|
101
|
+
minitest (5.14.1)
|
102
|
+
nio4r (2.5.5)
|
103
|
+
nokogiri (1.11.1)
|
104
|
+
mini_portile2 (~> 2.5.0)
|
105
|
+
racc (~> 1.4)
|
106
|
+
nokogiri (1.11.1-x86_64-darwin)
|
107
|
+
racc (~> 1.4)
|
108
|
+
public_suffix (4.0.6)
|
109
|
+
racc (1.5.2)
|
110
|
+
rack (2.2.3)
|
111
|
+
rack-test (1.1.0)
|
112
|
+
rack (>= 1.0, < 3)
|
113
|
+
rails (6.1.1)
|
114
|
+
actioncable (= 6.1.1)
|
115
|
+
actionmailbox (= 6.1.1)
|
116
|
+
actionmailer (= 6.1.1)
|
117
|
+
actionpack (= 6.1.1)
|
118
|
+
actiontext (= 6.1.1)
|
119
|
+
actionview (= 6.1.1)
|
120
|
+
activejob (= 6.1.1)
|
121
|
+
activemodel (= 6.1.1)
|
122
|
+
activerecord (= 6.1.1)
|
123
|
+
activestorage (= 6.1.1)
|
124
|
+
activesupport (= 6.1.1)
|
125
|
+
bundler (>= 1.15.0)
|
126
|
+
railties (= 6.1.1)
|
127
|
+
sprockets-rails (>= 2.0.0)
|
128
|
+
rails-dom-testing (2.0.3)
|
129
|
+
activesupport (>= 4.2.0)
|
130
|
+
nokogiri (>= 1.6)
|
131
|
+
rails-html-sanitizer (1.3.0)
|
132
|
+
loofah (~> 2.3)
|
133
|
+
railties (6.1.1)
|
134
|
+
actionpack (= 6.1.1)
|
135
|
+
activesupport (= 6.1.1)
|
136
|
+
method_source
|
137
|
+
rake (>= 0.8.7)
|
138
|
+
thor (~> 1.0)
|
139
|
+
rake (13.0.3)
|
140
|
+
regexp_parser (2.0.3)
|
141
|
+
rotp (6.2.0)
|
142
|
+
rqrcode (1.2.0)
|
143
|
+
chunky_png (~> 1.0)
|
144
|
+
rqrcode_core (~> 0.2)
|
145
|
+
rqrcode_core (0.2.0)
|
146
|
+
sprockets (4.0.2)
|
147
|
+
concurrent-ruby (~> 1.0)
|
148
|
+
rack (> 1, < 3)
|
149
|
+
sprockets-rails (3.2.2)
|
150
|
+
actionpack (>= 4.0)
|
151
|
+
activesupport (>= 4.0)
|
152
|
+
sprockets (>= 3.0.0)
|
153
|
+
sqlite3 (1.4.2)
|
154
|
+
thor (1.1.0)
|
155
|
+
tzinfo (2.0.4)
|
156
|
+
concurrent-ruby (~> 1.0)
|
157
|
+
websocket-driver (0.7.3)
|
158
|
+
websocket-extensions (>= 0.1.0)
|
159
|
+
websocket-extensions (0.1.5)
|
160
|
+
xpath (3.2.0)
|
161
|
+
nokogiri (~> 1.8)
|
162
|
+
zeitwerk (2.4.2)
|
163
|
+
|
164
|
+
PLATFORMS
|
165
|
+
ruby
|
166
|
+
x86_64-darwin-18
|
167
|
+
|
168
|
+
DEPENDENCIES
|
169
|
+
capybara
|
170
|
+
quo_vadis!
|
171
|
+
rails (>= 6)
|
172
|
+
rake (~> 13.0)
|
173
|
+
rotp
|
174
|
+
rqrcode
|
175
|
+
sqlite3
|
176
|
+
|
177
|
+
BUNDLED WITH
|
178
|
+
2.2.8
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2021 Andy Stewart
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
CHANGED
@@ -1,211 +1,519 @@
|
|
1
|
-
# Quo Vadis
|
1
|
+
# Quo Vadis
|
2
2
|
|
3
|
-
|
3
|
+
Multifactor authentication for your Rails 6 app.
|
4
4
|
|
5
|
-
|
5
|
+
Designed in accordance with the [OWASP Application Security Verification Standard](https://owasp.org/www-project-application-security-verification-standard/) and relevant [OWASP Cheatsheets](https://cheatsheetseries.owasp.org).
|
6
6
|
|
7
|
-
|
7
|
+
Simple to integrate into your application. The main task is customising the example views' markup to match your look-and-feel.
|
8
8
|
|
9
|
-
* Minimal effort to add authentication to your app: get up and running in 5 minutes.
|
10
|
-
* No surprises: it does what you expect.
|
11
|
-
* Easy to customise.
|
12
|
-
* Uses BCrypt to encrypt passwords.
|
13
|
-
* Sign in, sign out, forgotten password, authenticate actions, remember user between browser sessions, user activation.
|
14
|
-
* Block accounts.
|
15
|
-
* Let you choose which model(s) to authenticate (defaults to `User`).
|
16
9
|
|
17
|
-
|
10
|
+
## Features
|
18
11
|
|
19
|
-
|
20
|
-
* Let you choose the identification field (currently `username`).
|
21
|
-
* HTTP basic/digest authentication (probably).
|
22
|
-
* Generate model plus migration if it doesn't exist.
|
23
|
-
* Detect presence of `has_secure_password` (see below) and adapt appropriately.
|
12
|
+
### General features
|
24
13
|
|
25
|
-
|
14
|
+
- Works with any model, e.g. `User` or `Person`.
|
15
|
+
- Works with any identifier, e.g. `:username` or `:email`.
|
16
|
+
- Minimal footprint in your models and controllers.
|
17
|
+
- Does not touch your existing database tables.
|
18
|
+
- Secrets (password, TOTP secret, 2FA recovery codes) are encrypted at rest.
|
26
19
|
|
27
|
-
|
28
|
-
* Work outside Rails 3.
|
29
|
-
* OpenID, OAuth, LDAP, CAS, etc.
|
30
|
-
* Separate identity from authentication services (cf OmniAuth).
|
31
|
-
* Allow you to have multiple models/scope signed in simultaneously (cf Devise).
|
32
|
-
* Offer so much flexibility that it takes more than 10 minutes to wrap your head around it (cf Devise, Authlogic).
|
20
|
+
### Authentication features
|
33
21
|
|
22
|
+
- Authentication by password.
|
23
|
+
- Two-factor authentication (2FA) by TOTP with recovery codes as a backup factor. Can be optional or mandatory.
|
24
|
+
- Change password.
|
25
|
+
- Reset password.
|
26
|
+
- Account confirmation (optional).
|
27
|
+
- Tokens (account confirmation, password reset), TOTPs, and recovery codes are all one-time-only.
|
28
|
+
- Sessions expired after lifetime or idle time exceeded.
|
29
|
+
- Session replaced after any privilege change.
|
30
|
+
- View active sessions, log out of any of them.
|
31
|
+
- Email-notifications of updates to authentication details.
|
32
|
+
- Audit trail.
|
34
33
|
|
35
|
-
## Quick Start
|
36
34
|
|
37
|
-
|
35
|
+
## Installation
|
38
36
|
|
39
|
-
|
37
|
+
Add the gem to your Gemfile:
|
40
38
|
|
41
|
-
|
39
|
+
```ruby
|
40
|
+
gem 'quo_vadis', '~> 2.0'
|
41
|
+
```
|
42
42
|
|
43
|
-
|
43
|
+
Then run `bundle install`.
|
44
44
|
|
45
|
-
|
46
|
-
authenticates
|
47
|
-
end
|
45
|
+
Next, add the database tables:
|
48
46
|
|
49
|
-
|
47
|
+
```
|
48
|
+
$ rails quo_vadis:install:migrations
|
49
|
+
$ rails db:migrate
|
50
|
+
```
|
50
51
|
|
51
|
-
|
52
|
+
All the database tables are prefixed with `qv_`.
|
52
53
|
|
53
|
-
|
54
|
-
before_filter :authenticate, :except => [:index, :show]
|
55
|
-
end
|
54
|
+
Finally, copy the example views across:
|
56
55
|
|
57
|
-
|
56
|
+
```
|
57
|
+
$ rails generate quo_vadis:install
|
58
|
+
```
|
58
59
|
|
59
|
-
* be in `app/views/sessions/new.html.:format`
|
60
|
-
* POST the parameters `:username` and `:password` to `sign_in_url`
|
61
60
|
|
62
|
-
|
61
|
+
## Usage
|
63
62
|
|
64
|
-
Remember to serve your sign in form over HTTPS -- to avoid [the credentials being stolen](http://blog.jgc.org/2011/01/code-injected-to-steal-passwords-in.html).
|
65
63
|
|
66
|
-
|
64
|
+
### Model
|
67
65
|
|
66
|
+
Your model must have an `:email` attribute. All authentication-related emails will be sent to this address.
|
68
67
|
|
69
|
-
|
68
|
+
Your model must have an identifier, e.g. `:email` (default) or `:username`, with a uniqueness validation.
|
70
69
|
|
71
|
-
|
70
|
+
All you need do is add a call to `authenticates`, somewhere after your identifier's uniqueness validation.
|
72
71
|
|
73
|
-
|
74
|
-
2. [Forgotten password page] The user enters their username in the form and submits it.
|
75
|
-
3. Quo Vadis emails the user a message with a change-password link. The link is valid for 3 hours.
|
76
|
-
4. [The email] The user clicks the link.
|
77
|
-
5. [Change password page] The user types in a new password and saves it.
|
78
|
-
6. Quo Vadis changes the user's password and signs the user in.
|
72
|
+
For example, let's say you have a `User` model and the identifier is `:email`:
|
79
73
|
|
80
|
-
|
74
|
+
```ruby
|
75
|
+
class User < ApplicationRecord
|
76
|
+
validates :email, uniqueness: {case_sensitive: false}
|
77
|
+
authenticates
|
78
|
+
end
|
79
|
+
```
|
81
80
|
|
82
|
-
|
81
|
+
If instead you had a `Person` model with a `:username` identifier:
|
83
82
|
|
84
|
-
|
83
|
+
```ruby
|
84
|
+
class Person < ApplicationRecord
|
85
|
+
validates :username, uniqueness: {case_sensitive: false}
|
86
|
+
authenticates identifier: :username
|
87
|
+
end
|
88
|
+
```
|
85
89
|
|
86
|
-
|
87
|
-
* POST the parameter `:username` to `forgotten_sign_in_url`
|
90
|
+
When __creating__ a model instance, include a `:password` attribute and, optionally, `:password_confirmation` attribute.
|
88
91
|
|
89
|
-
|
92
|
+
When __updating__ a model instance, do not include a `:password` attribute. To change someone's password, use the Change Password feature (see below).
|
90
93
|
|
91
|
-
|
92
|
-
* render `@url` somewhere (this is the link the user clicks to go to the change-password page)
|
94
|
+
The minimum password length is configured by `QuoVadis.password_minimum_length` (12 by default).
|
93
95
|
|
94
|
-
You can also refer to `@username` in the email view.
|
95
96
|
|
96
|
-
|
97
|
+
### Controllers
|
97
98
|
|
98
|
-
|
99
|
+
You can use these methods in your controllers.
|
99
100
|
|
100
|
-
|
101
|
+
__`require_password_authentication`__
|
101
102
|
|
102
|
-
|
103
|
+
Use this to restrict actions to password-authenticated users. It is aliased to `:require_authentication` for convenience.
|
103
104
|
|
104
|
-
|
105
|
-
|
105
|
+
```ruby
|
106
|
+
class FoosController < ApplicationController
|
107
|
+
before_action :require_password_authentication
|
108
|
+
end
|
109
|
+
```
|
106
110
|
|
111
|
+
__`require_two_factor_authentication`__
|
107
112
|
|
108
|
-
|
113
|
+
Use this to restrict actions to users authenticated with both a password and a second factor. (You do not need to use `:require_password_authentication` for these actions.)
|
109
114
|
|
110
|
-
|
115
|
+
```ruby
|
116
|
+
class BarsController < ApplicationController
|
117
|
+
before_action :require_two_factor_authentication
|
118
|
+
end
|
119
|
+
```
|
111
120
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
121
|
+
__`login(model, browser_session = true)`__
|
122
|
+
|
123
|
+
To log in a user who has authenticated with a password, call `#login(model, browser_session = true)`. For the `browser_session` argument, pass `true` to log in for the duration of the browser session, or `false` to log in for `QuoVadis.session_lifetime` (which could be the browser session anyway).
|
124
|
+
|
125
|
+
__`request_confirmation(model)`__
|
126
|
+
|
127
|
+
This is used to sent an account confirmation email to the user. See the Account Confirmation feature below for details.
|
128
|
+
|
129
|
+
__`authenticated_model`__
|
130
|
+
|
131
|
+
Call this to get the authenticated user. Feel free to alias this to `:current_user` or set it into an `ActiveSupport::CurrentAttributes` class.
|
132
|
+
|
133
|
+
Available in controllers and views.
|
134
|
+
|
135
|
+
__`logged_in?`__
|
136
|
+
|
137
|
+
Call this to find out whether a user has authenticated with a password.
|
138
|
+
|
139
|
+
Available in controllers and views.
|
140
|
+
|
141
|
+
|
142
|
+
### Views
|
143
|
+
|
144
|
+
You can use `authenticated_model` and `logged_in?` in your views. For example:
|
123
145
|
|
124
|
-
|
146
|
+
```erb
|
147
|
+
<% if logged_in? %>
|
148
|
+
<%= link_to 'My profile', authenticated_model %>
|
149
|
+
<% end %>
|
150
|
+
```
|
125
151
|
|
152
|
+
In your own views, you must prefix QuoVadis's routes with `quo_vadis.`. For example:
|
126
153
|
|
127
|
-
|
154
|
+
```ruby
|
155
|
+
link_to 'Log in', quo_vadis.login_path
|
156
|
+
```
|
128
157
|
|
129
|
-
|
158
|
+
When you are customising QuoVadis's views, you must prefix your app's routes with `main_app.`. For example:
|
130
159
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
160
|
+
```ruby
|
161
|
+
link_to 'Home', main_app.root_path
|
162
|
+
```
|
163
|
+
|
164
|
+
|
165
|
+
## Features
|
166
|
+
|
167
|
+
The example views show the forms and fields you need. You should only need to adapt the markup to suit your app's appearance.
|
168
|
+
|
169
|
+
In the snippets below we assume a `User` model whose identifier is `:email`. You can of course use anything you like.
|
170
|
+
|
171
|
+
|
172
|
+
### Sign up
|
173
|
+
|
174
|
+
Your new user sign-up form ([example](https://github.com/airblade/quo_vadis/blob/master/test/dummy/app/views/users/new.html.erb)) must include:
|
175
|
+
|
176
|
+
- a `:password` field;
|
177
|
+
- optionally a `:password_confirmation` field;
|
178
|
+
- a field for their identifier;
|
179
|
+
- an `:email` field if the identifier is not their email.
|
180
|
+
|
181
|
+
In your controller, use the `#login` method to log in your new user. The optional second argument sets the length of the session (defaults to the browser session) - see the description above in the Controllers section).
|
182
|
+
|
183
|
+
After logging in the user, redirect them to `qv.path_after_authentication` which resolves to a route named `:after_login`, if you have one, or your root route.
|
184
|
+
|
185
|
+
```ruby
|
186
|
+
class UsersController < ApplicationController
|
187
|
+
def create
|
188
|
+
@user = User.new user_params
|
189
|
+
if @user.save
|
190
|
+
login @user
|
191
|
+
redirect_to qv.path_after_authentication
|
192
|
+
else
|
193
|
+
# ...
|
142
194
|
end
|
195
|
+
end
|
196
|
+
|
197
|
+
private
|
198
|
+
|
199
|
+
def user_params
|
200
|
+
params.require(:user).permit(:name, :email, :password, :password_confirmation)
|
201
|
+
end
|
202
|
+
end
|
203
|
+
```
|
204
|
+
|
205
|
+
```ruby
|
206
|
+
# config/routes.rb
|
207
|
+
get '/dashboard', as: 'after_login'
|
208
|
+
```
|
209
|
+
|
143
210
|
|
144
|
-
|
211
|
+
### Sign up with account confirmation
|
145
212
|
|
146
213
|
Here's the workflow:
|
147
214
|
|
148
|
-
1. [
|
149
|
-
2. [
|
150
|
-
3.
|
151
|
-
4. [
|
152
|
-
5.
|
153
|
-
|
215
|
+
1. [Sign up page] The user fills in their details.
|
216
|
+
2. [Your controller] Your code tells QuoVadis to email the user a confirmation link. The link is valid for `QuoVadis.account_confirmation_token_lifetime`.
|
217
|
+
3. [The email] The user clicks the link.
|
218
|
+
4. [Account-confirmation confirmation page] The user clicks a button to confirm their account. (This step is to prevent any link prefetching in the user's mail client from confirming them unintentionally.)
|
219
|
+
5. QuoVadis confirms the user's account and logs them in.
|
220
|
+
|
221
|
+
Your new user sign-up form ([example](https://github.com/airblade/quo_vadis/blob/master/test/dummy/app/views/users/new.html.erb)) must include:
|
222
|
+
|
223
|
+
- a `:password` field;
|
224
|
+
- optionally a `:password_confirmation` field;
|
225
|
+
- a field for their identifier;
|
226
|
+
- an `:email` field if the identifier is not their email.
|
227
|
+
|
228
|
+
In your controller, call `#request_confirmation`:
|
229
|
+
|
230
|
+
```ruby
|
231
|
+
class UsersController < ApplicationController
|
232
|
+
def create
|
233
|
+
@user = User.new user_params
|
234
|
+
if @user.save
|
235
|
+
request_confirmation @user
|
236
|
+
redirect_to qv.confirmations_path # a page where you advise the user to check their email
|
237
|
+
else
|
238
|
+
# ...
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
private
|
243
|
+
|
244
|
+
def user_params
|
245
|
+
params.require(:user).permit(:name, :email, :password, :password_confirmation)
|
246
|
+
end
|
247
|
+
end
|
248
|
+
```
|
249
|
+
|
250
|
+
QuoVadis will send the user an email with a link. Write the email view ([example](https://github.com/airblade/quo_vadis/blob/master/test/dummy/app/views/quo_vadis/mailer/account_confirmation.text.erb)). It must be in `app/views/quo_vadis/mailer/account_confirmation.{text,html}.erb` and output the `@url` variable.
|
251
|
+
|
252
|
+
See the Configuration section below for how to set QuoVadis's emails' from addresses, headers, etc.
|
253
|
+
|
254
|
+
Now write the page to where the user is redirected while they wait for the email ([example](https://github.com/airblade/quo_vadis/blob/master/test/dummy/app/views/quo_vadis/confirmations/index.html.erb)). It must be in `app/views/quo_vadis/confirmations/index.html.:format`.
|
255
|
+
|
256
|
+
It's a good idea for that page to link to `new_confirmation_path` where the user can request another email if need be.
|
257
|
+
|
258
|
+
Next, write the page to which the link in the email points ([example](https://github.com/airblade/quo_vadis/blob/master/test/dummy/app/views/quo_vadis/confirmations/edit.html.erb)). It must be in `app/views/quo_vadis/confirmations/edit.html.:format`.
|
259
|
+
|
260
|
+
Finally, write the page where people can put in their identifier (not their email, unless the identifier is email) again to request another confirmation email ([example](https://github.com/airblade/quo_vadis/blob/master/test/dummy/app/views/quo_vadis/confirmations/new.html.erb)). It must be in `app/views/quo_vadis/confirmations/new.html.:format`.
|
261
|
+
|
262
|
+
After the user has confirmed their account, they will be logged in and redirected to the first of these that exists:
|
263
|
+
|
264
|
+
- a route named `:after_login`;
|
265
|
+
- your root route.
|
266
|
+
|
267
|
+
So add whichever works best for you.
|
268
|
+
|
269
|
+
|
270
|
+
### Login
|
271
|
+
|
272
|
+
Use `before_action :require_password_authentication` or `before_action :require_authentication` in your controllers.
|
273
|
+
|
274
|
+
Write the login view ([example](https://github.com/airblade/quo_vadis/blob/master/test/dummy/app/views/quo_vadis/sessions/new.html.erb)). Your login form must be in `app/views/quo_vadis/sessions/new.html.:format`. Note it must capture the user's identifier (not email, unless the identifier is email).
|
275
|
+
|
276
|
+
If you include a `remember` checkbox in your login form:
|
277
|
+
|
278
|
+
- if the user checks it, they will be logged in for `QuoVadis.session_lifetime`;
|
279
|
+
- if the user does not check it, they will be logged in for the browser session.
|
280
|
+
|
281
|
+
If you do not include a `remember` checkbox, the user will be logged in for `QuoVadis.session_lifetime`.
|
282
|
+
|
283
|
+
After authenticating the user will be redirected to the first of these that exists:
|
284
|
+
|
285
|
+
- the page they tried to view before they were redirected to the login page;
|
286
|
+
- a route named `after_login`, if any;
|
287
|
+
- your root route.
|
288
|
+
|
289
|
+
|
290
|
+
### Two-factor authentication (2FA) or Two-step verification (2SV)
|
291
|
+
|
292
|
+
If you do not want 2FA at all, set `QuoVadis.two_factor_authentication_mandatory false` in your configuration and skip the rest of this section.
|
293
|
+
|
294
|
+
If you do want 2FA, you can choose whether it is optional or mandatory for your users by setting `QuoVadis.two_factor_authentication_mandatory <true|false>` in your configuration.
|
295
|
+
|
296
|
+
Use `before_action :require_two_factor_authentication` in your controllers (which supersedes `:require_password_authentication`). This will require the user, after authenticating with their password, to authenticate with 2FA – when 2FA is mandatory, or when it is optional and the user has set up 2FA.
|
297
|
+
|
298
|
+
Here's the workflow for a user setting up optional 2FA:
|
299
|
+
|
300
|
+
1. User visits their 2FA overview page.
|
301
|
+
2. [2FA overview page] User clicks a link to set up 2FA (TOTP for now).
|
302
|
+
3. [TOTP setup page] User scans the QR code with their authenticator and enters the 6-digit one-time password.
|
303
|
+
4. QuoVadis verifies the one-time password, generates 5 backup recovery codes, and redirects the user to the recovery codes page (or back to step 3 if the OTP is invalid).
|
304
|
+
5. [Recovery code page] User views and hopefully saves their 5 recovery codes.
|
305
|
+
|
306
|
+
When 2FA is mandatory the workflow starts automatically at step 3 after password authentication.
|
307
|
+
|
308
|
+
In your views, have a link where users can manage their 2FA:
|
309
|
+
|
310
|
+
```ruby
|
311
|
+
link_to '2FA', quo_vadis.twofa_path
|
312
|
+
```
|
313
|
+
|
314
|
+
Write the 2FA overview page ([example](https://github.com/airblade/quo_vadis/blob/master/test/dummy/app/views/quo_vadis/twofas/show.html.erb)). It must be in `app/views/quo_vadis/twofas/show.html.:format`. This page allows the user to set up 2FA, deactivate or reset it, and generate new recovery codes.
|
315
|
+
|
316
|
+
Next, write the TOTP setup page ([example](https://github.com/airblade/quo_vadis/blob/master/test/dummy/app/views/quo_vadis/totps/new.html.erb)). It must be in `app/views/quo_vadis/totps/new.html.:format`. This page shows the user a QR code (and the key as text) which they scan with their authenticator.
|
317
|
+
|
318
|
+
Next, write the recovery codes page ([example](https://github.com/airblade/quo_vadis/blob/master/test/dummy/app/views/quo_vadis/recovery_codes/index.html.erb)). It must be in `app/views/quo_vadis/recovery_codes/index.html.:format`. This shows the recovery codes immediately after TOTP is setup, and immediately after generating fresh recovery codes, but not otherwise.
|
319
|
+
|
320
|
+
Next, write the TOTP challenge page where a user inputs their 6-digit TOTP ([example](https://github.com/airblade/quo_vadis/blob/master/test/dummy/app/views/quo_vadis/totps/challenge.html.erb)). It must be in `app/views/quo_vadis/totps/challenge.html.:format`. It's a good idea to link to the recovery code page (`challenge_recovery_codes_path`) for any user who has lost their authenticator.
|
321
|
+
|
322
|
+
Finally, write the recovery code challenge page where a user inputs one of their recovery codes ([example](https://github.com/airblade/quo_vadis/blob/master/test/dummy/app/views/quo_vadis/recovery_codes/challenge.html.erb)). It must be in `app/views/quo_vadis/recovery_codes/challenge.html.:format`. A recovery code can only be used once, and using one deactivates TOTP – so the user will have to set it up again next time.
|
323
|
+
|
324
|
+
|
325
|
+
### Change password
|
326
|
+
|
327
|
+
To change their password, the user must provide their current one as well as the new one.
|
328
|
+
|
329
|
+
Write the change-password form ([example](https://github.com/airblade/quo_vadis/blob/master/test/dummy/app/views/quo_vadis/passwords/edit.html.erb)). It must be in `app/views/quo_vadis/passwords/edit.html.:format`.
|
330
|
+
|
331
|
+
After the password has been changed, the user is redirected to the first of:
|
332
|
+
|
333
|
+
- your route named `:after_password_change`, if any;
|
334
|
+
- your root route.
|
335
|
+
|
336
|
+
A successful password change logs out any other sessions the user has (e.g. on other devices).
|
337
|
+
|
338
|
+
|
339
|
+
### Reset password
|
340
|
+
|
341
|
+
The user can reset their password if they lose it. The flow is:
|
342
|
+
|
343
|
+
1. [Request password-reset page] User enters their identifier (not their email unless the identifier is email).
|
344
|
+
2. QuoVadis emails the user a link. The link is valid for `QuoVadis.password_reset_token_lifetime`.
|
345
|
+
3. [The email] The user clicks the link.
|
346
|
+
4. [Password-reset confirmation page] The user enters their new password and clicks a button.
|
347
|
+
5. QuoVadis sets the user's password and logs them in.
|
348
|
+
|
349
|
+
First, write the page where the user requests a password-reset ([example](https://github.com/airblade/quo_vadis/blob/master/test/dummy/app/views/quo_vadis/password_resets/new.html.erb)). It must be in `app/views/quo_vadis/password_resets/new.html.:format`. Note it must capture the user's identifier (not email, unless the identifier is email).
|
350
|
+
|
351
|
+
See the Configuration section below for how to set QuoVadis's emails' from addresses, headers, etc.
|
352
|
+
|
353
|
+
Now write the page to where the user is redirected while they wait for the email ([example](https://github.com/airblade/quo_vadis/blob/master/test/dummy/app/views/quo_vadis/password_resets/index.html.erb)). It must be in `app/views/quo_vadis/password_resets/index.html.:format`.
|
354
|
+
|
355
|
+
It's a good idea for that page to link to `new_password_reset_path` where the user can request another email if need be.
|
356
|
+
|
357
|
+
Next, write the page to which the link in the email points ([example](https://github.com/airblade/quo_vadis/blob/master/test/dummy/app/views/quo_vadis/password_resets/edit.html.erb)). It must be in `app/views/quo_vadis/password_resets/edit.html.:format`.
|
358
|
+
|
359
|
+
Finally, write the page where people can put in their identifier (not their email, unless the identifier is email) again to request another password-reset email ([example](https://github.com/airblade/quo_vadis/blob/master/test/dummy/app/views/quo_vadis/password_resets/new.html.erb)). It must be in `app/views/quo_vadis/password_resets/new.html.:format`.
|
360
|
+
|
361
|
+
After the user has reset their password, they will be logged in and redirected to the first of these that exists:
|
362
|
+
|
363
|
+
- a route named `:after_login`;
|
364
|
+
- your root route.
|
365
|
+
|
366
|
+
|
367
|
+
### Sessions
|
368
|
+
|
369
|
+
A logged-in session lasts for either the browser session or `QuoVadis.session_lifetime`. As well as having a lifetime, a session will also expire after it has been inactive for `QuoVadis.session_idle_timeout`.
|
370
|
+
|
371
|
+
A user can view their active sessions and log out of any of them.
|
372
|
+
|
373
|
+
Write the view showing the sessions ([example](https://github.com/airblade/quo_vadis/blob/master/test/dummy/app/views/quo_vadis/sessions/index.html.erb)). It must be in `app/views/quo_vadis/sessions/index.html.:format`.
|
374
|
+
|
375
|
+
|
376
|
+
### Audit trail
|
377
|
+
|
378
|
+
An audit trail is kept of authentication events. You can see the full list in the [`Log`](https://github.com/airblade/quo_vadis/blob/master/app/models/quo_vadis/log.rb) class.
|
379
|
+
|
380
|
+
Write the view showing the events ([example](https://github.com/airblade/quo_vadis/blob/master/test/dummy/app/views/quo_vadis/logs/index.html.erb)). It must be in `app/views/quo_vadis/logs/index.html.:format`.
|
381
|
+
|
382
|
+
|
383
|
+
### Notifications
|
384
|
+
|
385
|
+
QuoVadis notifies users by email whenever their authentication details are changed or something suspicious happens.
|
386
|
+
|
387
|
+
Write the corresponding mailer views:
|
388
|
+
|
389
|
+
- change of email ([example](https://github.com/airblade/quo_vadis/blob/master/test/dummy/app/views/quo_vadis/mailer/email_change_notification.text.erb))
|
390
|
+
- change of identifier (unless the identifier is email) ([example](https://github.com/airblade/quo_vadis/blob/master/test/dummy/app/views/quo_vadis/mailer/identifier_change_notification.text.erb))
|
391
|
+
- change of password ([example](https://github.com/airblade/quo_vadis/blob/master/test/dummy/app/views/quo_vadis/mailer/password_change_notification.text.erb))
|
392
|
+
- reset of password ([example](https://github.com/airblade/quo_vadis/blob/master/test/dummy/app/views/quo_vadis/mailer/password_reset_notification.text.erb))
|
393
|
+
- TOTP setup ([example](https://github.com/airblade/quo_vadis/blob/master/test/dummy/app/views/quo_vadis/mailer/totp_setup_notification.text.erb))
|
394
|
+
- TOTP code used a second time ([example](https://github.com/airblade/quo_vadis/blob/master/test/dummy/app/views/quo_vadis/mailer/totp_reuse_notification.text.erb))
|
395
|
+
- 2FA deactivated ([example](https://github.com/airblade/quo_vadis/blob/master/test/dummy/app/views/quo_vadis/mailer/twofa_deactivated_notification.text.erb))
|
396
|
+
- recovery codes generated ([example](https://github.com/airblade/quo_vadis/blob/master/test/dummy/app/views/quo_vadis/mailer/recovery_codes_generation_notification.text.erb))
|
397
|
+
|
398
|
+
They must be in `app/views/quo_vadis/mailer/NAME.{text,html}.erb`.
|
399
|
+
|
400
|
+
|
401
|
+
## Configuration
|
402
|
+
|
403
|
+
This is QuoVadis' [default configuration](https://github.com/airblade/quo_vadis/blob/master/lib/quo_vadis/defaults.rb):
|
404
|
+
|
405
|
+
```ruby
|
406
|
+
QuoVadis.configure do
|
407
|
+
password_minimum_length 12
|
408
|
+
mask_ips false
|
409
|
+
cookie_name '__Host-qv'
|
410
|
+
session_lifetime :session
|
411
|
+
session_lifetime_extend_to_end_of_day false
|
412
|
+
session_idle_timeout :lifetime
|
413
|
+
password_reset_token_lifetime 10.minutes
|
414
|
+
accounts_require_confirmation false
|
415
|
+
account_confirmation_token_lifetime 10.minutes
|
416
|
+
mail_headers ({ from: 'Example App <support@example.com>' })
|
417
|
+
enqueue_transactional_emails true
|
418
|
+
app_name Rails.app_class.to_s.deconstantize # for the TOTP QR code
|
419
|
+
two_factor_authentication_mandatory true
|
420
|
+
mount_point '/'
|
421
|
+
end
|
422
|
+
```
|
423
|
+
|
424
|
+
You can override any of it with a similarly structured file in `config/initializers/quo_vadis.rb`.
|
425
|
+
|
426
|
+
Here are the options in detail:
|
427
|
+
|
428
|
+
__`password_minimum_length`__ (integer)
|
429
|
+
|
430
|
+
The minimum number of characters for a password.
|
431
|
+
|
432
|
+
__`mask_ips`__ (boolean)
|
433
|
+
|
434
|
+
Whether to mask the IP address in the sessions list and the audit trail.
|
435
|
+
|
436
|
+
Masking means setting the last octet (IPv4) or the last 80 bits (IPv6) to 0.
|
437
|
+
|
438
|
+
__`cookie_name`__ (string)
|
439
|
+
|
440
|
+
The name of the cookie QuoVadis uses to store the session identifier. The `__Host-` prefix is [recommended](https://developer.mozilla.org/en-US/docs/Web/API/document/cookie).
|
441
|
+
|
442
|
+
__`session_lifetime`__ (`:session` | `ActiveSupport::Duration` | integer)
|
443
|
+
|
444
|
+
The lifetime of a logged-in session. Use `:session` for the browser session, or a `Duration` or number of seconds.
|
445
|
+
|
446
|
+
__`session_lifetime_extend_to_end_of_day`__ (boolean)
|
447
|
+
|
448
|
+
Whether to extend the session's lifetime to the end of the day it will expire on.
|
449
|
+
|
450
|
+
Set `true` to reduce the chance of a user being logged out while actively using your application.
|
451
|
+
|
452
|
+
__`session_idle_timeout`__ (`:lifetime` | `ActiveSupport::Duration` | integer)
|
453
|
+
|
454
|
+
The logged-in session is expired if the user isn't seen for this `Duration` or number of seconds. Use `:lifetime` to set the idle timeout to the session's lifetime (i.e. to turn off the idle timeout).
|
154
455
|
|
155
|
-
|
456
|
+
__`password_reset_token_lifetime`__ (`ActiveSupport::Duration` | integer)
|
156
457
|
|
157
|
-
|
458
|
+
The `Duration` or number of seconds for which a password-reset token is valid.
|
158
459
|
|
159
|
-
|
460
|
+
__`accounts_require_confirmation`__ (boolean)
|
160
461
|
|
161
|
-
|
162
|
-
* render `@url` somewhere (this is the link the user clicks to go to the invitation page)
|
462
|
+
Whether new users must confirm their account before they can log in.
|
163
463
|
|
164
|
-
|
464
|
+
__`account_confirmation_token_lifetime`__ (`ActiveSupport::Duration` | integer)
|
165
465
|
|
166
|
-
|
466
|
+
The `Duration` or number of seconds for which an account-confirmation token is valid.
|
167
467
|
|
168
|
-
|
468
|
+
__`mail_headers`__ (hash)
|
169
469
|
|
170
|
-
|
470
|
+
Mail headers which QuoVadis' emails should have.
|
171
471
|
|
172
|
-
|
472
|
+
__`enqueue_transactional_emails`__ (boolean)
|
173
473
|
|
174
|
-
|
175
|
-
* POST the parameters `:username` and `:password` to `activation_url(params[:token])`
|
474
|
+
Set `true` if account-confirmation and password-reset emails should be queued for later delivery (`#deliver_later`) or `false` if they should be sent inline (`#deliver_now`).
|
176
475
|
|
177
|
-
|
476
|
+
__`app_name`__ (string)
|
178
477
|
|
478
|
+
Used in the provisioning URI for the TOTP QR code.
|
179
479
|
|
180
|
-
|
480
|
+
__`two_factor_authentication_mandatory`__ (boolean)
|
181
481
|
|
182
|
-
|
482
|
+
Whether users must set up and use a second authentication factor.
|
183
483
|
|
184
|
-
|
484
|
+
__`mount_point`__ (string)
|
185
485
|
|
186
|
-
|
486
|
+
The path prefix for QuoVadis's routes.
|
187
487
|
|
188
|
-
|
488
|
+
For example, the default login path is at `/login`. If you set `mount_point` to `/auth`, the login path would be `/auth/login`.
|
189
489
|
|
490
|
+
#### Rails configuration
|
190
491
|
|
191
|
-
|
492
|
+
You must also configure the mailer host so URLs are generated correctly in emails:
|
192
493
|
|
193
|
-
|
194
|
-
|
494
|
+
```ruby
|
495
|
+
config.action_mailer.default_url_options: { host: 'example.com }
|
496
|
+
```
|
195
497
|
|
498
|
+
Finally, you can set up your post-authentication and post-password-change routes. If you don't, you must have a root route. For example:
|
196
499
|
|
197
|
-
|
500
|
+
```ruby
|
501
|
+
# config/routes.rb
|
502
|
+
get '/dashboard', to: 'dashboards#show', as: 'after_login'
|
503
|
+
get '/profile', to: 'profiles#show', as: 'after_password_change'
|
504
|
+
```
|
198
505
|
|
199
|
-
|
506
|
+
### I18n
|
200
507
|
|
508
|
+
All QuoVadis' flash messages are set via [i18n](https://github.com/airblade/quo_vadis/blob/master/config/locales/quo_vadis.en.yml).
|
201
509
|
|
202
|
-
|
510
|
+
You can override any of the messages with your own locale file at `config/locales/quo_vadis.en.yml`.
|
203
511
|
|
204
|
-
|
512
|
+
If you don't want a specific flash message at all, give the key an empty value in your locale file.
|
205
513
|
|
206
514
|
|
207
|
-
## Intellectual
|
515
|
+
## Intellectual Property
|
208
516
|
|
209
|
-
Copyright 2011
|
517
|
+
Copyright 2011-2021 Andrew Stewart (boss@airbladesoftware.com).
|
210
518
|
|
211
519
|
Released under the MIT licence.
|