rodauth-rails 0.10.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/README.md +54 -54
- data/lib/generators/rodauth/templates/app/views/rodauth_mailer/unlock_account.text.erb +1 -1
- data/lib/rodauth/rails/app.rb +8 -0
- data/lib/rodauth/rails/app/flash.rb +2 -8
- data/lib/rodauth/rails/feature.rb +30 -10
- data/lib/rodauth/rails/log_subscriber.rb +34 -0
- data/lib/rodauth/rails/railtie.rb +5 -0
- data/lib/rodauth/rails/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b8063be8ad00634114f74f0eb549c672e2b62cd1fa81cb7f124cc9cd12505e3f
|
4
|
+
data.tar.gz: 6f466e29420f9e4bacb58c855e942cc20289d2c3fc69a12638b97628d25dbbfb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8cc0af59c6ce29837fbc8a3401d456fd407ef76b74493b08ee9b4f2dfc8807d4a95c86f9bb0266401013d5162c009d46b7d07e3f741654af2cc267c0ee2c135e
|
7
|
+
data.tar.gz: 78c098dbaed458d5764ca2e7ee61f4710e01b2386d0cc04831b1732b9883d76c4b9f56c35c0a1e557c40951086d72bb0ed264f769313c1b45be30b2dd760024a
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
## 0.11.0 (2021-05-06)
|
2
|
+
|
3
|
+
* Add controller-like logging for requests to Rodauth endpoints (@janko)
|
4
|
+
|
5
|
+
* Add `#rails_routes` to Roda and Rodauth instance for accessing Rails route helpers (@janko)
|
6
|
+
|
7
|
+
* Add `#rails_request` to Roda and Rodauth instance for retrieving an `ActionDispatch::Request` instance (@janko)
|
8
|
+
|
1
9
|
## 0.10.0 (2021-03-23)
|
2
10
|
|
3
11
|
* Add `Rodauth::Rails::Auth` superclass for moving configurations into separate files (@janko)
|
data/README.md
CHANGED
@@ -2,35 +2,6 @@
|
|
2
2
|
|
3
3
|
Provides Rails integration for the [Rodauth] authentication framework.
|
4
4
|
|
5
|
-
## Table of contents
|
6
|
-
|
7
|
-
* [Resources](#resources)
|
8
|
-
* [Why Rodauth?](#why-rodauth)
|
9
|
-
* [Upgrading](#upgrading)
|
10
|
-
* [Installation](#installation)
|
11
|
-
* [Usage](#usage)
|
12
|
-
- [Routes](#routes)
|
13
|
-
- [Current account](#current-account)
|
14
|
-
- [Requiring authentication](#requiring-authentication)
|
15
|
-
- [Views](#views)
|
16
|
-
- [Mailer](#mailer)
|
17
|
-
- [Migrations](#migrations)
|
18
|
-
- [Multiple configurations](#multiple-configurations)
|
19
|
-
- [Calling controller methods](#calling-controller-methods)
|
20
|
-
- [Rodauth instance](#rodauth-instance)
|
21
|
-
* [How it works](#how-it-works)
|
22
|
-
- [Middleware](#middleware)
|
23
|
-
- [App](#app)
|
24
|
-
- [Sequel](#sequel)
|
25
|
-
* [JSON API](#json-api)
|
26
|
-
* [OmniAuth](#omniauth)
|
27
|
-
* [Configuring](#configuring)
|
28
|
-
* [Custom extensions](#custom-extensions)
|
29
|
-
* [Testing](#testing)
|
30
|
-
* [Rodauth defaults](#rodauth-defaults)
|
31
|
-
- [Database functions](#database-functions)
|
32
|
-
- [Account statuses](#account-statuses)
|
33
|
-
|
34
5
|
## Resources
|
35
6
|
|
36
7
|
Useful links:
|
@@ -43,6 +14,7 @@ Articles:
|
|
43
14
|
* [Rodauth: A Refreshing Authentication Solution for Ruby](https://janko.io/rodauth-a-refreshing-authentication-solution-for-ruby/)
|
44
15
|
* [Adding Authentication in Rails with Rodauth](https://janko.io/adding-authentication-in-rails-with-rodauth/)
|
45
16
|
* [Adding Multifactor Authentication in Rails with Rodauth](https://janko.io/adding-multifactor-authentication-in-rails-with-rodauth/)
|
17
|
+
* [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)
|
46
18
|
|
47
19
|
## Why Rodauth?
|
48
20
|
|
@@ -61,6 +33,12 @@ of the advantages that stand out for me:
|
|
61
33
|
* consistent before/after hooks around everything
|
62
34
|
* dedicated object encapsulating all authentication logic
|
63
35
|
|
36
|
+
One commmon concern is the fact that, unlike most other authentication
|
37
|
+
frameworks for Rails, Rodauth uses [Sequel] for database interaction instead of
|
38
|
+
Active Record. There are good reasons for this, and to make Rodauth work
|
39
|
+
smoothly alongside Active Record, rodauth-rails configures Sequel to [reuse
|
40
|
+
Active Record's database connection][sequel-activerecord_connection].
|
41
|
+
|
64
42
|
## Upgrading
|
65
43
|
|
66
44
|
### Upgrading to 0.7.0
|
@@ -271,6 +249,19 @@ These routes are fully functional, feel free to visit them and interact with the
|
|
271
249
|
pages. The templates that ship with Rodauth aim to provide a complete
|
272
250
|
authentication experience, and the forms use [Bootstrap] markup.
|
273
251
|
|
252
|
+
Inside Rodauth configuration and the `route` block you can access Rails route
|
253
|
+
helpers through `#rails_routes`:
|
254
|
+
|
255
|
+
```rb
|
256
|
+
class RodauthApp < Rodauth::Rails::App
|
257
|
+
configure do
|
258
|
+
# ...
|
259
|
+
login_redirect { rails_routes.activity_path }
|
260
|
+
# ...
|
261
|
+
end
|
262
|
+
end
|
263
|
+
```
|
264
|
+
|
274
265
|
### Current account
|
275
266
|
|
276
267
|
To be able to fetch currently authenticated account, let's define a
|
@@ -491,7 +482,6 @@ end
|
|
491
482
|
```rb
|
492
483
|
# app/lib/rodauth_app.rb
|
493
484
|
class RodauthApp < Rodauth::Rails::App
|
494
|
-
# ...
|
495
485
|
configure do
|
496
486
|
# ...
|
497
487
|
create_reset_password_email do
|
@@ -521,17 +511,17 @@ class RodauthApp < Rodauth::Rails::App
|
|
521
511
|
end
|
522
512
|
```
|
523
513
|
|
524
|
-
|
525
|
-
|
526
|
-
for better throughput and ability to retry
|
527
|
-
|
514
|
+
This configuration calls `#deliver_later`, which uses Active Job to deliver
|
515
|
+
emails in a background job. It's generally recommended to send emails
|
516
|
+
asynchronously for better request throughput and the ability to retry
|
517
|
+
deliveries. However, if you want to send emails synchronously, modify the
|
518
|
+
configuration to call `#deliver_now` instead.
|
528
519
|
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
SMTP.
|
520
|
+
If you're using a background processing library without an Active Job adapter,
|
521
|
+
or a 3rd-party service for sending transactional emails, this two-phase API
|
522
|
+
might not be suitable. In this case, instead of overriding `#create_*_email`
|
523
|
+
and `#send_email`, override the `#send_*_email` methods instead, which are
|
524
|
+
required to send the email immediately.
|
535
525
|
|
536
526
|
### Migrations
|
537
527
|
|
@@ -586,6 +576,7 @@ class RodauthApp < Rodauth::Rails::App
|
|
586
576
|
r.rodauth(:admin)
|
587
577
|
r.pass # allow the Rails app to handle other "/admin/*" requests
|
588
578
|
end
|
579
|
+
|
589
580
|
# ...
|
590
581
|
end
|
591
582
|
end
|
@@ -638,7 +629,7 @@ common settings:
|
|
638
629
|
|
639
630
|
```rb
|
640
631
|
# app/lib/rodauth_base.rb
|
641
|
-
class RodauthBase < Rodauth::Rails::
|
632
|
+
class RodauthBase < Rodauth::Rails::Auth
|
642
633
|
# common settings that can be shared between multiple configurations
|
643
634
|
configure do
|
644
635
|
enable :login, :logout
|
@@ -676,7 +667,7 @@ class RodauthAdmin < Rodauth::Rails::Auth
|
|
676
667
|
end
|
677
668
|
|
678
669
|
def superadmin?
|
679
|
-
Role.where(account_id: session_id
|
670
|
+
Role.where(account_id: session_id, type: "superadmin").any?
|
680
671
|
end
|
681
672
|
end
|
682
673
|
```
|
@@ -1179,29 +1170,38 @@ end
|
|
1179
1170
|
```
|
1180
1171
|
|
1181
1172
|
If you're delivering emails in the background, make sure to set Active Job
|
1182
|
-
queue adapter to `:test`:
|
1173
|
+
queue adapter to `:test` or `:inline`:
|
1183
1174
|
|
1184
1175
|
```rb
|
1185
1176
|
# config/environments/test.rb
|
1186
1177
|
Rails.application.configure do |config|
|
1187
1178
|
# ...
|
1188
|
-
config.active_job.queue_adapter = :test
|
1179
|
+
config.active_job.queue_adapter = :test # or :inline
|
1189
1180
|
# ...
|
1190
1181
|
end
|
1191
1182
|
```
|
1192
1183
|
|
1193
|
-
If you need to create
|
1184
|
+
If you need to create an account record with a password directly, you can do it
|
1185
|
+
as follows:
|
1194
1186
|
|
1195
1187
|
```rb
|
1196
|
-
|
1197
|
-
|
1198
|
-
|
1199
|
-
|
1200
|
-
|
1201
|
-
|
1202
|
-
|
1203
|
-
|
1204
|
-
|
1188
|
+
# app/models/account.rb
|
1189
|
+
class Account < ApplicationRecord
|
1190
|
+
has_one :password_hash, foreign_key: :id
|
1191
|
+
end
|
1192
|
+
```
|
1193
|
+
```rb
|
1194
|
+
# app/models/account/password_hash.rb
|
1195
|
+
class Account::PasswordHash < ApplicationRecord
|
1196
|
+
belongs_to :account, foreign_key: :id
|
1197
|
+
end
|
1198
|
+
```
|
1199
|
+
```rb
|
1200
|
+
require "bcrypt"
|
1201
|
+
|
1202
|
+
account = Account.create!(email: "user@example.com", status: "verified")
|
1203
|
+
password_hash = BCrypt::Password.create("secret", cost: BCrypt::Engine::MIN_COST)
|
1204
|
+
account.create_password_hash!(id: account.id, password_hash: password_hash)
|
1205
1205
|
```
|
1206
1206
|
|
1207
1207
|
## Rodauth defaults
|
@@ -1,4 +1,4 @@
|
|
1
|
-
Someone has requested
|
1
|
+
Someone has requested that the account with this email be unlocked.
|
2
2
|
If you did not request the unlocking of this account, please ignore this
|
3
3
|
message. If you requested the unlocking of this account, please go to
|
4
4
|
<%%= @email_link %>
|
data/lib/rodauth/rails/app.rb
CHANGED
@@ -27,24 +27,18 @@ module Rodauth
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def flash
|
30
|
-
rails_request.flash
|
30
|
+
scope.rails_request.flash
|
31
31
|
end
|
32
32
|
|
33
33
|
if ActionPack.version >= Gem::Version.new("5.0")
|
34
34
|
def commit_flash
|
35
|
-
rails_request.commit_flash
|
35
|
+
scope.rails_request.commit_flash
|
36
36
|
end
|
37
37
|
else
|
38
38
|
def commit_flash
|
39
39
|
# ActionPack 4.2 automatically commits flash
|
40
40
|
end
|
41
41
|
end
|
42
|
-
|
43
|
-
private
|
44
|
-
|
45
|
-
def rails_request
|
46
|
-
ActionDispatch::Request.new(env)
|
47
|
-
end
|
48
42
|
end
|
49
43
|
end
|
50
44
|
end
|
@@ -63,24 +63,33 @@ module Rodauth
|
|
63
63
|
super.html_safe
|
64
64
|
end
|
65
65
|
|
66
|
+
delegate :rails_routes, :rails_request, to: :scope
|
67
|
+
|
66
68
|
private
|
67
69
|
|
68
70
|
# Runs controller callbacks and rescue handlers around Rodauth actions.
|
69
71
|
def _around_rodauth(&block)
|
70
72
|
result = nil
|
71
73
|
|
72
|
-
|
73
|
-
|
74
|
-
|
74
|
+
rails_instrument_request do
|
75
|
+
rails_controller_rescue do
|
76
|
+
rails_controller_callbacks do
|
77
|
+
result = catch(:halt) { super(&block) }
|
78
|
+
end
|
75
79
|
end
|
80
|
+
|
81
|
+
result = handle_rails_controller_response(result)
|
76
82
|
end
|
77
83
|
|
84
|
+
throw :halt, result if result
|
85
|
+
end
|
86
|
+
|
87
|
+
# Handles controller rendering a response or setting response headers.
|
88
|
+
def handle_rails_controller_response(result)
|
78
89
|
if rails_controller_instance.performed?
|
79
90
|
rails_controller_response
|
80
91
|
elsif result
|
81
92
|
result[1].merge!(rails_controller_instance.response.headers)
|
82
|
-
throw :halt, result
|
83
|
-
else
|
84
93
|
result
|
85
94
|
end
|
86
95
|
end
|
@@ -109,6 +118,20 @@ module Rodauth
|
|
109
118
|
end
|
110
119
|
end
|
111
120
|
|
121
|
+
def rails_instrument_request
|
122
|
+
ActiveSupport::Notifications.instrument("start_processing.rodauth", rodauth: self)
|
123
|
+
ActiveSupport::Notifications.instrument("process_request.rodauth", rodauth: self) do |payload|
|
124
|
+
begin
|
125
|
+
status, headers, body = yield
|
126
|
+
payload[:status] = status || 404
|
127
|
+
payload[:headers] = headers
|
128
|
+
payload[:body] = body
|
129
|
+
ensure
|
130
|
+
rails_controller_instance.send(:append_info_to_payload, payload)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
112
135
|
# Returns Roda response from controller response if set.
|
113
136
|
def rails_controller_response
|
114
137
|
controller_response = rails_controller_instance.response
|
@@ -117,7 +140,7 @@ module Rodauth
|
|
117
140
|
response.headers.merge! controller_response.headers
|
118
141
|
response.write controller_response.body
|
119
142
|
|
120
|
-
|
143
|
+
response.finish
|
121
144
|
end
|
122
145
|
|
123
146
|
# Create emails with ActionMailer which uses configured delivery method.
|
@@ -168,11 +191,8 @@ module Rodauth
|
|
168
191
|
|
169
192
|
# Instances of the configured controller with current request's env hash.
|
170
193
|
def _rails_controller_instance
|
171
|
-
controller
|
172
|
-
rails_request = ActionDispatch::Request.new(scope.env)
|
173
|
-
|
194
|
+
controller = rails_controller.new
|
174
195
|
prepare_rails_controller(controller, rails_request)
|
175
|
-
|
176
196
|
controller
|
177
197
|
end
|
178
198
|
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Rodauth
|
2
|
+
module Rails
|
3
|
+
class LogSubscriber < ActiveSupport::LogSubscriber
|
4
|
+
def start_processing(event)
|
5
|
+
rodauth = event.payload[:rodauth]
|
6
|
+
app_class = rodauth.scope.class.superclass
|
7
|
+
format = rodauth.rails_request.format.ref
|
8
|
+
format = format.to_s.upcase if format.is_a?(Symbol)
|
9
|
+
format = "*/*" if format.nil?
|
10
|
+
|
11
|
+
info "Processing by #{app_class} as #{format}"
|
12
|
+
end
|
13
|
+
|
14
|
+
def process_request(event)
|
15
|
+
status = event.payload[:status]
|
16
|
+
|
17
|
+
additions = ActionController::Base.log_process_action(event.payload)
|
18
|
+
if ::Rails.gem_version >= Gem::Version.new("6.0")
|
19
|
+
additions << "Allocations: #{event.allocations}"
|
20
|
+
end
|
21
|
+
|
22
|
+
message = "Completed #{status} #{Rack::Utils::HTTP_STATUS_CODES[status]} in #{event.duration.round}ms"
|
23
|
+
message << " (#{additions.join(" | ")})"
|
24
|
+
message << "\n\n" if defined?(::Rails.env) && ::Rails.env.development?
|
25
|
+
|
26
|
+
info message
|
27
|
+
end
|
28
|
+
|
29
|
+
def logger
|
30
|
+
::Rails.logger
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require "rodauth/rails/middleware"
|
2
2
|
require "rodauth/rails/controller_methods"
|
3
|
+
require "rodauth/rails/log_subscriber"
|
3
4
|
|
4
5
|
require "rails"
|
5
6
|
|
@@ -16,6 +17,10 @@ module Rodauth
|
|
16
17
|
end
|
17
18
|
end
|
18
19
|
|
20
|
+
initializer "rodauth.log_subscriber" do
|
21
|
+
Rodauth::Rails::LogSubscriber.attach_to :rodauth
|
22
|
+
end
|
23
|
+
|
19
24
|
initializer "rodauth.test" do
|
20
25
|
# Rodauth uses RACK_ENV to set the default bcrypt hash cost
|
21
26
|
ENV["RACK_ENV"] = "test" if ::Rails.env.test?
|
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: 0.
|
4
|
+
version: 0.11.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Janko Marohnić
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-05-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: railties
|
@@ -207,6 +207,7 @@ files:
|
|
207
207
|
- lib/rodauth/rails/auth.rb
|
208
208
|
- lib/rodauth/rails/controller_methods.rb
|
209
209
|
- lib/rodauth/rails/feature.rb
|
210
|
+
- lib/rodauth/rails/log_subscriber.rb
|
210
211
|
- lib/rodauth/rails/middleware.rb
|
211
212
|
- lib/rodauth/rails/railtie.rb
|
212
213
|
- lib/rodauth/rails/tasks.rake
|