Skip to content

Commit ee9c8e2

Browse files
sjohnrSteve Riesenberg
authored and
Steve Riesenberg
committed
Store one request by default in WebSessionOAuth2ServerAuthorizationRequestRepository
Related to gh-9649 Closes gh-9857
1 parent e16b88c commit ee9c8e2

4 files changed

+498
-181
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -34,6 +34,7 @@
3434
* {@link OAuth2AuthorizationRequest} in the {@code WebSession}.
3535
*
3636
* @author Rob Winch
37+
* @author Steve Riesenberg
3738
* @since 5.1
3839
* @see AuthorizationRequestRepository
3940
* @see OAuth2AuthorizationRequest
@@ -46,24 +47,42 @@ public final class WebSessionOAuth2ServerAuthorizationRequestRepository
4647

4748
private final String sessionAttributeName = DEFAULT_AUTHORIZATION_REQUEST_ATTR_NAME;
4849

50+
private boolean allowMultipleAuthorizationRequests;
51+
4952
@Override
5053
public Mono<OAuth2AuthorizationRequest> loadAuthorizationRequest(
5154
ServerWebExchange exchange) {
5255
String state = getStateParameter(exchange);
5356
if (state == null) {
5457
return Mono.empty();
5558
}
56-
return getStateToAuthorizationRequest(exchange)
57-
.filter(stateToAuthorizationRequest -> stateToAuthorizationRequest.containsKey(state))
58-
.map(stateToAuthorizationRequest -> stateToAuthorizationRequest.get(state));
59+
// @formatter:off
60+
return this.getSessionAttributes(exchange)
61+
.filter((sessionAttrs) -> sessionAttrs.containsKey(this.sessionAttributeName))
62+
.map(this::getAuthorizationRequests)
63+
.filter((stateToAuthorizationRequest) -> stateToAuthorizationRequest.containsKey(state))
64+
.map((stateToAuthorizationRequest) -> stateToAuthorizationRequest.get(state));
65+
// @formatter:on
5966
}
6067

6168
@Override
6269
public Mono<Void> saveAuthorizationRequest(
6370
OAuth2AuthorizationRequest authorizationRequest, ServerWebExchange exchange) {
6471
Assert.notNull(authorizationRequest, "authorizationRequest cannot be null");
65-
return saveStateToAuthorizationRequest(exchange)
66-
.doOnNext(stateToAuthorizationRequest -> stateToAuthorizationRequest.put(authorizationRequest.getState(), authorizationRequest))
72+
Assert.notNull(exchange, "exchange cannot be null");
73+
// @formatter:off
74+
return getSessionAttributes(exchange)
75+
.doOnNext((sessionAttrs) -> {
76+
if (this.allowMultipleAuthorizationRequests) {
77+
Map<String, OAuth2AuthorizationRequest> authorizationRequests = this.getAuthorizationRequests(
78+
sessionAttrs);
79+
authorizationRequests.put(authorizationRequest.getState(), authorizationRequest);
80+
sessionAttrs.put(this.sessionAttributeName, authorizationRequests);
81+
}
82+
else {
83+
sessionAttrs.put(this.sessionAttributeName, authorizationRequest);
84+
}
85+
})
6786
.then();
6887
}
6988

@@ -74,27 +93,24 @@ public Mono<OAuth2AuthorizationRequest> removeAuthorizationRequest(
7493
if (state == null) {
7594
return Mono.empty();
7695
}
77-
return exchange.getSession()
78-
.map(WebSession::getAttributes)
79-
.handle((sessionAttrs, sink) -> {
80-
Map<String, OAuth2AuthorizationRequest> stateToAuthzRequest = sessionAttrsMapStateToAuthorizationRequest(sessionAttrs);
81-
if (stateToAuthzRequest == null) {
82-
sink.complete();
83-
return;
84-
}
85-
OAuth2AuthorizationRequest removedValue = stateToAuthzRequest.remove(state);
86-
if (stateToAuthzRequest.isEmpty()) {
87-
sessionAttrs.remove(this.sessionAttributeName);
88-
} else if (removedValue != null) {
89-
// gh-7327 Overwrite the existing Map to ensure the state is saved for distributed sessions
90-
sessionAttrs.put(this.sessionAttributeName, stateToAuthzRequest);
91-
}
92-
if (removedValue == null) {
93-
sink.complete();
94-
} else {
95-
sink.next(removedValue);
96-
}
97-
});
96+
// @formatter:off
97+
return getSessionAttributes(exchange)
98+
.flatMap((sessionAttrs) -> {
99+
Map<String, OAuth2AuthorizationRequest> authorizationRequests = this.getAuthorizationRequests(
100+
sessionAttrs);
101+
OAuth2AuthorizationRequest originalRequest = authorizationRequests.remove(state);
102+
if (authorizationRequests.isEmpty()) {
103+
sessionAttrs.remove(this.sessionAttributeName);
104+
}
105+
else if (authorizationRequests.size() == 1) {
106+
sessionAttrs.put(this.sessionAttributeName, authorizationRequests.values().iterator().next());
107+
}
108+
else {
109+
sessionAttrs.put(this.sessionAttributeName, authorizationRequests);
110+
}
111+
return Mono.justOrEmpty(originalRequest);
112+
});
113+
// @formatter:on
98114
}
99115

100116
/**
@@ -111,31 +127,40 @@ private Mono<Map<String, Object>> getSessionAttributes(ServerWebExchange exchang
111127
return exchange.getSession().map(WebSession::getAttributes);
112128
}
113129

114-
private Mono<Map<String, OAuth2AuthorizationRequest>> getStateToAuthorizationRequest(ServerWebExchange exchange) {
115-
Assert.notNull(exchange, "exchange cannot be null");
116-
117-
return getSessionAttributes(exchange)
118-
.flatMap(sessionAttrs -> Mono.justOrEmpty(this.sessionAttrsMapStateToAuthorizationRequest(sessionAttrs)));
119-
}
120-
121-
private Mono<Map<String, OAuth2AuthorizationRequest>> saveStateToAuthorizationRequest(ServerWebExchange exchange) {
122-
Assert.notNull(exchange, "exchange cannot be null");
123-
124-
return getSessionAttributes(exchange)
125-
.doOnNext(sessionAttrs -> {
126-
Object stateToAuthzRequest = sessionAttrs.get(this.sessionAttributeName);
127-
128-
if (stateToAuthzRequest == null) {
129-
stateToAuthzRequest = new HashMap<String, OAuth2AuthorizationRequest>();
130-
}
131-
132-
// No matter stateToAuthzRequest was in session or not, we should always put it into session again
133-
// in case of redis or hazelcast session. #6215
134-
sessionAttrs.put(this.sessionAttributeName, stateToAuthzRequest);
135-
}).flatMap(sessionAttrs -> Mono.justOrEmpty(this.sessionAttrsMapStateToAuthorizationRequest(sessionAttrs)));
130+
private Map<String, OAuth2AuthorizationRequest> getAuthorizationRequests(Map<String, Object> sessionAttrs) {
131+
Object sessionAttributeValue = sessionAttrs.get(this.sessionAttributeName);
132+
if (sessionAttributeValue == null) {
133+
return new HashMap<>();
134+
}
135+
else if (sessionAttributeValue instanceof OAuth2AuthorizationRequest) {
136+
OAuth2AuthorizationRequest oauth2AuthorizationRequest = (OAuth2AuthorizationRequest) sessionAttributeValue;
137+
Map<String, OAuth2AuthorizationRequest> authorizationRequests = new HashMap<>(1);
138+
authorizationRequests.put(oauth2AuthorizationRequest.getState(), oauth2AuthorizationRequest);
139+
return authorizationRequests;
140+
}
141+
else if (sessionAttributeValue instanceof Map) {
142+
@SuppressWarnings("unchecked")
143+
Map<String, OAuth2AuthorizationRequest> authorizationRequests = (Map<String, OAuth2AuthorizationRequest>) sessionAttrs
144+
.get(this.sessionAttributeName);
145+
return authorizationRequests;
146+
}
147+
else {
148+
throw new IllegalStateException(
149+
"authorizationRequests is supposed to be a Map or OAuth2AuthorizationRequest but actually is a "
150+
+ sessionAttributeValue.getClass());
151+
}
136152
}
137153

138-
private Map<String, OAuth2AuthorizationRequest> sessionAttrsMapStateToAuthorizationRequest(Map<String, Object> sessionAttrs) {
139-
return (Map<String, OAuth2AuthorizationRequest>) sessionAttrs.get(this.sessionAttributeName);
154+
/**
155+
* Configure if multiple {@link OAuth2AuthorizationRequest}s should be stored per
156+
* session. Default is false (not allow multiple {@link OAuth2AuthorizationRequest}
157+
* per session).
158+
* @param allowMultipleAuthorizationRequests true allows more than one
159+
* {@link OAuth2AuthorizationRequest} to be stored per session.
160+
* @since 5.5
161+
*/
162+
@Deprecated
163+
public void setAllowMultipleAuthorizationRequests(boolean allowMultipleAuthorizationRequests) {
164+
this.allowMultipleAuthorizationRequests = allowMultipleAuthorizationRequests;
140165
}
141166
}

0 commit comments

Comments
 (0)