rodauth-rails 0.10.0 → 0.11.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|