-
Notifications
You must be signed in to change notification settings - Fork 0
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
Implement authentication #67
Conversation
6f49f82
to
14a297b
Compare
Why these changes are being introduced: We will need user authentication on this app, as some features will be for authorized staff use only. Relevant ticket(s): * [TCO-29](https://mitlibraries.atlassian.net/browse/TCO-29) How this addresses that need: This adds and configures Devise, Omniauth, and the Omniauth OIDC strategy, so we can authenticate with Touchstone. Devise requires a minimal User model, to which I've added an email field and some validations. This commit does not include fake auth for local dev and PR builds. That feature will come in a subsequent commit. Side effects of this change: * The `sign_out` route is defined manually, as we are not using the `database_authenticatable` module that provides additional routes (including `destroy_user_session_path`). * This initial setup is pretty spare. We will likely need to add some more fields to the User model, and perhaps further Omniauth config as we continue to learn about Okta. * The sign-in/sign-out links are now buttons because Rails has dropped support for `method: :post`. It seems that [Turbo can replicate this behavior](https://discuss.rubyonrails.org/t/rails-7-0-4-link-to-method-post-no-longer-works/82321), but I was still seeing GET requests with Turbo. I'd still prefer to use links, but figuring out how to get them to work felt beyond the scope of this ticket.
Why these changes are being introduced: We need an easy way to bypass authentication in local dev and PR builds. Relevant ticket(s): * [TCO-29](https://mitlibraries.atlassian.net/browse/TCO-29) How this addresses that need: This implements fake auth in a similar way as we've done in ETD, using an initializer that checks the fake auth status as evaluated by a FakeAuthConfig module. Side effects of this change: We're missing an opportunity to use Keycloak for local authentication, which would better simulate the Touchstone process. That may be worth revisiting at some point.
14a297b
to
6911eca
Compare
At this point, I'm comfortable putting this into review. The test coverage drop is related to the Omniauth developer strategy details, which we also don't test in ETD. To be clear, though, I'd be happy to add coverage for any/all of what's lacking if the reviewer feels it's appropriate. |
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 one of those reviews in which there isn't really a ton of code but a heck of a lot is going on. Great job!
- OIDC via state: works as expected
- fake auth in PR build: only worked when I added
FAKE_AUTH_ENABLED=true
which is contrary to the docs (both in what variable is involved and that it doesn't need setting) - worked as advertised (no config changes, fake auth was working, users created as expected)
One test feels a bit misleading, but nothing else is blocking.
README.md
Outdated
### Optional | ||
|
||
`HEROKU_APP_NAME`: Used by the FakeAuthConfig module to determine whether an app is a PR build. |
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 isn't actually something we set right? It just shows up in PR builds and we check it and compare it to our expected PR pattern for this app. If so, I think clarifying that here so someone doesn't think they need to set this someplace would be great.
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.
Yeah, it's automatically added to PR builds. That's a good call, I'll update this to clarify.
OmniAuth.config.logger = previous_logger | ||
end | ||
|
||
test 'accessing callback without credentials redirects to signin' do |
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'm not sure this tests for what it says it tests for. It says it should be redirected to the sign in path but only confirms any 200 was received right?
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 agree, it could be clearer. We are following a redirect, but not confirming that we land anywhere in particular. I think I'll actually rewrite this to confirm that a new user isn't created.
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.
The docs imply we can actually test what the name says it is testing:
https://api.rubyonrails.org/v7.1.3.4/classes/ActionDispatch/IntegrationTest.html (i.e. that we are on a signin path?)
If not, renaming the test to say what we are testing would be great.
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 guess I'm not as concerned about the path as I am that logging in with invalid credentials doesn't create a user. So, I think renaming with some additional logic is the play here, unless you feel otherwise.
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.
Works for me
test/models/fake_auth_test.rb
Outdated
test 'fakeauth disabled' do | ||
ClimateControl.modify( | ||
FAKE_AUTH_ENABLED: 'false', | ||
HEROKU_APP_NAME: 'thesis-submit-pr-123' |
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.
Probably better to use a tacos pattern to confirm specifically that FAKE_AUTH_ENABLED
being false is enough to shut it off even if HEROKU_APP_NAME
would be allowed for these two assertions.
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.
What, you're criticizing my copypasta? 😅
test/models/fake_auth_test.rb
Outdated
end | ||
ClimateControl.modify( | ||
FAKE_AUTH_ENABLED: 'false', | ||
HEROKU_APP_NAME: 'thesis-dropbox-pr-123' |
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.
See above
# is available when needed. | ||
|
||
require "#{Rails.root}/app/models/concerns/fake_auth_config.rb" | ||
Rails.application.config.fake_auth_enabled = FakeAuthConfig.fake_auth_status |
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'm somewhat curious why we used Rails.application.config.fake_auth_enabled
instead of just calling FakeAuthConfig.fake_auth_status
throughout. I know this is an ETD pattern carried over, but I'm not currently understanding the added value fwiw.
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 does feel DRYer to me to do it in an initializer. That way, we don't have to include the module everywhere we use it. That's only in three places currently, so ymmv as to how much value it adds in practice.
One thing I did consider while copying this logic over, and am considering more seriously now, is whether we really need the FakeAuthConfig
module at all. What's the real value of using that over, say, a Flipflop feature? We basically would just need to add ENV['FAKE_AUTH_CONFIG']
(or ENV['FAKE_AUTH_ENABLED']
as it will so be named) in the pipeline and in our local dev environments, right? That doesn't feel any different from how we handle, e.g., API endpoints across multiple environments.
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.
Following some additional discussion in Slack, I think I prefer using the initializer and calling Rails.application.config.fake_auth_enabled
rather than FakeAuthConfig
for the sake of consistency and safety.
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.
Further amending my take on this. 🫠 I'm dropping the initializer due to the filenaming kludge required (i.e., it must load before the devise initializer so the config will be available there). It feels less wonky to me to require the FakeAuthConfig module where we need it.
README.md
Outdated
them. | ||
|
||
`BASE_URL`: The base url for the app. This is required for Omniauth config. | ||
`FAKE_AUTH_CONFIG`: Switches Omniauth to developer mode when set to `true`. Fake auth is also enabled whenever the |
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 believe this should be FAKE_AUTH_ENABLED
and it also reads like it is not required in PR builds, but in my testing I had to set FAKE_AUTH_ENABLED
to true in the PR build to switch the Sign In button to fake auth
@JPrevost I think the latest commit addresses all of your feedback, but let me know if I missed something. Ultimately, I decided to remove the fake auth initializer. This branch is currently deployed to staging if you'd like to confirm OIDC still works. Also, while ENV has been updated in staging, I'm waiting to update in prod until this passes review. (Saying that mostly as a note to myself do it before I merge.) |
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.
Nice. I like the refactor. Approving, but also made a suggestion on a readme update to be extremely clear that nobody should ever set that value while still explaining what it is used for.
2c15810
to
95d1b82
Compare
This adds test coverage and responds to to code review feedback for TCO-29. It includes the following changes: * Removal of the fake_auth_configuration initializer. We now evaluate fake auth using the FakeAuthConfig module directly. As part of this change, `FakeAuthConfig#fake_auth_status` has been renamed to `FakeAuthConfig#fake_auth_enabled?` and lightly refactored for clarity. * Revised documentation. * Removal of a superfluous `save` call in `OmniauthCallBacksController#developer`.
95d1b82
to
1d29f7d
Compare
@JPrevost Thanks for the detailed review! |
This adds Touchstone authentication via Devise and Omniauth, along with fake auth for local development and PR builds. The initial auth setup and the fake auth config are in separate commits for ease of review. Please check each commit message for more detailed info on the changesets.
For the time being, I've opted to use Omniauth developer mode for fake auth. We might benefit from using Keycloak in local dev to better simulate a real authentication flow, but setting that proved somewhat complicated and is probably best saved for another time. I've created a spike ticket to investigate further.
To confirm functionality:
HEROKU_APP_NAME
env.)main
.