-
Notifications
You must be signed in to change notification settings - Fork 6k
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
Expire OAuth2AuthorizationRequest when saving to the session #9513
Expire OAuth2AuthorizationRequest when saving to the session #9513
Conversation
dd27350
to
9d3429f
Compare
045afac
to
ffcb332
Compare
ffcb332
to
58fb623
Compare
@jgrandja can you please take a look at this PR? |
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 the PR @candrews ! Please see review comments.
...ingframework/security/oauth2/client/web/HttpSessionOAuth2AuthorizationRequestRepository.java
Outdated
Show resolved
Hide resolved
...ingframework/security/oauth2/client/web/HttpSessionOAuth2AuthorizationRequestRepository.java
Outdated
Show resolved
Hide resolved
...ingframework/security/oauth2/client/web/HttpSessionOAuth2AuthorizationRequestRepository.java
Outdated
Show resolved
Hide resolved
...ingframework/security/oauth2/client/web/HttpSessionOAuth2AuthorizationRequestRepository.java
Outdated
Show resolved
Hide resolved
...ingframework/security/oauth2/client/web/HttpSessionOAuth2AuthorizationRequestRepository.java
Outdated
Show resolved
Hide resolved
...amework/security/oauth2/client/web/HttpSessionOAuth2AuthorizationRequestRepositoryTests.java
Outdated
Show resolved
Hide resolved
...amework/security/oauth2/client/web/HttpSessionOAuth2AuthorizationRequestRepositoryTests.java
Show resolved
Hide resolved
...ingframework/security/oauth2/client/web/HttpSessionOAuth2AuthorizationRequestRepository.java
Show resolved
Hide resolved
...ingframework/security/oauth2/client/web/HttpSessionOAuth2AuthorizationRequestRepository.java
Outdated
Show resolved
Hide resolved
...ingframework/security/oauth2/client/web/HttpSessionOAuth2AuthorizationRequestRepository.java
Outdated
Show resolved
Hide resolved
I've addressed feedback in a fixup commit I added. I'm assuming that the commits will be squashed when the PR is merged. Thank you for your review! |
@jgrandja Is there anything else you'd like me to do? Thanks again |
I've updated this PR to also set a maximum number of @jgrandja can you please take a peek? |
@candrews Thanks. I will look at this shortly. |
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 the updates @candrews. Please see review comments.
...ingframework/security/oauth2/client/web/HttpSessionOAuth2AuthorizationRequestRepository.java
Outdated
Show resolved
Hide resolved
...ingframework/security/oauth2/client/web/HttpSessionOAuth2AuthorizationRequestRepository.java
Outdated
Show resolved
Hide resolved
* @param clock the clock | ||
* @since 5.5 | ||
*/ | ||
void setClock(Clock clock) { |
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.
Please remove this as it's not needed. The clock will always be in sync since this implementation operates independently within it's own application instance. Clock and clock skew is needed when components are interacting in a distributed way.
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 method is package private, so nothing other than Spring itself should be using it.
Being able to set the clock is important for testing. See https://github.com/candrews/spring-security/blob/9b1a85d992f3ac0d725f67ac03ee6d9f44659b21/oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/HttpSessionOAuth2AuthorizationRequestRepositoryTests.java#L249
Is there another approach that should be taken to make the clock available to be set by tests?
* attempt is made to save another one, then the oldest will be removed. | ||
* @param maxActiveAuthorizationRequests must not be negative. | ||
*/ | ||
public void setMaxActiveAuthorizationRequestsPerSession(int maxActiveAuthorizationRequestsPerSession) { |
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.
Can you explain the specific use case why this is needed?
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 possible to easily put a lot of OAuth2AuthorizationRequest
s in this map, resulting in Bad Things ™️ happening. This limit prevents that from being possible.
I contacted security@pivotal.io with the details. Let me know if I should post them here.
...ingframework/security/oauth2/client/web/HttpSessionOAuth2AuthorizationRequestRepository.java
Outdated
Show resolved
Hide resolved
1a5cf56
to
5f98510
Compare
How's this looking now? |
@candrews I've been giving this enhancement some further thought and I would prefer to keep this a patch change. Something about Furthermore, I'm not sure how much these configuration-related settings will be used given that gh-5145 did not receive any upvotes and the issue is now over 3 years old.
Can you provide me more details on your use case and why you need this enhancement? |
I'm happy to change those methods to be package visible (so they can be used by tests, unless you have a better approach for changing them to facilitating testing) instead of public. I don't really care if they're configurable, and as you said, I doubt anyone else would either.
I don't care about the configurability of the expiration or size parameters, but I do think having these limits is very important. As it stands now, Spring Security sets no limits, allowing the map to grow boundlessly. As @rwinch says:
I'm trying to not give away too much; having this map grow boundlessly is a real significant problem. If you'd like me to give the specifics, let me know and I will. |
Change setMaxActiveAuthorizationRequestsPerSession and setAuthorizationRequestTimeToLive to be package visible, not public.
No, I'm good. I got the message and much appreciated. I have another idea brewing for this patch. Let me think it over a bit. I'll get back to you by end of day tomorrow the latest. |
@candrews Here is a template for the solution. I've added implementation notes but let me know if you have any questions. /*
* 1) OAuth2AuthorizationRequest's are stored as Map<String, OAuth2AuthorizationRequestWrapper>, keyed by getState()
* 2) When saveAuthorizationRequest(), constrain limit by grouping by OAuth2AuthorizationRequestWrapper.getRegistrationId().
* For example, if there are 3 existing `google-registration-id` then reject the save by throwing IllegalStateException.
* I think constraining to 3 for the limit-based strategy is ok?
* 3) When loadAuthorizationRequest(), remove all isExpired() before returning the Map
*/
private static class OAuth2AuthorizationRequestWrapper implements Serializable {
private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
private static final Duration DEFAULT_TIME_TO_LIVE = Duration.ofMinutes(5);
private final OAuth2AuthorizationRequest authorizationRequest;
private final Instant createdAt;
private final Instant expiresAt;
private OAuth2AuthorizationRequestWrapper(OAuth2AuthorizationRequest authorizationRequest) {
this.authorizationRequest = authorizationRequest;
this.createdAt = Instant.now();
// I think 5 minutes is long enough to allow for the authorization (consent) flow to complete?
this.expiresAt = this.createdAt.plus(DEFAULT_TIME_TO_LIVE);
}
private OAuth2AuthorizationRequest getAuthorizationRequest() {
return this.authorizationRequest;
}
private String getRegistrationId() {
return this.authorizationRequest.getAttribute(OAuth2ParameterNames.REGISTRATION_ID);
}
private String getState() {
return this.authorizationRequest.getState();
}
private boolean isExpired() {
// NOTE:
// Given that Instant.now() uses the system clock and
// createdAt and expiresAt is instantiated by the same system clock,
// there is no need for a configurable Clock or any clock skew adjustment
return Instant.now().isAfter(this.expiresAt);
}
} |
That's already in place. Based on earlier feedback, the class is named
If we throw Perhaps instead of throwing I've just made that change and pushed the commit for it.
Already done. I kept Also, the commit history is getting excessive. Would you like me to squash all the commits and force push update this PR? |
9cd5e3b
to
5f720ff
Compare
Closes gh-5145
This straightforward approach cleans up expired
OAuth2AuthorizationRequest
s as they're loaded (and subsequently saved) to the session. It's basically the same approach as #7381 but storing creation instead of expiration and using a wrapper class instead of modifyingOAuth2AuthorizationRequest
.This approach introduces no new dependencies or requirements (such as Spring Cache abstraction).
From #7381 (review)
For
HttpSessionOAuth2AuthorizationRequestRepository
, I don't believe that could work because the session can only be loaded and saved while the request for it is being processed. In other words, the task that runs at the scheduled itme would not be able to callloadAuthorizationRequest()
and get the data back, nor would it be able to callremoveAuthorizationRequest
to write it. Even if it could call those methods, they wouldn't work right; session persistence is handed by servlet filters (see Spring Session) and those filters wouldn't be intercepting session use to handle persistence outside of a request.It make sense to create a new implementation of the
AuthorizationRequestRepository<OAuth2AuthorizationRequest>
interface at some point which uses a database or Spring Cache abstraction for persistence, as that would allow for expiration to run as a scheduled job. However, that's not of interest to me at the moment :)