rodauth-rails 0.4.1 → 0.7.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.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +42 -0
  3. data/README.md +187 -52
  4. data/lib/generators/rodauth/install_generator.rb +28 -20
  5. data/lib/generators/rodauth/migration/account_expiration.erb +7 -0
  6. data/lib/generators/rodauth/migration/active_sessions.erb +7 -0
  7. data/lib/generators/rodauth/migration/audit_logging.erb +16 -0
  8. data/lib/generators/rodauth/migration/base.erb +19 -0
  9. data/lib/generators/rodauth/migration/disallow_password_reuse.erb +5 -0
  10. data/lib/generators/rodauth/migration/email_auth.erb +7 -0
  11. data/lib/generators/rodauth/migration/jwt_refresh.erb +7 -0
  12. data/lib/generators/rodauth/migration/lockout.erb +11 -0
  13. data/lib/generators/rodauth/migration/otp.erb +7 -0
  14. data/lib/generators/rodauth/migration/password_expiration.erb +5 -0
  15. data/lib/generators/rodauth/migration/recovery_codes.erb +6 -0
  16. data/lib/generators/rodauth/migration/remember.erb +6 -0
  17. data/lib/generators/rodauth/migration/reset_password.erb +7 -0
  18. data/lib/generators/rodauth/migration/single_session.erb +5 -0
  19. data/lib/generators/rodauth/migration/sms_codes.erb +8 -0
  20. data/lib/generators/rodauth/migration/verify_account.erb +7 -0
  21. data/lib/generators/rodauth/migration/verify_login_change.erb +7 -0
  22. data/lib/generators/rodauth/migration/webauthn.erb +12 -0
  23. data/lib/generators/rodauth/migration_generator.rb +32 -0
  24. data/lib/generators/rodauth/migration_helpers.rb +69 -0
  25. data/lib/generators/rodauth/templates/app/controllers/rodauth_controller.rb +2 -1
  26. data/lib/generators/rodauth/templates/app/lib/rodauth_app.rb +18 -20
  27. data/lib/generators/rodauth/templates/config/initializers/sequel.rb +1 -5
  28. data/lib/generators/rodauth/templates/db/migrate/create_rodauth.rb +2 -176
  29. data/lib/rodauth/rails.rb +33 -4
  30. data/lib/rodauth/rails/app.rb +4 -2
  31. data/lib/rodauth/rails/app/flash.rb +1 -1
  32. data/lib/rodauth/rails/app/middleware.rb +26 -0
  33. data/lib/rodauth/rails/feature.rb +98 -30
  34. data/lib/rodauth/rails/railtie.rb +11 -0
  35. data/lib/rodauth/rails/tasks.rake +28 -0
  36. data/lib/rodauth/rails/version.rb +1 -1
  37. data/rodauth-rails.gemspec +3 -3
  38. metadata +29 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c1e2e56e1f7312210e9f8fc587a783445f701a238aec21febf5f6ae0489e39c9
4
- data.tar.gz: d192cdbbc8aeebbb0a8318430cc5771bf26abd6e392644393c1755af28aeb9dd
3
+ metadata.gz: 8163d64892cbebd867182d15148f3099abb3ed49ae3e07a89a5adea6606623d2
4
+ data.tar.gz: 3cc7990e0af8e5ffb2ac959f989fb45cf538490412adfc908571823e5dd7b160
5
5
  SHA512:
6
- metadata.gz: 145b25b7e6bdb4a6ad395ec5e717112c93624005480bda4d617c036d45766224ea9ebe7f389b14f6d3fb6a9036c9a9a08c7595cfae710b58ff3458f698e9ce70
7
- data.tar.gz: 51018b0878979bbc34c03f6dbd2a197c04854e3022561dd3db97ae2bb5d42f436d22c008d0ffd06ca8693435e5a69b5e938587f92baf5c39ad50bb247dfa2979
6
+ metadata.gz: 99005d6864310fa3a36f8314a13588900a5ac1559af7a77d75cb5aba66b0b829d32c83fe66a3f5a7ced098de32b39396edd666919177836bb84b35a0de3a558b
7
+ data.tar.gz: 2d66b5ab43d05b26483cb3d69181c506b19a937fa77a2d7d66a38708f6357fae7bd2e605cc0a96affdd8fed822076dccb1603577338e68620c70a816fc45db7a
@@ -1,3 +1,45 @@
1
+ ## 0.7.0 (2020-11-27)
2
+
3
+ * Add `#rails_controller_eval` method for running code in context of a controller instance (@janko)
4
+
5
+ * Detect `secret_key_base` from credentials and `$SECRET_KEY_BASE` environment variable (@janko)
6
+
7
+ ## 0.6.1 (2020-11-25)
8
+
9
+ * Generate the Rodauth controller for API-only Rails apps as well (@janko)
10
+
11
+ * Fix remember cookie deadline not extending in remember feature (@janko)
12
+
13
+ ## 0.6.0 (2020-11-22)
14
+
15
+ * Add `Rodauth::Rails.rodauth` method for retrieving Rodauth instance outside of request context (@janko)
16
+
17
+ * Add default Action Dispatch response headers in Rodauth responses (@janko)
18
+
19
+ * Run controller rescue handlers around Rodauth actions (@janko)
20
+
21
+ * Run controller action callbacks around Rodauth actions (@janko)
22
+
23
+ ## 0.5.0 (2020-11-16)
24
+
25
+ * Support more Active Record adapters in `rodauth:install` generator (@janko)
26
+
27
+ * Add `rodauth:migration` generator for creating tables of specified features (@janko)
28
+
29
+ * Use UUIDs for primary keys if so configured in Rails generators (@janko)
30
+
31
+ * Add `rodauth:routes` rake task for printing routes handled by Rodauth middleware (@janko)
32
+
33
+ ## 0.4.2 (2020-11-08)
34
+
35
+ * Drop support for Ruby 2.2 (@janko)
36
+
37
+ * Bump `sequel-activerecord_connection` dependency to 1.1+ (@janko)
38
+
39
+ * Set default bcrypt hash cost to `1` in tests (@janko)
40
+
41
+ * Call `AR::Base.connection_db_config` on Rails 6.1+ in `rodauth:install` generator (@janko)
42
+
1
43
  ## 0.4.1 (2020-11-02)
2
44
 
3
45
  * Don't generate `RodauthController` in API-only mode (@janko)
data/README.md CHANGED
@@ -4,16 +4,39 @@ Provides Rails integration for the [Rodauth] authentication framework.
4
4
 
5
5
  ## Resources
6
6
 
7
+ Useful links:
8
+
7
9
  * [Rodauth documentation](http://rodauth.jeremyevans.net/documentation.html)
8
- * [rodauth-rails wiki](https://github.com/janko/rodauth-rails/wiki)
9
10
  * [Rails demo](https://github.com/janko/rodauth-demo-rails)
10
11
 
12
+ Articles:
13
+
14
+ * [Rodauth: A Refreshing Authentication Solution for Ruby](https://janko.io/rodauth-a-refreshing-authentication-solution-for-ruby/)
15
+ * [Adding Authentication in Rails 6 with Rodauth](https://janko.io/adding-authentication-in-rails-with-rodauth/)
16
+
17
+ ## Upgrading
18
+
19
+ ### Upgrading to 0.7.0
20
+
21
+ Starting from version 0.7.0, rodauth-rails now correctly detects Rails
22
+ application's `secret_key_base` when setting default `hmac_secret`, including
23
+ when it's set via credentials or `$SECRET_KEY_BASE` environment variable. This
24
+ means authentication will be more secure by default, and Rodauth features that
25
+ require `hmac_secret` should now work automatically as well.
26
+
27
+ However, if you've already been using rodauth-rails in production, where the
28
+ `secret_key_base` is set via credentials or environment variable and `hmac_secret`
29
+ was not explicitly set, the fact that your authentication will now start using
30
+ HMACs has backwards compatibility considerations. See the [Rodauth
31
+ documentation](hmac) for instructions on how to safely transition, or just set
32
+ `hmac_secret nil` in your Rodauth configuration.
33
+
11
34
  ## Installation
12
35
 
13
36
  Add the gem to your Gemfile:
14
37
 
15
38
  ```rb
16
- gem "rodauth-rails", "~> 0.4"
39
+ gem "rodauth-rails", "~> 0.6"
17
40
 
18
41
  # gem "jwt", require: false # for JWT feature
19
42
  # gem "rotp", require: false # for OTP feature
@@ -54,7 +77,6 @@ class CreateRodauth < ActiveRecord::Migration
54
77
  create_table :account_verification_keys do |t| ... end
55
78
  create_table :account_login_change_keys do |t| ... end
56
79
  create_table :account_remember_keys do |t| ... end
57
- # ...
58
80
  end
59
81
  end
60
82
  ```
@@ -88,7 +110,7 @@ ActiveRecord connection.
88
110
  require "sequel/core"
89
111
 
90
112
  # initialize Sequel and have it reuse Active Record's database connection
91
- DB = Sequel.postgres(extensions: :activerecord_connection, test: false)
113
+ DB = Sequel.connect("postgresql://", extensions: :activerecord_connection)
92
114
  ```
93
115
 
94
116
  ### Rodauth app
@@ -112,8 +134,9 @@ end
112
134
 
113
135
  ### Controller
114
136
 
115
- Your Rodauth app will by default use `RodauthController` for view rendering
116
- and CSRF protection.
137
+ Your Rodauth app will by default use `RodauthController` for view rendering,
138
+ CSRF protection, and running controller callbacks and rescue handlers around
139
+ Rodauth actions.
117
140
 
118
141
  ```rb
119
142
  # app/controllers/rodauth_controller.rb
@@ -121,7 +144,7 @@ class RodauthController < ApplicationController
121
144
  end
122
145
  ```
123
146
 
124
- ### Account Model
147
+ ### Account model
125
148
 
126
149
  Rodauth stores user accounts in the `accounts` table, so the generator will
127
150
  also create an `Account` model for custom use.
@@ -132,10 +155,34 @@ class Account < ApplicationRecord
132
155
  end
133
156
  ```
134
157
 
135
- ## Getting started
158
+ ## Usage
159
+
160
+ ### Routes
161
+
162
+ We can see the list of routes our Rodauth middleware handles:
163
+
164
+ ```sh
165
+ $ rails rodauth:routes
166
+ ```
167
+ ```
168
+ Routes handled by RodauthApp:
169
+
170
+ /login rodauth.login_path
171
+ /create-account rodauth.create_account_path
172
+ /verify-account-resend rodauth.verify_account_resend_path
173
+ /verify-account rodauth.verify_account_path
174
+ /change-password rodauth.change_password_path
175
+ /change-login rodauth.change_login_path
176
+ /logout rodauth.logout_path
177
+ /remember rodauth.remember_path
178
+ /reset-password-request rodauth.reset_password_request_path
179
+ /reset-password rodauth.reset_password_path
180
+ /verify-login-change rodauth.verify_login_change_path
181
+ /close-account rodauth.close_account_path
182
+ ```
136
183
 
137
- Let's start by adding some basic authentication navigation links to our home
138
- page:
184
+ Using this information, we could add some basic authentication links to our
185
+ navigation header:
139
186
 
140
187
  ```erb
141
188
  <ul>
@@ -148,40 +195,45 @@ page:
148
195
  </ul>
149
196
  ```
150
197
 
151
- These links are fully functional, feel free to visit them and interact with the
198
+ These routes are fully functional, feel free to visit them and interact with the
152
199
  pages. The templates that ship with Rodauth aim to provide a complete
153
200
  authentication experience, and the forms use [Bootstrap] markup.
154
201
 
155
- Let's also load the account record for authenticated requests and expose it via
156
- `#current_account`:
202
+ ### Current account
203
+
204
+ To be able to fetch currently authenticated account, let's define a
205
+ `#current_account` method that fetches the account id from session and
206
+ retrieves the corresponding account record:
157
207
 
158
208
  ```rb
159
209
  # app/controllers/application_controller.rb
160
210
  class ApplicationController < ActionController::Base
161
- before_action :load_account, if: -> { rodauth.authenticated? }
211
+ before_action :current_account, if: -> { rodauth.authenticated? }
162
212
 
163
213
  private
164
214
 
165
- def load_account
166
- @current_account = Account.find(rodauth.session_value)
215
+ def current_account
216
+ @current_account ||= Account.find(rodauth.session_value)
167
217
  rescue ActiveRecord::RecordNotFound
168
218
  rodauth.logout
169
219
  rodauth.login_required
170
220
  end
171
-
172
- attr_reader :current_account
173
221
  helper_method :current_account
174
222
  end
175
223
  ```
224
+
225
+ This allows us to access the current account in controllers and views:
226
+
176
227
  ```erb
177
228
  <p>Authenticated as: <%= current_account.email %></p>
178
229
  ```
179
230
 
180
231
  ### Requiring authentication
181
232
 
182
- Next, we'll likely want to require authentication for certain sections/pages of
183
- our app. We can do this in our Rodauth app's routing block, which helps keep
184
- the authentication logic encapsulated:
233
+ We'll likely want to require authentication for certain parts of our app,
234
+ redirecting the user to the login page if they're not logged in. We can do this
235
+ in our Rodauth app's routing block, which helps keep the authentication logic
236
+ encapsulated:
185
237
 
186
238
  ```rb
187
239
  # app/lib/rodauth_app.rb
@@ -239,9 +291,9 @@ end
239
291
 
240
292
  ### Views
241
293
 
242
- The templates built into Rodauth are useful when getting started, but at some
243
- point we'll probably want more control over the markup. For that we can run the
244
- following command:
294
+ The templates built into Rodauth are useful when getting started, but soon
295
+ you'll want to start editing the markup. You can run the following command to
296
+ copy Rodauth templates into your Rails app:
245
297
 
246
298
  ```sh
247
299
  $ rails generate rodauth:views
@@ -265,7 +317,7 @@ $ rails generate rodauth:views --all
265
317
  ```
266
318
 
267
319
  You can also tell the generator to create views into another directory (in this
268
- case don't forget to rename the Rodauth controller accordingly).
320
+ case make sure to rename the Rodauth controller accordingly):
269
321
 
270
322
  ```sh
271
323
  # generates views into app/views/authentication
@@ -300,8 +352,8 @@ end
300
352
 
301
353
  ### Mailer
302
354
 
303
- Rodauth may send emails as part of the authentication flow. Most email settings
304
- can be customized:
355
+ Depending on the features you've enabled, Rodauth may send emails as part of
356
+ the authentication flow. Most email settings can be customized:
305
357
 
306
358
  ```rb
307
359
  # app/lib/rodauth_app.rb
@@ -345,8 +397,8 @@ end
345
397
  ```
346
398
 
347
399
  You can then uncomment the lines in your Rodauth configuration to have it call
348
- your mailer. If you've enabled additional authentication features, make sure to
349
- override their `send_*_email` methods as well.
400
+ your mailer. If you've enabled additional authentication features that send
401
+ emails, make sure to override their `create_*_email` methods as well.
350
402
 
351
403
  ```rb
352
404
  # app/lib/rodauth_app.rb
@@ -354,37 +406,58 @@ class RodauthApp < Rodauth::Rails::App
354
406
  # ...
355
407
  configure do
356
408
  # ...
357
- send_reset_password_email do
358
- mailer_send(:reset_password, email_to, reset_password_email_link)
409
+ create_reset_password_email do
410
+ RodauthMailer.reset_password(email_to, reset_password_email_link)
359
411
  end
360
- send_verify_account_email do
361
- mailer_send(:verify_account, email_to, verify_account_email_link)
412
+ create_verify_account_email do
413
+ RodauthMailer.verify_account(email_to, verify_account_email_link)
362
414
  end
363
- send_verify_login_change_email do |login|
364
- mailer_send(:verify_login_change, login, verify_login_change_old_login, verify_login_change_new_login, verify_login_change_email_link)
415
+ create_verify_login_change_email do |login|
416
+ RodauthMailer.verify_login_change(login, verify_login_change_old_login, verify_login_change_new_login, verify_login_change_email_link)
365
417
  end
366
- send_password_changed_email do
367
- mailer_send(:password_changed, email_to)
418
+ create_password_changed_email do
419
+ RodauthMailer.password_changed(email_to)
368
420
  end
369
- # send_email_auth_email do
370
- # mailer_send(:email_auth, email_to, email_auth_email_link)
421
+ # create_email_auth_email do
422
+ # RodauthMailer.email_auth(email_to, email_auth_email_link)
371
423
  # end
372
- # send_unlock_account_email do
373
- # mailer_send(:unlock_account, email_to, unlock_account_email_link)
424
+ # create_unlock_account_email do
425
+ # RodauthMailer.unlock_account(email_to, unlock_account_email_link)
374
426
  # end
375
- auth_class_eval do
427
+ send_email do |email|
376
428
  # queue email delivery on the mailer after the transaction commits
377
- def mailer_send(type, *args)
378
- db.after_commit do
379
- RodauthMailer.public_send(type, *args).deliver_later
380
- end
381
- end
429
+ db.after_commit { email.deliver_later }
382
430
  end
383
431
  # ...
384
432
  end
385
433
  end
386
434
  ```
387
435
 
436
+ This approach can be used even if you're using a 3rd-party service for
437
+ transactional emails, where emails are sent via API requests instead of
438
+ SMTP. Whatever the `create_*_email` block returns will be passed to
439
+ `send_email`, so you can be creative.
440
+
441
+ ### Migrations
442
+
443
+ The install generator will create a migration for tables used by the Rodauth
444
+ features enabled by default. For any additional features, you can use the
445
+ migration generator to create the corresponding tables:
446
+
447
+ ```sh
448
+ $ rails generate rodauth:migration otp sms_codes recovery_codes
449
+ ```
450
+ ```rb
451
+ # db/migration/*_create_rodauth_otp_sms_codes_recovery_codes.rb
452
+ class CreateRodauthOtpSmsCodesRecoveryCodes < ActiveRecord::Migration
453
+ def change
454
+ create_table :account_otp_keys do |t| ... end
455
+ create_table :account_sms_codes do |t| ... end
456
+ create_table :account_recovery_codes do |t| ... end
457
+ end
458
+ end
459
+ ```
460
+
388
461
  ### JSON API
389
462
 
390
463
  JSON API support in Rodauth is provided by the [JWT feature]. First you'll need
@@ -416,6 +489,51 @@ the configure method.
416
489
  Make sure to store the `jwt_secret` in a secure place, such as Rails
417
490
  credentials or environment variables.
418
491
 
492
+ ### Calling controller methods
493
+
494
+ When using Rodauth before/after hooks or generally overriding your Rodauth
495
+ configuration, in some cases you might want to call methods defined on your
496
+ controllers. You can do so with `rails_controller_eval`, for example:
497
+
498
+ ```rb
499
+ # app/controllers/application_controller.rb
500
+ class ApplicationController < ActionController::Base
501
+ private
502
+ def setup_tracking(account_id)
503
+ # ... some implementation ...
504
+ end
505
+ end
506
+ ```
507
+ ```rb
508
+ # app/lib/rodauth_app.rb
509
+ class RodauthApp < Rodauth::Rails::App
510
+ configure do
511
+ after_create_account do
512
+ rails_controller_eval { setup_tracking(account_id) }
513
+ end
514
+ end
515
+ end
516
+ ```
517
+
518
+ ### Rodauth instance
519
+
520
+ In some cases you might need to use Rodauth more programmatically, and perform
521
+ Rodauth operations outside of the request context. rodauth-rails gives you the
522
+ ability to retrieve the Rodauth instance:
523
+
524
+ ```rb
525
+ rodauth = Rodauth::Rails.rodauth # or Rodauth::Rails.rodauth(:secondary)
526
+
527
+ rodauth.login_url #=> "https://example.com/login"
528
+ rodauth.account_from_login("user@example.com") # loads user by email
529
+ rodauth.password_match?("secret") #=> true
530
+ rodauth.setup_account_verification
531
+ rodauth.close_account
532
+ ```
533
+
534
+ This Rodauth instance will be initialized with basic Rack env that allows is it
535
+ to generate URLs, using `config.action_mailer.default_url_options` options.
536
+
419
537
  ## How it works
420
538
 
421
539
  ### Middleware
@@ -460,11 +578,12 @@ end
460
578
  The `Rodauth::Rails::App` class is a [Roda] subclass that provides Rails
461
579
  integration for Rodauth:
462
580
 
463
- * uses Rails' flash instead of Roda's
464
- * uses Rails' CSRF protection instead of Roda's
581
+ * uses Action Dispatch flash instead of Roda's
582
+ * uses Action Dispatch CSRF protection instead of Roda's
465
583
  * sets [HMAC] secret to Rails' secret key base
466
- * uses ActionController for rendering templates
467
- * uses ActionMailer for sending emails
584
+ * uses Action Controller for rendering templates
585
+ * runs Action Controller callbacks & rescue handlers around Rodauth actions
586
+ * uses Action Mailer for sending emails
468
587
 
469
588
  The `configure { ... }` method wraps configuring the Rodauth plugin, forwarding
470
589
  any additional [plugin options].
@@ -588,6 +707,22 @@ disables the use of database functions, though you can always turn it back on.
588
707
  use_database_authentication_functions? true
589
708
  ```
590
709
 
710
+ To create the database functions, pass the Sequel database object into the
711
+ Rodauth method for creating database functions:
712
+
713
+ ```rb
714
+ # db/migrate/*_create_rodauth_database_functions.rb
715
+ class CreateRodauthDatabaseFunctions < ActiveRecord::Migration
716
+ def up
717
+ Rodauth.create_database_authentication_functions(DB)
718
+ end
719
+
720
+ def down
721
+ Rodauth.drop_database_authentication_functions(DB)
722
+ end
723
+ end
724
+ ```
725
+
591
726
  ### Account statuses
592
727
 
593
728
  The recommended [Rodauth migration] stores possible account status values in a
@@ -640,7 +775,6 @@ conduct](https://github.com/janko/rodauth-rails/blob/master/CODE_OF_CONDUCT.md).
640
775
 
641
776
  [Rodauth]: https://github.com/jeremyevans/rodauth
642
777
  [Sequel]: https://github.com/jeremyevans/sequel
643
- [rendering views outside of controllers]: https://blog.bigbinary.com/2016/01/08/rendering-views-outside-of-controllers-in-rails-5.html
644
778
  [feature documentation]: http://rodauth.jeremyevans.net/documentation.html
645
779
  [JWT feature]: http://rodauth.jeremyevans.net/rdoc/files/doc/jwt_rdoc.html
646
780
  [JWT gem]: https://github.com/jwt/ruby-jwt
@@ -651,3 +785,4 @@ conduct](https://github.com/janko/rodauth-rails/blob/master/CODE_OF_CONDUCT.md).
651
785
  [Rodauth migration]: http://rodauth.jeremyevans.net/rdoc/files/README_rdoc.html#label-Creating+tables
652
786
  [sequel-activerecord_connection]: https://github.com/janko/sequel-activerecord_connection
653
787
  [plugin options]: http://rodauth.jeremyevans.net/rdoc/files/README_rdoc.html#label-Plugin+Options
788
+ [hmac]: http://rodauth.jeremyevans.net/rdoc/files/README_rdoc.html#label-HMAC