|
@@ -65,7 +65,10 @@ import org.springframework.http.ResponseEntity;
|
|
import org.springframework.mock.web.MockHttpServletRequest;
|
|
import org.springframework.mock.web.MockHttpServletRequest;
|
|
import org.springframework.security.access.prepost.PreAuthorize;
|
|
import org.springframework.security.access.prepost.PreAuthorize;
|
|
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
|
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
|
|
|
+import org.springframework.security.authentication.AuthenticationManager;
|
|
|
|
+import org.springframework.security.authentication.AuthenticationProvider;
|
|
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
|
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
|
|
|
|
+import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
|
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
|
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
|
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
|
@@ -79,8 +82,6 @@ import org.springframework.security.core.userdetails.UserDetailsService;
|
|
import org.springframework.security.oauth2.core.OAuth2Error;
|
|
import org.springframework.security.oauth2.core.OAuth2Error;
|
|
import org.springframework.security.oauth2.core.OAuth2TokenValidator;
|
|
import org.springframework.security.oauth2.core.OAuth2TokenValidator;
|
|
import org.springframework.security.oauth2.core.OAuth2TokenValidatorResult;
|
|
import org.springframework.security.oauth2.core.OAuth2TokenValidatorResult;
|
|
-import org.springframework.security.oauth2.server.resource.introspection.NimbusOAuth2TokenIntrospectionClient;
|
|
|
|
-import org.springframework.security.oauth2.server.resource.introspection.OAuth2TokenIntrospectionClient;
|
|
|
|
import org.springframework.security.oauth2.jose.jws.JwsAlgorithms;
|
|
import org.springframework.security.oauth2.jose.jws.JwsAlgorithms;
|
|
import org.springframework.security.oauth2.jwt.Jwt;
|
|
import org.springframework.security.oauth2.jwt.Jwt;
|
|
import org.springframework.security.oauth2.jwt.JwtClaimNames;
|
|
import org.springframework.security.oauth2.jwt.JwtClaimNames;
|
|
@@ -90,6 +91,9 @@ import org.springframework.security.oauth2.jwt.JwtTimestampValidator;
|
|
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
|
|
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
|
|
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
|
|
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationConverter;
|
|
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
|
|
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
|
|
|
|
+import org.springframework.security.oauth2.server.resource.authentication.OAuth2IntrospectionAuthenticationToken;
|
|
|
|
+import org.springframework.security.oauth2.server.resource.introspection.NimbusOAuth2TokenIntrospectionClient;
|
|
|
|
+import org.springframework.security.oauth2.server.resource.introspection.OAuth2TokenIntrospectionClient;
|
|
import org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationEntryPoint;
|
|
import org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationEntryPoint;
|
|
import org.springframework.security.oauth2.server.resource.web.BearerTokenResolver;
|
|
import org.springframework.security.oauth2.server.resource.web.BearerTokenResolver;
|
|
import org.springframework.security.oauth2.server.resource.web.DefaultBearerTokenResolver;
|
|
import org.springframework.security.oauth2.server.resource.web.DefaultBearerTokenResolver;
|
|
@@ -120,8 +124,10 @@ import static org.mockito.ArgumentMatchers.any;
|
|
import static org.mockito.ArgumentMatchers.anyString;
|
|
import static org.mockito.ArgumentMatchers.anyString;
|
|
import static org.mockito.ArgumentMatchers.eq;
|
|
import static org.mockito.ArgumentMatchers.eq;
|
|
import static org.mockito.Mockito.mock;
|
|
import static org.mockito.Mockito.mock;
|
|
|
|
+import static org.mockito.Mockito.never;
|
|
import static org.mockito.Mockito.verify;
|
|
import static org.mockito.Mockito.verify;
|
|
import static org.mockito.Mockito.when;
|
|
import static org.mockito.Mockito.when;
|
|
|
|
+import static org.springframework.security.oauth2.core.TestOAuth2AccessTokens.noScopes;
|
|
import static org.springframework.security.oauth2.jwt.NimbusJwtDecoder.withJwkSetUri;
|
|
import static org.springframework.security.oauth2.jwt.NimbusJwtDecoder.withJwkSetUri;
|
|
import static org.springframework.security.oauth2.jwt.NimbusJwtDecoder.withPublicKey;
|
|
import static org.springframework.security.oauth2.jwt.NimbusJwtDecoder.withPublicKey;
|
|
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
|
|
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
|
|
@@ -153,6 +159,8 @@ public class OAuth2ResourceServerConfigurerTests {
|
|
private static final String INTROSPECTION_URI = "https://idp.example.com";
|
|
private static final String INTROSPECTION_URI = "https://idp.example.com";
|
|
private static final String CLIENT_ID = "client-id";
|
|
private static final String CLIENT_ID = "client-id";
|
|
private static final String CLIENT_SECRET = "client-secret";
|
|
private static final String CLIENT_SECRET = "client-secret";
|
|
|
|
+ private static final OAuth2IntrospectionAuthenticationToken INTROSPECTION_AUTHENTICATION_TOKEN =
|
|
|
|
+ new OAuth2IntrospectionAuthenticationToken(noScopes(), JWT_CLAIMS, Collections.emptyList());
|
|
|
|
|
|
@Autowired(required = false)
|
|
@Autowired(required = false)
|
|
MockMvc mvc;
|
|
MockMvc mvc;
|
|
@@ -1015,6 +1023,20 @@ public class OAuth2ResourceServerConfigurerTests {
|
|
.andExpect(invalidTokenHeader("algorithm"));
|
|
.andExpect(invalidTokenHeader("algorithm"));
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ @Test
|
|
|
|
+ public void getWhenCustomJwtAuthenticationManagerThenUsed() throws Exception {
|
|
|
|
+ this.spring.register(JwtAuthenticationManagerConfig.class, BasicController.class).autowire();
|
|
|
|
+
|
|
|
|
+ when(bean(AuthenticationProvider.class).authenticate(any(Authentication.class)))
|
|
|
|
+ .thenReturn(JWT_AUTHENTICATION_TOKEN);
|
|
|
|
+ this.mvc.perform(get("/authenticated")
|
|
|
|
+ .with(bearerToken("token")))
|
|
|
|
+ .andExpect(status().isOk())
|
|
|
|
+ .andExpect(content().string("mock-test-subject"));
|
|
|
|
+
|
|
|
|
+ verifyBean(AuthenticationProvider.class).authenticate(any(Authentication.class));
|
|
|
|
+ }
|
|
|
|
+
|
|
// -- opaque
|
|
// -- opaque
|
|
|
|
|
|
|
|
|
|
@@ -1052,6 +1074,20 @@ public class OAuth2ResourceServerConfigurerTests {
|
|
.andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, containsString("scope")));
|
|
.andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, containsString("scope")));
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ @Test
|
|
|
|
+ public void getWhenCustomIntrospectionAuthenticationManagerThenUsed() throws Exception {
|
|
|
|
+ this.spring.register(OpaqueTokenAuthenticationManagerConfig.class, BasicController.class).autowire();
|
|
|
|
+
|
|
|
|
+ when(bean(AuthenticationProvider.class).authenticate(any(Authentication.class)))
|
|
|
|
+ .thenReturn(INTROSPECTION_AUTHENTICATION_TOKEN);
|
|
|
|
+ this.mvc.perform(get("/authenticated")
|
|
|
|
+ .with(bearerToken("token")))
|
|
|
|
+ .andExpect(status().isOk())
|
|
|
|
+ .andExpect(content().string("mock-test-subject"));
|
|
|
|
+
|
|
|
|
+ verifyBean(AuthenticationProvider.class).authenticate(any(Authentication.class));
|
|
|
|
+ }
|
|
|
|
+
|
|
@Test
|
|
@Test
|
|
public void configureWhenOnlyIntrospectionUrlThenException() throws Exception {
|
|
public void configureWhenOnlyIntrospectionUrlThenException() throws Exception {
|
|
assertThatCode(() -> this.spring.register(OpaqueTokenHalfConfiguredConfig.class).autowire())
|
|
assertThatCode(() -> this.spring.register(OpaqueTokenHalfConfiguredConfig.class).autowire())
|
|
@@ -1191,6 +1227,30 @@ public class OAuth2ResourceServerConfigurerTests {
|
|
.andExpect(content().string("basic-user"));
|
|
.andExpect(content().string("basic-user"));
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ // -- authentication manager
|
|
|
|
+
|
|
|
|
+ @Test
|
|
|
|
+ public void getAuthenticationManagerWhenConfiguredAuthenticationManagerThenTakesPrecedence() {
|
|
|
|
+ ApplicationContext context = mock(ApplicationContext.class);
|
|
|
|
+ HttpSecurityBuilder http = mock(HttpSecurityBuilder.class);
|
|
|
|
+
|
|
|
|
+ OAuth2ResourceServerConfigurer oauth2ResourceServer = new OAuth2ResourceServerConfigurer(context);
|
|
|
|
+ AuthenticationManager authenticationManager = mock(AuthenticationManager.class);
|
|
|
|
+ oauth2ResourceServer
|
|
|
|
+ .jwt()
|
|
|
|
+ .authenticationManager(authenticationManager)
|
|
|
|
+ .decoder(mock(JwtDecoder.class));
|
|
|
|
+ assertThat(oauth2ResourceServer.getAuthenticationManager(http)).isSameAs(authenticationManager);
|
|
|
|
+
|
|
|
|
+ oauth2ResourceServer = new OAuth2ResourceServerConfigurer(context);
|
|
|
|
+ oauth2ResourceServer
|
|
|
|
+ .opaqueToken()
|
|
|
|
+ .authenticationManager(authenticationManager)
|
|
|
|
+ .introspectionClient(mock(OAuth2TokenIntrospectionClient.class));
|
|
|
|
+ assertThat(oauth2ResourceServer.getAuthenticationManager(http)).isSameAs(authenticationManager);
|
|
|
|
+ verify(http, never()).authenticationProvider(any(AuthenticationProvider.class));
|
|
|
|
+ }
|
|
|
|
+
|
|
// -- Incorrect Configuration
|
|
// -- Incorrect Configuration
|
|
|
|
|
|
@Test
|
|
@Test
|
|
@@ -1622,6 +1682,27 @@ public class OAuth2ResourceServerConfigurerTests {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ @EnableWebSecurity
|
|
|
|
+ static class JwtAuthenticationManagerConfig extends WebSecurityConfigurerAdapter {
|
|
|
|
+ @Override
|
|
|
|
+ protected void configure(HttpSecurity http) throws Exception {
|
|
|
|
+ // @formatter:off
|
|
|
|
+ http
|
|
|
|
+ .authorizeRequests()
|
|
|
|
+ .anyRequest().authenticated()
|
|
|
|
+ .and()
|
|
|
|
+ .oauth2ResourceServer()
|
|
|
|
+ .jwt()
|
|
|
|
+ .authenticationManager(authenticationProvider()::authenticate);
|
|
|
|
+ // @formatter:on
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Bean
|
|
|
|
+ public AuthenticationProvider authenticationProvider() {
|
|
|
|
+ return mock(AuthenticationProvider.class);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
@EnableWebSecurity
|
|
@EnableWebSecurity
|
|
static class CustomJwtValidatorConfig extends WebSecurityConfigurerAdapter {
|
|
static class CustomJwtValidatorConfig extends WebSecurityConfigurerAdapter {
|
|
@Autowired
|
|
@Autowired
|
|
@@ -1735,6 +1816,27 @@ public class OAuth2ResourceServerConfigurerTests {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ @EnableWebSecurity
|
|
|
|
+ static class OpaqueTokenAuthenticationManagerConfig extends WebSecurityConfigurerAdapter {
|
|
|
|
+ @Override
|
|
|
|
+ protected void configure(HttpSecurity http) throws Exception {
|
|
|
|
+ // @formatter:off
|
|
|
|
+ http
|
|
|
|
+ .authorizeRequests()
|
|
|
|
+ .anyRequest().authenticated()
|
|
|
|
+ .and()
|
|
|
|
+ .oauth2ResourceServer()
|
|
|
|
+ .opaqueToken()
|
|
|
|
+ .authenticationManager(authenticationProvider()::authenticate);
|
|
|
|
+ // @formatter:on
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Bean
|
|
|
|
+ public AuthenticationProvider authenticationProvider() {
|
|
|
|
+ return mock(AuthenticationProvider.class);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
@EnableWebSecurity
|
|
@EnableWebSecurity
|
|
static class OpaqueAndJwtConfig extends WebSecurityConfigurerAdapter {
|
|
static class OpaqueAndJwtConfig extends WebSecurityConfigurerAdapter {
|
|
@Override
|
|
@Override
|
|
@@ -1954,6 +2056,14 @@ public class OAuth2ResourceServerConfigurerTests {
|
|
.thenReturn(entity);
|
|
.thenReturn(entity);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ private <T> T bean(Class<T> beanClass) {
|
|
|
|
+ return (T) this.spring.getContext().getBean(beanClass);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private <T> T verifyBean(Class<T> beanClass) {
|
|
|
|
+ return (T) verify(this.spring.getContext().getBean(beanClass));
|
|
|
|
+ }
|
|
|
|
+
|
|
private String json(String name) throws IOException {
|
|
private String json(String name) throws IOException {
|
|
return resource(name + ".json");
|
|
return resource(name + ".json");
|
|
}
|
|
}
|