Skip to content

Commit 0730610

Browse files
jgrandjathomasdarimont
authored andcommitted
Use param matching for Authorization Response
Fixes spring-projectsgh-4576
1 parent cdbc812 commit 0730610

File tree

7 files changed

+58
-27
lines changed

7 files changed

+58
-27
lines changed

config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/AuthorizationCodeAuthenticationFilterConfigurer.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@
3636
import org.springframework.security.oauth2.core.user.OAuth2User;
3737
import org.springframework.security.oauth2.oidc.client.user.OidcUserService;
3838
import org.springframework.security.web.util.matcher.RequestMatcher;
39-
import org.springframework.security.web.util.matcher.RequestVariablesExtractor;
4039
import org.springframework.util.Assert;
4140

4241
import java.net.URI;
@@ -48,7 +47,7 @@
4847
/**
4948
* @author Joe Grandja
5049
*/
51-
final class AuthorizationCodeAuthenticationFilterConfigurer<H extends HttpSecurityBuilder<H>, R extends RequestMatcher & RequestVariablesExtractor> extends
50+
final class AuthorizationCodeAuthenticationFilterConfigurer<H extends HttpSecurityBuilder<H>, R extends RequestMatcher> extends
5251
AbstractAuthenticationFilterConfigurer<H, AuthorizationCodeAuthenticationFilterConfigurer<H, R>, AuthorizationCodeAuthenticationProcessingFilter> {
5352

5453
private R authorizationResponseMatcher;

config/src/main/java/org/springframework/security/config/annotation/web/configurers/oauth2/client/OAuth2LoginConfigurer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ public class RedirectionEndpointConfig {
166166
private RedirectionEndpointConfig() {
167167
}
168168

169-
public <R extends RequestMatcher & RequestVariablesExtractor> RedirectionEndpointConfig requestMatcher(R authorizationResponseMatcher) {
169+
public <R extends RequestMatcher> RedirectionEndpointConfig requestMatcher(R authorizationResponseMatcher) {
170170
Assert.notNull(authorizationResponseMatcher, "authorizationResponseMatcher cannot be null");
171171
OAuth2LoginConfigurer.this.authorizationCodeAuthenticationFilterConfigurer.authorizationResponseMatcher(authorizationResponseMatcher);
172172
return this;

oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/AuthorizationCodeAuthenticationProcessingFilter.java

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,7 @@
3737
import org.springframework.security.oauth2.core.endpoint.TokenResponseAttributes;
3838
import org.springframework.security.oauth2.core.user.OAuth2User;
3939
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
40-
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
4140
import org.springframework.security.web.util.matcher.RequestMatcher;
42-
import org.springframework.security.web.util.matcher.RequestVariablesExtractor;
4341
import org.springframework.util.Assert;
4442
import org.springframework.util.StringUtils;
4543

@@ -111,20 +109,18 @@
111109
*/
112110
public class AuthorizationCodeAuthenticationProcessingFilter extends AbstractAuthenticationProcessingFilter {
113111
public static final String DEFAULT_AUTHORIZATION_RESPONSE_BASE_URI = "/oauth2/authorize/code";
114-
public static final String REGISTRATION_ID_URI_VARIABLE_NAME = "registrationId";
115-
public static final String DEFAULT_AUTHORIZATION_RESPONSE_URI = DEFAULT_AUTHORIZATION_RESPONSE_BASE_URI + "/{" + REGISTRATION_ID_URI_VARIABLE_NAME + "}";
116112
private static final String AUTHORIZATION_REQUEST_NOT_FOUND_ERROR_CODE = "authorization_request_not_found";
117113
private static final String INVALID_STATE_PARAMETER_ERROR_CODE = "invalid_state_parameter";
118114
private static final String INVALID_REDIRECT_URI_PARAMETER_ERROR_CODE = "invalid_redirect_uri_parameter";
119115
private final ErrorResponseAttributesConverter errorResponseConverter = new ErrorResponseAttributesConverter();
120116
private final AuthorizationCodeAuthorizationResponseAttributesConverter authorizationCodeResponseConverter =
121117
new AuthorizationCodeAuthorizationResponseAttributesConverter();
122-
private RequestMatcher authorizationResponseMatcher = new AntPathRequestMatcher(DEFAULT_AUTHORIZATION_RESPONSE_URI);
123118
private ClientRegistrationRepository clientRegistrationRepository;
119+
private RequestMatcher authorizationResponseMatcher = new AuthorizationResponseMatcher();
124120
private AuthorizationRequestRepository authorizationRequestRepository = new HttpSessionAuthorizationRequestRepository();
125121

126122
public AuthorizationCodeAuthenticationProcessingFilter() {
127-
super(DEFAULT_AUTHORIZATION_RESPONSE_URI);
123+
super(new AuthorizationResponseMatcher());
128124
}
129125

130126
@Override
@@ -140,17 +136,8 @@ public Authentication attemptAuthentication(HttpServletRequest request, HttpServ
140136
}
141137

142138
AuthorizationRequestAttributes matchingAuthorizationRequest = this.resolveAuthorizationRequest(request);
143-
144-
String registrationId = ((RequestVariablesExtractor)this.getAuthorizationResponseMatcher())
145-
.extractUriTemplateVariables(request).get(REGISTRATION_ID_URI_VARIABLE_NAME);
146-
ClientRegistration clientRegistration = null;
147-
if (!StringUtils.isEmpty(registrationId)) {
148-
clientRegistration = this.getClientRegistrationRepository().findByRegistrationId(registrationId);
149-
}
150-
if (clientRegistration == null || !matchingAuthorizationRequest.getClientId().equals(clientRegistration.getClientId())) {
151-
OAuth2Error oauth2Error = new OAuth2Error(OAuth2Error.INVALID_REQUEST_ERROR_CODE);
152-
throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
153-
}
139+
String registrationId = (String)matchingAuthorizationRequest.getAdditionalParameters().get(OAuth2Parameter.REGISTRATION_ID);
140+
ClientRegistration clientRegistration = this.getClientRegistrationRepository().findByRegistrationId(registrationId);
154141

155142
// The clientRegistration.redirectUri may contain Uri template variables, whether it's configured by
156143
// the user or configured by default. In these cases, the redirectUri will be expanded and ultimately changed
@@ -180,7 +167,7 @@ public RequestMatcher getAuthorizationResponseMatcher() {
180167
return this.authorizationResponseMatcher;
181168
}
182169

183-
public final <T extends RequestMatcher & RequestVariablesExtractor> void setAuthorizationResponseMatcher(T authorizationResponseMatcher) {
170+
public final <T extends RequestMatcher> void setAuthorizationResponseMatcher(T authorizationResponseMatcher) {
184171
Assert.notNull(authorizationResponseMatcher, "authorizationResponseMatcher cannot be null");
185172
this.authorizationResponseMatcher = authorizationResponseMatcher;
186173
this.setRequiresAuthenticationRequestMatcher(authorizationResponseMatcher);
@@ -228,4 +215,22 @@ private void assertMatchingAuthorizationRequest(HttpServletRequest request, Auth
228215
throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
229216
}
230217
}
218+
219+
private static class AuthorizationResponseMatcher implements RequestMatcher {
220+
221+
@Override
222+
public boolean matches(HttpServletRequest request) {
223+
return this.successResponse(request) || this.errorResponse(request);
224+
}
225+
226+
private boolean successResponse(HttpServletRequest request) {
227+
return StringUtils.hasText(request.getParameter(OAuth2Parameter.CODE)) &&
228+
StringUtils.hasText(request.getParameter(OAuth2Parameter.STATE));
229+
}
230+
231+
private boolean errorResponse(HttpServletRequest request) {
232+
return StringUtils.hasText(request.getParameter(OAuth2Parameter.ERROR)) &&
233+
StringUtils.hasText(request.getParameter(OAuth2Parameter.STATE));
234+
}
235+
}
231236
}

oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/web/AuthorizationCodeRequestRedirectFilter.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import org.springframework.security.oauth2.client.registration.ClientRegistration;
2020
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
2121
import org.springframework.security.oauth2.core.endpoint.AuthorizationRequestAttributes;
22+
import org.springframework.security.oauth2.core.endpoint.OAuth2Parameter;
2223
import org.springframework.security.web.DefaultRedirectStrategy;
2324
import org.springframework.security.web.RedirectStrategy;
2425
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
@@ -122,13 +123,17 @@ protected void sendRedirectForAuthorizationCode(HttpServletRequest request, Http
122123

123124
String redirectUriStr = this.expandRedirectUri(request, clientRegistration);
124125

126+
Map<String,Object> additionalParameters = new HashMap<>();
127+
additionalParameters.put(OAuth2Parameter.REGISTRATION_ID, clientRegistration.getRegistrationId());
128+
125129
AuthorizationRequestAttributes authorizationRequestAttributes =
126130
AuthorizationRequestAttributes.withAuthorizationCode()
127131
.clientId(clientRegistration.getClientId())
128132
.authorizeUri(clientRegistration.getProviderDetails().getAuthorizationUri())
129133
.redirectUri(redirectUriStr)
130134
.scope(clientRegistration.getScope())
131135
.state(this.stateGenerator.generateKey())
136+
.additionalParameters(additionalParameters)
132137
.build();
133138

134139
this.authorizationRequestRepository.saveAuthorizationRequest(authorizationRequestAttributes, request, response);

oauth2/oauth2-client/src/test/java/org/springframework/security/oauth2/client/web/AuthorizationCodeAuthenticationProcessingFilterTests.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,8 @@
3838
import javax.servlet.FilterChain;
3939
import javax.servlet.http.HttpServletRequest;
4040
import javax.servlet.http.HttpServletResponse;
41-
42-
import static org.assertj.core.api.Assertions.assertThat;
43-
import static org.mockito.Matchers.any;
41+
import java.util.HashMap;
42+
import java.util.Map;
4443

4544
/**
4645
* Tests {@link AuthorizationCodeAuthenticationProcessingFilter}.
@@ -233,13 +232,17 @@ private void setupAuthorizationRequest(AuthorizationRequestRepository authorizat
233232
ClientRegistration clientRegistration,
234233
String state) {
235234

235+
Map<String,Object> additionalParameters = new HashMap<>();
236+
additionalParameters.put(OAuth2Parameter.REGISTRATION_ID, clientRegistration.getRegistrationId());
237+
236238
AuthorizationRequestAttributes authorizationRequestAttributes =
237239
AuthorizationRequestAttributes.withAuthorizationCode()
238240
.clientId(clientRegistration.getClientId())
239241
.authorizeUri(clientRegistration.getProviderDetails().getAuthorizationUri())
240242
.redirectUri(clientRegistration.getRedirectUri())
241243
.scope(clientRegistration.getScope())
242244
.state(state)
245+
.additionalParameters(additionalParameters)
243246
.build();
244247

245248
authorizationRequestRepository.saveAuthorizationRequest(authorizationRequestAttributes, request, response);

oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/endpoint/AuthorizationRequestAttributes.java

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@
2121

2222
import java.io.Serializable;
2323
import java.util.Collections;
24+
import java.util.LinkedHashMap;
2425
import java.util.LinkedHashSet;
26+
import java.util.Map;
2527
import java.util.Set;
2628

2729
/**
@@ -43,6 +45,7 @@ public final class AuthorizationRequestAttributes implements Serializable {
4345
private String redirectUri;
4446
private Set<String> scope;
4547
private String state;
48+
private Map<String,Object> additionalParameters;
4649

4750
private AuthorizationRequestAttributes() {
4851
}
@@ -75,6 +78,10 @@ public String getState() {
7578
return this.state;
7679
}
7780

81+
public Map<String, Object> getAdditionalParameters() {
82+
return this.additionalParameters;
83+
}
84+
7885
public static Builder withAuthorizationCode() {
7986
return new Builder(AuthorizationGrantType.AUTHORIZATION_CODE);
8087
}
@@ -107,8 +114,7 @@ public Builder redirectUri(String redirectUri) {
107114
}
108115

109116
public Builder scope(Set<String> scope) {
110-
this.authorizationRequest.scope = Collections.unmodifiableSet(
111-
CollectionUtils.isEmpty(scope) ? Collections.emptySet() : new LinkedHashSet<>(scope));
117+
this.authorizationRequest.scope = scope;
112118
return this;
113119
}
114120

@@ -117,9 +123,20 @@ public Builder state(String state) {
117123
return this;
118124
}
119125

126+
public Builder additionalParameters(Map<String,Object> additionalParameters) {
127+
this.authorizationRequest.additionalParameters = additionalParameters;
128+
return this;
129+
}
130+
120131
public AuthorizationRequestAttributes build() {
121132
Assert.hasText(this.authorizationRequest.clientId, "clientId cannot be empty");
122133
Assert.hasText(this.authorizationRequest.authorizeUri, "authorizeUri cannot be empty");
134+
this.authorizationRequest.scope = Collections.unmodifiableSet(
135+
CollectionUtils.isEmpty(this.authorizationRequest.scope) ?
136+
Collections.emptySet() : new LinkedHashSet<>(this.authorizationRequest.scope));
137+
this.authorizationRequest.additionalParameters = Collections.unmodifiableMap(
138+
CollectionUtils.isEmpty(this.authorizationRequest.additionalParameters) ?
139+
Collections.emptyMap() : new LinkedHashMap<>(this.authorizationRequest.additionalParameters));
123140
return this.authorizationRequest;
124141
}
125142
}

oauth2/oauth2-core/src/main/java/org/springframework/security/oauth2/core/endpoint/OAuth2Parameter.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
package org.springframework.security.oauth2.core.endpoint;
1717

1818
/**
19-
* Standard parameters defined in the OAuth Parameters Registry
19+
* Standard and additional (custom) parameters defined in the OAuth Parameters Registry
2020
* and used by the authorization endpoint and token endpoint.
2121
*
2222
* @author Joe Grandja
@@ -43,4 +43,6 @@ public interface OAuth2Parameter {
4343

4444
String ERROR_URI = "error_uri";
4545

46+
String REGISTRATION_ID = "registration_id"; // Non-standard additional parameter
47+
4648
}

0 commit comments

Comments
 (0)