rodauth-rails 1.1.0 โ 1.2.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +18 -0
- data/README.md +39 -25
- data/lib/generators/rodauth/migration/active_sessions.erb +2 -2
- data/lib/generators/rodauth/migration/audit_logging.erb +1 -1
- data/lib/generators/rodauth/migration/base.erb +2 -2
- data/lib/generators/rodauth/migration/email_auth.erb +1 -1
- data/lib/generators/rodauth/migration/otp.erb +1 -1
- data/lib/generators/rodauth/migration/password_expiration.erb +1 -1
- data/lib/generators/rodauth/migration/reset_password.erb +1 -1
- data/lib/generators/rodauth/migration/sms_codes.erb +1 -1
- data/lib/generators/rodauth/migration/verify_account.erb +2 -2
- data/lib/generators/rodauth/migration/webauthn.erb +1 -1
- data/lib/generators/rodauth/migration_helpers.rb +8 -0
- data/lib/generators/rodauth/templates/app/misc/rodauth_main.rb +1 -4
- data/lib/generators/rodauth/templates/app/models/account.rb +1 -0
- data/lib/rodauth/rails/app/flash.rb +1 -2
- data/lib/rodauth/rails/controller_methods.rb +4 -29
- data/lib/rodauth/rails/feature/base.rb +21 -0
- data/lib/rodauth/rails/feature/instrumentation.rb +1 -1
- data/lib/rodauth/rails/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 402cbf2f62d93eae97353a3aed436ce742b41421e880176649a7271c5516b39c
|
4
|
+
data.tar.gz: ca035e7a60c54b4e1b6f2a42ea6405f43811146141c30c5a6d14fd7c0600669e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 888fd37f380d6f4896b544374c6681445dbb0e90d692dd7c0239aa043c9d6c0cb2aaafa9b47f271cd6cc70ad3a6c88693c988901aed1e5bc0f77ed5c92cb4ab1
|
7
|
+
data.tar.gz: 48fe23bfbd3d78c3378ab47ecf92ffd7f87fe768f996764a71b8534a2cab8731ebc080998b03ea9a78f1fecd949548782ca8e38dc17c56fa2606ea11f7a7fbe9
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,21 @@
|
|
1
|
+
## 1.2.2 (2022-02-22)
|
2
|
+
|
3
|
+
* Fix flash messages not being preserved through consecutive redirects (@janko)
|
4
|
+
|
5
|
+
## 1.2.1 (2022-02-19)
|
6
|
+
|
7
|
+
* Change `accounts.status` column type from string to integer (@zhongsheng)
|
8
|
+
|
9
|
+
## 1.2.0 (2022-02-11)
|
10
|
+
|
11
|
+
* Work around Active Record 4.2 not supporting procs for literal SQL column default (@janko)
|
12
|
+
|
13
|
+
* Avoid re-fetching the account in `#current_account` when it has already been fetched by Rodauth (@janko)
|
14
|
+
|
15
|
+
* Extract `#current_account` helper functionality into `#rails_account` Rodauth method (@janko)
|
16
|
+
|
17
|
+
* Use default account status values in generated configuration, with enum on `Account` model (@janko)
|
18
|
+
|
1
19
|
## 1.1.0 (2022-01-16)
|
2
20
|
|
3
21
|
* Automatically route the path prefix in `r.rodauth` if one has been set (@janko)
|
data/README.md
CHANGED
@@ -4,7 +4,7 @@ Provides Rails integration for the [Rodauth] authentication framework.
|
|
4
4
|
|
5
5
|
## Resources
|
6
6
|
|
7
|
-
Useful links:
|
7
|
+
๐ Useful links:
|
8
8
|
|
9
9
|
* [Rodauth documentation](http://rodauth.jeremyevans.net/documentation.html)
|
10
10
|
* [Rails demo](https://github.com/janko/rodauth-demo-rails)
|
@@ -12,11 +12,15 @@ Useful links:
|
|
12
12
|
* [OmniAuth guide](https://github.com/janko/rodauth-rails/wiki/OmniAuth)
|
13
13
|
* [Testing guide](https://github.com/janko/rodauth-rails/wiki/Testing)
|
14
14
|
|
15
|
-
|
15
|
+
๐ฅ Screencasts:
|
16
|
+
|
17
|
+
* [Rails Authentication with Rodauth](https://www.youtube.com/watch?v=2hDpNikacf0)
|
18
|
+
|
19
|
+
๐ Articles:
|
16
20
|
|
17
21
|
* [Rodauth: A Refreshing Authentication Solution for Ruby](https://janko.io/rodauth-a-refreshing-authentication-solution-for-ruby/)
|
18
|
-
* [
|
19
|
-
* [
|
22
|
+
* [Rails Authentication with Rodauth](https://janko.io/adding-authentication-in-rails-with-rodauth/)
|
23
|
+
* [Multifactor Authentication in Rails with Rodauth](https://janko.io/adding-multifactor-authentication-in-rails-with-rodauth/)
|
20
24
|
* [How to build an OIDC provider using rodauth-oauth on Rails](https://honeyryderchuck.gitlab.io/httpx/2021/03/15/oidc-provider-on-rails-using-rodauth-oauth.html)
|
21
25
|
|
22
26
|
## Why Rodauth?
|
@@ -140,16 +144,14 @@ authentication experience, and the forms use [Bootstrap] markup.
|
|
140
144
|
### Current account
|
141
145
|
|
142
146
|
The `#current_account` method is defined in controllers and views, which
|
143
|
-
returns the model instance of the currently logged in account.
|
147
|
+
returns the model instance of the currently logged in account. If the account
|
148
|
+
doesn't exist in the database, the session will be cleared.
|
144
149
|
|
145
150
|
```rb
|
146
151
|
current_account #=> #<Account id=123 email="user@example.com">
|
147
152
|
current_account.email #=> "user@example.com"
|
148
153
|
```
|
149
154
|
|
150
|
-
If the account doesn't exist in the database, the session will be cleared and
|
151
|
-
login required.
|
152
|
-
|
153
155
|
Pass the configuration name to retrieve accounts belonging to other Rodauth
|
154
156
|
configurations:
|
155
157
|
|
@@ -157,6 +159,8 @@ configurations:
|
|
157
159
|
current_account(:admin)
|
158
160
|
```
|
159
161
|
|
162
|
+
This just delegates to the `#rails_account` method on the Rodauth object.
|
163
|
+
|
160
164
|
#### Custom account model
|
161
165
|
|
162
166
|
The `#current_account` method will try to infer the account model class from
|
@@ -248,6 +252,18 @@ Rails.application.routes.draw do
|
|
248
252
|
end
|
249
253
|
```
|
250
254
|
|
255
|
+
The current account can be retrieved via the `#rails_account` method:
|
256
|
+
|
257
|
+
```rb
|
258
|
+
# config/routes.rb
|
259
|
+
Rails.application.routes.draw do
|
260
|
+
# require user to be admin
|
261
|
+
constraints Rodauth::Rails.authenticated { |rodauth| rodauth.rails_account.admin? } do
|
262
|
+
# ...
|
263
|
+
end
|
264
|
+
end
|
265
|
+
```
|
266
|
+
|
251
267
|
You can specify the Rodauth configuration by passing the configuration name:
|
252
268
|
|
253
269
|
```rb
|
@@ -1097,16 +1113,15 @@ end
|
|
1097
1113
|
|
1098
1114
|
The recommended [Rodauth migration] stores possible account status values in a
|
1099
1115
|
separate table, and creates a foreign key on the accounts table, which ensures
|
1100
|
-
only a valid status value will be persisted.
|
1116
|
+
only a valid status value will be persisted. Unfortunately, this doesn't work
|
1117
|
+
when the database is restored from the schema file, in which case the account
|
1118
|
+
statuses table will be empty. This happens in tests by default, but it's also
|
1119
|
+
not unusual to do it in development.
|
1101
1120
|
|
1102
|
-
|
1103
|
-
|
1104
|
-
|
1105
|
-
|
1106
|
-
To address this, rodauth-rails modifies the setup to store account status text
|
1107
|
-
directly in the accounts table. If you're worried about invalid status values
|
1108
|
-
creeping in, you may use enums instead. Alternatively, you can always go back
|
1109
|
-
to the setup recommended by Rodauth.
|
1121
|
+
To address this, rodauth-rails uses a `status` column without a separate table.
|
1122
|
+
If you're worried about invalid status values creeping in, you may use enums
|
1123
|
+
instead. Alternatively, you can always go back to the setup recommended by
|
1124
|
+
Rodauth.
|
1110
1125
|
|
1111
1126
|
```rb
|
1112
1127
|
# in the migration:
|
@@ -1122,14 +1137,13 @@ create_table :accounts do |t|
|
|
1122
1137
|
end
|
1123
1138
|
```
|
1124
1139
|
```diff
|
1125
|
-
|
1126
|
-
|
1127
|
-
|
1128
|
-
-
|
1129
|
-
|
1130
|
-
|
1131
|
-
|
1132
|
-
end
|
1140
|
+
class RodauthMain < Rodauth::Rails::Auth
|
1141
|
+
configure do
|
1142
|
+
# ...
|
1143
|
+
- account_status_column :status
|
1144
|
+
# ...
|
1145
|
+
end
|
1146
|
+
end
|
1133
1147
|
```
|
1134
1148
|
|
1135
1149
|
### Deadline values
|
@@ -2,6 +2,6 @@
|
|
2
2
|
create_table :account_active_session_keys, primary_key: [:account_id, :session_id] do |t|
|
3
3
|
t.references :account, foreign_key: true<%= primary_key_type(:type) %>
|
4
4
|
t.string :session_id
|
5
|
-
t.datetime :created_at, null: false, default:
|
6
|
-
t.datetime :last_use, null: false, default:
|
5
|
+
t.datetime :created_at, null: false, default: <%= current_timestamp %>
|
6
|
+
t.datetime :last_use, null: false, default: <%= current_timestamp %>
|
7
7
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# Used by the audit logging feature
|
2
2
|
create_table :account_authentication_audit_logs<%= primary_key_type %> do |t|
|
3
3
|
t.references :account, foreign_key: true, null: false<%= primary_key_type(:type) %>
|
4
|
-
t.datetime :at, null: false, default:
|
4
|
+
t.datetime :at, null: false, default: <%= current_timestamp %>
|
5
5
|
t.text :message, null: false
|
6
6
|
<% case activerecord_adapter -%>
|
7
7
|
<% when "postgresql" -%>
|
@@ -9,10 +9,10 @@ create_table :accounts<%= primary_key_type %> do |t|
|
|
9
9
|
<% else -%>
|
10
10
|
t.string :email, null: false
|
11
11
|
<% end -%>
|
12
|
-
t.
|
12
|
+
t.integer :status, null: false, default: 1
|
13
13
|
<% case activerecord_adapter -%>
|
14
14
|
<% when "postgresql", "sqlite3" -%>
|
15
|
-
t.index :email, unique: true, where: "status IN (
|
15
|
+
t.index :email, unique: true, where: "status IN (1, 2)"
|
16
16
|
<% else -%>
|
17
17
|
t.index :email, unique: true
|
18
18
|
<% end -%>
|
@@ -3,5 +3,5 @@ create_table :account_email_auth_keys<%= primary_key_type %> do |t|
|
|
3
3
|
t.foreign_key :accounts, column: :id
|
4
4
|
t.string :key, null: false
|
5
5
|
t.datetime :deadline, null: false
|
6
|
-
t.datetime :email_last_sent, null: false, default:
|
6
|
+
t.datetime :email_last_sent, null: false, default: <%= current_timestamp %>
|
7
7
|
end
|
@@ -3,5 +3,5 @@ create_table :account_otp_keys<%= primary_key_type %> do |t|
|
|
3
3
|
t.foreign_key :accounts, column: :id
|
4
4
|
t.string :key, null: false
|
5
5
|
t.integer :num_failures, null: false, default: 0
|
6
|
-
t.datetime :last_use, null: false, default:
|
6
|
+
t.datetime :last_use, null: false, default: <%= current_timestamp %>
|
7
7
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# Used by the password expiration feature
|
2
2
|
create_table :account_password_change_times<%= primary_key_type %> do |t|
|
3
3
|
t.foreign_key :accounts, column: :id
|
4
|
-
t.datetime :changed_at, null: false, default:
|
4
|
+
t.datetime :changed_at, null: false, default: <%= current_timestamp %>
|
5
5
|
end
|
@@ -3,5 +3,5 @@ create_table :account_password_reset_keys<%= primary_key_type %> do |t|
|
|
3
3
|
t.foreign_key :accounts, column: :id
|
4
4
|
t.string :key, null: false
|
5
5
|
t.datetime :deadline, null: false
|
6
|
-
t.datetime :email_last_sent, null: false, default:
|
6
|
+
t.datetime :email_last_sent, null: false, default: <%= current_timestamp %>
|
7
7
|
end
|
@@ -4,5 +4,5 @@ create_table :account_sms_codes<%= primary_key_type %> do |t|
|
|
4
4
|
t.string :phone_number, null: false
|
5
5
|
t.integer :num_failures
|
6
6
|
t.string :code
|
7
|
-
t.datetime :code_issued_at, null: false, default:
|
7
|
+
t.datetime :code_issued_at, null: false, default: <%= current_timestamp %>
|
8
8
|
end
|
@@ -2,6 +2,6 @@
|
|
2
2
|
create_table :account_verification_keys<%= primary_key_type %> do |t|
|
3
3
|
t.foreign_key :accounts, column: :id
|
4
4
|
t.string :key, null: false
|
5
|
-
t.datetime :requested_at, null: false, default:
|
6
|
-
t.datetime :email_last_sent, null: false, default:
|
5
|
+
t.datetime :requested_at, null: false, default: <%= current_timestamp %>
|
6
|
+
t.datetime :email_last_sent, null: false, default: <%= current_timestamp %>
|
7
7
|
end
|
@@ -8,5 +8,5 @@ create_table :account_webauthn_keys, primary_key: [:account_id, :webauthn_id] do
|
|
8
8
|
t.string :webauthn_id
|
9
9
|
t.string :public_key, null: false
|
10
10
|
t.integer :sign_count, null: false
|
11
|
-
t.datetime :last_use, null: false, default:
|
11
|
+
t.datetime :last_use, null: false, default: <%= current_timestamp %>
|
12
12
|
end
|
@@ -63,6 +63,14 @@ module Rodauth
|
|
63
63
|
ERB.new(content, 0, "-").result(binding)
|
64
64
|
end
|
65
65
|
end
|
66
|
+
|
67
|
+
def current_timestamp
|
68
|
+
if ActiveRecord.version >= Gem::Version.new("5.0")
|
69
|
+
%(-> { "CURRENT_TIMESTAMP" })
|
70
|
+
else
|
71
|
+
%(OpenStruct.new(quoted_id: "CURRENT_TIMESTAMP"))
|
72
|
+
end
|
73
|
+
end
|
66
74
|
end
|
67
75
|
end
|
68
76
|
end
|
@@ -31,11 +31,8 @@ class RodauthMain < Rodauth::Rails::Auth
|
|
31
31
|
# Specify the controller used for view rendering and CSRF verification.
|
32
32
|
rails_controller { RodauthController }
|
33
33
|
|
34
|
-
# Store account status in
|
34
|
+
# Store account status in an integer column without foreign key constraint.
|
35
35
|
account_status_column :status
|
36
|
-
account_unverified_status_value "unverified"
|
37
|
-
account_open_status_value "verified"
|
38
|
-
account_closed_status_value "closed"
|
39
36
|
|
40
37
|
# Store password hash in a column instead of a separate table.
|
41
38
|
# account_password_hash_column :password_digest
|
@@ -8,41 +8,16 @@ module Rodauth
|
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
11
|
-
def rodauth(name = nil)
|
12
|
-
request.env.fetch ["rodauth", *name].join(".")
|
13
|
-
end
|
14
|
-
|
15
11
|
def current_account(name = nil)
|
16
|
-
|
17
|
-
|
12
|
+
rodauth(name).rails_account || rodauth(name).login_required
|
13
|
+
end
|
18
14
|
|
19
|
-
|
20
|
-
|
21
|
-
rodauth(name).clear_session
|
22
|
-
rodauth(name).login_required
|
23
|
-
end
|
15
|
+
def rodauth(name = nil)
|
16
|
+
request.env.fetch ["rodauth", *name].join(".")
|
24
17
|
end
|
25
18
|
|
26
19
|
private
|
27
20
|
|
28
|
-
def fetch_account(model, id, ¬_found)
|
29
|
-
if defined?(ActiveRecord::Base) && model < ActiveRecord::Base
|
30
|
-
begin
|
31
|
-
model.find(id)
|
32
|
-
rescue ActiveRecord::RecordNotFound
|
33
|
-
not_found.call
|
34
|
-
end
|
35
|
-
elsif defined?(Sequel::Model) && model < Sequel::Model
|
36
|
-
begin
|
37
|
-
model.with_pk!(id)
|
38
|
-
rescue Sequel::NoMatchingRow
|
39
|
-
not_found.call
|
40
|
-
end
|
41
|
-
else
|
42
|
-
fail Error, "unsupported model type: #{model}"
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
21
|
def rodauth_response
|
47
22
|
res = catch(:halt) { return yield }
|
48
23
|
|
@@ -8,6 +8,17 @@ module Rodauth
|
|
8
8
|
feature.auth_cached_method :rails_controller_instance
|
9
9
|
end
|
10
10
|
|
11
|
+
def rails_account
|
12
|
+
account_from_session unless account
|
13
|
+
|
14
|
+
unless account
|
15
|
+
clear_session if logged_in?
|
16
|
+
return
|
17
|
+
end
|
18
|
+
|
19
|
+
@rails_account ||= instantiate_rails_account
|
20
|
+
end
|
21
|
+
|
11
22
|
# Reset Rails session to protect from session fixation attacks.
|
12
23
|
def clear_session
|
13
24
|
rails_controller_instance.reset_session
|
@@ -43,6 +54,16 @@ module Rodauth
|
|
43
54
|
|
44
55
|
private
|
45
56
|
|
57
|
+
def instantiate_rails_account
|
58
|
+
if defined?(ActiveRecord::Base) && rails_account_model < ActiveRecord::Base
|
59
|
+
rails_account_model.instantiate(account.stringify_keys)
|
60
|
+
elsif defined?(Sequel::Model) && rails_account_model < Sequel::Model
|
61
|
+
rails_account_model.load(account)
|
62
|
+
else
|
63
|
+
fail Error, "unsupported model type: #{rails_account_model}"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
46
67
|
# Instances of the configured controller with current request's env hash.
|
47
68
|
def _rails_controller_instance
|
48
69
|
controller = rails_controller.new
|
@@ -40,7 +40,7 @@ module Rodauth
|
|
40
40
|
begin
|
41
41
|
result = catch(:halt) { yield }
|
42
42
|
|
43
|
-
response = ActionDispatch::Response.new
|
43
|
+
response = ActionDispatch::Response.new(*(result || [404, {}, []]))
|
44
44
|
payload[:response] = response
|
45
45
|
payload[:status] = response.status
|
46
46
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rodauth-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Janko Marohniฤ
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-02-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: railties
|
@@ -268,7 +268,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
268
268
|
- !ruby/object:Gem::Version
|
269
269
|
version: '0'
|
270
270
|
requirements: []
|
271
|
-
rubygems_version: 3.
|
271
|
+
rubygems_version: 3.3.3
|
272
272
|
signing_key:
|
273
273
|
specification_version: 4
|
274
274
|
summary: Provides Rails integration for Rodauth.
|