rodauth-rails 0.4.1 → 0.7.0

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