mirror of https://github.com/halo-dev/halo
chore: cleanup deprecated class (#1859)
parent
f1ccccb557
commit
8ac819ad14
|
@ -7,7 +7,7 @@ import org.springframework.util.Assert;
|
|||
* A facility for holding information associated to a specific context.
|
||||
*
|
||||
* @author guqing
|
||||
* @date 2022-04-14
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public interface Context {
|
||||
/**
|
||||
|
|
|
@ -8,7 +8,7 @@ import org.springframework.util.Assert;
|
|||
* Default implementation of {@link OAuth2TokenContext}.
|
||||
*
|
||||
* @author guqing
|
||||
* @date 2022-04-14
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public record DefaultOAuth2TokenContext(Map<Object, Object> context) implements OAuth2TokenContext {
|
||||
public DefaultOAuth2TokenContext {
|
||||
|
|
|
@ -1,153 +0,0 @@
|
|||
package run.halo.app.identity.authentication;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.Map;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.http.server.ServletServerHttpResponse;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.AuthenticationServiceException;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
||||
import org.springframework.security.oauth2.core.OAuth2AccessToken;
|
||||
import org.springframework.security.oauth2.core.OAuth2Error;
|
||||
import org.springframework.security.oauth2.core.OAuth2RefreshToken;
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
||||
import org.springframework.security.oauth2.core.http.converter.OAuth2AccessTokenResponseHttpMessageConverter;
|
||||
import org.springframework.security.oauth2.core.http.converter.OAuth2ErrorHttpMessageConverter;
|
||||
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Processes an authentication client request. Called
|
||||
* {@code AuthenticationProcessingFilter} prior to Spring Security 3.0.
|
||||
* <p>
|
||||
* Request parameter must present two parameters to this filter: a username and password. The
|
||||
* default parameter names to use are contained in the static fields
|
||||
* {@link #SPRING_SECURITY_FORM_USERNAME_KEY} and
|
||||
* {@link #SPRING_SECURITY_FORM_PASSWORD_KEY}. The parameter names can also be changed by
|
||||
* setting the {@code usernameParameter} and {@code passwordParameter} properties.
|
||||
* <p>
|
||||
* This filter by default responds to the URL {@code /api/v1/oauth2/login}.
|
||||
*
|
||||
* @author guqing
|
||||
* @see UsernamePasswordAuthenticationFilter
|
||||
* @see AbstractAuthenticationProcessingFilter
|
||||
* @see OAuth2AccessTokenAuthenticationToken
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public class JwtUsernamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
|
||||
/**
|
||||
* The default endpoint {@code URI} for access token requests.
|
||||
*/
|
||||
private static final String DEFAULT_TOKEN_ENDPOINT_URI = "/api/v1/oauth2/token";
|
||||
private final HttpMessageConverter<OAuth2AccessTokenResponse> accessTokenHttpResponseConverter =
|
||||
new OAuth2AccessTokenResponseHttpMessageConverter();
|
||||
private final HttpMessageConverter<OAuth2Error> errorHttpResponseConverter =
|
||||
new OAuth2ErrorHttpMessageConverter();
|
||||
|
||||
private boolean postOnly = true;
|
||||
|
||||
public JwtUsernamePasswordAuthenticationFilter() {
|
||||
this(DEFAULT_TOKEN_ENDPOINT_URI, null);
|
||||
}
|
||||
|
||||
public JwtUsernamePasswordAuthenticationFilter(String defaultFilterProcessesUrl) {
|
||||
this(defaultFilterProcessesUrl, null);
|
||||
}
|
||||
|
||||
public JwtUsernamePasswordAuthenticationFilter(AuthenticationManager authenticationManager) {
|
||||
this(DEFAULT_TOKEN_ENDPOINT_URI, authenticationManager);
|
||||
}
|
||||
|
||||
public JwtUsernamePasswordAuthenticationFilter(String defaultFilterProcessesUrl,
|
||||
AuthenticationManager authenticationManager) {
|
||||
super(authenticationManager);
|
||||
if (!StringUtils.hasText(defaultFilterProcessesUrl)) {
|
||||
throw new IllegalArgumentException("tokenEndpointUri cannot be empty.");
|
||||
}
|
||||
setFilterProcessesUrl(defaultFilterProcessesUrl);
|
||||
setAuthenticationSuccessHandler(this::sendAccessTokenResponse);
|
||||
setAuthenticationFailureHandler(this::sendErrorResponse);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Authentication attemptAuthentication(HttpServletRequest request,
|
||||
HttpServletResponse response)
|
||||
throws AuthenticationException {
|
||||
|
||||
if (this.postOnly && !HttpMethod.POST.name().equals(request.getMethod())) {
|
||||
throw new AuthenticationServiceException(
|
||||
"Authentication method not supported: " + request.getMethod());
|
||||
}
|
||||
String grantType = request.getParameter(OAuth2ParameterNames.GRANT_TYPE);
|
||||
if (!AuthorizationGrantType.PASSWORD.getValue().equals(grantType)) {
|
||||
return null;
|
||||
}
|
||||
String username = obtainUsername(request);
|
||||
username = (username != null) ? username : "";
|
||||
username = username.trim();
|
||||
String password = obtainPassword(request);
|
||||
password = (password != null) ? password : "";
|
||||
UsernamePasswordAuthenticationToken authRequest =
|
||||
new UsernamePasswordAuthenticationToken(username, password);
|
||||
// Allow subclasses to set the "details" property
|
||||
setDetails(request, authRequest);
|
||||
return this.getAuthenticationManager().authenticate(authRequest);
|
||||
}
|
||||
|
||||
private void sendAccessTokenResponse(HttpServletRequest request, HttpServletResponse response,
|
||||
Authentication authentication) throws IOException {
|
||||
|
||||
OAuth2AccessTokenAuthenticationToken accessTokenAuthentication =
|
||||
(OAuth2AccessTokenAuthenticationToken) authentication;
|
||||
|
||||
OAuth2AccessToken accessToken = accessTokenAuthentication.getAccessToken();
|
||||
OAuth2RefreshToken refreshToken = accessTokenAuthentication.getRefreshToken();
|
||||
Map<String, Object> additionalParameters =
|
||||
accessTokenAuthentication.getAdditionalParameters();
|
||||
|
||||
OAuth2AccessTokenResponse.Builder builder =
|
||||
OAuth2AccessTokenResponse.withToken(accessToken.getTokenValue())
|
||||
.tokenType(accessToken.getTokenType())
|
||||
.scopes(accessToken.getScopes());
|
||||
if (accessToken.getIssuedAt() != null && accessToken.getExpiresAt() != null) {
|
||||
builder.expiresIn(
|
||||
ChronoUnit.SECONDS.between(accessToken.getIssuedAt(), accessToken.getExpiresAt()));
|
||||
}
|
||||
if (refreshToken != null) {
|
||||
builder.refreshToken(refreshToken.getTokenValue());
|
||||
}
|
||||
if (!CollectionUtils.isEmpty(additionalParameters)) {
|
||||
builder.additionalParameters(additionalParameters);
|
||||
}
|
||||
OAuth2AccessTokenResponse accessTokenResponse = builder.build();
|
||||
ServletServerHttpResponse httpResponse = new ServletServerHttpResponse(response);
|
||||
this.accessTokenHttpResponseConverter.write(accessTokenResponse, null, httpResponse);
|
||||
}
|
||||
|
||||
private void sendErrorResponse(HttpServletRequest request, HttpServletResponse response,
|
||||
AuthenticationException exception) throws IOException {
|
||||
|
||||
//OAuth2Error error = ((AuthenticationServiceException) exception).getMessage();
|
||||
ServletServerHttpResponse httpResponse = new ServletServerHttpResponse(response);
|
||||
httpResponse.setStatusCode(HttpStatus.BAD_REQUEST);
|
||||
this.errorHttpResponseConverter.write(new OAuth2Error(exception.getMessage()), null,
|
||||
httpResponse);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPostOnly(boolean postOnly) {
|
||||
this.postOnly = postOnly;
|
||||
super.setPostOnly(postOnly);
|
||||
}
|
||||
}
|
|
@ -28,8 +28,6 @@ import org.springframework.util.StringUtils;
|
|||
* @since 2.0.0
|
||||
*/
|
||||
public class OAuth2RefreshTokenAuthenticationConverter implements AuthenticationConverter {
|
||||
static final String ACCESS_TOKEN_REQUEST_ERROR_URI =
|
||||
"https://datatracker.ietf.org/doc/html/rfc6749#section-5.2";
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
|
@ -48,7 +46,7 @@ public class OAuth2RefreshTokenAuthenticationConverter implements Authentication
|
|||
|| parameters.get(OAuth2ParameterNames.REFRESH_TOKEN).size() != 1) {
|
||||
OAuth2EndpointUtils.throwError(OAuth2ErrorCodes.INVALID_REQUEST,
|
||||
OAuth2ParameterNames.REFRESH_TOKEN,
|
||||
ACCESS_TOKEN_REQUEST_ERROR_URI);
|
||||
OAuth2EndpointUtils.ERROR_URI);
|
||||
}
|
||||
|
||||
// scope (OPTIONAL)
|
||||
|
@ -58,7 +56,7 @@ public class OAuth2RefreshTokenAuthenticationConverter implements Authentication
|
|||
OAuth2EndpointUtils.throwError(
|
||||
OAuth2ErrorCodes.INVALID_REQUEST,
|
||||
OAuth2ParameterNames.SCOPE,
|
||||
ACCESS_TOKEN_REQUEST_ERROR_URI);
|
||||
OAuth2EndpointUtils.ERROR_URI);
|
||||
}
|
||||
Set<String> requestedScopes = null;
|
||||
if (StringUtils.hasText(scope)) {
|
||||
|
|
|
@ -47,8 +47,6 @@ public class OAuth2TokenEndpointFilter extends OncePerRequestFilter {
|
|||
*/
|
||||
private static final String DEFAULT_TOKEN_ENDPOINT_URI = "/api/v1/oauth2/token";
|
||||
|
||||
private static final String DEFAULT_ERROR_URI =
|
||||
"https://datatracker.ietf.org/doc/html/rfc6749#section-5.2";
|
||||
private final AuthenticationManager authenticationManager;
|
||||
private final RequestMatcher tokenEndpointMatcher;
|
||||
private final HttpMessageConverter<OAuth2AccessTokenResponse> accessTokenHttpResponseConverter =
|
||||
|
@ -103,14 +101,15 @@ public class OAuth2TokenEndpointFilter extends OncePerRequestFilter {
|
|||
try {
|
||||
String[] grantTypes = request.getParameterValues(OAuth2ParameterNames.GRANT_TYPE);
|
||||
if (grantTypes == null || grantTypes.length != 1) {
|
||||
throwError(OAuth2ErrorCodes.INVALID_REQUEST, OAuth2ParameterNames.GRANT_TYPE);
|
||||
OAuth2EndpointUtils.throwError(OAuth2ErrorCodes.INVALID_REQUEST,
|
||||
OAuth2ParameterNames.GRANT_TYPE, OAuth2EndpointUtils.ERROR_URI);
|
||||
}
|
||||
|
||||
Authentication authorizationGrantAuthentication =
|
||||
this.authenticationConverter.convert(request);
|
||||
if (authorizationGrantAuthentication == null) {
|
||||
throwError(OAuth2ErrorCodes.UNSUPPORTED_GRANT_TYPE,
|
||||
OAuth2ParameterNames.GRANT_TYPE);
|
||||
OAuth2EndpointUtils.throwError(OAuth2ErrorCodes.UNSUPPORTED_GRANT_TYPE,
|
||||
OAuth2ParameterNames.GRANT_TYPE, OAuth2EndpointUtils.ERROR_URI);
|
||||
}
|
||||
if (authorizationGrantAuthentication instanceof AbstractAuthenticationToken) {
|
||||
((AbstractAuthenticationToken) authorizationGrantAuthentication)
|
||||
|
@ -221,10 +220,4 @@ public class OAuth2TokenEndpointFilter extends OncePerRequestFilter {
|
|||
httpResponse.setStatusCode(HttpStatus.BAD_REQUEST);
|
||||
this.errorHttpResponseConverter.write(error, null, httpResponse);
|
||||
}
|
||||
|
||||
private static void throwError(String errorCode, String parameterName) {
|
||||
OAuth2Error error =
|
||||
new OAuth2Error(errorCode, "OAuth 2.0 Parameter: " + parameterName, DEFAULT_ERROR_URI);
|
||||
throw new OAuth2AuthenticationException(error);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ import org.springframework.security.oauth2.core.OAuth2Token;
|
|||
*
|
||||
* @param <T> the type of the OAuth 2.0 Token
|
||||
* @author guqing
|
||||
* @date 2022-04-14
|
||||
* @since 2.0.0
|
||||
* @see OAuth2Token
|
||||
* @see OAuth2TokenContext
|
||||
* @see ClaimAccessor
|
||||
|
|
|
@ -5,7 +5,7 @@ import org.springframework.util.Assert;
|
|||
|
||||
/**
|
||||
* @author guqing
|
||||
* @date 2022-04-14
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public record OAuth2TokenType(String value) implements Serializable {
|
||||
public static final OAuth2TokenType ACCESS_TOKEN = new OAuth2TokenType("access_token");
|
||||
|
|
|
@ -8,7 +8,7 @@ import org.springframework.util.Assert;
|
|||
* A context that holds information of the Provider.
|
||||
*
|
||||
* @author guqing
|
||||
* @date 2022-04-14
|
||||
* @since 2.0.0
|
||||
*/
|
||||
public record ProviderContext(ProviderSettings providerSettings,
|
||||
@Nullable Supplier<String> issuerSupplier) {
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
package run.halo.app.identity.authentication;
|
||||
|
||||
/**
|
||||
* @author guqing
|
||||
* @date 2022-04-13
|
||||
*/
|
||||
public interface SecurityConstant {
|
||||
|
||||
/**
|
||||
* 30 mins
|
||||
*/
|
||||
long EXPIRATION_TIME = 1_800_000;
|
||||
|
||||
/**
|
||||
* Token prefix
|
||||
*/
|
||||
String TOKEN_PREFIX = "Bearer";
|
||||
|
||||
/**
|
||||
* Authentication header
|
||||
*/
|
||||
String HEADER_STRING = "Authorization";
|
||||
|
||||
/**
|
||||
* login uri
|
||||
*/
|
||||
String LOGIN_URL = "/api/v1/oauth/login";
|
||||
}
|
|
@ -1,253 +0,0 @@
|
|||
package run.halo.app.authentication;
|
||||
|
||||
import static java.util.Map.entry;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.assertj.core.api.InstanceOfAssertFactories.type;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import jakarta.servlet.FilterChain;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.mock.http.client.MockClientHttpResponse;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.oauth2.core.AuthorizationGrantType;
|
||||
import org.springframework.security.oauth2.core.OAuth2AccessToken;
|
||||
import org.springframework.security.oauth2.core.OAuth2RefreshToken;
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
|
||||
import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
|
||||
import org.springframework.security.oauth2.core.http.converter.OAuth2AccessTokenResponseHttpMessageConverter;
|
||||
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
|
||||
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
|
||||
import org.springframework.security.web.authentication.WebAuthenticationDetails;
|
||||
import run.halo.app.identity.authentication.JwtUsernamePasswordAuthenticationFilter;
|
||||
import run.halo.app.identity.authentication.OAuth2AccessTokenAuthenticationToken;
|
||||
|
||||
/**
|
||||
* Tests for {@link JwtUsernamePasswordAuthenticationFilter}.
|
||||
*
|
||||
* @author guqing
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Disabled
|
||||
public class JwtUsernamePasswordAuthenticationFilterTests {
|
||||
private static final String DEFAULT_TOKEN_ENDPOINT_URI = "/api/v1/oauth2/login";
|
||||
private static final String REMOTE_ADDRESS = "remote-address";
|
||||
private AuthenticationManager authenticationManager;
|
||||
private JwtUsernamePasswordAuthenticationFilter filter;
|
||||
|
||||
private final HttpMessageConverter<OAuth2AccessTokenResponse> accessTokenHttpResponseConverter =
|
||||
new OAuth2AccessTokenResponseHttpMessageConverter();
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
this.authenticationManager = mock(AuthenticationManager.class);
|
||||
this.filter = new JwtUsernamePasswordAuthenticationFilter(this.authenticationManager);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void cleanup() {
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void constructorWhenTokenEndpointUriNullThenThrowIllegalArgumentException() {
|
||||
assertThatThrownBy(
|
||||
() -> new JwtUsernamePasswordAuthenticationFilter(null, this.authenticationManager))
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessage("tokenEndpointUri cannot be empty.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setAuthenticationDetailsSourceWhenNullThenThrowIllegalArgumentException() {
|
||||
assertThatThrownBy(() -> this.filter.setAuthenticationDetailsSource(null))
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessage("AuthenticationDetailsSource required");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setAuthenticationSuccessHandlerWhenNullThenThrowIllegalArgumentException() {
|
||||
assertThatThrownBy(() -> this.filter.setAuthenticationSuccessHandler(null))
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessage("successHandler cannot be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setAuthenticationFailureHandlerWhenNullThenThrowIllegalArgumentException() {
|
||||
assertThatThrownBy(() -> this.filter.setAuthenticationFailureHandler(null))
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessage("failureHandler cannot be null");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterWhenNotTokenRequestThenNotProcessed() throws Exception {
|
||||
String requestUri = "/path";
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("POST", requestUri);
|
||||
request.setServletPath(requestUri);
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
FilterChain filterChain = mock(FilterChain.class);
|
||||
|
||||
this.filter.doFilter(request, response, filterChain);
|
||||
|
||||
verify(filterChain).doFilter(any(HttpServletRequest.class), any(HttpServletResponse.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterWhenTokenRequestGetThenNotProcessed() throws Exception {
|
||||
String requestUri = DEFAULT_TOKEN_ENDPOINT_URI;
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", requestUri);
|
||||
request.setServletPath(requestUri);
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
FilterChain filterChain = mock(FilterChain.class);
|
||||
|
||||
AuthenticationFailureHandler authenticationFailureHandler =
|
||||
mock(AuthenticationFailureHandler.class);
|
||||
filter.setAuthenticationFailureHandler(authenticationFailureHandler);
|
||||
|
||||
this.filter.doFilter(request, response, filterChain);
|
||||
|
||||
verify(authenticationFailureHandler).onAuthenticationFailure(any(HttpServletRequest.class),
|
||||
any(HttpServletResponse.class), any(AuthenticationException.class));
|
||||
|
||||
verifyNoInteractions(filterChain);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterWhenAuthorizationCodeTokenRequestThenAccessTokenResponse()
|
||||
throws Exception {
|
||||
OAuth2AccessToken accessToken = new OAuth2AccessToken(
|
||||
OAuth2AccessToken.TokenType.BEARER, "token",
|
||||
Instant.now(), Instant.now().plus(Duration.ofHours(1)),
|
||||
new HashSet<>(Arrays.asList("scope1", "scope2")));
|
||||
OAuth2RefreshToken refreshToken = new OAuth2RefreshToken(
|
||||
"refresh-token", Instant.now(), Instant.now().plus(Duration.ofDays(1)));
|
||||
Authentication clientPrincipal =
|
||||
new UsernamePasswordAuthenticationToken("guqing", "123456");
|
||||
Map<String, Object>
|
||||
additionalParameters = Collections.singletonMap("custom-param", "custom-value");
|
||||
OAuth2AccessTokenAuthenticationToken accessTokenAuthentication =
|
||||
new OAuth2AccessTokenAuthenticationToken(clientPrincipal, accessToken, refreshToken,
|
||||
additionalParameters);
|
||||
|
||||
when(this.authenticationManager.authenticate(any())).thenReturn(accessTokenAuthentication);
|
||||
|
||||
SecurityContext securityContext = SecurityContextHolder.createEmptyContext();
|
||||
securityContext.setAuthentication(clientPrincipal);
|
||||
SecurityContextHolder.setContext(securityContext);
|
||||
|
||||
MockHttpServletRequest request = createClientTokenRequest();
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
FilterChain filterChain = mock(FilterChain.class);
|
||||
|
||||
this.filter.doFilter(request, response, filterChain);
|
||||
|
||||
verifyNoInteractions(filterChain);
|
||||
|
||||
ArgumentCaptor<UsernamePasswordAuthenticationToken>
|
||||
authorizationCodeAuthenticationCaptor =
|
||||
ArgumentCaptor.forClass(UsernamePasswordAuthenticationToken.class);
|
||||
verify(this.authenticationManager).authenticate(
|
||||
authorizationCodeAuthenticationCaptor.capture());
|
||||
|
||||
UsernamePasswordAuthenticationToken accessTokenAuthenticationToken =
|
||||
authorizationCodeAuthenticationCaptor.getValue();
|
||||
assertThat(accessTokenAuthenticationToken.getName()).isEqualTo("guqing");
|
||||
assertThat(accessTokenAuthenticationToken.getDetails())
|
||||
.asInstanceOf(type(WebAuthenticationDetails.class))
|
||||
.extracting(WebAuthenticationDetails::getRemoteAddress)
|
||||
.isEqualTo(REMOTE_ADDRESS);
|
||||
|
||||
assertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value());
|
||||
OAuth2AccessTokenResponse accessTokenResponse = readAccessTokenResponse(response);
|
||||
|
||||
OAuth2AccessToken accessTokenResult = accessTokenResponse.getAccessToken();
|
||||
assertThat(accessTokenResult.getTokenType()).isEqualTo(accessToken.getTokenType());
|
||||
assertThat(accessTokenResult.getTokenValue()).isEqualTo(accessToken.getTokenValue());
|
||||
assertThat(accessTokenResult.getIssuedAt()).isBetween(
|
||||
accessToken.getIssuedAt().minusSeconds(1), accessToken.getIssuedAt().plusSeconds(1));
|
||||
assertThat(accessTokenResult.getExpiresAt()).isBetween(
|
||||
accessToken.getExpiresAt().minusSeconds(1), accessToken.getExpiresAt().plusSeconds(1));
|
||||
assertThat(accessTokenResult.getScopes()).isEqualTo(accessToken.getScopes());
|
||||
assertThat(accessTokenResponse.getRefreshToken().getTokenValue()).isEqualTo(
|
||||
refreshToken.getTokenValue());
|
||||
assertThat(accessTokenResponse.getAdditionalParameters()).containsExactly(
|
||||
entry("custom-param", "custom-value"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doFilterWhenCustomAuthenticationSuccessHandlerThenUsed() throws Exception {
|
||||
AuthenticationSuccessHandler authenticationSuccessHandler =
|
||||
mock(AuthenticationSuccessHandler.class);
|
||||
this.filter.setAuthenticationSuccessHandler(authenticationSuccessHandler);
|
||||
|
||||
Authentication clientPrincipal =
|
||||
new UsernamePasswordAuthenticationToken("guqing", "123456");
|
||||
OAuth2AccessToken accessToken = new OAuth2AccessToken(
|
||||
OAuth2AccessToken.TokenType.BEARER, "token",
|
||||
Instant.now(), Instant.now().plus(Duration.ofHours(1)),
|
||||
new HashSet<>(Arrays.asList("scope1", "scope2")));
|
||||
OAuth2AccessTokenAuthenticationToken accessTokenAuthentication =
|
||||
new OAuth2AccessTokenAuthenticationToken(clientPrincipal, accessToken);
|
||||
|
||||
when(this.authenticationManager.authenticate(any())).thenReturn(accessTokenAuthentication);
|
||||
|
||||
SecurityContext securityContext = SecurityContextHolder.createEmptyContext();
|
||||
securityContext.setAuthentication(clientPrincipal);
|
||||
SecurityContextHolder.setContext(securityContext);
|
||||
|
||||
MockHttpServletRequest request = createClientTokenRequest();
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
FilterChain filterChain = mock(FilterChain.class);
|
||||
|
||||
this.filter.doFilter(request, response, filterChain);
|
||||
|
||||
verify(authenticationSuccessHandler).onAuthenticationSuccess(any(), any(), any());
|
||||
}
|
||||
|
||||
private OAuth2AccessTokenResponse readAccessTokenResponse(MockHttpServletResponse response)
|
||||
throws Exception {
|
||||
MockClientHttpResponse httpResponse = new MockClientHttpResponse(
|
||||
response.getContentAsByteArray(), HttpStatus.valueOf(response.getStatus()));
|
||||
return this.accessTokenHttpResponseConverter.read(OAuth2AccessTokenResponse.class,
|
||||
httpResponse);
|
||||
}
|
||||
|
||||
private static MockHttpServletRequest createClientTokenRequest() {
|
||||
String requestUri = DEFAULT_TOKEN_ENDPOINT_URI;
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("POST", requestUri);
|
||||
request.setServletPath(requestUri);
|
||||
request.setRemoteAddr(REMOTE_ADDRESS);
|
||||
request.addParameter("username", "guqing");
|
||||
request.addParameter("password", "123456");
|
||||
|
||||
request.addParameter(OAuth2ParameterNames.GRANT_TYPE,
|
||||
AuthorizationGrantType.PASSWORD.getValue());
|
||||
request.addParameter("custom-param-1", "custom-value-1");
|
||||
|
||||
return request;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue