Polish config format

Issue gh-8945
This commit is contained in:
Rob Winch 2020-08-24 09:47:59 -05:00
parent e3dd8d2530
commit 254f2e2aec
115 changed files with 5971 additions and 1811 deletions

View File

@ -29,6 +29,8 @@ import org.springframework.security.config.annotation.web.configuration.WebSecur
import org.springframework.security.config.test.SpringTestRule;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders;
import org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin;
@ -55,35 +57,39 @@ public class LdapAuthenticationProviderConfigurerTests {
public void authenticationManagerSupportMultipleLdapContextWithDefaultRolePrefix() throws Exception {
this.spring.register(MultiLdapAuthenticationProvidersConfig.class).autowire();
this.mockMvc.perform(formLogin().user("bob").password("bobspassword"))
.andExpect(authenticated().withUsername("bob")
.withAuthorities(Collections.singleton(new SimpleGrantedAuthority("ROLE_DEVELOPERS"))));
SecurityMockMvcRequestBuilders.FormLoginRequestBuilder request = formLogin().user("bob").password("bobspassword");
SecurityMockMvcResultMatchers.AuthenticatedMatcher expectedUser = authenticated().withUsername("bob")
.withAuthorities(Collections.singleton(new SimpleGrantedAuthority("ROLE_DEVELOPERS")));
this.mockMvc.perform(request).andExpect(expectedUser);
}
@Test
public void authenticationManagerSupportMultipleLdapContextWithCustomRolePrefix() throws Exception {
this.spring.register(MultiLdapWithCustomRolePrefixAuthenticationProvidersConfig.class).autowire();
this.mockMvc.perform(formLogin().user("bob").password("bobspassword"))
.andExpect(authenticated().withUsername("bob")
.withAuthorities(Collections.singleton(new SimpleGrantedAuthority("ROL_DEVELOPERS"))));
SecurityMockMvcRequestBuilders.FormLoginRequestBuilder request = formLogin().user("bob").password("bobspassword");
SecurityMockMvcResultMatchers.AuthenticatedMatcher expectedUser = authenticated().withUsername("bob")
.withAuthorities(Collections.singleton(new SimpleGrantedAuthority("ROL_DEVELOPERS")));
this.mockMvc.perform(request).andExpect(expectedUser);
}
@Test
public void authenticationManagerWhenPortZeroThenAuthenticates() throws Exception {
this.spring.register(LdapWithRandomPortConfig.class).autowire();
this.mockMvc.perform(formLogin().user("bob").password("bobspassword"))
.andExpect(authenticated().withUsername("bob"));
SecurityMockMvcRequestBuilders.FormLoginRequestBuilder request = formLogin().user("bob").password("bobspassword");
SecurityMockMvcResultMatchers.AuthenticatedMatcher expectedUser = authenticated().withUsername("bob");
this.mockMvc.perform(request).andExpect(expectedUser);
}
@Test
public void authenticationManagerWhenSearchSubtreeThenNestedGroupFound() throws Exception {
this.spring.register(GroupSubtreeSearchConfig.class).autowire();
this.mockMvc.perform(formLogin().user("ben").password("benspassword"))
.andExpect(authenticated().withUsername("ben").withAuthorities(
AuthorityUtils.createAuthorityList("ROLE_SUBMANAGERS", "ROLE_MANAGERS", "ROLE_DEVELOPERS")));
SecurityMockMvcRequestBuilders.FormLoginRequestBuilder request = formLogin().user("ben").password("benspassword");
SecurityMockMvcResultMatchers.AuthenticatedMatcher expectedUser = authenticated().withUsername("ben").withAuthorities(
AuthorityUtils.createAuthorityList("ROLE_SUBMANAGERS", "ROLE_MANAGERS", "ROLE_DEVELOPERS"));
this.mockMvc.perform(request).andExpect(expectedUser);
}
@EnableWebSecurity

View File

@ -36,6 +36,8 @@ import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
import org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator;
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders;
import org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers;
import org.springframework.security.web.FilterChainProxy;
import org.springframework.test.web.servlet.MockMvc;
@ -57,16 +59,19 @@ public class NamespaceLdapAuthenticationProviderTests {
public void ldapAuthenticationProvider() throws Exception {
this.spring.register(LdapAuthenticationProviderConfig.class).autowire();
this.mockMvc.perform(formLogin().user("bob").password("bobspassword"))
.andExpect(authenticated().withUsername("bob"));
SecurityMockMvcRequestBuilders.FormLoginRequestBuilder request = formLogin().user("bob").password("bobspassword");
SecurityMockMvcResultMatchers.AuthenticatedMatcher user = authenticated().withUsername("bob");
this.mockMvc.perform(request).andExpect(user);
}
@Test
public void ldapAuthenticationProviderCustom() throws Exception {
this.spring.register(CustomLdapAuthenticationProviderConfig.class).autowire();
this.mockMvc.perform(formLogin().user("bob").password("bobspassword")).andExpect(authenticated()
.withAuthorities(Collections.singleton(new SimpleGrantedAuthority("PREFIX_DEVELOPERS"))));
SecurityMockMvcRequestBuilders.FormLoginRequestBuilder request = formLogin().user("bob").password("bobspassword");
SecurityMockMvcResultMatchers.AuthenticatedMatcher user = authenticated()
.withAuthorities(Collections.singleton(new SimpleGrantedAuthority("PREFIX_DEVELOPERS")));
this.mockMvc.perform(request).andExpect(user);
}
// SEC-2490
@ -83,16 +88,18 @@ public class NamespaceLdapAuthenticationProviderTests {
this.spring.register(CustomAuthoritiesPopulatorConfig.class).autowire();
this.mockMvc.perform(formLogin().user("bob").password("bobspassword")).andExpect(
authenticated().withAuthorities(Collections.singleton(new SimpleGrantedAuthority("ROLE_EXTRA"))));
SecurityMockMvcRequestBuilders.FormLoginRequestBuilder request = formLogin().user("bob").password("bobspassword");
SecurityMockMvcResultMatchers.AuthenticatedMatcher user = authenticated().withAuthorities(Collections.singleton(new SimpleGrantedAuthority("ROLE_EXTRA")));
this.mockMvc.perform(request).andExpect(user);
}
@Test
public void ldapAuthenticationProviderPasswordCompare() throws Exception {
this.spring.register(PasswordCompareLdapConfig.class).autowire();
this.mockMvc.perform(formLogin().user("bcrypt").password("password"))
.andExpect(authenticated().withUsername("bcrypt"));
SecurityMockMvcRequestBuilders.FormLoginRequestBuilder request = formLogin().user("bcrypt").password("password");
SecurityMockMvcResultMatchers.AuthenticatedMatcher user = authenticated().withUsername("bcrypt");
this.mockMvc.perform(request).andExpect(user);
}
}

View File

@ -71,9 +71,15 @@ public class HelloRSocketITests {
@Before
public void setup() {
this.server = RSocketFactory.receive().frameDecoder(PayloadDecoder.ZERO_COPY)
.addSocketAcceptorPlugin(this.interceptor).acceptor(this.handler.responder())
.transport(TcpServerTransport.create("localhost", 0)).start().block();
// @formatter:off
this.server = RSocketFactory.receive()
.frameDecoder(PayloadDecoder.ZERO_COPY)
.addSocketAcceptorPlugin(this.interceptor)
.acceptor(this.handler.responder())
.transport(TcpServerTransport.create("localhost", 0))
.start()
.block();
// @formatter:on
}
@After
@ -85,13 +91,23 @@ public class HelloRSocketITests {
@Test
public void retrieveMonoWhenSecureThenDenied() throws Exception {
this.requester = RSocketRequester.builder().rsocketStrategies(this.handler.getRSocketStrategies())
.connectTcp("localhost", this.server.address().getPort()).block();
// @formatter:off
this.requester = RSocketRequester.builder()
.rsocketStrategies(this.handler.getRSocketStrategies())
.connectTcp("localhost", this.server.address().getPort())
.block();
// @formatter:on
String data = "rob";
// @formatter:off
assertThatExceptionOfType(Exception.class).isThrownBy(
() -> this.requester.route("secure.retrieve-mono").data(data).retrieveMono(String.class).block())
() -> this.requester.route("secure.retrieve-mono")
.data(data)
.retrieveMono(String.class)
.block()
)
.matches((ex) -> ex instanceof RejectedSetupException
|| ex.getClass().toString().contains("ReactiveException"));
// @formatter:on
// FIXME: https://github.com/rsocket/rsocket-java/issues/686
assertThat(this.controller.payloads).isEmpty();
}
@ -99,14 +115,21 @@ public class HelloRSocketITests {
@Test
public void retrieveMonoWhenAuthorizedThenGranted() throws Exception {
UsernamePasswordMetadata credentials = new UsernamePasswordMetadata("rob", "password");
// @formatter:off
this.requester = RSocketRequester.builder()
.setupMetadata(credentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.rsocketStrategies(this.handler.getRSocketStrategies())
.connectTcp("localhost", this.server.address().getPort()).block();
.setupMetadata(credentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.rsocketStrategies(this.handler.getRSocketStrategies())
.connectTcp("localhost", this.server.address().getPort())
.block();
// @formatter:on
String data = "rob";
// @formatter:off
String hiRob = this.requester.route("secure.retrieve-mono")
.metadata(credentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE).data(data)
.retrieveMono(String.class).block();
.metadata(credentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.data(data)
.retrieveMono(String.class)
.block();
// @formatter:on
assertThat(hiRob).isEqualTo("Hi rob");
assertThat(this.controller.payloads).containsOnly(data);
}

View File

@ -99,10 +99,16 @@ public class JwtITests {
public void routeWhenBearerThenAuthorized() {
BearerTokenMetadata credentials = new BearerTokenMetadata("token");
given(this.decoder.decode(any())).willReturn(Mono.just(jwt()));
// @formatter:off
this.requester = requester()
.setupMetadata(credentials.getToken(), BearerTokenMetadata.BEARER_AUTHENTICATION_MIME_TYPE)
.connectTcp(this.server.address().getHostName(), this.server.address().getPort()).block();
String hiRob = this.requester.route("secure.retrieve-mono").data("rob").retrieveMono(String.class).block();
.setupMetadata(credentials.getToken(), BearerTokenMetadata.BEARER_AUTHENTICATION_MIME_TYPE)
.connectTcp(this.server.address().getHostName(), this.server.address().getPort())
.block();
String hiRob = this.requester.route("secure.retrieve-mono")
.data("rob")
.retrieveMono(String.class)
.block();
// @formatter:on
assertThat(hiRob).isEqualTo("Hi rob");
}
@ -112,9 +118,14 @@ public class JwtITests {
.parseMimeType(WellKnownMimeType.MESSAGE_RSOCKET_AUTHENTICATION.getString());
BearerTokenMetadata credentials = new BearerTokenMetadata("token");
given(this.decoder.decode(any())).willReturn(Mono.just(jwt()));
// @formatter:off
this.requester = requester().setupMetadata(credentials, authenticationMimeType)
.connectTcp(this.server.address().getHostName(), this.server.address().getPort()).block();
String hiRob = this.requester.route("secure.retrieve-mono").data("rob").retrieveMono(String.class).block();
.connectTcp(this.server.address().getHostName(), this.server.address().getPort())
.block();
String hiRob = this.requester.route("secure.retrieve-mono")
.data("rob")
.retrieveMono(String.class).block();
// @formatter:on
assertThat(hiRob).isEqualTo("Hi rob");
}

View File

@ -78,9 +78,15 @@ public class RSocketMessageHandlerConnectionITests {
@Before
public void setup() {
this.server = RSocketFactory.receive().frameDecoder(PayloadDecoder.ZERO_COPY)
.addSocketAcceptorPlugin(this.interceptor).acceptor(this.handler.responder())
.transport(TcpServerTransport.create("localhost", 0)).start().block();
// @formatter:off
this.server = RSocketFactory.receive()
.frameDecoder(PayloadDecoder.ZERO_COPY)
.addSocketAcceptorPlugin(this.interceptor)
.acceptor(this.handler.responder())
.transport(TcpServerTransport.create("localhost", 0))
.start()
.block();
// @formatter:on
}
@After
@ -93,94 +99,147 @@ public class RSocketMessageHandlerConnectionITests {
@Test
public void routeWhenAuthorized() {
UsernamePasswordMetadata credentials = new UsernamePasswordMetadata("user", "password");
// @formatter:off
this.requester = requester().setupMetadata(credentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.connectTcp(this.server.address().getHostName(), this.server.address().getPort()).block();
String hiRob = this.requester.route("secure.retrieve-mono").data("rob").retrieveMono(String.class).block();
.connectTcp(this.server.address().getHostName(), this.server.address().getPort())
.block();
String hiRob = this.requester.route("secure.retrieve-mono")
.data("rob")
.retrieveMono(String.class)
.block();
// @formatter:on
assertThat(hiRob).isEqualTo("Hi rob");
}
@Test
public void routeWhenNotAuthorized() {
UsernamePasswordMetadata credentials = new UsernamePasswordMetadata("user", "password");
// @formatter:off
this.requester = requester().setupMetadata(credentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.connectTcp(this.server.address().getHostName(), this.server.address().getPort()).block();
.connectTcp(this.server.address().getHostName(), this.server.address().getPort())
.block();
assertThatExceptionOfType(ApplicationErrorException.class).isThrownBy(() -> this.requester
.route("secure.admin.retrieve-mono").data("data").retrieveMono(String.class).block());
.route("secure.admin.retrieve-mono")
.data("data")
.retrieveMono(String.class)
.block()
);
// @formatter:on
}
@Test
public void routeWhenStreamCredentialsAuthorized() {
UsernamePasswordMetadata connectCredentials = new UsernamePasswordMetadata("user", "password");
this.requester = requester()
.setupMetadata(connectCredentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.connectTcp(this.server.address().getHostName(), this.server.address().getPort()).block();
// @formatter:off
this.requester = requester().setupMetadata(connectCredentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.connectTcp(this.server.address().getHostName(), this.server.address().getPort())
.block();
String hiRob = this.requester.route("secure.admin.retrieve-mono")
.metadata(new UsernamePasswordMetadata("admin", "password"),
UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.data("rob").retrieveMono(String.class).block();
.metadata(new UsernamePasswordMetadata("admin", "password"),
UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.data("rob")
.retrieveMono(String.class)
.block();
// @formatter:on
assertThat(hiRob).isEqualTo("Hi rob");
}
@Test
public void routeWhenStreamCredentialsHaveAuthority() {
UsernamePasswordMetadata connectCredentials = new UsernamePasswordMetadata("user", "password");
this.requester = requester()
.setupMetadata(connectCredentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.connectTcp(this.server.address().getHostName(), this.server.address().getPort()).block();
// @formatter:off
this.requester = requester().setupMetadata(connectCredentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.connectTcp(this.server.address().getHostName(), this.server.address().getPort())
.block();
String hiUser = this.requester.route("secure.authority.retrieve-mono")
.metadata(new UsernamePasswordMetadata("admin", "password"),
UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.data("Felipe").retrieveMono(String.class).block();
.metadata(new UsernamePasswordMetadata("admin", "password"),
UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.data("Felipe")
.retrieveMono(String.class)
.block();
// @formatter:on
assertThat(hiUser).isEqualTo("Hi Felipe");
}
@Test
public void connectWhenNotAuthenticated() {
// @formatter:off
this.requester = requester().connectTcp(this.server.address().getHostName(), this.server.address().getPort())
.block();
assertThatExceptionOfType(Exception.class)
.isThrownBy(() -> this.requester.route("retrieve-mono").data("data").retrieveMono(String.class).block())
.isThrownBy(() -> this.requester.route("retrieve-mono")
.data("data")
.retrieveMono(String.class)
.block()
)
.matches((ex) -> ex instanceof RejectedSetupException
|| ex.getClass().toString().contains("ReactiveException"));
// @formatter:on
// FIXME: https://github.com/rsocket/rsocket-java/issues/686
}
@Test
public void connectWhenNotAuthorized() {
UsernamePasswordMetadata credentials = new UsernamePasswordMetadata("evil", "password");
// @formatter:off
this.requester = requester().setupMetadata(credentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.connectTcp(this.server.address().getHostName(), this.server.address().getPort()).block();
.connectTcp(this.server.address().getHostName(), this.server.address().getPort())
.block();
assertThatExceptionOfType(Exception.class)
.isThrownBy(() -> this.requester.route("retrieve-mono").data("data").retrieveMono(String.class).block())
.isThrownBy(() -> this.requester.route("retrieve-mono")
.data("data")
.retrieveMono(String.class)
.block()
)
.matches((ex) -> ex instanceof RejectedSetupException
|| ex.getClass().toString().contains("ReactiveException"));
// @formatter:on
// FIXME: https://github.com/rsocket/rsocket-java/issues/686
}
@Test
public void connectionDenied() {
UsernamePasswordMetadata credentials = new UsernamePasswordMetadata("user", "password");
// @formatter:off
this.requester = requester().setupMetadata(credentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.connectTcp(this.server.address().getHostName(), this.server.address().getPort()).block();
.connectTcp(this.server.address().getHostName(), this.server.address().getPort())
.block();
assertThatExceptionOfType(ApplicationErrorException.class)
.isThrownBy(() -> this.requester.route("prohibit").data("data").retrieveMono(String.class).block());
.isThrownBy(() -> this.requester.route("prohibit")
.data("data")
.retrieveMono(String.class)
.block()
);
// @formatter:on
}
@Test
public void connectWithAnyRole() {
UsernamePasswordMetadata credentials = new UsernamePasswordMetadata("user", "password");
// @formatter:off
this.requester = requester().setupMetadata(credentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.connectTcp(this.server.address().getHostName(), this.server.address().getPort()).block();
String hiRob = this.requester.route("anyroute").data("rob").retrieveMono(String.class).block();
.connectTcp(this.server.address().getHostName(), this.server.address().getPort())
.block();
String hiRob = this.requester.route("anyroute")
.data("rob")
.retrieveMono(String.class)
.block();
// @formatter:on
assertThat(hiRob).isEqualTo("Hi rob");
}
@Test
public void connectWithAnyAuthority() {
UsernamePasswordMetadata credentials = new UsernamePasswordMetadata("admin", "password");
// @formatter:off
this.requester = requester().setupMetadata(credentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.connectTcp(this.server.address().getHostName(), this.server.address().getPort()).block();
String hiEbert = this.requester.route("management.users").data("admin").retrieveMono(String.class).block();
.connectTcp(this.server.address().getHostName(), this.server.address().getPort())
.block();
String hiEbert = this.requester.route("management.users")
.data("admin")
.retrieveMono(String.class)
.block();
// @formatter:on
assertThat(hiEbert).isEqualTo("Hi admin");
}
@ -233,10 +292,18 @@ public class RSocketMessageHandlerConnectionITests {
@Bean
PayloadSocketAcceptorInterceptor rsocketInterceptor(RSocketSecurity rsocket) {
rsocket.authorizePayload((authorize) -> authorize.setup().hasRole("SETUP").route("secure.admin.*")
.hasRole("ADMIN").route("secure.**").hasRole("USER").route("secure.authority.*")
.hasAuthority("ROLE_USER").route("management.*").hasAnyAuthority("ROLE_ADMIN").route("prohibit")
.denyAll().anyRequest().permitAll()).basicAuthentication(Customizer.withDefaults());
// @formatter:off
rsocket.authorizePayload((authorize) -> authorize
.setup().hasRole("SETUP")
.route("secure.admin.*").hasRole("ADMIN")
.route("secure.**").hasRole("USER")
.route("secure.authority.*").hasAuthority("ROLE_USER")
.route("management.*").hasAnyAuthority("ROLE_ADMIN")
.route("prohibit").denyAll()
.anyRequest().permitAll()
)
.basicAuthentication(Customizer.withDefaults());
// @formatter:on
return rsocket.build();
}

View File

@ -76,14 +76,21 @@ public class RSocketMessageHandlerITests {
@Before
public void setup() {
this.server = RSocketFactory.receive().frameDecoder(PayloadDecoder.ZERO_COPY)
.addSocketAcceptorPlugin(this.interceptor).acceptor(this.handler.responder())
.transport(TcpServerTransport.create("localhost", 0)).start().block();
// @formatter:off
this.server = RSocketFactory.receive()
.frameDecoder(PayloadDecoder.ZERO_COPY)
.addSocketAcceptorPlugin(this.interceptor)
.acceptor(this.handler.responder())
.transport(TcpServerTransport.create("localhost", 0))
.start()
.block();
this.requester = RSocketRequester.builder()
// .rsocketFactory((factory) ->
// factory.addRequesterPlugin(payloadInterceptor))
.rsocketStrategies(this.handler.getRSocketStrategies())
.connectTcp("localhost", this.server.address().getPort()).block();
.connectTcp("localhost", this.server.address().getPort())
.block();
// @formatter:on
}
@After
@ -96,9 +103,15 @@ public class RSocketMessageHandlerITests {
@Test
public void retrieveMonoWhenSecureThenDenied() throws Exception {
String data = "rob";
// @formatter:off
assertThatExceptionOfType(ApplicationErrorException.class).isThrownBy(
() -> this.requester.route("secure.retrieve-mono").data(data).retrieveMono(String.class).block())
.withMessageContaining("Access Denied");
() -> this.requester.route("secure.retrieve-mono")
.data(data)
.retrieveMono(String.class)
.block()
)
.withMessageContaining("Access Denied");
// @formatter:on
assertThat(this.controller.payloads).isEmpty();
}
@ -106,11 +119,15 @@ public class RSocketMessageHandlerITests {
public void retrieveMonoWhenAuthenticationFailedThenException() throws Exception {
String data = "rob";
UsernamePasswordMetadata credentials = new UsernamePasswordMetadata("invalid", "password");
// @formatter:off
assertThatExceptionOfType(ApplicationErrorException.class)
.isThrownBy(() -> this.requester.route("secure.retrieve-mono")
.metadata(credentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE).data(data)
.retrieveMono(String.class).block())
.withMessageContaining("Invalid Credentials");
.isThrownBy(() -> this.requester.route("secure.retrieve-mono")
.metadata(credentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE).data(data)
.retrieveMono(String.class)
.block()
)
.withMessageContaining("Invalid Credentials");
// @formatter:on
assertThat(this.controller.payloads).isEmpty();
}
@ -118,9 +135,13 @@ public class RSocketMessageHandlerITests {
public void retrieveMonoWhenAuthorizedThenGranted() throws Exception {
String data = "rob";
UsernamePasswordMetadata credentials = new UsernamePasswordMetadata("rob", "password");
// @formatter:off
String hiRob = this.requester.route("secure.retrieve-mono")
.metadata(credentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE).data(data)
.retrieveMono(String.class).block();
.metadata(credentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.data(data)
.retrieveMono(String.class)
.block();
// @formatter:on
assertThat(hiRob).isEqualTo("Hi rob");
assertThat(this.controller.payloads).containsOnly(data);
}
@ -128,7 +149,12 @@ public class RSocketMessageHandlerITests {
@Test
public void retrieveMonoWhenPublicThenGranted() throws Exception {
String data = "rob";
String hiRob = this.requester.route("retrieve-mono").data(data).retrieveMono(String.class).block();
// @formatter:off
String hiRob = this.requester.route("retrieve-mono")
.data(data)
.retrieveMono(String.class)
.block();
// @formatter:on
assertThat(hiRob).isEqualTo("Hi rob");
assertThat(this.controller.payloads).containsOnly(data);
}
@ -136,18 +162,29 @@ public class RSocketMessageHandlerITests {
@Test
public void retrieveFluxWhenDataFluxAndSecureThenDenied() throws Exception {
Flux<String> data = Flux.just("a", "b", "c");
// @formatter:off
assertThatExceptionOfType(ApplicationErrorException.class)
.isThrownBy(() -> this.requester.route("secure.retrieve-flux").data(data, String.class)
.retrieveFlux(String.class).collectList().block())
.withMessageContaining("Access Denied");
.isThrownBy(() -> this.requester.route("secure.retrieve-flux")
.data(data, String.class)
.retrieveFlux(String.class)
.collectList()
.block()
)
.withMessageContaining("Access Denied");
// @formatter:on
assertThat(this.controller.payloads).isEmpty();
}
@Test
public void retrieveFluxWhenDataFluxAndPublicThenGranted() throws Exception {
Flux<String> data = Flux.just("a", "b", "c");
List<String> hi = this.requester.route("retrieve-flux").data(data, String.class).retrieveFlux(String.class)
.collectList().block();
// @formatter:off
List<String> hi = this.requester.route("retrieve-flux")
.data(data, String.class)
.retrieveFlux(String.class)
.collectList()
.block();
// @formatter:on
assertThat(hi).containsOnly("hello a", "hello b", "hello c");
assertThat(this.controller.payloads).containsOnlyElementsOf(data.collectList().block());
}
@ -164,14 +201,24 @@ public class RSocketMessageHandlerITests {
@Test
public void sendWhenSecureThenDenied() throws Exception {
String data = "hi";
this.requester.route("secure.send").data(data).send().block();
// @formatter:off
this.requester.route("secure.send")
.data(data)
.send()
.block();
// @formatter:on
assertThat(this.controller.payloads).isEmpty();
}
@Test
public void sendWhenPublicThenGranted() throws Exception {
String data = "hi";
this.requester.route("send").data(data).send().block();
// @formatter:off
this.requester.route("send")
.data(data)
.send()
.block();
// @formatter:on
assertThat(this.controller.awaitPayloads()).containsOnly("hi");
}
@ -215,9 +262,14 @@ public class RSocketMessageHandlerITests {
@Bean
PayloadSocketAcceptorInterceptor rsocketInterceptor(RSocketSecurity rsocket) {
// @formatter:off
rsocket.authorizePayload(
(authorize) -> authorize.route("secure.*").authenticated().anyExchange().permitAll())
.basicAuthentication(Customizer.withDefaults());
(authorize) -> authorize
.route("secure.*").authenticated()
.anyExchange().permitAll()
)
.basicAuthentication(Customizer.withDefaults());
// @formatter:on
return rsocket.build();
}

View File

@ -76,9 +76,15 @@ public class SimpleAuthenticationITests {
@Before
public void setup() {
this.server = RSocketFactory.receive().frameDecoder(PayloadDecoder.ZERO_COPY)
.addSocketAcceptorPlugin(this.interceptor).acceptor(this.handler.responder())
.transport(TcpServerTransport.create("localhost", 0)).start().block();
// @formatter:off
this.server = RSocketFactory.receive()
.frameDecoder(PayloadDecoder.ZERO_COPY)
.addSocketAcceptorPlugin(this.interceptor)
.acceptor(this.handler.responder())
.transport(TcpServerTransport.create("localhost", 0))
.start()
.block();
// @formatter:on
}
@After
@ -90,11 +96,20 @@ public class SimpleAuthenticationITests {
@Test
public void retrieveMonoWhenSecureThenDenied() throws Exception {
this.requester = RSocketRequester.builder().rsocketStrategies(this.handler.getRSocketStrategies())
.connectTcp("localhost", this.server.address().getPort()).block();
// @formatter:off
this.requester = RSocketRequester.builder()
.rsocketStrategies(this.handler.getRSocketStrategies())
.connectTcp("localhost", this.server.address().getPort())
.block();
// @formatter:on
String data = "rob";
assertThatExceptionOfType(ApplicationErrorException.class).isThrownBy(
() -> this.requester.route("secure.retrieve-mono").data(data).retrieveMono(String.class).block());
// @formatter:off
assertThatExceptionOfType(ApplicationErrorException.class)
.isThrownBy(() -> this.requester.route("secure.retrieve-mono")
.data(data).retrieveMono(String.class)
.block()
);
// @formatter:on
assertThat(this.controller.payloads).isEmpty();
}
@ -103,12 +118,20 @@ public class SimpleAuthenticationITests {
MimeType authenticationMimeType = MimeTypeUtils
.parseMimeType(WellKnownMimeType.MESSAGE_RSOCKET_AUTHENTICATION.getString());
UsernamePasswordMetadata credentials = new UsernamePasswordMetadata("rob", "password");
this.requester = RSocketRequester.builder().setupMetadata(credentials, authenticationMimeType)
.rsocketStrategies(this.handler.getRSocketStrategies())
.connectTcp("localhost", this.server.address().getPort()).block();
// @formatter:off
this.requester = RSocketRequester.builder()
.setupMetadata(credentials, authenticationMimeType)
.rsocketStrategies(this.handler.getRSocketStrategies())
.connectTcp("localhost", this.server.address().getPort())
.block();
// @formatter:on
String data = "rob";
String hiRob = this.requester.route("secure.retrieve-mono").metadata(credentials, authenticationMimeType)
.data(data).retrieveMono(String.class).block();
// @formatter:off
String hiRob = this.requester.route("secure.retrieve-mono")
.metadata(credentials, authenticationMimeType)
.data(data).retrieveMono(String.class)
.block();
// @formatter:on
assertThat(hiRob).isEqualTo("Hi rob");
assertThat(this.controller.payloads).containsOnly(data);
}

View File

@ -46,9 +46,15 @@ class SecuritySocketAcceptorInterceptorConfiguration {
if (rsocket == null) {
throw new NoSuchBeanDefinitionException("No RSocketSecurity defined");
}
rsocket.basicAuthentication(Customizer.withDefaults()).simpleAuthentication(Customizer.withDefaults())
.authorizePayload((authz) -> authz.setup().authenticated().anyRequest().authenticated()
.matcher((e) -> MatchResult.match()).permitAll());
// @formatter:off
rsocket.basicAuthentication(Customizer.withDefaults())
.simpleAuthentication(Customizer.withDefaults())
.authorizePayload((authz) -> authz
.setup().authenticated()
.anyRequest().authenticated()
.matcher((e) -> MatchResult.match()).permitAll()
);
// @formatter:on
return rsocket.build();
}

View File

@ -84,17 +84,20 @@ class HttpSecurityConfiguration {
this.objectPostProcessor, passwordEncoder);
authenticationBuilder.parentAuthenticationManager(authenticationManager());
HttpSecurity http = new HttpSecurity(this.objectPostProcessor, authenticationBuilder, createSharedObjects());
http.csrf(withDefaults());
http.addFilter(new WebAsyncManagerIntegrationFilter());
http.exceptionHandling(withDefaults());
http.headers(withDefaults());
http.sessionManagement(withDefaults());
http.securityContext(withDefaults());
http.requestCache(withDefaults());
http.anonymous(withDefaults());
http.servletApi(withDefaults());
http.logout(withDefaults());
http.apply(new DefaultLoginPageConfigurer<>());
// @formatter:off
http
.csrf(withDefaults())
.addFilter(new WebAsyncManagerIntegrationFilter())
.exceptionHandling(withDefaults())
.headers(withDefaults())
.sessionManagement(withDefaults())
.securityContext(withDefaults())
.requestCache(withDefaults())
.anonymous(withDefaults())
.servletApi(withDefaults())
.logout(withDefaults())
.apply(new DefaultLoginPageConfigurer<>());
// @formatter:on
return http;
}

View File

@ -117,10 +117,15 @@ final class OAuth2ClientConfiguration {
OAuth2AuthorizedClientManager authorizedClientManager = null;
if (this.clientRegistrationRepository != null && this.authorizedClientRepository != null) {
if (this.accessTokenResponseClient != null) {
// @formatter:off
OAuth2AuthorizedClientProvider authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder
.builder().authorizationCode().refreshToken().clientCredentials((configurer) -> configurer
.accessTokenResponseClient(this.accessTokenResponseClient))
.password().build();
.builder()
.authorizationCode()
.refreshToken()
.clientCredentials((configurer) -> configurer.accessTokenResponseClient(this.accessTokenResponseClient))
.password()
.build();
// @formatter:on
DefaultOAuth2AuthorizedClientManager defaultAuthorizedClientManager = new DefaultOAuth2AuthorizedClientManager(
this.clientRegistrationRepository, this.authorizedClientRepository);
defaultAuthorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);

View File

@ -125,7 +125,11 @@ class ServerHttpSecurityConfiguration {
@Scope("prototype")
ServerHttpSecurity httpSecurity() {
ContextAwareServerHttpSecurity http = new ContextAwareServerHttpSecurity();
return http.authenticationManager(authenticationManager()).headers().and().logout().and();
// @formatter:off
return http.authenticationManager(authenticationManager())
.headers().and()
.logout().and();
// @formatter:on
}
private ReactiveAuthenticationManager authenticationManager() {

View File

@ -18,12 +18,17 @@ package org.springframework.security.config;
public abstract class ConfigTestUtils {
// @formatter:off
public static final String AUTH_PROVIDER_XML = "<authentication-manager alias='authManager'>"
+ " <authentication-provider>" + " <user-service id='us'>"
+ " <authentication-provider>"
+ " <user-service id='us'>"
+ " <user name='bob' password='{noop}bobspassword' authorities='ROLE_A,ROLE_B' />"
+ " <user name='bill' password='{noop}billspassword' authorities='ROLE_A,ROLE_B,AUTH_OTHER' />"
+ " <user name='admin' password='{noop}password' authorities='ROLE_ADMIN,ROLE_USER' />"
+ " <user name='user' password='{noop}password' authorities='ROLE_USER' />"
+ " </user-service>" + " </authentication-provider>" + "</authentication-manager>";
+ " </user-service>"
+ " </authentication-provider>"
+ "</authentication-manager>";
// @formatter:on
}

View File

@ -52,9 +52,15 @@ public class SecurityNamespaceHandlerTests {
@Rule
public ExpectedException thrown = ExpectedException.none();
private static final String XML_AUTHENTICATION_MANAGER = "<authentication-manager>" + " <authentication-provider>"
+ " <user-service id='us'>" + " <user name='bob' password='bobspassword' authorities='ROLE_A' />"
+ " </user-service>" + " </authentication-provider>" + "</authentication-manager>";
// @formatter:off
private static final String XML_AUTHENTICATION_MANAGER = "<authentication-manager>"
+ " <authentication-provider>"
+ " <user-service id='us'>"
+ " <user name='bob' password='bobspassword' authorities='ROLE_A' />"
+ " </user-service>"
+ " </authentication-provider>"
+ "</authentication-manager>";
// @formatter:on
private static final String XML_HTTP_BLOCK = "<http auto-config='true'/>";

View File

@ -50,6 +50,7 @@ import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers;
import org.springframework.test.web.servlet.MockMvc;
import static org.assertj.core.api.Assertions.assertThat;
@ -121,9 +122,10 @@ public class AuthenticationManagerBuilderTests {
@Test
public void authenticationManagerWhenMultipleProvidersThenWorks() throws Exception {
this.spring.register(MultiAuthenticationProvidersConfig.class).autowire();
this.mockMvc.perform(formLogin()).andExpect(authenticated().withUsername("user").withRoles("USER"));
this.mockMvc.perform(formLogin().user("admin"))
.andExpect(authenticated().withUsername("admin").withRoles("USER", "ADMIN"));
SecurityMockMvcResultMatchers.AuthenticatedMatcher user = authenticated().withUsername("user").withRoles("USER");
this.mockMvc.perform(formLogin()).andExpect(user);
SecurityMockMvcResultMatchers.AuthenticatedMatcher admin = authenticated().withUsername("admin").withRoles("USER", "ADMIN");
this.mockMvc.perform(formLogin().user("admin")).andExpect(admin);
}
@Test
@ -165,8 +167,14 @@ public class AuthenticationManagerBuilderTests {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser(PasswordEncodedUser.user()).and().inMemoryAuthentication()
// @formatter:off
auth
.inMemoryAuthentication()
.withUser(PasswordEncodedUser.user())
.and()
.inMemoryAuthentication()
.withUser(PasswordEncodedUser.admin());
// @formatter:on
}
}

View File

@ -47,20 +47,18 @@ public class NamespaceAuthenticationManagerTests {
@Test
public void authenticationMangerWhenDefaultThenEraseCredentialsIsTrue() throws Exception {
this.spring.register(EraseCredentialsTrueDefaultConfig.class).autowire();
this.mockMvc.perform(formLogin())
.andExpect(authenticated().withAuthentication((a) -> assertThat(a.getCredentials()).isNull()));
this.mockMvc.perform(formLogin())
.andExpect(authenticated().withAuthentication((a) -> assertThat(a.getCredentials()).isNull()));
SecurityMockMvcResultMatchers.AuthenticatedMatcher nullCredentials = authenticated().withAuthentication((a) -> assertThat(a.getCredentials()).isNull());
this.mockMvc.perform(formLogin()).andExpect(nullCredentials);
this.mockMvc.perform(formLogin()).andExpect(nullCredentials);
// no exception due to username being cleared out
}
@Test
public void authenticationMangerWhenEraseCredentialsIsFalseThenCredentialsNotNull() throws Exception {
this.spring.register(EraseCredentialsFalseConfig.class).autowire();
this.mockMvc.perform(formLogin())
.andExpect(authenticated().withAuthentication((a) -> assertThat(a.getCredentials()).isNotNull()));
this.mockMvc.perform(formLogin())
.andExpect(authenticated().withAuthentication((a) -> assertThat(a.getCredentials()).isNotNull()));
SecurityMockMvcResultMatchers.AuthenticatedMatcher notNullCredentials = authenticated().withAuthentication((a) -> assertThat(a.getCredentials()).isNotNull());
this.mockMvc.perform(formLogin()).andExpect(notNullCredentials);
this.mockMvc.perform(formLogin()).andExpect(notNullCredentials);
// no exception due to username being cleared out
}
@ -68,8 +66,8 @@ public class NamespaceAuthenticationManagerTests {
// SEC-2533
public void authenticationManagerWhenGlobalAndEraseCredentialsIsFalseThenCredentialsNotNull() throws Exception {
this.spring.register(GlobalEraseCredentialsFalseConfig.class).autowire();
this.mockMvc.perform(SecurityMockMvcRequestBuilders.formLogin()).andExpect(SecurityMockMvcResultMatchers
.authenticated().withAuthentication((a) -> assertThat(a.getCredentials()).isNotNull()));
SecurityMockMvcResultMatchers.AuthenticatedMatcher notNullCredentials = authenticated().withAuthentication((a) -> assertThat(a.getCredentials()).isNotNull());
this.mockMvc.perform(formLogin()).andExpect(notNullCredentials);
}
@EnableWebSecurity

View File

@ -34,6 +34,7 @@ import org.springframework.security.core.userdetails.PasswordEncodedUser;
import org.springframework.security.core.userdetails.UserCache;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl;
import org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin;
@ -53,13 +54,15 @@ public class NamespaceJdbcUserServiceTests {
@Test
public void jdbcUserService() throws Exception {
this.spring.register(DataSourceConfig.class, JdbcUserServiceConfig.class).autowire();
this.mockMvc.perform(formLogin()).andExpect(authenticated().withUsername("user"));
SecurityMockMvcResultMatchers.AuthenticatedMatcher user = authenticated().withUsername("user");
this.mockMvc.perform(formLogin()).andExpect(user);
}
@Test
public void jdbcUserServiceCustom() throws Exception {
this.spring.register(CustomDataSourceConfig.class, CustomJdbcUserServiceSampleConfig.class).autowire();
this.mockMvc.perform(formLogin()).andExpect(authenticated().withUsername("user").withRoles("DBA", "USER"));
SecurityMockMvcResultMatchers.AuthenticatedMatcher dba = authenticated().withUsername("user").withRoles("DBA", "USER");
this.mockMvc.perform(formLogin()).andExpect(dba);
}
@EnableWebSecurity

View File

@ -43,9 +43,17 @@ public class UserDetailsManagerConfigurerTests {
@Test
public void allAttributesSupported() {
UserDetails userDetails = new UserDetailsManagerConfigurer<AuthenticationManagerBuilder, InMemoryUserDetailsManagerConfigurer<AuthenticationManagerBuilder>>(
this.userDetailsManager).withUser("user").password("password").roles("USER").disabled(true)
.accountExpired(true).accountLocked(true).credentialsExpired(true).build();
// @formatter:off
UserDetails userDetails = configurer()
.withUser("user")
.password("password")
.roles("USER")
.disabled(true)
.accountExpired(true)
.accountLocked(true)
.credentialsExpired(true)
.build();
// @formatter:on
assertThat(userDetails.getUsername()).isEqualTo("user");
assertThat(userDetails.getPassword()).isEqualTo("password");
assertThat(userDetails.getAuthorities().stream().findFirst().get().getAuthority()).isEqualTo("ROLE_USER");
@ -58,26 +66,43 @@ public class UserDetailsManagerConfigurerTests {
@Test
public void authoritiesWithGrantedAuthorityWorks() {
SimpleGrantedAuthority authority = new SimpleGrantedAuthority("ROLE_USER");
UserDetails userDetails = new UserDetailsManagerConfigurer<AuthenticationManagerBuilder, InMemoryUserDetailsManagerConfigurer<AuthenticationManagerBuilder>>(
this.userDetailsManager).withUser("user").password("password").authorities(authority).build();
// @formatter:off
UserDetails userDetails = configurer()
.withUser("user")
.password("password")
.authorities(authority)
.build();
// @formatter:on
assertThat(userDetails.getAuthorities().stream().findFirst().get()).isEqualTo(authority);
}
@Test
public void authoritiesWithStringAuthorityWorks() {
String authority = "ROLE_USER";
UserDetails userDetails = new UserDetailsManagerConfigurer<AuthenticationManagerBuilder, InMemoryUserDetailsManagerConfigurer<AuthenticationManagerBuilder>>(
this.userDetailsManager).withUser("user").password("password").authorities(authority).build();
// @formatter:off
UserDetails userDetails = configurer()
.withUser("user")
.password("password")
.authorities(authority)
.build();
// @formatter:on
assertThat(userDetails.getAuthorities().stream().findFirst().get().getAuthority()).isEqualTo(authority);
}
@Test
public void authoritiesWithAListOfGrantedAuthorityWorks() {
SimpleGrantedAuthority authority = new SimpleGrantedAuthority("ROLE_USER");
UserDetails userDetails = new UserDetailsManagerConfigurer<AuthenticationManagerBuilder, InMemoryUserDetailsManagerConfigurer<AuthenticationManagerBuilder>>(
this.userDetailsManager).withUser("user").password("password").authorities(Arrays.asList(authority))
.build();
// @formatter:off
UserDetails userDetails = configurer()
.withUser("user")
.password("password")
.authorities(Arrays.asList(authority))
.build();
// @formatter:on
assertThat(userDetails.getAuthorities().stream().findFirst().get()).isEqualTo(authority);
}
private UserDetailsManagerConfigurer<AuthenticationManagerBuilder, InMemoryUserDetailsManagerConfigurer<AuthenticationManagerBuilder>> configurer() {
return new UserDetailsManagerConfigurer<AuthenticationManagerBuilder, InMemoryUserDetailsManagerConfigurer<AuthenticationManagerBuilder>>(this.userDetailsManager);
}
}

View File

@ -68,18 +68,23 @@ public class HttpSecurityHeadersTests {
// gh-3975
@Test
public void headerWhenSpringMvcResourceThenCacheRelatedHeadersReset() throws Exception {
this.mockMvc.perform(get("/resources/file.js")).andExpect(status().isOk())
// @formatter:off
this.mockMvc.perform(get("/resources/file.js"))
.andExpect(status().isOk())
.andExpect(header().string(HttpHeaders.CACHE_CONTROL, "max-age=12345"))
.andExpect(header().doesNotExist(HttpHeaders.PRAGMA))
.andExpect(header().doesNotExist(HttpHeaders.EXPIRES));
// @formatter:on
}
@Test
public void headerWhenNotSpringResourceThenCacheRelatedHeadersSet() throws Exception {
// @formatter:off
this.mockMvc.perform(get("/notresource"))
.andExpect(header().string(HttpHeaders.CACHE_CONTROL, "no-cache, no-store, max-age=0, must-revalidate"))
.andExpect(header().string(HttpHeaders.PRAGMA, "no-cache"))
.andExpect(header().string(HttpHeaders.EXPIRES, "0"));
// @formatter:on
}
@EnableWebSecurity
@ -97,8 +102,11 @@ public class HttpSecurityHeadersTests {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("classpath:/resources/")
// @formatter:off
registry.addResourceHandler("/resources/**")
.addResourceLocations("classpath:/resources/")
.setCachePeriod(12345);
// @formatter:on
}
}

View File

@ -51,6 +51,7 @@ import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.web.accept.ContentNegotiationStrategy;
import org.springframework.web.accept.HeaderContentNegotiationStrategy;
import org.springframework.web.filter.OncePerRequestFilter;
@ -83,12 +84,15 @@ public class WebSecurityConfigurerAdapterTests {
@Test
public void loadConfigWhenRequestSecureThenDefaultSecurityHeadersReturned() throws Exception {
this.spring.register(HeadersArePopulatedByDefaultConfig.class).autowire();
this.mockMvc.perform(get("/").secure(true)).andExpect(header().string("X-Content-Type-Options", "nosniff"))
// @formatter:off
this.mockMvc.perform(get("/").secure(true))
.andExpect(header().string("X-Content-Type-Options", "nosniff"))
.andExpect(header().string("X-Frame-Options", "DENY"))
.andExpect(header().string("Strict-Transport-Security", "max-age=31536000 ; includeSubDomains"))
.andExpect(header().string("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate"))
.andExpect(header().string("Pragma", "no-cache")).andExpect(header().string("Expires", "0"))
.andExpect(header().string("X-XSS-Protection", "1; mode=block"));
// @formatter:on
}
@Test
@ -188,10 +192,9 @@ public class WebSecurityConfigurerAdapterTests {
public void performWhenUsingAuthenticationEventPublisherInDslThenUses() throws Exception {
this.spring.register(CustomAuthenticationEventPublisherDsl.class).autowire();
AuthenticationEventPublisher authenticationEventPublisher = CustomAuthenticationEventPublisherDsl.EVENT_PUBLISHER;
this.mockMvc.perform(get("/").with(httpBasic("user", "password"))); // fails since
// no
// providers
// configured
MockHttpServletRequestBuilder userRequest = get("/").with(httpBasic("user", "password"));
// fails since no providers configured
this.mockMvc.perform(userRequest);
verify(authenticationEventPublisher).publishAuthenticationFailure(any(AuthenticationException.class),
any(Authentication.class));
}

View File

@ -155,8 +155,11 @@ public class NamespaceHttpTests {
public void configureWhenAuthenticationEntryPointSetAndRequestUnauthorizedThenRedirectedToAuthenticationEntryPoint()
throws Exception {
this.spring.register(EntryPointRefConfig.class).autowire();
this.mockMvc.perform(get("/")).andExpect(status().is3xxRedirection())
// @formatter:off
this.mockMvc.perform(get("/"))
.andExpect(status().is3xxRedirection())
.andExpect(redirectedUrlPattern("**/entry-point"));
// @formatter:on
}
@Test // http@jaas-api-provision
@ -174,8 +177,11 @@ public class NamespaceHttpTests {
@Test // http@realm
public void configureWhenHttpBasicAndRequestUnauthorizedThenReturnWWWAuthenticateWithRealm() throws Exception {
this.spring.register(RealmConfig.class).autowire();
this.mockMvc.perform(get("/")).andExpect(status().isUnauthorized())
// @formatter:off
this.mockMvc.perform(get("/"))
.andExpect(status().isUnauthorized())
.andExpect(header().string("WWW-Authenticate", "Basic realm=\"RealmConfig\""));
// @formatter:on
}
@Test // http@request-matcher-ref ant

View File

@ -68,7 +68,11 @@ public class AuthenticationPrincipalArgumentResolverTests {
new UsernamePasswordAuthenticationToken(user, user.getPassword(), user.getAuthorities()));
SecurityContextHolder.setContext(context);
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
mockMvc.perform(get("/users/self")).andExpect(status().isOk()).andExpect(content().string("extracted-user"));
// @formatter:off
mockMvc.perform(get("/users/self"))
.andExpect(status().isOk())
.andExpect(content().string("extracted-user"));
// @formatter:on
}
@EnableWebSecurity

View File

@ -41,6 +41,7 @@ import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@ -81,6 +82,7 @@ public class HttpSecurityConfigurationTests {
@Test
public void getWhenDefaultFilterChainBeanThenDefaultHeadersInResponse() throws Exception {
this.spring.register(DefaultWithFilterChainConfig.class).autowire();
// @formatter:off
MvcResult mvcResult = this.mockMvc.perform(get("/").secure(true))
.andExpect(header().string(HttpHeaders.X_CONTENT_TYPE_OPTIONS, "nosniff"))
.andExpect(header().string(HttpHeaders.X_FRAME_OPTIONS,
@ -90,7 +92,9 @@ public class HttpSecurityConfigurationTests {
.andExpect(header().string(HttpHeaders.CACHE_CONTROL, "no-cache, no-store, max-age=0, must-revalidate"))
.andExpect(header().string(HttpHeaders.EXPIRES, "0"))
.andExpect(header().string(HttpHeaders.PRAGMA, "no-cache"))
.andExpect(header().string(HttpHeaders.X_XSS_PROTECTION, "1; mode=block")).andReturn();
.andExpect(header().string(HttpHeaders.X_XSS_PROTECTION, "1; mode=block"))
.andReturn();
// @formatter:on
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactlyInAnyOrder(
HttpHeaders.X_CONTENT_TYPE_OPTIONS, HttpHeaders.X_FRAME_OPTIONS, HttpHeaders.STRICT_TRANSPORT_SECURITY,
HttpHeaders.CACHE_CONTROL, HttpHeaders.EXPIRES, HttpHeaders.PRAGMA, HttpHeaders.X_XSS_PROTECTION);
@ -99,21 +103,33 @@ public class HttpSecurityConfigurationTests {
@Test
public void logoutWhenDefaultFilterChainBeanThenCreatesDefaultLogoutEndpoint() throws Exception {
this.spring.register(DefaultWithFilterChainConfig.class).autowire();
this.mockMvc.perform(post("/logout").with(csrf())).andExpect(redirectedUrl("/login?logout"));
// @formatter:off
this.mockMvc.perform(post("/logout").with(csrf()))
.andExpect(redirectedUrl("/login?logout"));
// @formatter:on
}
@Test
public void loadConfigWhenDefaultConfigThenWebAsyncManagerIntegrationFilterAdded() throws Exception {
this.spring.register(DefaultWithFilterChainConfig.class, NameController.class).autowire();
MvcResult mvcResult = this.mockMvc.perform(get("/name").with(user("Bob"))).andExpect(request().asyncStarted())
// @formatter:off
MockHttpServletRequestBuilder requestWithBob = get("/name").with(user("Bob"));
MvcResult mvcResult = this.mockMvc.perform(requestWithBob)
.andExpect(request().asyncStarted())
.andReturn();
this.mockMvc.perform(asyncDispatch(mvcResult)).andExpect(status().isOk()).andExpect(content().string("Bob"));
this.mockMvc.perform(asyncDispatch(mvcResult))
.andExpect(status().isOk())
.andExpect(content().string("Bob"));
// @formatter:on
}
@Test
public void getWhenDefaultFilterChainBeanThenAnonymousPermitted() throws Exception {
this.spring.register(AuthorizeRequestsConfig.class, UserDetailsConfig.class, BaseController.class).autowire();
this.mockMvc.perform(get("/")).andExpect(status().isOk());
// @formatter:off
this.mockMvc.perform(get("/"))
.andExpect(status().isOk());
// @formatter:on
}
@Test
@ -121,29 +137,48 @@ public class HttpSecurityConfigurationTests {
this.spring.register(SecurityEnabledConfig.class, UserDetailsConfig.class).autowire();
MockHttpSession session = new MockHttpSession();
String sessionId = session.getId();
MvcResult result = this.mockMvc.perform(
post("/login").param("username", "user").param("password", "password").session(session).with(csrf()))
.andReturn();
// @formatter:off
MockHttpServletRequestBuilder loginRequest = post("/login")
.param("username", "user")
.param("password", "password")
.session(session)
.with(csrf());
// @formatter:on
MvcResult result = this.mockMvc.perform(loginRequest).andReturn();
assertThat(result.getRequest().getSession(false).getId()).isNotEqualTo(sessionId);
}
@Test
public void authenticateWhenDefaultFilterChainBeanThenRedirectsToSavedRequest() throws Exception {
this.spring.register(SecurityEnabledConfig.class, UserDetailsConfig.class).autowire();
MockHttpSession session = (MockHttpSession) this.mockMvc.perform(get("/messages")).andReturn().getRequest()
// @formatter:off
MockHttpSession session = (MockHttpSession) this.mockMvc.perform(get("/messages"))
.andReturn()
.getRequest()
.getSession();
this.mockMvc.perform(
post("/login").param("username", "user").param("password", "password").session(session).with(csrf()))
// @formatter:on
// @formatter:off
MockHttpServletRequestBuilder loginRequest = post("/login")
.param("username", "user")
.param("password", "password")
.session(session)
.with(csrf());
// @formatter:on
// @formatter:off
this.mockMvc.perform(loginRequest)
.andExpect(redirectedUrl("http://localhost/messages"));
// @formatter:on
}
@Test
public void authenticateWhenDefaultFilterChainBeanThenRolePrefixIsSet() throws Exception {
this.spring.register(SecurityEnabledConfig.class, UserDetailsConfig.class, UserController.class).autowire();
TestingAuthenticationToken user = new TestingAuthenticationToken("user", "password", "ROLE_USER");
// @formatter:off
this.mockMvc
.perform(get("/user")
.with(authentication(new TestingAuthenticationToken("user", "password", "ROLE_USER"))))
.perform(get("/user").with(authentication(user)))
.andExpect(status().isOk());
// @formatter:on
}
@Test
@ -177,7 +212,13 @@ public class HttpSecurityConfigurationTests {
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http.authorizeRequests((authorize) -> authorize.anyRequest().permitAll()).build();
// @formatter:off
return http
.authorizeRequests((authorize) -> authorize
.anyRequest().permitAll()
)
.build();
// @formatter:on
}
}
@ -187,8 +228,14 @@ public class HttpSecurityConfigurationTests {
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http.authorizeRequests((authorize) -> authorize.anyRequest().authenticated())
.formLogin(withDefaults()).build();
// @formatter:off
return http
.authorizeRequests((authorize) -> authorize
.anyRequest().authenticated()
)
.formLogin(withDefaults())
.build();
// @formatter:on
}
}
@ -198,8 +245,13 @@ public class HttpSecurityConfigurationTests {
@Bean
UserDetailsService userDetailsService() {
UserDetails user = User.withDefaultPasswordEncoder().username("user").password("password").roles("USER")
// @formatter:off
UserDetails user = User.withDefaultPasswordEncoder()
.username("user")
.password("password")
.roles("USER")
.build();
// @formatter:on
return new InMemoryUserDetailsManager(user);
}

View File

@ -43,6 +43,7 @@ import org.springframework.security.oauth2.core.TestOAuth2AccessTokens;
import org.springframework.security.oauth2.core.endpoint.OAuth2AccessTokenResponse;
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
@ -56,6 +57,7 @@ import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.authentication;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@ -97,7 +99,7 @@ public class OAuth2ClientConfigurationTests {
this.spring.register(OAuth2AuthorizedClientArgumentResolverConfig.class).autowire();
this.mockMvc
.perform(get("/authorized-client")
.with(SecurityMockMvcRequestPostProcessors.authentication(authentication)))
.with(authentication(authentication)))
.andExpect(status().isOk()).andExpect(content().string("resolved"));
verifyZeroInteractions(accessTokenResponseClient);
}
@ -114,18 +116,26 @@ public class OAuth2ClientConfigurationTests {
ClientRegistration clientRegistration = TestClientRegistrations.clientCredentials()
.registrationId(clientRegistrationId).build();
given(clientRegistrationRepository.findByRegistrationId(clientRegistrationId)).willReturn(clientRegistration);
OAuth2AccessTokenResponse accessTokenResponse = OAuth2AccessTokenResponse.withToken("access-token-1234")
.tokenType(OAuth2AccessToken.TokenType.BEARER).expiresIn(300).build();
// @formatter:off
OAuth2AccessTokenResponse accessTokenResponse = OAuth2AccessTokenResponse
.withToken("access-token-1234")
.tokenType(OAuth2AccessToken.TokenType.BEARER)
.expiresIn(300)
.build();
// @formatter:on
given(accessTokenResponseClient.getTokenResponse(any(OAuth2ClientCredentialsGrantRequest.class)))
.willReturn(accessTokenResponse);
OAuth2AuthorizedClientArgumentResolverConfig.CLIENT_REGISTRATION_REPOSITORY = clientRegistrationRepository;
OAuth2AuthorizedClientArgumentResolverConfig.AUTHORIZED_CLIENT_REPOSITORY = authorizedClientRepository;
OAuth2AuthorizedClientArgumentResolverConfig.ACCESS_TOKEN_RESPONSE_CLIENT = accessTokenResponseClient;
this.spring.register(OAuth2AuthorizedClientArgumentResolverConfig.class).autowire();
this.mockMvc
.perform(get("/authorized-client")
.with(SecurityMockMvcRequestPostProcessors.authentication(authentication)))
.andExpect(status().isOk()).andExpect(content().string("resolved"));
MockHttpServletRequestBuilder authenticatedRequest = get("/authorized-client")
.with(authentication(authentication));
// @formatter:off
this.mockMvc.perform(authenticatedRequest)
.andExpect(status().isOk())
.andExpect(content().string("resolved"));
// @formatter:on
verify(accessTokenResponseClient, times(1)).getTokenResponse(any(OAuth2ClientCredentialsGrantRequest.class));
}
@ -150,20 +160,25 @@ public class OAuth2ClientConfigurationTests {
@Test
public void loadContextWhenClientRegistrationRepositoryRegisteredTwiceThenThrowNoUniqueBeanDefinitionException() {
// @formatter:off
assertThatExceptionOfType(Exception.class)
.isThrownBy(
() -> this.spring.register(ClientRegistrationRepositoryRegisteredTwiceConfig.class).autowire())
.withMessageContaining(
"expected single matching bean but found 2: clientRegistrationRepository1,clientRegistrationRepository2")
.withRootCauseInstanceOf(NoUniqueBeanDefinitionException.class);
// @formatter:on
}
@Test
public void loadContextWhenAccessTokenResponseClientRegisteredTwiceThenThrowNoUniqueBeanDefinitionException() {
// @formatter:off
assertThatExceptionOfType(Exception.class)
.isThrownBy(() -> this.spring.register(AccessTokenResponseClientRegisteredTwiceConfig.class).autowire())
.withRootCauseInstanceOf(NoUniqueBeanDefinitionException.class).withMessageContaining(
.withRootCauseInstanceOf(NoUniqueBeanDefinitionException.class)
.withMessageContaining(
"expected single matching bean but found 2: accessTokenResponseClient1,accessTokenResponseClient2");
// @formatter:on
}
// gh-8700
@ -184,10 +199,14 @@ public class OAuth2ClientConfigurationTests {
OAuth2AuthorizedClientManagerRegisteredConfig.AUTHORIZED_CLIENT_REPOSITORY = authorizedClientRepository;
OAuth2AuthorizedClientManagerRegisteredConfig.AUTHORIZED_CLIENT_MANAGER = authorizedClientManager;
this.spring.register(OAuth2AuthorizedClientManagerRegisteredConfig.class).autowire();
MockHttpServletRequestBuilder authenticatedRequest = get("/authorized-client")
.with(authentication(authentication));
// @formatter:off
this.mockMvc
.perform(get("/authorized-client")
.with(SecurityMockMvcRequestPostProcessors.authentication(authentication)))
.andExpect(status().isOk()).andExpect(content().string("resolved"));
.perform(authenticatedRequest)
.andExpect(status().isOk())
.andExpect(content().string("resolved"));
// @formatter:on
verify(authorizedClientManager).authorize(any());
verifyNoInteractions(clientRegistrationRepository);
verifyNoInteractions(authorizedClientRepository);

View File

@ -36,10 +36,12 @@ import org.springframework.security.oauth2.server.resource.authentication.TestBe
import org.springframework.security.oauth2.server.resource.web.reactive.function.client.ServletBearerExchangeFilterFunction;
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.reactive.function.client.WebClient;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.authentication;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@ -63,8 +65,12 @@ public class SecurityReactorContextConfigurationResourceServerTests {
public void requestWhenUsingFilterThenBearerTokenPropagated() throws Exception {
BearerTokenAuthentication authentication = TestBearerTokenAuthentications.bearer();
this.spring.register(BearerFilterConfig.class, WebServerConfig.class, Controller.class).autowire();
this.mockMvc.perform(get("/token").with(SecurityMockMvcRequestPostProcessors.authentication(authentication)))
.andExpect(status().isOk()).andExpect(content().string("Bearer token"));
MockHttpServletRequestBuilder authenticatedRequest = get("/token").with(authentication(authentication));
// @formatter:off
this.mockMvc.perform(authenticatedRequest)
.andExpect(status().isOk())
.andExpect(content().string("Bearer token"));
// @formatter:on
}
// gh-7418
@ -72,8 +78,12 @@ public class SecurityReactorContextConfigurationResourceServerTests {
public void requestWhenNotUsingFilterThenBearerTokenNotPropagated() throws Exception {
BearerTokenAuthentication authentication = TestBearerTokenAuthentications.bearer();
this.spring.register(BearerFilterlessConfig.class, WebServerConfig.class, Controller.class).autowire();
this.mockMvc.perform(get("/token").with(SecurityMockMvcRequestPostProcessors.authentication(authentication)))
.andExpect(status().isOk()).andExpect(content().string(""));
MockHttpServletRequestBuilder authenticatedRequest = get("/token").with(authentication(authentication));
// @formatter:off
this.mockMvc.perform(authenticatedRequest)
.andExpect(status().isOk())
.andExpect(content().string(""));
// @formatter:on
}
@EnableWebSecurity
@ -120,8 +130,18 @@ public class SecurityReactorContextConfigurationResourceServerTests {
@GetMapping("/token")
String token() {
return this.rest.get().uri(this.uri).retrieve().bodyToMono(String.class)
.flatMap((result) -> this.rest.get().uri(this.uri).retrieve().bodyToMono(String.class)).block();
// @formatter:off
return this.rest.get()
.uri(this.uri)
.retrieve()
.bodyToMono(String.class)
.flatMap((result) -> this.rest.get()
.uri(this.uri)
.retrieve()
.bodyToMono(String.class)
)
.block();
// @formatter:on
}
}

View File

@ -198,9 +198,11 @@ public class SecurityReactorContextConfigurationTests {
.setRequestAttributes(new ServletRequestAttributes(this.servletRequest, this.servletResponse));
SecurityContextHolder.getContext().setAuthentication(this.authentication);
ClientResponse clientResponseOk = ClientResponse.create(HttpStatus.OK).build();
// @formatter:off
ExchangeFilterFunction filter = (req, next) -> Mono.subscriberContext()
.filter((ctx) -> ctx.hasKey(SecurityReactorContextSubscriber.SECURITY_CONTEXT_ATTRIBUTES))
.map((ctx) -> ctx.get(SecurityReactorContextSubscriber.SECURITY_CONTEXT_ATTRIBUTES)).cast(Map.class)
.map((ctx) -> ctx.get(SecurityReactorContextSubscriber.SECURITY_CONTEXT_ATTRIBUTES))
.cast(Map.class)
.map((attributes) -> {
if (attributes.containsKey(HttpServletRequest.class)
&& attributes.containsKey(HttpServletResponse.class)
@ -211,6 +213,7 @@ public class SecurityReactorContextConfigurationTests {
return ClientResponse.create(HttpStatus.NOT_FOUND).build();
}
});
// @formatter:on
ClientRequest clientRequest = ClientRequest.create(HttpMethod.GET, URI.create("https://example.com")).build();
MockExchangeFunction exchange = new MockExchangeFunction();
Map<Object, Object> expectedContextAttributes = new HashMap<>();
@ -219,9 +222,14 @@ public class SecurityReactorContextConfigurationTests {
expectedContextAttributes.put(Authentication.class, this.authentication);
Mono<ClientResponse> clientResponseMono = filter.filter(clientRequest, exchange)
.flatMap((response) -> filter.filter(clientRequest, exchange));
StepVerifier.create(clientResponseMono).expectAccessibleContext()
// @formatter:off
StepVerifier.create(clientResponseMono)
.expectAccessibleContext()
.contains(SecurityReactorContextSubscriber.SECURITY_CONTEXT_ATTRIBUTES, expectedContextAttributes)
.then().expectNext(clientResponseOk).verifyComplete();
.then()
.expectNext(clientResponseOk)
.verifyComplete();
// @formatter:on
}
@EnableWebSecurity

View File

@ -336,27 +336,51 @@ public class WebSecurityConfigurationTests {
@Order(1)
@Bean
SecurityFilterChain filterChain1(HttpSecurity http) throws Exception {
return http.antMatcher("/role1/**").authorizeRequests((authorize) -> authorize.anyRequest().hasRole("1"))
// @formatter:off
return http
.antMatcher("/role1/**")
.authorizeRequests((authorize) -> authorize
.anyRequest().hasRole("1")
)
.build();
// @formatter:on
}
@Order(2)
@Bean
SecurityFilterChain filterChain2(HttpSecurity http) throws Exception {
return http.antMatcher("/role2/**").authorizeRequests((authorize) -> authorize.anyRequest().hasRole("2"))
// @formatter:off
return http
.antMatcher("/role2/**")
.authorizeRequests((authorize) -> authorize
.anyRequest().hasRole("2")
)
.build();
// @formatter:on
}
@Order(3)
@Bean
SecurityFilterChain filterChain3(HttpSecurity http) throws Exception {
return http.antMatcher("/role3/**").authorizeRequests((authorize) -> authorize.anyRequest().hasRole("3"))
// @formatter:off
return http
.antMatcher("/role3/**")
.authorizeRequests((authorize) -> authorize
.anyRequest().hasRole("3")
)
.build();
// @formatter:on
}
@Bean
SecurityFilterChain filterChain4(HttpSecurity http) throws Exception {
return http.authorizeRequests((authorize) -> authorize.anyRequest().hasRole("4")).build();
// @formatter:off
return http
.authorizeRequests((authorize) -> authorize
.anyRequest().hasRole("4")
)
.build();
// @formatter:on
}
}
@ -509,7 +533,13 @@ public class WebSecurityConfigurationTests {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http.authorizeRequests((authorize) -> authorize.anyRequest().authenticated()).build();
// @formatter:off
return http
.authorizeRequests((authorize) -> authorize
.anyRequest().authenticated()
)
.build();
// @formatter:on
}
}
@ -623,8 +653,14 @@ public class WebSecurityConfigurationTests {
@Order(2)
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http.antMatcher("/filter/**")
.authorizeRequests((authorize) -> authorize.anyRequest().authenticated()).build();
// @formatter:off
return http
.antMatcher("/filter/**")
.authorizeRequests((authorize) -> authorize
.anyRequest().authenticated()
)
.build();
// @formatter:on
}
@Order(1)
@ -633,7 +669,13 @@ public class WebSecurityConfigurationTests {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/config/**").authorizeRequests((authorize) -> authorize.anyRequest().permitAll());
// @formatter:off
http
.antMatcher("/config/**")
.authorizeRequests((authorize) -> authorize
.anyRequest().permitAll()
);
// @formatter:on
}
}

View File

@ -46,6 +46,7 @@ import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
@ -288,8 +289,13 @@ public class CsrfConfigurerTests {
given(CsrfTokenRepositoryConfig.REPO.loadToken(any())).willReturn(csrfToken);
given(CsrfTokenRepositoryConfig.REPO.generateToken(any())).willReturn(csrfToken);
this.spring.register(CsrfTokenRepositoryConfig.class, BasicController.class).autowire();
this.mvc.perform(post("/login").with(csrf()).param("username", "user").param("password", "password"))
.andExpect(redirectedUrl("/"));
// @formatter:off
MockHttpServletRequestBuilder loginRequest = post("/login")
.with(csrf())
.param("username", "user")
.param("password", "password");
// @formatter:on
this.mvc.perform(loginRequest).andExpect(redirectedUrl("/"));
verify(CsrfTokenRepositoryConfig.REPO).saveToken(isNull(), any(HttpServletRequest.class),
any(HttpServletResponse.class));
}
@ -316,28 +322,40 @@ public class CsrfConfigurerTests {
@Test
public void loginWhenNoCsrfTokenThenRespondsWithForbidden() throws Exception {
this.spring.register(FormLoginConfig.class).autowire();
this.mvc.perform(post("/login").param("username", "user").param("password", "password"))
.andExpect(status().isForbidden()).andExpect(unauthenticated());
// @formatter:off
MockHttpServletRequestBuilder loginRequest = post("/login")
.param("username", "user")
.param("password", "password");
this.mvc.perform(loginRequest)
.andExpect(status().isForbidden())
.andExpect(unauthenticated());
// @formatter:on
}
@Test
public void logoutWhenNoCsrfTokenThenRespondsWithForbidden() throws Exception {
this.spring.register(FormLoginConfig.class).autowire();
this.mvc.perform(post("/logout").with(user("username"))).andExpect(status().isForbidden())
MockHttpServletRequestBuilder logoutRequest = post("/logout").with(user("username"));
// @formatter:off
this.mvc.perform(logoutRequest)
.andExpect(status().isForbidden())
.andExpect(authenticated());
// @formatter:on
}
// SEC-2543
@Test
public void logoutWhenCsrfEnabledAndGetRequestThenDoesNotLogout() throws Exception {
this.spring.register(FormLoginConfig.class).autowire();
this.mvc.perform(get("/logout").with(user("username"))).andExpect(authenticated());
MockHttpServletRequestBuilder logoutRequest = get("/logout").with(user("username"));
this.mvc.perform(logoutRequest).andExpect(authenticated());
}
@Test
public void logoutWhenGetRequestAndGetEnabledForLogoutThenLogsOut() throws Exception {
this.spring.register(LogoutAllowsGetConfig.class).autowire();
this.mvc.perform(get("/logout").with(user("username"))).andExpect(unauthenticated());
MockHttpServletRequestBuilder logoutRequest = get("/logout").with(user("username"));
this.mvc.perform(logoutRequest).andExpect(unauthenticated());
}
// SEC-2749
@ -366,8 +384,13 @@ public class CsrfConfigurerTests {
public void csrfAuthenticationStrategyConfiguredThenStrategyUsed() throws Exception {
CsrfAuthenticationStrategyConfig.STRATEGY = mock(SessionAuthenticationStrategy.class);
this.spring.register(CsrfAuthenticationStrategyConfig.class).autowire();
this.mvc.perform(post("/login").with(csrf()).param("username", "user").param("password", "password"))
.andExpect(redirectedUrl("/"));
// @formatter:off
MockHttpServletRequestBuilder loginRequest = post("/login")
.with(csrf())
.param("username", "user")
.param("password", "password");
// @formatter:on
this.mvc.perform(loginRequest).andExpect(redirectedUrl("/"));
verify(CsrfAuthenticationStrategyConfig.STRATEGY, atLeastOnce()).onAuthentication(any(Authentication.class),
any(HttpServletRequest.class), any(HttpServletResponse.class));
}

View File

@ -40,6 +40,7 @@ import org.springframework.security.web.csrf.DefaultCsrfToken;
import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
@ -76,26 +77,37 @@ public class DefaultLoginPageConfigurerTests {
this.spring.register(DefaultLoginPageConfig.class).autowire();
CsrfToken csrfToken = new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "BaseSpringSpec_CSRFTOKEN");
String csrfAttributeName = HttpSessionCsrfTokenRepository.class.getName().concat(".CSRF_TOKEN");
// @formatter:off
this.mvc.perform(get("/login").sessionAttr(csrfAttributeName, csrfToken))
.andExpect(content().string("<!DOCTYPE html>\n" + "<html lang=\"en\">\n" + " <head>\n"
.andExpect(content().string("<!DOCTYPE html>\n"
+ "<html lang=\"en\">\n"
+ " <head>\n"
+ " <meta charset=\"utf-8\">\n"
+ " <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\n"
+ " <meta name=\"description\" content=\"\">\n" + " <meta name=\"author\" content=\"\">\n"
+ " <meta name=\"description\" content=\"\">\n"
+ " <meta name=\"author\" content=\"\">\n"
+ " <title>Please sign in</title>\n"
+ " <link href=\"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css\" rel=\"stylesheet\" integrity=\"sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M\" crossorigin=\"anonymous\">\n"
+ " <link href=\"https://getbootstrap.com/docs/4.0/examples/signin/signin.css\" rel=\"stylesheet\" crossorigin=\"anonymous\"/>\n"
+ " </head>\n" + " <body>\n" + " <div class=\"container\">\n"
+ " </head>\n"
+ " <body>\n"
+ " <div class=\"container\">\n"
+ " <form class=\"form-signin\" method=\"post\" action=\"/login\">\n"
+ " <h2 class=\"form-signin-heading\">Please sign in</h2>\n" + " <p>\n"
+ " <h2 class=\"form-signin-heading\">Please sign in</h2>\n"
+ " <p>\n"
+ " <label for=\"username\" class=\"sr-only\">Username</label>\n"
+ " <input type=\"text\" id=\"username\" name=\"username\" class=\"form-control\" placeholder=\"Username\" required autofocus>\n"
+ " </p>\n" + " <p>\n"
+ " </p>\n"
+ " <p>\n"
+ " <label for=\"password\" class=\"sr-only\">Password</label>\n"
+ " <input type=\"password\" id=\"password\" name=\"password\" class=\"form-control\" placeholder=\"Password\" required>\n"
+ " </p>\n" + "<input name=\"" + csrfToken.getParameterName()
+ "\" type=\"hidden\" value=\"" + csrfToken.getToken() + "\" />\n"
+ " </p>\n"
+ "<input name=\""+ csrfToken.getParameterName() + "\" type=\"hidden\" value=\"" + csrfToken.getToken() + "\" />\n"
+ " <button class=\"btn btn-lg btn-primary btn-block\" type=\"submit\">Sign in</button>\n"
+ " </form>\n" + "</div>\n" + "</body></html>"));
+ " </form>\n"
+ "</div>\n"
+ "</body></html>"));
// @formatter:on
}
@Test
@ -110,16 +122,22 @@ public class DefaultLoginPageConfigurerTests {
CsrfToken csrfToken = new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "BaseSpringSpec_CSRFTOKEN");
String csrfAttributeName = HttpSessionCsrfTokenRepository.class.getName().concat(".CSRF_TOKEN");
MvcResult mvcResult = this.mvc.perform(post("/login").with(csrf())).andReturn();
// @formatter:off
this.mvc.perform(get("/login?error").session((MockHttpSession) mvcResult.getRequest().getSession())
.sessionAttr(csrfAttributeName, csrfToken))
.andExpect(content().string("<!DOCTYPE html>\n" + "<html lang=\"en\">\n" + " <head>\n"
.andExpect(content().string("<!DOCTYPE html>\n"
+ "<html lang=\"en\">\n"
+ " <head>\n"
+ " <meta charset=\"utf-8\">\n"
+ " <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\n"
+ " <meta name=\"description\" content=\"\">\n" + " <meta name=\"author\" content=\"\">\n"
+ " <meta name=\"description\" content=\"\">\n"
+ " <meta name=\"author\" content=\"\">\n"
+ " <title>Please sign in</title>\n"
+ " <link href=\"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css\" rel=\"stylesheet\" integrity=\"sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M\" crossorigin=\"anonymous\">\n"
+ " <link href=\"https://getbootstrap.com/docs/4.0/examples/signin/signin.css\" rel=\"stylesheet\" crossorigin=\"anonymous\"/>\n"
+ " </head>\n" + " <body>\n" + " <div class=\"container\">\n"
+ " </head>\n"
+ " <body>\n"
+ " <div class=\"container\">\n"
+ " <form class=\"form-signin\" method=\"post\" action=\"/login\">\n"
+ " <h2 class=\"form-signin-heading\">Please sign in</h2>\n"
+ "<div class=\"alert alert-danger\" role=\"alert\">Bad credentials</div> <p>\n"
@ -128,17 +146,25 @@ public class DefaultLoginPageConfigurerTests {
+ " </p>\n" + " <p>\n"
+ " <label for=\"password\" class=\"sr-only\">Password</label>\n"
+ " <input type=\"password\" id=\"password\" name=\"password\" class=\"form-control\" placeholder=\"Password\" required>\n"
+ " </p>\n" + "<input name=\"" + csrfToken.getParameterName()
+ "\" type=\"hidden\" value=\"" + csrfToken.getToken() + "\" />\n"
+ " </p>\n"
+ "<input name=\"" + csrfToken.getParameterName() + "\" type=\"hidden\" value=\"" + csrfToken.getToken() + "\" />\n"
+ " <button class=\"btn btn-lg btn-primary btn-block\" type=\"submit\">Sign in</button>\n"
+ " </form>\n" + "</div>\n" + "</body></html>"));
+ " </form>\n"
+ "</div>\n"
+ "</body></html>"));
// @formatter:on
}
@Test
public void loginWhenValidCredentialsThenRedirectsToDefaultSuccessPage() throws Exception {
this.spring.register(DefaultLoginPageConfig.class).autowire();
this.mvc.perform(post("/login").with(csrf()).param("username", "user").param("password", "password"))
.andExpect(redirectedUrl("/"));
// @formatter:off
MockHttpServletRequestBuilder loginRequest = post("/login")
.with(csrf())
.param("username", "user")
.param("password", "password");
// @formatter:on
this.mvc.perform(loginRequest).andExpect(redirectedUrl("/"));
}
@Test
@ -146,27 +172,37 @@ public class DefaultLoginPageConfigurerTests {
this.spring.register(DefaultLoginPageConfig.class).autowire();
CsrfToken csrfToken = new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "BaseSpringSpec_CSRFTOKEN");
String csrfAttributeName = HttpSessionCsrfTokenRepository.class.getName().concat(".CSRF_TOKEN");
// @formatter:off
this.mvc.perform(get("/login?logout").sessionAttr(csrfAttributeName, csrfToken))
.andExpect(content().string("<!DOCTYPE html>\n" + "<html lang=\"en\">\n" + " <head>\n"
.andExpect(content().string("<!DOCTYPE html>\n"
+ "<html lang=\"en\">\n"
+ " <head>\n"
+ " <meta charset=\"utf-8\">\n"
+ " <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\n"
+ " <meta name=\"description\" content=\"\">\n" + " <meta name=\"author\" content=\"\">\n"
+ " <meta name=\"description\" content=\"\">\n"
+ " <meta name=\"author\" content=\"\">\n"
+ " <title>Please sign in</title>\n"
+ " <link href=\"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css\" rel=\"stylesheet\" integrity=\"sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M\" crossorigin=\"anonymous\">\n"
+ " <link href=\"https://getbootstrap.com/docs/4.0/examples/signin/signin.css\" rel=\"stylesheet\" crossorigin=\"anonymous\"/>\n"
+ " </head>\n" + " <body>\n" + " <div class=\"container\">\n"
+ " </head>\n"
+ " <body>\n"
+ " <div class=\"container\">\n"
+ " <form class=\"form-signin\" method=\"post\" action=\"/login\">\n"
+ " <h2 class=\"form-signin-heading\">Please sign in</h2>\n"
+ "<div class=\"alert alert-success\" role=\"alert\">You have been signed out</div> <p>\n"
+ " <label for=\"username\" class=\"sr-only\">Username</label>\n"
+ " <input type=\"text\" id=\"username\" name=\"username\" class=\"form-control\" placeholder=\"Username\" required autofocus>\n"
+ " </p>\n" + " <p>\n"
+ " </p>\n"
+ " <p>\n"
+ " <label for=\"password\" class=\"sr-only\">Password</label>\n"
+ " <input type=\"password\" id=\"password\" name=\"password\" class=\"form-control\" placeholder=\"Password\" required>\n"
+ " </p>\n" + "<input name=\"" + csrfToken.getParameterName()
+ "\" type=\"hidden\" value=\"" + csrfToken.getToken() + "\" />\n"
+ " </p>\n"
+ "<input name=\"" + csrfToken.getParameterName() + "\" type=\"hidden\" value=\"" + csrfToken.getToken() + "\" />\n"
+ " <button class=\"btn btn-lg btn-primary btn-block\" type=\"submit\">Sign in</button>\n"
+ " </form>\n" + "</div>\n" + "</body></html>"));
+ " </form>\n"
+ "</div>\n"
+ "</body></html>"));
// @formatter:on
}
@Test
@ -186,28 +222,38 @@ public class DefaultLoginPageConfigurerTests {
this.spring.register(DefaultLoginPageWithRememberMeConfig.class).autowire();
CsrfToken csrfToken = new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "BaseSpringSpec_CSRFTOKEN");
String csrfAttributeName = HttpSessionCsrfTokenRepository.class.getName().concat(".CSRF_TOKEN");
// @formatter:off
this.mvc.perform(get("/login").sessionAttr(csrfAttributeName, csrfToken))
.andExpect(content().string("<!DOCTYPE html>\n" + "<html lang=\"en\">\n" + " <head>\n"
.andExpect(content().string("<!DOCTYPE html>\n"
+ "<html lang=\"en\">\n"
+ " <head>\n"
+ " <meta charset=\"utf-8\">\n"
+ " <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\n"
+ " <meta name=\"description\" content=\"\">\n" + " <meta name=\"author\" content=\"\">\n"
+ " <meta name=\"description\" content=\"\">\n"
+ " <meta name=\"author\" content=\"\">\n"
+ " <title>Please sign in</title>\n"
+ " <link href=\"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css\" rel=\"stylesheet\" integrity=\"sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M\" crossorigin=\"anonymous\">\n"
+ " <link href=\"https://getbootstrap.com/docs/4.0/examples/signin/signin.css\" rel=\"stylesheet\" crossorigin=\"anonymous\"/>\n"
+ " </head>\n" + " <body>\n" + " <div class=\"container\">\n"
+ " </head>\n"
+ " <body>\n"
+ " <div class=\"container\">\n"
+ " <form class=\"form-signin\" method=\"post\" action=\"/login\">\n"
+ " <h2 class=\"form-signin-heading\">Please sign in</h2>\n" + " <p>\n"
+ " <h2 class=\"form-signin-heading\">Please sign in</h2>\n"
+ " <p>\n"
+ " <label for=\"username\" class=\"sr-only\">Username</label>\n"
+ " <input type=\"text\" id=\"username\" name=\"username\" class=\"form-control\" placeholder=\"Username\" required autofocus>\n"
+ " </p>\n" + " <p>\n"
+ " </p>\n"
+ " <p>\n"
+ " <label for=\"password\" class=\"sr-only\">Password</label>\n"
+ " <input type=\"password\" id=\"password\" name=\"password\" class=\"form-control\" placeholder=\"Password\" required>\n"
+ " </p>\n"
+ "<p><input type='checkbox' name='remember-me'/> Remember me on this computer.</p>\n"
+ "<input name=\"" + csrfToken.getParameterName() + "\" type=\"hidden\" value=\""
+ csrfToken.getToken() + "\" />\n"
+ "<input name=\"" + csrfToken.getParameterName() + "\" type=\"hidden\" value=\"" + csrfToken.getToken() + "\" />\n"
+ " <button class=\"btn btn-lg btn-primary btn-block\" type=\"submit\">Sign in</button>\n"
+ " </form>\n" + "</div>\n" + "</body></html>"));
+ " </form>\n"
+ "</div>\n"
+ "</body></html>"));
// @formatter:on
}
@Test
@ -215,23 +261,33 @@ public class DefaultLoginPageConfigurerTests {
this.spring.register(DefaultLoginPageWithOpenIDConfig.class).autowire();
CsrfToken csrfToken = new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "BaseSpringSpec_CSRFTOKEN");
String csrfAttributeName = HttpSessionCsrfTokenRepository.class.getName().concat(".CSRF_TOKEN");
// @formatter:off
this.mvc.perform(get("/login").sessionAttr(csrfAttributeName, csrfToken))
.andExpect(content().string("<!DOCTYPE html>\n" + "<html lang=\"en\">\n" + " <head>\n"
.andExpect(content().string("<!DOCTYPE html>\n"
+ "<html lang=\"en\">\n"
+ " <head>\n"
+ " <meta charset=\"utf-8\">\n"
+ " <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\n"
+ " <meta name=\"description\" content=\"\">\n" + " <meta name=\"author\" content=\"\">\n"
+ " <meta name=\"description\" content=\"\">\n"
+ " <meta name=\"author\" content=\"\">\n"
+ " <title>Please sign in</title>\n"
+ " <link href=\"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css\" rel=\"stylesheet\" integrity=\"sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M\" crossorigin=\"anonymous\">\n"
+ " <link href=\"https://getbootstrap.com/docs/4.0/examples/signin/signin.css\" rel=\"stylesheet\" crossorigin=\"anonymous\"/>\n"
+ " </head>\n" + " <body>\n" + " <div class=\"container\">\n"
+ " </head>\n"
+ " <body>\n"
+ " <div class=\"container\">\n"
+ " <form name=\"oidf\" class=\"form-signin\" method=\"post\" action=\"/login/openid\">\n"
+ " <h2 class=\"form-signin-heading\">Login with OpenID Identity</h2>\n"
+ " <p>\n" + " <label for=\"username\" class=\"sr-only\">Identity</label>\n"
+ " <p>\n"
+ " <label for=\"username\" class=\"sr-only\">Identity</label>\n"
+ " <input type=\"text\" id=\"username\" name=\"openid_identifier\" class=\"form-control\" placeholder=\"Username\" required autofocus>\n"
+ " </p>\n" + "<input name=\"" + csrfToken.getParameterName()
+ "\" type=\"hidden\" value=\"" + csrfToken.getToken() + "\" />\n"
+ " </p>\n"
+ "<input name=\"" + csrfToken.getParameterName() + "\" type=\"hidden\" value=\"" + csrfToken.getToken() + "\" />\n"
+ " <button class=\"btn btn-lg btn-primary btn-block\" type=\"submit\">Sign in</button>\n"
+ " </form>\n" + "</div>\n" + "</body></html>"));
+ " </form>\n"
+ "</div>\n"
+ "</body></html>"));
// @formatter:on
}
@Test
@ -240,37 +296,45 @@ public class DefaultLoginPageConfigurerTests {
CsrfToken csrfToken = new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "BaseSpringSpec_CSRFTOKEN");
String csrfAttributeName = HttpSessionCsrfTokenRepository.class.getName().concat(".CSRF_TOKEN");
this.mvc.perform(get("/login").sessionAttr(csrfAttributeName, csrfToken))
.andExpect(content().string("<!DOCTYPE html>\n" + "<html lang=\"en\">\n" + " <head>\n"
.andExpect(content().string("<!DOCTYPE html>\n"
+ "<html lang=\"en\">\n"
+ " <head>\n"
+ " <meta charset=\"utf-8\">\n"
+ " <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\n"
+ " <meta name=\"description\" content=\"\">\n" + " <meta name=\"author\" content=\"\">\n"
+ " <meta name=\"description\" content=\"\">\n"
+ " <meta name=\"author\" content=\"\">\n"
+ " <title>Please sign in</title>\n"
+ " <link href=\"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css\" rel=\"stylesheet\" integrity=\"sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M\" crossorigin=\"anonymous\">\n"
+ " <link href=\"https://getbootstrap.com/docs/4.0/examples/signin/signin.css\" rel=\"stylesheet\" crossorigin=\"anonymous\"/>\n"
+ " </head>\n" + " <body>\n" + " <div class=\"container\">\n"
+ " </head>\n"
+ " <body>\n"
+ " <div class=\"container\">\n"
+ " <form class=\"form-signin\" method=\"post\" action=\"/login\">\n"
+ " <h2 class=\"form-signin-heading\">Please sign in</h2>\n" + " <p>\n"
+ " <h2 class=\"form-signin-heading\">Please sign in</h2>\n"
+ " <p>\n"
+ " <label for=\"username\" class=\"sr-only\">Username</label>\n"
+ " <input type=\"text\" id=\"username\" name=\"username\" class=\"form-control\" placeholder=\"Username\" required autofocus>\n"
+ " </p>\n" + " <p>\n"
+ " </p>\n"
+ " <p>\n"
+ " <label for=\"password\" class=\"sr-only\">Password</label>\n"
+ " <input type=\"password\" id=\"password\" name=\"password\" class=\"form-control\" placeholder=\"Password\" required>\n"
+ " </p>\n"
+ "<p><input type='checkbox' name='remember-me'/> Remember me on this computer.</p>\n"
+ "<input name=\"" + csrfToken.getParameterName() + "\" type=\"hidden\" value=\""
+ csrfToken.getToken() + "\" />\n"
+ "<input name=\"" + csrfToken.getParameterName() + "\" type=\"hidden\" value=\"" + csrfToken.getToken() + "\" />\n"
+ " <button class=\"btn btn-lg btn-primary btn-block\" type=\"submit\">Sign in</button>\n"
+ " </form>\n"
+ " <form name=\"oidf\" class=\"form-signin\" method=\"post\" action=\"/login/openid\">\n"
+ " <h2 class=\"form-signin-heading\">Login with OpenID Identity</h2>\n"
+ " <p>\n" + " <label for=\"username\" class=\"sr-only\">Identity</label>\n"
+ " <p>\n"
+ " <label for=\"username\" class=\"sr-only\">Identity</label>\n"
+ " <input type=\"text\" id=\"username\" name=\"openid_identifier\" class=\"form-control\" placeholder=\"Username\" required autofocus>\n"
+ " </p>\n"
+ "<p><input type='checkbox' name='remember-me'/> Remember me on this computer.</p>\n"
+ "<input name=\"" + csrfToken.getParameterName() + "\" type=\"hidden\" value=\""
+ csrfToken.getToken() + "\" />\n"
+ "<input name=\"" + csrfToken.getParameterName() + "\" type=\"hidden\" value=\"" + csrfToken.getToken() + "\" />\n"
+ " <button class=\"btn btn-lg btn-primary btn-block\" type=\"submit\">Sign in</button>\n"
+ " </form>\n" + "</div>\n" + "</body></html>"));
+ " </form>\n"
+ "</div>\n"
+ "</body></html>"));
}
@Test

View File

@ -322,8 +322,14 @@ public class ExceptionHandlingConfigurerTests {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:on
http.authorizeRequests().anyRequest().authenticated().and().exceptionHandling()
.authenticationEntryPoint(AEP).and().exceptionHandling();
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.exceptionHandling()
.authenticationEntryPoint(AEP)
.and()
.exceptionHandling();
// @formatter:off
}
}

View File

@ -51,6 +51,7 @@ import org.springframework.security.web.access.expression.WebExpressionVoter;
import org.springframework.security.web.access.expression.WebSecurityExpressionRoot;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
@ -113,16 +114,24 @@ public class ExpressionUrlAuthorizationConfigurerTests {
@Test
public void getWhenHasAnyAuthorityRoleUserConfiguredAndAuthorityIsRoleUserThenRespondsWithOk() throws Exception {
this.spring.register(RoleUserAnyAuthorityConfig.class, BasicController.class).autowire();
this.mvc.perform(get("/").with(user("user").authorities(new SimpleGrantedAuthority("ROLE_USER"))))
.andExpect(status().isOk());
// @formatter:off
MockHttpServletRequestBuilder requestWithUser = get("/")
.with(user("user")
.authorities(new SimpleGrantedAuthority("ROLE_USER")));
// @formatter:on
this.mvc.perform(requestWithUser).andExpect(status().isOk());
}
@Test
public void getWhenHasAnyAuthorityRoleUserConfiguredAndAuthorityIsRoleAdminThenRespondsWithForbidden()
throws Exception {
this.spring.register(RoleUserAnyAuthorityConfig.class, BasicController.class).autowire();
this.mvc.perform(get("/").with(user("user").authorities(new SimpleGrantedAuthority("ROLE_ADMIN"))))
.andExpect(status().isForbidden());
// @formatter:off
MockHttpServletRequestBuilder requestWithAdmin = get("/")
.with(user("user")
.authorities(new SimpleGrantedAuthority("ROLE_ADMIN")));
// @formatter:on
this.mvc.perform(requestWithAdmin).andExpect(status().isForbidden());
}
@Test
@ -134,16 +143,24 @@ public class ExpressionUrlAuthorizationConfigurerTests {
@Test
public void getWhenHasAuthorityRoleUserConfiguredAndAuthorityIsRoleUserThenRespondsWithOk() throws Exception {
this.spring.register(RoleUserAuthorityConfig.class, BasicController.class).autowire();
this.mvc.perform(get("/").with(user("user").authorities(new SimpleGrantedAuthority("ROLE_USER"))))
.andExpect(status().isOk());
// @formatter:off
MockHttpServletRequestBuilder requestWithUser = get("/")
.with(user("user")
.authorities(new SimpleGrantedAuthority("ROLE_USER")));
// @formatter:on
this.mvc.perform(requestWithUser).andExpect(status().isOk());
}
@Test
public void getWhenHasAuthorityRoleUserConfiguredAndAuthorityIsRoleAdminThenRespondsWithForbidden()
throws Exception {
this.spring.register(RoleUserAuthorityConfig.class, BasicController.class).autowire();
this.mvc.perform(get("/").with(user("user").authorities(new SimpleGrantedAuthority("ROLE_ADMIN"))))
.andExpect(status().isForbidden());
// @formatter:off
MockHttpServletRequestBuilder requestWithAdmin = get("/")
.with(user("user")
.authorities(new SimpleGrantedAuthority("ROLE_ADMIN")));
// @formatter:on
this.mvc.perform(requestWithAdmin).andExpect(status().isForbidden());
}
@Test
@ -155,22 +172,35 @@ public class ExpressionUrlAuthorizationConfigurerTests {
@Test
public void getWhenAuthorityRoleUserOrAdminRequiredAndAuthorityIsRoleUserThenRespondsWithOk() throws Exception {
this.spring.register(RoleUserOrRoleAdminAuthorityConfig.class, BasicController.class).autowire();
this.mvc.perform(get("/").with(user("user").authorities(new SimpleGrantedAuthority("ROLE_USER"))))
.andExpect(status().isOk());
// @formatter:off
MockHttpServletRequestBuilder requestWithUser = get("/")
.with(user("user")
.authorities(new SimpleGrantedAuthority("ROLE_USER")));
// @formatter:on
this.mvc.perform(requestWithUser).andExpect(status().isOk());
}
@Test
public void getWhenAuthorityRoleUserOrAdminRequiredAndAuthorityIsRoleAdminThenRespondsWithOk() throws Exception {
this.spring.register(RoleUserOrRoleAdminAuthorityConfig.class, BasicController.class).autowire();
this.mvc.perform(get("/").with(user("user").authorities(new SimpleGrantedAuthority("ROLE_ADMIN"))))
.andExpect(status().isOk());
// @formatter:off
MockHttpServletRequestBuilder requestWithUser = get("/")
.with(user("user")
.authorities(new SimpleGrantedAuthority("ROLE_ADMIN")));
// @formatter:on
this.mvc.perform(requestWithUser).andExpect(status().isOk());
}
@Test
public void getWhenAuthorityRoleUserOrAdminRequiredAndAuthorityIsRoleOtherThenRespondsWithForbidden()
throws Exception {
this.spring.register(RoleUserOrRoleAdminAuthorityConfig.class, BasicController.class).autowire();
this.mvc.perform(get("/").with(user("user").authorities(new SimpleGrantedAuthority("ROLE_OTHER"))))
// @formatter:off
MockHttpServletRequestBuilder requestWithUser = get("/")
.with(user("user")
.authorities(new SimpleGrantedAuthority("ROLE_OTHER")));
// @formatter:on
this.mvc.perform(requestWithUser)
.andExpect(status().isForbidden());
}
@ -183,31 +213,56 @@ public class ExpressionUrlAuthorizationConfigurerTests {
@Test
public void getWhenHasAnyRoleUserConfiguredAndRoleIsUserThenRespondsWithOk() throws Exception {
this.spring.register(RoleUserConfig.class, BasicController.class).autowire();
this.mvc.perform(get("/").with(user("user").roles("USER"))).andExpect(status().isOk());
// @formatter:off
MockHttpServletRequestBuilder requestWithUser = get("/")
.with(user("user")
.roles("USER"));
// @formatter:on
this.mvc.perform(requestWithUser).andExpect(status().isOk());
}
@Test
public void getWhenHasAnyRoleUserConfiguredAndRoleIsAdminThenRespondsWithForbidden() throws Exception {
this.spring.register(RoleUserConfig.class, BasicController.class).autowire();
this.mvc.perform(get("/").with(user("user").roles("ADMIN"))).andExpect(status().isForbidden());
// @formatter:off
MockHttpServletRequestBuilder requestWithAdmin = get("/")
.with(user("user")
.roles("ADMIN"));
// @formatter:on
this.mvc.perform(requestWithAdmin).andExpect(status().isForbidden());
}
@Test
public void getWhenRoleUserOrAdminConfiguredAndRoleIsUserThenRespondsWithOk() throws Exception {
this.spring.register(RoleUserOrAdminConfig.class, BasicController.class).autowire();
this.mvc.perform(get("/").with(user("user").roles("USER"))).andExpect(status().isOk());
// @formatter:off
MockHttpServletRequestBuilder requestWithUser = get("/")
.with(user("user")
.roles("USER"));
// @formatter:on
this.mvc.perform(requestWithUser).andExpect(status().isOk());
}
@Test
public void getWhenRoleUserOrAdminConfiguredAndRoleIsAdminThenRespondsWithOk() throws Exception {
this.spring.register(RoleUserOrAdminConfig.class, BasicController.class).autowire();
this.mvc.perform(get("/").with(user("user").roles("ADMIN"))).andExpect(status().isOk());
// @formatter:off
MockHttpServletRequestBuilder requestWithAdmin = get("/")
.with(user("user")
.roles("ADMIN"));
// @formatter:on
this.mvc.perform(requestWithAdmin).andExpect(status().isOk());
}
@Test
public void getWhenRoleUserOrAdminConfiguredAndRoleIsOtherThenRespondsWithForbidden() throws Exception {
this.spring.register(RoleUserOrAdminConfig.class, BasicController.class).autowire();
this.mvc.perform(get("/").with(user("user").roles("OTHER"))).andExpect(status().isForbidden());
//<editor-fold desc="Description">
MockHttpServletRequestBuilder requestWithRoleOther = get("/")
.with(user("user")
.roles("OTHER"));
//</editor-fold>
this.mvc.perform(requestWithRoleOther).andExpect(status().isForbidden());
}
@Test
@ -237,7 +292,8 @@ public class ExpressionUrlAuthorizationConfigurerTests {
@Test
public void getWhenAnonymousConfiguredAndLoggedInUserThenRespondsWithForbidden() throws Exception {
this.spring.register(AnonymousConfig.class, BasicController.class).autowire();
this.mvc.perform(get("/").with(user("user"))).andExpect(status().isForbidden());
MockHttpServletRequestBuilder requestWithUser = get("/").with(user("user"));
this.mvc.perform(requestWithUser).andExpect(status().isForbidden());
}
@Test
@ -249,9 +305,9 @@ public class ExpressionUrlAuthorizationConfigurerTests {
@Test
public void getWhenRememberMeConfiguredAndRememberMeTokenThenRespondsWithOk() throws Exception {
this.spring.register(RememberMeConfig.class, BasicController.class).autowire();
this.mvc.perform(get("/").with(authentication(
new RememberMeAuthenticationToken("key", "user", AuthorityUtils.createAuthorityList("ROLE_USER")))))
.andExpect(status().isOk());
RememberMeAuthenticationToken rememberme = new RememberMeAuthenticationToken("key", "user", AuthorityUtils.createAuthorityList("ROLE_USER"));
MockHttpServletRequestBuilder requestWithRememberme = get("/").with(authentication(rememberme));
this.mvc.perform(requestWithRememberme).andExpect(status().isOk());
}
@Test
@ -263,7 +319,8 @@ public class ExpressionUrlAuthorizationConfigurerTests {
@Test
public void getWheDenyAllConfiguredAndUserLoggedInThenRespondsWithForbidden() throws Exception {
this.spring.register(DenyAllConfig.class, BasicController.class).autowire();
this.mvc.perform(get("/").with(user("user").roles("USER"))).andExpect(status().isForbidden());
MockHttpServletRequestBuilder requestWithUser = get("/").with(user("user").roles("USER"));
this.mvc.perform(requestWithUser).andExpect(status().isForbidden());
}
@Test
@ -275,23 +332,24 @@ public class ExpressionUrlAuthorizationConfigurerTests {
@Test
public void getWhenNotDenyAllConfiguredAndRememberMeTokenThenRespondsWithOk() throws Exception {
this.spring.register(NotDenyAllConfig.class, BasicController.class).autowire();
this.mvc.perform(get("/").with(authentication(
new RememberMeAuthenticationToken("key", "user", AuthorityUtils.createAuthorityList("ROLE_USER")))))
.andExpect(status().isOk());
RememberMeAuthenticationToken rememberme = new RememberMeAuthenticationToken("key", "user", AuthorityUtils.createAuthorityList("ROLE_USER"));
MockHttpServletRequestBuilder requestWithRememberme = get("/").with(authentication(rememberme));
this.mvc.perform(requestWithRememberme).andExpect(status().isOk());
}
@Test
public void getWhenFullyAuthenticatedConfiguredAndRememberMeTokenThenRespondsWithUnauthorized() throws Exception {
this.spring.register(FullyAuthenticatedConfig.class, BasicController.class).autowire();
this.mvc.perform(get("/").with(authentication(
new RememberMeAuthenticationToken("key", "user", AuthorityUtils.createAuthorityList("ROLE_USER")))))
.andExpect(status().isUnauthorized());
RememberMeAuthenticationToken rememberme = new RememberMeAuthenticationToken("key", "user", AuthorityUtils.createAuthorityList("ROLE_USER"));
MockHttpServletRequestBuilder requestWithRememberme = get("/").with(authentication(rememberme));
this.mvc.perform(requestWithRememberme).andExpect(status().isUnauthorized());
}
@Test
public void getWhenFullyAuthenticatedConfiguredAndUserThenRespondsWithOk() throws Exception {
this.spring.register(FullyAuthenticatedConfig.class, BasicController.class).autowire();
this.mvc.perform(get("/").with(user("user").roles("USER"))).andExpect(status().isOk());
MockHttpServletRequestBuilder requestWithUser = get("/").with(user("user").roles("USER"));
this.mvc.perform(requestWithUser).andExpect(status().isOk());
}
@Test
@ -303,19 +361,26 @@ public class ExpressionUrlAuthorizationConfigurerTests {
@Test
public void postWhenAccessRoleUserOrGetRequestConfiguredAndRoleUserThenRespondsWithOk() throws Exception {
this.spring.register(AccessConfig.class, BasicController.class).autowire();
this.mvc.perform(post("/").with(csrf()).with(user("user").roles("USER"))).andExpect(status().isOk());
// @formatter:off
MockHttpServletRequestBuilder requestWithUser = post("/")
.with(csrf())
.with(user("user").roles("USER"));
// @formatter:on
this.mvc.perform(requestWithUser).andExpect(status().isOk());
}
@Test
public void postWhenAccessRoleUserOrGetRequestConfiguredThenRespondsWithUnauthorized() throws Exception {
this.spring.register(AccessConfig.class, BasicController.class).autowire();
this.mvc.perform(post("/").with(csrf())).andExpect(status().isUnauthorized());
MockHttpServletRequestBuilder requestWithCsrf = post("/").with(csrf());
this.mvc.perform(requestWithCsrf).andExpect(status().isUnauthorized());
}
@Test
public void authorizeRequestsWhenInvokedTwiceThenUsesOriginalConfiguration() throws Exception {
this.spring.register(InvokeTwiceDoesNotResetConfig.class, BasicController.class).autowire();
this.mvc.perform(post("/").with(csrf())).andExpect(status().isUnauthorized());
MockHttpServletRequestBuilder requestWithCsrf = post("/").with(csrf());
this.mvc.perform(requestWithCsrf).andExpect(status().isUnauthorized());
}
@Test
@ -334,50 +399,58 @@ public class ExpressionUrlAuthorizationConfigurerTests {
@Test
public void getWhenPermissionCheckAndRoleDoesNotMatchThenRespondsWithForbidden() throws Exception {
this.spring.register(UseBeansInExpressions.class, WildcardController.class).autowire();
this.mvc.perform(get("/admin").with(user("user").roles("USER"))).andExpect(status().isForbidden());
MockHttpServletRequestBuilder requestWithUser = get("/admin").with(user("user").roles("USER"));
this.mvc.perform(requestWithUser).andExpect(status().isForbidden());
}
@Test
public void getWhenPermissionCheckAndRoleMatchesThenRespondsWithOk() throws Exception {
this.spring.register(UseBeansInExpressions.class, WildcardController.class).autowire();
this.mvc.perform(get("/user").with(user("user").roles("USER"))).andExpect(status().isOk());
MockHttpServletRequestBuilder requestWithUser = get("/user").with(user("user").roles("USER"));
this.mvc.perform(requestWithUser).andExpect(status().isOk());
}
@Test
public void getWhenPermissionCheckAndAuthenticationNameMatchesThenRespondsWithOk() throws Exception {
this.spring.register(UseBeansInExpressions.class, WildcardController.class).autowire();
this.mvc.perform(get("/allow").with(user("user").roles("USER"))).andExpect(status().isOk());
MockHttpServletRequestBuilder requestWithUser = get("/allow").with(user("user").roles("USER"));
this.mvc.perform(requestWithUser).andExpect(status().isOk());
}
@Test
public void getWhenPermissionCheckAndAuthenticationNameDoesNotMatchThenRespondsWithForbidden() throws Exception {
this.spring.register(UseBeansInExpressions.class, WildcardController.class).autowire();
this.mvc.perform(get("/deny").with(user("user").roles("USER"))).andExpect(status().isForbidden());
MockHttpServletRequestBuilder requestWithUser = get("/deny").with(user("user").roles("USER"));
this.mvc.perform(requestWithUser).andExpect(status().isForbidden());
}
@Test
public void getWhenCustomExpressionHandlerAndRoleDoesNotMatchThenRespondsWithForbidden() throws Exception {
this.spring.register(CustomExpressionRootConfig.class, WildcardController.class).autowire();
this.mvc.perform(get("/admin").with(user("user").roles("USER"))).andExpect(status().isForbidden());
MockHttpServletRequestBuilder requestWithUser = get("/admin").with(user("user").roles("USER"));
this.mvc.perform(requestWithUser).andExpect(status().isForbidden());
}
@Test
public void getWhenCustomExpressionHandlerAndRoleMatchesThenRespondsWithOk() throws Exception {
this.spring.register(CustomExpressionRootConfig.class, WildcardController.class).autowire();
this.mvc.perform(get("/user").with(user("user").roles("USER"))).andExpect(status().isOk());
MockHttpServletRequestBuilder requestWithUser = get("/user").with(user("user").roles("USER"));
this.mvc.perform(requestWithUser).andExpect(status().isOk());
}
@Test
public void getWhenCustomExpressionHandlerAndAuthenticationNameMatchesThenRespondsWithOk() throws Exception {
this.spring.register(CustomExpressionRootConfig.class, WildcardController.class).autowire();
this.mvc.perform(get("/allow").with(user("user").roles("USER"))).andExpect(status().isOk());
MockHttpServletRequestBuilder requestWithUser = get("/allow").with(user("user").roles("USER"));
this.mvc.perform(requestWithUser).andExpect(status().isOk());
}
@Test
public void getWhenCustomExpressionHandlerAndAuthenticationNameDoesNotMatchThenRespondsWithForbidden()
throws Exception {
this.spring.register(CustomExpressionRootConfig.class, WildcardController.class).autowire();
this.mvc.perform(get("/deny").with(user("user").roles("USER"))).andExpect(status().isForbidden());
MockHttpServletRequestBuilder requestWithUser = get("/deny").with(user("user").roles("USER"));
this.mvc.perform(requestWithUser).andExpect(status().isForbidden());
}
// SEC-3011
@ -418,13 +491,15 @@ public class ExpressionUrlAuthorizationConfigurerTests {
@Test
public void getWhenRegisteringRoleHierarchyAndRelatedRoleAllowedThenRespondsWithOk() throws Exception {
this.spring.register(RoleHierarchyConfig.class, WildcardController.class).autowire();
this.mvc.perform(get("/allow").with(user("user").roles("USER"))).andExpect(status().isOk());
MockHttpServletRequestBuilder requestWithUser = get("/allow").with(user("user").roles("USER"));
this.mvc.perform(requestWithUser).andExpect(status().isOk());
}
@Test
public void getWhenRegisteringRoleHierarchyAndNoRelatedRolesAllowedThenRespondsWithForbidden() throws Exception {
this.spring.register(RoleHierarchyConfig.class, WildcardController.class).autowire();
this.mvc.perform(get("/deny").with(user("user").roles("USER"))).andExpect(status().isForbidden());
MockHttpServletRequestBuilder requestWithUser = get("/deny").with(user("user").roles("USER"));
this.mvc.perform(requestWithUser).andExpect(status().isForbidden());
}
@EnableWebSecurity

View File

@ -30,6 +30,7 @@ import org.springframework.security.config.annotation.web.configuration.WebSecur
import org.springframework.security.config.test.SpringTestRule;
import org.springframework.security.config.users.AuthenticationTestConfiguration;
import org.springframework.security.core.userdetails.PasswordEncodedUser;
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders;
import org.springframework.security.web.PortMapper;
import org.springframework.security.web.access.ExceptionTranslationFilter;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
@ -85,21 +86,34 @@ public class FormLoginConfigurerTests {
@Test
public void loginWhenFormLoginConfiguredThenHasDefaultUsernameAndPasswordParameterNames() throws Exception {
this.spring.register(FormLoginConfig.class).autowire();
this.mockMvc.perform(formLogin().user("username", "user").password("password", "password"))
.andExpect(status().isFound()).andExpect(redirectedUrl("/"));
// @formatter:off
SecurityMockMvcRequestBuilders.FormLoginRequestBuilder loginRequest = formLogin()
.user("username", "user")
.password("password", "password");
this.mockMvc.perform(loginRequest)
.andExpect(status().isFound())
.andExpect(redirectedUrl("/"));
// @formatter:on
}
@Test
public void loginWhenFormLoginConfiguredThenHasDefaultFailureUrl() throws Exception {
this.spring.register(FormLoginConfig.class).autowire();
this.mockMvc.perform(formLogin().user("invalid")).andExpect(status().isFound())
// @formatter:off
this.mockMvc.perform(formLogin().user("invalid"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("/login?error"));
// @formatter:on
}
@Test
public void loginWhenFormLoginConfiguredThenHasDefaultSuccessUrl() throws Exception {
this.spring.register(FormLoginConfig.class).autowire();
this.mockMvc.perform(formLogin()).andExpect(status().isFound()).andExpect(redirectedUrl("/"));
// @formatter:off
this.mockMvc.perform(formLogin())
.andExpect(status().isFound())
.andExpect(redirectedUrl("/"));
// @formatter:on
}
@Test
@ -117,28 +131,44 @@ public class FormLoginConfigurerTests {
@Test
public void requestProtectedWhenFormLoginConfiguredThenRedirectsToLogin() throws Exception {
this.spring.register(FormLoginConfig.class).autowire();
this.mockMvc.perform(get("/private")).andExpect(status().isFound())
// @formatter:off
this.mockMvc.perform(get("/private"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("http://localhost/login"));
// @formatter:on
}
@Test
public void loginWhenFormLoginDefaultsInLambdaThenHasDefaultUsernameAndPasswordParameterNames() throws Exception {
this.spring.register(FormLoginInLambdaConfig.class).autowire();
this.mockMvc.perform(formLogin().user("username", "user").password("password", "password"))
.andExpect(status().isFound()).andExpect(redirectedUrl("/"));
// @formatter:off
SecurityMockMvcRequestBuilders.FormLoginRequestBuilder loginRequest = formLogin()
.user("username", "user")
.password("password", "password");
this.mockMvc.perform(loginRequest)
.andExpect(status().isFound())
.andExpect(redirectedUrl("/"));
// @formatter:on
}
@Test
public void loginWhenFormLoginDefaultsInLambdaThenHasDefaultFailureUrl() throws Exception {
this.spring.register(FormLoginInLambdaConfig.class).autowire();
this.mockMvc.perform(formLogin().user("invalid")).andExpect(status().isFound())
// @formatter:off
this.mockMvc.perform(formLogin().user("invalid"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("/login?error"));
// @formatter:on
}
@Test
public void loginWhenFormLoginDefaultsInLambdaThenHasDefaultSuccessUrl() throws Exception {
this.spring.register(FormLoginInLambdaConfig.class).autowire();
this.mockMvc.perform(formLogin()).andExpect(status().isFound()).andExpect(redirectedUrl("/"));
// @formatter:off
this.mockMvc.perform(formLogin())
.andExpect(status().isFound())
.andExpect(redirectedUrl("/"));
// @formatter:on
}
@Test
@ -156,27 +186,41 @@ public class FormLoginConfigurerTests {
@Test
public void requestProtectedWhenFormLoginDefaultsInLambdaThenRedirectsToLogin() throws Exception {
this.spring.register(FormLoginInLambdaConfig.class).autowire();
this.mockMvc.perform(get("/private")).andExpect(status().isFound())
// @formatter:off
this.mockMvc.perform(get("/private"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("http://localhost/login"));
// @formatter:on
}
@Test
public void getLoginPageWhenFormLoginPermitAllThenPermittedAndNoRedirect() throws Exception {
this.spring.register(FormLoginConfigPermitAll.class).autowire();
this.mockMvc.perform(get("/login")).andExpect(status().isOk()).andExpect(redirectedUrl(null));
// @formatter:off
this.mockMvc.perform(get("/login"))
.andExpect(status().isOk())
.andExpect(redirectedUrl(null));
// @formatter:on
}
@Test
public void getLoginPageWithErrorQueryWhenFormLoginPermitAllThenPermittedAndNoRedirect() throws Exception {
this.spring.register(FormLoginConfigPermitAll.class).autowire();
this.mockMvc.perform(get("/login?error")).andExpect(status().isOk()).andExpect(redirectedUrl(null));
// @formatter:off
this.mockMvc.perform(get("/login?error"))
.andExpect(status().isOk())
.andExpect(redirectedUrl(null));
// @formatter:on
}
@Test
public void loginWhenFormLoginPermitAllAndInvalidUserThenRedirectsToLoginPageWithError() throws Exception {
this.spring.register(FormLoginConfigPermitAll.class).autowire();
this.mockMvc.perform(formLogin().user("invalid")).andExpect(status().isFound())
// @formatter:off
this.mockMvc.perform(formLogin().user("invalid"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("/login?error"));
// @formatter:on
}
@Test
@ -194,8 +238,12 @@ public class FormLoginConfigurerTests {
@Test
public void loginWhenCustomLoginPageAndInvalidUserThenRedirectsToCustomLoginPageWithError() throws Exception {
this.spring.register(FormLoginDefaultsConfig.class).autowire();
this.mockMvc.perform(formLogin("/authenticate").user("invalid")).andExpect(status().isFound())
SecurityMockMvcRequestBuilders.FormLoginRequestBuilder request = formLogin("/authenticate").user("invalid");
// @formatter:off
this.mockMvc.perform(request)
.andExpect(status().isFound())
.andExpect(redirectedUrl("/authenticate?error"));
// @formatter:on
}
@Test
@ -219,13 +267,21 @@ public class FormLoginConfigurerTests {
@Test
public void loginWhenCustomLoginProcessingUrlThenRedirectsToHome() throws Exception {
this.spring.register(FormLoginLoginProcessingUrlConfig.class).autowire();
this.mockMvc.perform(formLogin("/loginCheck")).andExpect(status().isFound()).andExpect(redirectedUrl("/"));
// @formatter:off
this.mockMvc.perform(formLogin("/loginCheck"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("/"));
// @formatter:on
}
@Test
public void loginWhenCustomLoginProcessingUrlInLambdaThenRedirectsToHome() throws Exception {
this.spring.register(FormLoginLoginProcessingUrlInLambdaConfig.class).autowire();
this.mockMvc.perform(formLogin("/loginCheck")).andExpect(status().isFound()).andExpect(redirectedUrl("/"));
// @formatter:off
this.mockMvc.perform(formLogin("/loginCheck"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("/"));
// @formatter:on
}
@Test
@ -233,28 +289,36 @@ public class FormLoginConfigurerTests {
FormLoginUsesPortMapperConfig.PORT_MAPPER = mock(PortMapper.class);
given(FormLoginUsesPortMapperConfig.PORT_MAPPER.lookupHttpsPort(any())).willReturn(9443);
this.spring.register(FormLoginUsesPortMapperConfig.class).autowire();
this.mockMvc.perform(get("http://localhost:9090")).andExpect(status().isFound())
// @formatter:off
this.mockMvc.perform(get("http://localhost:9090"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("https://localhost:9443/login"));
// @formatter:on
verify(FormLoginUsesPortMapperConfig.PORT_MAPPER).lookupHttpsPort(any());
}
@Test
public void failureUrlWhenPermitAllAndFailureHandlerThenSecured() throws Exception {
this.spring.register(PermitAllIgnoresFailureHandlerConfig.class).autowire();
this.mockMvc.perform(get("/login?error")).andExpect(status().isFound())
// @formatter:off
this.mockMvc.perform(get("/login?error"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("http://localhost/login"));
// @formatter:on
}
@Test
public void formLoginWhenInvokedTwiceThenUsesOriginalUsernameParameter() throws Exception {
this.spring.register(DuplicateInvocationsDoesNotOverrideConfig.class).autowire();
this.mockMvc.perform(formLogin().user("custom-username", "user")).andExpect(authenticated());
SecurityMockMvcRequestBuilders.FormLoginRequestBuilder loginRequest = formLogin().user("custom-username", "user");
this.mockMvc.perform(loginRequest).andExpect(authenticated());
}
@Test
public void loginWhenInvalidLoginAndFailureForwardUrlThenForwardsToFailureForwardUrl() throws Exception {
this.spring.register(FormLoginUserForwardAuthenticationSuccessAndFailureConfig.class).autowire();
this.mockMvc.perform(formLogin().user("invalid")).andExpect(forwardedUrl("/failure_forward_url"));
SecurityMockMvcRequestBuilders.FormLoginRequestBuilder loginRequest = formLogin().user("invalid");
this.mockMvc.perform(loginRequest).andExpect(forwardedUrl("/failure_forward_url"));
}
@Test

View File

@ -62,15 +62,17 @@ public class HeadersConfigurerEagerHeadersTests {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @ formatter:off
http.headers().addObjectPostProcessor(new ObjectPostProcessor<HeaderWriterFilter>() {
@Override
public HeaderWriterFilter postProcess(HeaderWriterFilter filter) {
filter.setShouldWriteHeadersEagerly(true);
return filter;
}
});
// @ formatter:on
// @formatter:off
http
.headers()
.addObjectPostProcessor(new ObjectPostProcessor<HeaderWriterFilter>() {
@Override
public HeaderWriterFilter postProcess(HeaderWriterFilter filter) {
filter.setShouldWriteHeadersEagerly(true);
return filter;
}
});
// @formatter:on
}
}

View File

@ -34,6 +34,7 @@ import org.springframework.security.web.header.writers.ReferrerPolicyHeaderWrite
import org.springframework.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter.XFrameOptionsMode;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.ResultMatcher;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
@ -198,10 +199,13 @@ public class HeadersConfigurerTests {
@Test
public void getWhenSecureRequestAndHpkpWithPinThenPublicKeyPinsReportOnlyHeaderInResponse() throws Exception {
this.spring.register(HpkpConfig.class).autowire();
ResultMatcher pinsReportOnly = header().string(HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY,
"max-age=5184000 ; pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\"");
// @formatter:off
MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
.andExpect(header().string(HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY,
"max-age=5184000 ; pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\""))
.andExpect(pinsReportOnly)
.andReturn();
// @formatter:on
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY);
}
@ -216,30 +220,40 @@ public class HeadersConfigurerTests {
public void getWhenHpkpWithMultiplePinsThenPublicKeyPinsReportOnlyHeaderWithMultiplePinsInResponse()
throws Exception {
this.spring.register(HpkpConfigWithPins.class).autowire();
MvcResult mvcResult = this.mvc.perform(get("/").secure(true)).andExpect(header().string(
ResultMatcher pinsReportOnly = header().string(
HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY,
"max-age=5184000 ; pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\" ; pin-sha256=\"E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=\""))
"max-age=5184000 ; pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\" ; pin-sha256=\"E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=\"");
// @formatter:off
MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
.andExpect(pinsReportOnly)
.andReturn();
// @formatter:on
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY);
}
@Test
public void getWhenHpkpWithCustomAgeThenPublicKeyPinsReportOnlyHeaderWithCustomAgeInResponse() throws Exception {
this.spring.register(HpkpConfigCustomAge.class).autowire();
ResultMatcher pinsReportOnly = header().string(HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY,
"max-age=604800 ; pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\"");
// @formatter:off
MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
.andExpect(header().string(HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY,
"max-age=604800 ; pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\""))
.andExpect(pinsReportOnly)
.andReturn();
// @formatter:on
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY);
}
@Test
public void getWhenHpkpWithReportOnlyFalseThenPublicKeyPinsHeaderInResponse() throws Exception {
this.spring.register(HpkpConfigTerminateConnection.class).autowire();
ResultMatcher pins = header().string(HttpHeaders.PUBLIC_KEY_PINS,
"max-age=5184000 ; pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\"");
// @formatter:off
MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
.andExpect(header().string(HttpHeaders.PUBLIC_KEY_PINS,
"max-age=5184000 ; pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\""))
.andExpect(pins)
.andReturn();
// @formatter:on
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.PUBLIC_KEY_PINS);
}
@ -247,20 +261,28 @@ public class HeadersConfigurerTests {
public void getWhenHpkpIncludeSubdomainThenPublicKeyPinsReportOnlyHeaderWithIncludeSubDomainsInResponse()
throws Exception {
this.spring.register(HpkpConfigIncludeSubDomains.class).autowire();
MvcResult mvcResult = this.mvc.perform(get("/").secure(true)).andExpect(header().string(
ResultMatcher pinsReportOnly = header().string(
HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY,
"max-age=5184000 ; pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\" ; includeSubDomains"))
"max-age=5184000 ; pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\" ; includeSubDomains");
// @formatter:off
MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
.andExpect(pinsReportOnly)
.andReturn();
// @formatter:on
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY);
}
@Test
public void getWhenHpkpWithReportUriThenPublicKeyPinsReportOnlyHeaderWithReportUriInResponse() throws Exception {
this.spring.register(HpkpConfigWithReportURI.class).autowire();
MvcResult mvcResult = this.mvc.perform(get("/").secure(true)).andExpect(header().string(
ResultMatcher pinsReportOnly = header().string(
HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY,
"max-age=5184000 ; pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\" ; report-uri=\"https://example.net/pkp-report\""))
"max-age=5184000 ; pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\" ; report-uri=\"https://example.net/pkp-report\"");
// @formatter:off
MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
.andExpect(pinsReportOnly)
.andReturn();
// @formatter:on
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY);
}
@ -268,10 +290,14 @@ public class HeadersConfigurerTests {
public void getWhenHpkpWithReportUriAsStringThenPublicKeyPinsReportOnlyHeaderWithReportUriInResponse()
throws Exception {
this.spring.register(HpkpConfigWithReportURIAsString.class).autowire();
MvcResult mvcResult = this.mvc.perform(get("/").secure(true)).andExpect(header().string(
ResultMatcher pinsReportOnly = header().string(
HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY,
"max-age=5184000 ; pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\" ; report-uri=\"https://example.net/pkp-report\""))
"max-age=5184000 ; pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\" ; report-uri=\"https://example.net/pkp-report\"");
// @formatter:off
MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
.andExpect(pinsReportOnly)
.andReturn();
// @formatter:on
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY);
}
@ -279,18 +305,26 @@ public class HeadersConfigurerTests {
public void getWhenHpkpWithReportUriInLambdaThenPublicKeyPinsReportOnlyHeaderWithReportUriInResponse()
throws Exception {
this.spring.register(HpkpWithReportUriInLambdaConfig.class).autowire();
MvcResult mvcResult = this.mvc.perform(get("/").secure(true)).andExpect(header().string(
ResultMatcher pinsReportOnly = header().string(
HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY,
"max-age=5184000 ; pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\" ; report-uri=\"https://example.net/pkp-report\""))
"max-age=5184000 ; pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\" ; report-uri=\"https://example.net/pkp-report\"");
// @formatter:off
MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
.andExpect(pinsReportOnly)
.andReturn();
// @formatter:on
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY);
}
@Test
public void getWhenContentSecurityPolicyConfiguredThenContentSecurityPolicyHeaderInResponse() throws Exception {
this.spring.register(ContentSecurityPolicyDefaultConfig.class).autowire();
ResultMatcher csp = header().string(HttpHeaders.CONTENT_SECURITY_POLICY, "default-src 'self'");
// @formatter:off
MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
.andExpect(header().string(HttpHeaders.CONTENT_SECURITY_POLICY, "default-src 'self'")).andReturn();
.andExpect(csp)
.andReturn();
// @formatter:on
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.CONTENT_SECURITY_POLICY);
}
@ -298,10 +332,13 @@ public class HeadersConfigurerTests {
public void getWhenContentSecurityPolicyWithReportOnlyThenContentSecurityPolicyReportOnlyHeaderInResponse()
throws Exception {
this.spring.register(ContentSecurityPolicyReportOnlyConfig.class).autowire();
ResultMatcher cspReportOnly = header().string(HttpHeaders.CONTENT_SECURITY_POLICY_REPORT_ONLY,
"default-src 'self'; script-src trustedscripts.example.com");
// @formatter:off
MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
.andExpect(header().string(HttpHeaders.CONTENT_SECURITY_POLICY_REPORT_ONLY,
"default-src 'self'; script-src trustedscripts.example.com"))
.andExpect(cspReportOnly)
.andReturn();
// @formatter:on
assertThat(mvcResult.getResponse().getHeaderNames())
.containsExactly(HttpHeaders.CONTENT_SECURITY_POLICY_REPORT_ONLY);
}
@ -310,10 +347,13 @@ public class HeadersConfigurerTests {
public void getWhenContentSecurityPolicyWithReportOnlyInLambdaThenContentSecurityPolicyReportOnlyHeaderInResponse()
throws Exception {
this.spring.register(ContentSecurityPolicyReportOnlyInLambdaConfig.class).autowire();
ResultMatcher csp = header().string(HttpHeaders.CONTENT_SECURITY_POLICY_REPORT_ONLY,
"default-src 'self'; script-src trustedscripts.example.com");
// @formatter:off
MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
.andExpect(header().string(HttpHeaders.CONTENT_SECURITY_POLICY_REPORT_ONLY,
"default-src 'self'; script-src trustedscripts.example.com"))
.andExpect(csp)
.andReturn();
// @formatter:on
assertThat(mvcResult.getResponse().getHeaderNames())
.containsExactly(HttpHeaders.CONTENT_SECURITY_POLICY_REPORT_ONLY);
}
@ -335,24 +375,36 @@ public class HeadersConfigurerTests {
@Test
public void configureWhenContentSecurityPolicyNoPolicyDirectivesInLambdaThenDefaultHeaderValue() throws Exception {
this.spring.register(ContentSecurityPolicyNoDirectivesInLambdaConfig.class).autowire();
ResultMatcher csp = header().string(HttpHeaders.CONTENT_SECURITY_POLICY, "default-src 'self'");
// @formatter:off
MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
.andExpect(header().string(HttpHeaders.CONTENT_SECURITY_POLICY, "default-src 'self'")).andReturn();
.andExpect(csp)
.andReturn();
// @formatter:on
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.CONTENT_SECURITY_POLICY);
}
@Test
public void getWhenReferrerPolicyConfiguredThenReferrerPolicyHeaderInResponse() throws Exception {
this.spring.register(ReferrerPolicyDefaultConfig.class).autowire();
ResultMatcher referrerPolicy = header().string("Referrer-Policy", ReferrerPolicy.NO_REFERRER.getPolicy());
// @formatter:off
MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
.andExpect(header().string("Referrer-Policy", ReferrerPolicy.NO_REFERRER.getPolicy())).andReturn();
.andExpect(referrerPolicy)
.andReturn();
// @formatter:on
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly("Referrer-Policy");
}
@Test
public void getWhenReferrerPolicyInLambdaThenReferrerPolicyHeaderInResponse() throws Exception {
this.spring.register(ReferrerPolicyDefaultInLambdaConfig.class).autowire();
ResultMatcher referrerPolicy = header().string("Referrer-Policy", ReferrerPolicy.NO_REFERRER.getPolicy());
// @formatter:off
MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
.andExpect(header().string("Referrer-Policy", ReferrerPolicy.NO_REFERRER.getPolicy())).andReturn();
.andExpect(referrerPolicy)
.andReturn();
// @formatter:on
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly("Referrer-Policy");
}
@ -360,24 +412,36 @@ public class HeadersConfigurerTests {
public void getWhenReferrerPolicyConfiguredWithCustomValueThenReferrerPolicyHeaderWithCustomValueInResponse()
throws Exception {
this.spring.register(ReferrerPolicyCustomConfig.class).autowire();
ResultMatcher referrerPolicy = header().string("Referrer-Policy", ReferrerPolicy.SAME_ORIGIN.getPolicy());
// @formatter:off
MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
.andExpect(header().string("Referrer-Policy", ReferrerPolicy.SAME_ORIGIN.getPolicy())).andReturn();
.andExpect(referrerPolicy)
.andReturn();
// @formatter:on
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly("Referrer-Policy");
}
@Test
public void getWhenReferrerPolicyConfiguredWithCustomValueInLambdaThenCustomValueInResponse() throws Exception {
this.spring.register(ReferrerPolicyCustomInLambdaConfig.class).autowire();
ResultMatcher referrerPolicy = header().string("Referrer-Policy", ReferrerPolicy.SAME_ORIGIN.getPolicy());
// @formatter:off
MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
.andExpect(header().string("Referrer-Policy", ReferrerPolicy.SAME_ORIGIN.getPolicy())).andReturn();
.andExpect(referrerPolicy)
.andReturn();
// @formatter:on
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly("Referrer-Policy");
}
@Test
public void getWhenFeaturePolicyConfiguredThenFeaturePolicyHeaderInResponse() throws Exception {
this.spring.register(FeaturePolicyConfig.class).autowire();
ResultMatcher featurePolicy = header().string("Feature-Policy", "geolocation 'self'");
// @formatter:off
MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
.andExpect(header().string("Feature-Policy", "geolocation 'self'")).andReturn();
.andExpect(featurePolicy)
.andReturn();
// @formatter:on
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly("Feature-Policy");
}
@ -392,9 +456,13 @@ public class HeadersConfigurerTests {
public void getWhenHstsConfiguredWithPreloadThenStrictTransportSecurityHeaderWithPreloadInResponse()
throws Exception {
this.spring.register(HstsWithPreloadConfig.class).autowire();
MvcResult mvcResult = this.mvc.perform(get("/").secure(true)).andExpect(header()
.string(HttpHeaders.STRICT_TRANSPORT_SECURITY, "max-age=31536000 ; includeSubDomains ; preload"))
ResultMatcher hsts = header()
.string(HttpHeaders.STRICT_TRANSPORT_SECURITY, "max-age=31536000 ; includeSubDomains ; preload");
// @formatter:off
MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
.andExpect(hsts)
.andReturn();
// @formatter:on
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.STRICT_TRANSPORT_SECURITY);
}
@ -402,9 +470,13 @@ public class HeadersConfigurerTests {
public void getWhenHstsConfiguredWithPreloadInLambdaThenStrictTransportSecurityHeaderWithPreloadInResponse()
throws Exception {
this.spring.register(HstsWithPreloadInLambdaConfig.class).autowire();
MvcResult mvcResult = this.mvc.perform(get("/").secure(true)).andExpect(header()
.string(HttpHeaders.STRICT_TRANSPORT_SECURITY, "max-age=31536000 ; includeSubDomains ; preload"))
ResultMatcher hsts = header()
.string(HttpHeaders.STRICT_TRANSPORT_SECURITY, "max-age=31536000 ; includeSubDomains ; preload");
// @formatter:off
MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
.andExpect(hsts)
.andReturn();
// @formatter:on
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.STRICT_TRANSPORT_SECURITY);
}

View File

@ -38,6 +38,7 @@ import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
@ -73,16 +74,22 @@ public class HttpBasicConfigurerTests {
@Test
public void httpBasicWhenUsingDefaultsInLambdaThenResponseIncludesBasicChallenge() throws Exception {
this.spring.register(DefaultsLambdaEntryPointConfig.class).autowire();
this.mvc.perform(get("/")).andExpect(status().isUnauthorized())
// @formatter:off
this.mvc.perform(get("/"))
.andExpect(status().isUnauthorized())
.andExpect(header().string("WWW-Authenticate", "Basic realm=\"Realm\""));
// @formatter:on
}
// SEC-2198
@Test
public void httpBasicWhenUsingDefaultsThenResponseIncludesBasicChallenge() throws Exception {
this.spring.register(DefaultsEntryPointConfig.class).autowire();
this.mvc.perform(get("/")).andExpect(status().isUnauthorized())
// @formatter:off
this.mvc.perform(get("/"))
.andExpect(status().isUnauthorized())
.andExpect(header().string("WWW-Authenticate", "Basic realm=\"Realm\""));
// @formatter:on
}
@Test
@ -105,8 +112,8 @@ public class HttpBasicConfigurerTests {
@Test
public void httpBasicWhenRememberMeConfiguredThenSetsRememberMeCookie() throws Exception {
this.spring.register(BasicUsesRememberMeConfig.class).autowire();
this.mvc.perform(get("/").with(httpBasic("user", "password")).param("remember-me", "true"))
.andExpect(cookie().exists("remember-me"));
MockHttpServletRequestBuilder rememberMeRequest = get("/").with(httpBasic("user", "password")).param("remember-me", "true");
this.mvc.perform(rememberMeRequest).andExpect(cookie().exists("remember-me"));
}
@EnableWebSecurity

View File

@ -31,9 +31,11 @@ import org.springframework.security.config.test.SpringTestRule;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers;
import org.springframework.security.web.authentication.preauth.j2ee.J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource;
import org.springframework.security.web.authentication.preauth.j2ee.J2eePreAuthenticatedProcessingFilter;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given;
@ -78,11 +80,16 @@ public class JeeConfigurerTests {
this.spring.register(InvokeTwiceDoesNotOverride.class).autowire();
Principal user = mock(Principal.class);
given(user.getName()).willReturn("user");
this.mvc.perform(get("/").principal(user).with((request) -> {
request.addUserRole("ROLE_ADMIN");
request.addUserRole("ROLE_USER");
return request;
})).andExpect(authenticated().withRoles("USER"));
// @formatter:off
MockHttpServletRequestBuilder request = get("/")
.principal(user)
.with((request) -> {
request.addUserRole("ROLE_ADMIN");
request.addUserRole("ROLE_USER");
return request;
});
// @formatter:on
this.mvc.perform(request).andExpect(authenticated().withRoles("USER"));
}
@Test
@ -90,11 +97,16 @@ public class JeeConfigurerTests {
this.spring.register(JeeMappableRolesConfig.class).autowire();
Principal user = mock(Principal.class);
given(user.getName()).willReturn("user");
this.mvc.perform(get("/").principal(user).with((request) -> {
request.addUserRole("ROLE_ADMIN");
request.addUserRole("ROLE_USER");
return request;
})).andExpect(authenticated().withRoles("USER"));
// @formatter:off
MockHttpServletRequestBuilder request = get("/")
.principal(user)
.with((request) -> {
request.addUserRole("ROLE_ADMIN");
request.addUserRole("ROLE_USER");
return request;
});
// @formatter:on
this.mvc.perform(request).andExpect(authenticated().withRoles("USER"));
}
@Test
@ -102,11 +114,17 @@ public class JeeConfigurerTests {
this.spring.register(JeeMappableAuthoritiesConfig.class).autowire();
Principal user = mock(Principal.class);
given(user.getName()).willReturn("user");
this.mvc.perform(get("/").principal(user).with((request) -> {
request.addUserRole("ROLE_ADMIN");
request.addUserRole("ROLE_USER");
return request;
})).andExpect(authenticated().withAuthorities(AuthorityUtils.createAuthorityList("ROLE_USER")));
// @formatter:off
MockHttpServletRequestBuilder request = get("/")
.principal(user)
.with((request) -> {
request.addUserRole("ROLE_ADMIN");
request.addUserRole("ROLE_USER");
return request;
});
// @formatter:on
SecurityMockMvcResultMatchers.AuthenticatedMatcher authenticatedAsUser = authenticated().withAuthorities(AuthorityUtils.createAuthorityList("ROLE_USER"));
this.mvc.perform(request).andExpect(authenticatedAsUser);
}
@Test
@ -119,11 +137,16 @@ public class JeeConfigurerTests {
given(user.getName()).willReturn("user");
given(JeeCustomAuthenticatedUserDetailsServiceConfig.authenticationUserDetailsService.loadUserDetails(any()))
.willReturn(userDetails);
this.mvc.perform(get("/").principal(user).with((request) -> {
request.addUserRole("ROLE_ADMIN");
request.addUserRole("ROLE_USER");
return request;
})).andExpect(authenticated().withRoles("USER"));
// @formatter:off
MockHttpServletRequestBuilder request = get("/")
.principal(user)
.with((request) -> {
request.addUserRole("ROLE_ADMIN");
request.addUserRole("ROLE_USER");
return request;
});
// @formatter:on
this.mvc.perform(request).andExpect(authenticated().withRoles("USER"));
}
@EnableWebSecurity

View File

@ -27,13 +27,14 @@ import org.springframework.security.config.annotation.web.configuration.WebSecur
import org.springframework.security.config.test.SpringTestRule;
import org.springframework.security.test.context.annotation.SecurityTestExecutionListeners;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors;
import org.springframework.security.web.authentication.logout.HeaderWriterLogoutHandler;
import org.springframework.security.web.header.writers.ClearSiteDataHeaderWriter;
import org.springframework.security.web.header.writers.ClearSiteDataHeaderWriter.Directive;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
@ -67,24 +68,24 @@ public class LogoutConfigurerClearSiteDataTests {
@WithMockUser
public void logoutWhenRequestTypeGetThenHeaderNotPresentt() throws Exception {
this.spring.register(HttpLogoutConfig.class).autowire();
this.mvc.perform(get("/logout").secure(true).with(SecurityMockMvcRequestPostProcessors.csrf()))
.andExpect(header().doesNotExist(CLEAR_SITE_DATA_HEADER));
MockHttpServletRequestBuilder logoutRequest = get("/logout").secure(true).with(csrf());
this.mvc.perform(logoutRequest).andExpect(header().doesNotExist(CLEAR_SITE_DATA_HEADER));
}
@Test
@WithMockUser
public void logoutWhenRequestTypePostAndNotSecureThenHeaderNotPresent() throws Exception {
this.spring.register(HttpLogoutConfig.class).autowire();
this.mvc.perform(post("/logout").with(SecurityMockMvcRequestPostProcessors.csrf()))
.andExpect(header().doesNotExist(CLEAR_SITE_DATA_HEADER));
MockHttpServletRequestBuilder logoutRequest = post("/logout").with(csrf());
this.mvc.perform(logoutRequest).andExpect(header().doesNotExist(CLEAR_SITE_DATA_HEADER));
}
@Test
@WithMockUser
public void logoutWhenRequestTypePostAndSecureThenHeaderIsPresent() throws Exception {
this.spring.register(HttpLogoutConfig.class).autowire();
this.mvc.perform(post("/logout").secure(true).with(SecurityMockMvcRequestPostProcessors.csrf()))
.andExpect(header().stringValues(CLEAR_SITE_DATA_HEADER, HEADER_VALUE));
MockHttpServletRequestBuilder logoutRequest = post("/logout").secure(true).with(csrf());
this.mvc.perform(logoutRequest).andExpect(header().stringValues(CLEAR_SITE_DATA_HEADER, HEADER_VALUE));
}
@EnableWebSecurity

View File

@ -35,6 +35,7 @@ import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.mockito.ArgumentMatchers.any;
@ -101,65 +102,103 @@ public class LogoutConfigurerTests {
@Test
public void logoutWhenInvokedTwiceThenUsesOriginalLogoutUrl() throws Exception {
this.spring.register(DuplicateDoesNotOverrideConfig.class).autowire();
this.mvc.perform(post("/custom/logout").with(csrf())).andExpect(status().isFound())
MockHttpServletRequestBuilder logoutRequest = post("/custom/logout").with(csrf());
// @formatter:off
this.mvc.perform(logoutRequest)
.andExpect(status().isFound())
.andExpect(redirectedUrl("/login?logout"));
// @formatter:on
}
// SEC-2311
@Test
public void logoutWhenGetRequestAndCsrfDisabledThenRedirectsToLogin() throws Exception {
this.spring.register(CsrfDisabledConfig.class).autowire();
this.mvc.perform(get("/logout")).andExpect(status().isFound()).andExpect(redirectedUrl("/login?logout"));
// @formatter:off
this.mvc.perform(get("/logout"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("/login?logout"));
// @formatter:on
}
@Test
public void logoutWhenPostRequestAndCsrfDisabledThenRedirectsToLogin() throws Exception {
this.spring.register(CsrfDisabledConfig.class).autowire();
this.mvc.perform(post("/logout")).andExpect(status().isFound()).andExpect(redirectedUrl("/login?logout"));
// @formatter:off
this.mvc.perform(post("/logout"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("/login?logout"));
// @formatter:on
}
@Test
public void logoutWhenPutRequestAndCsrfDisabledThenRedirectsToLogin() throws Exception {
this.spring.register(CsrfDisabledConfig.class).autowire();
this.mvc.perform(put("/logout")).andExpect(status().isFound()).andExpect(redirectedUrl("/login?logout"));
// @formatter:off
this.mvc.perform(put("/logout"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("/login?logout"));
// @formatter:on
}
@Test
public void logoutWhenDeleteRequestAndCsrfDisabledThenRedirectsToLogin() throws Exception {
this.spring.register(CsrfDisabledConfig.class).autowire();
this.mvc.perform(delete("/logout")).andExpect(status().isFound()).andExpect(redirectedUrl("/login?logout"));
// @formatter:off
this.mvc.perform(delete("/logout"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("/login?logout"));
// @formatter:on
}
@Test
public void logoutWhenGetRequestAndCsrfDisabledAndCustomLogoutUrlThenRedirectsToLogin() throws Exception {
this.spring.register(CsrfDisabledAndCustomLogoutConfig.class).autowire();
this.mvc.perform(get("/custom/logout")).andExpect(status().isFound()).andExpect(redirectedUrl("/login?logout"));
// @formatter:off
this.mvc.perform(get("/custom/logout"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("/login?logout"));
// @formatter:on
}
@Test
public void logoutWhenPostRequestAndCsrfDisabledAndCustomLogoutUrlThenRedirectsToLogin() throws Exception {
this.spring.register(CsrfDisabledAndCustomLogoutConfig.class).autowire();
this.mvc.perform(post("/custom/logout")).andExpect(status().isFound())
// @formatter:off
this.mvc.perform(post("/custom/logout"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("/login?logout"));
// @formatter:on
}
@Test
public void logoutWhenPutRequestAndCsrfDisabledAndCustomLogoutUrlThenRedirectsToLogin() throws Exception {
this.spring.register(CsrfDisabledAndCustomLogoutConfig.class).autowire();
this.mvc.perform(put("/custom/logout")).andExpect(status().isFound()).andExpect(redirectedUrl("/login?logout"));
// @formatter:off
this.mvc.perform(put("/custom/logout"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("/login?logout"));
// @formatter:on
}
@Test
public void logoutWhenDeleteRequestAndCsrfDisabledAndCustomLogoutUrlThenRedirectsToLogin() throws Exception {
this.spring.register(CsrfDisabledAndCustomLogoutConfig.class).autowire();
this.mvc.perform(delete("/custom/logout")).andExpect(status().isFound())
// @formatter:off
this.mvc.perform(delete("/custom/logout"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("/login?logout"));
// @formatter:on
}
@Test
public void logoutWhenCustomLogoutUrlInLambdaThenRedirectsToLogin() throws Exception {
this.spring.register(CsrfDisabledAndCustomLogoutInLambdaConfig.class).autowire();
this.mvc.perform(get("/custom/logout")).andExpect(status().isFound()).andExpect(redirectedUrl("/login?logout"));
// @formatter:off
this.mvc.perform(get("/custom/logout"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("/login?logout"));
// @formatter:on
}
// SEC-3170
@ -188,44 +227,70 @@ public class LogoutConfigurerTests {
@Test
public void logoutWhenAcceptTextHtmlThenRedirectsToLogin() throws Exception {
this.spring.register(BasicSecurityConfig.class).autowire();
this.mvc.perform(
post("/logout").with(csrf()).with(user("user")).header(HttpHeaders.ACCEPT, MediaType.TEXT_HTML_VALUE))
.andExpect(status().isFound()).andExpect(redirectedUrl("/login?logout"));
// @formatter:off
MockHttpServletRequestBuilder logoutRequest = post("/logout")
.with(csrf())
.with(user("user"))
.header(HttpHeaders.ACCEPT, MediaType.TEXT_HTML_VALUE);
this.mvc.perform(logoutRequest)
.andExpect(status().isFound())
.andExpect(redirectedUrl("/login?logout"));
// @formatter:on
}
// gh-3282
@Test
public void logoutWhenAcceptApplicationJsonThenReturnsStatusNoContent() throws Exception {
this.spring.register(BasicSecurityConfig.class).autowire();
this.mvc.perform(post("/logout").with(csrf()).with(user("user")).header(HttpHeaders.ACCEPT,
MediaType.APPLICATION_JSON_VALUE)).andExpect(status().isNoContent());
// @formatter:off
MockHttpServletRequestBuilder request = post("/logout")
.with(csrf())
.with(user("user"))
.header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE);
// @formatter:on
this.mvc.perform(request).andExpect(status().isNoContent());
}
// gh-4831
@Test
public void logoutWhenAcceptAllThenReturnsStatusNoContent() throws Exception {
this.spring.register(BasicSecurityConfig.class).autowire();
this.mvc.perform(
post("/logout").with(csrf()).with(user("user")).header(HttpHeaders.ACCEPT, MediaType.ALL_VALUE))
.andExpect(status().isNoContent());
// @formatter:off
MockHttpServletRequestBuilder logoutRequest = post("/logout")
.with(csrf())
.with(user("user"))
.header(HttpHeaders.ACCEPT, MediaType.ALL_VALUE);
// @formatter:on
this.mvc.perform(logoutRequest).andExpect(status().isNoContent());
}
// gh-3902
@Test
public void logoutWhenAcceptFromChromeThenRedirectsToLogin() throws Exception {
this.spring.register(BasicSecurityConfig.class).autowire();
this.mvc.perform(post("/logout").with(csrf()).with(user("user")).header(HttpHeaders.ACCEPT,
"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8"))
.andExpect(status().isFound()).andExpect(redirectedUrl("/login?logout"));
// @formatter:off
MockHttpServletRequestBuilder request = post("/logout")
.with(csrf())
.with(user("user"))
.header(HttpHeaders.ACCEPT, "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
this.mvc.perform(request)
.andExpect(status().isFound())
.andExpect(redirectedUrl("/login?logout"));
// @formatter:on
}
// gh-3997
@Test
public void logoutWhenXMLHttpRequestThenReturnsStatusNoContent() throws Exception {
this.spring.register(BasicSecurityConfig.class).autowire();
this.mvc.perform(post("/logout").with(csrf()).with(user("user"))
.header(HttpHeaders.ACCEPT, "text/html,application/json").header("X-Requested-With", "XMLHttpRequest"))
.andExpect(status().isNoContent());
// @formatter:off
MockHttpServletRequestBuilder request = post("/logout")
.with(csrf())
.with(user("user"))
.header(HttpHeaders.ACCEPT, "text/html,application/json")
.header("X-Requested-With", "XMLHttpRequest");
// @formatter:on
this.mvc.perform(request).andExpect(status().isNoContent());
}
@Test

View File

@ -35,6 +35,7 @@ import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
@ -66,18 +67,28 @@ public class NamespaceHttpBasicTests {
public void basicAuthenticationWhenUsingDefaultsThenMatchesNamespace() throws Exception {
this.spring.register(HttpBasicConfig.class, UserConfig.class).autowire();
this.mvc.perform(get("/")).andExpect(status().isUnauthorized());
this.mvc.perform(get("/").with(httpBasic("user", "invalid"))).andExpect(status().isUnauthorized())
MockHttpServletRequestBuilder requestWithInvalidPassword = get("/").with(httpBasic("user", "invalid"));
// @formatter:off
this.mvc.perform(requestWithInvalidPassword)
.andExpect(status().isUnauthorized())
.andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, "Basic realm=\"Realm\""));
this.mvc.perform(get("/").with(httpBasic("user", "password"))).andExpect(status().isNotFound());
// @formatter:on
MockHttpServletRequestBuilder requestWithValidPassword = get("/").with(httpBasic("user", "password"));
this.mvc.perform(requestWithValidPassword).andExpect(status().isNotFound());
}
@Test
public void basicAuthenticationWhenUsingDefaultsInLambdaThenMatchesNamespace() throws Exception {
this.spring.register(HttpBasicLambdaConfig.class, UserConfig.class).autowire();
this.mvc.perform(get("/")).andExpect(status().isUnauthorized());
this.mvc.perform(get("/").with(httpBasic("user", "invalid"))).andExpect(status().isUnauthorized())
MockHttpServletRequestBuilder requestWithInvalidPassword = get("/").with(httpBasic("user", "invalid"));
// @formatter:off
this.mvc.perform(requestWithInvalidPassword)
.andExpect(status().isUnauthorized())
.andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, "Basic realm=\"Realm\""));
this.mvc.perform(get("/").with(httpBasic("user", "password"))).andExpect(status().isNotFound());
// @formatter:on
MockHttpServletRequestBuilder requestWithValidPassword = get("/").with(httpBasic("user", "password"));
this.mvc.perform(requestWithValidPassword).andExpect(status().isNotFound());
}
/**
@ -86,15 +97,23 @@ public class NamespaceHttpBasicTests {
@Test
public void basicAuthenticationWhenUsingCustomRealmThenMatchesNamespace() throws Exception {
this.spring.register(CustomHttpBasicConfig.class, UserConfig.class).autowire();
this.mvc.perform(get("/").with(httpBasic("user", "invalid"))).andExpect(status().isUnauthorized())
MockHttpServletRequestBuilder requestWithInvalidPassword = get("/").with(httpBasic("user", "invalid"));
// @formatter:off
this.mvc.perform(requestWithInvalidPassword)
.andExpect(status().isUnauthorized())
.andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, "Basic realm=\"Custom Realm\""));
// @formatter:on
}
@Test
public void basicAuthenticationWhenUsingCustomRealmInLambdaThenMatchesNamespace() throws Exception {
this.spring.register(CustomHttpBasicLambdaConfig.class, UserConfig.class).autowire();
this.mvc.perform(get("/").with(httpBasic("user", "invalid"))).andExpect(status().isUnauthorized())
MockHttpServletRequestBuilder requestWithInvalidPassword = get("/").with(httpBasic("user", "invalid"));
// @formatter:off
this.mvc.perform(requestWithInvalidPassword)
.andExpect(status().isUnauthorized())
.andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, "Basic realm=\"Custom Realm\""));
// @formatter:on
}
/**

View File

@ -39,6 +39,7 @@ import org.springframework.security.config.test.SpringTestRule;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.FilterChainProxy;
@ -193,8 +194,14 @@ public class NamespaceHttpCustomFilterTests {
@Bean
UserDetailsService userDetailsService() {
return new InMemoryUserDetailsManager(
User.withDefaultPasswordEncoder().username("user").password("password").roles("USER").build());
// @formatter:off
UserDetails user = User.withDefaultPasswordEncoder()
.username("user")
.password("password")
.roles("USER")
.build();
// @formatter:on
return new InMemoryUserDetailsManager(user);
}
}

View File

@ -36,6 +36,7 @@ import org.springframework.security.web.authentication.SavedRequestAwareAuthenti
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.spy;
@ -65,8 +66,13 @@ public class NamespaceHttpFormLoginTests {
this.spring.register(FormLoginConfig.class, UserDetailsServiceConfig.class).autowire();
this.mvc.perform(get("/")).andExpect(redirectedUrl("http://localhost/login"));
this.mvc.perform(post("/login").with(csrf())).andExpect(redirectedUrl("/login?error"));
this.mvc.perform(post("/login").param("username", "user").param("password", "password").with(csrf()))
.andExpect(redirectedUrl("/"));
// @formatter:off
MockHttpServletRequestBuilder loginRequest = post("/login")
.param("username", "user")
.param("password", "password")
.with(csrf());
// @formatter:on
this.mvc.perform(loginRequest).andExpect(redirectedUrl("/"));
}
@Test
@ -75,8 +81,13 @@ public class NamespaceHttpFormLoginTests {
this.mvc.perform(get("/")).andExpect(redirectedUrl("http://localhost/authentication/login"));
this.mvc.perform(post("/authentication/login/process").with(csrf()))
.andExpect(redirectedUrl("/authentication/login?failed"));
this.mvc.perform(post("/authentication/login/process").param("username", "user").param("password", "password")
.with(csrf())).andExpect(redirectedUrl("/default"));
// @formatter:off
MockHttpServletRequestBuilder request = post("/authentication/login/process")
.param("username", "user")
.param("password", "password")
.with(csrf());
// @formatter:on
this.mvc.perform(request).andExpect(redirectedUrl("/default"));
}
@Test
@ -85,8 +96,13 @@ public class NamespaceHttpFormLoginTests {
this.mvc.perform(get("/")).andExpect(redirectedUrl("http://localhost/login"));
this.mvc.perform(post("/login").with(csrf())).andExpect(redirectedUrl("/custom/failure"));
verifyBean(WebAuthenticationDetailsSource.class).buildDetails(any(HttpServletRequest.class));
this.mvc.perform(post("/login").param("username", "user").param("password", "password").with(csrf()))
.andExpect(redirectedUrl("/custom/targetUrl"));
// @formatter:off
MockHttpServletRequestBuilder loginRequest = post("/login")
.param("username", "user")
.param("password", "password")
.with(csrf());
// @formatter:on
this.mvc.perform(loginRequest).andExpect(redirectedUrl("/custom/targetUrl"));
}
private <T> T verifyBean(Class<T> beanClass) {

View File

@ -30,6 +30,7 @@ import org.springframework.security.config.test.SpringTestRule;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@ -66,22 +67,26 @@ public class NamespaceHttpInterceptUrlTests {
@Test
public void authenticatedRequestWhenUrlRequiresElevatedPrivilegesThenBehaviorMatchesNamespace() throws Exception {
this.spring.register(HttpInterceptUrlConfig.class).autowire();
this.mvc.perform(get("/users").with(authentication(user("ROLE_USER")))).andExpect(status().isForbidden());
MockHttpServletRequestBuilder requestWithUser = get("/users").with(authentication(user("ROLE_USER")));
this.mvc.perform(requestWithUser).andExpect(status().isForbidden());
}
@Test
public void authenticatedRequestWhenAuthorizedThenBehaviorMatchesNamespace() throws Exception {
this.spring.register(HttpInterceptUrlConfig.class, BaseController.class).autowire();
this.mvc.perform(get("/users").with(authentication(user("ROLE_ADMIN")))).andExpect(status().isOk()).andReturn();
MockHttpServletRequestBuilder requestWithAdmin = get("/users").with(authentication(user("ROLE_ADMIN")));
this.mvc.perform(requestWithAdmin).andExpect(status().isOk()).andReturn();
}
@Test
public void requestWhenMappedByPostInterceptUrlThenBehaviorMatchesNamespace() throws Exception {
this.spring.register(HttpInterceptUrlConfig.class, BaseController.class).autowire();
this.mvc.perform(get("/admin/post").with(authentication(user("ROLE_USER")))).andExpect(status().isOk());
this.mvc.perform(post("/admin/post").with(authentication(user("ROLE_USER")))).andExpect(status().isForbidden());
this.mvc.perform(post("/admin/post").with(csrf()).with(authentication(user("ROLE_ADMIN"))))
.andExpect(status().isOk());
MockHttpServletRequestBuilder getWithUser = get("/admin/post").with(authentication(user("ROLE_USER")));
this.mvc.perform(getWithUser).andExpect(status().isOk());
MockHttpServletRequestBuilder postWithUser = post("/admin/post").with(authentication(user("ROLE_USER")));
this.mvc.perform(postWithUser).andExpect(status().isForbidden());
MockHttpServletRequestBuilder requestWithAdmin = post("/admin/post").with(csrf()).with(authentication(user("ROLE_ADMIN")));
this.mvc.perform(requestWithAdmin).andExpect(status().isOk());
}
@Test

View File

@ -40,6 +40,7 @@ import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuc
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultMatcher;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
@ -72,15 +73,21 @@ public class NamespaceHttpLogoutTests {
@WithMockUser
public void logoutWhenUsingDefaultsThenMatchesNamespace() throws Exception {
this.spring.register(HttpLogoutConfig.class).autowire();
this.mvc.perform(post("/logout").with(csrf())).andExpect(authenticated(false))
.andExpect(redirectedUrl("/login?logout")).andExpect(noCookies()).andExpect(session(Objects::isNull));
// @formatter:off
this.mvc.perform(post("/logout").with(csrf()))
.andExpect(authenticated(false))
.andExpect(redirectedUrl("/login?logout"))
.andExpect(noCookies())
.andExpect(session(Objects::isNull));
// @formatter:on
}
@Test
@WithMockUser
public void logoutWhenDisabledInLambdaThenRespondsWithNotFound() throws Exception {
this.spring.register(HttpLogoutDisabledInLambdaConfig.class).autowire();
this.mvc.perform(post("/logout").with(csrf()).with(user("user"))).andExpect(status().isNotFound());
MockHttpServletRequestBuilder logoutRequest = post("/logout").with(csrf()).with(user("user"));
this.mvc.perform(logoutRequest).andExpect(status().isNotFound());
}
/**
@ -90,20 +97,28 @@ public class NamespaceHttpLogoutTests {
@WithMockUser
public void logoutWhenUsingVariousCustomizationsMatchesNamespace() throws Exception {
this.spring.register(CustomHttpLogoutConfig.class).autowire();
this.mvc.perform(post("/custom-logout").with(csrf())).andExpect(authenticated(false))
// @formatter:off
this.mvc.perform(post("/custom-logout").with(csrf()))
.andExpect(authenticated(false))
.andExpect(redirectedUrl("/logout-success"))
.andExpect((result) -> assertThat(result.getResponse().getCookies()).hasSize(1))
.andExpect(cookie().maxAge("remove", 0)).andExpect(session(Objects::nonNull));
.andExpect(cookie().maxAge("remove", 0))
.andExpect(session(Objects::nonNull));
// @formatter:on
}
@Test
@WithMockUser
public void logoutWhenUsingVariousCustomizationsInLambdaThenMatchesNamespace() throws Exception {
this.spring.register(CustomHttpLogoutInLambdaConfig.class).autowire();
this.mvc.perform(post("/custom-logout").with(csrf())).andExpect(authenticated(false))
// @formatter:off
this.mvc.perform(post("/custom-logout").with(csrf()))
.andExpect(authenticated(false))
.andExpect(redirectedUrl("/logout-success"))
.andExpect((result) -> assertThat(result.getResponse().getCookies()).hasSize(1))
.andExpect(cookie().maxAge("remove", 0)).andExpect(session(Objects::nonNull));
.andExpect(cookie().maxAge("remove", 0))
.andExpect(session(Objects::nonNull));
// @formatter:on
}
/**
@ -113,18 +128,26 @@ public class NamespaceHttpLogoutTests {
@WithMockUser
public void logoutWhenUsingSuccessHandlerRefThenMatchesNamespace() throws Exception {
this.spring.register(SuccessHandlerRefHttpLogoutConfig.class).autowire();
this.mvc.perform(post("/logout").with(csrf())).andExpect(authenticated(false))
.andExpect(redirectedUrl("/SuccessHandlerRefHttpLogoutConfig")).andExpect(noCookies())
// @formatter:off
this.mvc.perform(post("/logout").with(csrf()))
.andExpect(authenticated(false))
.andExpect(redirectedUrl("/SuccessHandlerRefHttpLogoutConfig"))
.andExpect(noCookies())
.andExpect(session(Objects::isNull));
// @formatter:on
}
@Test
@WithMockUser
public void logoutWhenUsingSuccessHandlerRefInLambdaThenMatchesNamespace() throws Exception {
this.spring.register(SuccessHandlerRefHttpLogoutInLambdaConfig.class).autowire();
this.mvc.perform(post("/logout").with(csrf())).andExpect(authenticated(false))
.andExpect(redirectedUrl("/SuccessHandlerRefHttpLogoutConfig")).andExpect(noCookies())
// @formatter:off
this.mvc.perform(post("/logout").with(csrf()))
.andExpect(authenticated(false))
.andExpect(redirectedUrl("/SuccessHandlerRefHttpLogoutConfig"))
.andExpect(noCookies())
.andExpect(session(Objects::isNull));
// @formatter:on
}
ResultMatcher authenticated(boolean authenticated) {

View File

@ -56,6 +56,7 @@ import org.springframework.security.web.authentication.SimpleUrlAuthenticationFa
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
@ -141,19 +142,22 @@ public class NamespaceHttpOpenIDLoginTests {
OpenIDAuthenticationToken token = new OpenIDAuthenticationToken(OpenIDAuthenticationStatus.SUCCESS,
"identityUrl", "message", Arrays.asList(new OpenIDAttribute("name", "type")));
OpenIDLoginCustomRefsConfig.AUDS = mock(AuthenticationUserDetailsService.class);
given(OpenIDLoginCustomRefsConfig.AUDS.loadUserDetails(any(Authentication.class)))
.willReturn(new User("user", "password", AuthorityUtils.createAuthorityList("ROLE_USER")));
User user = new User("user", "password", AuthorityUtils.createAuthorityList("ROLE_USER"));
given(OpenIDLoginCustomRefsConfig.AUDS.loadUserDetails(any(Authentication.class))).willReturn(user);
OpenIDLoginCustomRefsConfig.ADS = spy(new WebAuthenticationDetailsSource());
OpenIDLoginCustomRefsConfig.CONSUMER = mock(OpenIDConsumer.class);
this.spring.register(OpenIDLoginCustomRefsConfig.class, UserDetailsServiceConfig.class).autowire();
given(OpenIDLoginCustomRefsConfig.CONSUMER.endConsumption(any(HttpServletRequest.class)))
.willThrow(new AuthenticationServiceException("boom"));
this.mvc.perform(post("/login/openid").with(csrf()).param("openid.identity", "identity"))
.andExpect(redirectedUrl("/custom/failure"));
// @formatter:off
MockHttpServletRequestBuilder login = post("/login/openid")
.with(csrf())
.param("openid.identity", "identity");
// @formatter:on
this.mvc.perform(login).andExpect(redirectedUrl("/custom/failure"));
reset(OpenIDLoginCustomRefsConfig.CONSUMER);
given(OpenIDLoginCustomRefsConfig.CONSUMER.endConsumption(any(HttpServletRequest.class))).willReturn(token);
this.mvc.perform(post("/login/openid").with(csrf()).param("openid.identity", "identity"))
.andExpect(redirectedUrl("/custom/targetUrl"));
this.mvc.perform(login).andExpect(redirectedUrl("/custom/targetUrl"));
verify(OpenIDLoginCustomRefsConfig.AUDS).loadUserDetails(any(Authentication.class));
verify(OpenIDLoginCustomRefsConfig.ADS).buildDetails(any(Object.class));
}

View File

@ -62,15 +62,21 @@ public class NamespaceHttpServerAccessDeniedHandlerTests {
@Test
public void requestWhenCustomAccessDeniedPageThenBehaviorMatchesNamespace() throws Exception {
this.spring.register(AccessDeniedPageConfig.class).autowire();
this.mvc.perform(get("/").with(authentication(user()))).andExpect(status().isForbidden())
// @formatter:off
this.mvc.perform(get("/").with(authentication(user())))
.andExpect(status().isForbidden())
.andExpect(forwardedUrl("/AccessDeniedPageConfig"));
// @formatter:on
}
@Test
public void requestWhenCustomAccessDeniedPageInLambdaThenForwardedToCustomPage() throws Exception {
this.spring.register(AccessDeniedPageInLambdaConfig.class).autowire();
this.mvc.perform(get("/").with(authentication(user()))).andExpect(status().isForbidden())
// @formatter:off
this.mvc.perform(get("/").with(authentication(user())))
.andExpect(status().isForbidden())
.andExpect(forwardedUrl("/AccessDeniedPageConfig"));
// @formatter:on
}
@Test

View File

@ -282,7 +282,11 @@ public class NamespaceHttpX509Tests {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("rod").password("password").roles("USER", "ADMIN");
// @formatter:off
auth
.inMemoryAuthentication()
.withUser("rod").password("password").roles("USER", "ADMIN");
// @formatter:on
}
@Override

View File

@ -46,6 +46,7 @@ import org.springframework.security.web.authentication.rememberme.PersistentReme
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.test.web.servlet.request.RequestPostProcessor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@ -87,12 +88,25 @@ public class NamespaceRememberMeTests {
assertThat(rememberMe).isNotNull();
this.mvc.perform(get("/authentication-class").cookie(rememberMe))
.andExpect(content().string(RememberMeAuthenticationToken.class.getName()));
result = this.mvc.perform(post("/logout").with(csrf()).session(session).cookie(rememberMe))
.andExpect(redirectedUrl("/login?logout")).andReturn();
// @formatter:off
MockHttpServletRequestBuilder logoutRequest = post("/logout")
.with(csrf())
.session(session)
.cookie(rememberMe);
result = this.mvc.perform(logoutRequest)
.andExpect(redirectedUrl("/login?logout"))
.andReturn();
// @formatter:on
rememberMe = result.getResponse().getCookie("remember-me");
assertThat(rememberMe).isNotNull().extracting(Cookie::getMaxAge).isEqualTo(0);
this.mvc.perform(post("/authentication-class").with(csrf()).cookie(rememberMe))
.andExpect(redirectedUrl("http://localhost/login")).andReturn();
// @formatter:off
MockHttpServletRequestBuilder authenticationClassRequest = post("/authentication-class")
.with(csrf())
.cookie(rememberMe);
this.mvc.perform(authenticationClassRequest)
.andExpect(redirectedUrl("http://localhost/login"))
.andReturn();
// @formatter:on
}
// SEC-3170 - RememberMeService implementations should not have to also implement
@ -125,13 +139,27 @@ public class NamespaceRememberMeTests {
@Test
public void rememberMeLoginWhenKeyDeclaredThenMatchesNamespace() throws Exception {
this.spring.register(WithoutKeyConfig.class, KeyConfig.class, SecurityController.class).autowire();
Cookie withoutKey = this.mvc.perform(post("/without-key/login").with(rememberMeLogin()))
.andExpect(redirectedUrl("/")).andReturn().getResponse().getCookie("remember-me");
this.mvc.perform(get("/somewhere").cookie(withoutKey)).andExpect(status().isFound())
.andExpect(redirectedUrl("http://localhost/login"));
Cookie withKey = this.mvc.perform(post("/login").with(rememberMeLogin())).andReturn().getResponse()
MockHttpServletRequestBuilder requestWithRememberme = post("/without-key/login").with(rememberMeLogin());
// @formatter:off
Cookie withoutKey = this.mvc.perform(requestWithRememberme)
.andExpect(redirectedUrl("/"))
.andReturn()
.getResponse()
.getCookie("remember-me");
this.mvc.perform(get("/somewhere").cookie(withKey)).andExpect(status().isNotFound());
// @formatter:on
MockHttpServletRequestBuilder somewhereRequest = get("/somewhere").cookie(withoutKey);
// @formatter:off
this.mvc.perform(somewhereRequest)
.andExpect(status().isFound())
.andExpect(redirectedUrl("http://localhost/login"));
MockHttpServletRequestBuilder loginWithRememberme = post("/login").with(rememberMeLogin());
Cookie withKey = this.mvc.perform(loginWithRememberme)
.andReturn()
.getResponse()
.getCookie("remember-me");
this.mvc.perform(get("/somewhere").cookie(withKey))
.andExpect(status().isNotFound());
// @formatter:on
}
// http/remember-me@services-alias is not supported use standard aliasing instead
@ -149,40 +177,61 @@ public class NamespaceRememberMeTests {
@Test
public void rememberMeLoginWhenTokenValidityDeclaredThenMatchesNamespace() throws Exception {
this.spring.register(TokenValiditySecondsConfig.class).autowire();
Cookie expiredRememberMe = this.mvc.perform(post("/login").with(rememberMeLogin())).andReturn().getResponse()
// @formatter:off
Cookie expiredRememberMe = this.mvc.perform(post("/login").with(rememberMeLogin()))
.andReturn()
.getResponse()
.getCookie("remember-me");
// @formatter:on
assertThat(expiredRememberMe).extracting(Cookie::getMaxAge).isEqualTo(314);
}
@Test
public void rememberMeLoginWhenUsingDefaultsThenCookieMaxAgeMatchesNamespace() throws Exception {
this.spring.register(RememberMeConfig.class).autowire();
Cookie expiredRememberMe = this.mvc.perform(post("/login").with(rememberMeLogin())).andReturn().getResponse()
// @formatter:off
Cookie expiredRememberMe = this.mvc.perform(post("/login").with(rememberMeLogin()))
.andReturn()
.getResponse()
.getCookie("remember-me");
// @formatter:on
assertThat(expiredRememberMe).extracting(Cookie::getMaxAge).isEqualTo(AbstractRememberMeServices.TWO_WEEKS_S);
}
@Test
public void rememberMeLoginWhenUsingSecureCookieThenMatchesNamespace() throws Exception {
this.spring.register(UseSecureCookieConfig.class).autowire();
Cookie secureCookie = this.mvc.perform(post("/login").with(rememberMeLogin())).andReturn().getResponse()
// @formatter:off
Cookie secureCookie = this.mvc.perform(post("/login").with(rememberMeLogin()))
.andReturn()
.getResponse()
.getCookie("remember-me");
// @formatter:on
assertThat(secureCookie).extracting(Cookie::getSecure).isEqualTo(true);
}
@Test
public void rememberMeLoginWhenUsingDefaultsThenCookieSecurityMatchesNamespace() throws Exception {
this.spring.register(RememberMeConfig.class).autowire();
Cookie secureCookie = this.mvc.perform(post("/login").with(rememberMeLogin()).secure(true)).andReturn()
.getResponse().getCookie("remember-me");
// @formatter:off
Cookie secureCookie = this.mvc.perform(post("/login").with(rememberMeLogin()).secure(true))
.andReturn()
.getResponse()
.getCookie("remember-me");
// @formatter:on
assertThat(secureCookie).extracting(Cookie::getSecure).isEqualTo(true);
}
@Test
public void rememberMeLoginWhenParameterSpecifiedThenMatchesNamespace() throws Exception {
this.spring.register(RememberMeParameterConfig.class).autowire();
Cookie rememberMe = this.mvc.perform(post("/login").with(rememberMeLogin("rememberMe", true))).andReturn()
.getResponse().getCookie("remember-me");
MockHttpServletRequestBuilder loginWithRememberme = post("/login").with(rememberMeLogin("rememberMe", true));
// @formatter:off
Cookie rememberMe = this.mvc.perform(loginWithRememberme)
.andReturn()
.getResponse()
.getCookie("remember-me");
// @formatter:on
assertThat(rememberMe).isNotNull();
}
@ -190,8 +239,12 @@ public class NamespaceRememberMeTests {
@Test
public void rememberMeLoginWhenCookieNameDeclaredThenMatchesNamespace() throws Exception {
this.spring.register(RememberMeCookieNameConfig.class).autowire();
Cookie rememberMe = this.mvc.perform(post("/login").with(rememberMeLogin())).andReturn().getResponse()
// @formatter:off
Cookie rememberMe = this.mvc.perform(post("/login").with(rememberMeLogin()))
.andReturn()
.getResponse()
.getCookie("rememberMe");
// @formatter:on
assertThat(rememberMe).isNotNull();
}
@ -207,8 +260,8 @@ public class NamespaceRememberMeTests {
public void rememberMeLoginWhenUserDetailsServiceDeclaredThenMatchesNamespace() throws Exception {
UserServiceRefConfig.USERDETAILS_SERVICE = mock(UserDetailsService.class);
this.spring.register(UserServiceRefConfig.class).autowire();
given(UserServiceRefConfig.USERDETAILS_SERVICE.loadUserByUsername("user"))
.willReturn(new User("user", "password", AuthorityUtils.createAuthorityList("ROLE_USER")));
User user = new User("user", "password", AuthorityUtils.createAuthorityList("ROLE_USER"));
given(UserServiceRefConfig.USERDETAILS_SERVICE.loadUserByUsername("user")).willReturn(user);
this.mvc.perform(post("/login").with(rememberMeLogin()));
verify(UserServiceRefConfig.USERDETAILS_SERVICE).loadUserByUsername("user");
}
@ -470,7 +523,7 @@ public class NamespaceRememberMeTests {
@Bean
public UserDetailsService userDetailsService() {
return new InMemoryUserDetailsManager(
// @formatter:off
// @formatter:off
User.withDefaultPasswordEncoder()
.username("user")
.password("password")

View File

@ -52,6 +52,7 @@ import org.springframework.security.web.session.InvalidSessionStrategy;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.ResultMatcher;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@ -84,19 +85,24 @@ public class NamespaceSessionManagementTests {
.autowire();
MockHttpSession session = new MockHttpSession();
String sessionId = session.getId();
MvcResult result = this.mvc.perform(get("/auth").session(session).with(httpBasic("user", "password")))
.andExpect(session()).andReturn();
MockHttpServletRequestBuilder request = get("/auth").session(session).with(httpBasic("user", "password"));
// @formatter:off
MvcResult result = this.mvc.perform(request)
.andExpect(session())
.andReturn();
// @formatter:on
assertThat(result.getRequest().getSession(false).getId()).isNotEqualTo(sessionId);
}
@Test
public void authenticateWhenUsingInvalidSessionUrlThenMatchesNamespace() throws Exception {
this.spring.register(CustomSessionManagementConfig.class).autowire();
this.mvc.perform(get("/auth").with((request) -> {
MockHttpServletRequestBuilder request = get("/auth").with((request) -> {
request.setRequestedSessionIdValid(false);
request.setRequestedSessionId("id");
return request;
})).andExpect(redirectedUrl("/invalid-session"));
});
this.mvc.perform(request).andExpect(redirectedUrl("/invalid-session"));
}
@Test
@ -127,8 +133,12 @@ public class NamespaceSessionManagementTests {
mock.setSession(new MockHttpSession());
given(mock.changeSessionId()).willThrow(SessionAuthenticationException.class);
mock.setMethod("GET");
this.mvc.perform(get("/auth").with((request) -> mock).with(httpBasic("user", "password")))
.andExpect(redirectedUrl("/session-auth-error"));
// @formatter:off
MockHttpServletRequestBuilder request = get("/auth")
.with((request) -> mock)
.with(httpBasic("user", "password"));
// @formatter:on
this.mvc.perform(request).andExpect(redirectedUrl("/session-auth-error"));
}
@Test
@ -136,7 +146,8 @@ public class NamespaceSessionManagementTests {
this.spring.register(CustomSessionManagementConfig.class, BasicController.class, UserDetailsServiceConfig.class)
.autowire();
SessionRegistry sessionRegistry = this.spring.getContext().getBean(SessionRegistry.class);
this.mvc.perform(get("/auth").with(httpBasic("user", "password"))).andExpect(status().isOk());
MockHttpServletRequestBuilder request = get("/auth").with(httpBasic("user", "password"));
this.mvc.perform(request).andExpect(status().isOk());
verify(sessionRegistry).registerNewSession(any(String.class), any(Object.class));
}
@ -144,11 +155,12 @@ public class NamespaceSessionManagementTests {
@Test
public void authenticateWhenUsingCustomInvalidSessionStrategyThenMatchesNamespace() throws Exception {
this.spring.register(InvalidSessionStrategyConfig.class).autowire();
this.mvc.perform(get("/auth").with((request) -> {
MockHttpServletRequestBuilder request = get("/auth").with((request) -> {
request.setRequestedSessionIdValid(false);
request.setRequestedSessionId("id");
return request;
})).andExpect(status().isOk());
});
this.mvc.perform(request).andExpect(status().isOk());
verifyBean(InvalidSessionStrategy.class).onInvalidSessionDetected(any(HttpServletRequest.class),
any(HttpServletResponse.class));
}
@ -157,7 +169,8 @@ public class NamespaceSessionManagementTests {
public void authenticateWhenUsingCustomSessionAuthenticationStrategyThenMatchesNamespace() throws Exception {
this.spring.register(RefsSessionManagementConfig.class, BasicController.class, UserDetailsServiceConfig.class)
.autowire();
this.mvc.perform(get("/auth").with(httpBasic("user", "password"))).andExpect(status().isOk());
MockHttpServletRequestBuilder request = get("/auth").with(httpBasic("user", "password"));
this.mvc.perform(request).andExpect(status().isOk());
verifyBean(SessionAuthenticationStrategy.class).onAuthentication(any(Authentication.class),
any(HttpServletRequest.class), any(HttpServletResponse.class));
}
@ -169,9 +182,16 @@ public class NamespaceSessionManagementTests {
.autowire();
MockHttpSession givenSession = new MockHttpSession();
String givenSessionId = givenSession.getId();
MockHttpSession resultingSession = (MockHttpSession) this.mvc
.perform(get("/auth").session(givenSession).with(httpBasic("user", "password")))
.andExpect(status().isOk()).andReturn().getRequest().getSession(false);
// @formatter:off
MockHttpServletRequestBuilder request = get("/auth")
.session(givenSession)
.with(httpBasic("user", "password"));
MockHttpSession resultingSession = (MockHttpSession) this.mvc.perform(request)
.andExpect(status().isOk())
.andReturn()
.getRequest()
.getSession(false);
// @formatter:on
assertThat(givenSessionId).isEqualTo(resultingSession.getId());
}
@ -182,9 +202,15 @@ public class NamespaceSessionManagementTests {
MockHttpSession givenSession = new MockHttpSession();
String givenSessionId = givenSession.getId();
givenSession.setAttribute("name", "value");
MockHttpSession resultingSession = (MockHttpSession) this.mvc
.perform(get("/auth").session(givenSession).with(httpBasic("user", "password")))
.andExpect(status().isOk()).andReturn().getRequest().getSession(false);
// @formatter:off
MockHttpSession resultingSession = (MockHttpSession) this.mvc.perform(get("/auth")
.session(givenSession)
.with(httpBasic("user", "password")))
.andExpect(status().isOk())
.andReturn()
.getRequest()
.getSession(false);
// @formatter:on
assertThat(givenSessionId).isNotEqualTo(resultingSession.getId());
assertThat(resultingSession.getAttribute("name")).isEqualTo("value");
}
@ -193,8 +219,12 @@ public class NamespaceSessionManagementTests {
@Test
public void authenticateWhenUsingSessionFixationProtectionThenUsesNonNullEventPublisher() throws Exception {
this.spring.register(SFPPostProcessedConfig.class, UserDetailsServiceConfig.class).autowire();
this.mvc.perform(get("/auth").session(new MockHttpSession()).with(httpBasic("user", "password")))
.andExpect(status().isNotFound());
// @formatter:off
MockHttpServletRequestBuilder request = get("/auth")
.session(new MockHttpSession())
.with(httpBasic("user", "password"));
// @formatter:on
this.mvc.perform(request).andExpect(status().isNotFound());
verifyBean(MockEventListener.class).onApplicationEvent(any(SessionFixationProtectionEvent.class));
}
@ -204,9 +234,15 @@ public class NamespaceSessionManagementTests {
MockHttpSession givenSession = new MockHttpSession();
String givenSessionId = givenSession.getId();
givenSession.setAttribute("name", "value");
MockHttpSession resultingSession = (MockHttpSession) this.mvc
.perform(get("/auth").session(givenSession).with(httpBasic("user", "password")))
.andExpect(status().isNotFound()).andReturn().getRequest().getSession(false);
MockHttpServletRequestBuilder request = get("/auth").session(givenSession)
.with(httpBasic("user", "password"));
// @formatter:off
MockHttpSession resultingSession = (MockHttpSession) this.mvc.perform(request)
.andExpect(status().isNotFound())
.andReturn()
.getRequest()
.getSession(false);
// @formatter:on
assertThat(givenSessionId).isNotEqualTo(resultingSession.getId());
assertThat(resultingSession.getAttribute("name")).isNull();
}

View File

@ -26,6 +26,7 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.test.SpringTestRule;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
@ -49,10 +50,14 @@ public class PermitAllSupportTests {
@Test
public void performWhenUsingPermitAllExactUrlRequestMatcherThenMatchesExactUrl() throws Exception {
this.spring.register(PermitAllConfig.class).autowire();
this.mvc.perform(get("/app/xyz").contextPath("/app")).andExpect(status().isNotFound());
this.mvc.perform(get("/app/xyz?def").contextPath("/app")).andExpect(status().isFound());
this.mvc.perform(post("/app/abc?def").with(csrf()).contextPath("/app")).andExpect(status().isNotFound());
this.mvc.perform(get("/app/abc").with(csrf()).contextPath("/app")).andExpect(status().isFound());
MockHttpServletRequestBuilder request = get("/app/xyz").contextPath("/app");
this.mvc.perform(request).andExpect(status().isNotFound());
MockHttpServletRequestBuilder getWithQuery = get("/app/xyz?def").contextPath("/app");
this.mvc.perform(getWithQuery).andExpect(status().isFound());
MockHttpServletRequestBuilder postWithQueryAndCsrf = post("/app/abc?def").with(csrf()).contextPath("/app");
this.mvc.perform(postWithQueryAndCsrf).andExpect(status().isNotFound());
MockHttpServletRequestBuilder getWithCsrf = get("/app/abc").with(csrf()).contextPath("/app");
this.mvc.perform(getWithCsrf).andExpect(status().isFound());
}
@Test

View File

@ -40,11 +40,13 @@ import org.springframework.security.core.userdetails.PasswordEncodedUser;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers;
import org.springframework.security.web.authentication.RememberMeServices;
import org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter;
import org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
@ -83,8 +85,16 @@ public class RememberMeConfigurerTests {
public void postWhenNoUserDetailsServiceThenException() {
this.spring.register(NullUserDetailsConfig.class).autowire();
assertThatIllegalStateException()
.isThrownBy(() -> this.mvc.perform(post("/login").param("username", "user")
.param("password", "password").param("remember-me", "true").with(csrf())))
.isThrownBy(() -> {
// @formatter:off
MockHttpServletRequestBuilder request = post("/login")
.param("username", "user")
.param("password", "password")
.param("remember-me", "true")
.with(csrf());
// @formatter:on
this.mvc.perform(request);
})
.withMessageContaining("UserDetailsService is required");
}
@ -99,15 +109,26 @@ public class RememberMeConfigurerTests {
given(DuplicateDoesNotOverrideConfig.userDetailsService.loadUserByUsername(anyString()))
.willReturn(new User("user", "password", Collections.emptyList()));
this.spring.register(DuplicateDoesNotOverrideConfig.class).autowire();
this.mvc.perform(get("/").with(httpBasic("user", "password")).param("remember-me", "true"));
// @formatter:off
MockHttpServletRequestBuilder request = get("/")
.with(httpBasic("user", "password"))
.param("remember-me", "true");
// @formatter:on
this.mvc.perform(request);
verify(DuplicateDoesNotOverrideConfig.userDetailsService).loadUserByUsername("user");
}
@Test
public void loginWhenRememberMeTrueThenRespondsWithRememberMeCookie() throws Exception {
this.spring.register(RememberMeConfig.class).autowire();
this.mvc.perform(post("/login").with(csrf()).param("username", "user").param("password", "password")
.param("remember-me", "true")).andExpect(cookie().exists("remember-me"));
// @formatter:off
MockHttpServletRequestBuilder request = post("/login")
.with(csrf())
.param("username", "user")
.param("password", "password")
.param("remember-me", "true");
// @formatter:on
this.mvc.perform(request).andExpect(cookie().exists("remember-me"));
}
@Test
@ -116,57 +137,108 @@ public class RememberMeConfigurerTests {
MvcResult mvcResult = this.mvc.perform(post("/login").with(csrf()).param("username", "user")
.param("password", "password").param("remember-me", "true")).andReturn();
Cookie rememberMeCookie = mvcResult.getResponse().getCookie("remember-me");
this.mvc.perform(get("/abc").cookie(rememberMeCookie)).andExpect(authenticated()
.withAuthentication((auth) -> assertThat(auth).isInstanceOf(RememberMeAuthenticationToken.class)));
// @formatter:off
MockHttpServletRequestBuilder request = get("/abc").cookie(rememberMeCookie);
SecurityMockMvcResultMatchers.AuthenticatedMatcher remembermeAuthentication = authenticated()
.withAuthentication((auth) -> assertThat(auth).isInstanceOf(RememberMeAuthenticationToken.class));
// @formatter:on
this.mvc.perform(request).andExpect(remembermeAuthentication);
}
@Test
public void logoutWhenRememberMeCookieThenAuthenticationIsRememberMeCookieExpired() throws Exception {
this.spring.register(RememberMeConfig.class).autowire();
MvcResult mvcResult = this.mvc.perform(post("/login").with(csrf()).param("username", "user")
.param("password", "password").param("remember-me", "true")).andReturn();
// @formatter:off
MockHttpServletRequestBuilder loginRequest = post("/login")
.with(csrf())
.param("username", "user")
.param("password", "password")
.param("remember-me", "true");
// @formatter:on
MvcResult mvcResult = this.mvc.perform(loginRequest).andReturn();
Cookie rememberMeCookie = mvcResult.getResponse().getCookie("remember-me");
HttpSession session = mvcResult.getRequest().getSession();
this.mvc.perform(post("/logout").with(csrf()).cookie(rememberMeCookie).session((MockHttpSession) session))
.andExpect(redirectedUrl("/login?logout")).andExpect(cookie().maxAge("remember-me", 0));
// @formatter:off
MockHttpServletRequestBuilder logoutRequest = post("/logout")
.with(csrf())
.cookie(rememberMeCookie)
.session((MockHttpSession) session);
this.mvc.perform(logoutRequest)
.andExpect(redirectedUrl("/login?logout"))
.andExpect(cookie().maxAge("remember-me", 0));
// @formatter:on
}
@Test
public void getWhenRememberMeCookieAndLoggedOutThenRedirectsToLogin() throws Exception {
this.spring.register(RememberMeConfig.class).autowire();
MvcResult loginMvcResult = this.mvc.perform(post("/login").with(csrf()).param("username", "user")
.param("password", "password").param("remember-me", "true")).andReturn();
// @formatter:off
MockHttpServletRequestBuilder loginRequest = post("/login")
.with(csrf())
.param("username", "user")
.param("password", "password")
.param("remember-me", "true");
// @formatter:on
MvcResult loginMvcResult = this.mvc.perform(loginRequest).andReturn();
Cookie rememberMeCookie = loginMvcResult.getResponse().getCookie("remember-me");
HttpSession session = loginMvcResult.getRequest().getSession();
MvcResult logoutMvcResult = this.mvc
.perform(post("/logout").with(csrf()).cookie(rememberMeCookie).session((MockHttpSession) session))
.andReturn();
// @formatter:off
MockHttpServletRequestBuilder logoutRequest = post("/logout")
.with(csrf())
.cookie(rememberMeCookie)
.session((MockHttpSession) session);
// @formatter:on
MvcResult logoutMvcResult = this.mvc.perform(logoutRequest).andReturn();
Cookie expiredRememberMeCookie = logoutMvcResult.getResponse().getCookie("remember-me");
this.mvc.perform(get("/abc").with(csrf()).cookie(expiredRememberMeCookie))
.andExpect(redirectedUrl("http://localhost/login"));
// @formatter:off
MockHttpServletRequestBuilder expiredRequest = get("/abc")
.with(csrf())
.cookie(expiredRememberMeCookie);
// @formatter:on
this.mvc.perform(expiredRequest).andExpect(redirectedUrl("http://localhost/login"));
}
@Test
public void loginWhenRememberMeConfiguredInLambdaThenRespondsWithRememberMeCookie() throws Exception {
this.spring.register(RememberMeInLambdaConfig.class).autowire();
this.mvc.perform(post("/login").with(csrf()).param("username", "user").param("password", "password")
.param("remember-me", "true")).andExpect(cookie().exists("remember-me"));
// @formatter:off
MockHttpServletRequestBuilder request = post("/login")
.with(csrf())
.param("username", "user")
.param("password", "password")
.param("remember-me", "true");
// @formatter:on
this.mvc.perform(request).andExpect(cookie().exists("remember-me"));
}
@Test
public void loginWhenRememberMeTrueAndCookieDomainThenRememberMeCookieHasDomain() throws Exception {
this.spring.register(RememberMeCookieDomainConfig.class).autowire();
this.mvc.perform(post("/login").with(csrf()).param("username", "user").param("password", "password")
.param("remember-me", "true")).andExpect(cookie().exists("remember-me"))
// @formatter:off
MockHttpServletRequestBuilder request = post("/login")
.with(csrf())
.param("username", "user")
.param("password", "password")
.param("remember-me", "true");
this.mvc.perform(request).
andExpect(cookie().exists("remember-me"))
.andExpect(cookie().domain("remember-me", "spring.io"));
// @formatter:on
}
@Test
public void loginWhenRememberMeTrueAndCookieDomainInLambdaThenRememberMeCookieHasDomain() throws Exception {
this.spring.register(RememberMeCookieDomainInLambdaConfig.class).autowire();
this.mvc.perform(post("/login").with(csrf()).param("username", "user").param("password", "password")
.param("remember-me", "true")).andExpect(cookie().exists("remember-me"))
// @formatter:off
MockHttpServletRequestBuilder loginRequest = post("/login")
.with(csrf())
.param("username", "user")
.param("password", "password")
.param("remember-me", "true");
this.mvc.perform(loginRequest)
.andExpect(cookie().exists("remember-me"))
.andExpect(cookie().domain("remember-me", "spring.io"));
// @formatter:on
}
@Test
@ -181,11 +253,21 @@ public class RememberMeConfigurerTests {
@Test
public void getWhenRememberMeCookieAndNoKeyConfiguredThenKeyFromRememberMeServicesIsUsed() throws Exception {
this.spring.register(FallbackRememberMeKeyConfig.class).autowire();
MvcResult mvcResult = this.mvc.perform(post("/login").with(csrf()).param("username", "user")
.param("password", "password").param("remember-me", "true")).andReturn();
// @formatter:off
MockHttpServletRequestBuilder loginRequest = post("/login")
.with(csrf())
.param("username", "user")
.param("password", "password")
.param("remember-me", "true");
// @formatter:on
MvcResult mvcResult = this.mvc.perform(loginRequest).andReturn();
Cookie rememberMeCookie = mvcResult.getResponse().getCookie("remember-me");
this.mvc.perform(get("/abc").cookie(rememberMeCookie)).andExpect(authenticated()
.withAuthentication((auth) -> assertThat(auth).isInstanceOf(RememberMeAuthenticationToken.class)));
MockHttpServletRequestBuilder requestWithRememberme = get("/abc").cookie(rememberMeCookie);
// @formatter:off
SecurityMockMvcResultMatchers.AuthenticatedMatcher remembermeAuthentication = authenticated()
.withAuthentication((auth) -> assertThat(auth).isInstanceOf(RememberMeAuthenticationToken.class));
// @formatter:on
this.mvc.perform(requestWithRememberme).andExpect(remembermeAuthentication);
}
@EnableWebSecurity

View File

@ -40,6 +40,8 @@ import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.security.web.savedrequest.RequestCacheAwareFilter;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.RequestBuilder;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.test.web.servlet.request.MockMultipartHttpServletRequestBuilder;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
@ -83,41 +85,63 @@ public class RequestCacheConfigurerTests {
@Test
public void getWhenBookmarkedUrlIsFaviconIcoThenPostAuthenticationRedirectsToRoot() throws Exception {
this.spring.register(RequestCacheDefaultsConfig.class, DefaultSecurityConfig.class).autowire();
// @formatter:off
MockHttpSession session = (MockHttpSession) this.mvc.perform(get("/favicon.ico"))
.andExpect(redirectedUrl("http://localhost/login")).andReturn().getRequest().getSession();
this.mvc.perform(formLogin(session)).andExpect(redirectedUrl("/")); // ignores
// favicon.ico
.andExpect(redirectedUrl("http://localhost/login"))
.andReturn()
.getRequest()
.getSession();
// @formatter:on
// ignores favicon.ico
this.mvc.perform(formLogin(session)).andExpect(redirectedUrl("/"));
}
@Test
public void getWhenBookmarkedUrlIsFaviconPngThenPostAuthenticationRedirectsToRoot() throws Exception {
this.spring.register(RequestCacheDefaultsConfig.class, DefaultSecurityConfig.class).autowire();
// @formatter:off
MockHttpSession session = (MockHttpSession) this.mvc.perform(get("/favicon.png"))
.andExpect(redirectedUrl("http://localhost/login")).andReturn().getRequest().getSession();
this.mvc.perform(formLogin(session)).andExpect(redirectedUrl("/")); // ignores
// favicon.png
.andExpect(redirectedUrl("http://localhost/login"))
.andReturn()
.getRequest()
.getSession();
// @formatter:on
// ignores favicon.png
this.mvc.perform(formLogin(session)).andExpect(redirectedUrl("/"));
}
// SEC-2321
@Test
public void getWhenBookmarkedRequestIsApplicationJsonThenPostAuthenticationRedirectsToRoot() throws Exception {
this.spring.register(RequestCacheDefaultsConfig.class, DefaultSecurityConfig.class).autowire();
MockHttpSession session = (MockHttpSession) this.mvc
.perform(get("/messages").header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON))
.andExpect(redirectedUrl("http://localhost/login")).andReturn().getRequest().getSession();
this.mvc.perform(formLogin(session)).andExpect(redirectedUrl("/")); // ignores
// application/json
MockHttpServletRequestBuilder request = get("/messages").header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON);
// @formatter:off
MockHttpSession session = (MockHttpSession) this.mvc.perform(request)
.andExpect(redirectedUrl("http://localhost/login"))
.andReturn()
.getRequest()
.getSession();
// @formatter:on
// ignores application/json
// This is desirable since JSON requests are typically not invoked directly from
// the browser and we don't want the browser to replay them
this.mvc.perform(formLogin(session)).andExpect(redirectedUrl("/"));
}
// SEC-2321
@Test
public void getWhenBookmarkedRequestIsXRequestedWithThenPostAuthenticationRedirectsToRoot() throws Exception {
this.spring.register(RequestCacheDefaultsConfig.class, DefaultSecurityConfig.class).autowire();
// @formatter:off
MockHttpServletRequestBuilder xRequestedWith = get("/messages")
.header("X-Requested-With", "XMLHttpRequest");
MockHttpSession session = (MockHttpSession) this.mvc
.perform(get("/messages").header("X-Requested-With", "XMLHttpRequest"))
.andExpect(redirectedUrl("http://localhost/login")).andReturn().getRequest().getSession();
.perform(xRequestedWith)
.andExpect(redirectedUrl("http://localhost/login"))
.andReturn()
.getRequest()
.getSession();
// @formatter:on
this.mvc.perform(formLogin(session)).andExpect(redirectedUrl("/"));
// This is desirable since XHR requests are typically not invoked directly from
// the browser and we don't want the browser to replay them
@ -126,49 +150,75 @@ public class RequestCacheConfigurerTests {
@Test
public void getWhenBookmarkedRequestIsTextEventStreamThenPostAuthenticationRedirectsToRoot() throws Exception {
this.spring.register(RequestCacheDefaultsConfig.class, DefaultSecurityConfig.class).autowire();
MockHttpSession session = (MockHttpSession) this.mvc
.perform(get("/messages").header(HttpHeaders.ACCEPT, MediaType.TEXT_EVENT_STREAM))
.andExpect(redirectedUrl("http://localhost/login")).andReturn().getRequest().getSession();
this.mvc.perform(formLogin(session)).andExpect(redirectedUrl("/")); // ignores
// text/event-stream
MockHttpServletRequestBuilder request = get("/messages").header(HttpHeaders.ACCEPT, MediaType.TEXT_EVENT_STREAM);
// @formatter:off
MockHttpSession session = (MockHttpSession) this.mvc.perform(request)
.andExpect(redirectedUrl("http://localhost/login"))
.andReturn()
.getRequest()
.getSession();
// @formatter:on
// ignores text/event-stream
// This is desirable since event-stream requests are typically not invoked
// directly from the browser and we don't want the browser to replay them
this.mvc.perform(formLogin(session)).andExpect(redirectedUrl("/"));
}
@Test
public void getWhenBookmarkedRequestIsAllMediaTypeThenPostAuthenticationRemembers() throws Exception {
this.spring.register(RequestCacheDefaultsConfig.class, DefaultSecurityConfig.class).autowire();
MockHttpSession session = (MockHttpSession) this.mvc
.perform(get("/messages").header(HttpHeaders.ACCEPT, MediaType.ALL))
.andExpect(redirectedUrl("http://localhost/login")).andReturn().getRequest().getSession();
MockHttpServletRequestBuilder request = get("/messages").header(HttpHeaders.ACCEPT, MediaType.ALL);
// @formatter:off
MockHttpSession session = (MockHttpSession) this.mvc.perform(request)
.andExpect(redirectedUrl("http://localhost/login"))
.andReturn()
.getRequest()
.getSession();
// @formatter:on
this.mvc.perform(formLogin(session)).andExpect(redirectedUrl("http://localhost/messages"));
}
@Test
public void getWhenBookmarkedRequestIsTextHtmlThenPostAuthenticationRemembers() throws Exception {
this.spring.register(RequestCacheDefaultsConfig.class, DefaultSecurityConfig.class).autowire();
MockHttpSession session = (MockHttpSession) this.mvc
.perform(get("/messages").header(HttpHeaders.ACCEPT, MediaType.TEXT_HTML))
.andExpect(redirectedUrl("http://localhost/login")).andReturn().getRequest().getSession();
MockHttpServletRequestBuilder request = get("/messages").header(HttpHeaders.ACCEPT, MediaType.TEXT_HTML);
// @formatter:off
MockHttpSession session = (MockHttpSession) this.mvc.perform(request)
.andExpect(redirectedUrl("http://localhost/login"))
.andReturn()
.getRequest()
.getSession();
// @formatter:on
this.mvc.perform(formLogin(session)).andExpect(redirectedUrl("http://localhost/messages"));
}
@Test
public void getWhenBookmarkedRequestIsChromeThenPostAuthenticationRemembers() throws Exception {
this.spring.register(RequestCacheDefaultsConfig.class, DefaultSecurityConfig.class).autowire();
MockHttpSession session = (MockHttpSession) this.mvc
.perform(get("/messages").header(HttpHeaders.ACCEPT,
"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8"))
.andExpect(redirectedUrl("http://localhost/login")).andReturn().getRequest().getSession();
// @formatter:off
MockHttpServletRequestBuilder request = get("/messages")
.header(HttpHeaders.ACCEPT, "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
MockHttpSession session = (MockHttpSession) this.mvc.perform(request)
.andExpect(redirectedUrl("http://localhost/login"))
.andReturn()
.getRequest()
.getSession();
// @formatter:on
this.mvc.perform(formLogin(session)).andExpect(redirectedUrl("http://localhost/messages"));
}
@Test
public void getWhenBookmarkedRequestIsRequestedWithAndroidThenPostAuthenticationRemembers() throws Exception {
this.spring.register(RequestCacheDefaultsConfig.class, DefaultSecurityConfig.class).autowire();
MockHttpSession session = (MockHttpSession) this.mvc
.perform(get("/messages").header("X-Requested-With", "com.android"))
.andExpect(redirectedUrl("http://localhost/login")).andReturn().getRequest().getSession();
// @formatter:off
MockHttpServletRequestBuilder request = get("/messages")
.header("X-Requested-With", "com.android");
MockHttpSession session = (MockHttpSession) this.mvc.perform(request)
.andExpect(redirectedUrl("http://localhost/login"))
.andReturn()
.getRequest()
.getSession();
// @formatter:on
this.mvc.perform(formLogin(session)).andExpect(redirectedUrl("http://localhost/messages"));
}
@ -177,7 +227,12 @@ public class RequestCacheConfigurerTests {
public void getWhenRequestCacheIsDisabledThenExceptionTranslationFilterDoesNotStoreRequest() throws Exception {
this.spring.register(RequestCacheDisabledConfig.class,
ExceptionHandlingConfigurerTests.DefaultSecurityConfig.class).autowire();
MockHttpSession session = (MockHttpSession) this.mvc.perform(get("/bob")).andReturn().getRequest().getSession();
// @formatter:off
MockHttpSession session = (MockHttpSession) this.mvc.perform(get("/bob"))
.andReturn()
.getRequest()
.getSession();
// @formatter:on
this.mvc.perform(formLogin(session)).andExpect(redirectedUrl("/"));
}
@ -186,8 +241,13 @@ public class RequestCacheConfigurerTests {
public void postWhenRequestIsMultipartThenPostAuthenticationRedirectsToRoot() throws Exception {
this.spring.register(RequestCacheDefaultsConfig.class, DefaultSecurityConfig.class).autowire();
MockMultipartFile aFile = new MockMultipartFile("aFile", "A_FILE".getBytes());
MockHttpSession session = (MockHttpSession) this.mvc.perform(multipart("/upload").file(aFile)).andReturn()
.getRequest().getSession();
MockMultipartHttpServletRequestBuilder request = multipart("/upload").file(aFile);
// @formatter:off
MockHttpSession session = (MockHttpSession) this.mvc.perform(request)
.andReturn()
.getRequest()
.getSession();
// @formatter:on
this.mvc.perform(formLogin(session)).andExpect(redirectedUrl("/"));
}
@ -195,26 +255,47 @@ public class RequestCacheConfigurerTests {
public void getWhenRequestCacheIsDisabledInLambdaThenExceptionTranslationFilterDoesNotStoreRequest()
throws Exception {
this.spring.register(RequestCacheDisabledInLambdaConfig.class, DefaultSecurityConfig.class).autowire();
MockHttpSession session = (MockHttpSession) this.mvc.perform(get("/bob")).andReturn().getRequest().getSession();
// @formatter:off
MockHttpSession session = (MockHttpSession) this.mvc.perform(get("/bob"))
.andReturn()
.getRequest()
.getSession();
// @formatter:on
this.mvc.perform(formLogin(session)).andExpect(redirectedUrl("/"));
}
@Test
public void getWhenRequestCacheInLambdaThenRedirectedToCachedPage() throws Exception {
this.spring.register(RequestCacheInLambdaConfig.class, DefaultSecurityConfig.class).autowire();
MockHttpSession session = (MockHttpSession) this.mvc.perform(get("/bob")).andReturn().getRequest().getSession();
// @formatter:off
MockHttpSession session = (MockHttpSession) this.mvc.perform(get("/bob"))
.andReturn()
.getRequest()
.getSession();
// @formatter:on
this.mvc.perform(formLogin(session)).andExpect(redirectedUrl("http://localhost/bob"));
}
@Test
public void getWhenCustomRequestCacheInLambdaThenCustomRequestCacheUsed() throws Exception {
this.spring.register(CustomRequestCacheInLambdaConfig.class, DefaultSecurityConfig.class).autowire();
MockHttpSession session = (MockHttpSession) this.mvc.perform(get("/bob")).andReturn().getRequest().getSession();
// @formatter:off
MockHttpSession session = (MockHttpSession) this.mvc.perform(get("/bob"))
.andReturn()
.getRequest()
.getSession();
// @formatter:on
this.mvc.perform(formLogin(session)).andExpect(redirectedUrl("/"));
}
private static RequestBuilder formLogin(MockHttpSession session) {
return post("/login").param("username", "user").param("password", "password").session(session).with(csrf());
// @formatter:off
return post("/login")
.param("username", "user")
.param("password", "password")
.session(session)
.with(csrf());
// @formatter:on
}
@EnableWebSecurity

View File

@ -47,15 +47,23 @@ public class RequestMatcherConfigurerTests {
@Test
public void authorizeRequestsWhenInvokedMultipleTimesThenChainsPaths() throws Exception {
this.spring.register(Sec2908Config.class).autowire();
this.mvc.perform(get("/oauth/abc")).andExpect(status().isForbidden());
this.mvc.perform(get("/api/abc")).andExpect(status().isForbidden());
// @formatter:off
this.mvc.perform(get("/oauth/abc"))
.andExpect(status().isForbidden());
this.mvc.perform(get("/api/abc"))
.andExpect(status().isForbidden());
// @formatter:on
}
@Test
public void authorizeRequestsWhenInvokedMultipleTimesInLambdaThenChainsPaths() throws Exception {
this.spring.register(AuthorizeRequestInLambdaConfig.class).autowire();
this.mvc.perform(get("/oauth/abc")).andExpect(status().isForbidden());
this.mvc.perform(get("/api/abc")).andExpect(status().isForbidden());
// @formatter:off
this.mvc.perform(get("/oauth/abc"))
.andExpect(status().isForbidden());
this.mvc.perform(get("/api/abc"))
.andExpect(status().isForbidden());
// @formatter:on
}
@EnableWebSecurity

View File

@ -42,6 +42,7 @@ import org.springframework.security.config.test.SpringTestRule;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.PasswordEncodedUser;
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors;
import org.springframework.security.util.FieldUtils;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.FilterChainProxy;
@ -52,6 +53,7 @@ import org.springframework.security.web.authentication.logout.LogoutSuccessEvent
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@ -109,9 +111,9 @@ public class ServletApiConfigurerTests {
@Test
public void configureWhenUsingDefaultsThenRolePrefixIsSet() throws Exception {
this.spring.register(ServletApiConfig.class, AdminController.class).autowire();
this.mvc.perform(
get("/admin").with(authentication(new TestingAuthenticationToken("user", "pass", "ROLE_ADMIN"))))
.andExpect(status().isOk());
TestingAuthenticationToken user = new TestingAuthenticationToken("user", "pass", "ROLE_ADMIN");
MockHttpServletRequestBuilder request = get("/admin").with(authentication(user));
this.mvc.perform(request).andExpect(status().isOk());
}
@Test
@ -125,11 +127,18 @@ public class ServletApiConfigurerTests {
@Test
public void servletApiWhenInvokedTwiceThenUsesOriginalRole() throws Exception {
this.spring.register(DuplicateInvocationsDoesNotOverrideConfig.class, AdminController.class).autowire();
this.mvc.perform(
get("/admin").with(user("user").authorities(AuthorityUtils.createAuthorityList("PERMISSION_ADMIN"))))
// @formatter:off
MockHttpServletRequestBuilder request = get("/admin")
.with(user("user").authorities(AuthorityUtils.createAuthorityList("PERMISSION_ADMIN")));
this.mvc.perform(request)
.andExpect(status().isOk());
this.mvc.perform(get("/admin").with(user("user").authorities(AuthorityUtils.createAuthorityList("ROLE_ADMIN"))))
SecurityMockMvcRequestPostProcessors.UserRequestPostProcessor userWithRoleAdmin = user("user")
.authorities(AuthorityUtils.createAuthorityList("ROLE_ADMIN"));
MockHttpServletRequestBuilder requestWithRoleAdmin = get("/admin")
.with(userWithRoleAdmin);
this.mvc.perform(requestWithRoleAdmin)
.andExpect(status().isForbidden());
// @formatter:on
}
@Test
@ -142,18 +151,25 @@ public class ServletApiConfigurerTests {
@Test
public void requestWhenServletApiWithDefaultsInLambdaThenUsesDefaultRolePrefix() throws Exception {
this.spring.register(ServletApiWithDefaultsInLambdaConfig.class, AdminController.class).autowire();
this.mvc.perform(get("/admin").with(user("user").authorities(AuthorityUtils.createAuthorityList("ROLE_ADMIN"))))
MockHttpServletRequestBuilder request = get("/admin")
.with(user("user").authorities(AuthorityUtils.createAuthorityList("ROLE_ADMIN")));
this.mvc.perform(request)
.andExpect(status().isOk());
}
@Test
public void requestWhenRolePrefixInLambdaThenUsesCustomRolePrefix() throws Exception {
this.spring.register(RolePrefixInLambdaConfig.class, AdminController.class).autowire();
this.mvc.perform(
get("/admin").with(user("user").authorities(AuthorityUtils.createAuthorityList("PERMISSION_ADMIN"))))
// @formatter:off
MockHttpServletRequestBuilder requestWithAdminPermission = get("/admin")
.with(user("user").authorities(AuthorityUtils.createAuthorityList("PERMISSION_ADMIN")));
this.mvc.perform(requestWithAdminPermission)
.andExpect(status().isOk());
this.mvc.perform(get("/admin").with(user("user").authorities(AuthorityUtils.createAuthorityList("ROLE_ADMIN"))))
MockHttpServletRequestBuilder requestWithAdminRole = get("/admin")
.with(user("user").authorities(AuthorityUtils.createAuthorityList("ROLE_ADMIN")));
this.mvc.perform(requestWithAdminRole)
.andExpect(status().isForbidden());
// @formatter:on
}
@Test

View File

@ -62,7 +62,11 @@ public class SessionManagementConfigurerSessionCreationPolicyTests {
@Test
public void getWhenDefaultsThenLoginChallengeCreatesSession() throws Exception {
this.spring.register(DefaultConfig.class, BasicController.class).autowire();
MvcResult result = this.mvc.perform(get("/")).andExpect(status().isUnauthorized()).andReturn();
// @formatter:off
MvcResult result = this.mvc.perform(get("/"))
.andExpect(status().isUnauthorized())
.andReturn();
// @formatter:on
assertThat(result.getRequest().getSession(false)).isNotNull();
}

View File

@ -49,6 +49,7 @@ import org.springframework.security.web.session.HttpSessionDestroyedEvent;
import org.springframework.security.web.session.SessionManagementFilter;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
@ -114,8 +115,14 @@ public class SessionManagementConfigurerTests {
this.spring.register(DisableSessionFixationEnableConcurrencyControlConfig.class).autowire();
MockHttpSession session = new MockHttpSession();
String sessionId = session.getId();
MvcResult mvcResult = this.mvc.perform(get("/").with(httpBasic("user", "password")).session(session))
.andExpect(status().isNotFound()).andReturn();
// @formatter:off
MockHttpServletRequestBuilder request = get("/")
.with(httpBasic("user", "password"))
.session(session);
MvcResult mvcResult = this.mvc.perform(request)
.andExpect(status().isNotFound())
.andReturn();
// @formatter:on
assertThat(mvcResult.getRequest().getSession().getId()).isEqualTo(sessionId);
}
@ -125,9 +132,16 @@ public class SessionManagementConfigurerTests {
MockHttpSession givenSession = new MockHttpSession();
String givenSessionId = givenSession.getId();
givenSession.setAttribute("name", "value");
MockHttpSession resultingSession = (MockHttpSession) this.mvc
.perform(get("/auth").session(givenSession).with(httpBasic("user", "password")))
.andExpect(status().isNotFound()).andReturn().getRequest().getSession(false);
// @formatter:off
MockHttpServletRequestBuilder request = get("/auth")
.session(givenSession)
.with(httpBasic("user", "password"));
MockHttpSession resultingSession = (MockHttpSession) this.mvc.perform(request)
.andExpect(status().isNotFound())
.andReturn()
.getRequest()
.getSession(false);
// @formatter:on
assertThat(givenSessionId).isNotEqualTo(resultingSession.getId());
assertThat(resultingSession.getAttribute("name")).isNull();
}
@ -135,29 +149,65 @@ public class SessionManagementConfigurerTests {
@Test
public void loginWhenUserLoggedInAndMaxSessionsIsOneThenLoginPrevented() throws Exception {
this.spring.register(ConcurrencyControlConfig.class).autowire();
this.mvc.perform(post("/login").with(csrf()).param("username", "user").param("password", "password"));
this.mvc.perform(post("/login").with(csrf()).param("username", "user").param("password", "password"))
.andExpect(status().isFound()).andExpect(redirectedUrl("/login?error"));
// @formatter:off
MockHttpServletRequestBuilder firstRequest = post("/login")
.with(csrf())
.param("username", "user")
.param("password", "password");
this.mvc.perform(firstRequest);
MockHttpServletRequestBuilder secondRequest = post("/login")
.with(csrf())
.param("username", "user")
.param("password", "password");
this.mvc.perform(secondRequest)
.andExpect(status().isFound())
.andExpect(redirectedUrl("/login?error"));
// @formatter:on
}
@Test
public void loginWhenUserSessionExpiredAndMaxSessionsIsOneThenLoggedIn() throws Exception {
this.spring.register(ConcurrencyControlConfig.class).autowire();
MvcResult mvcResult = this.mvc
.perform(post("/login").with(csrf()).param("username", "user").param("password", "password"))
// @formatter:off
MockHttpServletRequestBuilder firstRequest = post("/login")
.with(csrf())
.param("username", "user")
.param("password", "password");
MvcResult mvcResult = this.mvc.perform(firstRequest)
.andReturn();
// @formatter:on
HttpSession authenticatedSession = mvcResult.getRequest().getSession();
this.spring.getContext().publishEvent(new HttpSessionDestroyedEvent(authenticatedSession));
this.mvc.perform(post("/login").with(csrf()).param("username", "user").param("password", "password"))
.andExpect(status().isFound()).andExpect(redirectedUrl("/"));
// @formatter:off
MockHttpServletRequestBuilder secondRequest = post("/login")
.with(csrf())
.param("username", "user")
.param("password", "password");
this.mvc.perform(secondRequest)
.andExpect(status().isFound())
.andExpect(redirectedUrl("/"));
// @formatter:on
}
@Test
public void loginWhenUserLoggedInAndMaxSessionsOneInLambdaThenLoginPrevented() throws Exception {
this.spring.register(ConcurrencyControlInLambdaConfig.class).autowire();
this.mvc.perform(post("/login").with(csrf()).param("username", "user").param("password", "password"));
this.mvc.perform(post("/login").with(csrf()).param("username", "user").param("password", "password"))
.andExpect(status().isFound()).andExpect(redirectedUrl("/login?error"));
// @formatter:off
MockHttpServletRequestBuilder firstRequest = post("/login")
.with(csrf())
.param("username", "user")
.param("password", "password");
// @formatter:on
this.mvc.perform(firstRequest);
// @formatter:off
MockHttpServletRequestBuilder secondRequest = post("/login")
.with(csrf())
.param("username", "user")
.param("password", "password");
this.mvc.perform(secondRequest)
.andExpect(status().isFound())
.andExpect(redirectedUrl("/login?error"));
// @formatter:on
}
@Test

View File

@ -61,42 +61,60 @@ public class UrlAuthorizationsTests {
@WithMockUser(authorities = "ROLE_USER")
public void hasAnyAuthorityWhenAuthoritySpecifiedThenMatchesAuthority() throws Exception {
this.spring.register(RoleConfig.class).autowire();
this.mvc.perform(get("/role-user-authority")).andExpect(status().isNotFound());
this.mvc.perform(get("/role-user")).andExpect(status().isNotFound());
this.mvc.perform(get("/role-admin-authority")).andExpect(status().isForbidden());
// @formatter:off
this.mvc.perform(get("/role-user-authority"))
.andExpect(status().isNotFound());
this.mvc.perform(get("/role-user"))
.andExpect(status().isNotFound());
this.mvc.perform(get("/role-admin-authority"))
.andExpect(status().isForbidden());
// @formatter:on
}
@Test
@WithMockUser(authorities = "ROLE_ADMIN")
public void hasAnyAuthorityWhenAuthoritiesSpecifiedThenMatchesAuthority() throws Exception {
this.spring.register(RoleConfig.class).autowire();
this.mvc.perform(get("/role-user-admin-authority")).andExpect(status().isNotFound());
this.mvc.perform(get("/role-user-admin")).andExpect(status().isNotFound());
this.mvc.perform(get("/role-user-authority")).andExpect(status().isForbidden());
this.mvc.perform(get("/role-user-admin-authority"))
.andExpect(status().isNotFound());
this.mvc.perform(get("/role-user-admin"))
.andExpect(status().isNotFound());
this.mvc.perform(get("/role-user-authority"))
.andExpect(status().isForbidden());
}
@Test
@WithMockUser(roles = "USER")
public void hasAnyRoleWhenRoleSpecifiedThenMatchesRole() throws Exception {
this.spring.register(RoleConfig.class).autowire();
this.mvc.perform(get("/role-user")).andExpect(status().isNotFound());
this.mvc.perform(get("/role-admin")).andExpect(status().isForbidden());
// @formatter:off
this.mvc.perform(get("/role-user"))
.andExpect(status().isNotFound());
this.mvc.perform(get("/role-admin"))
.andExpect(status().isForbidden());
// @formatter:on
}
@Test
@WithMockUser(roles = "ADMIN")
public void hasAnyRoleWhenRolesSpecifiedThenMatchesRole() throws Exception {
this.spring.register(RoleConfig.class).autowire();
this.mvc.perform(get("/role-admin-user")).andExpect(status().isNotFound());
this.mvc.perform(get("/role-user")).andExpect(status().isForbidden());
this.mvc.perform(get("/role-admin-user"))
.andExpect(status().isNotFound());
this.mvc.perform(get("/role-user"))
.andExpect(status().isForbidden());
}
@Test
@WithMockUser(authorities = "USER")
public void hasAnyRoleWhenRoleSpecifiedThenDoesNotMatchAuthority() throws Exception {
this.spring.register(RoleConfig.class).autowire();
this.mvc.perform(get("/role-user")).andExpect(status().isForbidden());
this.mvc.perform(get("/role-admin")).andExpect(status().isForbidden());
// @formatter:off
this.mvc.perform(get("/role-user"))
.andExpect(status().isForbidden());
this.mvc.perform(get("/role-admin"))
.andExpect(status().isForbidden());
// @formatter:on
}
@Test
@ -145,7 +163,11 @@ public class UrlAuthorizationsTests {
ApplicationContext context = getApplicationContext();
UrlAuthorizationConfigurer<HttpSecurity>.StandardInterceptUrlRegistry registry = http
.apply(new UrlAuthorizationConfigurer(context)).getRegistry();
registry.antMatchers("/a").hasRole("ADMIN").anyRequest().hasRole("USER");
// @formatter:off
registry
.antMatchers("/a").hasRole("ADMIN")
.anyRequest().hasRole("USER");
// @formatter:on
}
}

View File

@ -68,21 +68,30 @@ public class X509ConfigurerTests {
public void x509WhenInvokedTwiceThenUsesOriginalSubjectPrincipalRegex() throws Exception {
this.spring.register(DuplicateDoesNotOverrideConfig.class).autowire();
X509Certificate certificate = loadCert("rodatexampledotcom.cer");
this.mvc.perform(get("/").with(x509(certificate))).andExpect(authenticated().withUsername("rod"));
// @formatter:off
this.mvc.perform(get("/").with(x509(certificate)))
.andExpect(authenticated().withUsername("rod"));
// @formatter:on
}
@Test
public void x509WhenConfiguredInLambdaThenUsesDefaults() throws Exception {
this.spring.register(DefaultsInLambdaConfig.class).autowire();
X509Certificate certificate = loadCert("rod.cer");
this.mvc.perform(get("/").with(x509(certificate))).andExpect(authenticated().withUsername("rod"));
// @formatter:off
this.mvc.perform(get("/").with(x509(certificate)))
.andExpect(authenticated().withUsername("rod"));
// @formatter:on
}
@Test
public void x509WhenSubjectPrincipalRegexInLambdaThenUsesRegexToExtractPrincipal() throws Exception {
this.spring.register(SubjectPrincipalRegexInLambdaConfig.class).autowire();
X509Certificate certificate = loadCert("rodatexampledotcom.cer");
this.mvc.perform(get("/").with(x509(certificate))).andExpect(authenticated().withUsername("rod"));
// @formatter:off
this.mvc.perform(get("/").with(x509(certificate)))
.andExpect(authenticated().withUsername("rod"));
// @formatter:on
}
private <T extends Certificate> T loadCert(String location) {

View File

@ -61,6 +61,7 @@ import org.springframework.security.oauth2.core.endpoint.OAuth2ParameterNames;
import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
@ -107,13 +108,22 @@ public class OAuth2ClientConfigurerTests {
@Before
public void setup() {
this.registration1 = TestClientRegistrations.clientRegistration().registrationId("registration-1")
.clientId("client-1").clientSecret("secret")
// @formatter:off
this.registration1 = TestClientRegistrations.clientRegistration()
.registrationId("registration-1")
.clientId("client-1")
.clientSecret("secret")
.clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE).redirectUri("{baseUrl}/client-1")
.scope("user").authorizationUri("https://provider.com/oauth2/authorize")
.tokenUri("https://provider.com/oauth2/token").userInfoUri("https://provider.com/oauth2/user")
.userNameAttributeName("id").clientName("client-1").build();
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.redirectUri("{baseUrl}/client-1")
.scope("user")
.authorizationUri("https://provider.com/oauth2/authorize")
.tokenUri("https://provider.com/oauth2/token")
.userInfoUri("https://provider.com/oauth2/user")
.userNameAttributeName("id")
.clientName("client-1")
.build();
// @formatter:on
clientRegistrationRepository = new InMemoryClientRegistrationRepository(this.registration1);
authorizedClientService = new InMemoryOAuth2AuthorizedClientService(clientRegistrationRepository);
authorizedClientRepository = new AuthenticatedPrincipalOAuth2AuthorizedClientRepository(
@ -131,11 +141,13 @@ public class OAuth2ClientConfigurerTests {
@Test
public void configureWhenAuthorizationCodeRequestThenRedirectForAuthorization() throws Exception {
this.spring.register(OAuth2ClientConfig.class).autowire();
// @formatter:off
MvcResult mvcResult = this.mockMvc.perform(get("/oauth2/authorization/registration-1"))
.andExpect(status().is3xxRedirection()).andReturn();
assertThat(mvcResult.getResponse().getRedirectedUrl())
.matches("https://provider.com/oauth2/authorize\\?" + "response_type=code&client_id=client-1&"
+ "scope=user&state=.{15,}&" + "redirect_uri=http://localhost/client-1");
// @formatter:on
}
@Test
@ -154,10 +166,15 @@ public class OAuth2ClientConfigurerTests {
// Setup the Authorization Request in the session
Map<String, Object> attributes = new HashMap<>();
attributes.put(OAuth2ParameterNames.REGISTRATION_ID, this.registration1.getRegistrationId());
// @formatter:off
OAuth2AuthorizationRequest authorizationRequest = OAuth2AuthorizationRequest.authorizationCode()
.authorizationUri(this.registration1.getProviderDetails().getAuthorizationUri())
.clientId(this.registration1.getClientId()).redirectUri("http://localhost/client-1").state("state")
.attributes(attributes).build();
.clientId(this.registration1.getClientId())
.redirectUri("http://localhost/client-1")
.state("state")
.attributes(attributes)
.build();
// @formatter:on
AuthorizationRequestRepository<OAuth2AuthorizationRequest> authorizationRequestRepository = new HttpSessionOAuth2AuthorizationRequestRepository();
MockHttpServletRequest request = new MockHttpServletRequest("GET", "");
MockHttpServletResponse response = new MockHttpServletResponse();
@ -165,9 +182,16 @@ public class OAuth2ClientConfigurerTests {
MockHttpSession session = (MockHttpSession) request.getSession();
String principalName = "user1";
TestingAuthenticationToken authentication = new TestingAuthenticationToken(principalName, "password");
this.mockMvc.perform(get("/client-1").param(OAuth2ParameterNames.CODE, "code")
.param(OAuth2ParameterNames.STATE, "state").with(authentication(authentication)).session(session))
.andExpect(status().is3xxRedirection()).andExpect(redirectedUrl("http://localhost/client-1"));
// @formatter:off
MockHttpServletRequestBuilder clientRequest = get("/client-1")
.param(OAuth2ParameterNames.CODE, "code")
.param(OAuth2ParameterNames.STATE, "state")
.with(authentication(authentication))
.session(session);
this.mockMvc.perform(clientRequest)
.andExpect(status().is3xxRedirection())
.andExpect(redirectedUrl("http://localhost/client-1"));
// @formatter:on
OAuth2AuthorizedClient authorizedClient = authorizedClientRepository
.loadAuthorizedClient(this.registration1.getRegistrationId(), authentication, request);
assertThat(authorizedClient).isNotNull();
@ -191,10 +215,14 @@ public class OAuth2ClientConfigurerTests {
// Setup the Authorization Request in the session
Map<String, Object> attributes = new HashMap<>();
attributes.put(OAuth2ParameterNames.REGISTRATION_ID, this.registration1.getRegistrationId());
// @formatter:off
OAuth2AuthorizationRequest authorizationRequest = OAuth2AuthorizationRequest.authorizationCode()
.authorizationUri(this.registration1.getProviderDetails().getAuthorizationUri())
.clientId(this.registration1.getClientId()).redirectUri("http://localhost/client-1").state("state")
.attributes(attributes).build();
.clientId(this.registration1.getClientId()).redirectUri("http://localhost/client-1")
.state("state")
.attributes(attributes)
.build();
// @formatter:on
AuthorizationRequestRepository<OAuth2AuthorizationRequest> authorizationRequestRepository = new HttpSessionOAuth2AuthorizationRequestRepository();
MockHttpServletRequest request = new MockHttpServletRequest("GET", "");
MockHttpServletResponse response = new MockHttpServletResponse();
@ -202,9 +230,16 @@ public class OAuth2ClientConfigurerTests {
MockHttpSession session = (MockHttpSession) request.getSession();
String principalName = "user1";
TestingAuthenticationToken authentication = new TestingAuthenticationToken(principalName, "password");
this.mockMvc.perform(get("/client-1").param(OAuth2ParameterNames.CODE, "code")
.param(OAuth2ParameterNames.STATE, "state").with(authentication(authentication)).session(session))
.andExpect(status().is3xxRedirection()).andExpect(redirectedUrl("http://localhost/client-1"));
// @formatter:off
MockHttpServletRequestBuilder clientRequest = get("/client-1")
.param(OAuth2ParameterNames.CODE, "code")
.param(OAuth2ParameterNames.STATE, "state")
.with(authentication(authentication))
.session(session);
this.mockMvc.perform(clientRequest)
.andExpect(status().is3xxRedirection())
.andExpect(redirectedUrl("http://localhost/client-1"));
// @formatter:on
verify(requestCache).getRequest(any(HttpServletRequest.class), any(HttpServletResponse.class));
}
@ -218,8 +253,11 @@ public class OAuth2ClientConfigurerTests {
given(authorizationRequestResolver.resolve(any()))
.willAnswer((invocation) -> defaultAuthorizationRequestResolver.resolve(invocation.getArgument(0)));
this.spring.register(OAuth2ClientConfig.class).autowire();
this.mockMvc.perform(get("/oauth2/authorization/registration-1")).andExpect(status().is3xxRedirection())
// @formatter:off
this.mockMvc.perform(get("/oauth2/authorization/registration-1"))
.andExpect(status().is3xxRedirection())
.andReturn();
// @formatter:on
verify(authorizationRequestResolver).resolve(any());
}

View File

@ -110,11 +110,21 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
*/
public class OAuth2LoginConfigurerTests {
// @formatter:off
private static final ClientRegistration GOOGLE_CLIENT_REGISTRATION = CommonOAuth2Provider.GOOGLE
.getBuilder("google").clientId("clientId").clientSecret("clientSecret").build();
.getBuilder("google")
.clientId("clientId")
.clientSecret("clientSecret")
.build();
// @formatter:on
// @formatter:off
private static final ClientRegistration GITHUB_CLIENT_REGISTRATION = CommonOAuth2Provider.GITHUB
.getBuilder("github").clientId("clientId").clientSecret("clientSecret").build();
.getBuilder("github")
.clientId("clientId")
.clientSecret("clientSecret")
.build();
// @formatter:on
private ConfigurableApplicationContext context;
@ -296,11 +306,15 @@ public class OAuth2LoginConfigurerTests {
loadConfig(OAuth2LoginConfigCustomAuthorizationRequestResolver.class);
OAuth2AuthorizationRequestResolver resolver = this.context
.getBean(OAuth2LoginConfigCustomAuthorizationRequestResolver.class).resolver;
// @formatter:off
OAuth2AuthorizationRequest result = OAuth2AuthorizationRequest.authorizationCode()
.authorizationUri("https://accounts.google.com/authorize").clientId("client-id").state("adsfa")
.authorizationUri("https://accounts.google.com/authorize")
.clientId("client-id")
.state("adsfa")
.authorizationRequestUri(
"https://accounts.google.com/o/oauth2/v2/auth?response_type=code&client_id=clientId&scope=openid+profile+email&state=state&redirect_uri=http%3A%2F%2Flocalhost%2Flogin%2Foauth2%2Fcode%2Fgoogle&custom-param1=custom-value1")
.build();
// @formatter:on
given(resolver.resolve(any())).willReturn(result);
String requestUri = "/oauth2/authorization/google";
this.request = new MockHttpServletRequest("GET", requestUri);
@ -316,11 +330,15 @@ public class OAuth2LoginConfigurerTests {
loadConfig(OAuth2LoginConfigCustomAuthorizationRequestResolverInLambda.class);
OAuth2AuthorizationRequestResolver resolver = this.context
.getBean(OAuth2LoginConfigCustomAuthorizationRequestResolverInLambda.class).resolver;
// @formatter:off
OAuth2AuthorizationRequest result = OAuth2AuthorizationRequest.authorizationCode()
.authorizationUri("https://accounts.google.com/authorize").clientId("client-id").state("adsfa")
.authorizationUri("https://accounts.google.com/authorize")
.clientId("client-id")
.state("adsfa")
.authorizationRequestUri(
"https://accounts.google.com/o/oauth2/v2/auth?response_type=code&client_id=clientId&scope=openid+profile+email&state=state&redirect_uri=http%3A%2F%2Flocalhost%2Flogin%2Foauth2%2Fcode%2Fgoogle&custom-param1=custom-value1")
.build();
// @formatter:on
given(resolver.resolve(any())).willReturn(result);
String requestUri = "/oauth2/authorization/google";
this.request = new MockHttpServletRequest("GET", requestUri);
@ -511,12 +529,17 @@ public class OAuth2LoginConfigurerTests {
private OAuth2AuthorizationRequest createOAuth2AuthorizationRequest(ClientRegistration registration,
String... scopes) {
// @formatter:off
return OAuth2AuthorizationRequest.authorizationCode()
.authorizationUri(registration.getProviderDetails().getAuthorizationUri())
.clientId(registration.getClientId()).state("state123").redirectUri("http://localhost")
.clientId(registration.getClientId())
.state("state123")
.redirectUri("http://localhost")
.attributes(Collections.singletonMap(OAuth2ParameterNames.REGISTRATION_ID,
registration.getRegistrationId()))
.scope(scopes).build();
.scope(scopes)
.build();
// @formatter:on
}
private static OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> createOauth2AccessTokenResponseClient() {

View File

@ -121,6 +121,7 @@ import org.springframework.security.web.access.AccessDeniedHandlerImpl;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.ResultMatcher;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.test.web.servlet.request.RequestPostProcessor;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
@ -199,8 +200,11 @@ public class OAuth2ResourceServerConfigurerTests {
this.spring.register(RestOperationsConfig.class, DefaultConfig.class, BasicController.class).autowire();
mockRestOperations(jwks("Default"));
String token = this.token("ValidNoScopes");
this.mvc.perform(get("/").with(bearerToken(token))).andExpect(status().isOk())
// @formatter:off
this.mvc.perform(get("/").with(bearerToken(token)))
.andExpect(status().isOk())
.andExpect(content().string("ok"));
// @formatter:on
}
@Test
@ -208,8 +212,11 @@ public class OAuth2ResourceServerConfigurerTests {
this.spring.register(RestOperationsConfig.class, DefaultInLambdaConfig.class, BasicController.class).autowire();
mockRestOperations(jwks("Default"));
String token = this.token("ValidNoScopes");
this.mvc.perform(get("/").with(bearerToken(token))).andExpect(status().isOk())
// @formatter:off
this.mvc.perform(get("/").with(bearerToken(token)))
.andExpect(status().isOk())
.andExpect(content().string("ok"));
// @formatter:on
}
@Test
@ -217,8 +224,11 @@ public class OAuth2ResourceServerConfigurerTests {
this.spring.register(WebServerConfig.class, JwkSetUriConfig.class, BasicController.class).autowire();
mockWebServer(jwks("Default"));
String token = this.token("ValidNoScopes");
this.mvc.perform(get("/").with(bearerToken(token))).andExpect(status().isOk())
// @formatter:off
this.mvc.perform(get("/").with(bearerToken(token)))
.andExpect(status().isOk())
.andExpect(content().string("ok"));
// @formatter:on
}
@Test
@ -226,8 +236,11 @@ public class OAuth2ResourceServerConfigurerTests {
this.spring.register(WebServerConfig.class, JwkSetUriInLambdaConfig.class, BasicController.class).autowire();
mockWebServer(jwks("Default"));
String token = this.token("ValidNoScopes");
this.mvc.perform(get("/").with(bearerToken(token))).andExpect(status().isOk())
// @formatter:off
this.mvc.perform(get("/").with(bearerToken(token)))
.andExpect(status().isOk())
.andExpect(content().string("ok"));
// @formatter:on
}
@Test
@ -235,8 +248,11 @@ public class OAuth2ResourceServerConfigurerTests {
this.spring.register(RestOperationsConfig.class, DefaultConfig.class, BasicController.class).autowire();
mockRestOperations(jwks("Default"));
String token = this.token("Expired");
this.mvc.perform(get("/").with(bearerToken(token))).andExpect(status().isUnauthorized())
// @formatter:off
this.mvc.perform(get("/").with(bearerToken(token)))
.andExpect(status().isUnauthorized())
.andExpect(invalidTokenHeader("An error occurred while attempting to decode the Jwt"));
// @formatter:on
}
@Test
@ -244,8 +260,11 @@ public class OAuth2ResourceServerConfigurerTests {
this.spring.register(RestOperationsConfig.class, DefaultConfig.class).autowire();
mockRestOperations("malformed");
String token = this.token("ValidNoScopes");
this.mvc.perform(get("/").with(bearerToken(token))).andExpect(status().isUnauthorized())
// @formatter:off
this.mvc.perform(get("/").with(bearerToken(token)))
.andExpect(status().isUnauthorized())
.andExpect(header().string("WWW-Authenticate", "Bearer"));
// @formatter:on
}
@Test
@ -253,15 +272,21 @@ public class OAuth2ResourceServerConfigurerTests {
this.spring.register(WebServerConfig.class, JwkSetUriConfig.class).autowire();
this.web.shutdown();
String token = this.token("ValidNoScopes");
this.mvc.perform(get("/").with(bearerToken(token))).andExpect(status().isUnauthorized())
// @formatter:off
this.mvc.perform(get("/").with(bearerToken(token)))
.andExpect(status().isUnauthorized())
.andExpect(header().string("WWW-Authenticate", "Bearer"));
// @formatter:on
}
@Test
public void getWhenUsingDefaultsWithMalformedBearerTokenThenInvalidToken() throws Exception {
this.spring.register(JwkSetUriConfig.class).autowire();
this.mvc.perform(get("/").with(bearerToken("an\"invalid\"token"))).andExpect(status().isUnauthorized())
// @formatter:off
this.mvc.perform(get("/").with(bearerToken("an\"invalid\"token")))
.andExpect(status().isUnauthorized())
.andExpect(invalidTokenHeader("Bearer token is malformed"));
// @formatter:on
}
@Test
@ -269,16 +294,22 @@ public class OAuth2ResourceServerConfigurerTests {
this.spring.register(RestOperationsConfig.class, DefaultConfig.class).autowire();
mockRestOperations(jwks("Default"));
String token = this.token("MalformedPayload");
this.mvc.perform(get("/").with(bearerToken(token))).andExpect(status().isUnauthorized()).andExpect(
invalidTokenHeader("An error occurred while attempting to decode the Jwt: Malformed payload"));
// @formatter:off
this.mvc.perform(get("/").with(bearerToken(token)))
.andExpect(status().isUnauthorized())
.andExpect(invalidTokenHeader("An error occurred while attempting to decode the Jwt: Malformed payload"));
// @formatter:on
}
@Test
public void getWhenUsingDefaultsWithUnsignedBearerTokenThenInvalidToken() throws Exception {
this.spring.register(JwkSetUriConfig.class).autowire();
String token = this.token("Unsigned");
this.mvc.perform(get("/").with(bearerToken(token))).andExpect(status().isUnauthorized())
// @formatter:off
this.mvc.perform(get("/").with(bearerToken(token)))
.andExpect(status().isUnauthorized())
.andExpect(invalidTokenHeader("Unsupported algorithm of none"));
// @formatter:on
}
@Test
@ -286,16 +317,21 @@ public class OAuth2ResourceServerConfigurerTests {
this.spring.register(RestOperationsConfig.class, DefaultConfig.class).autowire();
this.mockRestOperations(jwks("Default"));
String token = this.token("TooEarly");
this.mvc.perform(get("/").with(bearerToken(token))).andExpect(status().isUnauthorized())
// @formatter:off
this.mvc.perform(get("/").with(bearerToken(token)))
.andExpect(status().isUnauthorized())
.andExpect(invalidTokenHeader("An error occurred while attempting to decode the Jwt"));
// @formatter:on
}
@Test
public void getWhenUsingDefaultsWithBearerTokenInTwoPlacesThenInvalidRequest() throws Exception {
this.spring.register(JwkSetUriConfig.class).autowire();
// @formatter:off
this.mvc.perform(get("/").with(bearerToken("token")).with(bearerToken("token").asParam()))
.andExpect(status().isBadRequest())
.andExpect(invalidRequestHeader("Found multiple bearer tokens in the request"));
// @formatter:on
}
@Test
@ -304,23 +340,32 @@ public class OAuth2ResourceServerConfigurerTests {
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("access_token", "token1");
params.add("access_token", "token2");
this.mvc.perform(get("/").params(params)).andExpect(status().isBadRequest())
// @formatter:off
this.mvc.perform(get("/").params(params))
.andExpect(status().isBadRequest())
.andExpect(invalidRequestHeader("Found multiple bearer tokens in the request"));
// @formatter:on
}
@Test
public void postWhenUsingDefaultsWithBearerTokenAsFormParameterThenIgnoresToken() throws Exception {
this.spring.register(JwkSetUriConfig.class).autowire();
this.mvc.perform(post("/") // engage csrf
.with(bearerToken("token").asParam())).andExpect(status().isForbidden())
// engage csrf
// @formatter:off
this.mvc.perform(post("/").with(bearerToken("token").asParam()))
.andExpect(status().isForbidden())
.andExpect(header().doesNotExist(HttpHeaders.WWW_AUTHENTICATE));
// @formatter:on
}
@Test
public void postWhenCsrfDisabledWithBearerTokenAsFormParameterThenIgnoresToken() throws Exception {
this.spring.register(CsrfDisabledConfig.class).autowire();
this.mvc.perform(post("/").with(bearerToken("token").asParam())).andExpect(status().isUnauthorized())
// @formatter:off
this.mvc.perform(post("/").with(bearerToken("token").asParam()))
.andExpect(status().isUnauthorized())
.andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, "Bearer"));
// @formatter:on
}
// gh-8031
@ -329,14 +374,20 @@ public class OAuth2ResourceServerConfigurerTests {
this.spring.register(RestOperationsConfig.class, AnonymousDisabledConfig.class).autowire();
mockRestOperations(jwks("Default"));
String token = token("ValidNoScopes");
this.mvc.perform(get("/authenticated").with(bearerToken(token))).andExpect(status().isNotFound());
// @formatter:off
this.mvc.perform(get("/authenticated").with(bearerToken(token)))
.andExpect(status().isNotFound());
// @formatter:on
}
@Test
public void getWhenUsingDefaultsWithNoBearerTokenThenUnauthorized() throws Exception {
this.spring.register(JwkSetUriConfig.class).autowire();
this.mvc.perform(get("/")).andExpect(status().isUnauthorized())
// @formatter:off
this.mvc.perform(get("/"))
.andExpect(status().isUnauthorized())
.andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, "Bearer"));
// @formatter:on
}
@Test
@ -344,8 +395,11 @@ public class OAuth2ResourceServerConfigurerTests {
this.spring.register(RestOperationsConfig.class, DefaultConfig.class, BasicController.class).autowire();
mockRestOperations(jwks("Default"));
String token = this.token("ValidMessageReadScope");
this.mvc.perform(get("/requires-read-scope").with(bearerToken(token))).andExpect(status().isOk())
// @formatter:off
this.mvc.perform(get("/requires-read-scope").with(bearerToken(token)))
.andExpect(status().isOk())
.andExpect(content().string("[SCOPE_message:read]"));
// @formatter:on
}
@Test
@ -353,8 +407,11 @@ public class OAuth2ResourceServerConfigurerTests {
this.spring.register(RestOperationsConfig.class, DefaultConfig.class, BasicController.class).autowire();
mockRestOperations(jwks("Default"));
String token = this.token("ValidNoScopes");
this.mvc.perform(get("/requires-read-scope").with(bearerToken(token))).andExpect(status().isForbidden())
// @formatter:off
this.mvc.perform(get("/requires-read-scope").with(bearerToken(token)))
.andExpect(status().isForbidden())
.andExpect(insufficientScopeHeader());
// @formatter:on
}
@Test
@ -362,8 +419,11 @@ public class OAuth2ResourceServerConfigurerTests {
this.spring.register(RestOperationsConfig.class, DefaultConfig.class, BasicController.class).autowire();
mockRestOperations(jwks("Default"));
String token = this.token("ValidMessageWriteScp");
this.mvc.perform(get("/requires-read-scope").with(bearerToken(token))).andExpect(status().isForbidden())
// @formatter:off
this.mvc.perform(get("/requires-read-scope").with(bearerToken(token)))
.andExpect(status().isForbidden())
.andExpect(insufficientScopeHeader());
// @formatter:on
}
@Test
@ -371,8 +431,11 @@ public class OAuth2ResourceServerConfigurerTests {
this.spring.register(RestOperationsConfig.class, DefaultConfig.class).autowire();
mockRestOperations(jwks("Empty"));
String token = this.token("ValidNoScopes");
this.mvc.perform(get("/").with(bearerToken(token))).andExpect(status().isUnauthorized())
// @formatter:off
this.mvc.perform(get("/").with(bearerToken(token)))
.andExpect(status().isUnauthorized())
.andExpect(invalidTokenHeader("An error occurred while attempting to decode the Jwt"));
// @formatter:on
}
@Test
@ -380,8 +443,11 @@ public class OAuth2ResourceServerConfigurerTests {
this.spring.register(RestOperationsConfig.class, DefaultConfig.class, BasicController.class).autowire();
mockRestOperations(jwks("TwoKeys"));
String token = this.token("ValidNoScopes");
this.mvc.perform(get("/authenticated").with(bearerToken(token))).andExpect(status().isOk())
// @formatter:off
this.mvc.perform(get("/authenticated").with(bearerToken(token)))
.andExpect(status().isOk())
.andExpect(content().string("test-subject"));
// @formatter:on
}
@Test
@ -389,8 +455,11 @@ public class OAuth2ResourceServerConfigurerTests {
this.spring.register(RestOperationsConfig.class, DefaultConfig.class, BasicController.class).autowire();
mockRestOperations(jwks("TwoKeys"));
String token = this.token("Kid");
this.mvc.perform(get("/authenticated").with(bearerToken(token))).andExpect(status().isOk())
// @formatter:off
this.mvc.perform(get("/authenticated").with(bearerToken(token)))
.andExpect(status().isOk())
.andExpect(content().string("test-subject"));
// @formatter:on
}
@Test
@ -398,8 +467,11 @@ public class OAuth2ResourceServerConfigurerTests {
this.spring.register(RestOperationsConfig.class, MethodSecurityConfig.class, BasicController.class).autowire();
mockRestOperations(jwks("Default"));
String token = this.token("ValidMessageReadScope");
this.mvc.perform(get("/ms-requires-read-scope").with(bearerToken(token))).andExpect(status().isOk())
// @formatter:off
this.mvc.perform(get("/ms-requires-read-scope").with(bearerToken(token)))
.andExpect(status().isOk())
.andExpect(content().string("[SCOPE_message:read]"));
// @formatter:on
}
@Test
@ -407,8 +479,11 @@ public class OAuth2ResourceServerConfigurerTests {
this.spring.register(RestOperationsConfig.class, MethodSecurityConfig.class, BasicController.class).autowire();
mockRestOperations(jwks("Default"));
String token = this.token("ValidMessageReadScp");
this.mvc.perform(get("/ms-requires-read-scope").with(bearerToken(token))).andExpect(status().isOk())
// @formatter:off
this.mvc.perform(get("/ms-requires-read-scope").with(bearerToken(token)))
.andExpect(status().isOk())
.andExpect(content().string("[SCOPE_message:read]"));
// @formatter:on
}
@Test
@ -416,8 +491,11 @@ public class OAuth2ResourceServerConfigurerTests {
this.spring.register(RestOperationsConfig.class, MethodSecurityConfig.class, BasicController.class).autowire();
mockRestOperations(jwks("Default"));
String token = this.token("ValidNoScopes");
this.mvc.perform(get("/ms-requires-read-scope").with(bearerToken(token))).andExpect(status().isForbidden())
// @formatter:off
this.mvc.perform(get("/ms-requires-read-scope").with(bearerToken(token)))
.andExpect(status().isForbidden())
.andExpect(insufficientScopeHeader());
// @formatter:on
}
@Test
@ -425,8 +503,11 @@ public class OAuth2ResourceServerConfigurerTests {
this.spring.register(RestOperationsConfig.class, MethodSecurityConfig.class, BasicController.class).autowire();
mockRestOperations(jwks("Default"));
String token = this.token("ValidMessageWriteScp");
this.mvc.perform(get("/ms-requires-read-scope").with(bearerToken(token))).andExpect(status().isForbidden())
// @formatter:off
this.mvc.perform(get("/ms-requires-read-scope").with(bearerToken(token)))
.andExpect(status().isForbidden())
.andExpect(insufficientScopeHeader());
// @formatter:on
}
@Test
@ -434,8 +515,11 @@ public class OAuth2ResourceServerConfigurerTests {
this.spring.register(RestOperationsConfig.class, MethodSecurityConfig.class, BasicController.class).autowire();
mockRestOperations(jwks("Default"));
String token = this.token("ValidMessageReadScope");
this.mvc.perform(get("/ms-deny").with(bearerToken(token))).andExpect(status().isForbidden())
// @formatter:off
this.mvc.perform(get("/ms-deny").with(bearerToken(token)))
.andExpect(status().isForbidden())
.andExpect(insufficientScopeHeader());
// @formatter:on
}
@Test
@ -443,15 +527,21 @@ public class OAuth2ResourceServerConfigurerTests {
this.spring.register(RestOperationsConfig.class, DefaultConfig.class, BasicController.class).autowire();
mockRestOperations(jwks("Default"));
String token = this.token("ValidNoScopes");
this.mvc.perform(post("/authenticated").with(bearerToken(token))).andExpect(status().isOk())
// @formatter:off
this.mvc.perform(post("/authenticated").with(bearerToken(token)))
.andExpect(status().isOk())
.andExpect(content().string("test-subject"));
// @formatter:on
}
@Test
public void postWhenUsingDefaultsWithNoBearerTokenThenCsrfDenies() throws Exception {
this.spring.register(JwkSetUriConfig.class).autowire();
this.mvc.perform(post("/authenticated")).andExpect(status().isForbidden())
// @formatter:off
this.mvc.perform(post("/authenticated"))
.andExpect(status().isForbidden())
.andExpect(header().doesNotExist(HttpHeaders.WWW_AUTHENTICATE));
// @formatter:on
}
@Test
@ -459,8 +549,11 @@ public class OAuth2ResourceServerConfigurerTests {
this.spring.register(RestOperationsConfig.class, DefaultConfig.class).autowire();
mockRestOperations(jwks("Default"));
String token = this.token("Expired");
this.mvc.perform(post("/authenticated").with(bearerToken(token))).andExpect(status().isUnauthorized())
// @formatter:off
this.mvc.perform(post("/authenticated").with(bearerToken(token)))
.andExpect(status().isUnauthorized())
.andExpect(invalidTokenHeader("An error occurred while attempting to decode the Jwt"));
// @formatter:on
}
@Test
@ -468,7 +561,11 @@ public class OAuth2ResourceServerConfigurerTests {
this.spring.register(RestOperationsConfig.class, DefaultConfig.class, BasicController.class).autowire();
mockRestOperations(jwks("Default"));
String token = this.token("ValidNoScopes");
MvcResult result = this.mvc.perform(get("/").with(bearerToken(token))).andExpect(status().isOk()).andReturn();
// @formatter:off
MvcResult result = this.mvc.perform(get("/").with(bearerToken(token)))
.andExpect(status().isOk())
.andReturn();
// @formatter:on
assertThat(result.getRequest().getSession(false)).isNull();
}
@ -476,15 +573,23 @@ public class OAuth2ResourceServerConfigurerTests {
public void requestWhenIntrospectionConfiguredThenSessionIsNotCreated() throws Exception {
this.spring.register(RestOperationsConfig.class, OpaqueTokenConfig.class, BasicController.class).autowire();
mockRestOperations(json("Active"));
MvcResult result = this.mvc.perform(get("/authenticated").with(bearerToken("token"))).andExpect(status().isOk())
.andExpect(content().string("test-subject")).andReturn();
// @formatter:off
MvcResult result = this.mvc.perform(get("/authenticated").with(bearerToken("token")))
.andExpect(status().isOk())
.andExpect(content().string("test-subject"))
.andReturn();
// @formatter:on
assertThat(result.getRequest().getSession(false)).isNull();
}
@Test
public void requestWhenUsingDefaultsAndNoBearerTokenThenSessionIsCreated() throws Exception {
this.spring.register(JwkSetUriConfig.class, BasicController.class).autowire();
MvcResult result = this.mvc.perform(get("/")).andExpect(status().isUnauthorized()).andReturn();
// @formatter:off
MvcResult result = this.mvc.perform(get("/"))
.andExpect(status().isUnauthorized())
.andReturn();
// @formatter:on
assertThat(result.getRequest().getSession(false)).isNotNull();
}
@ -494,7 +599,11 @@ public class OAuth2ResourceServerConfigurerTests {
.autowire();
mockRestOperations(jwks("Default"));
String token = this.token("ValidNoScopes");
MvcResult result = this.mvc.perform(get("/").with(bearerToken(token))).andExpect(status().isOk()).andReturn();
// @formatter:off
MvcResult result = this.mvc.perform(get("/").with(bearerToken(token)))
.andExpect(status().isOk())
.andReturn();
// @formatter:on
assertThat(result.getRequest().getSession(false)).isNotNull();
}
@ -505,10 +614,14 @@ public class OAuth2ResourceServerConfigurerTests {
.autowire();
JwtDecoder decoder = this.spring.getContext().getBean(JwtDecoder.class);
given(decoder.decode(anyString())).willReturn(JWT);
this.mvc.perform(get("/authenticated").with(bearerToken(JWT_TOKEN))).andExpect(status().isOk())
// @formatter:off
this.mvc.perform(get("/authenticated").with(bearerToken(JWT_TOKEN)))
.andExpect(status().isOk())
.andExpect(content().string(JWT_SUBJECT));
this.mvc.perform(post("/authenticated").param("access_token", JWT_TOKEN)).andExpect(status().isOk())
this.mvc.perform(post("/authenticated").param("access_token", JWT_TOKEN))
.andExpect(status().isOk())
.andExpect(content().string(JWT_SUBJECT));
// @formatter:on
}
@Test
@ -519,10 +632,14 @@ public class OAuth2ResourceServerConfigurerTests {
.autowire();
JwtDecoder decoder = this.spring.getContext().getBean(JwtDecoder.class);
given(decoder.decode(anyString())).willReturn(JWT);
this.mvc.perform(get("/authenticated").with(bearerToken(JWT_TOKEN))).andExpect(status().isOk())
// @formatter:off
this.mvc.perform(get("/authenticated").with(bearerToken(JWT_TOKEN)))
.andExpect(status().isOk())
.andExpect(content().string(JWT_SUBJECT));
this.mvc.perform(get("/authenticated").param("access_token", JWT_TOKEN)).andExpect(status().isOk())
this.mvc.perform(get("/authenticated").param("access_token", JWT_TOKEN))
.andExpect(status().isOk())
.andExpect(content().string(JWT_SUBJECT));
// @formatter:on
}
@Test
@ -532,10 +649,15 @@ public class OAuth2ResourceServerConfigurerTests {
.autowire();
JwtDecoder decoder = this.spring.getContext().getBean(JwtDecoder.class);
given(decoder.decode(anyString())).willReturn(JWT);
this.mvc.perform(
post("/authenticated").param("access_token", JWT_TOKEN).with(bearerToken(JWT_TOKEN)).with(csrf()))
// @formatter:off
MockHttpServletRequestBuilder request = post("/authenticated")
.param("access_token", JWT_TOKEN)
.with(bearerToken(JWT_TOKEN))
.with(csrf());
this.mvc.perform(request)
.andExpect(status().isBadRequest())
.andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, containsString("invalid_request")));
// @formatter:on
}
@Test
@ -546,9 +668,14 @@ public class OAuth2ResourceServerConfigurerTests {
.autowire();
JwtDecoder decoder = this.spring.getContext().getBean(JwtDecoder.class);
given(decoder.decode(anyString())).willReturn(JWT);
this.mvc.perform(get("/authenticated").with(bearerToken(JWT_TOKEN)).param("access_token", JWT_TOKEN))
// @formatter:off
MockHttpServletRequestBuilder request = get("/authenticated")
.with(bearerToken(JWT_TOKEN))
.param("access_token", JWT_TOKEN);
this.mvc.perform(request)
.andExpect(status().isBadRequest())
.andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, containsString("invalid_request")));
// @formatter:on
}
@Test
@ -597,8 +724,11 @@ public class OAuth2ResourceServerConfigurerTests {
CustomJwtDecoderOnDsl config = this.spring.getContext().getBean(CustomJwtDecoderOnDsl.class);
JwtDecoder decoder = config.decoder();
given(decoder.decode(anyString())).willReturn(JWT);
this.mvc.perform(get("/authenticated").with(bearerToken(JWT_TOKEN))).andExpect(status().isOk())
// @formatter:off
this.mvc.perform(get("/authenticated").with(bearerToken(JWT_TOKEN)))
.andExpect(status().isOk())
.andExpect(content().string(JWT_SUBJECT));
// @formatter:on
}
@Test
@ -607,8 +737,11 @@ public class OAuth2ResourceServerConfigurerTests {
CustomJwtDecoderInLambdaOnDsl config = this.spring.getContext().getBean(CustomJwtDecoderInLambdaOnDsl.class);
JwtDecoder decoder = config.decoder();
given(decoder.decode(anyString())).willReturn(JWT);
this.mvc.perform(get("/authenticated").with(bearerToken(JWT_TOKEN))).andExpect(status().isOk())
// @formatter:off
this.mvc.perform(get("/authenticated").with(bearerToken(JWT_TOKEN)))
.andExpect(status().isOk())
.andExpect(content().string(JWT_SUBJECT));
// @formatter:on
}
@Test
@ -616,8 +749,11 @@ public class OAuth2ResourceServerConfigurerTests {
this.spring.register(CustomJwtDecoderAsBean.class, BasicController.class).autowire();
JwtDecoder decoder = this.spring.getContext().getBean(JwtDecoder.class);
given(decoder.decode(anyString())).willReturn(JWT);
this.mvc.perform(get("/authenticated").with(bearerToken(JWT_TOKEN))).andExpect(status().isOk())
// @formatter:off
this.mvc.perform(get("/authenticated").with(bearerToken(JWT_TOKEN)))
.andExpect(status().isOk())
.andExpect(content().string(JWT_SUBJECT));
// @formatter:on
}
@Test
@ -686,8 +822,11 @@ public class OAuth2ResourceServerConfigurerTests {
this.spring.register(RealmNameConfiguredOnEntryPoint.class, JwtDecoderConfig.class).autowire();
JwtDecoder decoder = this.spring.getContext().getBean(JwtDecoder.class);
given(decoder.decode(anyString())).willThrow(JwtException.class);
this.mvc.perform(get("/authenticated").with(bearerToken("invalid_token"))).andExpect(status().isUnauthorized())
// @formatter:off
this.mvc.perform(get("/authenticated").with(bearerToken("invalid_token")))
.andExpect(status().isUnauthorized())
.andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, startsWith("Bearer realm=\"myRealm\"")));
// @formatter:on
}
@Test
@ -695,9 +834,11 @@ public class OAuth2ResourceServerConfigurerTests {
this.spring.register(RealmNameConfiguredOnAccessDeniedHandler.class, JwtDecoderConfig.class).autowire();
JwtDecoder decoder = this.spring.getContext().getBean(JwtDecoder.class);
given(decoder.decode(anyString())).willReturn(JWT);
// @formatter:off
this.mvc.perform(get("/authenticated").with(bearerToken("insufficiently_scoped")))
.andExpect(status().isForbidden())
.andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, startsWith("Bearer realm=\"myRealm\"")));
// @formatter:on
}
@Test
@ -723,8 +864,11 @@ public class OAuth2ResourceServerConfigurerTests {
.getJwtValidator();
OAuth2Error error = new OAuth2Error("custom-error", "custom-description", "custom-uri");
given(jwtValidator.validate(any(Jwt.class))).willReturn(OAuth2TokenValidatorResult.failure(error));
this.mvc.perform(get("/").with(bearerToken(token))).andExpect(status().isUnauthorized())
// @formatter:off
this.mvc.perform(get("/").with(bearerToken(token)))
.andExpect(status().isUnauthorized())
.andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, containsString("custom-description")));
// @formatter:on
}
@Test
@ -733,7 +877,10 @@ public class OAuth2ResourceServerConfigurerTests {
.autowire();
mockRestOperations(jwks("Default"));
String token = this.token("ExpiresAt4687177990");
this.mvc.perform(get("/").with(bearerToken(token))).andExpect(status().isOk());
// @formatter:off
this.mvc.perform(get("/").with(bearerToken(token)))
.andExpect(status().isOk());
// @formatter:on
}
@Test
@ -742,8 +889,11 @@ public class OAuth2ResourceServerConfigurerTests {
.autowire();
mockRestOperations(jwks("Default"));
String token = this.token("ExpiresAt4687177990");
this.mvc.perform(get("/").with(bearerToken(token))).andExpect(status().isUnauthorized())
// @formatter:off
this.mvc.perform(get("/").with(bearerToken(token)))
.andExpect(status().isUnauthorized())
.andExpect(invalidTokenHeader("Jwt expired at"));
// @formatter:on
}
@Test
@ -755,7 +905,10 @@ public class OAuth2ResourceServerConfigurerTests {
given(jwtAuthenticationConverter.convert(JWT)).willReturn(JWT_AUTHENTICATION_TOKEN);
JwtDecoder jwtDecoder = this.spring.getContext().getBean(JwtDecoder.class);
given(jwtDecoder.decode(anyString())).willReturn(JWT);
this.mvc.perform(get("/").with(bearerToken(JWT_TOKEN))).andExpect(status().isOk());
// @formatter:off
this.mvc.perform(get("/").with(bearerToken(JWT_TOKEN)))
.andExpect(status().isOk());
// @formatter:on
verify(jwtAuthenticationConverter).convert(JWT);
}
@ -766,28 +919,40 @@ public class OAuth2ResourceServerConfigurerTests {
.autowire();
JwtDecoder decoder = this.spring.getContext().getBean(JwtDecoder.class);
given(decoder.decode(JWT_TOKEN)).willReturn(JWT);
this.mvc.perform(get("/requires-read-scope").with(bearerToken(JWT_TOKEN))).andExpect(status().isOk());
// @formatter:off
this.mvc.perform(get("/requires-read-scope").with(bearerToken(JWT_TOKEN)))
.andExpect(status().isOk());
// @formatter:on
}
@Test
public void requestWhenUsingPublicKeyAndValidTokenThenAuthenticates() throws Exception {
this.spring.register(SingleKeyConfig.class, BasicController.class).autowire();
String token = this.token("ValidNoScopes");
this.mvc.perform(get("/").with(bearerToken(token))).andExpect(status().isOk());
// @formatter:off
this.mvc.perform(get("/").with(bearerToken(token)))
.andExpect(status().isOk());
// @formatter:on
}
@Test
public void requestWhenUsingPublicKeyAndSignatureFailsThenReturnsInvalidToken() throws Exception {
this.spring.register(SingleKeyConfig.class).autowire();
String token = this.token("WrongSignature");
this.mvc.perform(get("/").with(bearerToken(token))).andExpect(invalidTokenHeader("signature"));
// @formatter:off
this.mvc.perform(get("/").with(bearerToken(token)))
.andExpect(invalidTokenHeader("signature"));
// @formatter:on
}
@Test
public void requestWhenUsingPublicKeyAlgorithmDoesNotMatchThenReturnsInvalidToken() throws Exception {
this.spring.register(SingleKeyConfig.class).autowire();
String token = this.token("WrongAlgorithm");
this.mvc.perform(get("/").with(bearerToken(token))).andExpect(invalidTokenHeader("algorithm"));
// @formatter:off
this.mvc.perform(get("/").with(bearerToken(token)))
.andExpect(invalidTokenHeader("algorithm"));
// @formatter:on
}
// gh-7793
@ -805,8 +970,11 @@ public class OAuth2ResourceServerConfigurerTests {
this.spring.register(JwtAuthenticationManagerConfig.class, BasicController.class).autowire();
given(bean(AuthenticationProvider.class).authenticate(any(Authentication.class)))
.willReturn(JWT_AUTHENTICATION_TOKEN);
this.mvc.perform(get("/authenticated").with(bearerToken("token"))).andExpect(status().isOk())
// @formatter:off
this.mvc.perform(get("/authenticated").with(bearerToken("token")))
.andExpect(status().isOk())
.andExpect(content().string("mock-test-subject"));
// @formatter:on
verifyBean(AuthenticationProvider.class).authenticate(any(Authentication.class));
}
@ -814,8 +982,11 @@ public class OAuth2ResourceServerConfigurerTests {
public void getWhenIntrospectingThenOk() throws Exception {
this.spring.register(RestOperationsConfig.class, OpaqueTokenConfig.class, BasicController.class).autowire();
mockRestOperations(json("Active"));
this.mvc.perform(get("/authenticated").with(bearerToken("token"))).andExpect(status().isOk())
// @formatter:off
this.mvc.perform(get("/authenticated").with(bearerToken("token")))
.andExpect(status().isOk())
.andExpect(content().string("test-subject"));
// @formatter:on
}
@Test
@ -823,24 +994,33 @@ public class OAuth2ResourceServerConfigurerTests {
this.spring.register(RestOperationsConfig.class, OpaqueTokenInLambdaConfig.class, BasicController.class)
.autowire();
mockRestOperations(json("Active"));
this.mvc.perform(get("/authenticated").with(bearerToken("token"))).andExpect(status().isOk())
// @formatter:off
this.mvc.perform(get("/authenticated").with(bearerToken("token")))
.andExpect(status().isOk())
.andExpect(content().string("test-subject"));
// @formatter:on
}
@Test
public void getWhenIntrospectionFailsThenUnauthorized() throws Exception {
this.spring.register(RestOperationsConfig.class, OpaqueTokenConfig.class).autowire();
mockRestOperations(json("Inactive"));
this.mvc.perform(get("/").with(bearerToken("token"))).andExpect(status().isUnauthorized()).andExpect(
header().string(HttpHeaders.WWW_AUTHENTICATE, containsString("Provided token isn't active")));
// @formatter:off
this.mvc.perform(get("/").with(bearerToken("token")))
.andExpect(status().isUnauthorized())
.andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, containsString("Provided token isn't active")));
// @formatter:on
}
@Test
public void getWhenIntrospectionLacksScopeThenForbidden() throws Exception {
this.spring.register(RestOperationsConfig.class, OpaqueTokenConfig.class).autowire();
mockRestOperations(json("ActiveNoScopes"));
this.mvc.perform(get("/requires-read-scope").with(bearerToken("token"))).andExpect(status().isForbidden())
// @formatter:off
this.mvc.perform(get("/requires-read-scope").with(bearerToken("token")))
.andExpect(status().isForbidden())
.andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, containsString("scope")));
// @formatter:on
}
@Test
@ -848,8 +1028,11 @@ public class OAuth2ResourceServerConfigurerTests {
this.spring.register(OpaqueTokenAuthenticationManagerConfig.class, BasicController.class).autowire();
given(bean(AuthenticationProvider.class).authenticate(any(Authentication.class)))
.willReturn(INTROSPECTION_AUTHENTICATION_TOKEN);
this.mvc.perform(get("/authenticated").with(bearerToken("token"))).andExpect(status().isOk())
// @formatter:off
this.mvc.perform(get("/authenticated").with(bearerToken("token")))
.andExpect(status().isOk())
.andExpect(content().string("mock-test-subject"));
// @formatter:on
verifyBean(AuthenticationProvider.class).authenticate(any(Authentication.class));
}
@ -858,8 +1041,11 @@ public class OAuth2ResourceServerConfigurerTests {
this.spring.register(OpaqueTokenAuthenticationManagerInLambdaConfig.class, BasicController.class).autowire();
given(bean(AuthenticationProvider.class).authenticate(any(Authentication.class)))
.willReturn(INTROSPECTION_AUTHENTICATION_TOKEN);
this.mvc.perform(get("/authenticated").with(bearerToken("token"))).andExpect(status().isOk())
// @formatter:off
this.mvc.perform(get("/authenticated").with(bearerToken("token")))
.andExpect(status().isOk())
.andExpect(content().string("mock-test-subject"));
// @formatter:on
verifyBean(AuthenticationProvider.class).authenticate(any(Authentication.class));
}
@ -903,12 +1089,17 @@ public class OAuth2ResourceServerConfigurerTests {
this.spring.register(BasicAndResourceServerConfig.class, JwtDecoderConfig.class).autowire();
JwtDecoder decoder = this.spring.getContext().getBean(JwtDecoder.class);
given(decoder.decode(anyString())).willThrow(JwtException.class);
this.mvc.perform(get("/authenticated").with(httpBasic("some", "user"))).andExpect(status().isUnauthorized())
// @formatter:off
this.mvc.perform(get("/authenticated").with(httpBasic("some", "user")))
.andExpect(status().isUnauthorized())
.andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, startsWith("Basic")));
this.mvc.perform(get("/authenticated")).andExpect(status().isUnauthorized())
this.mvc.perform(get("/authenticated"))
.andExpect(status().isUnauthorized())
.andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, startsWith("Basic")));
this.mvc.perform(get("/authenticated").with(bearerToken("invalid_token"))).andExpect(status().isUnauthorized())
this.mvc.perform(get("/authenticated").with(bearerToken("invalid_token")))
.andExpect(status().isUnauthorized())
.andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, startsWith("Bearer")));
// @formatter:on
}
@Test
@ -916,11 +1107,18 @@ public class OAuth2ResourceServerConfigurerTests {
this.spring.register(FormAndResourceServerConfig.class, JwtDecoderConfig.class).autowire();
JwtDecoder decoder = this.spring.getContext().getBean(JwtDecoder.class);
given(decoder.decode(anyString())).willThrow(JwtException.class);
MvcResult result = this.mvc.perform(get("/authenticated")).andExpect(status().isFound())
.andExpect(redirectedUrl("http://localhost/login")).andReturn();
assertThat(result.getRequest().getSession(false)).isNotNull();
result = this.mvc.perform(get("/authenticated").with(bearerToken("token"))).andExpect(status().isUnauthorized())
// @formatter:off
MvcResult result = this.mvc.perform(get("/authenticated"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("http://localhost/login"))
.andReturn();
// @formatter:on
assertThat(result.getRequest().getSession(false)).isNotNull();
// @formatter:off
result = this.mvc.perform(get("/authenticated").with(bearerToken("token")))
.andExpect(status().isUnauthorized())
.andReturn();
// @formatter:on
assertThat(result.getRequest().getSession(false)).isNull();
}
@ -931,11 +1129,14 @@ public class OAuth2ResourceServerConfigurerTests {
.autowire();
JwtDecoder decoder = this.spring.getContext().getBean(JwtDecoder.class);
given(decoder.decode(anyString())).willReturn(JWT);
// @formatter:off
this.mvc.perform(get("/authenticated").with(httpBasic("basic-user", "basic-password")))
.andExpect(status().isForbidden()).andExpect(header().doesNotExist(HttpHeaders.WWW_AUTHENTICATE));
.andExpect(status().isForbidden())
.andExpect(header().doesNotExist(HttpHeaders.WWW_AUTHENTICATE));
this.mvc.perform(get("/authenticated").with(bearerToken("insufficiently_scoped")))
.andExpect(status().isForbidden())
.andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, startsWith("Bearer")));
// @formatter:on
}
@Test
@ -944,10 +1145,14 @@ public class OAuth2ResourceServerConfigurerTests {
.autowire();
mockRestOperations(jwks("Default"));
String token = this.token("ValidNoScopes");
this.mvc.perform(get("/authenticated").with(bearerToken(token))).andExpect(status().isOk())
// @formatter:off
this.mvc.perform(get("/authenticated").with(bearerToken(token)))
.andExpect(status().isOk())
.andExpect(content().string("test-subject"));
this.mvc.perform(get("/authenticated").with(httpBasic("basic-user", "basic-password")))
.andExpect(status().isOk()).andExpect(content().string("basic-user"));
.andExpect(status().isOk())
.andExpect(content().string("basic-user"));
// @formatter:on
}
@Test
@ -980,16 +1185,25 @@ public class OAuth2ResourceServerConfigurerTests {
String jwtThree = jwtFromIssuer(issuerThree);
mockWebServer(String.format(metadata, issuerOne, issuerOne));
mockWebServer(jwkSet);
this.mvc.perform(get("/authenticated").with(bearerToken(jwtOne))).andExpect(status().isOk())
// @formatter:off
this.mvc.perform(get("/authenticated").with(bearerToken(jwtOne)))
.andExpect(status().isOk())
.andExpect(content().string("test-subject"));
// @formatter:on
mockWebServer(String.format(metadata, issuerTwo, issuerTwo));
mockWebServer(jwkSet);
this.mvc.perform(get("/authenticated").with(bearerToken(jwtTwo))).andExpect(status().isOk())
// @formatter:off
this.mvc.perform(get("/authenticated").with(bearerToken(jwtTwo)))
.andExpect(status().isOk())
.andExpect(content().string("test-subject"));
// @formatter:on
mockWebServer(String.format(metadata, issuerThree, issuerThree));
mockWebServer(jwkSet);
this.mvc.perform(get("/authenticated").with(bearerToken(jwtThree))).andExpect(status().isUnauthorized())
// @formatter:off
this.mvc.perform(get("/authenticated").with(bearerToken(jwtThree)))
.andExpect(status().isUnauthorized())
.andExpect(invalidTokenHeader("Invalid issuer"));
// @formatter:on
}
@Test

View File

@ -40,6 +40,7 @@ import org.springframework.security.openid.OpenIDAuthenticationFilter;
import org.springframework.security.openid.OpenIDAuthenticationProvider;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
@ -84,15 +85,21 @@ public class OpenIDLoginConfigurerTests {
@Test
public void openidLoginWhenInvokedTwiceThenUsesOriginalLoginPage() throws Exception {
this.spring.register(InvokeTwiceDoesNotOverrideConfig.class).autowire();
this.mvc.perform(get("/")).andExpect(status().isFound())
// @formatter:off
this.mvc.perform(get("/"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("http://localhost/login/custom"));
// @formatter:on
}
@Test
public void requestWhenOpenIdLoginPageInLambdaThenRedirectsToLoginPAge() throws Exception {
this.spring.register(OpenIdLoginPageInLambdaConfig.class).autowire();
this.mvc.perform(get("/")).andExpect(status().isFound())
// @formatter:off
this.mvc.perform(get("/"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("http://localhost/login/custom"));
// @formatter:on
}
@Test
@ -144,11 +151,15 @@ public class OpenIDLoginConfigurerTests {
server.enqueue(new MockResponse().addHeader(YadisResolver.YADIS_XRDS_LOCATION, endpoint));
server.enqueue(new MockResponse()
.setBody(String.format("<XRDS><XRD><Service><URI>%s</URI></Service></XRD></XRDS>", endpoint)));
MvcResult mvcResult = this.mvc.perform(
get("/login/openid").param(OpenIDAuthenticationFilter.DEFAULT_CLAIMED_IDENTITY_FIELD, endpoint))
.andExpect(status().isFound()).andReturn();
// @formatter:off
MockHttpServletRequestBuilder request = get("/login/openid")
.param(OpenIDAuthenticationFilter.DEFAULT_CLAIMED_IDENTITY_FIELD, endpoint);
MvcResult mvcResult = this.mvc.perform(request)
.andExpect(status().isFound())
.andReturn();
Object attributeObject = mvcResult.getRequest().getSession()
.getAttribute("SPRING_SECURITY_OPEN_ID_ATTRIBUTES_FETCH_LIST");
// @formatter:on
assertThat(attributeObject).isInstanceOf(List.class);
List<OpenIDAttribute> attributeList = (List<OpenIDAttribute>) attributeObject;
assertThat(attributeList).hasSize(1);

View File

@ -82,6 +82,7 @@ import org.springframework.security.web.context.SecurityContextRepository;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;
@ -198,8 +199,11 @@ public class Saml2LoginConfigurerTests {
String response = new String(samlDecode(SIGNED_RESPONSE));
given(CustomAuthenticationConverter.authenticationConverter.convert(any(HttpServletRequest.class)))
.willReturn(new Saml2AuthenticationToken(relyingPartyRegistration, response));
this.mvc.perform(post("/login/saml2/sso/" + relyingPartyRegistration.getRegistrationId()).param("SAMLResponse",
SIGNED_RESPONSE)).andExpect(redirectedUrl("/"));
// @formatter:off
MockHttpServletRequestBuilder request = post("/login/saml2/sso/" + relyingPartyRegistration.getRegistrationId())
.param("SAMLResponse", SIGNED_RESPONSE);
// @formatter:on
this.mvc.perform(request).andExpect(redirectedUrl("/"));
verify(CustomAuthenticationConverter.authenticationConverter).convert(any(HttpServletRequest.class));
}

View File

@ -35,6 +35,7 @@ public final class TestSaml2Credentials {
}
static Saml2X509Credential verificationCertificate() {
// @formatter:off
String certificate = "-----BEGIN CERTIFICATE-----\n"
+ "MIIEEzCCAvugAwIBAgIJAIc1qzLrv+5nMA0GCSqGSIb3DQEBCwUAMIGfMQswCQYD\n"
+ "VQQGEwJVUzELMAkGA1UECAwCQ08xFDASBgNVBAcMC0Nhc3RsZSBSb2NrMRwwGgYD\n"
@ -57,7 +58,9 @@ public final class TestSaml2Credentials {
+ "ZnrV+oc2zGD+no1/ySFOe3EiJCO5dehxKjYEmBRv5sU/LZFKZpozKN/BMEa6CqLu\n"
+ "xbzb7ykxVr7EVFXwltPxzE9TmL9OACNNyF5eJHWMRMllarUvkcXlh4pux4ks9e6z\n"
+ "V9DQBy2zds9f1I3qxg0eX6JnGrXi/ZiCT+lJgVe3ZFXiejiLAiKB04sXW3ti0LW3\n"
+ "lx13Y1YlQ4/tlpgTgfIJxKV6nyPiLoK0nywbMd+vpAirDt2Oc+hk\n" + "-----END CERTIFICATE-----";
+ "lx13Y1YlQ4/tlpgTgfIJxKV6nyPiLoK0nywbMd+vpAirDt2Oc+hk\n"
+ "-----END CERTIFICATE-----";
// @formatter:on
return new Saml2X509Credential(x509Certificate(certificate), Saml2X509CredentialType.VERIFICATION);
}
@ -73,6 +76,7 @@ public final class TestSaml2Credentials {
}
static Saml2X509Credential signingCredential() {
// @formatter:off
String key = "-----BEGIN PRIVATE KEY-----\n"
+ "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBANG7v8QjQGU3MwQE\n"
+ "VUBxvH6Uuiy/MhZT7TV0ZNjyAF2ExA1gpn3aUxx6jYK5UnrpxRRE/KbeLucYbOhK\n"
@ -86,8 +90,11 @@ public final class TestSaml2Credentials {
+ "EGvYtQJBAMm/i9NR7IVyyNIgZUpz5q4LI21rl1r4gUQuD8vA36zM81i4ROeuCly0\n"
+ "KkfdxR4PUfnKcQCX11YnHjk9uTFj75ECQEFY/gBnxDjzqyF35hAzrYIiMPQVfznt\n"
+ "YX/sDTE2AdVBVGaMj1Cb51bPHnNC6Q5kXKQnj/YrLqRQND09Q7ParX0CQQC5NxZr\n"
+ "9jKqhHj8yQD6PlXTsY4Occ7DH6/IoDenfdEVD5qlet0zmd50HatN2Jiqm5ubN7CM\n" + "INrtuLp4YHbgk1mi\n"
+ "9jKqhHj8yQD6PlXTsY4Occ7DH6/IoDenfdEVD5qlet0zmd50HatN2Jiqm5ubN7CM\n"
+ "INrtuLp4YHbgk1mi\n"
+ "-----END PRIVATE KEY-----";
// @formatter:on
// @formatter:off
String certificate = "-----BEGIN CERTIFICATE-----\n"
+ "MIICgTCCAeoCCQCuVzyqFgMSyDANBgkqhkiG9w0BAQsFADCBhDELMAkGA1UEBhMC\n"
+ "VVMxEzARBgNVBAgMCldhc2hpbmd0b24xEjAQBgNVBAcMCVZhbmNvdXZlcjEdMBsG\n"
@ -102,7 +109,9 @@ public final class TestSaml2Credentials {
+ "y3Q6x+I4qakY/9qhBQIDAQABMA0GCSqGSIb3DQEBCwUAA4GBAAeViTvHOyQopWEi\n"
+ "XOfI2Z9eukwrSknDwq/zscR0YxwwqDBMt/QdAODfSwAfnciiYLkmEjlozWRtOeN+\n"
+ "qK7UFgP1bRl5qksrYX5S0z2iGJh0GvonLUt3e20Ssfl5tTEDDnAEUMLfBkyaxEHD\n"
+ "RZ/nbTJ7VTeZOSyRoVn5XHhpuJ0B\n" + "-----END CERTIFICATE-----";
+ "RZ/nbTJ7VTeZOSyRoVn5XHhpuJ0B\n"
+ "-----END CERTIFICATE-----";
// @formatter:on
PrivateKey pk = RsaKeyConverters.pkcs8().convert(new ByteArrayInputStream(key.getBytes()));
X509Certificate cert = x509Certificate(certificate);
return new Saml2X509Credential(pk, cert, Saml2X509CredentialType.SIGNING, Saml2X509CredentialType.DECRYPTION);

View File

@ -49,9 +49,12 @@ public class MessageSecurityMetadataSourceRegistryTests {
@Before
public void setup() {
this.messages = new MessageSecurityMetadataSourceRegistry();
// @formatter:off
this.message = MessageBuilder.withPayload("Hi")
.setHeader(SimpMessageHeaderAccessor.DESTINATION_HEADER, "location")
.setHeader(SimpMessageHeaderAccessor.MESSAGE_TYPE_HEADER, SimpMessageType.MESSAGE).build();
.setHeader(SimpMessageHeaderAccessor.MESSAGE_TYPE_HEADER, SimpMessageType.MESSAGE)
.build();
// @formatter:on
}
// See
@ -59,24 +62,36 @@ public class MessageSecurityMetadataSourceRegistryTests {
// https://jira.spring.io/browse/SPR-11660
@Test
public void simpDestMatchersCustom() {
// @formatter:off
this.message = MessageBuilder.withPayload("Hi")
.setHeader(SimpMessageHeaderAccessor.DESTINATION_HEADER, "price.stock.1.2").build();
.setHeader(SimpMessageHeaderAccessor.DESTINATION_HEADER, "price.stock.1.2")
.build();
// @formatter:on
this.messages.simpDestPathMatcher(new AntPathMatcher(".")).simpDestMatchers("price.stock.*").permitAll();
assertThat(getAttribute()).isNull();
// @formatter:off
this.message = MessageBuilder.withPayload("Hi")
.setHeader(SimpMessageHeaderAccessor.DESTINATION_HEADER, "price.stock.1.2").build();
.setHeader(SimpMessageHeaderAccessor.DESTINATION_HEADER, "price.stock.1.2")
.build();
// @formatter:on
this.messages.simpDestPathMatcher(new AntPathMatcher(".")).simpDestMatchers("price.stock.**").permitAll();
assertThat(getAttribute()).isEqualTo("permitAll");
}
@Test
public void simpDestMatchersCustomSetAfterMatchersDoesNotMatter() {
// @formatter:off
this.message = MessageBuilder.withPayload("Hi")
.setHeader(SimpMessageHeaderAccessor.DESTINATION_HEADER, "price.stock.1.2").build();
.setHeader(SimpMessageHeaderAccessor.DESTINATION_HEADER, "price.stock.1.2")
.build();
// @formatter:on
this.messages.simpDestMatchers("price.stock.*").permitAll().simpDestPathMatcher(new AntPathMatcher("."));
assertThat(getAttribute()).isNull();
// @formatter:off
this.message = MessageBuilder.withPayload("Hi")
.setHeader(SimpMessageHeaderAccessor.DESTINATION_HEADER, "price.stock.1.2").build();
.setHeader(SimpMessageHeaderAccessor.DESTINATION_HEADER, "price.stock.1.2")
.build();
// @formatter:on
this.messages.simpDestMatchers("price.stock.**").permitAll().simpDestPathMatcher(new AntPathMatcher("."));
assertThat(getAttribute()).isEqualTo("permitAll");
}
@ -107,26 +122,41 @@ public class MessageSecurityMetadataSourceRegistryTests {
@Test
public void simpDestMatchersMulti() {
this.messages.simpDestMatchers("admin/**", "api/**").hasRole("ADMIN").simpDestMatchers("location").permitAll();
// @formatter:off
this.messages
.simpDestMatchers("admin/**", "api/**").hasRole("ADMIN")
.simpDestMatchers("location").permitAll();
// @formatter:on
assertThat(getAttribute()).isEqualTo("permitAll");
}
@Test
public void simpDestMatchersRole() {
this.messages.simpDestMatchers("admin/**", "location/**").hasRole("ADMIN").anyMessage().denyAll();
// @formatter:off
this.messages
.simpDestMatchers("admin/**", "location/**").hasRole("ADMIN")
.anyMessage().denyAll();
// @formatter:on
assertThat(getAttribute()).isEqualTo("hasRole('ROLE_ADMIN')");
}
@Test
public void simpDestMatchersAnyRole() {
this.messages.simpDestMatchers("admin/**", "location/**").hasAnyRole("ADMIN", "ROOT").anyMessage().denyAll();
// @formatter:off
this.messages
.simpDestMatchers("admin/**", "location/**").hasAnyRole("ADMIN", "ROOT")
.anyMessage().denyAll();
// @formatter:on
assertThat(getAttribute()).isEqualTo("hasAnyRole('ROLE_ADMIN','ROLE_ROOT')");
}
@Test
public void simpDestMatchersAuthority() {
this.messages.simpDestMatchers("admin/**", "location/**").hasAuthority("ROLE_ADMIN").anyMessage()
.fullyAuthenticated();
// @formatter:off
this.messages
.simpDestMatchers("admin/**", "location/**").hasAuthority("ROLE_ADMIN")
.anyMessage().fullyAuthenticated();
// @formatter:on
assertThat(getAttribute()).isEqualTo("hasAuthority('ROLE_ADMIN')");
}
@ -139,98 +169,157 @@ public class MessageSecurityMetadataSourceRegistryTests {
@Test
public void simpDestMatchersAnyAuthority() {
this.messages.simpDestMatchers("admin/**", "location/**").hasAnyAuthority("ROLE_ADMIN", "ROLE_ROOT")
// @formatter:off
this.messages
.simpDestMatchers("admin/**", "location/**").hasAnyAuthority("ROLE_ADMIN", "ROLE_ROOT")
.anyMessage().denyAll();
// @formatter:on
assertThat(getAttribute()).isEqualTo("hasAnyAuthority('ROLE_ADMIN','ROLE_ROOT')");
}
@Test
public void simpDestMatchersRememberMe() {
this.messages.simpDestMatchers("admin/**", "location/**").rememberMe().anyMessage().denyAll();
// @formatter:off
this.messages
.simpDestMatchers("admin/**", "location/**").rememberMe()
.anyMessage().denyAll();
// @formatter:on
assertThat(getAttribute()).isEqualTo("rememberMe");
}
@Test
public void simpDestMatchersAnonymous() {
this.messages.simpDestMatchers("admin/**", "location/**").anonymous().anyMessage().denyAll();
// @formatter:off
this.messages
.simpDestMatchers("admin/**", "location/**").anonymous()
.anyMessage().denyAll();
// @formatter:on
assertThat(getAttribute()).isEqualTo("anonymous");
}
@Test
public void simpDestMatchersFullyAuthenticated() {
this.messages.simpDestMatchers("admin/**", "location/**").fullyAuthenticated().anyMessage().denyAll();
// @formatter:off
this.messages
.simpDestMatchers("admin/**", "location/**").fullyAuthenticated()
.anyMessage().denyAll();
// @formatter:on
assertThat(getAttribute()).isEqualTo("fullyAuthenticated");
}
@Test
public void simpDestMatchersDenyAll() {
this.messages.simpDestMatchers("admin/**", "location/**").denyAll().anyMessage().permitAll();
// @formatter:off
this.messages
.simpDestMatchers("admin/**", "location/**").denyAll()
.anyMessage().permitAll();
// @formatter:on
assertThat(getAttribute()).isEqualTo("denyAll");
}
@Test
public void simpDestMessageMatchersNotMatch() {
this.messages.simpMessageDestMatchers("admin/**").denyAll().anyMessage().permitAll();
// @formatter:off
this.messages.
simpMessageDestMatchers("admin/**").denyAll()
.anyMessage().permitAll();
// @formatter:on
assertThat(getAttribute()).isEqualTo("permitAll");
}
@Test
public void simpDestMessageMatchersMatch() {
this.messages.simpMessageDestMatchers("location/**").denyAll().anyMessage().permitAll();
// @formatter:off
this.messages
.simpMessageDestMatchers("location/**").denyAll()
.anyMessage().permitAll();
// @formatter:on
assertThat(getAttribute()).isEqualTo("denyAll");
}
@Test
public void simpDestSubscribeMatchersNotMatch() {
this.messages.simpSubscribeDestMatchers("location/**").denyAll().anyMessage().permitAll();
// @formatter:off
this.messages
.simpSubscribeDestMatchers("location/**").denyAll()
.anyMessage().permitAll();
// @formatter:on
assertThat(getAttribute()).isEqualTo("permitAll");
}
@Test
public void simpDestSubscribeMatchersMatch() {
// @formatter:off
this.message = MessageBuilder.fromMessage(this.message)
.setHeader(SimpMessageHeaderAccessor.MESSAGE_TYPE_HEADER, SimpMessageType.SUBSCRIBE).build();
this.messages.simpSubscribeDestMatchers("location/**").denyAll().anyMessage().permitAll();
.setHeader(SimpMessageHeaderAccessor.MESSAGE_TYPE_HEADER, SimpMessageType.SUBSCRIBE)
.build();
this.messages
.simpSubscribeDestMatchers("location/**").denyAll()
.anyMessage().permitAll();
// @formatter:on
assertThat(getAttribute()).isEqualTo("denyAll");
}
@Test
public void nullDestMatcherNotMatches() {
this.messages.nullDestMatcher().denyAll().anyMessage().permitAll();
// @formatter:off
this.messages
.nullDestMatcher().denyAll()
.anyMessage().permitAll();
// @formatter:on
assertThat(getAttribute()).isEqualTo("permitAll");
}
@Test
public void nullDestMatcherMatch() {
// @formatter:off
this.message = MessageBuilder.withPayload("Hi")
.setHeader(SimpMessageHeaderAccessor.MESSAGE_TYPE_HEADER, SimpMessageType.CONNECT).build();
this.messages.nullDestMatcher().denyAll().anyMessage().permitAll();
.setHeader(SimpMessageHeaderAccessor.MESSAGE_TYPE_HEADER, SimpMessageType.CONNECT)
.build();
this.messages
.nullDestMatcher().denyAll()
.anyMessage().permitAll();
// @formatter:on
assertThat(getAttribute()).isEqualTo("denyAll");
}
@Test
public void simpTypeMatchersMatch() {
this.messages.simpTypeMatchers(SimpMessageType.MESSAGE).denyAll().anyMessage().permitAll();
// @formatter:off
this.messages
.simpTypeMatchers(SimpMessageType.MESSAGE).denyAll()
.anyMessage().permitAll();
// @formatter:on
assertThat(getAttribute()).isEqualTo("denyAll");
}
@Test
public void simpTypeMatchersMatchMulti() {
this.messages.simpTypeMatchers(SimpMessageType.CONNECT, SimpMessageType.MESSAGE).denyAll().anyMessage()
.permitAll();
// @formatter:off
this.messages
.simpTypeMatchers(SimpMessageType.CONNECT, SimpMessageType.MESSAGE).denyAll()
.anyMessage().permitAll();
// @formatter:on
assertThat(getAttribute()).isEqualTo("denyAll");
}
@Test
public void simpTypeMatchersNotMatch() {
this.messages.simpTypeMatchers(SimpMessageType.CONNECT).denyAll().anyMessage().permitAll();
// @formatter:off
this.messages
.simpTypeMatchers(SimpMessageType.CONNECT).denyAll()
.anyMessage().permitAll();
// @formatter:on
assertThat(getAttribute()).isEqualTo("permitAll");
}
@Test
public void simpTypeMatchersNotMatchMulti() {
this.messages.simpTypeMatchers(SimpMessageType.CONNECT, SimpMessageType.DISCONNECT).denyAll().anyMessage()
.permitAll();
// @formatter:off
this.messages
.simpTypeMatchers(SimpMessageType.CONNECT, SimpMessageType.DISCONNECT).denyAll()
.anyMessage().permitAll();
// @formatter:on
assertThat(getAttribute()).isEqualTo("permitAll");
}

View File

@ -22,6 +22,7 @@ import java.security.Principal;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.web.server.WebFilter;
import reactor.core.publisher.Mono;
import org.springframework.beans.factory.annotation.Autowired;
@ -72,6 +73,7 @@ import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.result.view.AbstractView;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.security.test.web.reactive.server.SecurityMockServerConfigurers.csrf;
/**
* @author Rob Winch
@ -90,24 +92,48 @@ public class EnableWebFluxSecurityTests {
@Test
public void defaultRequiresAuthentication() {
this.spring.register(Config.class).autowire();
WebTestClient client = WebTestClientBuilder.bindToWebFilters(this.springSecurityFilterChain).build();
client.get().uri("/").exchange().expectStatus().isUnauthorized().expectBody().isEmpty();
// @formatter:off
WebTestClient client = WebTestClientBuilder
.bindToWebFilters(this.springSecurityFilterChain)
.build();
client.get()
.uri("/")
.exchange()
.expectStatus().isUnauthorized()
.expectBody().isEmpty();
// @formatter:on
}
// gh-4831
@Test
public void defaultMediaAllThenUnAuthorized() {
this.spring.register(Config.class).autowire();
WebTestClient client = WebTestClientBuilder.bindToWebFilters(this.springSecurityFilterChain).build();
client.get().uri("/").accept(MediaType.ALL).exchange().expectStatus().isUnauthorized().expectBody().isEmpty();
// @formatter:off
WebTestClient client = WebTestClientBuilder
.bindToWebFilters(this.springSecurityFilterChain)
.build();
client.get()
.uri("/")
.accept(MediaType.ALL)
.exchange()
.expectStatus().isUnauthorized()
.expectBody().isEmpty();
// @formatter:on
}
@Test
public void authenticateWhenBasicThenNoSession() {
this.spring.register(Config.class).autowire();
WebTestClient client = WebTestClientBuilder.bindToWebFilters(this.springSecurityFilterChain).build();
FluxExchangeResult<String> result = client.get().headers((headers) -> headers.setBasicAuth("user", "password"))
.exchange().expectStatus().isOk().returnResult(String.class);
// @formatter:off
WebTestClient client = WebTestClientBuilder
.bindToWebFilters(this.springSecurityFilterChain)
.build();
FluxExchangeResult<String> result = client.get()
.headers((headers) -> headers.setBasicAuth("user", "password"))
.exchange()
.expectStatus().isOk()
.returnResult(String.class);
// @formatter:on
result.assertWithDiagnostics(() -> assertThat(result.getResponseCookies().isEmpty()));
}
@ -117,33 +143,45 @@ public class EnableWebFluxSecurityTests {
Authentication currentPrincipal = new TestingAuthenticationToken("user", "password", "ROLE_USER");
WebSessionServerSecurityContextRepository contextRepository = new WebSessionServerSecurityContextRepository();
SecurityContext context = new SecurityContextImpl(currentPrincipal);
// @formatter:off
WebFilter contextRepositoryWebFilter = (exchange, chain) -> contextRepository.save(exchange, context)
.switchIfEmpty(chain.filter(exchange))
.flatMap((e) -> chain.filter(exchange));
WebTestClient client = WebTestClientBuilder
.bindToWebFilters(
(exchange, chain) -> contextRepository.save(exchange, context)
.switchIfEmpty(chain.filter(exchange)).flatMap((e) -> chain.filter(exchange)),
this.springSecurityFilterChain,
(exchange,
chain) -> ReactiveSecurityContextHolder.getContext()
.map(SecurityContext::getAuthentication).flatMap((principal) -> exchange
.getResponse().writeWith(Mono.just(toDataBuffer(principal.getName())))))
.bindToWebFilters(contextRepositoryWebFilter, this.springSecurityFilterChain, writePrincipalWebFilter())
.build();
client.get().uri("/").exchange().expectStatus().isOk().expectBody(String.class)
.consumeWith((result) -> assertThat(result.getResponseBody()).isEqualTo(currentPrincipal.getName()));
client.get()
.uri("/")
.exchange()
.expectStatus().isOk()
.expectBody(String.class).consumeWith((result) -> assertThat(result.getResponseBody()).isEqualTo(currentPrincipal.getName()));
// @formatter:on
}
private WebFilter writePrincipalWebFilter() {
// @formatter:off
return (exchange, chain) -> ReactiveSecurityContextHolder.getContext()
.map(SecurityContext::getAuthentication)
.flatMap((principal) -> exchange.getResponse()
.writeWith(Mono.just(toDataBuffer(principal.getName())))
);
// @formatter:on
}
@Test
public void defaultPopulatesReactorContextWhenAuthenticating() {
this.spring.register(Config.class).autowire();
// @formatter:off
WebTestClient client = WebTestClientBuilder
.bindToWebFilters(this.springSecurityFilterChain,
(exchange,
chain) -> ReactiveSecurityContextHolder.getContext()
.map(SecurityContext::getAuthentication).flatMap((principal) -> exchange
.getResponse().writeWith(Mono.just(toDataBuffer(principal.getName())))))
.bindToWebFilters(this.springSecurityFilterChain, writePrincipalWebFilter())
.build();
client.get().uri("/").headers((headers) -> headers.setBasicAuth("user", "password")).exchange().expectStatus()
.isOk().expectBody(String.class)
.consumeWith((result) -> assertThat(result.getResponseBody()).isEqualTo("user"));
client.get()
.uri("/")
.headers((headers) -> headers.setBasicAuth("user", "password"))
.exchange()
.expectStatus().isOk()
.expectBody(String.class).consumeWith((result) -> assertThat(result.getResponseBody()).isEqualTo("user"));
// @formatter:on
}
@Test
@ -158,23 +196,30 @@ public class EnableWebFluxSecurityTests {
@Test
public void passwordEncoderBeanIsUsed() {
this.spring.register(CustomPasswordEncoderConfig.class).autowire();
// @formatter:off
WebTestClient client = WebTestClientBuilder
.bindToWebFilters(this.springSecurityFilterChain,
(exchange,
chain) -> ReactiveSecurityContextHolder.getContext()
.map(SecurityContext::getAuthentication).flatMap((principal) -> exchange
.getResponse().writeWith(Mono.just(toDataBuffer(principal.getName())))))
.bindToWebFilters(this.springSecurityFilterChain, writePrincipalWebFilter())
.build();
client.get().uri("/").headers((headers) -> headers.setBasicAuth("user", "password")).exchange().expectStatus()
.isOk().expectBody(String.class)
client.get().uri("/").headers((headers) -> headers.setBasicAuth("user", "password"))
.exchange().expectStatus().isOk()
.expectBody(String.class)
.consumeWith((result) -> assertThat(result.getResponseBody()).isEqualTo("user"));
// @formatter:on
}
@Test
public void passwordUpdateManagerUsed() {
this.spring.register(MapReactiveUserDetailsServiceConfig.class).autowire();
WebTestClient client = WebTestClientBuilder.bindToWebFilters(this.springSecurityFilterChain).build();
client.get().uri("/").headers((h) -> h.setBasicAuth("user", "password")).exchange().expectStatus().isOk();
// @formatter:off
WebTestClient client = WebTestClientBuilder
.bindToWebFilters(this.springSecurityFilterChain)
.build();
client.get()
.uri("/")
.headers((h) -> h.setBasicAuth("user", "password"))
.exchange()
.expectStatus().isOk();
// @formatter:on
ReactiveUserDetailsService users = this.spring.getContext().getBean(ReactiveUserDetailsService.class);
assertThat(users.findByUsername("user").block().getPassword()).startsWith("{bcrypt}");
}
@ -182,32 +227,58 @@ public class EnableWebFluxSecurityTests {
@Test
public void formLoginWorks() {
this.spring.register(Config.class).autowire();
WebTestClient client = WebTestClientBuilder.bindToWebFilters(this.springSecurityFilterChain, (exchange,
chain) -> Mono.subscriberContext().flatMap((c) -> c.<Mono<Principal>>get(Authentication.class)).flatMap(
(principal) -> exchange.getResponse().writeWith(Mono.just(toDataBuffer(principal.getName())))))
// @formatter:off
WebTestClient client = WebTestClientBuilder
.bindToWebFilters(this.springSecurityFilterChain, writePrincipalWebFilter())
.build();
// @formatter:on
MultiValueMap<String, String> data = new LinkedMultiValueMap<>();
data.add("username", "user");
data.add("password", "password");
client.mutateWith(SecurityMockServerConfigurers.csrf()).post().uri("/login")
.body(BodyInserters.fromFormData(data)).exchange().expectStatus().is3xxRedirection().expectHeader()
.valueMatches("Location", "/");
// @formatter:off
client.mutateWith(csrf())
.post()
.uri("/login")
.body(BodyInserters.fromFormData(data))
.exchange()
.expectStatus().is3xxRedirection()
.expectHeader().valueMatches("Location", "/");
// @formatter:on
}
@Test
public void multiWorks() {
this.spring.register(MultiSecurityHttpConfig.class).autowire();
WebTestClient client = WebTestClientBuilder.bindToWebFilters(this.springSecurityFilterChain).build();
client.get().uri("/api/test").exchange().expectStatus().isUnauthorized().expectBody().isEmpty();
client.get().uri("/test").exchange().expectStatus().isOk();
// @formatter:off
WebTestClient client = WebTestClientBuilder
.bindToWebFilters(this.springSecurityFilterChain)
.build();
client.get()
.uri("/api/test")
.exchange()
.expectStatus().isUnauthorized()
.expectBody().isEmpty();
client.get()
.uri("/test")
.exchange()
.expectStatus().isOk();
// @formatter:on
}
@Test
@WithMockUser
public void authenticationPrincipalArgumentResolverWhenSpelThenWorks() {
this.spring.register(AuthenticationPrincipalConfig.class).autowire();
WebTestClient client = WebTestClient.bindToApplicationContext(this.spring.getContext()).build();
client.get().uri("/spel").exchange().expectStatus().isOk().expectBody(String.class).isEqualTo("user");
// @formatter:off
WebTestClient client = WebTestClient
.bindToApplicationContext(this.spring.getContext())
.build();
client.get()
.uri("/spel")
.exchange()
.expectStatus().isOk()
.expectBody(String.class).isEqualTo("user");
// @formatter:on
}
private static DataBuffer toDataBuffer(String body) {

View File

@ -590,10 +590,12 @@ public class AbstractSecurityWebSocketMessageBrokerConfigurerTests {
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/other").setHandshakeHandler(testHandshakeHandler()).withSockJS()
.setInterceptors(new HttpSessionHandshakeInterceptor());
registry.addEndpoint("/chat").setHandshakeHandler(testHandshakeHandler()).withSockJS()
.setInterceptors(new HttpSessionHandshakeInterceptor());
// @formatter:off
registry.addEndpoint("/other").setHandshakeHandler(testHandshakeHandler())
.withSockJS().setInterceptors(new HttpSessionHandshakeInterceptor());
registry.addEndpoint("/chat").setHandshakeHandler(testHandshakeHandler())
.withSockJS().setInterceptors(new HttpSessionHandshakeInterceptor());
// @formatter:on
}
// @formatter:off
@ -646,8 +648,12 @@ public class AbstractSecurityWebSocketMessageBrokerConfigurerTests {
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/other").withSockJS().setInterceptors(new HttpSessionHandshakeInterceptor());
registry.addEndpoint("/chat").withSockJS().setInterceptors(new HttpSessionHandshakeInterceptor());
// @formatter:off
registry.addEndpoint("/other")
.withSockJS().setInterceptors(new HttpSessionHandshakeInterceptor());
registry.addEndpoint("/chat")
.withSockJS().setInterceptors(new HttpSessionHandshakeInterceptor());
// @formatter:on
}
@Override
@ -684,19 +690,23 @@ public class AbstractSecurityWebSocketMessageBrokerConfigurerTests {
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/websocket").setHandshakeHandler(testHandshakeHandler())
// @formatter:off
registry.addEndpoint("/websocket")
.setHandshakeHandler(testHandshakeHandler())
.addInterceptors(new HttpSessionHandshakeInterceptor());
// @formatter:on
}
// @formatter:off
@Override
protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
// @formatter:off
messages
.simpDestMatchers("/permitAll/**").permitAll()
.simpDestMatchers("/customExpression/**").access("denyRob")
.anyMessage().denyAll();
// @formatter:on
}
// @formatter:on
@Bean
public TestHandshakeHandler testHandshakeHandler() {
return new TestHandshakeHandler();
@ -713,8 +723,11 @@ public class AbstractSecurityWebSocketMessageBrokerConfigurerTests {
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/chat").setHandshakeHandler(this.context.getBean(TestHandshakeHandler.class))
// @formatter:off
registry.addEndpoint("/chat")
.setHandshakeHandler(this.context.getBean(TestHandshakeHandler.class))
.withSockJS().setInterceptors(new HttpSessionHandshakeInterceptor());
// @formatter:on
}
@Autowired

View File

@ -44,10 +44,15 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
*/
public class AuthenticationManagerBeanDefinitionParserTests {
private static final String CONTEXT = "<authentication-manager id='am'>" + " <authentication-provider>"
// @formatter:off
private static final String CONTEXT = "<authentication-manager id='am'>"
+ " <authentication-provider>"
+ " <user-service>"
+ " <user name='bob' password='{noop}bobspassword' authorities='ROLE_A,ROLE_B' />"
+ " </user-service>" + " </authentication-provider>" + "</authentication-manager>";
+ " </user-service>"
+ " </authentication-provider>"
+ "</authentication-manager>";
// @formatter:on
@Rule
public final SpringTestRule spring = new SpringTestRule();
@ -92,12 +97,17 @@ public class AuthenticationManagerBeanDefinitionParserTests {
@Test
public void passwordEncoderBeanUsed() throws Exception {
this.spring.context(
"<b:bean id='passwordEncoder' class='org.springframework.security.crypto.password.NoOpPasswordEncoder' factory-method='getInstance'/>"
+ "<user-service>" + " <user name='user' password='password' authorities='ROLE_A,ROLE_B' />"
+ "</user-service>" + "<http/>")
.mockMvcAfterSpringSecurityOk().autowire();
this.mockMvc.perform(get("/").with(httpBasic("user", "password"))).andExpect(status().isOk());
// @formatter:off
this.spring.context("<b:bean id='passwordEncoder' class='org.springframework.security.crypto.password.NoOpPasswordEncoder' factory-method='getInstance'/>"
+ "<user-service>"
+ " <user name='user' password='password' authorities='ROLE_A,ROLE_B' />"
+ "</user-service>"
+ "<http/>")
.mockMvcAfterSpringSecurityOk()
.autowire();
this.mockMvc.perform(get("/").with(httpBasic("user", "password")))
.andExpect(status().isOk());
// @formatter:on
}
private static class AuthListener implements ApplicationListener<AbstractAuthenticationEvent> {

View File

@ -51,73 +51,107 @@ public class AuthenticationProviderBeanDefinitionParserTests {
@Test
public void worksWithEmbeddedUserService() {
setContext(" <authentication-provider>" + " <user-service>"
// @formatter:off
setContext(" <authentication-provider>"
+ " <user-service>"
+ " <user name='bob' password='{noop}bobspassword' authorities='ROLE_A' />"
+ " </user-service>" + " </authentication-provider>");
+ " </user-service>"
+ " </authentication-provider>");
// @formatter:on
getProvider().authenticate(this.bob);
}
@Test
public void externalUserServiceRefWorks() {
// @formatter:off
this.appContext = new InMemoryXmlApplicationContext(
" <authentication-manager>" + " <authentication-provider user-service-ref='myUserService' />"
+ " </authentication-manager>" + " <user-service id='myUserService'>"
+ " <user name='bob' password='{noop}bobspassword' authorities='ROLE_A' />"
+ " </user-service>");
" <authentication-manager>"
+ " <authentication-provider user-service-ref='myUserService' />"
+ " </authentication-manager>" + " <user-service id='myUserService'>"
+ " <user name='bob' password='{noop}bobspassword' authorities='ROLE_A' />"
+ " </user-service>");
// @formatter:on
getProvider().authenticate(this.bob);
}
@Test
public void providerWithBCryptPasswordEncoderWorks() {
setContext(" <authentication-provider>" + " <password-encoder hash='bcrypt'/>" + " <user-service>"
// @formatter:off
setContext(" <authentication-provider>"
+ " <password-encoder hash='bcrypt'/>"
+ " <user-service>"
+ " <user name='bob' password='$2a$05$dRmjl1T05J7rvCPD2NgsHesCEJHww3pdmesUhjM3PD4m/gaEYyx/G' authorities='ROLE_A' />"
+ " </user-service>" + " </authentication-provider>");
+ " </user-service>"
// @formatter:on
+ " </authentication-provider>");
getProvider().authenticate(this.bob);
}
@Test
public void providerWithMd5PasswordEncoderWorks() {
this.appContext = new InMemoryXmlApplicationContext(" <authentication-manager>" + " <authentication-provider>"
+ " <password-encoder ref='passwordEncoder'/>" + " <user-service>"
// @formatter:off
this.appContext = new InMemoryXmlApplicationContext(" <authentication-manager>"
+ " <authentication-provider>"
+ " <password-encoder ref='passwordEncoder'/>"
+ " <user-service>"
+ " <user name='bob' password='12b141f35d58b8b3a46eea65e6ac179e' authorities='ROLE_A' />"
+ " </user-service>" + " </authentication-provider>" + " </authentication-manager>"
+ " </user-service>"
+ " </authentication-provider>"
+ " </authentication-manager>"
+ " <b:bean id='passwordEncoder' class='" + MessageDigestPasswordEncoder.class.getName() + "'>"
+ " <b:constructor-arg value='MD5'/>" + " </b:bean>");
+ " <b:constructor-arg value='MD5'/>"
+ " </b:bean>");
// @formatter:on
getProvider().authenticate(this.bob);
}
@Test
public void providerWithShaPasswordEncoderWorks() {
this.appContext = new InMemoryXmlApplicationContext(" <authentication-manager>" + " <authentication-provider>"
+ " <password-encoder ref='passwordEncoder'/>" + " <user-service>"
// @formatter:off
this.appContext = new InMemoryXmlApplicationContext(" <authentication-manager>"
+ " <authentication-provider>"
+ " <password-encoder ref='passwordEncoder'/>"
+ " <user-service>"
+ " <user name='bob' password='{SSHA}PpuEwfdj7M1rs0C2W4ssSM2XEN/Y6S5U' authorities='ROLE_A' />"
+ " </user-service>" + " </authentication-provider>" + " </authentication-manager>"
+ " </user-service>"
+ " </authentication-provider>"
+ " </authentication-manager>"
+ " <b:bean id='passwordEncoder' class='" + LdapShaPasswordEncoder.class.getName() + "'/>");
// @formatter:on
getProvider().authenticate(this.bob);
}
@Test
public void passwordIsBase64EncodedWhenBase64IsEnabled() {
this.appContext = new InMemoryXmlApplicationContext(" <authentication-manager>" + " <authentication-provider>"
+ " <password-encoder ref='passwordEncoder'/>" + " <user-service>"
// @formatter:off
this.appContext = new InMemoryXmlApplicationContext(" <authentication-manager>"
+ " <authentication-provider>"
+ " <password-encoder ref='passwordEncoder'/>"
+ " <user-service>"
+ " <user name='bob' password='ErFB811YuLOkbupl5qwXng==' authorities='ROLE_A' />"
+ " </user-service>" + " </authentication-provider>" + " </authentication-manager>"
+ " </user-service>"
+ " </authentication-provider>"
+ " </authentication-manager>"
+ " <b:bean id='passwordEncoder' class='" + MessageDigestPasswordEncoder.class.getName() + "'>"
+ " <b:constructor-arg value='MD5'/>" + " <b:property name='encodeHashAsBase64' value='true'/>"
+ " </b:bean>");
// @formatter:on
getProvider().authenticate(this.bob);
}
// SEC-1466
@Test(expected = BeanDefinitionParsingException.class)
public void exernalProviderDoesNotSupportChildElements() {
// @formatter:off
this.appContext = new InMemoryXmlApplicationContext(" <authentication-manager>"
+ " <authentication-provider ref='aProvider'> "
+ " <password-encoder ref='customPasswordEncoder'/>" + " </authentication-provider>"
+ " <password-encoder ref='customPasswordEncoder'/>"
+ " </authentication-provider>"
+ " </authentication-manager>"
+ " <b:bean id='aProvider' class='org.springframework.security.authentication.TestingAuthenticationProvider'/>"
+ " <b:bean id='customPasswordEncoder' "
+ " class='org.springframework.security.authentication.encoding.Md5PasswordEncoder'/>");
// @formatter:on
}
private AuthenticationProvider getProvider() {

View File

@ -44,10 +44,14 @@ public class JdbcUserServiceBeanDefinitionParserTests {
private static String USER_CACHE_XML = "<b:bean id='userCache' class='org.springframework.security.authentication.dao.MockUserCache'/>";
// @formatter:off
private static String DATA_SOURCE = " <b:bean id='populator' class='org.springframework.security.config.DataSourcePopulator'>"
+ " <b:property name='dataSource' ref='dataSource'/>" + " </b:bean>"
+ " <b:property name='dataSource' ref='dataSource'/>"
+ " </b:bean>"
+ " <b:bean id='dataSource' class='org.springframework.security.TestDataSource'>"
+ " <b:constructor-arg value='jdbcnamespaces'/>" + " </b:bean>";
+ " <b:constructor-arg value='jdbcnamespaces'/>"
+ " </b:bean>";
// @formatter:on
private InMemoryXmlApplicationContext appContext;
@ -81,9 +85,13 @@ public class JdbcUserServiceBeanDefinitionParserTests {
public void usernameAndAuthorityQueriesAreParsedCorrectly() throws Exception {
String userQuery = "select username, password, true from users where username = ?";
String authoritiesQuery = "select username, authority from authorities where username = ? and 1 = 1";
setContext("<jdbc-user-service id='myUserService' " + "data-source-ref='dataSource' "
+ "users-by-username-query='" + userQuery + "' " + "authorities-by-username-query='" + authoritiesQuery
// @formatter:off
setContext("<jdbc-user-service id='myUserService' "
+ "data-source-ref='dataSource' "
+ "users-by-username-query='" + userQuery + "' "
+ "authorities-by-username-query='" + authoritiesQuery
+ "'/>" + DATA_SOURCE);
// @formatter:on
JdbcUserDetailsManager mgr = (JdbcUserDetailsManager) this.appContext.getBean("myUserService");
assertThat(FieldUtils.getFieldValue(mgr, "usersByUsernameQuery")).isEqualTo(userQuery);
assertThat(FieldUtils.getFieldValue(mgr, "authoritiesByUsernameQuery")).isEqualTo(authoritiesQuery);
@ -112,18 +120,29 @@ public class JdbcUserServiceBeanDefinitionParserTests {
@Test
public void isSupportedByAuthenticationProviderElement() {
setContext("<authentication-manager>" + " <authentication-provider>"
+ " <jdbc-user-service data-source-ref='dataSource'/>" + " </authentication-provider>"
+ "</authentication-manager>" + DATA_SOURCE);
// @formatter:off
setContext("<authentication-manager>"
+ " <authentication-provider>"
+ " <jdbc-user-service data-source-ref='dataSource'/>"
+ " </authentication-provider>"
+ "</authentication-manager>"
+ DATA_SOURCE);
// @formatter:on
AuthenticationManager mgr = (AuthenticationManager) this.appContext.getBean(BeanIds.AUTHENTICATION_MANAGER);
mgr.authenticate(new UsernamePasswordAuthenticationToken("rod", "koala"));
}
@Test
public void cacheIsInjectedIntoAuthenticationProvider() {
setContext("<authentication-manager>" + " <authentication-provider>"
// @formatter:off
setContext("<authentication-manager>"
+ " <authentication-provider>"
+ " <jdbc-user-service cache-ref='userCache' data-source-ref='dataSource'/>"
+ " </authentication-provider>" + "</authentication-manager>" + DATA_SOURCE + USER_CACHE_XML);
+ " </authentication-provider>"
+ "</authentication-manager>"
+ DATA_SOURCE
+ USER_CACHE_XML);
// @formatter:on
ProviderManager mgr = (ProviderManager) this.appContext.getBean(BeanIds.AUTHENTICATION_MANAGER);
DaoAuthenticationProvider provider = (DaoAuthenticationProvider) mgr.getProviders().get(0);
assertThat(this.appContext.getBean("userCache")).isSameAs(provider.getUserCache());

View File

@ -44,7 +44,10 @@ public class PasswordEncoderParserTests {
this.spring.configLocations(
"classpath:org/springframework/security/config/authentication/PasswordEncoderParserTests-default.xml")
.mockMvcAfterSpringSecurityOk().autowire();
this.mockMvc.perform(get("/").with(httpBasic("user", "password"))).andExpect(status().isOk());
// @formatter:off
this.mockMvc.perform(get("/").with(httpBasic("user", "password")))
.andExpect(status().isOk());
// @formatter:on
}
@Test
@ -52,7 +55,10 @@ public class PasswordEncoderParserTests {
this.spring.configLocations(
"classpath:org/springframework/security/config/authentication/PasswordEncoderParserTests-bean.xml")
.mockMvcAfterSpringSecurityOk().autowire();
this.mockMvc.perform(get("/").with(httpBasic("user", "password"))).andExpect(status().isOk());
// @formatter:off
this.mockMvc.perform(get("/").with(httpBasic("user", "password")))
.andExpect(status().isOk());
// @formatter:on
}
}

View File

@ -52,8 +52,11 @@ public class UserServiceBeanDefinitionParserTests {
@Test
public void userServiceWithEmbeddedUsersWorksSuccessfully() {
setContext("<user-service id='service'>" + " <user name='joe' password='joespassword' authorities='ROLE_A'/>"
// @formatter:off
setContext("<user-service id='service'>"
+ " <user name='joe' password='joespassword' authorities='ROLE_A'/>"
+ "</user-service>");
// @formatter:on
UserDetailsService userService = (UserDetailsService) this.appContext.getBean("service");
userService.loadUserByUsername("joe");
}
@ -63,10 +66,12 @@ public class UserServiceBeanDefinitionParserTests {
System.setProperty("principal.name", "joe");
System.setProperty("principal.pass", "joespassword");
System.setProperty("principal.authorities", "ROLE_A,ROLE_B");
// @formatter:off
setContext("<b:bean class='org.springframework.beans.factory.config.PropertyPlaceholderConfigurer'/>"
+ "<user-service id='service'>"
+ " <user name='${principal.name}' password='${principal.pass}' authorities='${principal.authorities}'/>"
+ "</user-service>");
// @formatter:on
UserDetailsService userService = (UserDetailsService) this.appContext.getBean("service");
UserDetails joe = userService.loadUserByUsername("joe");
assertThat(joe.getPassword()).isEqualTo("joespassword");
@ -75,7 +80,11 @@ public class UserServiceBeanDefinitionParserTests {
@Test
public void embeddedUsersWithNoPasswordIsGivenGeneratedValue() {
setContext("<user-service id='service'>" + " <user name='joe' authorities='ROLE_A'/>" + "</user-service>");
// @formatter:off
setContext("<user-service id='service'>"
+ " <user name='joe' authorities='ROLE_A'/>"
+ "</user-service>");
// @formatter:on
UserDetailsService userService = (UserDetailsService) this.appContext.getBean("service");
UserDetails joe = userService.loadUserByUsername("joe");
assertThat(joe.getPassword().length() > 0).isTrue();
@ -84,9 +93,12 @@ public class UserServiceBeanDefinitionParserTests {
@Test
public void worksWithOpenIDUrlsAsNames() {
setContext("<user-service id='service'>" + " <user name='https://joe.myopenid.com/' authorities='ROLE_A'/>"
// @formatter:off
setContext("<user-service id='service'>"
+ " <user name='https://joe.myopenid.com/' authorities='ROLE_A'/>"
+ " <user name='https://www.google.com/accounts/o8/id?id=MPtOaenBIk5yzW9n7n9' authorities='ROLE_A'/>"
+ "</user-service>");
// @formatter:on
UserDetailsService userService = (UserDetailsService) this.appContext.getBean("service");
assertThat(userService.loadUserByUsername("https://joe.myopenid.com/").getUsername())
.isEqualTo("https://joe.myopenid.com/");
@ -96,10 +108,12 @@ public class UserServiceBeanDefinitionParserTests {
@Test
public void disabledAndEmbeddedFlagsAreSupported() {
// @formatter:off
setContext("<user-service id='service'>"
+ " <user name='joe' password='joespassword' authorities='ROLE_A' locked='true'/>"
+ " <user name='Bob' password='bobspassword' authorities='ROLE_A' disabled='true'/>"
+ "</user-service>");
// @formatter:on
UserDetailsService userService = (UserDetailsService) this.appContext.getBean("service");
UserDetails joe = userService.loadUserByUsername("joe");
assertThat(joe.isAccountNonLocked()).isFalse();
@ -110,8 +124,11 @@ public class UserServiceBeanDefinitionParserTests {
@Test(expected = FatalBeanException.class)
public void userWithBothPropertiesAndEmbeddedUsersThrowsException() {
// @formatter:off
setContext("<user-service id='service' properties='doesntmatter.props'>"
+ " <user name='joe' password='joespassword' authorities='ROLE_A'/>" + "</user-service>");
+ " <user name='joe' password='joespassword' authorities='ROLE_A'/>"
+ "</user-service>");
// @formatter:on
UserDetailsService userService = (UserDetailsService) this.appContext.getBean("service");
userService.loadUserByUsername("Joe");
}

View File

@ -46,15 +46,21 @@ public class UserDetailsResourceFactoryBeanTests {
@Test
public void setResourceLoaderWhenNullThenThrowsException() {
assertThatIllegalArgumentException().isThrownBy(() -> this.factory.setResourceLoader(null))
// @formatter:off
assertThatIllegalArgumentException()
.isThrownBy(() -> this.factory.setResourceLoader(null))
.withStackTraceContaining("resourceLoader cannot be null");
// @formatter:on
}
@Test
public void getObjectWhenPropertiesResourceLocationNullThenThrowsIllegalStateException() {
this.factory.setResourceLoader(this.resourceLoader);
assertThatIllegalArgumentException().isThrownBy(() -> this.factory.getObject())
// @formatter:off
assertThatIllegalArgumentException()
.isThrownBy(() -> this.factory.getObject())
.withStackTraceContaining("resource cannot be null if resourceLocation is null");
// @formatter:on
}
@Test
@ -73,8 +79,12 @@ public class UserDetailsResourceFactoryBeanTests {
@Test
public void getObjectWhenInvalidUserThenThrowsMeaningfulException() {
this.factory.setResource(new InMemoryResource("user=invalidFormatHere"));
assertThatIllegalStateException().isThrownBy(() -> this.factory.getObject()).withStackTraceContaining("user")
// @formatter:off
assertThatIllegalStateException()
.isThrownBy(() -> this.factory.getObject())
.withStackTraceContaining("user")
.withStackTraceContaining("invalidFormatHere");
// @formatter:on
}
@Test

View File

@ -45,6 +45,7 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
*/
public class RsaKeyConversionServicePostProcessorTests {
// @formatter:off
private static final String PKCS8_PRIVATE_KEY = "-----BEGIN PRIVATE KEY-----\n"
+ "MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCMk7CKSTfu3QoV\n"
+ "HoPVXxwZO+qweztd36cVWYqGOZinrOR2crWFu50AgR2CsdIH0+cqo7F4Vx7/3O8i\n"
@ -70,8 +71,10 @@ public class RsaKeyConversionServicePostProcessorTests {
+ "OHjxffBM0hH+fySx8m53gFfr2BpaqDX5f6ZGBlly1SlsWZ4CchCVsc71nshipi7I\n"
+ "k8HL9F5/OpQdDNprJ5RMBNfkWE65Nrcsb1e6oPkCgYAxwgdiSOtNg8PjDVDmAhwT\n"
+ "Mxj0Dtwi2fAqQ76RVrrXpNp3uCOIAu4CfruIb5llcJ3uak0ZbnWri32AxSgk80y3\n"
+ "EWiRX/WEDu5znejF+5O3pI02atWWcnxifEKGGlxwkcMbQdA67MlrJLFaSnnGpNXo\n" + "yPfcul058SOqhafIZQMEKQ==\n"
+ "EWiRX/WEDu5znejF+5O3pI02atWWcnxifEKGGlxwkcMbQdA67MlrJLFaSnnGpNXo\n"
+ "yPfcul058SOqhafIZQMEKQ==\n"
+ "-----END PRIVATE KEY-----";
// @formatter:on
private static final String X509_PUBLIC_KEY_LOCATION = "classpath:org/springframework/security/config/annotation/web/configuration/simple.pub";

View File

@ -124,12 +124,19 @@ public class SpringSecurityXsdParser {
while (!"schema".equals(root.simpleName())) {
root = root.parent().get();
}
return expand(root).filter((node) -> name.equals(node.attribute("name"))).findFirst()
// @formatter:off
return expand(root)
.filter((node) -> name.equals(node.attribute("name")))
.findFirst()
.orElseThrow(IllegalArgumentException::new);
// @formatter:on
}
private Stream<XmlNode> expand(XmlNode root) {
return Stream.concat(Stream.of(root), root.children().flatMap(this::expand));
// @formatter:off
return Stream.concat(Stream.of(root), root.children()
.flatMap(this::expand));
// @formatter:on
}
/**

View File

@ -45,20 +45,33 @@ public class XmlNode {
public Stream<XmlNode> children() {
NodeList children = this.node.getChildNodes();
return IntStream.range(0, children.getLength()).mapToObj(children::item).map(XmlNode::new);
// @formatter:off
return IntStream.range(0, children.getLength())
.mapToObj(children::item)
.map(XmlNode::new);
// @formatter:on
}
public Optional<XmlNode> child(String name) {
return this.children().filter((child) -> name.equals(child.simpleName())).findFirst();
return this.children()
.filter((child) -> name.equals(child.simpleName()))
.findFirst();
}
public Optional<XmlNode> parent() {
return Optional.ofNullable(this.node.getParentNode()).map((parent) -> new XmlNode(parent));
// @formatter:off
return Optional.ofNullable(this.node.getParentNode())
.map((parent) -> new XmlNode(parent));
// @formatter:on
}
public String attribute(String name) {
return Optional.ofNullable(this.node.getAttributes()).map((attrs) -> attrs.getNamedItem(name))
.map((attr) -> attr.getTextContent()).orElse(null);
// @formatter:off
return Optional.ofNullable(this.node.getAttributes())
.map((attrs) -> attrs.getNamedItem(name))
.map((attr) -> attr.getTextContent())
.orElse(null);
// @formatter:on
}
public Node node() {

View File

@ -46,11 +46,20 @@ import static org.assertj.core.api.Assertions.assertThat;
*/
public class XsdDocumentedTests {
Collection<String> ignoredIds = Arrays.asList("nsa-any-user-service", "nsa-any-user-service-parents",
"nsa-authentication", "nsa-websocket-security", "nsa-ldap", "nsa-method-security", "nsa-web",
// @formatter:off
Collection<String> ignoredIds = Arrays.asList("nsa-any-user-service",
"nsa-any-user-service-parents",
"nsa-authentication",
"nsa-websocket-security",
"nsa-ldap",
"nsa-method-security",
"nsa-web",
// deprecated and for removal
"nsa-frame-options-strategy", "nsa-frame-options-ref", "nsa-frame-options-value",
"nsa-frame-options-strategy",
"nsa-frame-options-ref",
"nsa-frame-options-value",
"nsa-frame-options-from-parameter");
// @formatter:on
String referenceLocation = "../docs/manual/src/docs/asciidoc/_includes/servlet/appendix/namespace.adoc";
@ -68,28 +77,61 @@ public class XsdDocumentedTests {
@Test
public void parseWhenLatestXsdThenAllNamedSecurityFiltersAreDefinedAndOrderedProperly() throws IOException {
XmlNode root = this.xml.parse(this.schemaDocumentLocation);
List<String> nodes = root.child("schema").map(XmlNode::children).orElse(Stream.empty())
// @formatter:off
List<String> nodes = root.child("schema")
.map(XmlNode::children)
.orElse(Stream.empty())
.filter((node) -> "simpleType".equals(node.simpleName())
&& "named-security-filter".equals(node.attribute("name")))
.flatMap(XmlNode::children).flatMap(XmlNode::children).map((node) -> node.attribute("value"))
.filter(StringUtils::isNotEmpty).collect(Collectors.toList());
.flatMap(XmlNode::children)
.flatMap(XmlNode::children)
.map((node) -> node.attribute("value"))
.filter(StringUtils::isNotEmpty)
.collect(Collectors.toList());
// @formatter:on
SecurityFiltersAssertions.assertEquals(nodes);
}
@Test
public void parseWhen31XsdThenAllNamedSecurityFiltersAreDefinedAndOrderedProperly() throws IOException {
List<String> expected = Arrays.asList("FIRST", "CHANNEL_FILTER", "SECURITY_CONTEXT_FILTER",
"CONCURRENT_SESSION_FILTER", "LOGOUT_FILTER", "X509_FILTER", "PRE_AUTH_FILTER", "CAS_FILTER",
"FORM_LOGIN_FILTER", "OPENID_FILTER", "LOGIN_PAGE_FILTER", "DIGEST_AUTH_FILTER", "BASIC_AUTH_FILTER",
"REQUEST_CACHE_FILTER", "SERVLET_API_SUPPORT_FILTER", "JAAS_API_SUPPORT_FILTER", "REMEMBER_ME_FILTER",
"ANONYMOUS_FILTER", "SESSION_MANAGEMENT_FILTER", "EXCEPTION_TRANSLATION_FILTER",
"FILTER_SECURITY_INTERCEPTOR", "SWITCH_USER_FILTER", "LAST");
// @formatter:off
List<String> expected = Arrays.asList("FIRST",
"CHANNEL_FILTER",
"SECURITY_CONTEXT_FILTER",
"CONCURRENT_SESSION_FILTER",
"LOGOUT_FILTER",
"X509_FILTER",
"PRE_AUTH_FILTER",
"CAS_FILTER",
"FORM_LOGIN_FILTER",
"OPENID_FILTER",
"LOGIN_PAGE_FILTER",
"DIGEST_AUTH_FILTER",
"BASIC_AUTH_FILTER",
"REQUEST_CACHE_FILTER",
"SERVLET_API_SUPPORT_FILTER",
"JAAS_API_SUPPORT_FILTER",
"REMEMBER_ME_FILTER",
"ANONYMOUS_FILTER",
"SESSION_MANAGEMENT_FILTER",
"EXCEPTION_TRANSLATION_FILTER",
"FILTER_SECURITY_INTERCEPTOR",
"SWITCH_USER_FILTER",
"LAST");
// @formatter:on
XmlNode root = this.xml.parse(this.schema31xDocumentLocation);
List<String> nodes = root.child("schema").map(XmlNode::children).orElse(Stream.empty())
// @formatter:off
List<String> nodes = root.child("schema")
.map(XmlNode::children)
.orElse(Stream.empty())
.filter((node) -> "simpleType".equals(node.simpleName())
&& "named-security-filter".equals(node.attribute("name")))
.flatMap(XmlNode::children).flatMap(XmlNode::children).map((node) -> node.attribute("value"))
.filter(StringUtils::isNotEmpty).collect(Collectors.toList());
.flatMap(XmlNode::children)
.flatMap(XmlNode::children)
.map((node) -> node.attribute("value"))
.filter(StringUtils::isNotEmpty)
.collect(Collectors.toList());
// @formatter:on
assertThat(nodes).isEqualTo(expected);
}
@ -103,7 +145,11 @@ public class XsdDocumentedTests {
@Test
public void sizeWhenReadingFilesystemThenIsCorrectNumberOfSchemaFiles() throws IOException {
ClassPathResource resource = new ClassPathResource(this.schemaDocumentLocation);
String[] schemas = resource.getFile().getParentFile().list((dir, name) -> name.endsWith(".xsd"));
// @formatter:off
String[] schemas = resource.getFile()
.getParentFile()
.list((dir, name) -> name.endsWith(".xsd"));
// @formatter:on
assertThat(schemas.length).isEqualTo(16)
.withFailMessage("the count is equal to 16, if not then schemaDocument needs updating");
}
@ -117,11 +163,16 @@ public class XsdDocumentedTests {
@Test
public void countReferencesWhenReviewingDocumentationThenEntireSchemaIsIncluded() throws IOException {
Map<String, Element> elementsByElementName = this.xml.elementsByElementName(this.schemaDocumentLocation);
// @formatter:off
List<String> documentIds = Files.lines(Paths.get(this.referenceLocation))
.filter((line) -> line.matches("\\[\\[(nsa-.*)\\]\\]"))
.map((line) -> line.substring(2, line.length() - 2)).collect(Collectors.toList());
Set<String> expectedIds = elementsByElementName.values().stream()
.flatMap((element) -> element.getIds().stream()).collect(Collectors.toSet());
.map((line) -> line.substring(2, line.length() - 2))
.collect(Collectors.toList());
Set<String> expectedIds = elementsByElementName.values()
.stream()
.flatMap((element) -> element.getIds().stream())
.collect(Collectors.toSet());
// @formatter:on
documentIds.removeAll(this.ignoredIds);
expectedIds.removeAll(this.ignoredIds);
assertThat(documentIds).containsAll(expectedIds);
@ -172,15 +223,28 @@ public class XsdDocumentedTests {
if (this.ignoredIds.contains(key)) {
return;
}
List<String> parentIds = entry.getValue().getAllParentElmts().values().stream()
.filter((element) -> !this.ignoredIds.contains(element.getId())).map((element) -> element.getId())
.sorted().collect(Collectors.toList());
// @formatter:off
List<String> parentIds = entry.getValue()
.getAllParentElmts()
.values()
.stream()
.filter((element) -> !this.ignoredIds.contains(element.getId()))
.map((element) -> element.getId())
.sorted()
.collect(Collectors.toList());
// @formatter:on
if (!parentIds.isEmpty()) {
schemaAttrNameToParents.put(key, parentIds);
}
List<String> childIds = entry.getValue().getAllChildElmts().values().stream()
// @formatter:off
List<String> childIds = entry.getValue()
.getAllChildElmts()
.values()
.stream()
.filter((element) -> !this.ignoredIds.contains(element.getId())).map((element) -> element.getId())
.sorted().collect(Collectors.toList());
.sorted()
.collect(Collectors.toList());
// @formatter:on
if (!childIds.isEmpty()) {
schemaAttrNameToChildren.put(key, childIds);
}
@ -196,14 +260,23 @@ public class XsdDocumentedTests {
@Test
public void countWhenReviewingDocumentationThenAllElementsDocumented() throws IOException {
Map<String, Element> elementNameToElement = this.xml.elementsByElementName(this.schemaDocumentLocation);
String notDocElmtIds = elementNameToElement.values().stream()
// @formatter:off
String notDocElmtIds = elementNameToElement.values()
.stream()
.filter((element) -> StringUtils.isEmpty(element.getDesc())
&& !this.ignoredIds.contains(element.getId()))
.map((element) -> element.getId()).sorted().collect(Collectors.joining("\n"));
String notDocAttrIds = elementNameToElement.values().stream().flatMap((element) -> element.getAttrs().stream())
.map((element) -> element.getId())
.sorted()
.collect(Collectors.joining("\n"));
String notDocAttrIds = elementNameToElement.values()
.stream()
.flatMap((element) -> element.getAttrs().stream())
.filter((element) -> StringUtils.isEmpty(element.getDesc())
&& !this.ignoredIds.contains(element.getId()))
.map((element) -> element.getId()).sorted().collect(Collectors.joining("\n"));
.map((element) -> element.getId())
.sorted()
.collect(Collectors.joining("\n"));
// @formatter:on
assertThat(notDocElmtIds).isEmpty();
assertThat(notDocAttrIds).isEmpty();
}

View File

@ -48,6 +48,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.ResultMatcher;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@ -90,124 +91,190 @@ public class CsrfConfigTests {
@Test
public void postWhenDefaultConfigurationThenForbiddenSinceCsrfIsEnabled() throws Exception {
this.spring.configLocations(this.xml("AutoConfig")).autowire();
this.mvc.perform(post("/csrf")).andExpect(status().isForbidden()).andExpect(csrfCreated());
// @formatter:off
this.mvc.perform(post("/csrf"))
.andExpect(status().isForbidden())
.andExpect(csrfCreated());
// @formatter:on
}
@Test
public void putWhenDefaultConfigurationThenForbiddenSinceCsrfIsEnabled() throws Exception {
this.spring.configLocations(this.xml("AutoConfig")).autowire();
this.mvc.perform(put("/csrf")).andExpect(status().isForbidden()).andExpect(csrfCreated());
// @formatter:off
this.mvc.perform(put("/csrf"))
.andExpect(status().isForbidden())
.andExpect(csrfCreated());
// @formatter:on
}
@Test
public void patchWhenDefaultConfigurationThenForbiddenSinceCsrfIsEnabled() throws Exception {
this.spring.configLocations(this.xml("AutoConfig")).autowire();
this.mvc.perform(patch("/csrf")).andExpect(status().isForbidden()).andExpect(csrfCreated());
// @formatter:off
this.mvc.perform(patch("/csrf"))
.andExpect(status().isForbidden())
.andExpect(csrfCreated());
// @formatter:on
}
@Test
public void deleteWhenDefaultConfigurationThenForbiddenSinceCsrfIsEnabled() throws Exception {
this.spring.configLocations(this.xml("AutoConfig")).autowire();
this.mvc.perform(delete("/csrf")).andExpect(status().isForbidden()).andExpect(csrfCreated());
// @formatter:off
this.mvc.perform(delete("/csrf"))
.andExpect(status().isForbidden())
.andExpect(csrfCreated());
// @formatter:on
}
@Test
public void invalidWhenDefaultConfigurationThenForbiddenSinceCsrfIsEnabled() throws Exception {
this.spring.configLocations(this.xml("AutoConfig")).autowire();
this.mvc.perform(request("INVALID", new URI("/csrf"))).andExpect(status().isForbidden())
// @formatter:off
this.mvc.perform(request("INVALID", new URI("/csrf")))
.andExpect(status().isForbidden())
.andExpect(csrfCreated());
// @formatter:on
}
@Test
public void getWhenDefaultConfigurationThenCsrfIsEnabled() throws Exception {
this.spring.configLocations(this.xml("shared-controllers"), this.xml("AutoConfig")).autowire();
this.mvc.perform(get("/csrf")).andExpect(csrfInBody());
// @formatter:off
this.mvc.perform(get("/csrf"))
.andExpect(csrfInBody());
// @formatter:on
}
@Test
public void headWhenDefaultConfigurationThenCsrfIsEnabled() throws Exception {
this.spring.configLocations(this.xml("shared-controllers"), this.xml("AutoConfig")).autowire();
this.mvc.perform(head("/csrf-in-header")).andExpect(csrfInHeader());
// @formatter:off
this.mvc.perform(head("/csrf-in-header"))
.andExpect(csrfInHeader());
// @formatter:on
}
@Test
public void traceWhenDefaultConfigurationThenCsrfIsEnabled() throws Exception {
this.spring.configLocations(this.xml("shared-controllers"), this.xml("AutoConfig")).autowire();
MockMvc traceEnabled = MockMvcBuilders.webAppContextSetup(this.spring.getContext()).apply(springSecurity())
// @formatter:off
MockMvc traceEnabled = MockMvcBuilders.webAppContextSetup(this.spring.getContext())
.apply(springSecurity())
.addDispatcherServletCustomizer((dispatcherServlet) -> dispatcherServlet.setDispatchTraceRequest(true))
.build();
traceEnabled.perform(request(HttpMethod.TRACE, "/csrf-in-header")).andExpect(csrfInHeader());
traceEnabled.perform(request(HttpMethod.TRACE, "/csrf-in-header"))
.andExpect(csrfInHeader());
// @formatter:on
}
@Test
public void optionsWhenDefaultConfigurationThenCsrfIsEnabled() throws Exception {
this.spring.configLocations(this.xml("shared-controllers"), this.xml("AutoConfig")).autowire();
this.mvc.perform(options("/csrf-in-header")).andExpect(csrfInHeader());
// @formatter:off
this.mvc.perform(options("/csrf-in-header"))
.andExpect(csrfInHeader());
// @formatter:on
}
@Test
public void postWhenCsrfDisabledThenRequestAllowed() throws Exception {
this.spring.configLocations(this.xml("shared-controllers"), this.xml("CsrfDisabled")).autowire();
this.mvc.perform(post("/ok")).andExpect(status().isOk());
// @formatter:off
this.mvc.perform(post("/ok"))
.andExpect(status().isOk());
// @formatter:on
assertThat(getFilter(this.spring, CsrfFilter.class)).isNull();
}
@Test
public void postWhenCsrfElementEnabledThenForbidden() throws Exception {
this.spring.configLocations(this.xml("CsrfEnabled")).autowire();
this.mvc.perform(post("/csrf")).andExpect(status().isForbidden()).andExpect(csrfCreated());
// @formatter:off
this.mvc.perform(post("/csrf"))
.andExpect(status().isForbidden())
.andExpect(csrfCreated());
// @formatter:on
}
@Test
public void putWhenCsrfElementEnabledThenForbidden() throws Exception {
this.spring.configLocations(this.xml("CsrfEnabled")).autowire();
this.mvc.perform(put("/csrf")).andExpect(status().isForbidden()).andExpect(csrfCreated());
// @formatter:off
this.mvc.perform(put("/csrf"))
.andExpect(status().isForbidden())
.andExpect(csrfCreated());
// @formatter:on
}
@Test
public void patchWhenCsrfElementEnabledThenForbidden() throws Exception {
this.spring.configLocations(this.xml("CsrfEnabled")).autowire();
this.mvc.perform(patch("/csrf")).andExpect(status().isForbidden()).andExpect(csrfCreated());
// @formatter:off
this.mvc.perform(patch("/csrf"))
.andExpect(status().isForbidden())
.andExpect(csrfCreated());
// @formatter:on
}
@Test
public void deleteWhenCsrfElementEnabledThenForbidden() throws Exception {
this.spring.configLocations(this.xml("CsrfEnabled")).autowire();
this.mvc.perform(delete("/csrf")).andExpect(status().isForbidden()).andExpect(csrfCreated());
// @formatter:off
this.mvc.perform(delete("/csrf"))
.andExpect(status().isForbidden())
.andExpect(csrfCreated());
// @formatter:on
}
@Test
public void invalidWhenCsrfElementEnabledThenForbidden() throws Exception {
this.spring.configLocations(this.xml("CsrfEnabled")).autowire();
this.mvc.perform(request("INVALID", new URI("/csrf"))).andExpect(status().isForbidden())
// @formatter:off
this.mvc.perform(request("INVALID", new URI("/csrf")))
.andExpect(status().isForbidden())
.andExpect(csrfCreated());
// @formatter:on
}
@Test
public void getWhenCsrfElementEnabledThenOk() throws Exception {
this.spring.configLocations(this.xml("shared-controllers"), this.xml("CsrfEnabled")).autowire();
this.mvc.perform(get("/csrf")).andExpect(csrfInBody());
// @formatter:off
this.mvc.perform(get("/csrf"))
.andExpect(csrfInBody());
// @formatter:on
}
@Test
public void headWhenCsrfElementEnabledThenOk() throws Exception {
this.spring.configLocations(this.xml("shared-controllers"), this.xml("CsrfEnabled")).autowire();
this.mvc.perform(head("/csrf-in-header")).andExpect(csrfInHeader());
// @formatter:off
this.mvc.perform(head("/csrf-in-header"))
.andExpect(csrfInHeader());
// @formatter:on
}
@Test
public void traceWhenCsrfElementEnabledThenOk() throws Exception {
this.spring.configLocations(this.xml("shared-controllers"), this.xml("CsrfEnabled")).autowire();
MockMvc traceEnabled = MockMvcBuilders.webAppContextSetup(this.spring.getContext()).apply(springSecurity())
// @formatter:off
MockMvc traceEnabled = MockMvcBuilders.webAppContextSetup(this.spring.getContext())
.apply(springSecurity())
.addDispatcherServletCustomizer((dispatcherServlet) -> dispatcherServlet.setDispatchTraceRequest(true))
.build();
// @formatter:on
traceEnabled.perform(request(HttpMethod.TRACE, "/csrf-in-header")).andExpect(csrfInHeader());
}
@Test
public void optionsWhenCsrfElementEnabledThenOk() throws Exception {
this.spring.configLocations(this.xml("shared-controllers"), this.xml("CsrfEnabled")).autowire();
this.mvc.perform(options("/csrf-in-header")).andExpect(csrfInHeader());
// @formatter:off
this.mvc.perform(options("/csrf-in-header"))
.andExpect(csrfInHeader());
// @formatter:on
}
@Test
@ -220,7 +287,10 @@ public class CsrfConfigTests {
public void postWhenUsingCsrfAndCustomAccessDeniedHandlerThenTheHandlerIsAppropriatelyEngaged() throws Exception {
this.spring.configLocations(this.xml("WithAccessDeniedHandler"), this.xml("shared-access-denied-handler"))
.autowire();
this.mvc.perform(post("/ok")).andExpect(status().isIAmATeapot());
// @formatter:off
this.mvc.perform(post("/ok"))
.andExpect(status().isIAmATeapot());
// @formatter:on
}
@Test
@ -233,9 +303,15 @@ public class CsrfConfigTests {
MockHttpSession session = (MockHttpSession) result.getRequest().getSession();
// if the request cache is consulted, then it will redirect back to /some-url,
// which we don't want
this.mvc.perform(
post("/login").param("username", "user").param("password", "password").session(session).with(csrf()))
// @formatter:off
MockHttpServletRequestBuilder login = post("/login")
.param("username", "user")
.param("password", "password")
.session(session)
.with(csrf());
this.mvc.perform(login)
.andExpect(redirectedUrl("/"));
// @formatter:on
}
@Test
@ -248,9 +324,15 @@ public class CsrfConfigTests {
MockHttpSession session = (MockHttpSession) result.getRequest().getSession();
// if the request cache is consulted, then it will redirect back to /some-url,
// which we do want
this.mvc.perform(
post("/login").param("username", "user").param("password", "password").session(session).with(csrf()))
// @formatter:off
MockHttpServletRequestBuilder login = post("/login")
.param("username", "user")
.param("password", "password")
.session(session)
.with(csrf());
this.mvc.perform(login)
.andExpect(redirectedUrl("http://localhost/authenticated"));
// @formatter:on
}
/**
@ -260,10 +342,16 @@ public class CsrfConfigTests {
public void postWhenUsingCsrfAndCustomSessionManagementAndNoSessionThenStillRedirectsToInvalidSessionUrl()
throws Exception {
this.spring.configLocations(this.xml("WithSessionManagement")).autowire();
MvcResult result = this.mvc.perform(post("/ok").param("_csrf", "abc"))
.andExpect(redirectedUrl("/error/sessionError")).andReturn();
// @formatter:off
MockHttpServletRequestBuilder postToOk = post("/ok")
.param("_csrf", "abc");
MvcResult result = this.mvc.perform(postToOk)
.andExpect(redirectedUrl("/error/sessionError"))
.andReturn();
MockHttpSession session = (MockHttpSession) result.getRequest().getSession();
this.mvc.perform(post("/csrf").session(session)).andExpect(status().isForbidden());
this.mvc.perform(post("/csrf").session(session))
.andExpect(status().isForbidden());
// @formatter:on
}
@Test
@ -273,15 +361,24 @@ public class CsrfConfigTests {
context.autowire();
RequestMatcher matcher = context.getContext().getBean(RequestMatcher.class);
given(matcher.matches(any(HttpServletRequest.class))).willReturn(false);
this.mvc.perform(post("/ok")).andExpect(status().isOk());
// @formatter:off
this.mvc.perform(post("/ok"))
.andExpect(status().isOk());
// @formatter:on
given(matcher.matches(any(HttpServletRequest.class))).willReturn(true);
this.mvc.perform(get("/ok")).andExpect(status().isForbidden());
// @formatter:off
this.mvc.perform(get("/ok"))
.andExpect(status().isForbidden());
// @formatter:on
}
@Test
public void getWhenDefaultConfigurationThenSessionNotImmediatelyCreated() throws Exception {
this.spring.configLocations(this.xml("shared-controllers"), this.xml("AutoConfig")).autowire();
MvcResult result = this.mvc.perform(get("/ok")).andExpect(status().isOk()).andReturn();
// @formatter:off
MvcResult result = this.mvc.perform(get("/ok"))
.andExpect(status().isOk()).andReturn();
// @formatter:on
assertThat(result.getRequest().getSession(false)).isNull();
}
@ -291,7 +388,13 @@ public class CsrfConfigTests {
this.spring.configLocations(this.xml("shared-controllers"), this.xml("AutoConfig")).autowire();
MvcResult result = this.mvc.perform(get("/ok")).andReturn();
MockHttpSession session = (MockHttpSession) result.getRequest().getSession();
this.mvc.perform(post("/ok").session(session).with(csrf().useInvalidToken())).andExpect(status().isForbidden());
// @formatter:off
MockHttpServletRequestBuilder postOk = post("/ok")
.session(session)
.with(csrf().useInvalidToken());
this.mvc.perform(postOk)
.andExpect(status().isForbidden());
// @formatter:on
}
@Test
@ -299,10 +402,17 @@ public class CsrfConfigTests {
this.spring.configLocations(this.xml("shared-controllers"), this.xml("AutoConfig")).autowire();
MvcResult result = this.mvc.perform(get("/csrf")).andReturn();
MockHttpSession session = (MockHttpSession) result.getRequest().getSession();
this.mvc.perform(
post("/login").param("username", "user").param("password", "password").session(session).with(csrf()))
// @formatter:off
MockHttpServletRequestBuilder loginRequest = post("/login")
.param("username", "user")
.param("password", "password")
.session(session)
.with(csrf());
this.mvc.perform(loginRequest)
.andExpect(status().isFound());
this.mvc.perform(get("/csrf").session(session)).andExpect(csrfChanged(result));
this.mvc.perform(get("/csrf").session(session))
.andExpect(csrfChanged(result));
// @formatter:on
}
@Test
@ -310,8 +420,12 @@ public class CsrfConfigTests {
this.spring.configLocations(this.xml("shared-controllers"), this.xml("AutoConfig")).autowire();
MvcResult result = this.mvc.perform(get("/csrf")).andReturn();
MockHttpSession session = (MockHttpSession) result.getRequest().getSession();
this.mvc.perform(post("/logout").session(session).with(csrf())).andExpect(status().isFound());
this.mvc.perform(get("/csrf").session(session)).andExpect(csrfChanged(result));
// @formatter:off
this.mvc.perform(post("/logout").session(session).with(csrf()))
.andExpect(status().isFound());
this.mvc.perform(get("/csrf").session(session))
.andExpect(csrfChanged(result));
// @formatter:on
}
/**
@ -321,13 +435,16 @@ public class CsrfConfigTests {
@WithMockUser
public void logoutWhenDefaultConfigurationThenDisabled() throws Exception {
this.spring.configLocations(this.xml("shared-controllers"), this.xml("CsrfEnabled")).autowire();
this.mvc.perform(get("/logout")).andExpect(status().isOk()); // renders form to
// log out but
// does not
// perform a
// redirect
// renders form to log out but does not perform a redirect
// @formatter:off
this.mvc.perform(get("/logout"))
.andExpect(status().isOk());
// @formatter:on
// still logged in
this.mvc.perform(get("/authenticated")).andExpect(status().isOk());
// @formatter:off
this.mvc.perform(get("/authenticated"))
.andExpect(status().isOk());
// @formatter:on
}
private <T extends Filter> T getFilter(SpringTestContext context, Class<T> type) {

View File

@ -60,8 +60,11 @@ public class FilterSecurityMetadataSourceBeanDefinitionParserTests {
@Test
public void parsingMinimalConfigurationIsSuccessful() {
// @formatter:off
setContext("<filter-security-metadata-source id='fids' use-expressions='false'>"
+ " <intercept-url pattern='/**' access='ROLE_A'/>" + "</filter-security-metadata-source>");
+ " <intercept-url pattern='/**' access='ROLE_A'/>"
+ "</filter-security-metadata-source>");
// @formatter:on
DefaultFilterInvocationSecurityMetadataSource fids = (DefaultFilterInvocationSecurityMetadataSource) this.appContext
.getBean("fids");
Collection<ConfigAttribute> cad = fids.getAttributes(createFilterInvocation("/anything", "GET"));
@ -70,9 +73,11 @@ public class FilterSecurityMetadataSourceBeanDefinitionParserTests {
@Test
public void expressionsAreSupported() {
// @formatter:off
setContext("<filter-security-metadata-source id='fids'>"
+ " <intercept-url pattern='/**' access=\"hasRole('ROLE_A')\" />"
+ "</filter-security-metadata-source>");
// @formatter:on
ExpressionBasedFilterInvocationSecurityMetadataSource fids = (ExpressionBasedFilterInvocationSecurityMetadataSource) this.appContext
.getBean("fids");
ConfigAttribute[] cad = fids.getAttributes(createFilterInvocation("/anything", "GET"))
@ -98,6 +103,7 @@ public class FilterSecurityMetadataSourceBeanDefinitionParserTests {
@Test
public void parsingWithinFilterSecurityInterceptorIsSuccessful() {
// @formatter:off
setContext("<http auto-config='true' use-expressions='false'/>"
+ "<b:bean id='fsi' class='org.springframework.security.web.access.intercept.FilterSecurityInterceptor' autowire='byType'>"
+ " <b:property name='securityMetadataSource'>"
@ -105,9 +111,12 @@ public class FilterSecurityMetadataSourceBeanDefinitionParserTests {
+ " <intercept-url pattern='/secure/extreme/**' access='ROLE_SUPERVISOR'/>"
+ " <intercept-url pattern='/secure/**' access='ROLE_USER'/>"
+ " <intercept-url pattern='/**' access='ROLE_USER'/>"
+ " </filter-security-metadata-source>" + " </b:property>"
+ " </filter-security-metadata-source>"
+ " </b:property>"
+ " <b:property name='authenticationManager' ref='" + BeanIds.AUTHENTICATION_MANAGER + "'/>"
+ "</b:bean>" + ConfigTestUtils.AUTH_PROVIDER_XML);
+ "</b:bean>"
+ ConfigTestUtils.AUTH_PROVIDER_XML);
// @formatter:on
}
@Test(expected = BeanDefinitionParsingException.class)

View File

@ -23,6 +23,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.config.test.SpringTestRule;
import org.springframework.security.web.WebAttributes;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.not;
@ -51,24 +52,35 @@ public class FormLoginBeanDefinitionParserTests {
@Test
public void getLoginWhenAutoConfigThenShowsDefaultLoginPage() throws Exception {
this.spring.configLocations(this.xml("Simple")).autowire();
String expectedContent = "<!DOCTYPE html>\n" + "<html lang=\"en\">\n" + " <head>\n"
// @formatter:off
String expectedContent = "<!DOCTYPE html>\n"
+ "<html lang=\"en\">\n"
+ " <head>\n"
+ " <meta charset=\"utf-8\">\n"
+ " <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\n"
+ " <meta name=\"description\" content=\"\">\n" + " <meta name=\"author\" content=\"\">\n"
+ " <meta name=\"description\" content=\"\">\n"
+ " <meta name=\"author\" content=\"\">\n"
+ " <title>Please sign in</title>\n"
+ " <link href=\"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css\" rel=\"stylesheet\" integrity=\"sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M\" crossorigin=\"anonymous\">\n"
+ " <link href=\"https://getbootstrap.com/docs/4.0/examples/signin/signin.css\" rel=\"stylesheet\" crossorigin=\"anonymous\"/>\n"
+ " </head>\n" + " <body>\n" + " <div class=\"container\">\n"
+ " </head>\n"
+ " <body>\n"
+ " <div class=\"container\">\n"
+ " <form class=\"form-signin\" method=\"post\" action=\"/login\">\n"
+ " <h2 class=\"form-signin-heading\">Please sign in</h2>\n" + " <p>\n"
+ " <h2 class=\"form-signin-heading\">Please sign in</h2>\n"
+ " <p>\n"
+ " <label for=\"username\" class=\"sr-only\">Username</label>\n"
+ " <input type=\"text\" id=\"username\" name=\"username\" class=\"form-control\" placeholder=\"Username\" required autofocus>\n"
+ " </p>\n" + " <p>\n"
+ " </p>\n"
+ " <p>\n"
+ " <label for=\"password\" class=\"sr-only\">Password</label>\n"
+ " <input type=\"password\" id=\"password\" name=\"password\" class=\"form-control\" placeholder=\"Password\" required>\n"
+ " </p>\n"
+ " <button class=\"btn btn-lg btn-primary btn-block\" type=\"submit\">Sign in</button>\n"
+ " </form>\n" + "</div>\n" + "</body></html>";
+ " </form>\n"
+ "</div>\n"
+ "</body></html>";
// @formatter:on
this.mvc.perform(get("/login")).andExpect(content().string(expectedContent));
}
@ -81,75 +93,108 @@ public class FormLoginBeanDefinitionParserTests {
@Test
public void getLoginWhenConfiguredWithCustomAttributesThenLoginPageReflects() throws Exception {
this.spring.configLocations(this.xml("WithCustomAttributes")).autowire();
String expectedContent = "<!DOCTYPE html>\n" + "<html lang=\"en\">\n" + " <head>\n"
// @formatter:off
String expectedContent = "<!DOCTYPE html>\n"
+ "<html lang=\"en\">\n"
+ " <head>\n"
+ " <meta charset=\"utf-8\">\n"
+ " <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\n"
+ " <meta name=\"description\" content=\"\">\n" + " <meta name=\"author\" content=\"\">\n"
+ " <meta name=\"description\" content=\"\">\n"
+ " <meta name=\"author\" content=\"\">\n"
+ " <title>Please sign in</title>\n"
+ " <link href=\"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css\" rel=\"stylesheet\" integrity=\"sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M\" crossorigin=\"anonymous\">\n"
+ " <link href=\"https://getbootstrap.com/docs/4.0/examples/signin/signin.css\" rel=\"stylesheet\" crossorigin=\"anonymous\"/>\n"
+ " </head>\n" + " <body>\n" + " <div class=\"container\">\n"
+ " </head>\n"
+ " <body>\n"
+ " <div class=\"container\">\n"
+ " <form class=\"form-signin\" method=\"post\" action=\"/signin\">\n"
+ " <h2 class=\"form-signin-heading\">Please sign in</h2>\n" + " <p>\n"
+ " <h2 class=\"form-signin-heading\">Please sign in</h2>\n"
+ " <p>\n"
+ " <label for=\"username\" class=\"sr-only\">Username</label>\n"
+ " <input type=\"text\" id=\"username\" name=\"custom_user\" class=\"form-control\" placeholder=\"Username\" required autofocus>\n"
+ " </p>\n" + " <p>\n"
+ " </p>\n"
+ " <p>\n"
+ " <label for=\"password\" class=\"sr-only\">Password</label>\n"
+ " <input type=\"password\" id=\"password\" name=\"custom_pass\" class=\"form-control\" placeholder=\"Password\" required>\n"
+ " </p>\n"
+ " <button class=\"btn btn-lg btn-primary btn-block\" type=\"submit\">Sign in</button>\n"
+ " </form>\n" + "</div>\n" + "</body></html>";
this.mvc.perform(get("/login")).andExpect(content().string(expectedContent));
this.mvc.perform(get("/logout")).andExpect(status().is3xxRedirection());
+ " </form>\n"
+ "</div>\n"
+ "</body></html>";
this.mvc.perform(get("/login"))
.andExpect(content().string(expectedContent));
this.mvc.perform(get("/logout"))
.andExpect(status().is3xxRedirection());
// @formatter:on
}
@Test
public void getLoginWhenConfiguredForOpenIdThenLoginPageReflects() throws Exception {
this.spring.configLocations(this.xml("WithOpenId")).autowire();
String expectedContent = "<!DOCTYPE html>\n" + "<html lang=\"en\">\n" + " <head>\n"
// @formatter:off
String expectedContent = "<!DOCTYPE html>\n"
+ "<html lang=\"en\">\n"
+ " <head>\n"
+ " <meta charset=\"utf-8\">\n"
+ " <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\n"
+ " <meta name=\"description\" content=\"\">\n" + " <meta name=\"author\" content=\"\">\n"
+ " <meta name=\"description\" content=\"\">\n"
+ " <meta name=\"author\" content=\"\">\n"
+ " <title>Please sign in</title>\n"
+ " <link href=\"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css\" rel=\"stylesheet\" integrity=\"sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M\" crossorigin=\"anonymous\">\n"
+ " <link href=\"https://getbootstrap.com/docs/4.0/examples/signin/signin.css\" rel=\"stylesheet\" crossorigin=\"anonymous\"/>\n"
+ " </head>\n" + " <body>\n" + " <div class=\"container\">\n"
+ " </head>\n"
+ " <body>\n"
+ " <div class=\"container\">\n"
+ " <form class=\"form-signin\" method=\"post\" action=\"/login\">\n"
+ " <h2 class=\"form-signin-heading\">Please sign in</h2>\n" + " <p>\n"
+ " <h2 class=\"form-signin-heading\">Please sign in</h2>\n"
+ " <p>\n"
+ " <label for=\"username\" class=\"sr-only\">Username</label>\n"
+ " <input type=\"text\" id=\"username\" name=\"username\" class=\"form-control\" placeholder=\"Username\" required autofocus>\n"
+ " </p>\n" + " <p>\n"
+ " </p>\n"
+ " <p>\n"
+ " <label for=\"password\" class=\"sr-only\">Password</label>\n"
+ " <input type=\"password\" id=\"password\" name=\"password\" class=\"form-control\" placeholder=\"Password\" required>\n"
+ " </p>\n"
+ " <button class=\"btn btn-lg btn-primary btn-block\" type=\"submit\">Sign in</button>\n"
+ " </form>\n"
+ " <form name=\"oidf\" class=\"form-signin\" method=\"post\" action=\"/login/openid\">\n"
+ " <h2 class=\"form-signin-heading\">Login with OpenID Identity</h2>\n" + " <p>\n"
+ " <h2 class=\"form-signin-heading\">Login with OpenID Identity</h2>\n"
+ " <p>\n"
+ " <label for=\"username\" class=\"sr-only\">Identity</label>\n"
+ " <input type=\"text\" id=\"username\" name=\"openid_identifier\" class=\"form-control\" placeholder=\"Username\" required autofocus>\n"
+ " </p>\n"
+ " <button class=\"btn btn-lg btn-primary btn-block\" type=\"submit\">Sign in</button>\n"
+ " </form>\n" + "</div>\n" + "</body></html>";
+ " </form>\n"
+ "</div>\n"
+ "</body></html>";
// @formatter:on
this.mvc.perform(get("/login")).andExpect(content().string(expectedContent));
}
@Test
public void getLoginWhenConfiguredForOpenIdWithCustomAttributesThenLoginPageReflects() throws Exception {
this.spring.configLocations(this.xml("WithOpenIdCustomAttributes")).autowire();
String expectedContent = "<!DOCTYPE html>\n" + "<html lang=\"en\">\n" + " <head>\n"
// @formatter:off
String expectedContent = "<!DOCTYPE html>\n"
+ "<html lang=\"en\">\n"
+ " <head>\n"
+ " <meta charset=\"utf-8\">\n"
+ " <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\n"
+ " <meta name=\"description\" content=\"\">\n" + " <meta name=\"author\" content=\"\">\n"
+ " <meta name=\"description\" content=\"\">\n"
+ " <meta name=\"author\" content=\"\">\n"
+ " <title>Please sign in</title>\n"
+ " <link href=\"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css\" rel=\"stylesheet\" integrity=\"sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M\" crossorigin=\"anonymous\">\n"
+ " <link href=\"https://getbootstrap.com/docs/4.0/examples/signin/signin.css\" rel=\"stylesheet\" crossorigin=\"anonymous\"/>\n"
+ " </head>\n" + " <body>\n" + " <div class=\"container\">\n"
+ " </head>\n"
+ " <body>\n"
+ " <div class=\"container\">\n"
+ " <form class=\"form-signin\" method=\"post\" action=\"/login\">\n"
+ " <h2 class=\"form-signin-heading\">Please sign in</h2>\n" + " <p>\n"
+ " <h2 class=\"form-signin-heading\">Please sign in</h2>\n"
+ " <p>\n"
+ " <label for=\"username\" class=\"sr-only\">Username</label>\n"
+ " <input type=\"text\" id=\"username\" name=\"username\" class=\"form-control\" placeholder=\"Username\" required autofocus>\n"
+ " </p>\n" + " <p>\n"
+ " </p>\n"
+ " <p>\n"
+ " <label for=\"password\" class=\"sr-only\">Password</label>\n"
+ " <input type=\"password\" id=\"password\" name=\"password\" class=\"form-control\" placeholder=\"Password\" required>\n"
+ " </p>\n"
@ -161,23 +206,38 @@ public class FormLoginBeanDefinitionParserTests {
+ " <input type=\"text\" id=\"username\" name=\"openid_identifier\" class=\"form-control\" placeholder=\"Username\" required autofocus>\n"
+ " </p>\n"
+ " <button class=\"btn btn-lg btn-primary btn-block\" type=\"submit\">Sign in</button>\n"
+ " </form>\n" + "</div>\n" + "</body></html>";
+ " </form>\n"
+ "</div>\n"
+ "</body></html>";
// @formatter:on
this.mvc.perform(get("/login")).andExpect(content().string(expectedContent));
}
@Test
public void failedLoginWhenConfiguredWithCustomAuthenticationFailureThenForwardsAccordingly() throws Exception {
this.spring.configLocations(this.xml("WithAuthenticationFailureForwardUrl")).autowire();
this.mvc.perform(post("/login").param("username", "bob").param("password", "invalidpassword"))
.andExpect(status().isOk()).andExpect(forwardedUrl("/failure_forward_url"))
// @formatter:off
MockHttpServletRequestBuilder loginRequest = post("/login")
.param("username", "bob")
.param("password", "invalidpassword");
this.mvc.perform(loginRequest)
.andExpect(status().isOk())
.andExpect(forwardedUrl("/failure_forward_url"))
.andExpect(request().attribute(WebAttributes.AUTHENTICATION_EXCEPTION, not(nullValue())));
// @formatter:on
}
@Test
public void successfulLoginWhenConfiguredWithCustomAuthenticationSuccessThenForwardsAccordingly() throws Exception {
this.spring.configLocations(this.xml("WithAuthenticationSuccessForwardUrl")).autowire();
this.mvc.perform(post("/login").param("username", "user").param("password", "password"))
.andExpect(status().isOk()).andExpect(forwardedUrl("/success_forward_url"));
// @formatter:off
MockHttpServletRequestBuilder loginRequest = post("/login")
.param("username", "user")
.param("password", "password");
this.mvc.perform(loginRequest)
.andExpect(status().isOk())
.andExpect(forwardedUrl("/success_forward_url"));
// @formatter:on
}
private String xml(String configName) {

View File

@ -38,6 +38,7 @@ import org.springframework.security.web.authentication.AuthenticationFailureHand
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@ -67,24 +68,44 @@ public class FormLoginConfigTests {
@Test
public void getProtectedPageWhenFormLoginConfiguredThenRedirectsToDefaultLoginPage() throws Exception {
this.spring.configLocations(this.xml("WithAntRequestMatcher")).autowire();
this.mvc.perform(get("/")).andExpect(redirectedUrl("http://localhost/login"));
// @formatter:off
this.mvc.perform(get("/"))
.andExpect(redirectedUrl("http://localhost/login"));
// @formatter:on
}
@Test
public void authenticateWhenDefaultTargetUrlConfiguredThenRedirectsAccordingly() throws Exception {
this.spring.configLocations(this.xml("WithDefaultTargetUrl")).autowire();
this.mvc.perform(post("/login").param("username", "user").param("password", "password").with(csrf()))
// @formatter:off
MockHttpServletRequestBuilder loginRequest = post("/login")
.param("username", "user")
.param("password", "password")
.with(csrf());
this.mvc.perform(loginRequest)
.andExpect(redirectedUrl("/default"));
// @formatter:on
}
@Test
public void authenticateWhenConfiguredWithSpelThenRedirectsAccordingly() throws Exception {
this.spring.configLocations(this.xml("UsingSpel")).autowire();
this.mvc.perform(post("/login").param("username", "user").param("password", "password").with(csrf()))
// @formatter:off
MockHttpServletRequestBuilder loginRequest = post("/login")
.param("username", "user")
.param("password", "password")
.with(csrf());
this.mvc.perform(loginRequest)
.andExpect(redirectedUrl(WebConfigUtilsTests.URL + "/default"));
this.mvc.perform(post("/login").param("username", "user").param("password", "wrong").with(csrf()))
MockHttpServletRequestBuilder invalidPassword = post("/login")
.param("username", "user")
.param("password", "wrong")
.with(csrf());
this.mvc.perform(invalidPassword)
.andExpect(redirectedUrl(WebConfigUtilsTests.URL + "/failure"));
this.mvc.perform(get("/")).andExpect(redirectedUrl("http://localhost" + WebConfigUtilsTests.URL + "/login"));
this.mvc.perform(get("/"))
.andExpect(redirectedUrl("http://localhost" + WebConfigUtilsTests.URL + "/login"));
// @formatter:on
}
@Test
@ -102,10 +123,20 @@ public class FormLoginConfigTests {
@Test
public void authenticateWhenCustomHandlerBeansConfiguredThenInvokesAccordingly() throws Exception {
this.spring.configLocations(this.xml("WithSuccessAndFailureHandlers")).autowire();
this.mvc.perform(post("/login").param("username", "user").param("password", "password").with(csrf()))
// @formatter:off
MockHttpServletRequestBuilder loginRequest = post("/login")
.param("username", "user")
.param("password", "password")
.with(csrf());
this.mvc.perform(loginRequest)
.andExpect(status().isIAmATeapot());
this.mvc.perform(post("/login").param("username", "user").param("password", "wrong").with(csrf()))
MockHttpServletRequestBuilder invalidPassword = post("/login")
.param("username", "user")
.param("password", "wrong")
.with(csrf());
this.mvc.perform(invalidPassword)
.andExpect(status().isIAmATeapot());
// @formatter:on
}
@Test
@ -129,15 +160,25 @@ public class FormLoginConfigTests {
@Test
public void authenticateWhenCsrfIsEnabledThenRequiresToken() throws Exception {
this.spring.configLocations(this.xml("WithCsrfEnabled")).autowire();
this.mvc.perform(post("/login").param("username", "user").param("password", "password"))
// @formatter:off
MockHttpServletRequestBuilder loginRequest = post("/login")
.param("username", "user")
.param("password", "password");
this.mvc.perform(loginRequest)
.andExpect(status().isForbidden());
// @formatter:on
}
@Test
public void authenticateWhenCsrfIsDisabledThenDoesNotRequireToken() throws Exception {
this.spring.configLocations(this.xml("WithCsrfDisabled")).autowire();
this.mvc.perform(post("/login").param("username", "user").param("password", "password"))
// @formatter:off
MockHttpServletRequestBuilder loginRequest = post("/login")
.param("username", "user")
.param("password", "password");
this.mvc.perform(loginRequest)
.andExpect(status().isFound());
// @formatter:on
}
/**
@ -148,8 +189,14 @@ public class FormLoginConfigTests {
public void authenticateWhenLoginPageIsSlashLoginAndAuthenticationFailsThenRedirectContainsErrorParameter()
throws Exception {
this.spring.configLocations(this.xml("ForSec3147")).autowire();
this.mvc.perform(post("/login").param("username", "user").param("password", "wrong").with(csrf()))
// @formatter:off
MockHttpServletRequestBuilder loginRequest = post("/login")
.param("username", "user")
.param("password", "wrong")
.with(csrf());
this.mvc.perform(loginRequest)
.andExpect(redirectedUrl("/login?error"));
// @formatter:on
}
private Filter getFilter(ApplicationContext context, Class<? extends Filter> filterClass) {

View File

@ -52,7 +52,11 @@ public class HttpConfigTests {
@Test
public void getWhenUsingMinimalConfigurationThenRedirectsToLogin() throws Exception {
this.spring.configLocations(this.xml("Minimal")).autowire();
this.mvc.perform(get("/")).andExpect(status().isFound()).andExpect(redirectedUrl("http://localhost/login"));
// @formatter:off
this.mvc.perform(get("/"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("http://localhost/login"));
// @formatter:on
}
@Test

View File

@ -68,28 +68,40 @@ public class HttpCorsConfigTests {
@Test
public void getWhenUsingCorsThenDoesSpringSecurityCorsHandshake() throws Exception {
this.spring.configLocations(this.xml("WithCors")).autowire();
this.mvc.perform(get("/").with(this.approved())).andExpect(corsResponseHeaders())
// @formatter:off
this.mvc.perform(get("/").with(this.approved()))
.andExpect(corsResponseHeaders())
.andExpect((status().isIAmATeapot()));
this.mvc.perform(options("/").with(this.preflight())).andExpect(corsResponseHeaders())
this.mvc.perform(options("/").with(this.preflight()))
.andExpect(corsResponseHeaders())
.andExpect(status().isOk());
// @formatter:on
}
@Test
public void getWhenUsingCustomCorsConfigurationSourceThenDoesSpringSecurityCorsHandshake() throws Exception {
this.spring.configLocations(this.xml("WithCorsConfigurationSource")).autowire();
this.mvc.perform(get("/").with(this.approved())).andExpect(corsResponseHeaders())
// @formatter:off
this.mvc.perform(get("/").with(this.approved()))
.andExpect(corsResponseHeaders())
.andExpect((status().isIAmATeapot()));
this.mvc.perform(options("/").with(this.preflight())).andExpect(corsResponseHeaders())
this.mvc.perform(options("/").with(this.preflight()))
.andExpect(corsResponseHeaders())
.andExpect(status().isOk());
// @formatter:on
}
@Test
public void getWhenUsingCustomCorsFilterThenDoesSPringSecurityCorsHandshake() throws Exception {
this.spring.configLocations(this.xml("WithCorsFilter")).autowire();
this.mvc.perform(get("/").with(this.approved())).andExpect(corsResponseHeaders())
// @formatter:off
this.mvc.perform(get("/").with(this.approved()))
.andExpect(corsResponseHeaders())
.andExpect((status().isIAmATeapot()));
this.mvc.perform(options("/").with(this.preflight())).andExpect(corsResponseHeaders())
this.mvc.perform(options("/").with(this.preflight()))
.andExpect(corsResponseHeaders())
.andExpect(status().isOk());
// @formatter:on
}
private String xml(String configName) {

View File

@ -51,11 +51,16 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
public class HttpHeadersConfigTests {
private static final String CONFIG_LOCATION_PREFIX = "classpath:org/springframework/security/config/http/HttpHeadersConfigTests";
// @formatter:off
static final Map<String, String> defaultHeaders = ImmutableMap.<String, String>builder()
.put("X-Content-Type-Options", "nosniff").put("X-Frame-Options", "DENY")
.put("Strict-Transport-Security", "max-age=31536000 ; includeSubDomains")
.put("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate").put("Expires", "0")
.put("Pragma", "no-cache").put("X-XSS-Protection", "1; mode=block").build();
.put("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate")
.put("Expires", "0")
.put("Pragma", "no-cache")
.put("X-XSS-Protection", "1; mode=block")
.build();
// @formatter:on
@Rule
public final SpringTestRule spring = new SpringTestRule();
@ -66,28 +71,44 @@ public class HttpHeadersConfigTests {
@Test
public void requestWhenHeadersDisabledThenResponseExcludesAllSecureHeaders() throws Exception {
this.spring.configLocations(this.xml("HeadersDisabled")).autowire();
this.mvc.perform(get("/")).andExpect(status().isOk()).andExpect(excludesDefaults());
// @formatter:off
this.mvc.perform(get("/"))
.andExpect(status().isOk())
.andExpect(excludesDefaults());
// @formatter:on
}
@Test
public void requestWhenHeadersDisabledViaPlaceholderThenResponseExcludesAllSecureHeaders() throws Exception {
System.setProperty("security.headers.disabled", "true");
this.spring.configLocations(this.xml("DisabledWithPlaceholder")).autowire();
this.mvc.perform(get("/").secure(true)).andExpect(status().isOk()).andExpect(excludesDefaults());
// @formatter:off
this.mvc.perform(get("/").secure(true))
.andExpect(status().isOk())
.andExpect(excludesDefaults());
// @formatter:on
}
@Test
public void requestWhenHeadersEnabledViaPlaceholderThenResponseIncludesAllSecureHeaders() throws Exception {
System.setProperty("security.headers.disabled", "false");
this.spring.configLocations(this.xml("DisabledWithPlaceholder")).autowire();
this.mvc.perform(get("/").secure(true)).andExpect(status().isOk()).andExpect(includesDefaults());
// @formatter:off
this.mvc.perform(get("/").secure(true))
.andExpect(status().isOk())
.andExpect(includesDefaults());
// @formatter:on
}
@Test
public void requestWhenHeadersDisabledRefMissingPlaceholderThenResponseIncludesAllSecureHeaders() throws Exception {
System.clearProperty("security.headers.disabled");
this.spring.configLocations(this.xml("DisabledWithPlaceholder")).autowire();
this.mvc.perform(get("/").secure(true)).andExpect(status().isOk()).andExpect(includesDefaults());
// @formatter:off
this.mvc.perform(get("/").secure(true))
.andExpect(status().isOk())
.andExpect(includesDefaults());
// @formatter:on
}
@Test
@ -100,13 +121,21 @@ public class HttpHeadersConfigTests {
@Test
public void requestWhenHeadersEnabledThenResponseContainsAllSecureHeaders() throws Exception {
this.spring.configLocations(this.xml("DefaultConfig")).autowire();
this.mvc.perform(get("/").secure(true)).andExpect(status().isOk()).andExpect(includesDefaults());
// @formatter:off
this.mvc.perform(get("/").secure(true))
.andExpect(status().isOk())
.andExpect(includesDefaults());
// @formatter:on
}
@Test
public void requestWhenHeadersElementUsedThenResponseContainsAllSecureHeaders() throws Exception {
this.spring.configLocations(this.xml("HeadersEnabled")).autowire();
this.mvc.perform(get("/").secure(true)).andExpect(status().isOk()).andExpect(includesDefaults());
// @formatter:off
this.mvc.perform(get("/").secure(true))
.andExpect(status().isOk())
.andExpect(includesDefaults());
// @formatter:on
}
@Test
@ -114,7 +143,11 @@ public class HttpHeadersConfigTests {
Map<String, String> headers = new HashMap(defaultHeaders);
headers.put("X-Frame-Options", "SAMEORIGIN");
this.spring.configLocations(this.xml("WithFrameOptions")).autowire();
this.mvc.perform(get("/").secure(true)).andExpect(status().isOk()).andExpect(includes(headers));
// @formatter:off
this.mvc.perform(get("/").secure(true))
.andExpect(status().isOk())
.andExpect(includes(headers));
// @formatter:on
}
/**
@ -123,28 +156,44 @@ public class HttpHeadersConfigTests {
@Test
public void requestWhenDefaultsDisabledWithNoOverrideThenExcludesAllSecureHeaders() throws Exception {
this.spring.configLocations(this.xml("DefaultsDisabledWithNoOverride")).autowire();
this.mvc.perform(get("/").secure(true)).andExpect(status().isOk()).andExpect(excludesDefaults());
// @formatter:off
this.mvc.perform(get("/").secure(true))
.andExpect(status().isOk())
.andExpect(excludesDefaults());
// @formatter:on
}
@Test
public void requestWhenDefaultsDisabledWithPlaceholderTrueThenExcludesAllSecureHeaders() throws Exception {
System.setProperty("security.headers.defaults.disabled", "true");
this.spring.configLocations(this.xml("DefaultsDisabledWithPlaceholder")).autowire();
this.mvc.perform(get("/").secure(true)).andExpect(status().isOk()).andExpect(excludesDefaults());
// @formatter:off
this.mvc.perform(get("/").secure(true))
.andExpect(status().isOk())
.andExpect(excludesDefaults());
// @formatter:on
}
@Test
public void requestWhenDefaultsDisabledWithPlaceholderFalseThenIncludeAllSecureHeaders() throws Exception {
System.setProperty("security.headers.defaults.disabled", "false");
this.spring.configLocations(this.xml("DefaultsDisabledWithPlaceholder")).autowire();
this.mvc.perform(get("/").secure(true)).andExpect(status().isOk()).andExpect(includesDefaults());
// @formatter:off
this.mvc.perform(get("/").secure(true))
.andExpect(status().isOk())
.andExpect(includesDefaults());
// @formatter:on
}
@Test
public void requestWhenDefaultsDisabledWithPlaceholderMissingThenIncludeAllSecureHeaders() throws Exception {
System.clearProperty("security.headers.defaults.disabled");
this.spring.configLocations(this.xml("DefaultsDisabledWithPlaceholder")).autowire();
this.mvc.perform(get("/").secure(true)).andExpect(status().isOk()).andExpect(includesDefaults());
// @formatter:off
this.mvc.perform(get("/").secure(true))
.andExpect(status().isOk())
.andExpect(includesDefaults());
// @formatter:on
}
@Test
@ -152,8 +201,12 @@ public class HttpHeadersConfigTests {
Set<String> excludedHeaders = new HashSet<>(defaultHeaders.keySet());
excludedHeaders.remove("X-Content-Type-Options");
this.spring.configLocations(this.xml("DefaultsDisabledWithContentTypeOptions")).autowire();
this.mvc.perform(get("/")).andExpect(status().isOk())
.andExpect(header().string("X-Content-Type-Options", "nosniff")).andExpect(excludes(excludedHeaders));
// @formatter:off
this.mvc.perform(get("/"))
.andExpect(status().isOk())
.andExpect(header().string("X-Content-Type-Options", "nosniff"))
.andExpect(excludes(excludedHeaders));
// @formatter:on
}
@Test
@ -161,8 +214,12 @@ public class HttpHeadersConfigTests {
Set<String> excludedHeaders = new HashSet<>(defaultHeaders.keySet());
excludedHeaders.remove("X-Frame-Options");
this.spring.configLocations(this.xml("DefaultsDisabledWithFrameOptions")).autowire();
this.mvc.perform(get("/")).andExpect(status().isOk()).andExpect(header().string("X-Frame-Options", "DENY"))
// @formatter:off
this.mvc.perform(get("/"))
.andExpect(status().isOk())
.andExpect(header().string("X-Frame-Options", "DENY"))
.andExpect(excludes(excludedHeaders));
// @formatter:on
}
@Test
@ -170,8 +227,12 @@ public class HttpHeadersConfigTests {
Set<String> excludedHeaders = new HashSet<>(defaultHeaders.keySet());
excludedHeaders.remove("X-Frame-Options");
this.spring.configLocations(this.xml("DefaultsDisabledWithFrameOptionsDeny")).autowire();
this.mvc.perform(get("/")).andExpect(status().isOk()).andExpect(header().string("X-Frame-Options", "DENY"))
// @formatter:off
this.mvc.perform(get("/"))
.andExpect(status().isOk())
.andExpect(header().string("X-Frame-Options", "DENY"))
.andExpect(excludes(excludedHeaders));
// @formatter:on
}
@Test
@ -179,8 +240,12 @@ public class HttpHeadersConfigTests {
Set<String> excludedHeaders = new HashSet<>(defaultHeaders.keySet());
excludedHeaders.remove("X-Frame-Options");
this.spring.configLocations(this.xml("DefaultsDisabledWithFrameOptionsSameOrigin")).autowire();
this.mvc.perform(get("/")).andExpect(status().isOk())
.andExpect(header().string("X-Frame-Options", "SAMEORIGIN")).andExpect(excludes(excludedHeaders));
// @formatter:off
this.mvc.perform(get("/"))
.andExpect(status().isOk())
.andExpect(header().string("X-Frame-Options", "SAMEORIGIN"))
.andExpect(excludes(excludedHeaders));
// @formatter:on
}
@Test
@ -206,9 +271,12 @@ public class HttpHeadersConfigTests {
Set<String> excludedHeaders = new HashSet<>(defaultHeaders.keySet());
excludedHeaders.remove("X-Frame-Options");
this.spring.configLocations(this.xml("DefaultsDisabledWithFrameOptionsAllowFrom")).autowire();
this.mvc.perform(get("/")).andExpect(status().isOk())
// @formatter:off
this.mvc.perform(get("/"))
.andExpect(status().isOk())
.andExpect(header().string("X-Frame-Options", "ALLOW-FROM https://example.org"))
.andExpect(excludes(excludedHeaders));
// @formatter:on
}
@Test
@ -216,25 +284,39 @@ public class HttpHeadersConfigTests {
Set<String> excludedHeaders = new HashSet<>(defaultHeaders.keySet());
excludedHeaders.remove("X-Frame-Options");
this.spring.configLocations(this.xml("DefaultsDisabledWithFrameOptionsAllowFromWhitelist")).autowire();
this.mvc.perform(get("/").param("from", "https://example.org")).andExpect(status().isOk())
// @formatter:off
this.mvc.perform(get("/").param("from", "https://example.org"))
.andExpect(status().isOk())
.andExpect(header().string("X-Frame-Options", "ALLOW-FROM https://example.org"))
.andExpect(excludes(excludedHeaders));
this.mvc.perform(get("/")).andExpect(status().isOk()).andExpect(header().string("X-Frame-Options", "DENY"))
this.mvc.perform(get("/"))
.andExpect(status().isOk())
.andExpect(header().string("X-Frame-Options", "DENY"))
.andExpect(excludes(excludedHeaders));
// @formatter:on
}
@Test
public void requestWhenUsingCustomHeaderThenRespondsWithThatHeader() throws Exception {
this.spring.configLocations(this.xml("DefaultsDisabledWithCustomHeader")).autowire();
this.mvc.perform(get("/")).andExpect(status().isOk()).andExpect(header().string("a", "b"))
.andExpect(header().string("c", "d")).andExpect(excludesDefaults());
// @formatter:off
this.mvc.perform(get("/"))
.andExpect(status().isOk())
.andExpect(header().string("a", "b"))
.andExpect(header().string("c", "d"))
.andExpect(excludesDefaults());
// @formatter:on
}
@Test
public void requestWhenUsingCustomHeaderWriterThenRespondsWithThatHeader() throws Exception {
this.spring.configLocations(this.xml("DefaultsDisabledWithCustomHeaderWriter")).autowire();
this.mvc.perform(get("/")).andExpect(status().isOk()).andExpect(header().string("abc", "def"))
// @formatter:off
this.mvc.perform(get("/"))
.andExpect(status().isOk())
.andExpect(header().string("abc", "def"))
.andExpect(excludesDefaults());
// @formatter:on
}
@Test
@ -254,8 +336,12 @@ public class HttpHeadersConfigTests {
Set<String> excludedHeaders = new HashSet<>(defaultHeaders.keySet());
excludedHeaders.remove("X-XSS-Protection");
this.spring.configLocations(this.xml("DefaultsDisabledWithXssProtection")).autowire();
this.mvc.perform(get("/")).andExpect(status().isOk())
.andExpect(header().string("X-XSS-Protection", "1; mode=block")).andExpect(excludes(excludedHeaders));
// @formatter:off
this.mvc.perform(get("/"))
.andExpect(status().isOk())
.andExpect(header().string("X-XSS-Protection", "1; mode=block"))
.andExpect(excludes(excludedHeaders));
// @formatter:on
}
@Test
@ -263,8 +349,12 @@ public class HttpHeadersConfigTests {
Set<String> excludedHeaders = new HashSet<>(defaultHeaders.keySet());
excludedHeaders.remove("X-XSS-Protection");
this.spring.configLocations(this.xml("DefaultsDisabledWithXssProtectionEnabled")).autowire();
this.mvc.perform(get("/")).andExpect(status().isOk())
.andExpect(header().string("X-XSS-Protection", "1; mode=block")).andExpect(excludes(excludedHeaders));
// @formatter:off
this.mvc.perform(get("/"))
.andExpect(status().isOk())
.andExpect(header().string("X-XSS-Protection", "1; mode=block"))
.andExpect(excludes(excludedHeaders));
// @formatter:on
}
@Test
@ -272,8 +362,12 @@ public class HttpHeadersConfigTests {
Set<String> excludedHeaders = new HashSet<>(defaultHeaders.keySet());
excludedHeaders.remove("X-XSS-Protection");
this.spring.configLocations(this.xml("DefaultsDisabledWithXssProtectionDisabled")).autowire();
this.mvc.perform(get("/")).andExpect(status().isOk()).andExpect(header().string("X-XSS-Protection", "0"))
// @formatter:off
this.mvc.perform(get("/"))
.andExpect(status().isOk())
.andExpect(header().string("X-XSS-Protection", "0"))
.andExpect(excludes(excludedHeaders));
// @formatter:on
}
@Test
@ -290,7 +384,11 @@ public class HttpHeadersConfigTests {
.put("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate").put("Expires", "0")
.put("Pragma", "no-cache").build();
this.spring.configLocations(this.xml("DefaultsDisabledWithCacheControl")).autowire();
this.mvc.perform(get("/")).andExpect(status().isOk()).andExpect(includes(includedHeaders));
// @formatter:off
this.mvc.perform(get("/"))
.andExpect(status().isOk())
.andExpect(includes(includedHeaders));
// @formatter:on
}
@Test
@ -298,15 +396,22 @@ public class HttpHeadersConfigTests {
Set<String> excludedHeaders = new HashSet<>(defaultHeaders.keySet());
excludedHeaders.remove("Strict-Transport-Security");
this.spring.configLocations(this.xml("DefaultsDisabledWithHsts")).autowire();
this.mvc.perform(get("/").secure(true)).andExpect(status().isOk())
// @formatter:off
this.mvc.perform(get("/").secure(true))
.andExpect(status().isOk())
.andExpect(header().string("Strict-Transport-Security", "max-age=31536000 ; includeSubDomains"))
.andExpect(excludes(excludedHeaders));
// @formatter:on
}
@Test
public void insecureRequestWhenUsingHstsThenExcludesHstsHeader() throws Exception {
this.spring.configLocations(this.xml("DefaultsDisabledWithHsts")).autowire();
this.mvc.perform(get("/")).andExpect(status().isOk()).andExpect(excludesDefaults());
// @formatter:off
this.mvc.perform(get("/"))
.andExpect(status().isOk())
.andExpect(excludesDefaults());
// @formatter:on
}
@Test
@ -314,9 +419,12 @@ public class HttpHeadersConfigTests {
Set<String> excludedHeaders = new HashSet<>(defaultHeaders.keySet());
excludedHeaders.remove("Strict-Transport-Security");
this.spring.configLocations(this.xml("DefaultsDisabledWithCustomHstsRequestMatcher")).autowire();
this.mvc.perform(get("/")).andExpect(status().isOk())
// @formatter:off
this.mvc.perform(get("/"))
.andExpect(status().isOk())
.andExpect(header().string("Strict-Transport-Security", "max-age=1"))
.andExpect(excludes(excludedHeaders));
// @formatter:on
}
@Test
@ -336,62 +444,84 @@ public class HttpHeadersConfigTests {
@Test
public void requestWhenUsingHpkpThenIncludesHpkpHeader() throws Exception {
this.spring.configLocations(this.xml("DefaultsDisabledWithHpkp")).autowire();
this.mvc.perform(get("/").secure(true)).andExpect(status().isOk())
// @formatter:off
this.mvc.perform(get("/").secure(true))
.andExpect(status().isOk())
.andExpect(header().string("Public-Key-Pins-Report-Only",
"max-age=5184000 ; pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\""))
.andExpect(excludesDefaults());
// @formatter:on
}
@Test
public void requestWhenUsingHpkpDefaultsThenIncludesHpkpHeaderUsingSha256() throws Exception {
this.spring.configLocations(this.xml("DefaultsDisabledWithHpkpDefaults")).autowire();
this.mvc.perform(get("/").secure(true)).andExpect(status().isOk())
// @formatter:off
this.mvc.perform(get("/").secure(true))
.andExpect(status().isOk())
.andExpect(header().string("Public-Key-Pins-Report-Only",
"max-age=5184000 ; pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\""))
.andExpect(excludesDefaults());
// @formatter:on
}
@Test
public void insecureRequestWhenUsingHpkpThenExcludesHpkpHeader() throws Exception {
this.spring.configLocations(this.xml("DefaultsDisabledWithHpkpDefaults")).autowire();
this.mvc.perform(get("/")).andExpect(status().isOk())
.andExpect(header().doesNotExist("Public-Key-Pins-Report-Only")).andExpect(excludesDefaults());
// @formatter:off
this.mvc.perform(get("/"))
.andExpect(status().isOk())
.andExpect(header().doesNotExist("Public-Key-Pins-Report-Only"))
.andExpect(excludesDefaults());
// @formatter:on
}
@Test
public void requestWhenUsingHpkpCustomMaxAgeThenIncludesHpkpHeaderAccordingly() throws Exception {
this.spring.configLocations(this.xml("DefaultsDisabledWithHpkpMaxAge")).autowire();
this.mvc.perform(get("/").secure(true)).andExpect(status().isOk())
// @formatter:off
this.mvc.perform(get("/").secure(true))
.andExpect(status().isOk())
.andExpect(header().string("Public-Key-Pins-Report-Only",
"max-age=604800 ; pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\""))
.andExpect(excludesDefaults());
// @formatter:on
}
@Test
public void requestWhenUsingHpkpReportThenIncludesHpkpHeaderAccordingly() throws Exception {
this.spring.configLocations(this.xml("DefaultsDisabledWithHpkpReport")).autowire();
this.mvc.perform(get("/").secure(true)).andExpect(status().isOk())
// @formatter:off
this.mvc.perform(get("/").secure(true))
.andExpect(status().isOk())
.andExpect(header().string("Public-Key-Pins",
"max-age=5184000 ; pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\""))
.andExpect(excludesDefaults());
// @formatter:on
}
@Test
public void requestWhenUsingHpkpIncludeSubdomainsThenIncludesHpkpHeaderAccordingly() throws Exception {
this.spring.configLocations(this.xml("DefaultsDisabledWithHpkpIncludeSubdomains")).autowire();
this.mvc.perform(get("/").secure(true)).andExpect(status().isOk()).andExpect(header().string(
"Public-Key-Pins-Report-Only",
"max-age=5184000 ; pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\" ; includeSubDomains"))
// @formatter:off
this.mvc.perform(get("/").secure(true))
.andExpect(status().isOk())
.andExpect(header().string("Public-Key-Pins-Report-Only",
"max-age=5184000 ; pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\" ; includeSubDomains"))
.andExpect(excludesDefaults());
// @formatter:on
}
@Test
public void requestWhenUsingHpkpReportUriThenIncludesHpkpHeaderAccordingly() throws Exception {
this.spring.configLocations(this.xml("DefaultsDisabledWithHpkpReportUri")).autowire();
this.mvc.perform(get("/").secure(true)).andExpect(status().isOk()).andExpect(header().string(
"Public-Key-Pins-Report-Only",
"max-age=5184000 ; pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\" ; report-uri=\"https://example.net/pkp-report\""))
// @formatter:off
this.mvc.perform(get("/").secure(true))
.andExpect(status().isOk())
.andExpect(header().string("Public-Key-Pins-Report-Only",
"max-age=5184000 ; pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\" ; report-uri=\"https://example.net/pkp-report\""))
.andExpect(excludesDefaults());
// @formatter:on
}
@Test
@ -399,8 +529,12 @@ public class HttpHeadersConfigTests {
Collection<String> cacheControl = Arrays.asList("Cache-Control", "Expires", "Pragma");
Map<String, String> allButCacheControl = remove(defaultHeaders, cacheControl);
this.spring.configLocations(this.xml("CacheControlDisabled")).autowire();
this.mvc.perform(get("/").secure(true)).andExpect(status().isOk()).andExpect(includes(allButCacheControl))
// @formatter:off
this.mvc.perform(get("/").secure(true))
.andExpect(status().isOk())
.andExpect(includes(allButCacheControl))
.andExpect(excludes(cacheControl));
// @formatter:on
}
@Test
@ -408,8 +542,12 @@ public class HttpHeadersConfigTests {
Collection<String> contentTypeOptions = Arrays.asList("X-Content-Type-Options");
Map<String, String> allButContentTypeOptions = remove(defaultHeaders, contentTypeOptions);
this.spring.configLocations(this.xml("ContentTypeOptionsDisabled")).autowire();
this.mvc.perform(get("/").secure(true)).andExpect(status().isOk()).andExpect(includes(allButContentTypeOptions))
// @formatter:off
this.mvc.perform(get("/").secure(true))
.andExpect(status().isOk())
.andExpect(includes(allButContentTypeOptions))
.andExpect(excludes(contentTypeOptions));
// @formatter:on
}
@Test
@ -417,14 +555,22 @@ public class HttpHeadersConfigTests {
Collection<String> hsts = Arrays.asList("Strict-Transport-Security");
Map<String, String> allButHsts = remove(defaultHeaders, hsts);
this.spring.configLocations(this.xml("HstsDisabled")).autowire();
this.mvc.perform(get("/").secure(true)).andExpect(status().isOk()).andExpect(includes(allButHsts))
// @formatter:off
this.mvc.perform(get("/").secure(true))
.andExpect(status().isOk())
.andExpect(includes(allButHsts))
.andExpect(excludes(hsts));
// @formatter:on
}
@Test
public void requestWhenHpkpDisabledThenExcludesHeader() throws Exception {
this.spring.configLocations(this.xml("HpkpDisabled")).autowire();
this.mvc.perform(get("/").secure(true)).andExpect(status().isOk()).andExpect(includesDefaults());
// @formatter:off
this.mvc.perform(get("/").secure(true))
.andExpect(status().isOk())
.andExpect(includesDefaults());
// @formatter:on
}
@Test
@ -432,8 +578,12 @@ public class HttpHeadersConfigTests {
Collection<String> frameOptions = Arrays.asList("X-Frame-Options");
Map<String, String> allButFrameOptions = remove(defaultHeaders, frameOptions);
this.spring.configLocations(this.xml("FrameOptionsDisabled")).autowire();
this.mvc.perform(get("/").secure(true)).andExpect(status().isOk()).andExpect(includes(allButFrameOptions))
// @formatter:off
this.mvc.perform(get("/").secure(true))
.andExpect(status().isOk())
.andExpect(includes(allButFrameOptions))
.andExpect(excludes(frameOptions));
// @formatter:on
}
@Test
@ -441,8 +591,12 @@ public class HttpHeadersConfigTests {
Collection<String> xssProtection = Arrays.asList("X-XSS-Protection");
Map<String, String> allButXssProtection = remove(defaultHeaders, xssProtection);
this.spring.configLocations(this.xml("XssProtectionDisabled")).autowire();
this.mvc.perform(get("/").secure(true)).andExpect(status().isOk()).andExpect(includes(allButXssProtection))
// @formatter:off
this.mvc.perform(get("/").secure(true))
.andExpect(status().isOk())
.andExpect(includes(allButXssProtection))
.andExpect(excludes(xssProtection));
// @formatter:on
}
@Test
@ -495,21 +649,33 @@ public class HttpHeadersConfigTests {
Map<String, String> includedHeaders = new HashMap<>(defaultHeaders);
includedHeaders.put("Content-Security-Policy", "default-src 'self'");
this.spring.configLocations(this.xml("ContentSecurityPolicyWithPolicyDirectives")).autowire();
this.mvc.perform(get("/").secure(true)).andExpect(status().isOk()).andExpect(includes(includedHeaders));
// @formatter:off
this.mvc.perform(get("/").secure(true))
.andExpect(status().isOk())
.andExpect(includes(includedHeaders));
// @formatter:on
}
@Test
public void requestWhenHeadersDisabledAndContentSecurityPolicyConfiguredThenExcludesHeader() throws Exception {
this.spring.configLocations(this.xml("HeadersDisabledWithContentSecurityPolicy")).autowire();
this.mvc.perform(get("/")).andExpect(status().isOk()).andExpect(excludesDefaults())
// @formatter:off
this.mvc.perform(get("/"))
.andExpect(status().isOk())
.andExpect(excludesDefaults())
.andExpect(excludes("Content-Security-Policy"));
// @formatter:on
}
@Test
public void requestWhenDefaultsDisabledAndContentSecurityPolicyConfiguredThenIncludesHeader() throws Exception {
this.spring.configLocations(this.xml("DefaultsDisabledWithContentSecurityPolicy")).autowire();
this.mvc.perform(get("/")).andExpect(status().isOk()).andExpect(excludesDefaults())
// @formatter:off
this.mvc.perform(get("/"))
.andExpect(status().isOk())
.andExpect(excludesDefaults())
.andExpect(header().string("Content-Security-Policy", "default-src 'self'"));
// @formatter:on
}
@Test
@ -525,21 +691,33 @@ public class HttpHeadersConfigTests {
includedHeaders.put("Content-Security-Policy-Report-Only",
"default-src https:; report-uri https://example.org/");
this.spring.configLocations(this.xml("ContentSecurityPolicyWithReportOnly")).autowire();
this.mvc.perform(get("/").secure(true)).andExpect(status().isOk()).andExpect(includes(includedHeaders));
// @formatter:off
this.mvc.perform(get("/").secure(true))
.andExpect(status().isOk())
.andExpect(includes(includedHeaders));
// @formatter:on
}
@Test
public void requestWhenReferrerPolicyConfiguredThenResponseDefaultsToNoReferrer() throws Exception {
this.spring.configLocations(this.xml("DefaultsDisabledWithReferrerPolicy")).autowire();
this.mvc.perform(get("/")).andExpect(status().isOk()).andExpect(excludesDefaults())
// @formatter:off
this.mvc.perform(get("/"))
.andExpect(status().isOk())
.andExpect(excludesDefaults())
.andExpect(header().string("Referrer-Policy", "no-referrer"));
// @formatter:on
}
@Test
public void requestWhenReferrerPolicyConfiguredWithSameOriginThenRespondsWithSameOrigin() throws Exception {
this.spring.configLocations(this.xml("DefaultsDisabledWithReferrerPolicySameOrigin")).autowire();
this.mvc.perform(get("/")).andExpect(status().isOk()).andExpect(excludesDefaults())
// @formatter:off
this.mvc.perform(get("/"))
.andExpect(status().isOk())
.andExpect(excludesDefaults())
.andExpect(header().string("Referrer-Policy", "same-origin"));
// @formatter:on
}
private static ResultMatcher includesDefaults() {

View File

@ -48,9 +48,14 @@ public class HttpInterceptUrlTests {
@Test
public void interceptUrlWhenRequestMatcherRefThenWorks() throws Exception {
loadConfig("interceptUrlWhenRequestMatcherRefThenWorks.xml");
this.mockMvc.perform(get("/foo")).andExpect(status().isUnauthorized());
this.mockMvc.perform(get("/FOO")).andExpect(status().isUnauthorized());
this.mockMvc.perform(get("/other")).andExpect(status().isOk());
// @formatter:off
this.mockMvc.perform(get("/foo"))
.andExpect(status().isUnauthorized());
this.mockMvc.perform(get("/FOO"))
.andExpect(status().isUnauthorized());
this.mockMvc.perform(get("/other"))
.andExpect(status().isOk());
// @formatter:on
}
private void loadConfig(String... configLocations) {

View File

@ -30,6 +30,7 @@ import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
import org.springframework.mock.web.MockServletContext;
import org.springframework.security.config.test.SpringTestRule;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.RequestPostProcessor;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@ -65,8 +66,12 @@ public class InterceptUrlConfigTests {
@Test
public void requestWhenMethodIsSpecifiedThenItIsNotGivenPriority() throws Exception {
this.spring.configLocations(this.xml("Sec2256")).autowire();
this.mvc.perform(post("/path").with(httpBasic("user", "password"))).andExpect(status().isOk());
this.mvc.perform(get("/path").with(httpBasic("user", "password"))).andExpect(status().isOk());
// @formatter:off
this.mvc.perform(post("/path").with(userCredentials()))
.andExpect(status().isOk());
this.mvc.perform(get("/path").with(userCredentials()))
.andExpect(status().isOk());
// @formatter:on
}
/**
@ -75,16 +80,25 @@ public class InterceptUrlConfigTests {
@Test
public void requestWhenUsingPatchThenAuthorizesRequestsAccordingly() throws Exception {
this.spring.configLocations(this.xml("PatchMethod")).autowire();
this.mvc.perform(get("/path").with(httpBasic("user", "password"))).andExpect(status().isOk());
this.mvc.perform(patch("/path").with(httpBasic("user", "password"))).andExpect(status().isForbidden());
this.mvc.perform(patch("/path").with(httpBasic("admin", "password"))).andExpect(status().isOk());
// @formatter:off
this.mvc.perform(get("/path").with(userCredentials()))
.andExpect(status().isOk());
this.mvc.perform(patch("/path").with(userCredentials()))
.andExpect(status().isForbidden());
this.mvc.perform(patch("/path").with(adminCredentials()))
.andExpect(status().isOk());
// @formatter:on
}
@Test
public void requestWhenUsingHasAnyRoleThenAuthorizesRequestsAccordingly() throws Exception {
this.spring.configLocations(this.xml("HasAnyRole")).autowire();
this.mvc.perform(get("/path").with(httpBasic("user", "password"))).andExpect(status().isOk());
this.mvc.perform(get("/path").with(httpBasic("admin", "password"))).andExpect(status().isForbidden());
// @formatter:off
this.mvc.perform(get("/path").with(userCredentials()))
.andExpect(status().isOk());
this.mvc.perform(get("/path").with(adminCredentials()))
.andExpect(status().isForbidden());
// @formatter:on
}
/**
@ -93,10 +107,14 @@ public class InterceptUrlConfigTests {
@Test
public void requestWhenUsingPathVariablesThenAuthorizesRequestsAccordingly() throws Exception {
this.spring.configLocations(this.xml("PathVariables")).autowire();
this.mvc.perform(get("/path/user/path").with(httpBasic("user", "password"))).andExpect(status().isOk());
this.mvc.perform(get("/path/otheruser/path").with(httpBasic("user", "password")))
// @formatter:off
this.mvc.perform(get("/path/user/path").with(userCredentials()))
.andExpect(status().isOk());
this.mvc.perform(get("/path/otheruser/path").with(userCredentials()))
.andExpect(status().isForbidden());
this.mvc.perform(get("/path").with(httpBasic("user", "password"))).andExpect(status().isForbidden());
this.mvc.perform(get("/path").with(userCredentials()))
.andExpect(status().isForbidden());
// @formatter:on
}
/**
@ -105,10 +123,14 @@ public class InterceptUrlConfigTests {
@Test
public void requestWhenUsingCamelCasePathVariablesThenAuthorizesRequestsAccordingly() throws Exception {
this.spring.configLocations(this.xml("CamelCasePathVariables")).autowire();
this.mvc.perform(get("/path/user/path").with(httpBasic("user", "password"))).andExpect(status().isOk());
this.mvc.perform(get("/path/otheruser/path").with(httpBasic("user", "password")))
// @formatter:off
this.mvc.perform(get("/path/user/path").with(userCredentials()))
.andExpect(status().isOk());
this.mvc.perform(get("/path/otheruser/path").with(userCredentials()))
.andExpect(status().isForbidden());
this.mvc.perform(get("/PATH/user/path").with(httpBasic("user", "password"))).andExpect(status().isForbidden());
this.mvc.perform(get("/PATH/user/path").with(userCredentials()))
.andExpect(status().isForbidden());
// @formatter:on
}
/**
@ -117,25 +139,36 @@ public class InterceptUrlConfigTests {
@Test
public void requestWhenUsingPathVariablesAndTypeConversionThenAuthorizesRequestsAccordingly() throws Exception {
this.spring.configLocations(this.xml("TypeConversionPathVariables")).autowire();
this.mvc.perform(get("/path/1/path").with(httpBasic("user", "password"))).andExpect(status().isOk());
this.mvc.perform(get("/path/2/path").with(httpBasic("user", "password"))).andExpect(status().isForbidden());
// @formatter:off
this.mvc.perform(get("/path/1/path").with(userCredentials()))
.andExpect(status().isOk());
this.mvc.perform(get("/path/2/path").with(userCredentials()))
.andExpect(status().isForbidden());
// @formatter:on
}
@Test
public void requestWhenUsingMvcMatchersThenAuthorizesRequestsAccordingly() throws Exception {
this.spring.configLocations(this.xml("MvcMatchers")).autowire();
this.mvc.perform(get("/path")).andExpect(status().isUnauthorized());
this.mvc.perform(get("/path.html")).andExpect(status().isUnauthorized());
this.mvc.perform(get("/path/")).andExpect(status().isUnauthorized());
this.mvc.perform(get("/path"))
.andExpect(status().isUnauthorized());
this.mvc.perform(get("/path.html"))
.andExpect(status().isUnauthorized());
this.mvc.perform(get("/path/"))
.andExpect(status().isUnauthorized());
}
@Test
public void requestWhenUsingMvcMatchersAndPathVariablesThenAuthorizesRequestsAccordingly() throws Exception {
this.spring.configLocations(this.xml("MvcMatchersPathVariables")).autowire();
this.mvc.perform(get("/path/user/path").with(httpBasic("user", "password"))).andExpect(status().isOk());
this.mvc.perform(get("/path/otheruser/path").with(httpBasic("user", "password")))
// @formatter:off
this.mvc.perform(get("/path/user/path").with(userCredentials()))
.andExpect(status().isOk());
this.mvc.perform(get("/path/otheruser/path").with(userCredentials()))
.andExpect(status().isForbidden());
this.mvc.perform(get("/PATH/user/path").with(httpBasic("user", "password"))).andExpect(status().isForbidden());
this.mvc.perform(get("/PATH/user/path").with(userCredentials()))
.andExpect(status().isForbidden());
// @formatter:on
}
@Test
@ -144,9 +177,14 @@ public class InterceptUrlConfigTests {
MockServletContext servletContext = mockServletContext("/spring");
ConfigurableWebApplicationContext context = this.spring.getContext();
context.setServletContext(servletContext);
this.mvc.perform(get("/spring/path").servletPath("/spring")).andExpect(status().isUnauthorized());
this.mvc.perform(get("/spring/path.html").servletPath("/spring")).andExpect(status().isUnauthorized());
this.mvc.perform(get("/spring/path/").servletPath("/spring")).andExpect(status().isUnauthorized());
// @formatter:off
this.mvc.perform(get("/spring/path").servletPath("/spring"))
.andExpect(status().isUnauthorized());
this.mvc.perform(get("/spring/path.html").servletPath("/spring"))
.andExpect(status().isUnauthorized());
this.mvc.perform(get("/spring/path/").servletPath("/spring"))
.andExpect(status().isUnauthorized());
// @formatter:on
}
@Test
@ -173,6 +211,14 @@ public class InterceptUrlConfigTests {
.isThrownBy(() -> this.spring.configLocations(this.xml("DefaultMatcherServletPath")).autowire());
}
private static RequestPostProcessor adminCredentials() {
return httpBasic("admin", "password");
}
private static RequestPostProcessor userCredentials() {
return httpBasic("user", "password");
}
private MockServletContext mockServletContext(String servletPath) {
MockServletContext servletContext = spy(new MockServletContext());
final ServletRegistration registration = mock(ServletRegistration.class);

View File

@ -43,6 +43,7 @@ import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.Appender;
import org.apache.http.HttpStatus;
import org.assertj.core.api.iterable.Extractor;
import org.jetbrains.annotations.NotNull;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.stubbing.Answer;
@ -105,6 +106,8 @@ import org.springframework.security.web.session.SessionManagementFilter;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.test.web.servlet.request.RequestPostProcessor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@ -162,29 +165,45 @@ public class MiscHttpConfigTests {
@Test
public void requestWhenUsingDebugFilterAndPatternIsNotConfigureForSecurityThenRespondsOk() throws Exception {
this.spring.configLocations(xml("NoSecurityForPattern")).autowire();
this.mvc.perform(get("/unprotected")).andExpect(status().isNotFound());
this.mvc.perform(get("/nomatch")).andExpect(status().isNotFound());
// @formatter:off
this.mvc.perform(get("/unprotected"))
.andExpect(status().isNotFound());
this.mvc.perform(get("/nomatch"))
.andExpect(status().isNotFound());
// @formatter:on
}
@Test
public void requestWhenHttpPatternUsesRegexMatchingThenMatchesAccordingly() throws Exception {
this.spring.configLocations(xml("RegexSecurityPattern")).autowire();
this.mvc.perform(get("/protected")).andExpect(status().isUnauthorized());
this.mvc.perform(get("/unprotected")).andExpect(status().isNotFound());
// @formatter:off
this.mvc.perform(get("/protected"))
.andExpect(status().isUnauthorized());
this.mvc.perform(get("/unprotected"))
.andExpect(status().isNotFound());
// @formatter:on
}
@Test
public void requestWhenHttpPatternUsesCiRegexMatchingThenMatchesAccordingly() throws Exception {
this.spring.configLocations(xml("CiRegexSecurityPattern")).autowire();
this.mvc.perform(get("/ProTectEd")).andExpect(status().isUnauthorized());
this.mvc.perform(get("/UnProTectEd")).andExpect(status().isNotFound());
// @formatter:off
this.mvc.perform(get("/ProTectEd"))
.andExpect(status().isUnauthorized());
this.mvc.perform(get("/UnProTectEd"))
.andExpect(status().isNotFound());
// @formatter:on
}
@Test
public void requestWhenHttpPatternUsesCustomRequestMatcherThenMatchesAccordingly() throws Exception {
this.spring.configLocations(xml("CustomRequestMatcher")).autowire();
this.mvc.perform(get("/protected")).andExpect(status().isUnauthorized());
this.mvc.perform(get("/unprotected")).andExpect(status().isNotFound());
// @formatter:off
this.mvc.perform(get("/protected"))
.andExpect(status().isUnauthorized());
this.mvc.perform(get("/unprotected"))
.andExpect(status().isNotFound());
// @formatter:on
}
/**
@ -193,65 +212,98 @@ public class MiscHttpConfigTests {
@Test
public void requestWhenUsingMinimalConfigurationThenHonorsAnonymousEndpoints() throws Exception {
this.spring.configLocations(xml("AnonymousEndpoints")).autowire();
this.mvc.perform(get("/protected")).andExpect(status().isUnauthorized());
this.mvc.perform(get("/unprotected")).andExpect(status().isNotFound());
// @formatter:off
this.mvc.perform(get("/protected"))
.andExpect(status().isUnauthorized());
this.mvc.perform(get("/unprotected"))
.andExpect(status().isNotFound());
// @formatter:on
assertThat(getFilter(AnonymousAuthenticationFilter.class)).isNotNull();
}
@Test
public void requestWhenAnonymousIsDisabledThenRejectsAnonymousEndpoints() throws Exception {
this.spring.configLocations(xml("AnonymousDisabled")).autowire();
this.mvc.perform(get("/protected")).andExpect(status().isUnauthorized());
this.mvc.perform(get("/unprotected")).andExpect(status().isUnauthorized());
// @formatter:off
this.mvc.perform(get("/protected"))
.andExpect(status().isUnauthorized());
this.mvc.perform(get("/unprotected"))
.andExpect(status().isUnauthorized());
// @formatter:on
assertThat(getFilter(AnonymousAuthenticationFilter.class)).isNull();
}
@Test
public void requestWhenAnonymousUsesCustomAttributesThenRespondsWithThoseAttributes() throws Exception {
this.spring.configLocations(xml("AnonymousCustomAttributes")).autowire();
this.mvc.perform(get("/protected").with(httpBasic("user", "password"))).andExpect(status().isForbidden());
this.mvc.perform(get("/protected")).andExpect(status().isOk()).andExpect(content().string("josh"));
this.mvc.perform(get("/customKey")).andExpect(status().isOk())
// @formatter:off
this.mvc.perform(get("/protected").with(userCredentials()))
.andExpect(status().isForbidden());
this.mvc.perform(get("/protected"))
.andExpect(status().isOk())
.andExpect(content().string("josh"));
this.mvc.perform(get("/customKey"))
.andExpect(status().isOk())
.andExpect(content().string(String.valueOf("myCustomKey".hashCode())));
// @formatter:on
}
@Test
public void requestWhenAnonymousUsesMultipleGrantedAuthoritiesThenRespondsWithThoseAttributes() throws Exception {
this.spring.configLocations(xml("AnonymousMultipleAuthorities")).autowire();
this.mvc.perform(get("/protected").with(httpBasic("user", "password"))).andExpect(status().isForbidden());
this.mvc.perform(get("/protected")).andExpect(status().isOk()).andExpect(content().string("josh"));
this.mvc.perform(get("/customKey")).andExpect(status().isOk())
// @formatter:off
this.mvc.perform(get("/protected").with(userCredentials()))
.andExpect(status().isForbidden());
this.mvc.perform(get("/protected"))
.andExpect(status().isOk())
.andExpect(content().string("josh"));
this.mvc.perform(get("/customKey"))
.andExpect(status().isOk())
.andExpect(content().string(String.valueOf("myCustomKey".hashCode())));
// @formatter:on
}
@Test
public void requestWhenInterceptUrlMatchesMethodThenSecuresAccordingly() throws Exception {
this.spring.configLocations(xml("InterceptUrlMethod")).autowire();
this.mvc.perform(get("/protected").with(httpBasic("user", "password"))).andExpect(status().isOk());
this.mvc.perform(post("/protected").with(httpBasic("user", "password"))).andExpect(status().isForbidden());
this.mvc.perform(post("/protected").with(httpBasic("poster", "password"))).andExpect(status().isOk());
this.mvc.perform(delete("/protected").with(httpBasic("poster", "password"))).andExpect(status().isForbidden());
this.mvc.perform(delete("/protected").with(httpBasic("admin", "password"))).andExpect(status().isOk());
// @formatter:off
this.mvc.perform(get("/protected").with(userCredentials()))
.andExpect(status().isOk());
this.mvc.perform(post("/protected").with(userCredentials()))
.andExpect(status().isForbidden());
this.mvc.perform(post("/protected").with(postCredentials()))
.andExpect(status().isOk());
this.mvc.perform(delete("/protected").with(postCredentials()))
.andExpect(status().isForbidden());
this.mvc.perform(delete("/protected").with(adminCredentials()))
.andExpect(status().isOk());
// @formatter:on
}
@Test
public void requestWhenInterceptUrlMatchesMethodAndRequiresHttpsThenSecuresAccordingly() throws Exception {
this.spring.configLocations(xml("InterceptUrlMethodRequiresHttps")).autowire();
this.mvc.perform(post("/protected").with(csrf())).andExpect(status().isOk());
this.mvc.perform(get("/protected").secure(true).with(httpBasic("user", "password")))
.andExpect(status().isForbidden());
this.mvc.perform(get("/protected").secure(true).with(httpBasic("admin", "password")))
// @formatter:off
this.mvc.perform(post("/protected").with(csrf()))
.andExpect(status().isOk());
this.mvc.perform(get("/protected").secure(true).with(userCredentials()))
.andExpect(status().isForbidden());
this.mvc.perform(get("/protected").secure(true).with(adminCredentials()))
.andExpect(status().isOk());
// @formatter:on
}
@Test
public void requestWhenInterceptUrlMatchesAnyPatternAndRequiresHttpsThenSecuresAccordingly() throws Exception {
this.spring.configLocations(xml("InterceptUrlMethodRequiresHttpsAny")).autowire();
this.mvc.perform(post("/protected").with(csrf())).andExpect(status().isOk());
this.mvc.perform(get("/protected").secure(true).with(httpBasic("user", "password")))
.andExpect(status().isForbidden());
this.mvc.perform(get("/protected").secure(true).with(httpBasic("admin", "password")))
// @formatter:off
this.mvc.perform(post("/protected").with(csrf()))
.andExpect(status().isOk());
this.mvc.perform(get("/protected").secure(true).with(userCredentials()))
.andExpect(status().isForbidden());
this.mvc.perform(get("/protected").secure(true).with(adminCredentials()))
.andExpect(status().isOk());
// @formatter:on
}
@Test
@ -265,7 +317,10 @@ public class MiscHttpConfigTests {
public void requestWhenCustomHttpBasicEntryPointRefThenInvokesOnCommence() throws Exception {
this.spring.configLocations(xml("CustomHttpBasicEntryPointRef")).autowire();
AuthenticationEntryPoint entryPoint = this.spring.getContext().getBean(AuthenticationEntryPoint.class);
this.mvc.perform(get("/protected")).andExpect(status().isOk());
// @formatter:off
this.mvc.perform(get("/protected"))
.andExpect(status().isOk());
// @formatter:on
verify(entryPoint).commence(any(HttpServletRequest.class), any(HttpServletResponse.class),
any(AuthenticationException.class));
}
@ -279,8 +334,10 @@ public class MiscHttpConfigTests {
@Test
public void getWhenPortsMappedThenRedirectedAccordingly() throws Exception {
this.spring.configLocations(xml("PortsMappedInterceptUrlMethodRequiresAny")).autowire();
// @formatter:off
this.mvc.perform(get("http://localhost:9080/protected"))
.andExpect(redirectedUrl("https://localhost:9443/protected"));
// @formatter:on
}
@Test
@ -312,9 +369,11 @@ public class MiscHttpConfigTests {
public void getWhenUsingX509AndPropertyPlaceholderThenSubjectPrincipalRegexIsConfigured() throws Exception {
System.setProperty("subject_principal_regex", "OU=(.*?)(?:,|$)");
this.spring.configLocations(xml("X509")).autowire();
this.mvc.perform(get("/protected")
.with(x509("classpath:org/springframework/security/config/http/MiscHttpConfigTests-certificate.pem")))
RequestPostProcessor x509 = x509("classpath:org/springframework/security/config/http/MiscHttpConfigTests-certificate.pem");
// @formatter:off
this.mvc.perform(get("/protected").with(x509))
.andExpect(status().isOk());
// @formatter:on
}
@Test
@ -335,7 +394,10 @@ public class MiscHttpConfigTests {
@Test
public void logoutWhenSpecifyingSuccessHandlerRefThenResponseHandledAccordingly() throws Exception {
this.spring.configLocations(xml("LogoutSuccessHandlerRef")).autowire();
this.mvc.perform(post("/logout").with(csrf())).andExpect(redirectedUrl("/logoutSuccessEndpoint"));
// @formatter:off
this.mvc.perform(post("/logout").with(csrf()))
.andExpect(redirectedUrl("/logoutSuccessEndpoint"));
// @formatter:on
}
@Test
@ -374,8 +436,12 @@ public class MiscHttpConfigTests {
@Test
public void getWhenUsingTwoIdenticalInterceptUrlsThenTheSecondTakesPrecedence() throws Exception {
this.spring.configLocations(xml("Sec934")).autowire();
this.mvc.perform(get("/protected").with(httpBasic("user", "password"))).andExpect(status().isOk());
this.mvc.perform(get("/protected").with(httpBasic("admin", "password"))).andExpect(status().isForbidden());
// @formatter:off
this.mvc.perform(get("/protected").with(userCredentials()))
.andExpect(status().isOk());
this.mvc.perform(get("/protected").with(adminCredentials()))
.andExpect(status().isForbidden());
// @formatter:on
}
@Test
@ -384,8 +450,11 @@ public class MiscHttpConfigTests {
SecurityContextRepository repository = this.spring.getContext().getBean(SecurityContextRepository.class);
SecurityContext context = new SecurityContextImpl(new TestingAuthenticationToken("user", "password"));
given(repository.loadContext(any(HttpRequestResponseHolder.class))).willReturn(context);
MvcResult result = this.mvc.perform(get("/protected").with(httpBasic("user", "password")))
.andExpect(status().isOk()).andReturn();
// @formatter:off
MvcResult result = this.mvc.perform(get("/protected").with(userCredentials()))
.andExpect(status().isOk())
.andReturn();
// @formatter:on
assertThat(result.getRequest().getSession(false)).isNotNull();
verify(repository, atLeastOnce()).saveContext(any(SecurityContext.class), any(HttpServletRequest.class),
any(HttpServletResponse.class));
@ -394,9 +463,14 @@ public class MiscHttpConfigTests {
@Test
public void getWhenUsingInterceptUrlExpressionsThenAuthorizesAccordingly() throws Exception {
this.spring.configLocations(xml("InterceptUrlExpressions")).autowire();
this.mvc.perform(get("/protected").with(httpBasic("admin", "password"))).andExpect(status().isOk());
this.mvc.perform(get("/protected").with(httpBasic("user", "password"))).andExpect(status().isForbidden());
this.mvc.perform(get("/unprotected").with(httpBasic("user", "password"))).andExpect(status().isOk());
// @formatter:off
this.mvc.perform(get("/protected").with(adminCredentials()))
.andExpect(status().isOk());
this.mvc.perform(get("/protected").with(userCredentials()))
.andExpect(status().isForbidden());
this.mvc.perform(get("/unprotected").with(userCredentials()))
.andExpect(status().isOk());
// @formatter:on
}
@Test
@ -405,7 +479,10 @@ public class MiscHttpConfigTests {
PermissionEvaluator permissionEvaluator = this.spring.getContext().getBean(PermissionEvaluator.class);
given(permissionEvaluator.hasPermission(any(Authentication.class), any(Object.class), any(Object.class)))
.willReturn(false);
this.mvc.perform(get("/").with(httpBasic("user", "password"))).andExpect(status().isForbidden());
// @formatter:off
this.mvc.perform(get("/").with(userCredentials()))
.andExpect(status().isForbidden());
// @formatter:on
verify(permissionEvaluator).hasPermission(any(Authentication.class), any(Object.class), any(Object.class));
}
@ -449,21 +526,32 @@ public class MiscHttpConfigTests {
public void loginWhenConfiguredWithNoInternalAuthenticationProvidersThenSuccessfullyAuthenticates()
throws Exception {
this.spring.configLocations(xml("NoInternalAuthenticationProviders")).autowire();
this.mvc.perform(post("/login").param("username", "user").param("password", "password"))
// @formatter:off
MockHttpServletRequestBuilder loginRequest = post("/login")
.param("username", "user")
.param("password", "password");
this.mvc.perform(loginRequest)
.andExpect(redirectedUrl("/"));
// @formatter:on
}
@Test
public void loginWhenUsingDefaultsThenErasesCredentialsAfterAuthentication() throws Exception {
this.spring.configLocations(xml("HttpBasic")).autowire();
this.mvc.perform(get("/password").with(httpBasic("user", "password"))).andExpect(content().string(""));
// @formatter:off
this.mvc.perform(get("/password").with(userCredentials()))
.andExpect(content().string(""));
// @formatter:on
}
@Test
public void loginWhenAuthenticationManagerConfiguredToEraseCredentialsThenErasesCredentialsAfterAuthentication()
throws Exception {
this.spring.configLocations(xml("AuthenticationManagerEraseCredentials")).autowire();
this.mvc.perform(get("/password").with(httpBasic("user", "password"))).andExpect(content().string(""));
// @formatter:off
this.mvc.perform(get("/password").with(userCredentials()))
.andExpect(content().string(""));
// @formatter:on
}
/**
@ -473,14 +561,20 @@ public class MiscHttpConfigTests {
public void loginWhenAuthenticationManagerRefConfiguredToKeepCredentialsThenKeepsCredentialsAfterAuthentication()
throws Exception {
this.spring.configLocations(xml("AuthenticationManagerRefKeepCredentials")).autowire();
this.mvc.perform(get("/password").with(httpBasic("user", "password"))).andExpect(content().string("password"));
// @formatter:off
this.mvc.perform(get("/password").with(userCredentials()))
.andExpect(content().string("password"));
// @formatter:on
}
@Test
public void loginWhenAuthenticationManagerRefIsNotAProviderManagerThenKeepsCredentialsAccordingly()
throws Exception {
this.spring.configLocations(xml("AuthenticationManagerRefNotProviderManager")).autowire();
this.mvc.perform(get("/password").with(httpBasic("user", "password"))).andExpect(content().string("password"));
// @formatter:off
this.mvc.perform(get("/password").with(userCredentials()))
.andExpect(content().string("password"));
// @formatter:on
}
@Test
@ -488,12 +582,18 @@ public class MiscHttpConfigTests {
this.spring.configLocations(xml("JeeFilter")).autowire();
Principal user = mock(Principal.class);
given(user.getName()).willReturn("joe");
this.mvc.perform(get("/roles").principal(user).with((request) -> {
request.addUserRole("admin");
request.addUserRole("user");
request.addUserRole("unmapped");
return request;
})).andExpect(content().string("ROLE_admin,ROLE_user"));
// @formatter:off
MockHttpServletRequestBuilder rolesRequest = get("/roles")
.principal(user)
.with((request) -> {
request.addUserRole("admin");
request.addUserRole("user");
request.addUserRole("unmapped");
return request;
});
this.mvc.perform(rolesRequest)
.andExpect(content().string("ROLE_admin,ROLE_user"));
// @formatter:on
}
@Test
@ -503,15 +603,23 @@ public class MiscHttpConfigTests {
Object details = mock(Object.class);
AuthenticationDetailsSource source = this.spring.getContext().getBean(AuthenticationDetailsSource.class);
given(source.buildDetails(any(Object.class))).willReturn(details);
this.mvc.perform(get("/details").with(httpBasic("user", "password")))
RequestPostProcessor x509 = x509("classpath:org/springframework/security/config/http/MiscHttpConfigTests-certificate.pem");
// @formatter:off
this.mvc.perform(get("/details").with(userCredentials()))
.andExpect(content().string(details.getClass().getName()));
this.mvc.perform(get("/details")
.with(x509("classpath:org/springframework/security/config/http/MiscHttpConfigTests-certificate.pem")))
this.mvc.perform(get("/details").with(x509))
.andExpect(content().string(details.getClass().getName()));
MockHttpSession session = (MockHttpSession) this.mvc
.perform(post("/login").param("username", "user").param("password", "password").with(csrf()))
.andReturn().getRequest().getSession(false);
this.mvc.perform(get("/details").session(session)).andExpect(content().string(details.getClass().getName()));
MockHttpServletRequestBuilder loginRequest = post("/login")
.param("username", "user")
.param("password", "password")
.with(csrf());
MockHttpSession session = (MockHttpSession) this.mvc.perform(loginRequest)
.andReturn()
.getRequest()
.getSession(false);
this.mvc.perform(get("/details").session(session))
.andExpect(content().string(details.getClass().getName()));
// @formatter:on
assertThat(ReflectionTestUtils.getField(getFilter(OpenIDAuthenticationFilter.class),
"authenticationDetailsSource")).isEqualTo(source);
}
@ -521,7 +629,10 @@ public class MiscHttpConfigTests {
this.spring.configLocations(xml("Jaas")).autowire();
AuthorityGranter granter = this.spring.getContext().getBean(AuthorityGranter.class);
given(granter.grant(any(Principal.class))).willReturn(new HashSet<>(Arrays.asList("USER")));
this.mvc.perform(get("/username").with(httpBasic("user", "password"))).andExpect(content().string("user"));
// @formatter:off
this.mvc.perform(get("/username").with(userCredentials()))
.andExpect(content().string("user"));
// @formatter:on
}
@Test
@ -556,7 +667,10 @@ public class MiscHttpConfigTests {
@Test
public void getWhenUsingCustomAccessDecisionManagerThenAuthorizesAccordingly() throws Exception {
this.spring.configLocations(xml("CustomAccessDecisionManager")).autowire();
this.mvc.perform(get("/unprotected").with(httpBasic("user", "password"))).andExpect(status().isForbidden());
// @formatter:off
this.mvc.perform(get("/unprotected").with(userCredentials()))
.andExpect(status().isForbidden());
// @formatter:on
}
/**
@ -565,15 +679,25 @@ public class MiscHttpConfigTests {
@Test
public void authenticateWhenUsingPortMapperThenRedirectsAppropriately() throws Exception {
this.spring.configLocations(xml("PortsMappedRequiresHttps")).autowire();
// @formatter:off
MockHttpSession session = (MockHttpSession) this.mvc.perform(get("https://localhost:9080/protected"))
.andExpect(redirectedUrl("https://localhost:9443/login")).andReturn().getRequest().getSession(false);
session = (MockHttpSession) this.mvc
.perform(post("/login").param("username", "user").param("password", "password").session(session)
.with(csrf()))
.andExpect(redirectedUrl("https://localhost:9443/protected")).andReturn().getRequest()
.andExpect(redirectedUrl("https://localhost:9443/login"))
.andReturn()
.getRequest()
.getSession(false);
MockHttpServletRequestBuilder loginRequest = post("/login")
.param("username", "user")
.param("password", "password")
.session(session)
.with(csrf());
session = (MockHttpSession) this.mvc.perform(loginRequest)
.andExpect(redirectedUrl("https://localhost:9443/protected"))
.andReturn()
.getRequest()
.getSession(false);
this.mvc.perform(get("http://localhost:9080/protected").session(session))
.andExpect(redirectedUrl("https://localhost:9443/protected"));
// @formatter:on
}
private void redirectLogsTo(OutputStream os, Class<?> clazz) {
@ -624,6 +748,21 @@ public class MiscHttpConfigTests {
return proxy.getFilters(url);
}
@NotNull
private static RequestPostProcessor userCredentials() {
return httpBasic("user", "password");
}
@NotNull
private static RequestPostProcessor adminCredentials() {
return httpBasic("admin", "password");
}
@NotNull
private static RequestPostProcessor postCredentials() {
return httpBasic("poster", "password");
}
private static String xml(String configName) {
return CONFIG_LOCATION_PREFIX + "-" + configName + ".xml";
}

View File

@ -24,7 +24,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.config.test.SpringTestRule;
import org.springframework.stereotype.Controller;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.web.bind.annotation.GetMapping;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
@ -53,10 +53,17 @@ public class MultiHttpBlockConfigTests {
@Test
public void requestWhenUsingMutuallyExclusiveHttpElementsThenIsRoutedAccordingly() throws Exception {
this.spring.configLocations(this.xml("DistinctHttpElements")).autowire();
this.mvc.perform(MockMvcRequestBuilders.get("/first").with(httpBasic("user", "password")))
// @formatter:off
this.mvc.perform(get("/first").with(httpBasic("user", "password")))
.andExpect(status().isOk());
this.mvc.perform(post("/second/login").param("username", "user").param("password", "password").with(csrf()))
.andExpect(status().isFound()).andExpect(redirectedUrl("/"));
MockHttpServletRequestBuilder formLoginRequest = post("/second/login")
.param("username", "user")
.param("password", "password")
.with(csrf());
this.mvc.perform(formLoginRequest)
.andExpect(status().isFound())
.andExpect(redirectedUrl("/"));
// @formatter:on
}
@Test
@ -80,9 +87,19 @@ public class MultiHttpBlockConfigTests {
public void requestWhenTargettingAuthenticationManagersToCorrespondingHttpElementsThenAuthenticationProceeds()
throws Exception {
this.spring.configLocations(this.xml("Sec1937")).autowire();
this.mvc.perform(get("/first").with(httpBasic("first", "password")).with(csrf())).andExpect(status().isOk());
this.mvc.perform(post("/second/login").param("username", "second").param("password", "password").with(csrf()))
// @formatter:off
MockHttpServletRequestBuilder basicLoginRequest = get("/first")
.with(httpBasic("first", "password"))
.with(csrf());
this.mvc.perform(basicLoginRequest)
.andExpect(status().isOk());
MockHttpServletRequestBuilder formLoginRequest = post("/second/login")
.param("username", "second")
.param("password", "password")
.with(csrf());
this.mvc.perform(formLoginRequest)
.andExpect(redirectedUrl("/"));
// @formatter:on
}
private String xml(String configName) {

View File

@ -72,24 +72,23 @@ public class NamespaceHttpBasicTests {
@Test
public void httpBasicWithPasswordEncoder() throws Exception {
// @formatter:off
loadContext("<http>\n" +
" <intercept-url pattern=\"/**\" access=\"hasRole('USER')\" />\n" +
" <http-basic />\n" +
" </http>\n" +
"\n" +
" <authentication-manager id=\"authenticationManager\">\n" +
" <authentication-provider>\n" +
" <password-encoder ref=\"passwordEncoder\" />\n" +
" <user-service>\n" +
" <user name=\"user\" password=\"$2a$10$Zk1MxFEt7YYji4Ccy9xlfuewWzUMsmHZfy4UcCmNKVV6z5i/JNGJW\" authorities=\"ROLE_USER\"/>\n" +
" </user-service>\n" +
" </authentication-provider>\n" +
" </authentication-manager>\n" +
" <b:bean id=\"passwordEncoder\"\n" +
" class=\"org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder\" />");
// @formatter:on
this.request.addHeader("Authorization",
"Basic " + Base64.getEncoder().encodeToString("user:test".getBytes("UTF-8")));
loadContext("<http>\n"
+ " <intercept-url pattern=\"/**\" access=\"hasRole('USER')\" />\n"
+ " <http-basic />\n"
+ "</http>\n"
+ "\n"
+ "<authentication-manager id=\"authenticationManager\">\n"
+ " <authentication-provider>\n"
+ " <password-encoder ref=\"passwordEncoder\" />\n"
+ " <user-service>\n"
+ " <user name=\"user\" password=\"$2a$10$Zk1MxFEt7YYji4Ccy9xlfuewWzUMsmHZfy4UcCmNKVV6z5i/JNGJW\" authorities=\"ROLE_USER\"/>\n"
+ " </user-service>\n"
+ " </authentication-provider>\n"
+ "</authentication-manager>\n"
+ "<b:bean id=\"passwordEncoder\"\n"
+ " class=\"org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder\" />");
// @formatter:on
this.request.addHeader("Authorization", "Basic " + Base64.getEncoder().encodeToString("user:test".getBytes("UTF-8")));
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
}
@ -98,12 +97,12 @@ public class NamespaceHttpBasicTests {
@Test
public void httpBasicUnauthorizedOnDefault() throws Exception {
// @formatter:off
loadContext("<http>\n" +
" <intercept-url pattern=\"/**\" access=\"hasRole('USER')\" />\n" +
" <http-basic />\n" +
" </http>\n" +
"\n" +
" <authentication-manager />");
loadContext("<http>\n"
+ " <intercept-url pattern=\"/**\" access=\"hasRole('USER')\" />\n"
+ " <http-basic />\n"
+ "</http>\n"
+ "\n"
+ "<authentication-manager />");
// @formatter:on
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);

View File

@ -100,8 +100,11 @@ public class OAuth2ClientBeanDefinitionParserTests {
@Test
public void requestWhenAuthorizeThenRedirect() throws Exception {
this.spring.configLocations(xml("Minimal")).autowire();
MvcResult result = this.mvc.perform(get("/oauth2/authorization/google")).andExpect(status().is3xxRedirection())
// @formatter:off
MvcResult result = this.mvc.perform(get("/oauth2/authorization/google"))
.andExpect(status().is3xxRedirection())
.andReturn();
// @formatter:on
assertThat(result.getResponse().getRedirectedUrl()).matches(
"https://accounts.google.com/o/oauth2/v2/auth\\?" + "response_type=code&client_id=google-client-id&"
+ "scope=scope1%20scope2&state=.{15,}&redirect_uri=http://localhost/callback/google");
@ -110,12 +113,20 @@ public class OAuth2ClientBeanDefinitionParserTests {
@Test
public void requestWhenCustomClientRegistrationRepositoryThenCalled() throws Exception {
this.spring.configLocations(xml("CustomClientRegistrationRepository")).autowire();
// @formatter:off
ClientRegistration clientRegistration = CommonOAuth2Provider.GOOGLE.getBuilder("google")
.clientId("google-client-id").clientSecret("google-client-secret")
.redirectUri("http://localhost/callback/google").scope("scope1", "scope2").build();
.clientId("google-client-id")
.clientSecret("google-client-secret")
.redirectUri("http://localhost/callback/google")
.scope("scope1", "scope2")
.build();
// @formatter:on
given(this.clientRegistrationRepository.findByRegistrationId(any())).willReturn(clientRegistration);
MvcResult result = this.mvc.perform(get("/oauth2/authorization/google")).andExpect(status().is3xxRedirection())
// @formatter:off
MvcResult result = this.mvc.perform(get("/oauth2/authorization/google"))
.andExpect(status().is3xxRedirection())
.andReturn();
// @formatter:on
assertThat(result.getResponse().getRedirectedUrl()).matches(
"https://accounts.google.com/o/oauth2/v2/auth\\?" + "response_type=code&client_id=google-client-id&"
+ "scope=scope1%20scope2&state=.{15,}&redirect_uri=http://localhost/callback/google");
@ -128,10 +139,13 @@ public class OAuth2ClientBeanDefinitionParserTests {
ClientRegistration clientRegistration = this.clientRegistrationRepository.findByRegistrationId("google");
OAuth2AuthorizationRequest authorizationRequest = createAuthorizationRequest(clientRegistration);
given(this.authorizationRequestResolver.resolve(any())).willReturn(authorizationRequest);
this.mvc.perform(get("/oauth2/authorization/google")).andExpect(status().is3xxRedirection())
// @formatter:off
this.mvc.perform(get("/oauth2/authorization/google"))
.andExpect(status().is3xxRedirection())
.andExpect(redirectedUrl("https://accounts.google.com/o/oauth2/v2/auth?"
+ "response_type=code&client_id=google-client-id&"
+ "scope=scope1%20scope2&state=state&redirect_uri=http://localhost/callback/google"));
// @formatter:on
verify(this.authorizationRequestResolver).resolve(any());
}
@ -148,8 +162,11 @@ public class OAuth2ClientBeanDefinitionParserTests {
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("code", "code123");
params.add("state", authorizationRequest.getState());
// @formatter:off
this.mvc.perform(get(authorizationRequest.getRedirectUri()).params(params))
.andExpect(status().is3xxRedirection()).andExpect(redirectedUrl(authorizationRequest.getRedirectUri()));
.andExpect(status().is3xxRedirection())
.andExpect(redirectedUrl(authorizationRequest.getRedirectUri()));
// @formatter:on
ArgumentCaptor<OAuth2AuthorizedClient> authorizedClientCaptor = ArgumentCaptor
.forClass(OAuth2AuthorizedClient.class);
verify(this.authorizedClientRepository).saveAuthorizedClient(authorizedClientCaptor.capture(), any(), any(),
@ -173,8 +190,11 @@ public class OAuth2ClientBeanDefinitionParserTests {
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("code", "code123");
params.add("state", authorizationRequest.getState());
// @formatter:off
this.mvc.perform(get(authorizationRequest.getRedirectUri()).params(params))
.andExpect(status().is3xxRedirection()).andExpect(redirectedUrl(authorizationRequest.getRedirectUri()));
.andExpect(status().is3xxRedirection())
.andExpect(redirectedUrl(authorizationRequest.getRedirectUri()));
// @formatter:on
verify(this.authorizedClientService).saveAuthorizedClient(any(), any());
}
@ -192,10 +212,15 @@ public class OAuth2ClientBeanDefinitionParserTests {
private static OAuth2AuthorizationRequest createAuthorizationRequest(ClientRegistration clientRegistration) {
Map<String, Object> attributes = new HashMap<>();
attributes.put(OAuth2ParameterNames.REGISTRATION_ID, clientRegistration.getRegistrationId());
// @formatter:off
return OAuth2AuthorizationRequest.authorizationCode()
.authorizationUri(clientRegistration.getProviderDetails().getAuthorizationUri())
.clientId(clientRegistration.getClientId()).redirectUri(clientRegistration.getRedirectUri())
.scopes(clientRegistration.getScopes()).state("state").attributes(attributes).build();
.scopes(clientRegistration.getScopes())
.state("state")
.attributes(attributes)
.build();
// @formatter:on
}
private static String xml(String configName) {

View File

@ -144,7 +144,11 @@ public class OAuth2LoginBeanDefinitionParserTests {
@Test
public void requestLoginWhenMultiClientRegistrationThenReturnLoginPageWithClients() throws Exception {
this.spring.configLocations(this.xml("MultiClientRegistration")).autowire();
MvcResult result = this.mvc.perform(get("/login")).andExpect(status().is2xxSuccessful()).andReturn();
// @formatter:off
MvcResult result = this.mvc.perform(get("/login"))
.andExpect(status().is2xxSuccessful())
.andReturn();
// @formatter:on
assertThat(result.getResponse().getContentAsString())
.contains("<a href=\"/oauth2/authorization/google-login\">Google</a>");
assertThat(result.getResponse().getContentAsString())
@ -155,8 +159,11 @@ public class OAuth2LoginBeanDefinitionParserTests {
@Test
public void requestWhenSingleClientRegistrationThenAutoRedirect() throws Exception {
this.spring.configLocations(this.xml("SingleClientRegistration")).autowire();
this.mvc.perform(get("/")).andExpect(status().is3xxRedirection())
// @formatter:off
this.mvc.perform(get("/"))
.andExpect(status().is3xxRedirection())
.andExpect(redirectedUrl("http://localhost/oauth2/authorization/google-login"));
// @formatter:on
verify(this.requestCache).saveRequest(any(), any());
}
@ -165,8 +172,11 @@ public class OAuth2LoginBeanDefinitionParserTests {
public void requestWhenSingleClientRegistrationAndRequestFaviconNotAuthenticatedThenRedirectDefaultLoginPage()
throws Exception {
this.spring.configLocations(this.xml("SingleClientRegistration")).autowire();
this.mvc.perform(get("/favicon.ico").accept(new MediaType("image", "*"))).andExpect(status().is3xxRedirection())
// @formatter:off
this.mvc.perform(get("/favicon.ico").accept(new MediaType("image", "*")))
.andExpect(status().is3xxRedirection())
.andExpect(redirectedUrl("http://localhost/login"));
// @formatter:on
}
// gh-6812
@ -174,8 +184,11 @@ public class OAuth2LoginBeanDefinitionParserTests {
public void requestWhenSingleClientRegistrationAndRequestXHRNotAuthenticatedThenDoesNotRedirectForAuthorization()
throws Exception {
this.spring.configLocations(this.xml("SingleClientRegistration")).autowire();
this.mvc.perform(get("/").header("X-Requested-With", "XMLHttpRequest")).andExpect(status().is3xxRedirection())
// @formatter:off
this.mvc.perform(get("/").header("X-Requested-With", "XMLHttpRequest"))
.andExpect(status().is3xxRedirection())
.andExpect(redirectedUrl("http://localhost/login"));
// @formatter:on
}
@Test
@ -211,7 +224,10 @@ public class OAuth2LoginBeanDefinitionParserTests {
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("code", "code123");
params.add("state", authorizationRequest.getState());
this.mvc.perform(get("/login/oauth2/code/github-login").params(params)).andExpect(status().is2xxSuccessful());
// @formatter:off
this.mvc.perform(get("/login/oauth2/code/github-login").params(params))
.andExpect(status().is2xxSuccessful());
// @formatter:on
ArgumentCaptor<Authentication> authenticationCaptor = ArgumentCaptor.forClass(Authentication.class);
verify(this.authenticationSuccessHandler).onAuthenticationSuccess(any(), any(), authenticationCaptor.capture());
Authentication authentication = authenticationCaptor.getValue();
@ -257,8 +273,11 @@ public class OAuth2LoginBeanDefinitionParserTests {
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("code", "code123");
params.add("state", authorizationRequest.getState());
this.mvc.perform(get("/login/oauth2/code/google-login").params(params)).andExpect(status().is3xxRedirection())
// @formatter:off
this.mvc.perform(get("/login/oauth2/code/google-login").params(params))
.andExpect(status().is3xxRedirection())
.andExpect(redirectedUrl("/"));
// @formatter:on
verify(this.jwtDecoderFactory).createDecoder(any());
verify(this.requestCache).getRequest(any(), any());
}
@ -302,7 +321,10 @@ public class OAuth2LoginBeanDefinitionParserTests {
given(this.jwtDecoderFactory.createDecoder(any())).willReturn((token) -> jwt);
given(this.userAuthoritiesMapper.mapAuthorities(any()))
.willReturn((Collection) AuthorityUtils.createAuthorityList("ROLE_OIDC_USER"));
this.mvc.perform(get("/login/oauth2/code/google-login").params(params)).andExpect(status().is2xxSuccessful());
// @formatter:off
this.mvc.perform(get("/login/oauth2/code/google-login").params(params))
.andExpect(status().is2xxSuccessful());
// @formatter:on
authenticationCaptor = ArgumentCaptor.forClass(Authentication.class);
verify(this.authenticationSuccessHandler, times(2)).onAuthenticationSuccess(any(), any(),
authenticationCaptor.capture());
@ -330,7 +352,10 @@ public class OAuth2LoginBeanDefinitionParserTests {
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("code", "code123");
params.add("state", authorizationRequest.getState());
this.mvc.perform(get("/login/oauth2/github-login").params(params)).andExpect(status().is2xxSuccessful());
// @formatter:off
this.mvc.perform(get("/login/oauth2/github-login").params(params))
.andExpect(status().is2xxSuccessful());
// @formatter:on
ArgumentCaptor<Authentication> authenticationCaptor = ArgumentCaptor.forClass(Authentication.class);
verify(this.authenticationSuccessHandler).onAuthenticationSuccess(any(), any(), authenticationCaptor.capture());
Authentication authentication = authenticationCaptor.getValue();
@ -342,7 +367,10 @@ public class OAuth2LoginBeanDefinitionParserTests {
public void requestWhenCustomAuthorizationRequestResolverThenCalled() throws Exception {
this.spring.configLocations(this.xml("SingleClientRegistration-WithCustomAuthorizationRequestResolver"))
.autowire();
this.mvc.perform(get("/oauth2/authorization/google-login")).andExpect(status().is3xxRedirection());
// @formatter:off
this.mvc.perform(get("/oauth2/authorization/google-login"))
.andExpect(status().is3xxRedirection());
// @formatter:on
verify(this.authorizationRequestResolver).resolve(any());
}
@ -350,15 +378,21 @@ public class OAuth2LoginBeanDefinitionParserTests {
@Test
public void requestWhenMultiClientRegistrationThenRedirectDefaultLoginPage() throws Exception {
this.spring.configLocations(this.xml("MultiClientRegistration")).autowire();
this.mvc.perform(get("/")).andExpect(status().is3xxRedirection())
// @formatter:off
this.mvc.perform(get("/"))
.andExpect(status().is3xxRedirection())
.andExpect(redirectedUrl("http://localhost/login"));
// @formatter:on
}
@Test
public void requestWhenCustomLoginPageThenRedirectCustomLoginPage() throws Exception {
this.spring.configLocations(this.xml("SingleClientRegistration-WithCustomLoginPage")).autowire();
this.mvc.perform(get("/")).andExpect(status().is3xxRedirection())
// @formatter:off
this.mvc.perform(get("/"))
.andExpect(status().is3xxRedirection())
.andExpect(redirectedUrl("http://localhost/custom-login"));
// @formatter:on
}
// gh-6802
@ -366,8 +400,11 @@ public class OAuth2LoginBeanDefinitionParserTests {
public void requestWhenSingleClientRegistrationAndFormLoginConfiguredThenRedirectDefaultLoginPage()
throws Exception {
this.spring.configLocations(this.xml("SingleClientRegistration-WithFormLogin")).autowire();
this.mvc.perform(get("/")).andExpect(status().is3xxRedirection())
// @formatter:off
this.mvc.perform(get("/"))
.andExpect(status().is3xxRedirection())
.andExpect(redirectedUrl("http://localhost/login"));
// @formatter:on
}
@Test
@ -444,7 +481,11 @@ public class OAuth2LoginBeanDefinitionParserTests {
OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient(clientRegistration, "user",
TestOAuth2AccessTokens.noScopes());
given(this.authorizedClientRepository.loadAuthorizedClient(any(), any(), any())).willReturn(authorizedClient);
this.mvc.perform(get("/authorized-client")).andExpect(status().isOk()).andExpect(content().string("resolved"));
// @formatter:off
this.mvc.perform(get("/authorized-client"))
.andExpect(status().isOk())
.andExpect(content().string("resolved"));
// @formatter:on
}
private String xml(String configName) {

View File

@ -50,6 +50,7 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.w3c.dom.Element;
import org.springframework.beans.factory.DisposableBean;
@ -137,7 +138,10 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
this.spring.configLocations(xml("JwtRestOperations"), xml("Jwt")).autowire();
mockRestOperations(jwks("Default"));
String token = this.token("ValidNoScopes");
this.mvc.perform(get("/").header("Authorization", "Bearer " + token)).andExpect(status().isNotFound());
// @formatter:off
this.mvc.perform(get("/").header("Authorization", "Bearer " + token))
.andExpect(status().isNotFound());
// @formatter:on
}
@Test
@ -145,7 +149,10 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
this.spring.configLocations(xml("WebServer"), xml("JwkSetUri")).autowire();
mockWebServer(jwks("Default"));
String token = this.token("ValidNoScopes");
this.mvc.perform(get("/").header("Authorization", "Bearer " + token)).andExpect(status().isNotFound());
// @formatter:off
this.mvc.perform(get("/").header("Authorization", "Bearer " + token))
.andExpect(status().isNotFound());
// @formatter:on
}
@Test
@ -153,8 +160,11 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
this.spring.configLocations(xml("JwtRestOperations"), xml("Jwt")).autowire();
mockRestOperations(jwks("Default"));
String token = this.token("Expired");
this.mvc.perform(get("/").header("Authorization", "Bearer " + token)).andExpect(status().isUnauthorized())
// @formatter:off
this.mvc.perform(get("/").header("Authorization", "Bearer " + token))
.andExpect(status().isUnauthorized())
.andExpect(invalidTokenHeader("An error occurred while attempting to decode the Jwt"));
// @formatter:on
}
@Test
@ -162,8 +172,11 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
this.spring.configLocations(xml("JwtRestOperations"), xml("Jwt")).autowire();
mockRestOperations("malformed");
String token = this.token("ValidNoScopes");
this.mvc.perform(get("/").header("Authorization", "Bearer " + token)).andExpect(status().isUnauthorized())
// @formatter:off
this.mvc.perform(get("/").header("Authorization", "Bearer " + token))
.andExpect(status().isUnauthorized())
.andExpect(header().string("WWW-Authenticate", "Bearer"));
// @formatter:on
}
@Test
@ -171,15 +184,21 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
this.spring.configLocations(xml("WebServer"), xml("JwkSetUri")).autowire();
this.web.shutdown();
String token = this.token("ValidNoScopes");
this.mvc.perform(get("/").header("Authorization", "Bearer " + token)).andExpect(status().isUnauthorized())
// @formatter:off
this.mvc.perform(get("/").header("Authorization", "Bearer " + token))
.andExpect(status().isUnauthorized())
.andExpect(header().string("WWW-Authenticate", "Bearer"));
// @formatter:on
}
@Test
public void getWhenMalformedBearerTokenThenInvalidToken() throws Exception {
this.spring.configLocations(xml("JwkSetUri")).autowire();
// @formatter:off
this.mvc.perform(get("/").header("Authorization", "Bearer an\"invalid\"token"))
.andExpect(status().isUnauthorized()).andExpect(invalidTokenHeader("Bearer token is malformed"));
.andExpect(status().isUnauthorized())
.andExpect(invalidTokenHeader("Bearer token is malformed"));
// @formatter:on
}
@Test
@ -187,17 +206,22 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
this.spring.configLocations(xml("JwtRestOperations"), xml("Jwt")).autowire();
mockRestOperations(jwks("Default"));
String token = this.token("MalformedPayload");
this.mvc.perform(get("/").header("Authorization", "Bearer " + token)).andExpect(status().isUnauthorized())
.andExpect(
invalidTokenHeader("An error occurred while attempting to decode the Jwt: Malformed payload"));
// @formatter:off
this.mvc.perform(get("/").header("Authorization", "Bearer " + token))
.andExpect(status().isUnauthorized())
.andExpect(invalidTokenHeader("An error occurred while attempting to decode the Jwt: Malformed payload"));
// @formatter:on
}
@Test
public void getWhenUnsignedBearerTokenThenInvalidToken() throws Exception {
this.spring.configLocations(xml("JwkSetUri")).autowire();
String token = this.token("Unsigned");
this.mvc.perform(get("/").header("Authorization", "Bearer " + token)).andExpect(status().isUnauthorized())
// @formatter:off
this.mvc.perform(get("/").header("Authorization", "Bearer " + token))
.andExpect(status().isUnauthorized())
.andExpect(invalidTokenHeader("Unsupported algorithm of none"));
// @formatter:on
}
@Test
@ -205,16 +229,21 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
this.spring.configLocations(xml("JwtRestOperations"), xml("Jwt")).autowire();
this.mockRestOperations(jwks("Default"));
String token = this.token("TooEarly");
this.mvc.perform(get("/").header("Authorization", "Bearer " + token)).andExpect(status().isUnauthorized())
// @formatter:off
this.mvc.perform(get("/").header("Authorization", "Bearer " + token))
.andExpect(status().isUnauthorized())
.andExpect(invalidTokenHeader("An error occurred while attempting to decode the Jwt"));
// @formatter:on
}
@Test
public void getWhenBearerTokenInTwoPlacesThenInvalidRequest() throws Exception {
this.spring.configLocations(xml("JwkSetUri")).autowire();
// @formatter:off
this.mvc.perform(get("/").header("Authorization", "Bearer token").param("access_token", "token"))
.andExpect(status().isBadRequest())
.andExpect(invalidRequestHeader("Found multiple bearer tokens in the request"));
// @formatter:on
}
@Test
@ -223,8 +252,11 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("access_token", "token1");
params.add("access_token", "token2");
this.mvc.perform(get("/").params(params)).andExpect(status().isBadRequest())
// @formatter:off
this.mvc.perform(get("/").params(params))
.andExpect(status().isBadRequest())
.andExpect(invalidRequestHeader("Found multiple bearer tokens in the request"));
// @formatter:on
}
@Test
@ -240,8 +272,11 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
@Test
public void getWhenNoBearerTokenThenUnauthorized() throws Exception {
this.spring.configLocations(xml("JwkSetUri")).autowire();
this.mvc.perform(get("/")).andExpect(status().isUnauthorized())
// @formatter:off
this.mvc.perform(get("/"))
.andExpect(status().isUnauthorized())
.andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, "Bearer"));
// @formatter:on
}
@Test
@ -249,8 +284,10 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
this.spring.configLocations(xml("JwtRestOperations"), xml("Jwt")).autowire();
mockRestOperations(jwks("Default"));
String token = this.token("ValidMessageReadScope");
// @formatter:off
this.mvc.perform(get("/requires-read-scope").header("Authorization", "Bearer " + token))
.andExpect(status().isNotFound());
// @formatter:on
}
@Test
@ -258,8 +295,11 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
this.spring.configLocations(xml("JwtRestOperations"), xml("Jwt")).autowire();
mockRestOperations(jwks("Default"));
String token = this.token("ValidNoScopes");
// @formatter:off
this.mvc.perform(get("/requires-read-scope").header("Authorization", "Bearer " + token))
.andExpect(status().isForbidden()).andExpect(insufficientScopeHeader());
.andExpect(status().isForbidden())
.andExpect(insufficientScopeHeader());
// @formatter:on
}
@Test
@ -267,8 +307,11 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
this.spring.configLocations(xml("JwtRestOperations"), xml("Jwt")).autowire();
mockRestOperations(jwks("Default"));
String token = this.token("ValidMessageWriteScp");
// @formatter:off
this.mvc.perform(get("/requires-read-scope").header("Authorization", "Bearer " + token))
.andExpect(status().isForbidden()).andExpect(insufficientScopeHeader());
.andExpect(status().isForbidden())
.andExpect(insufficientScopeHeader());
// @formatter:on
}
@Test
@ -276,8 +319,11 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
this.spring.configLocations(xml("JwtRestOperations"), xml("Jwt")).autowire();
mockRestOperations(jwks("Empty"));
String token = this.token("ValidNoScopes");
this.mvc.perform(get("/").header("Authorization", "Bearer " + token)).andExpect(status().isUnauthorized())
// @formatter:off
this.mvc.perform(get("/").header("Authorization", "Bearer " + token))
.andExpect(status().isUnauthorized())
.andExpect(invalidTokenHeader("An error occurred while attempting to decode the Jwt"));
// @formatter:on
}
@Test
@ -285,8 +331,10 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
this.spring.configLocations(xml("JwtRestOperations"), xml("Jwt")).autowire();
mockRestOperations(jwks("TwoKeys"));
String token = this.token("ValidNoScopes");
// @formatter:off
this.mvc.perform(get("/authenticated").header("Authorization", "Bearer " + token))
.andExpect(status().isNotFound());
// @formatter:on
}
@Test
@ -294,8 +342,10 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
this.spring.configLocations(xml("JwtRestOperations"), xml("Jwt")).autowire();
mockRestOperations(jwks("TwoKeys"));
String token = this.token("Kid");
// @formatter:off
this.mvc.perform(get("/authenticated").header("Authorization", "Bearer " + token))
.andExpect(status().isNotFound());
// @formatter:on
}
@Test
@ -303,17 +353,21 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
this.spring.configLocations(xml("JwtRestOperations"), xml("Jwt")).autowire();
mockRestOperations(jwks("Default"));
String token = this.token("ValidNoScopes");
// @formatter:off
this.mvc.perform(post("/authenticated").header("Authorization", "Bearer " + token))
.andExpect(status().isNotFound());
// @formatter:on
}
@Test
public void postWhenNoBearerTokenThenCsrfDenies() throws Exception {
this.spring.configLocations(xml("JwkSetUri")).autowire();
this.mvc.perform(post("/authenticated")).andExpect(status().isForbidden())
.andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, "Bearer")); // different
// from
// DSL
// @formatter:off
this.mvc.perform(post("/authenticated"))
.andExpect(status().isForbidden())
// different from DSL
.andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, "Bearer"));
// @formatter:on
}
@Test
@ -321,9 +375,11 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
this.spring.configLocations(xml("JwtRestOperations"), xml("Jwt")).autowire();
mockRestOperations(jwks("Default"));
String token = this.token("Expired");
// @formatter:off
this.mvc.perform(post("/authenticated").header("Authorization", "Bearer " + token))
.andExpect(status().isUnauthorized())
.andExpect(invalidTokenHeader("An error occurred while attempting to decode the Jwt"));
// @formatter:on
}
@Test
@ -331,8 +387,11 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
this.spring.configLocations(xml("JwtRestOperations"), xml("Jwt")).autowire();
mockRestOperations(jwks("Default"));
String token = this.token("ValidNoScopes");
// @formatter:off
MvcResult result = this.mvc.perform(get("/").header("Authorization", "Bearer " + token))
.andExpect(status().isNotFound()).andReturn();
.andExpect(status().isNotFound())
.andReturn();
// @formatter:on
assertThat(result.getRequest().getSession(false)).isNull();
}
@ -340,15 +399,22 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
public void requestWhenIntrospectionThenSessionIsNotCreated() throws Exception {
this.spring.configLocations(xml("WebServer"), xml("IntrospectionUri")).autowire();
mockWebServer(json("Active"));
// @formatter:off
MvcResult result = this.mvc.perform(get("/authenticated").header("Authorization", "Bearer token"))
.andExpect(status().isNotFound()).andReturn();
.andExpect(status().isNotFound())
.andReturn();
// @formatter:on
assertThat(result.getRequest().getSession(false)).isNull();
}
@Test
public void requestWhenNoBearerTokenThenSessionIsCreated() throws Exception {
this.spring.configLocations(xml("JwkSetUri")).autowire();
MvcResult result = this.mvc.perform(get("/")).andExpect(status().isUnauthorized()).andReturn();
// @formatter:off
MvcResult result = this.mvc.perform(get("/"))
.andExpect(status().isUnauthorized())
.andReturn();
// @formatter:on
assertThat(result.getRequest().getSession(false)).isNotNull();
}
@ -357,8 +423,11 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
this.spring.configLocations(xml("JwtRestOperations"), xml("AlwaysSessionCreation")).autowire();
mockRestOperations(jwks("Default"));
String token = this.token("ValidNoScopes");
// @formatter:off
MvcResult result = this.mvc.perform(get("/").header("Authorization", "Bearer " + token))
.andExpect(status().isNotFound()).andReturn();
.andExpect(status().isNotFound())
.andReturn();
// @formatter:on
assertThat(result.getRequest().getSession(false)).isNotNull();
}
@ -381,9 +450,12 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
this.spring.configLocations(xml("MockJwtDecoder"), xml("AllowBearerTokenInBody")).autowire();
JwtDecoder decoder = this.spring.getContext().getBean(JwtDecoder.class);
given(decoder.decode(anyString())).willReturn(TestJwts.jwt().build());
// @formatter:off
this.mvc.perform(get("/authenticated").header("Authorization", "Bearer token"))
.andExpect(status().isNotFound());
this.mvc.perform(post("/authenticated").param("access_token", "token")).andExpect(status().isNotFound());
this.mvc.perform(post("/authenticated").param("access_token", "token"))
.andExpect(status().isNotFound());
// @formatter:on
}
@Test
@ -392,9 +464,12 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
this.spring.configLocations(xml("MockJwtDecoder"), xml("AllowBearerTokenInQuery")).autowire();
JwtDecoder decoder = this.spring.getContext().getBean(JwtDecoder.class);
given(decoder.decode(anyString())).willReturn(TestJwts.jwt().build());
// @formatter:off
this.mvc.perform(get("/authenticated").header("Authorization", "Bearer token"))
.andExpect(status().isNotFound());
this.mvc.perform(get("/authenticated").param("access_token", "token")).andExpect(status().isNotFound());
this.mvc.perform(get("/authenticated").param("access_token", "token"))
.andExpect(status().isNotFound());
// @formatter:on
verify(decoder, times(2)).decode("token");
}
@ -402,18 +477,29 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
public void requestWhenBearerTokenResolverAllowsRequestBodyAndRequestContainsTwoTokensThenInvalidRequest()
throws Exception {
this.spring.configLocations(xml("MockJwtDecoder"), xml("AllowBearerTokenInBody")).autowire();
this.mvc.perform(post("/authenticated").param("access_token", "token").header("Authorization", "Bearer token")
.with(csrf())).andExpect(status().isBadRequest())
// @formatter:off
MockHttpServletRequestBuilder request = post("/authenticated")
.param("access_token", "token")
.header("Authorization", "Bearer token")
.with(csrf());
this.mvc.perform(request)
.andExpect(status().isBadRequest())
.andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, containsString("invalid_request")));
// @formatter:on
}
@Test
public void requestWhenBearerTokenResolverAllowsQueryParameterAndRequestContainsTwoTokensThenInvalidRequest()
throws Exception {
this.spring.configLocations(xml("MockJwtDecoder"), xml("AllowBearerTokenInQuery")).autowire();
this.mvc.perform(get("/authenticated").header("Authorization", "Bearer token").param("access_token", "token"))
// @formatter:off
MockHttpServletRequestBuilder request = get("/authenticated")
.header("Authorization", "Bearer token")
.param("access_token", "token");
this.mvc.perform(request)
.andExpect(status().isBadRequest())
.andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, containsString("invalid_request")));
// @formatter:on
}
@Test
@ -444,9 +530,11 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
this.spring.configLocations(xml("MockJwtDecoder"), xml("AuthenticationEntryPoint")).autowire();
JwtDecoder decoder = this.spring.getContext().getBean(JwtDecoder.class);
Mockito.when(decoder.decode(anyString())).thenThrow(JwtException.class);
// @formatter:off
this.mvc.perform(get("/authenticated").header("Authorization", "Bearer invalid_token"))
.andExpect(status().isUnauthorized())
.andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, startsWith("Bearer realm=\"myRealm\"")));
// @formatter:on
}
@Test
@ -454,9 +542,11 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
this.spring.configLocations(xml("MockJwtDecoder"), xml("AccessDeniedHandler")).autowire();
JwtDecoder decoder = this.spring.getContext().getBean(JwtDecoder.class);
given(decoder.decode(anyString())).willReturn(TestJwts.jwt().build());
// @formatter:off
this.mvc.perform(get("/authenticated").header("Authorization", "Bearer insufficiently_scoped"))
.andExpect(status().isForbidden())
.andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, startsWith("Bearer realm=\"myRealm\"")));
// @formatter:on
}
@Test
@ -467,8 +557,11 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
OAuth2TokenValidator<Jwt> jwtValidator = this.spring.getContext().getBean(OAuth2TokenValidator.class);
OAuth2Error error = new OAuth2Error("custom-error", "custom-description", "custom-uri");
given(jwtValidator.validate(any(Jwt.class))).willReturn(OAuth2TokenValidatorResult.failure(error));
this.mvc.perform(get("/").header("Authorization", "Bearer " + token)).andExpect(status().isUnauthorized())
// @formatter:off
this.mvc.perform(get("/").header("Authorization", "Bearer " + token))
.andExpect(status().isUnauthorized())
.andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, containsString("custom-description")));
// @formatter:on
}
@Test
@ -476,7 +569,10 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
this.spring.configLocations(xml("UnexpiredJwtClockSkew"), xml("Jwt")).autowire();
mockRestOperations(jwks("Default"));
String token = this.token("ExpiresAt4687177990");
this.mvc.perform(get("/").header("Authorization", "Bearer " + token)).andExpect(status().isNotFound());
// @formatter:off
this.mvc.perform(get("/").header("Authorization", "Bearer " + token))
.andExpect(status().isNotFound());
// @formatter:on
}
@Test
@ -484,8 +580,11 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
this.spring.configLocations(xml("ExpiredJwtClockSkew"), xml("Jwt")).autowire();
mockRestOperations(jwks("Default"));
String token = this.token("ExpiresAt4687177990");
this.mvc.perform(get("/").header("Authorization", "Bearer " + token)).andExpect(status().isUnauthorized())
// @formatter:off
this.mvc.perform(get("/").header("Authorization", "Bearer " + token))
.andExpect(status().isUnauthorized())
.andExpect(invalidTokenHeader("Jwt expired at"));
// @formatter:on
}
@Test
@ -498,7 +597,10 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
.willReturn(new JwtAuthenticationToken(TestJwts.jwt().build(), Collections.emptyList()));
JwtDecoder jwtDecoder = this.spring.getContext().getBean(JwtDecoder.class);
given(jwtDecoder.decode(anyString())).willReturn(TestJwts.jwt().build());
this.mvc.perform(get("/").header("Authorization", "Bearer token")).andExpect(status().isNotFound());
// @formatter:off
this.mvc.perform(get("/").header("Authorization", "Bearer token"))
.andExpect(status().isNotFound());
// @formatter:on
verify(jwtAuthenticationConverter).convert(any(Jwt.class));
}
@ -506,49 +608,64 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
public void requestWhenUsingPublicKeyAndValidTokenThenAuthenticates() throws Exception {
this.spring.configLocations(xml("SingleKey"), xml("Jwt")).autowire();
String token = this.token("ValidNoScopes");
this.mvc.perform(get("/").header("Authorization", "Bearer " + token)).andExpect(status().isNotFound());
// @formatter:off
this.mvc.perform(get("/").header("Authorization", "Bearer " + token))
.andExpect(status().isNotFound());
// @formatter:on
}
@Test
public void requestWhenUsingPublicKeyAndSignatureFailsThenReturnsInvalidToken() throws Exception {
this.spring.configLocations(xml("SingleKey"), xml("Jwt")).autowire();
String token = this.token("WrongSignature");
// @formatter:off
this.mvc.perform(get("/").header("Authorization", "Bearer " + token))
.andExpect(invalidTokenHeader("signature"));
// @formatter:on
}
@Test
public void requestWhenUsingPublicKeyAlgorithmDoesNotMatchThenReturnsInvalidToken() throws Exception {
this.spring.configLocations(xml("SingleKey"), xml("Jwt")).autowire();
String token = this.token("WrongAlgorithm");
// @formatter:off
this.mvc.perform(get("/").header("Authorization", "Bearer " + token))
.andExpect(invalidTokenHeader("algorithm"));
// @formatter:on
}
@Test
public void getWhenIntrospectingThenOk() throws Exception {
this.spring.configLocations(xml("OpaqueTokenRestOperations"), xml("OpaqueToken")).autowire();
mockRestOperations(json("Active"));
// @formatter:off
this.mvc.perform(get("/authenticated").header("Authorization", "Bearer token"))
.andExpect(status().isNotFound());
// @formatter:on
}
@Test
public void getWhenIntrospectionFailsThenUnauthorized() throws Exception {
this.spring.configLocations(xml("OpaqueTokenRestOperations"), xml("OpaqueToken")).autowire();
mockRestOperations(json("Inactive"));
this.mvc.perform(get("/").header("Authorization", "Bearer token")).andExpect(status().isUnauthorized())
.andExpect(
header().string(HttpHeaders.WWW_AUTHENTICATE, containsString("Provided token isn't active")));
// @formatter:off
MockHttpServletRequestBuilder request = get("/")
.header("Authorization", "Bearer token");
this.mvc.perform(request)
.andExpect(status().isUnauthorized())
.andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, containsString("Provided token isn't active")));
// @formatter:on
}
@Test
public void getWhenIntrospectionLacksScopeThenForbidden() throws Exception {
this.spring.configLocations(xml("OpaqueTokenRestOperations"), xml("OpaqueToken")).autowire();
mockRestOperations(json("ActiveNoScopes"));
// @formatter:off
this.mvc.perform(get("/requires-read-scope").header("Authorization", "Bearer token"))
.andExpect(status().isForbidden())
.andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, containsString("scope")));
// @formatter:on
}
@Test
@ -570,7 +687,10 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
.getBean(AuthenticationManagerResolver.class);
given(authenticationManagerResolver.resolve(any(HttpServletRequest.class))).willReturn(
(authentication) -> new JwtAuthenticationToken(TestJwts.jwt().build(), Collections.emptyList()));
this.mvc.perform(get("/").header("Authorization", "Bearer token")).andExpect(status().isNotFound());
// @formatter:off
this.mvc.perform(get("/").header("Authorization", "Bearer token"))
.andExpect(status().isNotFound());
// @formatter:on
verify(authenticationManagerResolver).resolve(any(HttpServletRequest.class));
}
@ -589,16 +709,23 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
String jwtThree = jwtFromIssuer(issuerThree);
mockWebServer(String.format(metadata, issuerOne, issuerOne));
mockWebServer(jwkSet);
// @formatter:off
this.mvc.perform(get("/authenticated").header("Authorization", "Bearer " + jwtOne))
.andExpect(status().isNotFound());
// @formatter:on
mockWebServer(String.format(metadata, issuerTwo, issuerTwo));
mockWebServer(jwkSet);
// @formatter:off
this.mvc.perform(get("/authenticated").header("Authorization", "Bearer " + jwtTwo))
.andExpect(status().isNotFound());
// @formatter:on
mockWebServer(String.format(metadata, issuerThree, issuerThree));
mockWebServer(jwkSet);
// @formatter:off
this.mvc.perform(get("/authenticated").header("Authorization", "Bearer " + jwtThree))
.andExpect(status().isUnauthorized()).andExpect(invalidTokenHeader("Invalid issuer"));
.andExpect(status().isUnauthorized())
.andExpect(invalidTokenHeader("Invalid issuer"));
// @formatter:on
}
@Test
@ -607,13 +734,17 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
this.spring.configLocations(xml("MockJwtDecoder"), xml("BasicAndResourceServer")).autowire();
JwtDecoder decoder = this.spring.getContext().getBean(JwtDecoder.class);
given(decoder.decode(anyString())).willThrow(JwtException.class);
this.mvc.perform(get("/authenticated").with(httpBasic("some", "user"))).andExpect(status().isUnauthorized())
// @formatter:off
this.mvc.perform(get("/authenticated").with(httpBasic("some", "user")))
.andExpect(status().isUnauthorized())
.andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, startsWith("Basic")));
this.mvc.perform(get("/authenticated")).andExpect(status().isUnauthorized())
this.mvc.perform(get("/authenticated"))
.andExpect(status().isUnauthorized())
.andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, startsWith("Bearer")));
this.mvc.perform(get("/authenticated").header("Authorization", "Bearer invalid_token"))
.andExpect(status().isUnauthorized())
.andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, startsWith("Bearer")));
// @formatter:on
}
@Test
@ -624,8 +755,11 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
given(decoder.decode(anyString())).willThrow(JwtException.class);
MvcResult result = this.mvc.perform(get("/authenticated")).andExpect(status().isUnauthorized()).andReturn();
assertThat(result.getRequest().getSession(false)).isNotNull();
// @formatter:off
result = this.mvc.perform(get("/authenticated").header("Authorization", "Bearer token"))
.andExpect(status().isUnauthorized()).andReturn();
.andExpect(status().isUnauthorized())
.andReturn();
// @formatter:on
assertThat(result.getRequest().getSession(false)).isNull();
}
@ -634,9 +768,12 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
this.spring.configLocations(xml("JwtRestOperations"), xml("BasicAndResourceServer")).autowire();
mockRestOperations(jwks("Default"));
String token = this.token("ValidNoScopes");
// @formatter:off
this.mvc.perform(get("/authenticated").header("Authorization", "Bearer " + token))
.andExpect(status().isNotFound());
this.mvc.perform(get("/authenticated").with(httpBasic("user", "password"))).andExpect(status().isNotFound());
this.mvc.perform(get("/authenticated").with(httpBasic("user", "password")))
.andExpect(status().isNotFound());
// @formatter:on
}
@Test

View File

@ -40,6 +40,7 @@ import org.springframework.security.web.FilterChainProxy;
import org.springframework.security.web.authentication.rememberme.AbstractRememberMeServices;
import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@ -73,21 +74,32 @@ public class OpenIDConfigTests {
@Test
public void requestWhenOpenIDAndFormLoginBothConfiguredThenRedirectsToGeneratedLoginPage() throws Exception {
this.spring.configLocations(this.xml("WithFormLogin")).autowire();
this.mvc.perform(get("/")).andExpect(status().isFound()).andExpect(redirectedUrl("http://localhost/login"));
// @formatter:off
this.mvc.perform(get("/"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("http://localhost/login"));
// @formatter:on
assertThat(getFilter(DefaultLoginPageGeneratingFilter.class)).isNotNull();
}
@Test
public void requestWhenOpenIDAndFormLoginWithFormLoginPageConfiguredThenFormLoginPageWins() throws Exception {
this.spring.configLocations(this.xml("WithFormLoginPage")).autowire();
this.mvc.perform(get("/")).andExpect(status().isFound()).andExpect(redirectedUrl("http://localhost/form-page"));
// @formatter:off
this.mvc.perform(get("/"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("http://localhost/form-page"));
// @formatter:on
}
@Test
public void requestWhenOpenIDAndFormLoginWithOpenIDLoginPageConfiguredThenOpenIDLoginPageWins() throws Exception {
this.spring.configLocations(this.xml("WithOpenIDLoginPageAndFormLogin")).autowire();
this.mvc.perform(get("/")).andExpect(status().isFound())
// @formatter:off
this.mvc.perform(get("/"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("http://localhost/openid-page"));
// @formatter:on
}
@Test
@ -110,13 +122,20 @@ public class OpenIDConfigTests {
openIDFilter.setConsumer(consumer);
String expectedReturnTo = new StringBuilder("http://localhost/login/openid").append("?")
.append(AbstractRememberMeServices.DEFAULT_PARAMETER).append("=").append("on").toString();
this.mvc.perform(get("/")).andExpect(status().isFound()).andExpect(redirectedUrl("http://localhost/login"));
this.mvc.perform(get("/login")).andExpect(status().isOk())
// @formatter:off
this.mvc.perform(get("/"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("http://localhost/login"));
this.mvc.perform(get("/login"))
.andExpect(status().isOk())
.andExpect(content().string(containsString(AbstractRememberMeServices.DEFAULT_PARAMETER)));
this.mvc.perform(get("/login/openid")
MockHttpServletRequestBuilder openidLogin = get("/login/openid")
.param(OpenIDAuthenticationFilter.DEFAULT_CLAIMED_IDENTITY_FIELD, "https://ww1.openid.com")
.param(AbstractRememberMeServices.DEFAULT_PARAMETER, "on")).andExpect(status().isFound())
.param(AbstractRememberMeServices.DEFAULT_PARAMETER, "on");
this.mvc.perform(openidLogin)
.andExpect(status().isFound())
.andExpect(redirectedUrl(openIdEndpointUrl + expectedReturnTo));
// @formatter:on
}
@Test
@ -131,8 +150,7 @@ public class OpenIDConfigTests {
server.enqueue(new MockResponse().addHeader(YadisResolver.YADIS_XRDS_LOCATION, endpoint));
server.enqueue(new MockResponse()
.setBody(String.format("<XRDS><XRD><Service><URI>%s</URI></Service></XRD></XRDS>", endpoint)));
this.mvc.perform(
get("/login/openid").param(OpenIDAuthenticationFilter.DEFAULT_CLAIMED_IDENTITY_FIELD, endpoint))
this.mvc.perform(get("/login/openid").param(OpenIDAuthenticationFilter.DEFAULT_CLAIMED_IDENTITY_FIELD, endpoint))
.andExpect(status().isFound())
.andExpect((result) -> result.getResponse().getRedirectedUrl().endsWith(
"openid.ext1.type.nickname=http%3A%2F%2Fschema.openid.net%2FnamePerson%2Ffriendly&"
@ -150,7 +168,11 @@ public class OpenIDConfigTests {
throws Exception {
this.spring.configLocations(this.xml("Sec2919")).autowire();
assertThat(getFilter(DefaultLoginPageGeneratingFilter.class)).isNull();
this.mvc.perform(get("/login")).andExpect(status().isOk()).andExpect(content().string("a custom login page"));
// @formatter:off
this.mvc.perform(get("/login"))
.andExpect(status().isOk())
.andExpect(content().string("a custom login page"));
// @formatter:on
}
private <T extends Filter> T getFilter(Class<T> clazz) {

View File

@ -54,7 +54,10 @@ public class PlaceHolderAndELConfigTests {
public void getWhenUsingPlaceholderThenUnsecuredPatternCorrectlyConfigured() throws Exception {
System.setProperty("pattern.nofilters", "/unsecured");
this.spring.configLocations(this.xml("UnsecuredPattern")).autowire();
this.mvc.perform(get("/unsecured")).andExpect(status().isOk());
// @formatter:off
this.mvc.perform(get("/unsecured"))
.andExpect(status().isOk());
// @formatter:on
}
/**
@ -69,7 +72,9 @@ public class PlaceHolderAndELConfigTests {
System.setProperty("auth.failure", "/authFailure");
this.spring.configLocations(this.xml("InterceptUrlAndFormLogin")).autowire();
// login-page setting
this.mvc.perform(get("/secured")).andExpect(redirectedUrl("http://localhost/loginPage"));
// @formatter:off
this.mvc.perform(get("/secured"))
.andExpect(redirectedUrl("http://localhost/loginPage"));
// login-processing-url setting
// default-target-url setting
this.mvc.perform(post("/loginPage").param("username", "user").param("password", "password"))
@ -77,6 +82,7 @@ public class PlaceHolderAndELConfigTests {
// authentication-failure-url setting
this.mvc.perform(post("/loginPage").param("username", "user").param("password", "wrong"))
.andExpect(redirectedUrl("/authFailure"));
// @formatter:on
}
/**
@ -91,7 +97,9 @@ public class PlaceHolderAndELConfigTests {
System.setProperty("auth.failure", "/authFailure");
this.spring.configLocations(this.xml("InterceptUrlAndFormLoginWithSpEL")).autowire();
// login-page setting
this.mvc.perform(get("/secured")).andExpect(redirectedUrl("http://localhost/loginPage"));
// @formatter:off
this.mvc.perform(get("/secured"))
.andExpect(redirectedUrl("http://localhost/loginPage"));
// login-processing-url setting
// default-target-url setting
this.mvc.perform(post("/loginPage").param("username", "user").param("password", "password"))
@ -99,6 +107,7 @@ public class PlaceHolderAndELConfigTests {
// authentication-failure-url setting
this.mvc.perform(post("/loginPage").param("username", "user").param("password", "wrong"))
.andExpect(redirectedUrl("/authFailure"));
// @formatter:on
}
@Test
@ -107,10 +116,14 @@ public class PlaceHolderAndELConfigTests {
System.setProperty("http", "9080");
System.setProperty("https", "9443");
this.spring.configLocations(this.xml("PortMapping")).autowire();
this.mvc.perform(get("http://localhost:9080/secured")).andExpect(status().isFound())
// @formatter:off
this.mvc.perform(get("http://localhost:9080/secured"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("https://localhost:9443/secured"));
this.mvc.perform(get("https://localhost:9443/unsecured")).andExpect(status().isFound())
this.mvc.perform(get("https://localhost:9443/unsecured"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("http://localhost:9080/unsecured"));
// @formatter:on
}
@Test
@ -119,8 +132,11 @@ public class PlaceHolderAndELConfigTests {
System.setProperty("secure.url", "/secured");
System.setProperty("required.channel", "https");
this.spring.configLocations(this.xml("RequiresChannel")).autowire();
this.mvc.perform(get("http://localhost/secured")).andExpect(status().isFound())
// @formatter:off
this.mvc.perform(get("http://localhost/secured"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("https://localhost/secured"));
// @formatter:on
}
@Test
@ -128,14 +144,20 @@ public class PlaceHolderAndELConfigTests {
public void requestWhenUsingPlaceholderThenAccessDeniedPageWorks() throws Exception {
System.setProperty("accessDenied", "/go-away");
this.spring.configLocations(this.xml("AccessDeniedPage")).autowire();
this.mvc.perform(get("/secured")).andExpect(forwardedUrl("/go-away"));
// @formatter:off
this.mvc.perform(get("/secured"))
.andExpect(forwardedUrl("/go-away"));
// @formatter:on
}
@Test
@WithMockUser
public void requestWhenUsingSpELThenAccessDeniedPageWorks() throws Exception {
this.spring.configLocations(this.xml("AccessDeniedPageWithSpEL")).autowire();
this.mvc.perform(get("/secured")).andExpect(forwardedUrl("/go-away"));
// @formatter:off
this.mvc.perform(get("/secured"))
.andExpect(forwardedUrl("/go-away"));
// @formatter:on
}
private String xml(String configName) {

View File

@ -69,12 +69,17 @@ public class RememberMeConfigTests {
@Test
public void requestWithRememberMeWhenUsingCustomTokenRepositoryThenAutomaticallyReauthenticates() throws Exception {
this.spring.configLocations(this.xml("WithTokenRepository")).autowire();
MvcResult result = this.rememberAuthentication("user", "password")
this.spring.configLocations(xml("WithTokenRepository")).autowire();
// @formatter:off
MvcResult result = rememberAuthentication("user", "password")
.andExpect(cookie().secure(AbstractRememberMeServices.SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY, false))
.andReturn();
// @formatter:on
Cookie cookie = rememberMeCookie(result);
this.mvc.perform(get("/authenticated").cookie(cookie)).andExpect(status().isOk());
// @formatter:off
this.mvc.perform(get("/authenticated").cookie(cookie))
.andExpect(status().isOk());
// @formatter:on
JdbcTemplate template = this.spring.getContext().getBean(JdbcTemplate.class);
int count = template.queryForObject("select count(*) from persistent_logins", int.class);
assertThat(count).isEqualTo(1);
@ -82,30 +87,40 @@ public class RememberMeConfigTests {
@Test
public void requestWithRememberMeWhenUsingCustomDataSourceThenAutomaticallyReauthenticates() throws Exception {
this.spring.configLocations(this.xml("WithDataSource")).autowire();
this.spring.configLocations(xml("WithDataSource")).autowire();
TestDataSource dataSource = this.spring.getContext().getBean(TestDataSource.class);
JdbcTemplate template = new JdbcTemplate(dataSource);
template.execute(JdbcTokenRepositoryImpl.CREATE_TABLE_SQL);
MvcResult result = this.rememberAuthentication("user", "password")
// @formatter:off
MvcResult result = rememberAuthentication("user", "password")
.andExpect(cookie().secure(AbstractRememberMeServices.SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY, false))
.andReturn();
// @formatter:on
Cookie cookie = rememberMeCookie(result);
this.mvc.perform(get("/authenticated").cookie(cookie)).andExpect(status().isOk());
// @formatter:off
this.mvc.perform(get("/authenticated").cookie(cookie))
.andExpect(status().isOk());
// @formatter:on
int count = template.queryForObject("select count(*) from persistent_logins", int.class);
assertThat(count).isEqualTo(1);
}
@Test
public void requestWithRememberMeWhenUsingAuthenticationSuccessHandlerThenInvokesHandler() throws Exception {
this.spring.configLocations(this.xml("WithAuthenticationSuccessHandler")).autowire();
this.spring.configLocations(xml("WithAuthenticationSuccessHandler")).autowire();
TestDataSource dataSource = this.spring.getContext().getBean(TestDataSource.class);
JdbcTemplate template = new JdbcTemplate(dataSource);
template.execute(JdbcTokenRepositoryImpl.CREATE_TABLE_SQL);
MvcResult result = this.rememberAuthentication("user", "password")
// @formatter:off
MvcResult result = rememberAuthentication("user", "password")
.andExpect(cookie().secure(AbstractRememberMeServices.SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY, false))
.andReturn();
// @formatter:on
Cookie cookie = rememberMeCookie(result);
this.mvc.perform(get("/authenticated").cookie(cookie)).andExpect(redirectedUrl("/target"));
// @formatter:off
this.mvc.perform(get("/authenticated").cookie(cookie))
.andExpect(redirectedUrl("/target"));
// @formatter:on
int count = template.queryForObject("select count(*) from persistent_logins", int.class);
assertThat(count).isEqualTo(1);
}
@ -113,64 +128,78 @@ public class RememberMeConfigTests {
@Test
public void requestWithRememberMeWhenUsingCustomRememberMeServicesThenAuthenticates() throws Exception {
// SEC-1281 - using key with external services
this.spring.configLocations(this.xml("WithServicesRef")).autowire();
MvcResult result = this.rememberAuthentication("user", "password")
this.spring.configLocations(xml("WithServicesRef")).autowire();
// @formatter:off
MvcResult result = rememberAuthentication("user", "password")
.andExpect(cookie().secure(AbstractRememberMeServices.SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY, false))
.andExpect(cookie().maxAge(AbstractRememberMeServices.SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY, 5000))
.andReturn();
// @formatter:on
Cookie cookie = rememberMeCookie(result);
this.mvc.perform(get("/authenticated").cookie(cookie)).andExpect(status().isOk());
// @formatter:off
this.mvc.perform(get("/authenticated").cookie(cookie))
.andExpect(status().isOk());
// SEC-909
this.mvc.perform(post("/logout").cookie(cookie).with(csrf()))
.andExpect(cookie().maxAge(AbstractRememberMeServices.SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY, 0))
.andReturn();
// @formatter:on
}
@Test
public void logoutWhenUsingRememberMeDefaultsThenCookieIsCancelled() throws Exception {
this.spring.configLocations(this.xml("DefaultConfig")).autowire();
MvcResult result = this.rememberAuthentication("user", "password").andReturn();
this.spring.configLocations(xml("DefaultConfig")).autowire();
MvcResult result = rememberAuthentication("user", "password").andReturn();
Cookie cookie = rememberMeCookie(result);
// @formatter:off
this.mvc.perform(post("/logout").cookie(cookie).with(csrf()))
.andExpect(cookie().maxAge(AbstractRememberMeServices.SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY, 0));
// @formatter:on
}
@Test
public void requestWithRememberMeWhenTokenValidityIsConfiguredThenCookieReflectsCorrectExpiration()
throws Exception {
this.spring.configLocations(this.xml("TokenValidity")).autowire();
MvcResult result = this.rememberAuthentication("user", "password")
this.spring.configLocations(xml("TokenValidity")).autowire();
// @formatter:off
MvcResult result = rememberAuthentication("user", "password")
.andExpect(cookie().maxAge(AbstractRememberMeServices.SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY, 10000))
.andReturn();
// @formatter:on
Cookie cookie = rememberMeCookie(result);
this.mvc.perform(get("/authenticated").cookie(cookie)).andExpect(status().isOk());
// @formatter:off
this.mvc.perform(get("/authenticated").cookie(cookie))
.andExpect(status().isOk());
// @formatter:on
}
@Test
public void requestWithRememberMeWhenTokenValidityIsNegativeThenCookieReflectsCorrectExpiration() throws Exception {
this.spring.configLocations(this.xml("NegativeTokenValidity")).autowire();
this.rememberAuthentication("user", "password")
this.spring.configLocations(xml("NegativeTokenValidity")).autowire();
// @formatter:off
rememberAuthentication("user", "password")
.andExpect(cookie().maxAge(AbstractRememberMeServices.SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY, -1));
// @formatter:on
}
@Test
public void configureWhenUsingDataSourceAndANegativeTokenValidityThenThrowsWiringException() {
assertThatExceptionOfType(FatalBeanException.class).isThrownBy(
() -> this.spring.configLocations(this.xml("NegativeTokenValidityWithDataSource")).autowire());
() -> this.spring.configLocations(xml("NegativeTokenValidityWithDataSource")).autowire());
}
@Test
public void requestWithRememberMeWhenTokenValidityIsResolvedByPropertyPlaceholderThenCookieReflectsCorrectExpiration()
throws Exception {
this.spring.configLocations(this.xml("Sec2165")).autowire();
this.rememberAuthentication("user", "password")
this.spring.configLocations(xml("Sec2165")).autowire();
rememberAuthentication("user", "password")
.andExpect(cookie().maxAge(AbstractRememberMeServices.SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY, 30));
}
@Test
public void requestWithRememberMeWhenUseSecureCookieIsTrueThenCookieIsSecure() throws Exception {
this.spring.configLocations(this.xml("SecureCookie")).autowire();
this.rememberAuthentication("user", "password")
this.spring.configLocations(xml("SecureCookie")).autowire();
rememberAuthentication("user", "password")
.andExpect(cookie().secure(AbstractRememberMeServices.SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY, true));
}
@ -179,27 +208,30 @@ public class RememberMeConfigTests {
*/
@Test
public void requestWithRememberMeWhenUseSecureCookieIsFalseThenCookieIsNotSecure() throws Exception {
this.spring.configLocations(this.xml("Sec1827")).autowire();
this.rememberAuthentication("user", "password")
this.spring.configLocations(xml("Sec1827")).autowire();
rememberAuthentication("user", "password")
.andExpect(cookie().secure(AbstractRememberMeServices.SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY, false));
}
@Test
public void configureWhenUsingPersistentTokenRepositoryAndANegativeTokenValidityThenThrowsWiringException() {
assertThatExceptionOfType(BeanDefinitionParsingException.class).isThrownBy(() -> this.spring
.configLocations(this.xml("NegativeTokenValidityWithPersistentRepository")).autowire());
.configLocations(xml("NegativeTokenValidityWithPersistentRepository")).autowire());
}
@Test
public void requestWithRememberMeWhenUsingCustomUserDetailsServiceThenInvokesThisUserDetailsService()
throws Exception {
this.spring.configLocations(this.xml("WithUserDetailsService")).autowire();
this.spring.configLocations(xml("WithUserDetailsService")).autowire();
UserDetailsService userDetailsService = this.spring.getContext().getBean(UserDetailsService.class);
given(userDetailsService.loadUserByUsername("user"))
.willAnswer((invocation) -> new User("user", "{noop}password", Collections.emptyList()));
MvcResult result = this.rememberAuthentication("user", "password").andReturn();
MvcResult result = rememberAuthentication("user", "password").andReturn();
Cookie cookie = rememberMeCookie(result);
this.mvc.perform(get("/authenticated").cookie(cookie)).andExpect(status().isOk());
// @formatter:off
this.mvc.perform(get("/authenticated").cookie(cookie))
.andExpect(status().isOk());
// @formatter:on
verify(userDetailsService, atLeastOnce()).loadUserByUsername("user");
}
@ -208,11 +240,17 @@ public class RememberMeConfigTests {
*/
@Test
public void requestWithRememberMeWhenExcludingBasicAuthenticationFilterThenStillReauthenticates() throws Exception {
this.spring.configLocations(this.xml("Sec742")).autowire();
this.spring.configLocations(xml("Sec742")).autowire();
// @formatter:off
MvcResult result = this.mvc.perform(login("user", "password").param("remember-me", "true").with(csrf()))
.andExpect(redirectedUrl("/messageList.html")).andReturn();
.andExpect(redirectedUrl("/messageList.html"))
.andReturn();
// @formatter:on
Cookie cookie = rememberMeCookie(result);
this.mvc.perform(get("/authenticated").cookie(cookie)).andExpect(status().isOk());
// @formatter:off
this.mvc.perform(get("/authenticated").cookie(cookie))
.andExpect(status().isOk());
// @formatter:on
}
/**
@ -220,18 +258,26 @@ public class RememberMeConfigTests {
*/
@Test
public void requestWithRememberMeWhenUsingCustomRememberMeParameterThenReauthenticates() throws Exception {
this.spring.configLocations(this.xml("WithRememberMeParameter")).autowire();
MvcResult result = this.mvc
.perform(login("user", "password").param("custom-remember-me-parameter", "true").with(csrf()))
.andExpect(redirectedUrl("/")).andReturn();
this.spring.configLocations(xml("WithRememberMeParameter")).autowire();
// @formatter:off
MockHttpServletRequestBuilder request = login("user", "password")
.param("custom-remember-me-parameter", "true")
.with(csrf());
MvcResult result = this.mvc.perform(request)
.andExpect(redirectedUrl("/"))
.andReturn();
// @formatter:on
Cookie cookie = rememberMeCookie(result);
this.mvc.perform(get("/authenticated").cookie(cookie)).andExpect(status().isOk());
// @formatter:off
this.mvc.perform(get("/authenticated").cookie(cookie))
.andExpect(status().isOk());
// @formatter:on
}
@Test
public void configureWhenUsingRememberMeParameterAndServicesRefThenThrowsWiringException() {
assertThatExceptionOfType(BeanDefinitionParsingException.class).isThrownBy(
() -> this.spring.configLocations(this.xml("WithRememberMeParameterAndServicesRef")).autowire());
() -> this.spring.configLocations(xml("WithRememberMeParameterAndServicesRef")).autowire());
}
/**
@ -239,8 +285,11 @@ public class RememberMeConfigTests {
*/
@Test
public void authenticateWhenUsingCustomRememberMeCookieNameThenIssuesCookieWithThatName() throws Exception {
this.spring.configLocations(this.xml("WithRememberMeCookie")).autowire();
this.rememberAuthentication("user", "password").andExpect(cookie().exists("custom-remember-me-cookie"));
this.spring.configLocations(xml("WithRememberMeCookie")).autowire();
// @formatter:off
rememberAuthentication("user", "password")
.andExpect(cookie().exists("custom-remember-me-cookie"));
// @formatter:on
}
/**
@ -250,7 +299,7 @@ public class RememberMeConfigTests {
public void configureWhenUsingRememberMeCookieAndServicesRefThenThrowsWiringException() {
assertThatExceptionOfType(BeanDefinitionParsingException.class)
.isThrownBy(
() -> this.spring.configLocations(this.xml("WithRememberMeCookieAndServicesRef")).autowire())
() -> this.spring.configLocations(xml("WithRememberMeCookieAndServicesRef")).autowire())
.withMessageContaining(
"Configuration problem: services-ref can't be used in combination with attributes "
+ "token-repository-ref,data-source-ref, user-service-ref, token-validity-seconds, "
@ -258,13 +307,21 @@ public class RememberMeConfigTests {
}
private ResultActions rememberAuthentication(String username, String password) throws Exception {
return this.mvc.perform(
login(username, password).param(AbstractRememberMeServices.DEFAULT_PARAMETER, "true").with(csrf()))
// @formatter:off
MockHttpServletRequestBuilder request = login(username, password)
.param(AbstractRememberMeServices.DEFAULT_PARAMETER, "true")
.with(csrf());
return this.mvc.perform(request)
.andExpect(redirectedUrl("/"));
// @formatter:on
}
private static MockHttpServletRequestBuilder login(String username, String password) {
return post("/login").param("username", username).param("password", password);
// @formatter:off
return post("/login")
.param("username", username)
.param("password", password);
// @formatter:on
}
private static Cookie rememberMeCookie(MvcResult result) {

View File

@ -67,14 +67,21 @@ public class SecurityContextHolderAwareRequestConfigTests {
@Test
public void servletLoginWhenUsingDefaultConfigurationThenUsesSpringSecurity() throws Exception {
this.spring.configLocations(this.xml("Simple")).autowire();
this.mvc.perform(get("/good-login")).andExpect(status().isOk()).andExpect(content().string("user"));
// @formatter:off
this.mvc.perform(get("/good-login"))
.andExpect(status().isOk())
.andExpect(content().string("user"));
// @formatter:on
}
@Test
public void servletAuthenticateWhenUsingDefaultConfigurationThenUsesSpringSecurity() throws Exception {
this.spring.configLocations(this.xml("Simple")).autowire();
this.mvc.perform(get("/authenticate")).andExpect(status().isFound())
// @formatter:off
this.mvc.perform(get("/authenticate"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("http://localhost/login"));
// @formatter:on
}
@Test
@ -83,8 +90,12 @@ public class SecurityContextHolderAwareRequestConfigTests {
MvcResult result = this.mvc.perform(get("/good-login")).andReturn();
MockHttpSession session = (MockHttpSession) result.getRequest().getSession(false);
assertThat(session).isNotNull();
result = this.mvc.perform(get("/do-logout").session(session)).andExpect(status().isOk())
.andExpect(content().string("")).andReturn();
// @formatter:off
result = this.mvc.perform(get("/do-logout").session(session))
.andExpect(status().isOk())
.andExpect(content().string(""))
.andReturn();
// @formatter:on
session = (MockHttpSession) result.getRequest().getSession(false);
assertThat(session).isNull();
}
@ -92,31 +103,47 @@ public class SecurityContextHolderAwareRequestConfigTests {
@Test
public void servletAuthenticateWhenUsingHttpBasicThenUsesSpringSecurity() throws Exception {
this.spring.configLocations(this.xml("HttpBasic")).autowire();
this.mvc.perform(get("/authenticate")).andExpect(status().isUnauthorized())
// @formatter:off
this.mvc.perform(get("/authenticate"))
.andExpect(status().isUnauthorized())
.andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, containsString("discworld")));
// @formatter:on
}
@Test
public void servletAuthenticateWhenUsingFormLoginThenUsesSpringSecurity() throws Exception {
this.spring.configLocations(this.xml("FormLogin")).autowire();
this.mvc.perform(get("/authenticate")).andExpect(status().isFound())
// @formatter:off
this.mvc.perform(get("/authenticate"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("http://localhost/login"));
// @formatter:on
}
@Test
public void servletLoginWhenUsingMultipleHttpConfigsThenUsesSpringSecurity() throws Exception {
this.spring.configLocations(this.xml("MultiHttp")).autowire();
this.mvc.perform(get("/good-login")).andExpect(status().isOk()).andExpect(content().string("user"));
this.mvc.perform(get("/v2/good-login")).andExpect(status().isOk()).andExpect(content().string("user2"));
// @formatter:off
this.mvc.perform(get("/good-login"))
.andExpect(status().isOk())
.andExpect(content().string("user"));
this.mvc.perform(get("/v2/good-login"))
.andExpect(status().isOk())
.andExpect(content().string("user2"));
// @formatter:on
}
@Test
public void servletAuthenticateWhenUsingMultipleHttpConfigsThenUsesSpringSecurity() throws Exception {
this.spring.configLocations(this.xml("MultiHttp")).autowire();
this.mvc.perform(get("/authenticate")).andExpect(status().isFound())
// @formatter:off
this.mvc.perform(get("/authenticate"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("http://localhost/login"));
this.mvc.perform(get("/v2/authenticate")).andExpect(status().isFound())
this.mvc.perform(get("/v2/authenticate"))
.andExpect(status().isFound())
.andExpect(redirectedUrl("http://localhost/login2"));
// @formatter:on
}
@Test
@ -125,15 +152,26 @@ public class SecurityContextHolderAwareRequestConfigTests {
MvcResult result = this.mvc.perform(get("/good-login")).andReturn();
MockHttpSession session = (MockHttpSession) result.getRequest().getSession(false);
assertThat(session).isNotNull();
result = this.mvc.perform(get("/do-logout").session(session)).andExpect(status().isOk())
.andExpect(content().string("")).andReturn();
// @formatter:off
result = this.mvc.perform(get("/do-logout").session(session))
.andExpect(status().isOk())
.andExpect(content().string(""))
.andReturn();
// @formatter:on
session = (MockHttpSession) result.getRequest().getSession(false);
assertThat(session).isNotNull();
result = this.mvc.perform(get("/v2/good-login")).andReturn();
// @formatter:off
result = this.mvc.perform(get("/v2/good-login"))
.andReturn();
// @formatter:on
session = (MockHttpSession) result.getRequest().getSession(false);
assertThat(session).isNotNull();
result = this.mvc.perform(get("/v2/do-logout").session(session)).andExpect(status().isOk())
.andExpect(content().string("")).andReturn();
// @formatter:off
result = this.mvc.perform(get("/v2/do-logout").session(session))
.andExpect(status().isOk())
.andExpect(content().string(""))
.andReturn();
// @formatter:on
session = (MockHttpSession) result.getRequest().getSession(false);
assertThat(session).isNull();
}
@ -143,11 +181,19 @@ public class SecurityContextHolderAwareRequestConfigTests {
this.spring.configLocations(this.xml("Logout")).autowire();
this.mvc.perform(get("/authenticate")).andExpect(status().isFound())
.andExpect(redirectedUrl("http://localhost/signin"));
MvcResult result = this.mvc.perform(get("/good-login")).andReturn();
// @formatter:off
MvcResult result = this.mvc.perform(get("/good-login"))
.andReturn();
// @formatter:on
MockHttpSession session = (MockHttpSession) result.getRequest().getSession(false);
assertThat(session).isNotNull();
result = this.mvc.perform(get("/do-logout").session(session)).andExpect(status().isOk())
.andExpect(content().string("")).andExpect(cookie().maxAge("JSESSIONID", 0)).andReturn();
// @formatter:off
result = this.mvc.perform(get("/do-logout").session(session))
.andExpect(status().isOk())
.andExpect(content().string(""))
.andExpect(cookie().maxAge("JSESSIONID", 0))
.andReturn();
// @formatter:on
session = (MockHttpSession) result.getRequest().getSession(false);
assertThat(session).isNotNull();
}
@ -159,7 +205,10 @@ public class SecurityContextHolderAwareRequestConfigTests {
@WithMockUser
public void servletIsUserInRoleWhenUsingDefaultConfigThenRoleIsSet() throws Exception {
this.spring.configLocations(this.xml("Simple")).autowire();
this.mvc.perform(get("/role")).andExpect(content().string("true"));
// @formatter:off
this.mvc.perform(get("/role"))
.andExpect(content().string("true"));
// @formatter:on
}
private String xml(String configName) {

View File

@ -51,9 +51,15 @@ import static org.assertj.core.api.Assertions.assertThat;
@PowerMockIgnore({ "org.w3c.dom.*", "org.xml.sax.*", "org.apache.xerces.*", "javax.xml.parsers.*" })
public class SessionManagementConfigServlet31Tests {
private static final String XML_AUTHENTICATION_MANAGER = "<authentication-manager>" + " <authentication-provider>"
+ " <user-service>" + " <user name='user' password='{noop}password' authorities='ROLE_USER' />"
+ " </user-service>" + " </authentication-provider>" + "</authentication-manager>";
// @formatter:off
private static final String XML_AUTHENTICATION_MANAGER = "<authentication-manager>"
+ " <authentication-provider>"
+ " <user-service>"
+ " <user name='user' password='{noop}password' authorities='ROLE_USER' />"
+ " </user-service>"
+ " </authentication-provider>"
+ "</authentication-manager>";
// @formatter:on
@Mock
Method method;
@ -92,8 +98,14 @@ public class SessionManagementConfigServlet31Tests {
request.setParameter("password", "password");
request.getSession().setAttribute("attribute1", "value1");
String id = request.getSession().getId();
loadContext("<http>\n" + " <form-login/>\n" + " <session-management/>\n"
+ " <csrf disabled='true'/>\n" + " </http>" + XML_AUTHENTICATION_MANAGER);
// @formatter:off
loadContext("<http>\n"
+ " <form-login/>\n"
+ " <session-management/>\n"
+ " <csrf disabled='true'/>\n"
+ " </http>"
+ XML_AUTHENTICATION_MANAGER);
// @formatter:on
this.springSecurityFilterChain.doFilter(request, this.response, this.chain);
assertThat(request.getSession().getId()).isNotEqualTo(id);
assertThat(request.getSession().getAttribute("attribute1")).isEqualTo("value1");
@ -108,9 +120,14 @@ public class SessionManagementConfigServlet31Tests {
request.setParameter("username", "user");
request.setParameter("password", "password");
String id = request.getSession().getId();
loadContext("<http>\n" + " <form-login/>\n"
// @formatter:off
loadContext("<http>\n"
+ " <form-login/>\n"
+ " <session-management session-fixation-protection='changeSessionId'/>\n"
+ " <csrf disabled='true'/>\n" + " </http>" + XML_AUTHENTICATION_MANAGER);
+ " <csrf disabled='true'/>\n"
+ " </http>"
+ XML_AUTHENTICATION_MANAGER);
// @formatter:on
this.springSecurityFilterChain.doFilter(request, this.response, this.chain);
assertThat(request.getSession().getId()).isNotEqualTo(id);
}

View File

@ -55,6 +55,7 @@ import org.springframework.security.web.session.SessionManagementFilter;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.ResultMatcher;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.WebApplicationContext;
@ -91,7 +92,7 @@ public class SessionManagementConfigTests {
@Test
public void requestWhenCreateSessionAlwaysThenAlwaysCreatesSession() throws Exception {
this.spring.configLocations(this.xml("CreateSessionAlways")).autowire();
this.spring.configLocations(xml("CreateSessionAlways")).autowire();
MockHttpServletRequest request = get("/").buildRequest(this.servletContext());
MockHttpServletResponse response = request(request, this.spring.getContext());
assertThat(response.getStatus()).isEqualTo(HttpStatus.SC_OK);
@ -100,7 +101,7 @@ public class SessionManagementConfigTests {
@Test
public void requestWhenCreateSessionIsSetToNeverThenDoesNotCreateSessionOnLoginChallenge() throws Exception {
this.spring.configLocations(this.xml("CreateSessionNever")).autowire();
this.spring.configLocations(xml("CreateSessionNever")).autowire();
MockHttpServletRequest request = get("/auth").buildRequest(this.servletContext());
MockHttpServletResponse response = request(request, this.spring.getContext());
assertThat(response.getStatus()).isEqualTo(HttpStatus.SC_MOVED_TEMPORARILY);
@ -109,9 +110,13 @@ public class SessionManagementConfigTests {
@Test
public void requestWhenCreateSessionIsSetToNeverThenDoesNotCreateSessionOnLogin() throws Exception {
this.spring.configLocations(this.xml("CreateSessionNever")).autowire();
MockHttpServletRequest request = post("/login").param("username", "user").param("password", "password")
this.spring.configLocations(xml("CreateSessionNever")).autowire();
// @formatter:off
MockHttpServletRequest request = post("/login")
.param("username", "user")
.param("password", "password")
.buildRequest(this.servletContext());
// @formatter:on
request = csrf().postProcessRequest(request);
MockHttpServletResponse response = request(request, this.spring.getContext());
assertThat(response.getStatus()).isEqualTo(HttpStatus.SC_MOVED_TEMPORARILY);
@ -120,9 +125,13 @@ public class SessionManagementConfigTests {
@Test
public void requestWhenCreateSessionIsSetToNeverThenUsesExistingSession() throws Exception {
this.spring.configLocations(this.xml("CreateSessionNever")).autowire();
MockHttpServletRequest request = post("/login").param("username", "user").param("password", "password")
this.spring.configLocations(xml("CreateSessionNever")).autowire();
// @formatter:off
MockHttpServletRequest request = post("/login")
.param("username", "user")
.param("password", "password")
.buildRequest(this.servletContext());
// @formatter:on
request = csrf().postProcessRequest(request);
MockHttpSession session = new MockHttpSession();
request.setSession(session);
@ -135,31 +144,48 @@ public class SessionManagementConfigTests {
@Test
public void requestWhenCreateSessionIsSetToStatelessThenDoesNotCreateSessionOnLoginChallenge() throws Exception {
this.spring.configLocations(this.xml("CreateSessionStateless")).autowire();
this.mvc.perform(get("/auth")).andExpect(status().isFound()).andExpect(session().exists(false));
this.spring.configLocations(xml("CreateSessionStateless")).autowire();
// @formatter:off
this.mvc.perform(get("/auth"))
.andExpect(status().isFound())
.andExpect(session().exists(false));
// @formatter:on
}
@Test
public void requestWhenCreateSessionIsSetToStatelessThenDoesNotCreateSessionOnLogin() throws Exception {
this.spring.configLocations(this.xml("CreateSessionStateless")).autowire();
this.mvc.perform(post("/login").param("username", "user").param("password", "password").with(csrf()))
.andExpect(status().isFound()).andExpect(session().exists(false));
this.spring.configLocations(xml("CreateSessionStateless")).autowire();
// @formatter:off
MockHttpServletRequestBuilder loginRequest = post("/login")
.param("username", "user")
.param("password", "password")
.with(csrf());
this.mvc.perform(loginRequest)
.andExpect(status().isFound())
.andExpect(session().exists(false));
// @formatter:on
}
@Test
public void requestWhenCreateSessionIsSetToStatelessThenIgnoresExistingSession() throws Exception {
this.spring.configLocations(this.xml("CreateSessionStateless")).autowire();
MvcResult result = this.mvc
.perform(post("/login").param("username", "user").param("password", "password")
.session(new MockHttpSession()).with(csrf()))
.andExpect(status().isFound()).andExpect(session()).andReturn();
this.spring.configLocations(xml("CreateSessionStateless")).autowire();
// @formatter:off
MockHttpServletRequestBuilder loginRequest = post("/login")
.param("username", "user")
.param("password", "password")
.session(new MockHttpSession())
.with(csrf());
MvcResult result = this.mvc.perform(loginRequest)
.andExpect(status().isFound())
.andExpect(session()).andReturn();
// @formatter:on
assertThat(result.getRequest().getSession(false)
.getAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY)).isNull();
}
@Test
public void requestWhenCreateSessionIsSetToIfRequiredThenDoesNotCreateSessionOnPublicInvocation() throws Exception {
this.spring.configLocations(this.xml("CreateSessionIfRequired")).autowire();
this.spring.configLocations(xml("CreateSessionIfRequired")).autowire();
ServletContext servletContext = this.mvc.getDispatcherServlet().getServletContext();
MockHttpServletRequest request = get("/").buildRequest(servletContext);
MockHttpServletResponse response = request(request, this.spring.getContext());
@ -169,7 +195,7 @@ public class SessionManagementConfigTests {
@Test
public void requestWhenCreateSessionIsSetToIfRequiredThenCreatesSessionOnLoginChallenge() throws Exception {
this.spring.configLocations(this.xml("CreateSessionIfRequired")).autowire();
this.spring.configLocations(xml("CreateSessionIfRequired")).autowire();
ServletContext servletContext = this.mvc.getDispatcherServlet().getServletContext();
MockHttpServletRequest request = get("/auth").buildRequest(servletContext);
MockHttpServletResponse response = request(request, this.spring.getContext());
@ -179,10 +205,14 @@ public class SessionManagementConfigTests {
@Test
public void requestWhenCreateSessionIsSetToIfRequiredThenCreatesSessionOnLogin() throws Exception {
this.spring.configLocations(this.xml("CreateSessionIfRequired")).autowire();
this.spring.configLocations(xml("CreateSessionIfRequired")).autowire();
ServletContext servletContext = this.mvc.getDispatcherServlet().getServletContext();
MockHttpServletRequest request = post("/login").param("username", "user").param("password", "password")
// @formatter:off
MockHttpServletRequest request = post("/login")
.param("username", "user")
.param("password", "password")
.buildRequest(servletContext);
// @formatter:on
request = csrf().postProcessRequest(request);
MockHttpServletResponse response = request(request, this.spring.getContext());
assertThat(response.getStatus()).isEqualTo(HttpStatus.SC_MOVED_TEMPORARILY);
@ -194,11 +224,15 @@ public class SessionManagementConfigTests {
*/
@Test
public void requestWhenRejectingUserBasedOnMaxSessionsExceededThenDoesNotCreateSession() throws Exception {
this.spring.configLocations(this.xml("Sec1208")).autowire();
this.mvc.perform(get("/auth").with(httpBasic("user", "password"))).andExpect(status().isOk())
this.spring.configLocations(xml("Sec1208")).autowire();
// @formatter:off
this.mvc.perform(get("/auth").with(httpBasic("user", "password")))
.andExpect(status().isOk())
.andExpect(session());
this.mvc.perform(get("/auth").with(httpBasic("user", "password"))).andExpect(status().isUnauthorized())
this.mvc.perform(get("/auth").with(httpBasic("user", "password")))
.andExpect(status().isUnauthorized())
.andExpect(session().exists(false));
// @formatter:on
}
/**
@ -207,40 +241,61 @@ public class SessionManagementConfigTests {
@Test
public void requestWhenSessionFixationProtectionDisabledAndConcurrencyControlEnabledThenSessionNotInvalidated()
throws Exception {
this.spring.configLocations(this.xml("Sec2137")).autowire();
this.spring.configLocations(xml("Sec2137")).autowire();
MockHttpSession session = new MockHttpSession();
this.mvc.perform(get("/auth").session(session).with(httpBasic("user", "password"))).andExpect(status().isOk())
// @formatter:off
this.mvc.perform(get("/auth").session(session).with(httpBasic("user", "password")))
.andExpect(status().isOk())
.andExpect(session().id(session.getId()));
// @formatter:on
}
@Test
public void autowireWhenExportingSessionRegistryBeanThenAvailableForWiring() {
this.spring.configLocations(this.xml("ConcurrencyControlSessionRegistryAlias")).autowire();
this.spring.configLocations(xml("ConcurrencyControlSessionRegistryAlias")).autowire();
this.sessionRegistryIsValid();
}
@Test
public void requestWhenExpiredUrlIsSetThenInvalidatesSessionAndRedirects() throws Exception {
this.spring.configLocations(this.xml("ConcurrencyControlExpiredUrl")).autowire();
this.mvc.perform(get("/auth").session(this.expiredSession()).with(httpBasic("user", "password")))
.andExpect(redirectedUrl("/expired")).andExpect(session().exists(false));
this.spring.configLocations(xml("ConcurrencyControlExpiredUrl")).autowire();
// @formatter:off
MockHttpServletRequestBuilder request = get("/auth")
.session(expiredSession())
.with(httpBasic("user", "password"));
this.mvc.perform(request)
.andExpect(redirectedUrl("/expired"))
.andExpect(session().exists(false));
// @formatter:on
}
@Test
public void requestWhenConcurrencyControlAndCustomLogoutHandlersAreSetThenAllAreInvokedWhenSessionExpires()
throws Exception {
this.spring.configLocations(this.xml("ConcurrencyControlLogoutAndRememberMeHandlers")).autowire();
this.mvc.perform(get("/auth").session(this.expiredSession()).with(httpBasic("user", "password")))
.andExpect(status().isOk()).andExpect(cookie().maxAge("testCookie", 0))
.andExpect(cookie().exists("rememberMeCookie")).andExpect(session().valid(true));
this.spring.configLocations(xml("ConcurrencyControlLogoutAndRememberMeHandlers")).autowire();
// @formatter:off
MockHttpServletRequestBuilder request = get("/auth")
.session(expiredSession())
.with(httpBasic("user", "password"));
this.mvc.perform(request)
.andExpect(status().isOk())
.andExpect(cookie().maxAge("testCookie", 0))
.andExpect(cookie().exists("rememberMeCookie"))
.andExpect(session().valid(true));
// @formatter:on
}
@Test
public void requestWhenConcurrencyControlAndRememberMeAreSetThenInvokedWhenSessionExpires() throws Exception {
this.spring.configLocations(this.xml("ConcurrencyControlRememberMeHandler")).autowire();
this.mvc.perform(get("/auth").session(this.expiredSession()).with(httpBasic("user", "password")))
this.spring.configLocations(xml("ConcurrencyControlRememberMeHandler")).autowire();
// @formatter:off
MockHttpServletRequestBuilder request = get("/auth")
.session(expiredSession())
.with(httpBasic("user", "password"));
this.mvc.perform(request)
.andExpect(status().isOk()).andExpect(cookie().exists("rememberMeCookie"))
.andExpect(session().exists(false));
// @formatter:on
}
/**
@ -248,77 +303,104 @@ public class SessionManagementConfigTests {
*/
@Test
public void autowireWhenConcurrencyControlIsSetThenLogoutHandlersGetAuthenticationObject() throws Exception {
this.spring.configLocations(this.xml("ConcurrencyControlCustomLogoutHandler")).autowire();
MvcResult result = this.mvc.perform(get("/auth").with(httpBasic("user", "password"))).andExpect(session())
this.spring.configLocations(xml("ConcurrencyControlCustomLogoutHandler")).autowire();
MvcResult result = this.mvc.perform(get("/auth").with(httpBasic("user", "password")))
.andExpect(session())
.andReturn();
MockHttpSession session = (MockHttpSession) result.getRequest().getSession(false);
SessionRegistry sessionRegistry = this.spring.getContext().getBean(SessionRegistry.class);
sessionRegistry.getSessionInformation(session.getId()).expireNow();
this.mvc.perform(get("/auth").session(session)).andExpect(header().string("X-Username", "user"));
// @formatter:off
this.mvc.perform(get("/auth").session(session))
.andExpect(header().string("X-Username", "user"));
// @formatter:on
}
@Test
public void requestWhenConcurrencyControlIsSetThenDefaultsToResponseBodyExpirationResponse() throws Exception {
this.spring.configLocations(this.xml("ConcurrencyControlSessionRegistryAlias")).autowire();
this.mvc.perform(get("/auth").session(this.expiredSession()).with(httpBasic("user", "password")))
this.spring.configLocations(xml("ConcurrencyControlSessionRegistryAlias")).autowire();
// @formatter:off
MockHttpServletRequestBuilder request = get("/auth")
.session(expiredSession())
.with(httpBasic("user", "password"));
this.mvc.perform(request)
.andExpect(content().string("This session has been expired (possibly due to multiple concurrent "
+ "logins being attempted as the same user)."));
// @formatter:on
}
@Test
public void requestWhenCustomSessionAuthenticationStrategyThenInvokesOnAuthentication() throws Exception {
this.spring.configLocations(this.xml("SessionAuthenticationStrategyRef")).autowire();
this.mvc.perform(get("/auth").with(httpBasic("user", "password"))).andExpect(status().isIAmATeapot());
this.spring.configLocations(xml("SessionAuthenticationStrategyRef")).autowire();
// @formatter:off
this.mvc.perform(get("/auth").with(httpBasic("user", "password")))
.andExpect(status().isIAmATeapot());
// @formatter:on
}
@Test
public void autowireWhenSessionRegistryRefIsSetThenAvailableForWiring() {
this.spring.configLocations(this.xml("ConcurrencyControlSessionRegistryRef")).autowire();
this.spring.configLocations(xml("ConcurrencyControlSessionRegistryRef")).autowire();
this.sessionRegistryIsValid();
}
@Test
public void requestWhenMaxSessionsIsSetThenErrorsWhenExceeded() throws Exception {
this.spring.configLocations(this.xml("ConcurrencyControlMaxSessions")).autowire();
this.mvc.perform(get("/auth").with(httpBasic("user", "password"))).andExpect(status().isOk());
this.mvc.perform(get("/auth").with(httpBasic("user", "password"))).andExpect(status().isOk());
this.mvc.perform(get("/auth").with(httpBasic("user", "password"))).andExpect(redirectedUrl("/max-exceeded"));
this.spring.configLocations(xml("ConcurrencyControlMaxSessions")).autowire();
// @formatter:off
this.mvc.perform(get("/auth").with(httpBasic("user", "password")))
.andExpect(status().isOk());
this.mvc.perform(get("/auth").with(httpBasic("user", "password")))
.andExpect(status().isOk());
this.mvc.perform(get("/auth").with(httpBasic("user", "password")))
.andExpect(redirectedUrl("/max-exceeded"));
// @formatter:on
}
@Test
public void autowireWhenSessionFixationProtectionIsNoneAndCsrfDisabledThenSessionManagementFilterIsNotWired() {
this.spring.configLocations(this.xml("NoSessionManagementFilter")).autowire();
this.spring.configLocations(xml("NoSessionManagementFilter")).autowire();
assertThat(this.getFilter(SessionManagementFilter.class)).isNull();
}
@Test
public void requestWhenSessionFixationProtectionIsNoneThenSessionNotInvalidated() throws Exception {
this.spring.configLocations(this.xml("SessionFixationProtectionNone")).autowire();
this.spring.configLocations(xml("SessionFixationProtectionNone")).autowire();
MockHttpSession session = new MockHttpSession();
String sessionId = session.getId();
// @formatter:off
this.mvc.perform(get("/auth").session(session).with(httpBasic("user", "password")))
.andExpect(session().id(sessionId));
// @formatter:on
}
@Test
public void requestWhenSessionFixationProtectionIsMigrateSessionThenSessionIsReplaced() throws Exception {
this.spring.configLocations(this.xml("SessionFixationProtectionMigrateSession")).autowire();
this.spring.configLocations(xml("SessionFixationProtectionMigrateSession")).autowire();
MockHttpSession session = new MockHttpSession();
String sessionId = session.getId();
// @formatter:off
MvcResult result = this.mvc.perform(get("/auth").session(session).with(httpBasic("user", "password")))
.andExpect(session()).andReturn();
.andExpect(session())
.andReturn();
// @formatter:on
assertThat(result.getRequest().getSession(false).getId()).isNotEqualTo(sessionId);
}
@Test
public void requestWhenSessionFixationProtectionIsNoneAndInvalidSessionUrlIsSetThenStillRedirectsOnInvalidSession()
throws Exception {
this.spring.configLocations(this.xml("SessionFixationProtectionNoneWithInvalidSessionUrl")).autowire();
this.mvc.perform(get("/auth").with((request) -> {
request.setRequestedSessionId("1");
request.setRequestedSessionIdValid(false);
return request;
})).andExpect(redirectedUrl("/timeoutUrl"));
this.spring.configLocations(xml("SessionFixationProtectionNoneWithInvalidSessionUrl")).autowire();
// @formatter:off
MockHttpServletRequestBuilder request = get("/auth")
.with((request) -> {
request.setRequestedSessionId("1");
request.setRequestedSessionIdValid(false);
return request;
});
this.mvc.perform(request)
.andExpect(redirectedUrl("/timeoutUrl"));
// @formatter:on
}
private void sessionRegistryIsValid() {
@ -367,7 +449,7 @@ public class SessionManagementConfigTests {
*/
@Test
public void checkConcurrencyAndLogoutFilterHasSameSizeAndHasLogoutSuccessEventPublishingLogoutHandler() {
this.spring.configLocations(this.xml("ConcurrencyControlLogoutAndRememberMeHandlers")).autowire();
this.spring.configLocations(xml("ConcurrencyControlLogoutAndRememberMeHandlers")).autowire();
ConcurrentSessionFilter concurrentSessionFilter = getFilter(ConcurrentSessionFilter.class);
LogoutFilter logoutFilter = getFilter(LogoutFilter.class);
LogoutHandler csfLogoutHandler = getFieldValue(concurrentSessionFilter, "handlers");

View File

@ -75,11 +75,14 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
private BusinessService target;
public void loadContext() {
// @formatter:off
setContext("<b:bean id='target' class='org.springframework.security.access.annotation.BusinessServiceImpl'/>"
+ "<global-method-security order='1001' proxy-target-class='false' >"
+ " <protect-pointcut expression='execution(* *.someUser*(..))' access='ROLE_USER'/>"
+ " <protect-pointcut expression='execution(* *.someAdmin*(..))' access='ROLE_ADMIN'/>"
+ "</global-method-security>" + ConfigTestUtils.AUTH_PROVIDER_XML);
+ "</global-method-security>"
+ ConfigTestUtils.AUTH_PROVIDER_XML);
// @formatter:on
this.target = (BusinessService) this.appContext.getBean("target");
}
@ -122,11 +125,14 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
@Test
public void doesntInterfereWithBeanPostProcessing() {
setContext(
"<b:bean id='myUserService' class='org.springframework.security.config.PostProcessedMockUserDetailsService'/>"
+ "<global-method-security />" + "<authentication-manager>"
+ " <authentication-provider user-service-ref='myUserService'/>" + "</authentication-manager>"
+ "<b:bean id='beanPostProcessor' class='org.springframework.security.config.MockUserServiceBeanPostProcessor'/>");
// @formatter:off
setContext("<b:bean id='myUserService' class='org.springframework.security.config.PostProcessedMockUserDetailsService'/>"
+ "<global-method-security />"
+ "<authentication-manager>"
+ " <authentication-provider user-service-ref='myUserService'/>"
+ "</authentication-manager>"
+ "<b:bean id='beanPostProcessor' class='org.springframework.security.config.MockUserServiceBeanPostProcessor'/>");
// @formatter:on
PostProcessedMockUserDetailsService service = (PostProcessedMockUserDetailsService) this.appContext
.getBean("myUserService");
assertThat(service.getPostProcessorWasHere()).isEqualTo("Hello from the post processor!");
@ -134,12 +140,17 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
@Test(expected = AccessDeniedException.class)
public void worksWithAspectJAutoproxy() {
// @formatter:off
setContext("<global-method-security>"
+ " <protect-pointcut expression='execution(* org.springframework.security.config.*Service.*(..))'"
+ " access='ROLE_SOMETHING' />" + "</global-method-security>"
+ " access='ROLE_SOMETHING' />"
+ "</global-method-security>"
+ "<b:bean id='myUserService' class='org.springframework.security.config.PostProcessedMockUserDetailsService'/>"
+ "<aop:aspectj-autoproxy />" + "<authentication-manager>"
+ " <authentication-provider user-service-ref='myUserService'/>" + "</authentication-manager>");
+ "<aop:aspectj-autoproxy />"
+ "<authentication-manager>"
+ " <authentication-provider user-service-ref='myUserService'/>"
+ "</authentication-manager>");
// @formatter:on
UserDetailsService service = (UserDetailsService) this.appContext.getBean("myUserService");
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", "Password",
AuthorityUtils.createAuthorityList("ROLE_SOMEOTHERROLE"));
@ -149,11 +160,14 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
@Test
public void supportsMethodArgumentsInPointcut() {
// @formatter:off
setContext("<b:bean id='target' class='org.springframework.security.access.annotation.BusinessServiceImpl'/>"
+ "<global-method-security>"
+ " <protect-pointcut expression='execution(* org.springframework.security.access.annotation.BusinessService.someOther(String))' access='ROLE_ADMIN'/>"
+ " <protect-pointcut expression='execution(* org.springframework.security.access.annotation.BusinessService.*(..))' access='ROLE_USER'/>"
+ "</global-method-security>" + ConfigTestUtils.AUTH_PROVIDER_XML);
+ "</global-method-security>"
+ ConfigTestUtils.AUTH_PROVIDER_XML);
// @formatter:on
SecurityContextHolder.getContext()
.setAuthentication(new UsernamePasswordAuthenticationToken("user", "password"));
this.target = (BusinessService) this.appContext.getBean("target");
@ -171,12 +185,16 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
@Test
public void supportsBooleanPointcutExpressions() {
// @formatter:off
setContext("<b:bean id='target' class='org.springframework.security.access.annotation.BusinessServiceImpl'/>"
+ "<global-method-security>" + " <protect-pointcut expression="
+ "<global-method-security>"
+ " <protect-pointcut expression="
+ " 'execution(* org.springframework.security.access.annotation.BusinessService.*(..)) "
+ " and not execution(* org.springframework.security.access.annotation.BusinessService.someOther(String)))' "
+ " access='ROLE_USER'/>" + "</global-method-security>"
+ " access='ROLE_USER'/>"
+ "</global-method-security>"
+ ConfigTestUtils.AUTH_PROVIDER_XML);
// @formatter:on
this.target = (BusinessService) this.appContext.getBean("target");
// String method should not be protected
this.target.someOther("somestring");
@ -200,11 +218,14 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
// SEC-936
@Test(expected = AccessDeniedException.class)
public void worksWithoutTargetOrClass() {
// @formatter:off
setContext("<global-method-security secured-annotations='enabled'/>"
+ "<b:bean id='businessService' class='org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean'>"
+ " <b:property name='serviceUrl' value='http://localhost:8080/SomeService'/>"
+ " <b:property name='serviceInterface' value='org.springframework.security.access.annotation.BusinessService'/>"
+ "</b:bean>" + ConfigTestUtils.AUTH_PROVIDER_XML);
+ "</b:bean>"
+ ConfigTestUtils.AUTH_PROVIDER_XML);
// @formatter:on
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", "Password",
AuthorityUtils.createAuthorityList("ROLE_SOMEOTHERROLE"));
SecurityContextHolder.getContext().setAuthentication(token);
@ -232,9 +253,11 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
@Test(expected = AccessDeniedException.class)
public void accessIsDeniedForHasRoleExpression() {
// @formatter:off
setContext("<global-method-security pre-post-annotations='enabled'/>"
+ "<b:bean id='target' class='org.springframework.security.access.annotation.ExpressionProtectedBusinessServiceImpl'/>"
+ ConfigTestUtils.AUTH_PROVIDER_XML);
// @formatter:on
SecurityContextHolder.getContext().setAuthentication(this.bob);
this.target = (BusinessService) this.appContext.getBean("target");
this.target.someAdminMethod();
@ -242,11 +265,14 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
@Test
public void beanNameExpressionPropertyIsSupported() {
// @formatter:off
setContext("<global-method-security pre-post-annotations='enabled' proxy-target-class='true'/>"
+ "<b:bean id='number' class='java.lang.Integer'>" + " <b:constructor-arg value='1294'/>"
+ "<b:bean id='number' class='java.lang.Integer'>"
+ " <b:constructor-arg value='1294'/>"
+ "</b:bean>"
+ "<b:bean id='target' class='org.springframework.security.access.annotation.ExpressionProtectedBusinessServiceImpl'/>"
+ ConfigTestUtils.AUTH_PROVIDER_XML);
// @formatter:on
SecurityContextHolder.getContext().setAuthentication(this.bob);
ExpressionProtectedBusinessServiceImpl target = (ExpressionProtectedBusinessServiceImpl) this.appContext
.getBean("target");
@ -255,9 +281,11 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
@Test
public void preAndPostFilterAnnotationsWorkWithLists() {
// @formatter:off
setContext("<global-method-security pre-post-annotations='enabled'/>"
+ "<b:bean id='target' class='org.springframework.security.access.annotation.ExpressionProtectedBusinessServiceImpl'/>"
+ ConfigTestUtils.AUTH_PROVIDER_XML);
// @formatter:on
SecurityContextHolder.getContext().setAuthentication(this.bob);
this.target = (BusinessService) this.appContext.getBean("target");
List<String> arg = new ArrayList<>();
@ -274,9 +302,11 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
@Test
public void prePostFilterAnnotationWorksWithArrays() {
// @formatter:off
setContext("<global-method-security pre-post-annotations='enabled'/>"
+ "<b:bean id='target' class='org.springframework.security.access.annotation.ExpressionProtectedBusinessServiceImpl'/>"
+ ConfigTestUtils.AUTH_PROVIDER_XML);
// @formatter:on
SecurityContextHolder.getContext().setAuthentication(this.bob);
this.target = (BusinessService) this.appContext.getBean("target");
Object[] arg = new String[] { "joe", "bob", "sam" };
@ -288,23 +318,30 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
// SEC-1392
@Test
public void customPermissionEvaluatorIsSupported() {
// @formatter:off
setContext("<global-method-security pre-post-annotations='enabled'>"
+ " <expression-handler ref='expressionHandler'/>" + "</global-method-security>"
+ " <expression-handler ref='expressionHandler'/>"
+ "</global-method-security>"
+ "<b:bean id='expressionHandler' class='org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler'>"
+ " <b:property name='permissionEvaluator' ref='myPermissionEvaluator'/>" + "</b:bean>"
+ " <b:property name='permissionEvaluator' ref='myPermissionEvaluator'/>"
+ "</b:bean>"
+ "<b:bean id='myPermissionEvaluator' class='org.springframework.security.config.method.TestPermissionEvaluator'/>"
+ ConfigTestUtils.AUTH_PROVIDER_XML);
// @formatter:on
}
// SEC-1450
@Test(expected = AuthenticationException.class)
@SuppressWarnings("unchecked")
public void genericsAreMatchedByProtectPointcut() {
// @formatter:off
setContext(
"<b:bean id='target' class='org.springframework.security.config.method.GlobalMethodSecurityBeanDefinitionParserTests$ConcreteFoo'/>"
+ "<global-method-security>"
+ " <protect-pointcut expression='execution(* org..*Foo.foo(..))' access='ROLE_USER'/>"
+ "</global-method-security>" + ConfigTestUtils.AUTH_PROVIDER_XML);
+ "</global-method-security>"
+ ConfigTestUtils.AUTH_PROVIDER_XML);
// @formatter:on
Foo foo = (Foo) this.appContext.getBean("target");
foo.foo(new SecurityConfig("A"));
}
@ -313,8 +350,11 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
@Test
@SuppressWarnings("unchecked")
public void genericsMethodArgumentNamesAreResolved() {
// @formatter:off
setContext("<b:bean id='target' class='" + ConcreteFoo.class.getName() + "'/>"
+ "<global-method-security pre-post-annotations='enabled'/>" + ConfigTestUtils.AUTH_PROVIDER_XML);
+ "<global-method-security pre-post-annotations='enabled'/>"
+ ConfigTestUtils.AUTH_PROVIDER_XML);
// @formatter:on
SecurityContextHolder.getContext().setAuthentication(this.bob);
Foo foo = (Foo) this.appContext.getBean("target");
foo.foo(new SecurityConfig("A"));
@ -338,11 +378,14 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
@Test
@SuppressWarnings("unchecked")
public void supportsExternalMetadataSource() {
// @formatter:off
setContext("<b:bean id='target' class='" + ConcreteFoo.class.getName() + "'/>"
+ "<method-security-metadata-source id='mds'>" + " <protect method='" + Foo.class.getName()
+ ".foo' access='ROLE_ADMIN'/>" + "</method-security-metadata-source>"
+ "<method-security-metadata-source id='mds'>"
+ " <protect method='" + Foo.class.getName() + ".foo' access='ROLE_ADMIN'/>"
+ "</method-security-metadata-source>"
+ "<global-method-security pre-post-annotations='enabled' metadata-source-ref='mds'/>"
+ ConfigTestUtils.AUTH_PROVIDER_XML);
// @formatter:on
// External MDS should take precedence over PreAuthorize
SecurityContextHolder.getContext().setAuthentication(this.bob);
Foo foo = (Foo) this.appContext.getBean("target");
@ -359,12 +402,17 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
@Test
public void supportsCustomAuthenticationManager() {
// @formatter:off
setContext("<b:bean id='target' class='" + ConcreteFoo.class.getName() + "'/>"
+ "<method-security-metadata-source id='mds'>" + " <protect method='" + Foo.class.getName()
+ ".foo' access='ROLE_ADMIN'/>" + "</method-security-metadata-source>"
+ "<method-security-metadata-source id='mds'>"
+ " <protect method='" + Foo.class.getName() + ".foo' access='ROLE_ADMIN'/>"
+ "</method-security-metadata-source>"
+ "<global-method-security pre-post-annotations='enabled' metadata-source-ref='mds' authentication-manager-ref='customAuthMgr'/>"
+ "<b:bean id='customAuthMgr' class='org.springframework.security.config.method.GlobalMethodSecurityBeanDefinitionParserTests$CustomAuthManager'>"
+ " <b:constructor-arg value='authManager'/>" + "</b:bean>" + ConfigTestUtils.AUTH_PROVIDER_XML);
+ " <b:constructor-arg value='authManager'/>"
+ "</b:bean>"
+ ConfigTestUtils.AUTH_PROVIDER_XML);
// @formatter:on
SecurityContextHolder.getContext().setAuthentication(this.bob);
Foo foo = (Foo) this.appContext.getBean("target");
try {

View File

@ -40,9 +40,12 @@ public class Jsr250AnnotationDrivenBeanDefinitionParserTests {
@Before
public void loadContext() {
// @formatter:off
this.appContext = new InMemoryXmlApplicationContext(
"<b:bean id='target' class='org.springframework.security.access.annotation.Jsr250BusinessServiceImpl'/>"
+ "<global-method-security jsr250-annotations='enabled'/>" + ConfigTestUtils.AUTH_PROVIDER_XML);
+ "<global-method-security jsr250-annotations='enabled'/>"
+ ConfigTestUtils.AUTH_PROVIDER_XML);
// @formatter:on
this.target = (BusinessService) this.appContext.getBean("target");
}

View File

@ -46,39 +46,80 @@ public class ClientRegistrationsBeanDefinitionParserTests {
private static final String CONFIG_LOCATION_PREFIX = "classpath:org/springframework/security/config/oauth2/client/ClientRegistrationsBeanDefinitionParserTests";
// @formatter:off
private static final String ISSUER_URI_XML_CONFIG = "<b:beans xmlns:b=\"http://www.springframework.org/schema/beans\"\n"
+ "\t\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
+ "\t\txmlns=\"http://www.springframework.org/schema/security\"\n" + "\t\txsi:schemaLocation=\"\n"
+ "\t\t\thttp://www.springframework.org/schema/security\n"
+ "\t\t\thttps://www.springframework.org/schema/security/spring-security.xsd\n"
+ "\t\t\thttp://www.springframework.org/schema/beans\n"
+ "\t\t\thttps://www.springframework.org/schema/beans/spring-beans.xsd\">\n" + "\n"
+ "\t<client-registrations>\n"
+ "\t\t<client-registration registration-id=\"google-login\" client-id=\"google-client-id\" \n"
+ "\t\t\t\t\t\t\t client-secret=\"google-client-secret\" provider-id=\"google\"/>\n"
+ "\t\t<provider provider-id=\"google\" issuer-uri=\"${issuer-uri}\"/>\n" + "\t</client-registrations>\n"
+ "\n" + "</b:beans>\n";
+ " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
+ " xmlns=\"http://www.springframework.org/schema/security\"\n"
+ " xsi:schemaLocation=\"\n"
+ " http://www.springframework.org/schema/security\n"
+ " https://www.springframework.org/schema/security/spring-security.xsd\n"
+ " http://www.springframework.org/schema/beans\n"
+ " https://www.springframework.org/schema/beans/spring-beans.xsd\">\n"
+ "\n"
+ " <client-registrations>\n"
+ " <client-registration registration-id=\"google-login\" client-id=\"google-client-id\" \n"
+ " client-secret=\"google-client-secret\" provider-id=\"google\"/>\n"
+ " <provider provider-id=\"google\" issuer-uri=\"${issuer-uri}\"/>\n"
+ " </client-registrations>\n"
+ "\n"
+ "</b:beans>\n";
// @formatter:on
// @formatter:off
private static final String OIDC_DISCOVERY_RESPONSE = "{\n"
+ " \"authorization_endpoint\": \"https://example.com/o/oauth2/v2/auth\", \n"
+ " \"claims_supported\": [\n" + " \"aud\", \n" + " \"email\", \n"
+ " \"email_verified\", \n" + " \"exp\", \n" + " \"family_name\", \n"
+ " \"given_name\", \n" + " \"iat\", \n" + " \"iss\", \n" + " \"locale\", \n"
+ " \"name\", \n" + " \"picture\", \n" + " \"sub\"\n" + " ], \n"
+ " \"code_challenge_methods_supported\": [\n" + " \"plain\", \n" + " \"S256\"\n"
+ " ], \n" + " \"id_token_signing_alg_values_supported\": [\n" + " \"RS256\"\n" + " ], \n"
+ " \"issuer\": \"${issuer-uri}\", \n" + " \"jwks_uri\": \"https://example.com/oauth2/v3/certs\", \n"
+ " \"response_types_supported\": [\n" + " \"code\", \n" + " \"token\", \n"
+ " \"id_token\", \n" + " \"code token\", \n" + " \"code id_token\", \n"
+ " \"token id_token\", \n" + " \"code token id_token\", \n" + " \"none\"\n"
+ " ], \n" + " \"revocation_endpoint\": \"https://example.com/o/oauth2/revoke\", \n"
+ " \"scopes_supported\": [\n" + " \"openid\", \n" + " \"email\", \n"
+ " \"profile\"\n" + " ], \n" + " \"subject_types_supported\": [\n" + " \"public\"\n"
+ " ], \n" + " \"grant_types_supported\" : [\"authorization_code\"], \n"
+ " \"claims_supported\": [\n"
+ " \"aud\", \n"
+ " \"email\", \n"
+ " \"email_verified\", \n"
+ " \"exp\", \n"
+ " \"family_name\", \n"
+ " \"given_name\", \n"
+ " \"iat\", \n"
+ " \"iss\", \n"
+ " \"locale\", \n"
+ " \"name\", \n"
+ " \"picture\", \n"
+ " \"sub\"\n"
+ " ], \n"
+ " \"code_challenge_methods_supported\": [\n"
+ " \"plain\", \n"
+ " \"S256\"\n"
+ " ], \n"
+ " \"id_token_signing_alg_values_supported\": [\n"
+ " \"RS256\"\n"
+ " ], \n"
+ " \"issuer\": \"${issuer-uri}\", \n"
+ " \"jwks_uri\": \"https://example.com/oauth2/v3/certs\", \n"
+ " \"response_types_supported\": [\n"
+ " \"code\", \n"
+ " \"token\", \n"
+ " \"id_token\", \n"
+ " \"code token\", \n"
+ " \"code id_token\", \n"
+ " \"token id_token\", \n"
+ " \"code token id_token\", \n"
+ " \"none\"\n"
+ " ], \n"
+ " \"revocation_endpoint\": \"https://example.com/o/oauth2/revoke\", \n"
+ " \"scopes_supported\": [\n"
+ " \"openid\", \n"
+ " \"email\", \n"
+ " \"profile\"\n"
+ " ], \n"
+ " \"subject_types_supported\": [\n"
+ " \"public\"\n"
+ " ], \n"
+ " \"grant_types_supported\" : [\"authorization_code\"], \n"
+ " \"token_endpoint\": \"https://example.com/oauth2/v4/token\", \n"
+ " \"token_endpoint_auth_methods_supported\": [\n" + " \"client_secret_post\", \n"
+ " \"client_secret_basic\", \n" + " \"none\"\n" + " ], \n"
+ " \"userinfo_endpoint\": \"https://example.com/oauth2/v3/userinfo\"\n" + "}";
+ " \"token_endpoint_auth_methods_supported\": [\n"
+ " \"client_secret_post\", \n"
+ " \"client_secret_basic\", \n"
+ " \"none\"\n"
+ " ], \n"
+ " \"userinfo_endpoint\": \"https://example.com/oauth2/v3/userinfo\"\n"
+ "}";
// @formatter:on
@Autowired
private ClientRegistrationRepository clientRegistrationRepository;
@ -183,7 +224,10 @@ public class ClientRegistrationsBeanDefinitionParserTests {
}
private static String xml(String configName) {
return CONFIG_LOCATION_PREFIX + "-" + configName + ".xml";
return CONFIG_LOCATION_PREFIX
+ "-"
+ configName
+ ".xml";
}
}

View File

@ -129,8 +129,12 @@ public class SpringTestContext implements Closeable {
this.context.setServletConfig(new MockServletConfig());
this.context.refresh();
if (this.context.containsBean(BeanIds.SPRING_SECURITY_FILTER_CHAIN)) {
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context).apply(springSecurity())
.apply(new AddFilter()).build();
// @formatter:off
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context).
apply(springSecurity())
.apply(new AddFilter())
.build();
// @formatter:on
this.context.getBeanFactory().registerResolvableDependency(MockMvc.class, mockMvc);
}
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();

Some files were not shown because too many files have changed in this diff Show More