-
Notifications
You must be signed in to change notification settings - Fork 6.1k
Add support for One-Time Token Authentication #15492
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
Add support for One-Time Token Authentication #15492
Conversation
92e918a
to
c70b2b2
Compare
3c46abf
to
ac04741
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.
@marcusdacoregio this looks great! I had a few minor comments for your consideration.
docs/modules/ROOT/pages/servlet/authentication/onetimetoken.adoc
Outdated
Show resolved
Hide resolved
core/src/main/java/org/springframework/security/authentication/ott/OneTimeToken.java
Outdated
Show resolved
Hide resolved
core/src/main/java/org/springframework/security/authentication/ott/OneTimeToken.java
Outdated
Show resolved
Hide resolved
...java/org/springframework/security/authentication/ott/OneTimeTokenAuthenticationProvider.java
Show resolved
Hide resolved
core/src/main/java/org/springframework/security/authentication/ott/OneTimeTokenSender.java
Outdated
Show resolved
Hide resolved
...va/org/springframework/security/web/authentication/ott/OneTimeTokenAuthenticationFilter.java
Outdated
Show resolved
Hide resolved
...springframework/security/web/authentication/ott/OneTimeTokenAuthenticationRequestFilter.java
Outdated
Show resolved
Hide resolved
...ringframework/security/web/authentication/ott/OneTimeTokenAuthenticationRequestResolver.java
Outdated
Show resolved
Hide resolved
ac04741
to
74dcab3
Compare
...ig/src/main/java/org/springframework/security/config/annotation/web/HttpSecurityBuilder.java
Outdated
Show resolved
Hide resolved
fdb949c
to
dfbe909
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.
This is so cool, @marcusdacoregio! I've left my feedback inline.
// ... | ||
.formLogin(Customizer.withDefaults()) | ||
.oneTimeTokenLogin((ott) -> ott | ||
.showSubmitPage(false) |
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 wonder if this would benefit from a more complete example, given that they will need to allow /my-ott-submit
in authorizeHttpRequests
. Also, a statement that this doesn't change the POST location.
...ingframework/security/config/annotation/web/configurers/ott/OneTimeTokenLoginConfigurer.java
Outdated
Show resolved
Hide resolved
core/src/main/java/org/springframework/security/authentication/ott/DefaultOneTimeToken.java
Outdated
Show resolved
Hide resolved
* configured. | ||
* @param show | ||
*/ | ||
public OneTimeTokenLoginConfigurer<H> showSubmitPage(boolean show) { |
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'd probably call this generateSubmitPage
or maybe showGeneratedSubmitPage
(or showDefaultSubmitPage
)
* Defaults to {@code POST /ott/generate}. | ||
* @param generateUrl | ||
*/ | ||
public OneTimeTokenLoginConfigurer<H> generateUrl(String generateUrl) { |
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 this could benefit from being called authenticationRequestUrl
since it's conceptually similar to OAuth and SAML RP-initiated flows.
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.
Also, it feels odd to me that we'd depart from referring to this as an "authentication request", but then not depart from "loginProcessingUrl". Either they should both be contextual to this auth mechanism (generateTokenUrl
and tokenProcessingUrl
) or they should both align with other auth mechs (authenticationRequestUrl
and loginProcessingUrl
).
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'd prefer to use naming that matches OTT rather than borrowing from other stack's terminology. The URL is not an authentication request. It requests generating a OTT and maps to OneTimeTokenService.generate, so I prefer this name.
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 that case, I think the PR would improve by consistently avoid referring to it as an authentication request. Some examples are:
- https://github.com/spring-projects/spring-security/pull/15492/files#diff-1f0c1f3e21d89097244c3e1d1d6fda15448f2ca10f53081f9ef8273321e60dbdR75
- https://github.com/spring-projects/spring-security/pull/15492/files#diff-0b1250656907699f84f5b819dbcd30e0e57fb930de8229a312ef63da9384b907R148
- https://github.com/spring-projects/spring-security/pull/15492/files#diff-59ed948eb5454b069306a935d9612e90ba45a32bec4df90eb2f2f08771f73707R69
- https://github.com/spring-projects/spring-security/pull/15492/files#diff-59ed948eb5454b069306a935d9612e90ba45a32bec4df90eb2f2f08771f73707R94
- https://github.com/spring-projects/spring-security/pull/15492/files#diff-fb7008c7001c4e4909c65029da8c59d1012cbdd08ea44dd0d514d85e99031a5eR161
Most of these are minor cleanups except for the last one, and so I've bolded it.
I think the conversation about using OTT terminology for loginProcessingUrl
is still a good one to have.
...ingframework/security/config/annotation/web/configurers/ott/OneTimeTokenLoginConfigurer.java
Outdated
Show resolved
Hide resolved
* Defaults to {@code POST /ott/generate}. | ||
* @param generateUrl | ||
*/ | ||
public OneTimeTokenLoginConfigurer<H> generateUrl(String generateUrl) { |
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'd prefer to use naming that matches OTT rather than borrowing from other stack's terminology. The URL is not an authentication request. It requests generating a OTT and maps to OneTimeTokenService.generate, so I prefer this name.
...c/main/java/org/springframework/security/authentication/ott/OneTimeTokenGenerateRequest.java
Outdated
Show resolved
Hide resolved
...org/springframework/security/web/authentication/ott/OneTimeTokenAuthenticationConverter.java
Outdated
Show resolved
Hide resolved
...ain/java/org/springframework/security/web/authentication/ott/OneTimeTokenGenerateFilter.java
Outdated
Show resolved
Hide resolved
...org/springframework/security/web/authentication/ott/OneTimeTokenGenerateRequestResolver.java
Outdated
Show resolved
Hide resolved
* @author Marcus da Coregio | ||
* @since 6.4 | ||
*/ | ||
public final class RedirectGeneratedOneTimeTokenSuccessHandler implements GeneratedOneTimeTokenSuccessHandler { |
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 how useful this is since nothing is done with the OneTimeToken. How would the user receive the token to consume it?
Perhaps a more useful implementation would be to set the OneTimeToken on a request attribute and then forward to a new URL. We could provide Spring MVC argument resolver to resolve the token to simplify processing this in Spring. I think all of this could be done in a future iteration.
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 about a forward tho. If we forward from POST /ott/generate
to /login/ott
it will be a POST
request, not a GET
, I'm not sure how useful that is. Maybe the default implementation could store the OneTimeToken
in the session and then redirect to the 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.
I think that the location that receives OTT would be in charge of doing something with it (e.g. sending it in an email, sending in a text message, placing it in session, etc) and then it would redirect to a new URL for the success page.
I'd like to reiterate that this can be done in a future iteration and does not need to be done now.
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.
Sure, we can continue the discussion on #15697
* @author Marcus da Coregio | ||
* @since 6.4 | ||
*/ | ||
public final class RequestParameterOneTimeTokenGenerateRequestResolver implements OneTimeTokenGenerateRequestResolver { |
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.
Like the corresponding interface, I'm not sure that this is needed today.
...gframework/security/web/authentication/ui/DefaultOneTimeTokenSubmitPageGeneratingFilter.java
Outdated
Show resolved
Hide resolved
...gframework/security/web/authentication/ui/DefaultOneTimeTokenSubmitPageGeneratingFilter.java
Outdated
Show resolved
Hide resolved
...gframework/security/web/authentication/ui/DefaultOneTimeTokenSubmitPageGeneratingFilter.java
Outdated
Show resolved
Hide resolved
dfbe909
to
f98f133
Compare
bd30072
to
2d33d68
Compare
2d33d68
to
28485be
Compare
Run
./gradlew publishToMavenLocal
and try the Magic Link sample: https://github.com/marcusdacoregio/passwordless-spring-security