Polish AuthorizationCodeAuthenticationFilter

Fixes gh-4599
This commit is contained in:
Joe Grandja 2017-10-10 14:39:47 -04:00
parent efa4bf409c
commit da0a7afa38
3 changed files with 56 additions and 52 deletions

View File

@ -45,7 +45,6 @@ import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.security.oauth2.oidc.client.authentication.OidcAuthorizationCodeAuthenticator; import org.springframework.security.oauth2.oidc.client.authentication.OidcAuthorizationCodeAuthenticator;
import org.springframework.security.oauth2.oidc.client.user.OidcUserService; import org.springframework.security.oauth2.oidc.client.user.OidcUserService;
import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy; import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import java.net.URI; import java.net.URI;
@ -65,13 +64,13 @@ public class AuthorizationCodeGrantConfigurer<B extends HttpSecurityBuilder<B>>
// ***** Authorization Request members // ***** Authorization Request members
private AuthorizationCodeRequestRedirectFilter authorizationRequestFilter; private AuthorizationCodeRequestRedirectFilter authorizationRequestFilter;
private String authorizationRequestBaseUri = AuthorizationCodeRequestRedirectFilter.DEFAULT_AUTHORIZATION_REQUEST_BASE_URI; private String authorizationRequestBaseUri;
private AuthorizationRequestUriBuilder authorizationRequestBuilder; private AuthorizationRequestUriBuilder authorizationRequestBuilder;
private AuthorizationRequestRepository authorizationRequestRepository; private AuthorizationRequestRepository authorizationRequestRepository;
// ***** Authorization Response members // ***** Authorization Response members
private AuthorizationCodeAuthenticationFilter authorizationResponseFilter; private AuthorizationCodeAuthenticationFilter authorizationResponseFilter;
private RequestMatcher authorizationResponseMatcher; private String authorizationResponseBaseUri;
private AuthorizationGrantAuthenticator<AuthorizationCodeAuthenticationToken> authorizationCodeAuthenticator; private AuthorizationGrantAuthenticator<AuthorizationCodeAuthenticationToken> authorizationCodeAuthenticator;
private AuthorizationGrantTokenExchanger<AuthorizationCodeAuthenticationToken> authorizationCodeTokenExchanger; private AuthorizationGrantTokenExchanger<AuthorizationCodeAuthenticationToken> authorizationCodeTokenExchanger;
private SecurityTokenRepository<AccessToken> accessTokenRepository; private SecurityTokenRepository<AccessToken> accessTokenRepository;
@ -98,9 +97,9 @@ public class AuthorizationCodeGrantConfigurer<B extends HttpSecurityBuilder<B>>
return this; return this;
} }
public AuthorizationCodeGrantConfigurer<B> authorizationResponseMatcher(RequestMatcher authorizationResponseMatcher) { public AuthorizationCodeGrantConfigurer<B> authorizationResponseBaseUri(String authorizationResponseBaseUri) {
Assert.notNull(authorizationResponseMatcher, "authorizationResponseMatcher cannot be null"); Assert.hasText(authorizationResponseBaseUri, "authorizationResponseBaseUri cannot be empty");
this.authorizationResponseMatcher = authorizationResponseMatcher; this.authorizationResponseBaseUri = authorizationResponseBaseUri;
return this; return this;
} }
@ -183,7 +182,7 @@ public class AuthorizationCodeGrantConfigurer<B extends HttpSecurityBuilder<B>>
// //
// -> AuthorizationCodeRequestRedirectFilter // -> AuthorizationCodeRequestRedirectFilter
this.authorizationRequestFilter = new AuthorizationCodeRequestRedirectFilter( this.authorizationRequestFilter = new AuthorizationCodeRequestRedirectFilter(
this.authorizationRequestBaseUri, this.getClientRegistrationRepository()); this.getAuthorizationRequestBaseUri(), this.getClientRegistrationRepository());
if (this.authorizationRequestBuilder != null) { if (this.authorizationRequestBuilder != null) {
this.authorizationRequestFilter.setAuthorizationUriBuilder(this.authorizationRequestBuilder); this.authorizationRequestFilter.setAuthorizationUriBuilder(this.authorizationRequestBuilder);
} }
@ -192,11 +191,8 @@ public class AuthorizationCodeGrantConfigurer<B extends HttpSecurityBuilder<B>>
} }
// -> AuthorizationCodeAuthenticationFilter // -> AuthorizationCodeAuthenticationFilter
this.authorizationResponseFilter = new AuthorizationCodeAuthenticationFilter(); this.authorizationResponseFilter = new AuthorizationCodeAuthenticationFilter(this.getAuthorizationResponseBaseUri());
this.authorizationResponseFilter.setClientRegistrationRepository(this.getClientRegistrationRepository()); this.authorizationResponseFilter.setClientRegistrationRepository(this.getClientRegistrationRepository());
if (this.authorizationResponseMatcher != null) {
this.authorizationResponseFilter.setAuthorizationResponseMatcher(this.authorizationResponseMatcher);
}
if (this.authorizationRequestRepository != null) { if (this.authorizationRequestRepository != null) {
this.authorizationResponseFilter.setAuthorizationRequestRepository(this.authorizationRequestRepository); this.authorizationResponseFilter.setAuthorizationRequestRepository(this.authorizationRequestRepository);
} }
@ -219,15 +215,15 @@ public class AuthorizationCodeGrantConfigurer<B extends HttpSecurityBuilder<B>>
} }
String getAuthorizationRequestBaseUri() { String getAuthorizationRequestBaseUri() {
return this.authorizationRequestBaseUri; return this.authorizationRequestBaseUri != null ?
this.authorizationRequestBaseUri :
AuthorizationCodeRequestRedirectFilter.DEFAULT_AUTHORIZATION_REQUEST_BASE_URI;
} }
AuthorizationCodeAuthenticationFilter getAuthorizationResponseFilter() { String getAuthorizationResponseBaseUri() {
return this.authorizationResponseFilter; return this.authorizationResponseBaseUri != null ?
} this.authorizationResponseBaseUri :
AuthorizationCodeAuthenticationFilter.DEFAULT_AUTHORIZATION_RESPONSE_BASE_URI;
RequestMatcher getAuthorizationResponseMatcher() {
return this.authorizationResponseMatcher;
} }
AuthorizationRequestRepository getAuthorizationRequestRepository() { AuthorizationRequestRepository getAuthorizationRequestRepository() {

View File

@ -149,9 +149,9 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>> exten
private RedirectionEndpointConfig() { private RedirectionEndpointConfig() {
} }
public RedirectionEndpointConfig requestMatcher(RequestMatcher authorizationResponseMatcher) { public RedirectionEndpointConfig baseUri(String authorizationResponseBaseUri) {
Assert.notNull(authorizationResponseMatcher, "authorizationResponseMatcher cannot be null"); Assert.hasText(authorizationResponseBaseUri, "authorizationResponseBaseUri cannot be empty");
authorizationCodeGrantConfigurer.authorizationResponseMatcher(authorizationResponseMatcher); authorizationCodeGrantConfigurer.authorizationResponseBaseUri(authorizationResponseBaseUri);
return this; return this;
} }
@ -209,9 +209,7 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>> exten
@Override @Override
protected RequestMatcher createLoginProcessingUrlMatcher(String loginProcessingUrl) { protected RequestMatcher createLoginProcessingUrlMatcher(String loginProcessingUrl) {
return (this.authorizationCodeGrantConfigurer.getAuthorizationResponseMatcher() != null ? return this.getAuthenticationFilter().getAuthorizationResponseMatcher();
this.authorizationCodeGrantConfigurer.getAuthorizationResponseMatcher() :
this.getAuthenticationFilter().getAuthorizationResponseMatcher());
} }
private ClientRegistrationRepository getClientRegistrationRepository() { private ClientRegistrationRepository getClientRegistrationRepository() {
@ -244,9 +242,11 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>> exten
} }
Map<String, String> authenticationUrlToClientName = new HashMap<>(); Map<String, String> authenticationUrlToClientName = new HashMap<>();
clientRegistrations.forEach(registration -> authenticationUrlToClientName.put( clientRegistrations.forEach(registration -> {
authorizationCodeGrantConfigurer.getAuthorizationRequestBaseUri() + "/" + registration.getRegistrationId(), authenticationUrlToClientName.put(
registration.getClientName())); authorizationCodeGrantConfigurer.getAuthorizationRequestBaseUri() + "/" + registration.getRegistrationId(),
registration.getClientName());
});
loginPageGeneratingFilter.setOauth2LoginEnabled(true); loginPageGeneratingFilter.setOauth2LoginEnabled(true);
loginPageGeneratingFilter.setOauth2AuthenticationUrlToClientName(authenticationUrlToClientName); loginPageGeneratingFilter.setOauth2AuthenticationUrlToClientName(authenticationUrlToClientName);
loginPageGeneratingFilter.setLoginPageUrl(this.getLoginPage()); loginPageGeneratingFilter.setLoginPageUrl(this.getLoginPage());
@ -261,10 +261,8 @@ public final class OAuth2LoginConfigurer<B extends HttpSecurityBuilder<B>> exten
AuthorizationCodeAuthenticationFilter authorizationResponseFilter = getAuthenticationFilter(); AuthorizationCodeAuthenticationFilter authorizationResponseFilter = getAuthenticationFilter();
authorizationResponseFilter.setClientRegistrationRepository(getClientRegistrationRepository()); authorizationResponseFilter.setClientRegistrationRepository(getClientRegistrationRepository());
if (authorizationCodeGrantConfigurer.getAuthorizationResponseMatcher() != null) { authorizationResponseFilter.setAuthorizationResponseBaseUri(
authorizationResponseFilter.setAuthorizationResponseMatcher( authorizationCodeGrantConfigurer.getAuthorizationResponseBaseUri());
authorizationCodeGrantConfigurer.getAuthorizationResponseMatcher());
}
if (authorizationCodeGrantConfigurer.getAuthorizationRequestRepository() != null) { if (authorizationCodeGrantConfigurer.getAuthorizationRequestRepository() != null) {
authorizationResponseFilter.setAuthorizationRequestRepository( authorizationResponseFilter.setAuthorizationRequestRepository(
authorizationCodeGrantConfigurer.getAuthorizationRequestRepository()); authorizationCodeGrantConfigurer.getAuthorizationRequestRepository());

View File

@ -83,30 +83,41 @@ public class AuthorizationCodeAuthenticationFilter extends AbstractAuthenticatio
public static final String DEFAULT_AUTHORIZATION_RESPONSE_BASE_URI = "/oauth2/authorize/code"; public static final String DEFAULT_AUTHORIZATION_RESPONSE_BASE_URI = "/oauth2/authorize/code";
private static final String AUTHORIZATION_REQUEST_NOT_FOUND_ERROR_CODE = "authorization_request_not_found"; private static final String AUTHORIZATION_REQUEST_NOT_FOUND_ERROR_CODE = "authorization_request_not_found";
private final AuthorizationResponseConverter authorizationResponseConverter = new AuthorizationResponseConverter(); private final AuthorizationResponseConverter authorizationResponseConverter = new AuthorizationResponseConverter();
private ClientRegistrationRepository clientRegistrationRepository;
private RequestMatcher authorizationResponseMatcher = new AuthorizationResponseMatcher();
private AuthorizationRequestRepository authorizationRequestRepository = new HttpSessionAuthorizationRequestRepository();
private final ClientRegistrationIdentifierStrategy<String> providerIdentifierStrategy = new ProviderIdentifierStrategy(); private final ClientRegistrationIdentifierStrategy<String> providerIdentifierStrategy = new ProviderIdentifierStrategy();
private RequestMatcher authorizationResponseMatcher;
private ClientRegistrationRepository clientRegistrationRepository;
private AuthorizationRequestRepository authorizationRequestRepository = new HttpSessionAuthorizationRequestRepository();
public AuthorizationCodeAuthenticationFilter() { public AuthorizationCodeAuthenticationFilter() {
super(new AuthorizationResponseMatcher()); this(DEFAULT_AUTHORIZATION_RESPONSE_BASE_URI);
}
public AuthorizationCodeAuthenticationFilter(String authorizationResponseBaseUri) {
super(new AuthorizationResponseMatcher(authorizationResponseBaseUri));
this.authorizationResponseMatcher = new AuthorizationResponseMatcher(authorizationResponseBaseUri);
}
@Override
public void afterPropertiesSet() {
super.afterPropertiesSet();
Assert.notNull(this.clientRegistrationRepository, "clientRegistrationRepository cannot be null");
} }
@Override @Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException, IOException, ServletException { throws AuthenticationException, IOException, ServletException {
AuthorizationRequest authorizationRequest = this.getAuthorizationRequestRepository().loadAuthorizationRequest(request); AuthorizationRequest authorizationRequest = this.authorizationRequestRepository.loadAuthorizationRequest(request);
if (authorizationRequest == null) { if (authorizationRequest == null) {
OAuth2Error oauth2Error = new OAuth2Error(AUTHORIZATION_REQUEST_NOT_FOUND_ERROR_CODE); OAuth2Error oauth2Error = new OAuth2Error(AUTHORIZATION_REQUEST_NOT_FOUND_ERROR_CODE);
throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString()); throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
} }
this.getAuthorizationRequestRepository().removeAuthorizationRequest(request); this.authorizationRequestRepository.removeAuthorizationRequest(request);
AuthorizationResponse authorizationResponse = this.authorizationResponseConverter.apply(request); AuthorizationResponse authorizationResponse = this.authorizationResponseConverter.apply(request);
String registrationId = (String)authorizationRequest.getAdditionalParameters().get(OAuth2Parameter.REGISTRATION_ID); String registrationId = (String)authorizationRequest.getAdditionalParameters().get(OAuth2Parameter.REGISTRATION_ID);
ClientRegistration clientRegistration = this.getClientRegistrationRepository().findByRegistrationId(registrationId); ClientRegistration clientRegistration = this.clientRegistrationRepository.findByRegistrationId(registrationId);
// The clientRegistration.redirectUri may contain Uri template variables, whether it's configured by // The clientRegistration.redirectUri may contain Uri template variables, whether it's configured by
// the user or configured by default. In these cases, the redirectUri will be expanded and ultimately changed // the user or configured by default. In these cases, the redirectUri will be expanded and ultimately changed
@ -142,18 +153,14 @@ public class AuthorizationCodeAuthenticationFilter extends AbstractAuthenticatio
return oauth2UserAuthentication; return oauth2UserAuthentication;
} }
public RequestMatcher getAuthorizationResponseMatcher() { public final RequestMatcher getAuthorizationResponseMatcher() {
return this.authorizationResponseMatcher; return this.authorizationResponseMatcher;
} }
public final <T extends RequestMatcher> void setAuthorizationResponseMatcher(T authorizationResponseMatcher) { public final void setAuthorizationResponseBaseUri(String authorizationResponseBaseUri) {
Assert.notNull(authorizationResponseMatcher, "authorizationResponseMatcher cannot be null"); Assert.hasText(authorizationResponseBaseUri, "authorizationResponseBaseUri cannot be empty");
this.authorizationResponseMatcher = authorizationResponseMatcher; this.authorizationResponseMatcher = new AuthorizationResponseMatcher(authorizationResponseBaseUri);
this.setRequiresAuthenticationRequestMatcher(authorizationResponseMatcher); this.setRequiresAuthenticationRequestMatcher(this.authorizationResponseMatcher);
}
protected ClientRegistrationRepository getClientRegistrationRepository() {
return this.clientRegistrationRepository;
} }
public final void setClientRegistrationRepository(ClientRegistrationRepository clientRegistrationRepository) { public final void setClientRegistrationRepository(ClientRegistrationRepository clientRegistrationRepository) {
@ -161,10 +168,6 @@ public class AuthorizationCodeAuthenticationFilter extends AbstractAuthenticatio
this.clientRegistrationRepository = clientRegistrationRepository; this.clientRegistrationRepository = clientRegistrationRepository;
} }
protected AuthorizationRequestRepository getAuthorizationRequestRepository() {
return this.authorizationRequestRepository;
}
public final void setAuthorizationRequestRepository(AuthorizationRequestRepository authorizationRequestRepository) { public final void setAuthorizationRequestRepository(AuthorizationRequestRepository authorizationRequestRepository) {
Assert.notNull(authorizationRequestRepository, "authorizationRequestRepository cannot be null"); Assert.notNull(authorizationRequestRepository, "authorizationRequestRepository cannot be null");
this.authorizationRequestRepository = authorizationRequestRepository; this.authorizationRequestRepository = authorizationRequestRepository;
@ -215,10 +218,17 @@ public class AuthorizationCodeAuthenticationFilter extends AbstractAuthenticatio
} }
private static class AuthorizationResponseMatcher implements RequestMatcher { private static class AuthorizationResponseMatcher implements RequestMatcher {
private final String baseUri;
private AuthorizationResponseMatcher(String baseUri) {
Assert.hasText(baseUri, "baseUri cannot be empty");
this.baseUri = baseUri;
}
@Override @Override
public boolean matches(HttpServletRequest request) { public boolean matches(HttpServletRequest request) {
return this.successResponse(request) || this.errorResponse(request); return request.getRequestURI().startsWith(this.baseUri) &&
(this.successResponse(request) || this.errorResponse(request));
} }
private boolean successResponse(HttpServletRequest request) { private boolean successResponse(HttpServletRequest request) {