rodauth-rails 1.0.0 → 1.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 34d196440d63f28b871b42b21686018546c3e98df2239f69611847a0b3a2546a
4
- data.tar.gz: d73de73af3c8985be686bf512c7b15bdf9bf27ecda1bfe30ad8d8a21964f0de0
3
+ metadata.gz: 8643f8a912963b78be7d03a815b813688304f4e4b2777a1fdade807f79a4c712
4
+ data.tar.gz: 31aadb16115fc826750b7d160dcb572ae9c24255d99a7c640abef5fd157bd319
5
5
  SHA512:
6
- metadata.gz: acddd3554346ce6f7048ac56a59e0f0439312668fbf8e94450fd23d4d2464ad82655e221e6e15cd5755ef9207c49fe56c6fb67d95bbb764989ec39c6ff4df46a
7
- data.tar.gz: a2be70d18c1ac8f1d6fca8eaef39a54c88a468dc96140eff05b5bb6bf9c901b93de64fd71c9dc27ef302edf643d024e34141b9258b3879a75e0aa96af28b7a27
6
+ metadata.gz: dd27d717b3a01f0b5f43e346c0cd839e2703ee0db44f7503eb6ce80f7cffd4493f4ed9e208db474af56af536f675444170f16a6d47435e1f4ce2af38a7487916
7
+ data.tar.gz: bbac5b7492751e76886a5bcd275af78aada1026d2cd95ddee732817e8d7a5a154f559e5c27ce08606d444a1ffd4640f8522744bd13939f6491288d57c986fea0
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## 1.1.0 (2022-01-16)
2
+
3
+ * Automatically route the path prefix in `r.rodauth` if one has been set (@janko)
4
+
1
5
  ## 1.0.0 (2021-12-25)
2
6
 
3
7
  * Set Rodauth's email subject in the generated mailer (@janko)
data/LICENSE.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2020 Janko Marohnić
3
+ Copyright (c) 2020-2022 Janko Marohnić
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -95,8 +95,8 @@ config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
95
95
 
96
96
  ### Routes
97
97
 
98
- Because requests to Rodauth endpoints are handled by the Rodauth middleware, and
99
- not a Rails controller, Rodauth routes will not show in `rails routes`.
98
+ Because requests to Rodauth endpoints are handled by a Rack middleware (and not
99
+ a Rails controller), Rodauth routes will not show in `rails routes`.
100
100
 
101
101
  Use the `rodauth:routes` rake task to view the list of endpoints based on
102
102
  currently loaded features:
@@ -609,21 +609,12 @@ them under a name.
609
609
  ```rb
610
610
  # app/misc/rodauth_app.rb
611
611
  class RodauthApp < Rodauth::Rails::App
612
- # primary configuration
613
- configure RodauthMain
614
-
615
- # secondary configuration
616
- configure RodauthAdmin, :admin
612
+ configure RodauthMain # primary configuration
613
+ configure RodauthAdmin, :admin # secondary configuration
617
614
 
618
615
  route do |r|
619
- r.rodauth
620
-
621
- r.on "admin" do
622
- r.rodauth(:admin)
623
- break # allow routing of other /admin/* requests to continue to Rails
624
- end
625
-
626
- # ...
616
+ r.rodauth # route primary rodauth requests
617
+ r.rodauth(:admin) # route secondary rodauth requests
627
618
  end
628
619
  end
629
620
  ```
@@ -635,7 +626,6 @@ class RodauthAdmin < Rodauth::Rails::Auth
635
626
  prefix "/admin"
636
627
  session_key_prefix "admin_"
637
628
  remember_cookie_key "_admin_remember" # if using remember feature
638
- # ...
639
629
 
640
630
  # search views in `app/views/admin/rodauth` directory
641
631
  rails_controller { Admin::RodauthController }
@@ -717,10 +707,6 @@ RodauthApp.rodauth.verify_account(account_login: "user@example.com")
717
707
  RodauthApp.rodauth(:admin).close_account(account_login: "user@example.com")
718
708
  ```
719
709
 
720
- The rodauth-rails gem additionally updates the internal rack env hash with your
721
- `config.action_mailer.default_url_options`, which is used for generating email
722
- links.
723
-
724
710
  ### Generating URLs
725
711
 
726
712
  For generating authentication URLs outside of a request use the
@@ -781,104 +767,6 @@ Rodauth::Rails.rodauth(session: { two_factor_auth_setup: true })
781
767
  Rodauth::Rails.rodauth(:admin, params: { "param" => "value" })
782
768
  ```
783
769
 
784
- ## How it works
785
-
786
- ### Middleware
787
-
788
- rodauth-rails inserts a `Rodauth::Rails::Middleware` into your middleware
789
- stack, which calls your Rodauth app for each request, before the request
790
- reaches the Rails router.
791
-
792
- ```sh
793
- $ rails middleware
794
- ...
795
- use Rodauth::Rails::Middleware
796
- run MyApp::Application.routes
797
- ```
798
-
799
- The Rodauth app stores the `Rodauth::Auth` instance in the Rack env hash, which
800
- is then available in your Rails app:
801
-
802
- ```rb
803
- request.env["rodauth"] #=> #<Rodauth::Auth>
804
- request.env["rodauth.admin"] #=> #<Rodauth::Auth> (if using multiple configurations)
805
- ```
806
-
807
- For convenience, this object can be accessed via the `#rodauth` method in views
808
- and controllers:
809
-
810
- ```rb
811
- class MyController < ApplicationController
812
- def my_action
813
- rodauth #=> #<Rodauth::Auth>
814
- rodauth(:admin) #=> #<Rodauth::Auth> (if using multiple configurations)
815
- end
816
- end
817
- ```
818
- ```erb
819
- <% rodauth #=> #<Rodauth::Auth> %>
820
- <% rodauth(:admin) #=> #<Rodauth::Auth> (if using multiple configurations) %>
821
- ```
822
-
823
- ### App
824
-
825
- The `Rodauth::Rails::App` class is a [Roda] subclass that provides Rails
826
- integration for Rodauth:
827
-
828
- * uses Action Dispatch flash instead of Roda's
829
- * uses Action Dispatch CSRF protection instead of Roda's
830
- * sets [HMAC] secret to Rails' secret key base
831
- * uses Action Controller for rendering templates
832
- * runs Action Controller callbacks & rescue handlers around Rodauth actions
833
- * uses Action Mailer for sending emails
834
-
835
- The `configure` method wraps configuring the Rodauth plugin, forwarding
836
- any additional [plugin options].
837
-
838
- ```rb
839
- class RodauthApp < Rodauth::Rails::App
840
- configure { ... } # defining default Rodauth configuration
841
- configure(json: true) { ... } # passing options to the Rodauth plugin
842
- configure(:admin) { ... } # defining multiple Rodauth configurations
843
- end
844
- ```
845
-
846
- The `route` block is provided by Roda, and it's called on each request before
847
- it reaches the Rails router.
848
-
849
- ```rb
850
- class RodauthApp < Rodauth::Rails::App
851
- route do |r|
852
- # ... called before each request ...
853
- end
854
- end
855
- ```
856
-
857
- Since `Rodauth::Rails::App` is just a Roda subclass, you can do anything you
858
- would with a Roda app, such as loading additional Roda plugins:
859
-
860
- ```rb
861
- class RodauthApp < Rodauth::Rails::App
862
- plugin :request_headers # easier access to request headers
863
- plugin :typecast_params # methods for conversion of request params
864
- plugin :default_headers, { "Foo" => "Bar" }
865
- # ...
866
- end
867
- ```
868
-
869
- ### Sequel
870
-
871
- Rodauth uses the [Sequel] library for database queries, due to more advanced
872
- database usage (SQL expressions, database-agnostic date arithmetic, SQL
873
- function calls).
874
-
875
- If ActiveRecord is used in the application, the `rodauth:install` generator
876
- will have automatically configured Sequel to reuse ActiveRecord's database
877
- connection, using the [sequel-activerecord_connection] gem.
878
-
879
- This means that, from the usage perspective, Sequel can be considered just
880
- as an implementation detail of Rodauth.
881
-
882
770
  ## Configuring
883
771
 
884
772
  ### Configuration methods
@@ -897,23 +785,6 @@ methods:
897
785
  | `rails_controller` | Controller class to use for rendering and CSRF protection. |
898
786
  | `rails_account_model` | Model class connected with the accounts table. |
899
787
 
900
- ### General configuration
901
-
902
- The `Rodauth::Rails` module has a few config settings available as well:
903
-
904
- | Name | Description |
905
- | :----- | :---------- |
906
- | `app` | Constant name of your Rodauth app, which is called by the middleware. |
907
- | `middleware` | Whether to insert the middleware into the Rails application's middleware stack. Defaults to `true`. |
908
-
909
- ```rb
910
- # config/initializers/rodauth.rb
911
- Rodauth::Rails.configure do |config|
912
- config.app = "RodauthApp"
913
- config.middleware = true
914
- end
915
- ```
916
-
917
788
  For the list of configuration methods provided by Rodauth, see the [feature
918
789
  documentation].
919
790
 
@@ -926,7 +797,9 @@ auth class:
926
797
  ```rb
927
798
  class RodauthMain < Rodauth::Rails::Auth
928
799
  configure do
800
+ # ...
929
801
  password_match? { |password| ldap_valid?(password) }
802
+ # ...
930
803
  end
931
804
 
932
805
  # Example external identities table
@@ -1013,6 +886,172 @@ class RodauthApp < Rodauth::Rails::App
1013
886
  end
1014
887
  ```
1015
888
 
889
+ ## How it works
890
+
891
+ ### Rack middleware
892
+
893
+ The railtie inserts [`Rodauth::Rails::Middleware`](/lib/rodauth/rails/middleware.rb)
894
+ at the end of the middleware stack, which calls your Rodauth app around each request.
895
+
896
+ ```sh
897
+ $ rails middleware
898
+ # ...
899
+ # use Rodauth::Rails::Middleware
900
+ # run MyApp::Application.routes
901
+ ```
902
+
903
+ It can be inserted at any point in the middleware stack:
904
+
905
+ ```rb
906
+ Rodauth::Rails.configure do |config|
907
+ config.middleware = false # disable auto-insertion
908
+ end
909
+
910
+ Rails.application.config.middleware.insert_before AnotherMiddleware, Rodauth::Rails::Middleware
911
+ ```
912
+
913
+ The middleware retrieves the Rodauth app via `Rodauth::Rails.app`, which is
914
+ specified as a string to keep the class autoloadable and reloadable in
915
+ development.
916
+
917
+ ```rb
918
+ Rodauth::Rails.configure do |config|
919
+ config.app = "RodauthApp"
920
+ end
921
+ ```
922
+
923
+ In addition to Zeitwerk compatibility, this extra layer catches Rodauth redirects
924
+ that happen on the controller level (e.g. when calling
925
+ `rodauth.require_authentication` in a `before_action` filter).
926
+
927
+ ### Roda app
928
+
929
+ The [`Rodauth::Rails::App`](/lib/rodauth/rails/app.rb) class is a [Roda]
930
+ subclass that provides a convenience layer for Rodauth:
931
+
932
+ * uses Action Dispatch flash messages
933
+ * provides syntax sugar for loading the rodauth plugin
934
+ * saves Rodauth object(s) to Rack env hash
935
+ * propagates edited headers to Rails responses
936
+
937
+ #### Configure block
938
+
939
+ The `configure` call loads the rodauth plugin. By convention, it receives an
940
+ auth class and configuration name as positional arguments (forwarded as
941
+ `:auth_class` and `:name` plugin options), a block for anonymous auth classes,
942
+ and also accepts any additional plugin options.
943
+
944
+ ```rb
945
+ class RodauthApp < Rodauth::Rails::App
946
+ # named auth class
947
+ configure(RodauthMain)
948
+ configure(RodauthAdmin, :admin)
949
+
950
+ # anonymous auth class
951
+ configure { ... }
952
+ configure(:admin) { ... }
953
+
954
+ # plugin options
955
+ configure(RodauthMain, json: :only)
956
+ end
957
+ ```
958
+
959
+ #### Route block
960
+
961
+ The `route` block is called for each request, before it reaches the Rails
962
+ router, and it's yielded the request object.
963
+
964
+ ```rb
965
+ class RodauthApp < Rodauth::Rails::App
966
+ route do |r|
967
+ # called before each request
968
+ end
969
+ end
970
+ ```
971
+
972
+ #### Routing prefix
973
+
974
+ If you use a routing prefix, you don't need to add a call to `r.on` like with
975
+ vanilla Rodauth, as `r.rodauth` has been modified to automatically route the
976
+ prefix.
977
+
978
+ ```rb
979
+ class RodauthApp < Rodauth::Rails::App
980
+ configure do
981
+ prefix "/user"
982
+ end
983
+
984
+ route do |r|
985
+ r.rodauth # no need to wrap with `r.on("user") { ... }`
986
+ end
987
+ end
988
+ ```
989
+
990
+ ### Auth class
991
+
992
+ The [`Rodauth::Rails::Auth`](/lib/rodauth/rails/auth.rb) class is a subclass of
993
+ `Rodauth::Auth`, which preloads the `rails` rodauth feature, sets [HMAC] secret to
994
+ Rails' secret key base, and modifies some [configuration defaults](#rodauth-defaults).
995
+
996
+ ```rb
997
+ class RodauthMain < Rodauth::Rails::Auth
998
+ configure do
999
+ # authentication configuration
1000
+ end
1001
+ end
1002
+ ```
1003
+
1004
+ ### Rodauth feature
1005
+
1006
+ The [`rails`](/lib/rodauth/rails/feature.rb) Rodauth feature loaded by
1007
+ `Rodauth::Rails::Auth` provides the main part of the Rails integration for Rodauth:
1008
+
1009
+ * uses Action View for template rendering
1010
+ * uses Action Dispatch for CSRF protection
1011
+ * runs Action Controller callbacks and rescue from blocks around Rodauth requests
1012
+ * uses Action Mailer to create and deliver emails
1013
+ * uses Action Controller instrumentation around Rodauth requests
1014
+ * uses Action Mailer's default URL options when calling Rodauth outside of a request
1015
+
1016
+ ### Controller
1017
+
1018
+ The Rodauth app stores the `Rodauth::Rails::Auth` instances in the Rack env
1019
+ hash, which is then available in your Rails app:
1020
+
1021
+ ```rb
1022
+ request.env["rodauth"] #=> #<RodauthMain>
1023
+ request.env["rodauth.admin"] #=> #<RodauthAdmin> (if using multiple configurations)
1024
+ ```
1025
+
1026
+ For convenience, this object can be accessed via the `#rodauth` method in views
1027
+ and controllers:
1028
+
1029
+ ```rb
1030
+ class MyController < ApplicationController
1031
+ def my_action
1032
+ rodauth #=> #<RodauthMain>
1033
+ rodauth(:admin) #=> #<RodauthAdmin> (if using multiple configurations)
1034
+ end
1035
+ end
1036
+ ```
1037
+ ```erb
1038
+ <% rodauth #=> #<RodauthMain> %>
1039
+ <% rodauth(:admin) #=> #<RodauthAdmin> (if using multiple configurations) %>
1040
+ ```
1041
+
1042
+ ### Sequel
1043
+
1044
+ Rodauth uses the [Sequel] library for database interaction, which offers
1045
+ powerful APIs for building advanced queries (it supports SQL expressions,
1046
+ database-agnostic date arithmetic, SQL function calls).
1047
+
1048
+ If you're using Active Record in your application, the `rodauth:install`
1049
+ generator automatically configures Sequel to reuse ActiveRecord's database
1050
+ connection, using the [sequel-activerecord_connection] gem.
1051
+
1052
+ This means that, from the usage perspective, Sequel can be considered just
1053
+ as an implementation detail of Rodauth.
1054
+
1016
1055
  ## Rodauth defaults
1017
1056
 
1018
1057
  rodauth-rails changes some of the default Rodauth settings for easier setup:
@@ -12,12 +12,9 @@ class RodauthApp < Rodauth::Rails::App
12
12
  <% end -%>
13
13
  r.rodauth # route rodauth requests
14
14
 
15
- # ==> Authenticating Requests
15
+ # ==> Authenticating requests
16
16
  # Call `rodauth.require_authentication` for requests that you want to
17
- # require authentication for. Some examples:
18
- #
19
- # next if r.path.start_with?("/docs") # skip authentication for documentation pages
20
- # next if session[:admin] # skip authentication for admins
17
+ # require authentication for. For example:
21
18
  #
22
19
  # # authenticate /dashboard/* and /account/* requests
23
20
  # if r.path.start_with?("/dashboard") || r.path.start_with?("/account")
@@ -25,14 +22,6 @@ class RodauthApp < Rodauth::Rails::App
25
22
  # end
26
23
 
27
24
  # ==> Secondary configurations
28
- # r.on "admin" do
29
- # r.rodauth(:admin)
30
- #
31
- # unless rodauth(:admin).logged_in?
32
- # rodauth(:admin).require_http_basic_auth
33
- # end
34
- #
35
- # break # allow the Rails app to handle other "/admin/*" requests
36
- # end
25
+ # r.rodauth(:admin) # route admin rodauth requests
37
26
  end
38
27
  end
@@ -25,6 +25,8 @@ module Rodauth
25
25
  auth_class ||= Class.new(Rodauth::Rails::Auth)
26
26
 
27
27
  plugin :rodauth, auth_class: auth_class, name: name, csrf: false, flash: false, json: true, **options, &block
28
+
29
+ self::RodaRequest.include RequestMethods
28
30
  end
29
31
 
30
32
  before do
@@ -44,6 +46,21 @@ module Rodauth
44
46
  def self.rodauth!(name)
45
47
  rodauth(name) or fail ArgumentError, "unknown rodauth configuration: #{name.inspect}"
46
48
  end
49
+
50
+ module RequestMethods
51
+ def rodauth(name = nil)
52
+ prefix = scope.rodauth(name).prefix
53
+
54
+ if prefix.present? && remaining_path == path_info
55
+ on prefix[1..-1] do
56
+ super
57
+ break # forward other `{prefix}/*` requests to the rails router
58
+ end
59
+ else
60
+ super
61
+ end
62
+ end
63
+ end
47
64
  end
48
65
  end
49
66
  end
@@ -1,5 +1,5 @@
1
1
  module Rodauth
2
2
  module Rails
3
- VERSION = "1.0.0"
3
+ VERSION = "1.1.0"
4
4
  end
5
5
  end
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.0.0
4
+ version: 1.1.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-12-25 00:00:00.000000000 Z
11
+ date: 2022-01-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: railties