-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Admin] Add an auth configuration that can be attached to the existing one #5214
Conversation
Codecov Report
@@ Coverage Diff @@
## nebulab/admin #5214 +/- ##
=================================================
+ Coverage 88.51% 88.55% +0.04%
=================================================
Files 596 598 +2
Lines 14511 14554 +43
=================================================
+ Hits 12844 12888 +44
+ Misses 1667 1666 -1
... and 1 file with indirect coverage changes 📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you, @elia! Having that simple configuration for authentication seems like a good approach to me 👍
This might make a lot of sense @elia! Can you please share a high-level overview of how you envision the long-term plan to separate operators and users? I understand this is just the first piece but I miss all the rest of the strategy to leave some feedback that makes sense. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for raising it now, @elia. We're at the right moment to make solidus admin authentication decoupled from the one for customers, as it'll guide us in making the right architectural decisions. I'd also like to hear about the rest of the plan when that's ready, but this is a significant first step! I left some questions.
include ActiveStorage::SetCurrent | ||
include ::SolidusAdmin::Auth | ||
include Spree::Core::ControllerHelpers::Store |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need SetCurrent
& Store
modules in this context? 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Those includes are a trimmed down version of what's included in Spree::BaseController
:
ActiveStorage::SetCurrent
is needed whenever you use AS, which is the default for images and there's no doubt we'll need to support uploadingSpree::Core::ControllerHelpers::Store
is the one providingcurrent_store
, I initially removed it, but then it would have required more than a simple helper and so I cut it short and kept it; eventually I'd be more than happy to remove it and be don with anyCore::ControllerHelpers
🙌
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I understand they'll be used, but are they needed in the context of the PR configuring authentication? 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@current_ability ||= Spree::Ability.new(spree_current_user) | ||
end | ||
|
||
def store_location |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where is this method used? 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a sad story, it's used by the solidus_auth_devise
version of Spree::Admin::BaseController.unauthorized_redirect
, usually is provided by the core Auth controller helper along with a bunch of other stuff.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see. Do you think it's worth it to drop a comment so it's clear for those reading the code?
@@ -0,0 +1,28 @@ | |||
# frozen_string_literal: true | |||
|
|||
module SolidusAdmin::BackendAuthSupport |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't we also define the spree_current_user
method? Or is it already available from somewhere else?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's coming from spree_auth_devise
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As above, do you think a comment will make things clearer?
1cde4c0
to
604af8d
Compare
def authenticate_solidus_admin_user! | ||
send SolidusAdmin::Config.authentication_method if SolidusAdmin::Config.authentication_method | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not define those methods in the included module adapter?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This file contains the adapter mechanics, providing the hooks that different adapter can use. The backend one is of course the one we need while migrating out of it, but eventually I think other will pop up (devise, maybe 3rd party single sign on, etc.) according to "the plan" in the description.
preference :authentication_method, :string, default: :authenticate_solidus_backend_user! | ||
|
||
# The method used to retrieve the current user in the admin interface. | ||
preference :current_user_method, :string, default: :spree_current_user | ||
|
||
# The path used to logout the user in the admin interface. | ||
preference :logout_link_path, :string, default: :admin_logout_path | ||
|
||
# The HTTP method used to logout the user in the admin interface. | ||
preference :logout_link_method, :string, default: :delete |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the same direction as the above comment, if we expect the adapter to define those methods, there's no need to define them in the initializer.
include ActiveStorage::SetCurrent | ||
include ::SolidusAdmin::Auth | ||
include Spree::Core::ControllerHelpers::Store |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I understand they'll be used, but are they needed in the context of the PR configuring authentication? 🤔
@elia reading the plan, I have a question. I know it's hard to predict at this stage but if you already wrapped your mind around this, what's the DX for making the switch? I imagine at some point, we will release a rake task that converts all the users that have some admin/operator roles to the other model, with the right roles assigned. That rake task should be run right before the switch of the |
I think in this regard we have an opportunity to leverage the new admin for the switch, and the old backend will still run on the spree_users table So once the apps are fully switched we'll offere a rake task for the migration and preferences, but I think for some time the core will need to still allow using the old table. That shouldn't be a big problem if everything related to admins has stopped assuming it's the same model as customers (that's probably the biggest lift). |
604af8d
to
af6b6db
Compare
b532cd9
to
ced3dd7
Compare
ced3dd7
to
a53cccf
Compare
a53cccf
to
7cce8ce
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
✅ Thanks for taking care of this @the-krg!
let(:user) { create(:admin_user, email: '[email protected]') } | ||
|
||
before do | ||
allow_any_instance_of(SolidusAdmin::BaseController).to receive(:spree_current_user).and_return(user) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think eventually we'll need a helper method for doing the sign in programmatically, but for now this is ok 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great job! 🥇
class="text-4xl" | ||
><a href="#" data-action="hello#greet">Account</a></h1> | ||
|
||
<h2 class="text-3xl underline">Your account info</h1> | ||
<p>Logged in as <%= current_solidus_admin_user.email %></p> | ||
<p><%= button_to "Log out", solidus_admin_logout_path, method: solidus_admin_logout_method, class: 'underline' %></p> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This view could be part of a new "account/show" component to be rendered (like "products/index").
Non-blocking for now, I've added a dedicated point in the list of the final things to do before the release:
Thanks, @elia & @the-krg, for working on that! This is a very nice step towards having a decoupled authentication system ❤️ I'm only left wondering if there's a benefit to the extra indirection we're adding through the option to configure the adapter method names. If the adapter is configurable, and we expect users to create those interfaces, why not fix the method names? In short, instead of: # admin/lib/solidus_admin/configuration.rb
preference :authentication_method, :string, default: :authenticate_solidus_backend_user!
preference :current_user_method, :string, default: :spree_current_user
preference :logout_link_path, :string, default: :admin_logout_path
preference :logout_link_method, :string, default: :delete
preference :authentication_adapter, :string, default: 'SolidusAdmin::AuthAdapters::Backend' We could only have the following: preference :authentication_adapter, :string, default: 'SolidusAdmin::AuthAdapters::Backend' With: # admin/app/controllers/solidus_admin/auth_adapters/backend.rb
def authentication_method
authenticate_solidus_backend_user!
end
def current_user_method
spree_current_user
end
def logout_link_path
admin_logout_path
end
def logout_link_method
:delete
end That's to say: simply require the configured module to implement the expected interface. Am I missing some context? Thoughts, @elia, @the-krg, @rainerdema? |
@waiting-for-dev that's a completely valid alternative, and that's why it made sense to pick either the configurations or the adapter (and we picked the configuration). The reason the configuration was preferred is that generally any existing authentication system won't require any adapter and will have those methods in place (one way or another). The only reason that made auth-devise need an adapter is that weird entanglement of authentication and authorization that we have. In other words we're building on the experience accrued by active-admin with the following benefits:
Hope this makes sense, but happy to answer to more questions 🙌 |
Thanks for your answer, @elia! That makes sense. To better understand real-world usage, do you have an example you can share about how other authentication systems different than devise are used in active admin? |
Yes, looking at https://www.ruby-toolbox.com/categories/rails_authentication and picking the most popular ones:
|
Thanks, @elia. I saw that the option to configure the adapter was removed altogether in another PR. I'm a bit concerned that it will require users to patch |
@waiting-for-dev I don't think we need to optimize for every possible authentication system, should be easy to use the popular ones and possible to use anything else. That said I think even for
and you can |
Summary
This PR is not intended for merging (yet)
Having the long term goal of separating the storefront customers form the admin users, would be nice to create the layer of configuration that will then allow us to replace with a different setup when the time comes.
The configuration options were inspired from the extensive experience gathered by ActiveAdmin over the years.
A default setup that taps in the existing
solidus_backend
authentication is provided and will be helpful during the transition frombackend
toadmin
. Eventuallysolidus_auth_devise
can supportsolidus_admin
directly or an alternative system can be provided.A tentative plan for the great separation ✂️
spree_orders.created_by
should accept an arbitrary admin class when created by an admin, etc.)Checklist
Check out our PR guidelines for more details.
The following are mandatory for all PRs:
The following are not always needed: