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.config.test.SpringTestRule;
import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.authority.SimpleGrantedAuthority; 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 org.springframework.test.web.servlet.MockMvc;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin;
@ -55,35 +57,39 @@ public class LdapAuthenticationProviderConfigurerTests {
public void authenticationManagerSupportMultipleLdapContextWithDefaultRolePrefix() throws Exception { public void authenticationManagerSupportMultipleLdapContextWithDefaultRolePrefix() throws Exception {
this.spring.register(MultiLdapAuthenticationProvidersConfig.class).autowire(); this.spring.register(MultiLdapAuthenticationProvidersConfig.class).autowire();
this.mockMvc.perform(formLogin().user("bob").password("bobspassword")) SecurityMockMvcRequestBuilders.FormLoginRequestBuilder request = formLogin().user("bob").password("bobspassword");
.andExpect(authenticated().withUsername("bob") SecurityMockMvcResultMatchers.AuthenticatedMatcher expectedUser = authenticated().withUsername("bob")
.withAuthorities(Collections.singleton(new SimpleGrantedAuthority("ROLE_DEVELOPERS")))); .withAuthorities(Collections.singleton(new SimpleGrantedAuthority("ROLE_DEVELOPERS")));
this.mockMvc.perform(request).andExpect(expectedUser);
} }
@Test @Test
public void authenticationManagerSupportMultipleLdapContextWithCustomRolePrefix() throws Exception { public void authenticationManagerSupportMultipleLdapContextWithCustomRolePrefix() throws Exception {
this.spring.register(MultiLdapWithCustomRolePrefixAuthenticationProvidersConfig.class).autowire(); this.spring.register(MultiLdapWithCustomRolePrefixAuthenticationProvidersConfig.class).autowire();
this.mockMvc.perform(formLogin().user("bob").password("bobspassword")) SecurityMockMvcRequestBuilders.FormLoginRequestBuilder request = formLogin().user("bob").password("bobspassword");
.andExpect(authenticated().withUsername("bob") SecurityMockMvcResultMatchers.AuthenticatedMatcher expectedUser = authenticated().withUsername("bob")
.withAuthorities(Collections.singleton(new SimpleGrantedAuthority("ROL_DEVELOPERS")))); .withAuthorities(Collections.singleton(new SimpleGrantedAuthority("ROL_DEVELOPERS")));
this.mockMvc.perform(request).andExpect(expectedUser);
} }
@Test @Test
public void authenticationManagerWhenPortZeroThenAuthenticates() throws Exception { public void authenticationManagerWhenPortZeroThenAuthenticates() throws Exception {
this.spring.register(LdapWithRandomPortConfig.class).autowire(); this.spring.register(LdapWithRandomPortConfig.class).autowire();
this.mockMvc.perform(formLogin().user("bob").password("bobspassword")) SecurityMockMvcRequestBuilders.FormLoginRequestBuilder request = formLogin().user("bob").password("bobspassword");
.andExpect(authenticated().withUsername("bob")); SecurityMockMvcResultMatchers.AuthenticatedMatcher expectedUser = authenticated().withUsername("bob");
this.mockMvc.perform(request).andExpect(expectedUser);
} }
@Test @Test
public void authenticationManagerWhenSearchSubtreeThenNestedGroupFound() throws Exception { public void authenticationManagerWhenSearchSubtreeThenNestedGroupFound() throws Exception {
this.spring.register(GroupSubtreeSearchConfig.class).autowire(); this.spring.register(GroupSubtreeSearchConfig.class).autowire();
this.mockMvc.perform(formLogin().user("ben").password("benspassword")) SecurityMockMvcRequestBuilders.FormLoginRequestBuilder request = formLogin().user("ben").password("benspassword");
.andExpect(authenticated().withUsername("ben").withAuthorities( SecurityMockMvcResultMatchers.AuthenticatedMatcher expectedUser = authenticated().withUsername("ben").withAuthorities(
AuthorityUtils.createAuthorityList("ROLE_SUBMANAGERS", "ROLE_MANAGERS", "ROLE_DEVELOPERS"))); AuthorityUtils.createAuthorityList("ROLE_SUBMANAGERS", "ROLE_MANAGERS", "ROLE_DEVELOPERS"));
this.mockMvc.perform(request).andExpect(expectedUser);
} }
@EnableWebSecurity @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.core.authority.SimpleGrantedAuthority;
import org.springframework.security.ldap.DefaultSpringSecurityContextSource; import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
import org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator; 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.security.web.FilterChainProxy;
import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MockMvc;
@ -57,16 +59,19 @@ public class NamespaceLdapAuthenticationProviderTests {
public void ldapAuthenticationProvider() throws Exception { public void ldapAuthenticationProvider() throws Exception {
this.spring.register(LdapAuthenticationProviderConfig.class).autowire(); this.spring.register(LdapAuthenticationProviderConfig.class).autowire();
this.mockMvc.perform(formLogin().user("bob").password("bobspassword")) SecurityMockMvcRequestBuilders.FormLoginRequestBuilder request = formLogin().user("bob").password("bobspassword");
.andExpect(authenticated().withUsername("bob")); SecurityMockMvcResultMatchers.AuthenticatedMatcher user = authenticated().withUsername("bob");
this.mockMvc.perform(request).andExpect(user);
} }
@Test @Test
public void ldapAuthenticationProviderCustom() throws Exception { public void ldapAuthenticationProviderCustom() throws Exception {
this.spring.register(CustomLdapAuthenticationProviderConfig.class).autowire(); this.spring.register(CustomLdapAuthenticationProviderConfig.class).autowire();
this.mockMvc.perform(formLogin().user("bob").password("bobspassword")).andExpect(authenticated() SecurityMockMvcRequestBuilders.FormLoginRequestBuilder request = formLogin().user("bob").password("bobspassword");
.withAuthorities(Collections.singleton(new SimpleGrantedAuthority("PREFIX_DEVELOPERS")))); SecurityMockMvcResultMatchers.AuthenticatedMatcher user = authenticated()
.withAuthorities(Collections.singleton(new SimpleGrantedAuthority("PREFIX_DEVELOPERS")));
this.mockMvc.perform(request).andExpect(user);
} }
// SEC-2490 // SEC-2490
@ -83,16 +88,18 @@ public class NamespaceLdapAuthenticationProviderTests {
this.spring.register(CustomAuthoritiesPopulatorConfig.class).autowire(); this.spring.register(CustomAuthoritiesPopulatorConfig.class).autowire();
this.mockMvc.perform(formLogin().user("bob").password("bobspassword")).andExpect( SecurityMockMvcRequestBuilders.FormLoginRequestBuilder request = formLogin().user("bob").password("bobspassword");
authenticated().withAuthorities(Collections.singleton(new SimpleGrantedAuthority("ROLE_EXTRA")))); SecurityMockMvcResultMatchers.AuthenticatedMatcher user = authenticated().withAuthorities(Collections.singleton(new SimpleGrantedAuthority("ROLE_EXTRA")));
this.mockMvc.perform(request).andExpect(user);
} }
@Test @Test
public void ldapAuthenticationProviderPasswordCompare() throws Exception { public void ldapAuthenticationProviderPasswordCompare() throws Exception {
this.spring.register(PasswordCompareLdapConfig.class).autowire(); this.spring.register(PasswordCompareLdapConfig.class).autowire();
this.mockMvc.perform(formLogin().user("bcrypt").password("password")) SecurityMockMvcRequestBuilders.FormLoginRequestBuilder request = formLogin().user("bcrypt").password("password");
.andExpect(authenticated().withUsername("bcrypt")); SecurityMockMvcResultMatchers.AuthenticatedMatcher user = authenticated().withUsername("bcrypt");
this.mockMvc.perform(request).andExpect(user);
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -125,7 +125,11 @@ class ServerHttpSecurityConfiguration {
@Scope("prototype") @Scope("prototype")
ServerHttpSecurity httpSecurity() { ServerHttpSecurity httpSecurity() {
ContextAwareServerHttpSecurity http = new ContextAwareServerHttpSecurity(); 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() { private ReactiveAuthenticationManager authenticationManager() {

View File

@ -18,12 +18,17 @@ package org.springframework.security.config;
public abstract class ConfigTestUtils { public abstract class ConfigTestUtils {
// @formatter:off
public static final String AUTH_PROVIDER_XML = "<authentication-manager alias='authManager'>" 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='bob' password='{noop}bobspassword' authorities='ROLE_A,ROLE_B' />"
+ " <user name='bill' password='{noop}billspassword' authorities='ROLE_A,ROLE_B,AUTH_OTHER' />" + " <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='admin' password='{noop}password' authorities='ROLE_ADMIN,ROLE_USER' />"
+ " <user name='user' password='{noop}password' authorities='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 @Rule
public ExpectedException thrown = ExpectedException.none(); public ExpectedException thrown = ExpectedException.none();
private static final String XML_AUTHENTICATION_MANAGER = "<authentication-manager>" + " <authentication-provider>" // @formatter:off
+ " <user-service id='us'>" + " <user name='bob' password='bobspassword' authorities='ROLE_A' />" private static final String XML_AUTHENTICATION_MANAGER = "<authentication-manager>"
+ " </user-service>" + " </authentication-provider>" + "</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'/>"; 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.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager; import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers;
import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MockMvc;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
@ -121,9 +122,10 @@ public class AuthenticationManagerBuilderTests {
@Test @Test
public void authenticationManagerWhenMultipleProvidersThenWorks() throws Exception { public void authenticationManagerWhenMultipleProvidersThenWorks() throws Exception {
this.spring.register(MultiAuthenticationProvidersConfig.class).autowire(); this.spring.register(MultiAuthenticationProvidersConfig.class).autowire();
this.mockMvc.perform(formLogin()).andExpect(authenticated().withUsername("user").withRoles("USER")); SecurityMockMvcResultMatchers.AuthenticatedMatcher user = authenticated().withUsername("user").withRoles("USER");
this.mockMvc.perform(formLogin().user("admin")) this.mockMvc.perform(formLogin()).andExpect(user);
.andExpect(authenticated().withUsername("admin").withRoles("USER", "ADMIN")); SecurityMockMvcResultMatchers.AuthenticatedMatcher admin = authenticated().withUsername("admin").withRoles("USER", "ADMIN");
this.mockMvc.perform(formLogin().user("admin")).andExpect(admin);
} }
@Test @Test
@ -165,8 +167,14 @@ public class AuthenticationManagerBuilderTests {
@Override @Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception { 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()); .withUser(PasswordEncodedUser.admin());
// @formatter:on
} }
} }

View File

@ -47,20 +47,18 @@ public class NamespaceAuthenticationManagerTests {
@Test @Test
public void authenticationMangerWhenDefaultThenEraseCredentialsIsTrue() throws Exception { public void authenticationMangerWhenDefaultThenEraseCredentialsIsTrue() throws Exception {
this.spring.register(EraseCredentialsTrueDefaultConfig.class).autowire(); this.spring.register(EraseCredentialsTrueDefaultConfig.class).autowire();
this.mockMvc.perform(formLogin()) SecurityMockMvcResultMatchers.AuthenticatedMatcher nullCredentials = authenticated().withAuthentication((a) -> assertThat(a.getCredentials()).isNull());
.andExpect(authenticated().withAuthentication((a) -> assertThat(a.getCredentials()).isNull())); this.mockMvc.perform(formLogin()).andExpect(nullCredentials);
this.mockMvc.perform(formLogin()) this.mockMvc.perform(formLogin()).andExpect(nullCredentials);
.andExpect(authenticated().withAuthentication((a) -> assertThat(a.getCredentials()).isNull()));
// no exception due to username being cleared out // no exception due to username being cleared out
} }
@Test @Test
public void authenticationMangerWhenEraseCredentialsIsFalseThenCredentialsNotNull() throws Exception { public void authenticationMangerWhenEraseCredentialsIsFalseThenCredentialsNotNull() throws Exception {
this.spring.register(EraseCredentialsFalseConfig.class).autowire(); this.spring.register(EraseCredentialsFalseConfig.class).autowire();
this.mockMvc.perform(formLogin()) SecurityMockMvcResultMatchers.AuthenticatedMatcher notNullCredentials = authenticated().withAuthentication((a) -> assertThat(a.getCredentials()).isNotNull());
.andExpect(authenticated().withAuthentication((a) -> assertThat(a.getCredentials()).isNotNull())); this.mockMvc.perform(formLogin()).andExpect(notNullCredentials);
this.mockMvc.perform(formLogin()) this.mockMvc.perform(formLogin()).andExpect(notNullCredentials);
.andExpect(authenticated().withAuthentication((a) -> assertThat(a.getCredentials()).isNotNull()));
// no exception due to username being cleared out // no exception due to username being cleared out
} }
@ -68,8 +66,8 @@ public class NamespaceAuthenticationManagerTests {
// SEC-2533 // SEC-2533
public void authenticationManagerWhenGlobalAndEraseCredentialsIsFalseThenCredentialsNotNull() throws Exception { public void authenticationManagerWhenGlobalAndEraseCredentialsIsFalseThenCredentialsNotNull() throws Exception {
this.spring.register(GlobalEraseCredentialsFalseConfig.class).autowire(); this.spring.register(GlobalEraseCredentialsFalseConfig.class).autowire();
this.mockMvc.perform(SecurityMockMvcRequestBuilders.formLogin()).andExpect(SecurityMockMvcResultMatchers SecurityMockMvcResultMatchers.AuthenticatedMatcher notNullCredentials = authenticated().withAuthentication((a) -> assertThat(a.getCredentials()).isNotNull());
.authenticated().withAuthentication((a) -> assertThat(a.getCredentials()).isNotNull())); this.mockMvc.perform(formLogin()).andExpect(notNullCredentials);
} }
@EnableWebSecurity @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.UserCache;
import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl; 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 org.springframework.test.web.servlet.MockMvc;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin;
@ -53,13 +54,15 @@ public class NamespaceJdbcUserServiceTests {
@Test @Test
public void jdbcUserService() throws Exception { public void jdbcUserService() throws Exception {
this.spring.register(DataSourceConfig.class, JdbcUserServiceConfig.class).autowire(); 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 @Test
public void jdbcUserServiceCustom() throws Exception { public void jdbcUserServiceCustom() throws Exception {
this.spring.register(CustomDataSourceConfig.class, CustomJdbcUserServiceSampleConfig.class).autowire(); 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 @EnableWebSecurity

View File

@ -43,9 +43,17 @@ public class UserDetailsManagerConfigurerTests {
@Test @Test
public void allAttributesSupported() { public void allAttributesSupported() {
UserDetails userDetails = new UserDetailsManagerConfigurer<AuthenticationManagerBuilder, InMemoryUserDetailsManagerConfigurer<AuthenticationManagerBuilder>>( // @formatter:off
this.userDetailsManager).withUser("user").password("password").roles("USER").disabled(true) UserDetails userDetails = configurer()
.accountExpired(true).accountLocked(true).credentialsExpired(true).build(); .withUser("user")
.password("password")
.roles("USER")
.disabled(true)
.accountExpired(true)
.accountLocked(true)
.credentialsExpired(true)
.build();
// @formatter:on
assertThat(userDetails.getUsername()).isEqualTo("user"); assertThat(userDetails.getUsername()).isEqualTo("user");
assertThat(userDetails.getPassword()).isEqualTo("password"); assertThat(userDetails.getPassword()).isEqualTo("password");
assertThat(userDetails.getAuthorities().stream().findFirst().get().getAuthority()).isEqualTo("ROLE_USER"); assertThat(userDetails.getAuthorities().stream().findFirst().get().getAuthority()).isEqualTo("ROLE_USER");
@ -58,26 +66,43 @@ public class UserDetailsManagerConfigurerTests {
@Test @Test
public void authoritiesWithGrantedAuthorityWorks() { public void authoritiesWithGrantedAuthorityWorks() {
SimpleGrantedAuthority authority = new SimpleGrantedAuthority("ROLE_USER"); SimpleGrantedAuthority authority = new SimpleGrantedAuthority("ROLE_USER");
UserDetails userDetails = new UserDetailsManagerConfigurer<AuthenticationManagerBuilder, InMemoryUserDetailsManagerConfigurer<AuthenticationManagerBuilder>>( // @formatter:off
this.userDetailsManager).withUser("user").password("password").authorities(authority).build(); UserDetails userDetails = configurer()
.withUser("user")
.password("password")
.authorities(authority)
.build();
// @formatter:on
assertThat(userDetails.getAuthorities().stream().findFirst().get()).isEqualTo(authority); assertThat(userDetails.getAuthorities().stream().findFirst().get()).isEqualTo(authority);
} }
@Test @Test
public void authoritiesWithStringAuthorityWorks() { public void authoritiesWithStringAuthorityWorks() {
String authority = "ROLE_USER"; String authority = "ROLE_USER";
UserDetails userDetails = new UserDetailsManagerConfigurer<AuthenticationManagerBuilder, InMemoryUserDetailsManagerConfigurer<AuthenticationManagerBuilder>>( // @formatter:off
this.userDetailsManager).withUser("user").password("password").authorities(authority).build(); UserDetails userDetails = configurer()
.withUser("user")
.password("password")
.authorities(authority)
.build();
// @formatter:on
assertThat(userDetails.getAuthorities().stream().findFirst().get().getAuthority()).isEqualTo(authority); assertThat(userDetails.getAuthorities().stream().findFirst().get().getAuthority()).isEqualTo(authority);
} }
@Test @Test
public void authoritiesWithAListOfGrantedAuthorityWorks() { public void authoritiesWithAListOfGrantedAuthorityWorks() {
SimpleGrantedAuthority authority = new SimpleGrantedAuthority("ROLE_USER"); SimpleGrantedAuthority authority = new SimpleGrantedAuthority("ROLE_USER");
UserDetails userDetails = new UserDetailsManagerConfigurer<AuthenticationManagerBuilder, InMemoryUserDetailsManagerConfigurer<AuthenticationManagerBuilder>>( // @formatter:off
this.userDetailsManager).withUser("user").password("password").authorities(Arrays.asList(authority)) UserDetails userDetails = configurer()
.withUser("user")
.password("password")
.authorities(Arrays.asList(authority))
.build(); .build();
// @formatter:on
assertThat(userDetails.getAuthorities().stream().findFirst().get()).isEqualTo(authority); 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 // gh-3975
@Test @Test
public void headerWhenSpringMvcResourceThenCacheRelatedHeadersReset() throws Exception { 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().string(HttpHeaders.CACHE_CONTROL, "max-age=12345"))
.andExpect(header().doesNotExist(HttpHeaders.PRAGMA)) .andExpect(header().doesNotExist(HttpHeaders.PRAGMA))
.andExpect(header().doesNotExist(HttpHeaders.EXPIRES)); .andExpect(header().doesNotExist(HttpHeaders.EXPIRES));
// @formatter:on
} }
@Test @Test
public void headerWhenNotSpringResourceThenCacheRelatedHeadersSet() throws Exception { public void headerWhenNotSpringResourceThenCacheRelatedHeadersSet() throws Exception {
// @formatter:off
this.mockMvc.perform(get("/notresource")) this.mockMvc.perform(get("/notresource"))
.andExpect(header().string(HttpHeaders.CACHE_CONTROL, "no-cache, no-store, max-age=0, must-revalidate")) .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.PRAGMA, "no-cache"))
.andExpect(header().string(HttpHeaders.EXPIRES, "0")); .andExpect(header().string(HttpHeaders.EXPIRES, "0"));
// @formatter:on
} }
@EnableWebSecurity @EnableWebSecurity
@ -97,8 +102,11 @@ public class HttpSecurityHeadersTests {
@Override @Override
public void addResourceHandlers(ResourceHandlerRegistry registry) { public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations("classpath:/resources/") // @formatter:off
registry.addResourceHandler("/resources/**")
.addResourceLocations("classpath:/resources/")
.setCachePeriod(12345); .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.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.test.web.servlet.MockMvc; 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.ContentNegotiationStrategy;
import org.springframework.web.accept.HeaderContentNegotiationStrategy; import org.springframework.web.accept.HeaderContentNegotiationStrategy;
import org.springframework.web.filter.OncePerRequestFilter; import org.springframework.web.filter.OncePerRequestFilter;
@ -83,12 +84,15 @@ public class WebSecurityConfigurerAdapterTests {
@Test @Test
public void loadConfigWhenRequestSecureThenDefaultSecurityHeadersReturned() throws Exception { public void loadConfigWhenRequestSecureThenDefaultSecurityHeadersReturned() throws Exception {
this.spring.register(HeadersArePopulatedByDefaultConfig.class).autowire(); 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("X-Frame-Options", "DENY"))
.andExpect(header().string("Strict-Transport-Security", "max-age=31536000 ; includeSubDomains")) .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("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("Pragma", "no-cache")).andExpect(header().string("Expires", "0"))
.andExpect(header().string("X-XSS-Protection", "1; mode=block")); .andExpect(header().string("X-XSS-Protection", "1; mode=block"));
// @formatter:on
} }
@Test @Test
@ -188,10 +192,9 @@ public class WebSecurityConfigurerAdapterTests {
public void performWhenUsingAuthenticationEventPublisherInDslThenUses() throws Exception { public void performWhenUsingAuthenticationEventPublisherInDslThenUses() throws Exception {
this.spring.register(CustomAuthenticationEventPublisherDsl.class).autowire(); this.spring.register(CustomAuthenticationEventPublisherDsl.class).autowire();
AuthenticationEventPublisher authenticationEventPublisher = CustomAuthenticationEventPublisherDsl.EVENT_PUBLISHER; AuthenticationEventPublisher authenticationEventPublisher = CustomAuthenticationEventPublisherDsl.EVENT_PUBLISHER;
this.mockMvc.perform(get("/").with(httpBasic("user", "password"))); // fails since MockHttpServletRequestBuilder userRequest = get("/").with(httpBasic("user", "password"));
// no // fails since no providers configured
// providers this.mockMvc.perform(userRequest);
// configured
verify(authenticationEventPublisher).publishAuthenticationFailure(any(AuthenticationException.class), verify(authenticationEventPublisher).publishAuthenticationFailure(any(AuthenticationException.class),
any(Authentication.class)); any(Authentication.class));
} }

View File

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

View File

@ -68,7 +68,11 @@ public class AuthenticationPrincipalArgumentResolverTests {
new UsernamePasswordAuthenticationToken(user, user.getPassword(), user.getAuthorities())); new UsernamePasswordAuthenticationToken(user, user.getPassword(), user.getAuthorities()));
SecurityContextHolder.setContext(context); SecurityContextHolder.setContext(context);
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); 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 @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.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter;
import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult; 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.GetMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
@ -81,6 +82,7 @@ public class HttpSecurityConfigurationTests {
@Test @Test
public void getWhenDefaultFilterChainBeanThenDefaultHeadersInResponse() throws Exception { public void getWhenDefaultFilterChainBeanThenDefaultHeadersInResponse() throws Exception {
this.spring.register(DefaultWithFilterChainConfig.class).autowire(); this.spring.register(DefaultWithFilterChainConfig.class).autowire();
// @formatter:off
MvcResult mvcResult = this.mockMvc.perform(get("/").secure(true)) MvcResult mvcResult = this.mockMvc.perform(get("/").secure(true))
.andExpect(header().string(HttpHeaders.X_CONTENT_TYPE_OPTIONS, "nosniff")) .andExpect(header().string(HttpHeaders.X_CONTENT_TYPE_OPTIONS, "nosniff"))
.andExpect(header().string(HttpHeaders.X_FRAME_OPTIONS, .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.CACHE_CONTROL, "no-cache, no-store, max-age=0, must-revalidate"))
.andExpect(header().string(HttpHeaders.EXPIRES, "0")) .andExpect(header().string(HttpHeaders.EXPIRES, "0"))
.andExpect(header().string(HttpHeaders.PRAGMA, "no-cache")) .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( assertThat(mvcResult.getResponse().getHeaderNames()).containsExactlyInAnyOrder(
HttpHeaders.X_CONTENT_TYPE_OPTIONS, HttpHeaders.X_FRAME_OPTIONS, HttpHeaders.STRICT_TRANSPORT_SECURITY, HttpHeaders.X_CONTENT_TYPE_OPTIONS, HttpHeaders.X_FRAME_OPTIONS, HttpHeaders.STRICT_TRANSPORT_SECURITY,
HttpHeaders.CACHE_CONTROL, HttpHeaders.EXPIRES, HttpHeaders.PRAGMA, HttpHeaders.X_XSS_PROTECTION); HttpHeaders.CACHE_CONTROL, HttpHeaders.EXPIRES, HttpHeaders.PRAGMA, HttpHeaders.X_XSS_PROTECTION);
@ -99,21 +103,33 @@ public class HttpSecurityConfigurationTests {
@Test @Test
public void logoutWhenDefaultFilterChainBeanThenCreatesDefaultLogoutEndpoint() throws Exception { public void logoutWhenDefaultFilterChainBeanThenCreatesDefaultLogoutEndpoint() throws Exception {
this.spring.register(DefaultWithFilterChainConfig.class).autowire(); 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 @Test
public void loadConfigWhenDefaultConfigThenWebAsyncManagerIntegrationFilterAdded() throws Exception { public void loadConfigWhenDefaultConfigThenWebAsyncManagerIntegrationFilterAdded() throws Exception {
this.spring.register(DefaultWithFilterChainConfig.class, NameController.class).autowire(); 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(); .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 @Test
public void getWhenDefaultFilterChainBeanThenAnonymousPermitted() throws Exception { public void getWhenDefaultFilterChainBeanThenAnonymousPermitted() throws Exception {
this.spring.register(AuthorizeRequestsConfig.class, UserDetailsConfig.class, BaseController.class).autowire(); 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 @Test
@ -121,29 +137,48 @@ public class HttpSecurityConfigurationTests {
this.spring.register(SecurityEnabledConfig.class, UserDetailsConfig.class).autowire(); this.spring.register(SecurityEnabledConfig.class, UserDetailsConfig.class).autowire();
MockHttpSession session = new MockHttpSession(); MockHttpSession session = new MockHttpSession();
String sessionId = session.getId(); String sessionId = session.getId();
MvcResult result = this.mockMvc.perform( // @formatter:off
post("/login").param("username", "user").param("password", "password").session(session).with(csrf())) MockHttpServletRequestBuilder loginRequest = post("/login")
.andReturn(); .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); assertThat(result.getRequest().getSession(false).getId()).isNotEqualTo(sessionId);
} }
@Test @Test
public void authenticateWhenDefaultFilterChainBeanThenRedirectsToSavedRequest() throws Exception { public void authenticateWhenDefaultFilterChainBeanThenRedirectsToSavedRequest() throws Exception {
this.spring.register(SecurityEnabledConfig.class, UserDetailsConfig.class).autowire(); 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(); .getSession();
this.mockMvc.perform( // @formatter:on
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());
// @formatter:on
// @formatter:off
this.mockMvc.perform(loginRequest)
.andExpect(redirectedUrl("http://localhost/messages")); .andExpect(redirectedUrl("http://localhost/messages"));
// @formatter:on
} }
@Test @Test
public void authenticateWhenDefaultFilterChainBeanThenRolePrefixIsSet() throws Exception { public void authenticateWhenDefaultFilterChainBeanThenRolePrefixIsSet() throws Exception {
this.spring.register(SecurityEnabledConfig.class, UserDetailsConfig.class, UserController.class).autowire(); this.spring.register(SecurityEnabledConfig.class, UserDetailsConfig.class, UserController.class).autowire();
TestingAuthenticationToken user = new TestingAuthenticationToken("user", "password", "ROLE_USER");
// @formatter:off
this.mockMvc this.mockMvc
.perform(get("/user") .perform(get("/user").with(authentication(user)))
.with(authentication(new TestingAuthenticationToken("user", "password", "ROLE_USER"))))
.andExpect(status().isOk()); .andExpect(status().isOk());
// @formatter:on
} }
@Test @Test
@ -177,7 +212,13 @@ public class HttpSecurityConfigurationTests {
@Bean @Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception { 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 @Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception { SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http.authorizeRequests((authorize) -> authorize.anyRequest().authenticated()) // @formatter:off
.formLogin(withDefaults()).build(); return http
.authorizeRequests((authorize) -> authorize
.anyRequest().authenticated()
)
.formLogin(withDefaults())
.build();
// @formatter:on
} }
} }
@ -198,8 +245,13 @@ public class HttpSecurityConfigurationTests {
@Bean @Bean
UserDetailsService userDetailsService() { 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(); .build();
// @formatter:on
return new InMemoryUserDetailsManager(user); 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.oauth2.core.endpoint.OAuth2AccessTokenResponse;
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors; import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors;
import org.springframework.test.web.servlet.MockMvc; 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.GetMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.config.annotation.EnableWebMvc; 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.verify;
import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.verifyZeroInteractions; 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.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@ -97,7 +99,7 @@ public class OAuth2ClientConfigurationTests {
this.spring.register(OAuth2AuthorizedClientArgumentResolverConfig.class).autowire(); this.spring.register(OAuth2AuthorizedClientArgumentResolverConfig.class).autowire();
this.mockMvc this.mockMvc
.perform(get("/authorized-client") .perform(get("/authorized-client")
.with(SecurityMockMvcRequestPostProcessors.authentication(authentication))) .with(authentication(authentication)))
.andExpect(status().isOk()).andExpect(content().string("resolved")); .andExpect(status().isOk()).andExpect(content().string("resolved"));
verifyZeroInteractions(accessTokenResponseClient); verifyZeroInteractions(accessTokenResponseClient);
} }
@ -114,18 +116,26 @@ public class OAuth2ClientConfigurationTests {
ClientRegistration clientRegistration = TestClientRegistrations.clientCredentials() ClientRegistration clientRegistration = TestClientRegistrations.clientCredentials()
.registrationId(clientRegistrationId).build(); .registrationId(clientRegistrationId).build();
given(clientRegistrationRepository.findByRegistrationId(clientRegistrationId)).willReturn(clientRegistration); given(clientRegistrationRepository.findByRegistrationId(clientRegistrationId)).willReturn(clientRegistration);
OAuth2AccessTokenResponse accessTokenResponse = OAuth2AccessTokenResponse.withToken("access-token-1234") // @formatter:off
.tokenType(OAuth2AccessToken.TokenType.BEARER).expiresIn(300).build(); OAuth2AccessTokenResponse accessTokenResponse = OAuth2AccessTokenResponse
.withToken("access-token-1234")
.tokenType(OAuth2AccessToken.TokenType.BEARER)
.expiresIn(300)
.build();
// @formatter:on
given(accessTokenResponseClient.getTokenResponse(any(OAuth2ClientCredentialsGrantRequest.class))) given(accessTokenResponseClient.getTokenResponse(any(OAuth2ClientCredentialsGrantRequest.class)))
.willReturn(accessTokenResponse); .willReturn(accessTokenResponse);
OAuth2AuthorizedClientArgumentResolverConfig.CLIENT_REGISTRATION_REPOSITORY = clientRegistrationRepository; OAuth2AuthorizedClientArgumentResolverConfig.CLIENT_REGISTRATION_REPOSITORY = clientRegistrationRepository;
OAuth2AuthorizedClientArgumentResolverConfig.AUTHORIZED_CLIENT_REPOSITORY = authorizedClientRepository; OAuth2AuthorizedClientArgumentResolverConfig.AUTHORIZED_CLIENT_REPOSITORY = authorizedClientRepository;
OAuth2AuthorizedClientArgumentResolverConfig.ACCESS_TOKEN_RESPONSE_CLIENT = accessTokenResponseClient; OAuth2AuthorizedClientArgumentResolverConfig.ACCESS_TOKEN_RESPONSE_CLIENT = accessTokenResponseClient;
this.spring.register(OAuth2AuthorizedClientArgumentResolverConfig.class).autowire(); this.spring.register(OAuth2AuthorizedClientArgumentResolverConfig.class).autowire();
this.mockMvc MockHttpServletRequestBuilder authenticatedRequest = get("/authorized-client")
.perform(get("/authorized-client") .with(authentication(authentication));
.with(SecurityMockMvcRequestPostProcessors.authentication(authentication))) // @formatter:off
.andExpect(status().isOk()).andExpect(content().string("resolved")); this.mockMvc.perform(authenticatedRequest)
.andExpect(status().isOk())
.andExpect(content().string("resolved"));
// @formatter:on
verify(accessTokenResponseClient, times(1)).getTokenResponse(any(OAuth2ClientCredentialsGrantRequest.class)); verify(accessTokenResponseClient, times(1)).getTokenResponse(any(OAuth2ClientCredentialsGrantRequest.class));
} }
@ -150,20 +160,25 @@ public class OAuth2ClientConfigurationTests {
@Test @Test
public void loadContextWhenClientRegistrationRepositoryRegisteredTwiceThenThrowNoUniqueBeanDefinitionException() { public void loadContextWhenClientRegistrationRepositoryRegisteredTwiceThenThrowNoUniqueBeanDefinitionException() {
// @formatter:off
assertThatExceptionOfType(Exception.class) assertThatExceptionOfType(Exception.class)
.isThrownBy( .isThrownBy(
() -> this.spring.register(ClientRegistrationRepositoryRegisteredTwiceConfig.class).autowire()) () -> this.spring.register(ClientRegistrationRepositoryRegisteredTwiceConfig.class).autowire())
.withMessageContaining( .withMessageContaining(
"expected single matching bean but found 2: clientRegistrationRepository1,clientRegistrationRepository2") "expected single matching bean but found 2: clientRegistrationRepository1,clientRegistrationRepository2")
.withRootCauseInstanceOf(NoUniqueBeanDefinitionException.class); .withRootCauseInstanceOf(NoUniqueBeanDefinitionException.class);
// @formatter:on
} }
@Test @Test
public void loadContextWhenAccessTokenResponseClientRegisteredTwiceThenThrowNoUniqueBeanDefinitionException() { public void loadContextWhenAccessTokenResponseClientRegisteredTwiceThenThrowNoUniqueBeanDefinitionException() {
// @formatter:off
assertThatExceptionOfType(Exception.class) assertThatExceptionOfType(Exception.class)
.isThrownBy(() -> this.spring.register(AccessTokenResponseClientRegisteredTwiceConfig.class).autowire()) .isThrownBy(() -> this.spring.register(AccessTokenResponseClientRegisteredTwiceConfig.class).autowire())
.withRootCauseInstanceOf(NoUniqueBeanDefinitionException.class).withMessageContaining( .withRootCauseInstanceOf(NoUniqueBeanDefinitionException.class)
.withMessageContaining(
"expected single matching bean but found 2: accessTokenResponseClient1,accessTokenResponseClient2"); "expected single matching bean but found 2: accessTokenResponseClient1,accessTokenResponseClient2");
// @formatter:on
} }
// gh-8700 // gh-8700
@ -184,10 +199,14 @@ public class OAuth2ClientConfigurationTests {
OAuth2AuthorizedClientManagerRegisteredConfig.AUTHORIZED_CLIENT_REPOSITORY = authorizedClientRepository; OAuth2AuthorizedClientManagerRegisteredConfig.AUTHORIZED_CLIENT_REPOSITORY = authorizedClientRepository;
OAuth2AuthorizedClientManagerRegisteredConfig.AUTHORIZED_CLIENT_MANAGER = authorizedClientManager; OAuth2AuthorizedClientManagerRegisteredConfig.AUTHORIZED_CLIENT_MANAGER = authorizedClientManager;
this.spring.register(OAuth2AuthorizedClientManagerRegisteredConfig.class).autowire(); this.spring.register(OAuth2AuthorizedClientManagerRegisteredConfig.class).autowire();
MockHttpServletRequestBuilder authenticatedRequest = get("/authorized-client")
.with(authentication(authentication));
// @formatter:off
this.mockMvc this.mockMvc
.perform(get("/authorized-client") .perform(authenticatedRequest)
.with(SecurityMockMvcRequestPostProcessors.authentication(authentication))) .andExpect(status().isOk())
.andExpect(status().isOk()).andExpect(content().string("resolved")); .andExpect(content().string("resolved"));
// @formatter:on
verify(authorizedClientManager).authorize(any()); verify(authorizedClientManager).authorize(any());
verifyNoInteractions(clientRegistrationRepository); verifyNoInteractions(clientRegistrationRepository);
verifyNoInteractions(authorizedClientRepository); 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.oauth2.server.resource.web.reactive.function.client.ServletBearerExchangeFilterFunction;
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors; import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors;
import org.springframework.test.web.servlet.MockMvc; 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.GetMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.reactive.function.client.WebClient; 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.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@ -63,8 +65,12 @@ public class SecurityReactorContextConfigurationResourceServerTests {
public void requestWhenUsingFilterThenBearerTokenPropagated() throws Exception { public void requestWhenUsingFilterThenBearerTokenPropagated() throws Exception {
BearerTokenAuthentication authentication = TestBearerTokenAuthentications.bearer(); BearerTokenAuthentication authentication = TestBearerTokenAuthentications.bearer();
this.spring.register(BearerFilterConfig.class, WebServerConfig.class, Controller.class).autowire(); this.spring.register(BearerFilterConfig.class, WebServerConfig.class, Controller.class).autowire();
this.mockMvc.perform(get("/token").with(SecurityMockMvcRequestPostProcessors.authentication(authentication))) MockHttpServletRequestBuilder authenticatedRequest = get("/token").with(authentication(authentication));
.andExpect(status().isOk()).andExpect(content().string("Bearer token")); // @formatter:off
this.mockMvc.perform(authenticatedRequest)
.andExpect(status().isOk())
.andExpect(content().string("Bearer token"));
// @formatter:on
} }
// gh-7418 // gh-7418
@ -72,8 +78,12 @@ public class SecurityReactorContextConfigurationResourceServerTests {
public void requestWhenNotUsingFilterThenBearerTokenNotPropagated() throws Exception { public void requestWhenNotUsingFilterThenBearerTokenNotPropagated() throws Exception {
BearerTokenAuthentication authentication = TestBearerTokenAuthentications.bearer(); BearerTokenAuthentication authentication = TestBearerTokenAuthentications.bearer();
this.spring.register(BearerFilterlessConfig.class, WebServerConfig.class, Controller.class).autowire(); this.spring.register(BearerFilterlessConfig.class, WebServerConfig.class, Controller.class).autowire();
this.mockMvc.perform(get("/token").with(SecurityMockMvcRequestPostProcessors.authentication(authentication))) MockHttpServletRequestBuilder authenticatedRequest = get("/token").with(authentication(authentication));
.andExpect(status().isOk()).andExpect(content().string("")); // @formatter:off
this.mockMvc.perform(authenticatedRequest)
.andExpect(status().isOk())
.andExpect(content().string(""));
// @formatter:on
} }
@EnableWebSecurity @EnableWebSecurity
@ -120,8 +130,18 @@ public class SecurityReactorContextConfigurationResourceServerTests {
@GetMapping("/token") @GetMapping("/token")
String token() { String token() {
return this.rest.get().uri(this.uri).retrieve().bodyToMono(String.class) // @formatter:off
.flatMap((result) -> this.rest.get().uri(this.uri).retrieve().bodyToMono(String.class)).block(); 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)); .setRequestAttributes(new ServletRequestAttributes(this.servletRequest, this.servletResponse));
SecurityContextHolder.getContext().setAuthentication(this.authentication); SecurityContextHolder.getContext().setAuthentication(this.authentication);
ClientResponse clientResponseOk = ClientResponse.create(HttpStatus.OK).build(); ClientResponse clientResponseOk = ClientResponse.create(HttpStatus.OK).build();
// @formatter:off
ExchangeFilterFunction filter = (req, next) -> Mono.subscriberContext() ExchangeFilterFunction filter = (req, next) -> Mono.subscriberContext()
.filter((ctx) -> ctx.hasKey(SecurityReactorContextSubscriber.SECURITY_CONTEXT_ATTRIBUTES)) .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) -> { .map((attributes) -> {
if (attributes.containsKey(HttpServletRequest.class) if (attributes.containsKey(HttpServletRequest.class)
&& attributes.containsKey(HttpServletResponse.class) && attributes.containsKey(HttpServletResponse.class)
@ -211,6 +213,7 @@ public class SecurityReactorContextConfigurationTests {
return ClientResponse.create(HttpStatus.NOT_FOUND).build(); return ClientResponse.create(HttpStatus.NOT_FOUND).build();
} }
}); });
// @formatter:on
ClientRequest clientRequest = ClientRequest.create(HttpMethod.GET, URI.create("https://example.com")).build(); ClientRequest clientRequest = ClientRequest.create(HttpMethod.GET, URI.create("https://example.com")).build();
MockExchangeFunction exchange = new MockExchangeFunction(); MockExchangeFunction exchange = new MockExchangeFunction();
Map<Object, Object> expectedContextAttributes = new HashMap<>(); Map<Object, Object> expectedContextAttributes = new HashMap<>();
@ -219,9 +222,14 @@ public class SecurityReactorContextConfigurationTests {
expectedContextAttributes.put(Authentication.class, this.authentication); expectedContextAttributes.put(Authentication.class, this.authentication);
Mono<ClientResponse> clientResponseMono = filter.filter(clientRequest, exchange) Mono<ClientResponse> clientResponseMono = filter.filter(clientRequest, exchange)
.flatMap((response) -> 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) .contains(SecurityReactorContextSubscriber.SECURITY_CONTEXT_ATTRIBUTES, expectedContextAttributes)
.then().expectNext(clientResponseOk).verifyComplete(); .then()
.expectNext(clientResponseOk)
.verifyComplete();
// @formatter:on
} }
@EnableWebSecurity @EnableWebSecurity

View File

@ -336,27 +336,51 @@ public class WebSecurityConfigurationTests {
@Order(1) @Order(1)
@Bean @Bean
SecurityFilterChain filterChain1(HttpSecurity http) throws Exception { 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(); .build();
// @formatter:on
} }
@Order(2) @Order(2)
@Bean @Bean
SecurityFilterChain filterChain2(HttpSecurity http) throws Exception { 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(); .build();
// @formatter:on
} }
@Order(3) @Order(3)
@Bean @Bean
SecurityFilterChain filterChain3(HttpSecurity http) throws Exception { 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(); .build();
// @formatter:on
} }
@Bean @Bean
SecurityFilterChain filterChain4(HttpSecurity http) throws Exception { 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 @Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { 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) @Order(2)
@Bean @Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception { SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
return http.antMatcher("/filter/**") // @formatter:off
.authorizeRequests((authorize) -> authorize.anyRequest().authenticated()).build(); return http
.antMatcher("/filter/**")
.authorizeRequests((authorize) -> authorize
.anyRequest().authenticated()
)
.build();
// @formatter:on
} }
@Order(1) @Order(1)
@ -633,7 +669,13 @@ public class WebSecurityConfigurationTests {
@Override @Override
protected void configure(HttpSecurity http) throws Exception { 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.security.web.util.matcher.RequestMatcher;
import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult; 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.GetMapping;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
@ -288,8 +289,13 @@ public class CsrfConfigurerTests {
given(CsrfTokenRepositoryConfig.REPO.loadToken(any())).willReturn(csrfToken); given(CsrfTokenRepositoryConfig.REPO.loadToken(any())).willReturn(csrfToken);
given(CsrfTokenRepositoryConfig.REPO.generateToken(any())).willReturn(csrfToken); given(CsrfTokenRepositoryConfig.REPO.generateToken(any())).willReturn(csrfToken);
this.spring.register(CsrfTokenRepositoryConfig.class, BasicController.class).autowire(); this.spring.register(CsrfTokenRepositoryConfig.class, BasicController.class).autowire();
this.mvc.perform(post("/login").with(csrf()).param("username", "user").param("password", "password")) // @formatter:off
.andExpect(redirectedUrl("/")); 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), verify(CsrfTokenRepositoryConfig.REPO).saveToken(isNull(), any(HttpServletRequest.class),
any(HttpServletResponse.class)); any(HttpServletResponse.class));
} }
@ -316,28 +322,40 @@ public class CsrfConfigurerTests {
@Test @Test
public void loginWhenNoCsrfTokenThenRespondsWithForbidden() throws Exception { public void loginWhenNoCsrfTokenThenRespondsWithForbidden() throws Exception {
this.spring.register(FormLoginConfig.class).autowire(); this.spring.register(FormLoginConfig.class).autowire();
this.mvc.perform(post("/login").param("username", "user").param("password", "password")) // @formatter:off
.andExpect(status().isForbidden()).andExpect(unauthenticated()); MockHttpServletRequestBuilder loginRequest = post("/login")
.param("username", "user")
.param("password", "password");
this.mvc.perform(loginRequest)
.andExpect(status().isForbidden())
.andExpect(unauthenticated());
// @formatter:on
} }
@Test @Test
public void logoutWhenNoCsrfTokenThenRespondsWithForbidden() throws Exception { public void logoutWhenNoCsrfTokenThenRespondsWithForbidden() throws Exception {
this.spring.register(FormLoginConfig.class).autowire(); 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()); .andExpect(authenticated());
// @formatter:on
} }
// SEC-2543 // SEC-2543
@Test @Test
public void logoutWhenCsrfEnabledAndGetRequestThenDoesNotLogout() throws Exception { public void logoutWhenCsrfEnabledAndGetRequestThenDoesNotLogout() throws Exception {
this.spring.register(FormLoginConfig.class).autowire(); 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 @Test
public void logoutWhenGetRequestAndGetEnabledForLogoutThenLogsOut() throws Exception { public void logoutWhenGetRequestAndGetEnabledForLogoutThenLogsOut() throws Exception {
this.spring.register(LogoutAllowsGetConfig.class).autowire(); 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 // SEC-2749
@ -366,8 +384,13 @@ public class CsrfConfigurerTests {
public void csrfAuthenticationStrategyConfiguredThenStrategyUsed() throws Exception { public void csrfAuthenticationStrategyConfiguredThenStrategyUsed() throws Exception {
CsrfAuthenticationStrategyConfig.STRATEGY = mock(SessionAuthenticationStrategy.class); CsrfAuthenticationStrategyConfig.STRATEGY = mock(SessionAuthenticationStrategy.class);
this.spring.register(CsrfAuthenticationStrategyConfig.class).autowire(); this.spring.register(CsrfAuthenticationStrategyConfig.class).autowire();
this.mvc.perform(post("/login").with(csrf()).param("username", "user").param("password", "password")) // @formatter:off
.andExpect(redirectedUrl("/")); 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), verify(CsrfAuthenticationStrategyConfig.STRATEGY, atLeastOnce()).onAuthentication(any(Authentication.class),
any(HttpServletRequest.class), any(HttpServletResponse.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.security.web.csrf.HttpSessionCsrfTokenRepository;
import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult; 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.assertThat;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
@ -76,26 +77,37 @@ public class DefaultLoginPageConfigurerTests {
this.spring.register(DefaultLoginPageConfig.class).autowire(); this.spring.register(DefaultLoginPageConfig.class).autowire();
CsrfToken csrfToken = new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "BaseSpringSpec_CSRFTOKEN"); CsrfToken csrfToken = new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "BaseSpringSpec_CSRFTOKEN");
String csrfAttributeName = HttpSessionCsrfTokenRepository.class.getName().concat(".CSRF_TOKEN"); String csrfAttributeName = HttpSessionCsrfTokenRepository.class.getName().concat(".CSRF_TOKEN");
// @formatter:off
this.mvc.perform(get("/login").sessionAttr(csrfAttributeName, csrfToken)) 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 charset=\"utf-8\">\n"
+ " <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\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" + " <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://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" + " <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" + " <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" + " <label for=\"username\" class=\"sr-only\">Username</label>\n"
+ " <input type=\"text\" id=\"username\" name=\"username\" class=\"form-control\" placeholder=\"Username\" required autofocus>\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" + " <label for=\"password\" class=\"sr-only\">Password</label>\n"
+ " <input type=\"password\" id=\"password\" name=\"password\" class=\"form-control\" placeholder=\"Password\" required>\n" + " <input type=\"password\" id=\"password\" name=\"password\" class=\"form-control\" placeholder=\"Password\" required>\n"
+ " </p>\n" + "<input name=\"" + csrfToken.getParameterName() + " </p>\n"
+ "\" 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" + " <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 @Test
@ -110,16 +122,22 @@ public class DefaultLoginPageConfigurerTests {
CsrfToken csrfToken = new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "BaseSpringSpec_CSRFTOKEN"); CsrfToken csrfToken = new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "BaseSpringSpec_CSRFTOKEN");
String csrfAttributeName = HttpSessionCsrfTokenRepository.class.getName().concat(".CSRF_TOKEN"); String csrfAttributeName = HttpSessionCsrfTokenRepository.class.getName().concat(".CSRF_TOKEN");
MvcResult mvcResult = this.mvc.perform(post("/login").with(csrf())).andReturn(); MvcResult mvcResult = this.mvc.perform(post("/login").with(csrf())).andReturn();
// @formatter:off
this.mvc.perform(get("/login?error").session((MockHttpSession) mvcResult.getRequest().getSession()) this.mvc.perform(get("/login?error").session((MockHttpSession) mvcResult.getRequest().getSession())
.sessionAttr(csrfAttributeName, csrfToken)) .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 charset=\"utf-8\">\n"
+ " <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\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" + " <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://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" + " <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" + " <form class=\"form-signin\" method=\"post\" action=\"/login\">\n"
+ " <h2 class=\"form-signin-heading\">Please sign in</h2>\n" + " <h2 class=\"form-signin-heading\">Please sign in</h2>\n"
+ "<div class=\"alert alert-danger\" role=\"alert\">Bad credentials</div> <p>\n" + "<div class=\"alert alert-danger\" role=\"alert\">Bad credentials</div> <p>\n"
@ -128,17 +146,25 @@ public class DefaultLoginPageConfigurerTests {
+ " </p>\n" + " <p>\n" + " </p>\n" + " <p>\n"
+ " <label for=\"password\" class=\"sr-only\">Password</label>\n" + " <label for=\"password\" class=\"sr-only\">Password</label>\n"
+ " <input type=\"password\" id=\"password\" name=\"password\" class=\"form-control\" placeholder=\"Password\" required>\n" + " <input type=\"password\" id=\"password\" name=\"password\" class=\"form-control\" placeholder=\"Password\" required>\n"
+ " </p>\n" + "<input name=\"" + csrfToken.getParameterName() + " </p>\n"
+ "\" 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" + " <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 @Test
public void loginWhenValidCredentialsThenRedirectsToDefaultSuccessPage() throws Exception { public void loginWhenValidCredentialsThenRedirectsToDefaultSuccessPage() throws Exception {
this.spring.register(DefaultLoginPageConfig.class).autowire(); this.spring.register(DefaultLoginPageConfig.class).autowire();
this.mvc.perform(post("/login").with(csrf()).param("username", "user").param("password", "password")) // @formatter:off
.andExpect(redirectedUrl("/")); MockHttpServletRequestBuilder loginRequest = post("/login")
.with(csrf())
.param("username", "user")
.param("password", "password");
// @formatter:on
this.mvc.perform(loginRequest).andExpect(redirectedUrl("/"));
} }
@Test @Test
@ -146,27 +172,37 @@ public class DefaultLoginPageConfigurerTests {
this.spring.register(DefaultLoginPageConfig.class).autowire(); this.spring.register(DefaultLoginPageConfig.class).autowire();
CsrfToken csrfToken = new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "BaseSpringSpec_CSRFTOKEN"); CsrfToken csrfToken = new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "BaseSpringSpec_CSRFTOKEN");
String csrfAttributeName = HttpSessionCsrfTokenRepository.class.getName().concat(".CSRF_TOKEN"); String csrfAttributeName = HttpSessionCsrfTokenRepository.class.getName().concat(".CSRF_TOKEN");
// @formatter:off
this.mvc.perform(get("/login?logout").sessionAttr(csrfAttributeName, csrfToken)) 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 charset=\"utf-8\">\n"
+ " <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\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" + " <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://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" + " <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" + " <form class=\"form-signin\" method=\"post\" action=\"/login\">\n"
+ " <h2 class=\"form-signin-heading\">Please sign in</h2>\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" + "<div class=\"alert alert-success\" role=\"alert\">You have been signed out</div> <p>\n"
+ " <label for=\"username\" class=\"sr-only\">Username</label>\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" + " <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" + " <label for=\"password\" class=\"sr-only\">Password</label>\n"
+ " <input type=\"password\" id=\"password\" name=\"password\" class=\"form-control\" placeholder=\"Password\" required>\n" + " <input type=\"password\" id=\"password\" name=\"password\" class=\"form-control\" placeholder=\"Password\" required>\n"
+ " </p>\n" + "<input name=\"" + csrfToken.getParameterName() + " </p>\n"
+ "\" 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" + " <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 @Test
@ -186,28 +222,38 @@ public class DefaultLoginPageConfigurerTests {
this.spring.register(DefaultLoginPageWithRememberMeConfig.class).autowire(); this.spring.register(DefaultLoginPageWithRememberMeConfig.class).autowire();
CsrfToken csrfToken = new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "BaseSpringSpec_CSRFTOKEN"); CsrfToken csrfToken = new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "BaseSpringSpec_CSRFTOKEN");
String csrfAttributeName = HttpSessionCsrfTokenRepository.class.getName().concat(".CSRF_TOKEN"); String csrfAttributeName = HttpSessionCsrfTokenRepository.class.getName().concat(".CSRF_TOKEN");
// @formatter:off
this.mvc.perform(get("/login").sessionAttr(csrfAttributeName, csrfToken)) 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 charset=\"utf-8\">\n"
+ " <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\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" + " <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://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" + " <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" + " <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" + " <label for=\"username\" class=\"sr-only\">Username</label>\n"
+ " <input type=\"text\" id=\"username\" name=\"username\" class=\"form-control\" placeholder=\"Username\" required autofocus>\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" + " <label for=\"password\" class=\"sr-only\">Password</label>\n"
+ " <input type=\"password\" id=\"password\" name=\"password\" class=\"form-control\" placeholder=\"Password\" required>\n" + " <input type=\"password\" id=\"password\" name=\"password\" class=\"form-control\" placeholder=\"Password\" required>\n"
+ " </p>\n" + " </p>\n"
+ "<p><input type='checkbox' name='remember-me'/> Remember me on this computer.</p>\n" + "<p><input type='checkbox' name='remember-me'/> Remember me on this computer.</p>\n"
+ "<input name=\"" + csrfToken.getParameterName() + "\" type=\"hidden\" value=\"" + "<input name=\"" + csrfToken.getParameterName() + "\" type=\"hidden\" value=\"" + csrfToken.getToken() + "\" />\n"
+ csrfToken.getToken() + "\" />\n"
+ " <button class=\"btn btn-lg btn-primary btn-block\" type=\"submit\">Sign in</button>\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 @Test
@ -215,23 +261,33 @@ public class DefaultLoginPageConfigurerTests {
this.spring.register(DefaultLoginPageWithOpenIDConfig.class).autowire(); this.spring.register(DefaultLoginPageWithOpenIDConfig.class).autowire();
CsrfToken csrfToken = new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "BaseSpringSpec_CSRFTOKEN"); CsrfToken csrfToken = new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "BaseSpringSpec_CSRFTOKEN");
String csrfAttributeName = HttpSessionCsrfTokenRepository.class.getName().concat(".CSRF_TOKEN"); String csrfAttributeName = HttpSessionCsrfTokenRepository.class.getName().concat(".CSRF_TOKEN");
// @formatter:off
this.mvc.perform(get("/login").sessionAttr(csrfAttributeName, csrfToken)) 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 charset=\"utf-8\">\n"
+ " <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\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" + " <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://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" + " <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" + " <form name=\"oidf\" class=\"form-signin\" method=\"post\" action=\"/login/openid\">\n"
+ " <h2 class=\"form-signin-heading\">Login with OpenID Identity</h2>\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" + " <input type=\"text\" id=\"username\" name=\"openid_identifier\" class=\"form-control\" placeholder=\"Username\" required autofocus>\n"
+ " </p>\n" + "<input name=\"" + csrfToken.getParameterName() + " </p>\n"
+ "\" 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" + " <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 @Test
@ -240,37 +296,45 @@ public class DefaultLoginPageConfigurerTests {
CsrfToken csrfToken = new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "BaseSpringSpec_CSRFTOKEN"); CsrfToken csrfToken = new DefaultCsrfToken("X-CSRF-TOKEN", "_csrf", "BaseSpringSpec_CSRFTOKEN");
String csrfAttributeName = HttpSessionCsrfTokenRepository.class.getName().concat(".CSRF_TOKEN"); String csrfAttributeName = HttpSessionCsrfTokenRepository.class.getName().concat(".CSRF_TOKEN");
this.mvc.perform(get("/login").sessionAttr(csrfAttributeName, csrfToken)) 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 charset=\"utf-8\">\n"
+ " <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\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" + " <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://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" + " <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" + " <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" + " <label for=\"username\" class=\"sr-only\">Username</label>\n"
+ " <input type=\"text\" id=\"username\" name=\"username\" class=\"form-control\" placeholder=\"Username\" required autofocus>\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" + " <label for=\"password\" class=\"sr-only\">Password</label>\n"
+ " <input type=\"password\" id=\"password\" name=\"password\" class=\"form-control\" placeholder=\"Password\" required>\n" + " <input type=\"password\" id=\"password\" name=\"password\" class=\"form-control\" placeholder=\"Password\" required>\n"
+ " </p>\n" + " </p>\n"
+ "<p><input type='checkbox' name='remember-me'/> Remember me on this computer.</p>\n" + "<p><input type='checkbox' name='remember-me'/> Remember me on this computer.</p>\n"
+ "<input name=\"" + csrfToken.getParameterName() + "\" type=\"hidden\" value=\"" + "<input name=\"" + csrfToken.getParameterName() + "\" type=\"hidden\" value=\"" + csrfToken.getToken() + "\" />\n"
+ csrfToken.getToken() + "\" />\n"
+ " <button class=\"btn btn-lg btn-primary btn-block\" type=\"submit\">Sign in</button>\n" + " <button class=\"btn btn-lg btn-primary btn-block\" type=\"submit\">Sign in</button>\n"
+ " </form>\n" + " </form>\n"
+ " <form name=\"oidf\" class=\"form-signin\" method=\"post\" action=\"/login/openid\">\n" + " <form name=\"oidf\" class=\"form-signin\" method=\"post\" action=\"/login/openid\">\n"
+ " <h2 class=\"form-signin-heading\">Login with OpenID Identity</h2>\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" + " <input type=\"text\" id=\"username\" name=\"openid_identifier\" class=\"form-control\" placeholder=\"Username\" required autofocus>\n"
+ " </p>\n" + " </p>\n"
+ "<p><input type='checkbox' name='remember-me'/> Remember me on this computer.</p>\n" + "<p><input type='checkbox' name='remember-me'/> Remember me on this computer.</p>\n"
+ "<input name=\"" + csrfToken.getParameterName() + "\" type=\"hidden\" value=\"" + "<input name=\"" + csrfToken.getParameterName() + "\" type=\"hidden\" value=\"" + csrfToken.getToken() + "\" />\n"
+ csrfToken.getToken() + "\" />\n"
+ " <button class=\"btn btn-lg btn-primary btn-block\" type=\"submit\">Sign in</button>\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 @Test

View File

@ -322,8 +322,14 @@ public class ExceptionHandlingConfigurerTests {
@Override @Override
protected void configure(HttpSecurity http) throws Exception { protected void configure(HttpSecurity http) throws Exception {
// @formatter:on // @formatter:on
http.authorizeRequests().anyRequest().authenticated().and().exceptionHandling() http
.authenticationEntryPoint(AEP).and().exceptionHandling(); .authorizeRequests()
.anyRequest().authenticated()
.and()
.exceptionHandling()
.authenticationEntryPoint(AEP)
.and()
.exceptionHandling();
// @formatter:off // @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.expression.WebSecurityExpressionRoot;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor; import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.test.web.servlet.MockMvc; 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.GetMapping;
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PostMapping;
@ -113,16 +114,24 @@ public class ExpressionUrlAuthorizationConfigurerTests {
@Test @Test
public void getWhenHasAnyAuthorityRoleUserConfiguredAndAuthorityIsRoleUserThenRespondsWithOk() throws Exception { public void getWhenHasAnyAuthorityRoleUserConfiguredAndAuthorityIsRoleUserThenRespondsWithOk() throws Exception {
this.spring.register(RoleUserAnyAuthorityConfig.class, BasicController.class).autowire(); this.spring.register(RoleUserAnyAuthorityConfig.class, BasicController.class).autowire();
this.mvc.perform(get("/").with(user("user").authorities(new SimpleGrantedAuthority("ROLE_USER")))) // @formatter:off
.andExpect(status().isOk()); MockHttpServletRequestBuilder requestWithUser = get("/")
.with(user("user")
.authorities(new SimpleGrantedAuthority("ROLE_USER")));
// @formatter:on
this.mvc.perform(requestWithUser).andExpect(status().isOk());
} }
@Test @Test
public void getWhenHasAnyAuthorityRoleUserConfiguredAndAuthorityIsRoleAdminThenRespondsWithForbidden() public void getWhenHasAnyAuthorityRoleUserConfiguredAndAuthorityIsRoleAdminThenRespondsWithForbidden()
throws Exception { throws Exception {
this.spring.register(RoleUserAnyAuthorityConfig.class, BasicController.class).autowire(); this.spring.register(RoleUserAnyAuthorityConfig.class, BasicController.class).autowire();
this.mvc.perform(get("/").with(user("user").authorities(new SimpleGrantedAuthority("ROLE_ADMIN")))) // @formatter:off
.andExpect(status().isForbidden()); MockHttpServletRequestBuilder requestWithAdmin = get("/")
.with(user("user")
.authorities(new SimpleGrantedAuthority("ROLE_ADMIN")));
// @formatter:on
this.mvc.perform(requestWithAdmin).andExpect(status().isForbidden());
} }
@Test @Test
@ -134,16 +143,24 @@ public class ExpressionUrlAuthorizationConfigurerTests {
@Test @Test
public void getWhenHasAuthorityRoleUserConfiguredAndAuthorityIsRoleUserThenRespondsWithOk() throws Exception { public void getWhenHasAuthorityRoleUserConfiguredAndAuthorityIsRoleUserThenRespondsWithOk() throws Exception {
this.spring.register(RoleUserAuthorityConfig.class, BasicController.class).autowire(); this.spring.register(RoleUserAuthorityConfig.class, BasicController.class).autowire();
this.mvc.perform(get("/").with(user("user").authorities(new SimpleGrantedAuthority("ROLE_USER")))) // @formatter:off
.andExpect(status().isOk()); MockHttpServletRequestBuilder requestWithUser = get("/")
.with(user("user")
.authorities(new SimpleGrantedAuthority("ROLE_USER")));
// @formatter:on
this.mvc.perform(requestWithUser).andExpect(status().isOk());
} }
@Test @Test
public void getWhenHasAuthorityRoleUserConfiguredAndAuthorityIsRoleAdminThenRespondsWithForbidden() public void getWhenHasAuthorityRoleUserConfiguredAndAuthorityIsRoleAdminThenRespondsWithForbidden()
throws Exception { throws Exception {
this.spring.register(RoleUserAuthorityConfig.class, BasicController.class).autowire(); this.spring.register(RoleUserAuthorityConfig.class, BasicController.class).autowire();
this.mvc.perform(get("/").with(user("user").authorities(new SimpleGrantedAuthority("ROLE_ADMIN")))) // @formatter:off
.andExpect(status().isForbidden()); MockHttpServletRequestBuilder requestWithAdmin = get("/")
.with(user("user")
.authorities(new SimpleGrantedAuthority("ROLE_ADMIN")));
// @formatter:on
this.mvc.perform(requestWithAdmin).andExpect(status().isForbidden());
} }
@Test @Test
@ -155,22 +172,35 @@ public class ExpressionUrlAuthorizationConfigurerTests {
@Test @Test
public void getWhenAuthorityRoleUserOrAdminRequiredAndAuthorityIsRoleUserThenRespondsWithOk() throws Exception { public void getWhenAuthorityRoleUserOrAdminRequiredAndAuthorityIsRoleUserThenRespondsWithOk() throws Exception {
this.spring.register(RoleUserOrRoleAdminAuthorityConfig.class, BasicController.class).autowire(); this.spring.register(RoleUserOrRoleAdminAuthorityConfig.class, BasicController.class).autowire();
this.mvc.perform(get("/").with(user("user").authorities(new SimpleGrantedAuthority("ROLE_USER")))) // @formatter:off
.andExpect(status().isOk()); MockHttpServletRequestBuilder requestWithUser = get("/")
.with(user("user")
.authorities(new SimpleGrantedAuthority("ROLE_USER")));
// @formatter:on
this.mvc.perform(requestWithUser).andExpect(status().isOk());
} }
@Test @Test
public void getWhenAuthorityRoleUserOrAdminRequiredAndAuthorityIsRoleAdminThenRespondsWithOk() throws Exception { public void getWhenAuthorityRoleUserOrAdminRequiredAndAuthorityIsRoleAdminThenRespondsWithOk() throws Exception {
this.spring.register(RoleUserOrRoleAdminAuthorityConfig.class, BasicController.class).autowire(); this.spring.register(RoleUserOrRoleAdminAuthorityConfig.class, BasicController.class).autowire();
this.mvc.perform(get("/").with(user("user").authorities(new SimpleGrantedAuthority("ROLE_ADMIN")))) // @formatter:off
.andExpect(status().isOk()); MockHttpServletRequestBuilder requestWithUser = get("/")
.with(user("user")
.authorities(new SimpleGrantedAuthority("ROLE_ADMIN")));
// @formatter:on
this.mvc.perform(requestWithUser).andExpect(status().isOk());
} }
@Test @Test
public void getWhenAuthorityRoleUserOrAdminRequiredAndAuthorityIsRoleOtherThenRespondsWithForbidden() public void getWhenAuthorityRoleUserOrAdminRequiredAndAuthorityIsRoleOtherThenRespondsWithForbidden()
throws Exception { throws Exception {
this.spring.register(RoleUserOrRoleAdminAuthorityConfig.class, BasicController.class).autowire(); 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()); .andExpect(status().isForbidden());
} }
@ -183,31 +213,56 @@ public class ExpressionUrlAuthorizationConfigurerTests {
@Test @Test
public void getWhenHasAnyRoleUserConfiguredAndRoleIsUserThenRespondsWithOk() throws Exception { public void getWhenHasAnyRoleUserConfiguredAndRoleIsUserThenRespondsWithOk() throws Exception {
this.spring.register(RoleUserConfig.class, BasicController.class).autowire(); 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 @Test
public void getWhenHasAnyRoleUserConfiguredAndRoleIsAdminThenRespondsWithForbidden() throws Exception { public void getWhenHasAnyRoleUserConfiguredAndRoleIsAdminThenRespondsWithForbidden() throws Exception {
this.spring.register(RoleUserConfig.class, BasicController.class).autowire(); 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 @Test
public void getWhenRoleUserOrAdminConfiguredAndRoleIsUserThenRespondsWithOk() throws Exception { public void getWhenRoleUserOrAdminConfiguredAndRoleIsUserThenRespondsWithOk() throws Exception {
this.spring.register(RoleUserOrAdminConfig.class, BasicController.class).autowire(); 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 @Test
public void getWhenRoleUserOrAdminConfiguredAndRoleIsAdminThenRespondsWithOk() throws Exception { public void getWhenRoleUserOrAdminConfiguredAndRoleIsAdminThenRespondsWithOk() throws Exception {
this.spring.register(RoleUserOrAdminConfig.class, BasicController.class).autowire(); 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 @Test
public void getWhenRoleUserOrAdminConfiguredAndRoleIsOtherThenRespondsWithForbidden() throws Exception { public void getWhenRoleUserOrAdminConfiguredAndRoleIsOtherThenRespondsWithForbidden() throws Exception {
this.spring.register(RoleUserOrAdminConfig.class, BasicController.class).autowire(); 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 @Test
@ -237,7 +292,8 @@ public class ExpressionUrlAuthorizationConfigurerTests {
@Test @Test
public void getWhenAnonymousConfiguredAndLoggedInUserThenRespondsWithForbidden() throws Exception { public void getWhenAnonymousConfiguredAndLoggedInUserThenRespondsWithForbidden() throws Exception {
this.spring.register(AnonymousConfig.class, BasicController.class).autowire(); 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 @Test
@ -249,9 +305,9 @@ public class ExpressionUrlAuthorizationConfigurerTests {
@Test @Test
public void getWhenRememberMeConfiguredAndRememberMeTokenThenRespondsWithOk() throws Exception { public void getWhenRememberMeConfiguredAndRememberMeTokenThenRespondsWithOk() throws Exception {
this.spring.register(RememberMeConfig.class, BasicController.class).autowire(); this.spring.register(RememberMeConfig.class, BasicController.class).autowire();
this.mvc.perform(get("/").with(authentication( RememberMeAuthenticationToken rememberme = new RememberMeAuthenticationToken("key", "user", AuthorityUtils.createAuthorityList("ROLE_USER"));
new RememberMeAuthenticationToken("key", "user", AuthorityUtils.createAuthorityList("ROLE_USER"))))) MockHttpServletRequestBuilder requestWithRememberme = get("/").with(authentication(rememberme));
.andExpect(status().isOk()); this.mvc.perform(requestWithRememberme).andExpect(status().isOk());
} }
@Test @Test
@ -263,7 +319,8 @@ public class ExpressionUrlAuthorizationConfigurerTests {
@Test @Test
public void getWheDenyAllConfiguredAndUserLoggedInThenRespondsWithForbidden() throws Exception { public void getWheDenyAllConfiguredAndUserLoggedInThenRespondsWithForbidden() throws Exception {
this.spring.register(DenyAllConfig.class, BasicController.class).autowire(); 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 @Test
@ -275,23 +332,24 @@ public class ExpressionUrlAuthorizationConfigurerTests {
@Test @Test
public void getWhenNotDenyAllConfiguredAndRememberMeTokenThenRespondsWithOk() throws Exception { public void getWhenNotDenyAllConfiguredAndRememberMeTokenThenRespondsWithOk() throws Exception {
this.spring.register(NotDenyAllConfig.class, BasicController.class).autowire(); this.spring.register(NotDenyAllConfig.class, BasicController.class).autowire();
this.mvc.perform(get("/").with(authentication( RememberMeAuthenticationToken rememberme = new RememberMeAuthenticationToken("key", "user", AuthorityUtils.createAuthorityList("ROLE_USER"));
new RememberMeAuthenticationToken("key", "user", AuthorityUtils.createAuthorityList("ROLE_USER"))))) MockHttpServletRequestBuilder requestWithRememberme = get("/").with(authentication(rememberme));
.andExpect(status().isOk()); this.mvc.perform(requestWithRememberme).andExpect(status().isOk());
} }
@Test @Test
public void getWhenFullyAuthenticatedConfiguredAndRememberMeTokenThenRespondsWithUnauthorized() throws Exception { public void getWhenFullyAuthenticatedConfiguredAndRememberMeTokenThenRespondsWithUnauthorized() throws Exception {
this.spring.register(FullyAuthenticatedConfig.class, BasicController.class).autowire(); this.spring.register(FullyAuthenticatedConfig.class, BasicController.class).autowire();
this.mvc.perform(get("/").with(authentication( RememberMeAuthenticationToken rememberme = new RememberMeAuthenticationToken("key", "user", AuthorityUtils.createAuthorityList("ROLE_USER"));
new RememberMeAuthenticationToken("key", "user", AuthorityUtils.createAuthorityList("ROLE_USER"))))) MockHttpServletRequestBuilder requestWithRememberme = get("/").with(authentication(rememberme));
.andExpect(status().isUnauthorized()); this.mvc.perform(requestWithRememberme).andExpect(status().isUnauthorized());
} }
@Test @Test
public void getWhenFullyAuthenticatedConfiguredAndUserThenRespondsWithOk() throws Exception { public void getWhenFullyAuthenticatedConfiguredAndUserThenRespondsWithOk() throws Exception {
this.spring.register(FullyAuthenticatedConfig.class, BasicController.class).autowire(); 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 @Test
@ -303,19 +361,26 @@ public class ExpressionUrlAuthorizationConfigurerTests {
@Test @Test
public void postWhenAccessRoleUserOrGetRequestConfiguredAndRoleUserThenRespondsWithOk() throws Exception { public void postWhenAccessRoleUserOrGetRequestConfiguredAndRoleUserThenRespondsWithOk() throws Exception {
this.spring.register(AccessConfig.class, BasicController.class).autowire(); 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 @Test
public void postWhenAccessRoleUserOrGetRequestConfiguredThenRespondsWithUnauthorized() throws Exception { public void postWhenAccessRoleUserOrGetRequestConfiguredThenRespondsWithUnauthorized() throws Exception {
this.spring.register(AccessConfig.class, BasicController.class).autowire(); 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 @Test
public void authorizeRequestsWhenInvokedTwiceThenUsesOriginalConfiguration() throws Exception { public void authorizeRequestsWhenInvokedTwiceThenUsesOriginalConfiguration() throws Exception {
this.spring.register(InvokeTwiceDoesNotResetConfig.class, BasicController.class).autowire(); 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 @Test
@ -334,50 +399,58 @@ public class ExpressionUrlAuthorizationConfigurerTests {
@Test @Test
public void getWhenPermissionCheckAndRoleDoesNotMatchThenRespondsWithForbidden() throws Exception { public void getWhenPermissionCheckAndRoleDoesNotMatchThenRespondsWithForbidden() throws Exception {
this.spring.register(UseBeansInExpressions.class, WildcardController.class).autowire(); 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 @Test
public void getWhenPermissionCheckAndRoleMatchesThenRespondsWithOk() throws Exception { public void getWhenPermissionCheckAndRoleMatchesThenRespondsWithOk() throws Exception {
this.spring.register(UseBeansInExpressions.class, WildcardController.class).autowire(); 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 @Test
public void getWhenPermissionCheckAndAuthenticationNameMatchesThenRespondsWithOk() throws Exception { public void getWhenPermissionCheckAndAuthenticationNameMatchesThenRespondsWithOk() throws Exception {
this.spring.register(UseBeansInExpressions.class, WildcardController.class).autowire(); 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 @Test
public void getWhenPermissionCheckAndAuthenticationNameDoesNotMatchThenRespondsWithForbidden() throws Exception { public void getWhenPermissionCheckAndAuthenticationNameDoesNotMatchThenRespondsWithForbidden() throws Exception {
this.spring.register(UseBeansInExpressions.class, WildcardController.class).autowire(); 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 @Test
public void getWhenCustomExpressionHandlerAndRoleDoesNotMatchThenRespondsWithForbidden() throws Exception { public void getWhenCustomExpressionHandlerAndRoleDoesNotMatchThenRespondsWithForbidden() throws Exception {
this.spring.register(CustomExpressionRootConfig.class, WildcardController.class).autowire(); 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 @Test
public void getWhenCustomExpressionHandlerAndRoleMatchesThenRespondsWithOk() throws Exception { public void getWhenCustomExpressionHandlerAndRoleMatchesThenRespondsWithOk() throws Exception {
this.spring.register(CustomExpressionRootConfig.class, WildcardController.class).autowire(); 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 @Test
public void getWhenCustomExpressionHandlerAndAuthenticationNameMatchesThenRespondsWithOk() throws Exception { public void getWhenCustomExpressionHandlerAndAuthenticationNameMatchesThenRespondsWithOk() throws Exception {
this.spring.register(CustomExpressionRootConfig.class, WildcardController.class).autowire(); 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 @Test
public void getWhenCustomExpressionHandlerAndAuthenticationNameDoesNotMatchThenRespondsWithForbidden() public void getWhenCustomExpressionHandlerAndAuthenticationNameDoesNotMatchThenRespondsWithForbidden()
throws Exception { throws Exception {
this.spring.register(CustomExpressionRootConfig.class, WildcardController.class).autowire(); 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 // SEC-3011
@ -418,13 +491,15 @@ public class ExpressionUrlAuthorizationConfigurerTests {
@Test @Test
public void getWhenRegisteringRoleHierarchyAndRelatedRoleAllowedThenRespondsWithOk() throws Exception { public void getWhenRegisteringRoleHierarchyAndRelatedRoleAllowedThenRespondsWithOk() throws Exception {
this.spring.register(RoleHierarchyConfig.class, WildcardController.class).autowire(); 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 @Test
public void getWhenRegisteringRoleHierarchyAndNoRelatedRolesAllowedThenRespondsWithForbidden() throws Exception { public void getWhenRegisteringRoleHierarchyAndNoRelatedRolesAllowedThenRespondsWithForbidden() throws Exception {
this.spring.register(RoleHierarchyConfig.class, WildcardController.class).autowire(); 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 @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.test.SpringTestRule;
import org.springframework.security.config.users.AuthenticationTestConfiguration; import org.springframework.security.config.users.AuthenticationTestConfiguration;
import org.springframework.security.core.userdetails.PasswordEncodedUser; 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.PortMapper;
import org.springframework.security.web.access.ExceptionTranslationFilter; import org.springframework.security.web.access.ExceptionTranslationFilter;
import org.springframework.security.web.authentication.AuthenticationFailureHandler; import org.springframework.security.web.authentication.AuthenticationFailureHandler;
@ -85,21 +86,34 @@ public class FormLoginConfigurerTests {
@Test @Test
public void loginWhenFormLoginConfiguredThenHasDefaultUsernameAndPasswordParameterNames() throws Exception { public void loginWhenFormLoginConfiguredThenHasDefaultUsernameAndPasswordParameterNames() throws Exception {
this.spring.register(FormLoginConfig.class).autowire(); this.spring.register(FormLoginConfig.class).autowire();
this.mockMvc.perform(formLogin().user("username", "user").password("password", "password")) // @formatter:off
.andExpect(status().isFound()).andExpect(redirectedUrl("/")); SecurityMockMvcRequestBuilders.FormLoginRequestBuilder loginRequest = formLogin()
.user("username", "user")
.password("password", "password");
this.mockMvc.perform(loginRequest)
.andExpect(status().isFound())
.andExpect(redirectedUrl("/"));
// @formatter:on
} }
@Test @Test
public void loginWhenFormLoginConfiguredThenHasDefaultFailureUrl() throws Exception { public void loginWhenFormLoginConfiguredThenHasDefaultFailureUrl() throws Exception {
this.spring.register(FormLoginConfig.class).autowire(); 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")); .andExpect(redirectedUrl("/login?error"));
// @formatter:on
} }
@Test @Test
public void loginWhenFormLoginConfiguredThenHasDefaultSuccessUrl() throws Exception { public void loginWhenFormLoginConfiguredThenHasDefaultSuccessUrl() throws Exception {
this.spring.register(FormLoginConfig.class).autowire(); 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 @Test
@ -117,28 +131,44 @@ public class FormLoginConfigurerTests {
@Test @Test
public void requestProtectedWhenFormLoginConfiguredThenRedirectsToLogin() throws Exception { public void requestProtectedWhenFormLoginConfiguredThenRedirectsToLogin() throws Exception {
this.spring.register(FormLoginConfig.class).autowire(); 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")); .andExpect(redirectedUrl("http://localhost/login"));
// @formatter:on
} }
@Test @Test
public void loginWhenFormLoginDefaultsInLambdaThenHasDefaultUsernameAndPasswordParameterNames() throws Exception { public void loginWhenFormLoginDefaultsInLambdaThenHasDefaultUsernameAndPasswordParameterNames() throws Exception {
this.spring.register(FormLoginInLambdaConfig.class).autowire(); this.spring.register(FormLoginInLambdaConfig.class).autowire();
this.mockMvc.perform(formLogin().user("username", "user").password("password", "password")) // @formatter:off
.andExpect(status().isFound()).andExpect(redirectedUrl("/")); SecurityMockMvcRequestBuilders.FormLoginRequestBuilder loginRequest = formLogin()
.user("username", "user")
.password("password", "password");
this.mockMvc.perform(loginRequest)
.andExpect(status().isFound())
.andExpect(redirectedUrl("/"));
// @formatter:on
} }
@Test @Test
public void loginWhenFormLoginDefaultsInLambdaThenHasDefaultFailureUrl() throws Exception { public void loginWhenFormLoginDefaultsInLambdaThenHasDefaultFailureUrl() throws Exception {
this.spring.register(FormLoginInLambdaConfig.class).autowire(); 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")); .andExpect(redirectedUrl("/login?error"));
// @formatter:on
} }
@Test @Test
public void loginWhenFormLoginDefaultsInLambdaThenHasDefaultSuccessUrl() throws Exception { public void loginWhenFormLoginDefaultsInLambdaThenHasDefaultSuccessUrl() throws Exception {
this.spring.register(FormLoginInLambdaConfig.class).autowire(); 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 @Test
@ -156,27 +186,41 @@ public class FormLoginConfigurerTests {
@Test @Test
public void requestProtectedWhenFormLoginDefaultsInLambdaThenRedirectsToLogin() throws Exception { public void requestProtectedWhenFormLoginDefaultsInLambdaThenRedirectsToLogin() throws Exception {
this.spring.register(FormLoginInLambdaConfig.class).autowire(); 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")); .andExpect(redirectedUrl("http://localhost/login"));
// @formatter:on
} }
@Test @Test
public void getLoginPageWhenFormLoginPermitAllThenPermittedAndNoRedirect() throws Exception { public void getLoginPageWhenFormLoginPermitAllThenPermittedAndNoRedirect() throws Exception {
this.spring.register(FormLoginConfigPermitAll.class).autowire(); 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 @Test
public void getLoginPageWithErrorQueryWhenFormLoginPermitAllThenPermittedAndNoRedirect() throws Exception { public void getLoginPageWithErrorQueryWhenFormLoginPermitAllThenPermittedAndNoRedirect() throws Exception {
this.spring.register(FormLoginConfigPermitAll.class).autowire(); 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 @Test
public void loginWhenFormLoginPermitAllAndInvalidUserThenRedirectsToLoginPageWithError() throws Exception { public void loginWhenFormLoginPermitAllAndInvalidUserThenRedirectsToLoginPageWithError() throws Exception {
this.spring.register(FormLoginConfigPermitAll.class).autowire(); 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")); .andExpect(redirectedUrl("/login?error"));
// @formatter:on
} }
@Test @Test
@ -194,8 +238,12 @@ public class FormLoginConfigurerTests {
@Test @Test
public void loginWhenCustomLoginPageAndInvalidUserThenRedirectsToCustomLoginPageWithError() throws Exception { public void loginWhenCustomLoginPageAndInvalidUserThenRedirectsToCustomLoginPageWithError() throws Exception {
this.spring.register(FormLoginDefaultsConfig.class).autowire(); 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")); .andExpect(redirectedUrl("/authenticate?error"));
// @formatter:on
} }
@Test @Test
@ -219,13 +267,21 @@ public class FormLoginConfigurerTests {
@Test @Test
public void loginWhenCustomLoginProcessingUrlThenRedirectsToHome() throws Exception { public void loginWhenCustomLoginProcessingUrlThenRedirectsToHome() throws Exception {
this.spring.register(FormLoginLoginProcessingUrlConfig.class).autowire(); 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 @Test
public void loginWhenCustomLoginProcessingUrlInLambdaThenRedirectsToHome() throws Exception { public void loginWhenCustomLoginProcessingUrlInLambdaThenRedirectsToHome() throws Exception {
this.spring.register(FormLoginLoginProcessingUrlInLambdaConfig.class).autowire(); 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 @Test
@ -233,28 +289,36 @@ public class FormLoginConfigurerTests {
FormLoginUsesPortMapperConfig.PORT_MAPPER = mock(PortMapper.class); FormLoginUsesPortMapperConfig.PORT_MAPPER = mock(PortMapper.class);
given(FormLoginUsesPortMapperConfig.PORT_MAPPER.lookupHttpsPort(any())).willReturn(9443); given(FormLoginUsesPortMapperConfig.PORT_MAPPER.lookupHttpsPort(any())).willReturn(9443);
this.spring.register(FormLoginUsesPortMapperConfig.class).autowire(); 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")); .andExpect(redirectedUrl("https://localhost:9443/login"));
// @formatter:on
verify(FormLoginUsesPortMapperConfig.PORT_MAPPER).lookupHttpsPort(any()); verify(FormLoginUsesPortMapperConfig.PORT_MAPPER).lookupHttpsPort(any());
} }
@Test @Test
public void failureUrlWhenPermitAllAndFailureHandlerThenSecured() throws Exception { public void failureUrlWhenPermitAllAndFailureHandlerThenSecured() throws Exception {
this.spring.register(PermitAllIgnoresFailureHandlerConfig.class).autowire(); 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")); .andExpect(redirectedUrl("http://localhost/login"));
// @formatter:on
} }
@Test @Test
public void formLoginWhenInvokedTwiceThenUsesOriginalUsernameParameter() throws Exception { public void formLoginWhenInvokedTwiceThenUsesOriginalUsernameParameter() throws Exception {
this.spring.register(DuplicateInvocationsDoesNotOverrideConfig.class).autowire(); 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 @Test
public void loginWhenInvalidLoginAndFailureForwardUrlThenForwardsToFailureForwardUrl() throws Exception { public void loginWhenInvalidLoginAndFailureForwardUrlThenForwardsToFailureForwardUrl() throws Exception {
this.spring.register(FormLoginUserForwardAuthenticationSuccessAndFailureConfig.class).autowire(); 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 @Test

View File

@ -63,7 +63,9 @@ public class HeadersConfigurerEagerHeadersTests {
@Override @Override
protected void configure(HttpSecurity http) throws Exception { protected void configure(HttpSecurity http) throws Exception {
// @formatter:off // @formatter:off
http.headers().addObjectPostProcessor(new ObjectPostProcessor<HeaderWriterFilter>() { http
.headers()
.addObjectPostProcessor(new ObjectPostProcessor<HeaderWriterFilter>() {
@Override @Override
public HeaderWriterFilter postProcess(HeaderWriterFilter filter) { public HeaderWriterFilter postProcess(HeaderWriterFilter filter) {
filter.setShouldWriteHeadersEagerly(true); filter.setShouldWriteHeadersEagerly(true);

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.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter.XFrameOptionsMode;
import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult; 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.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
@ -198,10 +199,13 @@ public class HeadersConfigurerTests {
@Test @Test
public void getWhenSecureRequestAndHpkpWithPinThenPublicKeyPinsReportOnlyHeaderInResponse() throws Exception { public void getWhenSecureRequestAndHpkpWithPinThenPublicKeyPinsReportOnlyHeaderInResponse() throws Exception {
this.spring.register(HpkpConfig.class).autowire(); 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)) MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
.andExpect(header().string(HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY, .andExpect(pinsReportOnly)
"max-age=5184000 ; pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\""))
.andReturn(); .andReturn();
// @formatter:on
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY); assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY);
} }
@ -216,30 +220,40 @@ public class HeadersConfigurerTests {
public void getWhenHpkpWithMultiplePinsThenPublicKeyPinsReportOnlyHeaderWithMultiplePinsInResponse() public void getWhenHpkpWithMultiplePinsThenPublicKeyPinsReportOnlyHeaderWithMultiplePinsInResponse()
throws Exception { throws Exception {
this.spring.register(HpkpConfigWithPins.class).autowire(); 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, 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(); .andReturn();
// @formatter:on
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY); assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY);
} }
@Test @Test
public void getWhenHpkpWithCustomAgeThenPublicKeyPinsReportOnlyHeaderWithCustomAgeInResponse() throws Exception { public void getWhenHpkpWithCustomAgeThenPublicKeyPinsReportOnlyHeaderWithCustomAgeInResponse() throws Exception {
this.spring.register(HpkpConfigCustomAge.class).autowire(); 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)) MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
.andExpect(header().string(HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY, .andExpect(pinsReportOnly)
"max-age=604800 ; pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\""))
.andReturn(); .andReturn();
// @formatter:on
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY); assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY);
} }
@Test @Test
public void getWhenHpkpWithReportOnlyFalseThenPublicKeyPinsHeaderInResponse() throws Exception { public void getWhenHpkpWithReportOnlyFalseThenPublicKeyPinsHeaderInResponse() throws Exception {
this.spring.register(HpkpConfigTerminateConnection.class).autowire(); 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)) MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
.andExpect(header().string(HttpHeaders.PUBLIC_KEY_PINS, .andExpect(pins)
"max-age=5184000 ; pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\""))
.andReturn(); .andReturn();
// @formatter:on
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.PUBLIC_KEY_PINS); assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.PUBLIC_KEY_PINS);
} }
@ -247,20 +261,28 @@ public class HeadersConfigurerTests {
public void getWhenHpkpIncludeSubdomainThenPublicKeyPinsReportOnlyHeaderWithIncludeSubDomainsInResponse() public void getWhenHpkpIncludeSubdomainThenPublicKeyPinsReportOnlyHeaderWithIncludeSubDomainsInResponse()
throws Exception { throws Exception {
this.spring.register(HpkpConfigIncludeSubDomains.class).autowire(); 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, 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(); .andReturn();
// @formatter:on
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY); assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY);
} }
@Test @Test
public void getWhenHpkpWithReportUriThenPublicKeyPinsReportOnlyHeaderWithReportUriInResponse() throws Exception { public void getWhenHpkpWithReportUriThenPublicKeyPinsReportOnlyHeaderWithReportUriInResponse() throws Exception {
this.spring.register(HpkpConfigWithReportURI.class).autowire(); 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, 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(); .andReturn();
// @formatter:on
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY); assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY);
} }
@ -268,10 +290,14 @@ public class HeadersConfigurerTests {
public void getWhenHpkpWithReportUriAsStringThenPublicKeyPinsReportOnlyHeaderWithReportUriInResponse() public void getWhenHpkpWithReportUriAsStringThenPublicKeyPinsReportOnlyHeaderWithReportUriInResponse()
throws Exception { throws Exception {
this.spring.register(HpkpConfigWithReportURIAsString.class).autowire(); 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, 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(); .andReturn();
// @formatter:on
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY); assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY);
} }
@ -279,18 +305,26 @@ public class HeadersConfigurerTests {
public void getWhenHpkpWithReportUriInLambdaThenPublicKeyPinsReportOnlyHeaderWithReportUriInResponse() public void getWhenHpkpWithReportUriInLambdaThenPublicKeyPinsReportOnlyHeaderWithReportUriInResponse()
throws Exception { throws Exception {
this.spring.register(HpkpWithReportUriInLambdaConfig.class).autowire(); 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, 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(); .andReturn();
// @formatter:on
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY); assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY);
} }
@Test @Test
public void getWhenContentSecurityPolicyConfiguredThenContentSecurityPolicyHeaderInResponse() throws Exception { public void getWhenContentSecurityPolicyConfiguredThenContentSecurityPolicyHeaderInResponse() throws Exception {
this.spring.register(ContentSecurityPolicyDefaultConfig.class).autowire(); 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)) 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); assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.CONTENT_SECURITY_POLICY);
} }
@ -298,10 +332,13 @@ public class HeadersConfigurerTests {
public void getWhenContentSecurityPolicyWithReportOnlyThenContentSecurityPolicyReportOnlyHeaderInResponse() public void getWhenContentSecurityPolicyWithReportOnlyThenContentSecurityPolicyReportOnlyHeaderInResponse()
throws Exception { throws Exception {
this.spring.register(ContentSecurityPolicyReportOnlyConfig.class).autowire(); 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)) MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
.andExpect(header().string(HttpHeaders.CONTENT_SECURITY_POLICY_REPORT_ONLY, .andExpect(cspReportOnly)
"default-src 'self'; script-src trustedscripts.example.com"))
.andReturn(); .andReturn();
// @formatter:on
assertThat(mvcResult.getResponse().getHeaderNames()) assertThat(mvcResult.getResponse().getHeaderNames())
.containsExactly(HttpHeaders.CONTENT_SECURITY_POLICY_REPORT_ONLY); .containsExactly(HttpHeaders.CONTENT_SECURITY_POLICY_REPORT_ONLY);
} }
@ -310,10 +347,13 @@ public class HeadersConfigurerTests {
public void getWhenContentSecurityPolicyWithReportOnlyInLambdaThenContentSecurityPolicyReportOnlyHeaderInResponse() public void getWhenContentSecurityPolicyWithReportOnlyInLambdaThenContentSecurityPolicyReportOnlyHeaderInResponse()
throws Exception { throws Exception {
this.spring.register(ContentSecurityPolicyReportOnlyInLambdaConfig.class).autowire(); 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)) MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
.andExpect(header().string(HttpHeaders.CONTENT_SECURITY_POLICY_REPORT_ONLY, .andExpect(csp)
"default-src 'self'; script-src trustedscripts.example.com"))
.andReturn(); .andReturn();
// @formatter:on
assertThat(mvcResult.getResponse().getHeaderNames()) assertThat(mvcResult.getResponse().getHeaderNames())
.containsExactly(HttpHeaders.CONTENT_SECURITY_POLICY_REPORT_ONLY); .containsExactly(HttpHeaders.CONTENT_SECURITY_POLICY_REPORT_ONLY);
} }
@ -335,24 +375,36 @@ public class HeadersConfigurerTests {
@Test @Test
public void configureWhenContentSecurityPolicyNoPolicyDirectivesInLambdaThenDefaultHeaderValue() throws Exception { public void configureWhenContentSecurityPolicyNoPolicyDirectivesInLambdaThenDefaultHeaderValue() throws Exception {
this.spring.register(ContentSecurityPolicyNoDirectivesInLambdaConfig.class).autowire(); 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)) 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); assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.CONTENT_SECURITY_POLICY);
} }
@Test @Test
public void getWhenReferrerPolicyConfiguredThenReferrerPolicyHeaderInResponse() throws Exception { public void getWhenReferrerPolicyConfiguredThenReferrerPolicyHeaderInResponse() throws Exception {
this.spring.register(ReferrerPolicyDefaultConfig.class).autowire(); 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)) 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"); assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly("Referrer-Policy");
} }
@Test @Test
public void getWhenReferrerPolicyInLambdaThenReferrerPolicyHeaderInResponse() throws Exception { public void getWhenReferrerPolicyInLambdaThenReferrerPolicyHeaderInResponse() throws Exception {
this.spring.register(ReferrerPolicyDefaultInLambdaConfig.class).autowire(); 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)) 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"); assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly("Referrer-Policy");
} }
@ -360,24 +412,36 @@ public class HeadersConfigurerTests {
public void getWhenReferrerPolicyConfiguredWithCustomValueThenReferrerPolicyHeaderWithCustomValueInResponse() public void getWhenReferrerPolicyConfiguredWithCustomValueThenReferrerPolicyHeaderWithCustomValueInResponse()
throws Exception { throws Exception {
this.spring.register(ReferrerPolicyCustomConfig.class).autowire(); 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)) 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"); assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly("Referrer-Policy");
} }
@Test @Test
public void getWhenReferrerPolicyConfiguredWithCustomValueInLambdaThenCustomValueInResponse() throws Exception { public void getWhenReferrerPolicyConfiguredWithCustomValueInLambdaThenCustomValueInResponse() throws Exception {
this.spring.register(ReferrerPolicyCustomInLambdaConfig.class).autowire(); 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)) 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"); assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly("Referrer-Policy");
} }
@Test @Test
public void getWhenFeaturePolicyConfiguredThenFeaturePolicyHeaderInResponse() throws Exception { public void getWhenFeaturePolicyConfiguredThenFeaturePolicyHeaderInResponse() throws Exception {
this.spring.register(FeaturePolicyConfig.class).autowire(); this.spring.register(FeaturePolicyConfig.class).autowire();
ResultMatcher featurePolicy = header().string("Feature-Policy", "geolocation 'self'");
// @formatter:off
MvcResult mvcResult = this.mvc.perform(get("/").secure(true)) 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"); assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly("Feature-Policy");
} }
@ -392,9 +456,13 @@ public class HeadersConfigurerTests {
public void getWhenHstsConfiguredWithPreloadThenStrictTransportSecurityHeaderWithPreloadInResponse() public void getWhenHstsConfiguredWithPreloadThenStrictTransportSecurityHeaderWithPreloadInResponse()
throws Exception { throws Exception {
this.spring.register(HstsWithPreloadConfig.class).autowire(); this.spring.register(HstsWithPreloadConfig.class).autowire();
MvcResult mvcResult = this.mvc.perform(get("/").secure(true)).andExpect(header() ResultMatcher hsts = header()
.string(HttpHeaders.STRICT_TRANSPORT_SECURITY, "max-age=31536000 ; includeSubDomains ; preload")) .string(HttpHeaders.STRICT_TRANSPORT_SECURITY, "max-age=31536000 ; includeSubDomains ; preload");
// @formatter:off
MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
.andExpect(hsts)
.andReturn(); .andReturn();
// @formatter:on
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.STRICT_TRANSPORT_SECURITY); assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.STRICT_TRANSPORT_SECURITY);
} }
@ -402,9 +470,13 @@ public class HeadersConfigurerTests {
public void getWhenHstsConfiguredWithPreloadInLambdaThenStrictTransportSecurityHeaderWithPreloadInResponse() public void getWhenHstsConfiguredWithPreloadInLambdaThenStrictTransportSecurityHeaderWithPreloadInResponse()
throws Exception { throws Exception {
this.spring.register(HstsWithPreloadInLambdaConfig.class).autowire(); this.spring.register(HstsWithPreloadInLambdaConfig.class).autowire();
MvcResult mvcResult = this.mvc.perform(get("/").secure(true)).andExpect(header() ResultMatcher hsts = header()
.string(HttpHeaders.STRICT_TRANSPORT_SECURITY, "max-age=31536000 ; includeSubDomains ; preload")) .string(HttpHeaders.STRICT_TRANSPORT_SECURITY, "max-age=31536000 ; includeSubDomains ; preload");
// @formatter:off
MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
.andExpect(hsts)
.andReturn(); .andReturn();
// @formatter:on
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.STRICT_TRANSPORT_SECURITY); 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.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.test.web.servlet.MockMvc; 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.ArgumentMatchers.any;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
@ -73,16 +74,22 @@ public class HttpBasicConfigurerTests {
@Test @Test
public void httpBasicWhenUsingDefaultsInLambdaThenResponseIncludesBasicChallenge() throws Exception { public void httpBasicWhenUsingDefaultsInLambdaThenResponseIncludesBasicChallenge() throws Exception {
this.spring.register(DefaultsLambdaEntryPointConfig.class).autowire(); 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\"")); .andExpect(header().string("WWW-Authenticate", "Basic realm=\"Realm\""));
// @formatter:on
} }
// SEC-2198 // SEC-2198
@Test @Test
public void httpBasicWhenUsingDefaultsThenResponseIncludesBasicChallenge() throws Exception { public void httpBasicWhenUsingDefaultsThenResponseIncludesBasicChallenge() throws Exception {
this.spring.register(DefaultsEntryPointConfig.class).autowire(); 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\"")); .andExpect(header().string("WWW-Authenticate", "Basic realm=\"Realm\""));
// @formatter:on
} }
@Test @Test
@ -105,8 +112,8 @@ public class HttpBasicConfigurerTests {
@Test @Test
public void httpBasicWhenRememberMeConfiguredThenSetsRememberMeCookie() throws Exception { public void httpBasicWhenRememberMeConfiguredThenSetsRememberMeCookie() throws Exception {
this.spring.register(BasicUsesRememberMeConfig.class).autowire(); this.spring.register(BasicUsesRememberMeConfig.class).autowire();
this.mvc.perform(get("/").with(httpBasic("user", "password")).param("remember-me", "true")) MockHttpServletRequestBuilder rememberMeRequest = get("/").with(httpBasic("user", "password")).param("remember-me", "true");
.andExpect(cookie().exists("remember-me")); this.mvc.perform(rememberMeRequest).andExpect(cookie().exists("remember-me"));
} }
@EnableWebSecurity @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.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.AuthenticationUserDetailsService; import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
import org.springframework.security.core.userdetails.User; 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.J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource;
import org.springframework.security.web.authentication.preauth.j2ee.J2eePreAuthenticatedProcessingFilter; import org.springframework.security.web.authentication.preauth.j2ee.J2eePreAuthenticatedProcessingFilter;
import org.springframework.test.web.servlet.MockMvc; 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.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given; import static org.mockito.BDDMockito.given;
@ -78,11 +80,16 @@ public class JeeConfigurerTests {
this.spring.register(InvokeTwiceDoesNotOverride.class).autowire(); this.spring.register(InvokeTwiceDoesNotOverride.class).autowire();
Principal user = mock(Principal.class); Principal user = mock(Principal.class);
given(user.getName()).willReturn("user"); given(user.getName()).willReturn("user");
this.mvc.perform(get("/").principal(user).with((request) -> { // @formatter:off
MockHttpServletRequestBuilder request = get("/")
.principal(user)
.with((request) -> {
request.addUserRole("ROLE_ADMIN"); request.addUserRole("ROLE_ADMIN");
request.addUserRole("ROLE_USER"); request.addUserRole("ROLE_USER");
return request; return request;
})).andExpect(authenticated().withRoles("USER")); });
// @formatter:on
this.mvc.perform(request).andExpect(authenticated().withRoles("USER"));
} }
@Test @Test
@ -90,11 +97,16 @@ public class JeeConfigurerTests {
this.spring.register(JeeMappableRolesConfig.class).autowire(); this.spring.register(JeeMappableRolesConfig.class).autowire();
Principal user = mock(Principal.class); Principal user = mock(Principal.class);
given(user.getName()).willReturn("user"); given(user.getName()).willReturn("user");
this.mvc.perform(get("/").principal(user).with((request) -> { // @formatter:off
MockHttpServletRequestBuilder request = get("/")
.principal(user)
.with((request) -> {
request.addUserRole("ROLE_ADMIN"); request.addUserRole("ROLE_ADMIN");
request.addUserRole("ROLE_USER"); request.addUserRole("ROLE_USER");
return request; return request;
})).andExpect(authenticated().withRoles("USER")); });
// @formatter:on
this.mvc.perform(request).andExpect(authenticated().withRoles("USER"));
} }
@Test @Test
@ -102,11 +114,17 @@ public class JeeConfigurerTests {
this.spring.register(JeeMappableAuthoritiesConfig.class).autowire(); this.spring.register(JeeMappableAuthoritiesConfig.class).autowire();
Principal user = mock(Principal.class); Principal user = mock(Principal.class);
given(user.getName()).willReturn("user"); given(user.getName()).willReturn("user");
this.mvc.perform(get("/").principal(user).with((request) -> { // @formatter:off
MockHttpServletRequestBuilder request = get("/")
.principal(user)
.with((request) -> {
request.addUserRole("ROLE_ADMIN"); request.addUserRole("ROLE_ADMIN");
request.addUserRole("ROLE_USER"); request.addUserRole("ROLE_USER");
return request; return request;
})).andExpect(authenticated().withAuthorities(AuthorityUtils.createAuthorityList("ROLE_USER"))); });
// @formatter:on
SecurityMockMvcResultMatchers.AuthenticatedMatcher authenticatedAsUser = authenticated().withAuthorities(AuthorityUtils.createAuthorityList("ROLE_USER"));
this.mvc.perform(request).andExpect(authenticatedAsUser);
} }
@Test @Test
@ -119,11 +137,16 @@ public class JeeConfigurerTests {
given(user.getName()).willReturn("user"); given(user.getName()).willReturn("user");
given(JeeCustomAuthenticatedUserDetailsServiceConfig.authenticationUserDetailsService.loadUserDetails(any())) given(JeeCustomAuthenticatedUserDetailsServiceConfig.authenticationUserDetailsService.loadUserDetails(any()))
.willReturn(userDetails); .willReturn(userDetails);
this.mvc.perform(get("/").principal(user).with((request) -> { // @formatter:off
MockHttpServletRequestBuilder request = get("/")
.principal(user)
.with((request) -> {
request.addUserRole("ROLE_ADMIN"); request.addUserRole("ROLE_ADMIN");
request.addUserRole("ROLE_USER"); request.addUserRole("ROLE_USER");
return request; return request;
})).andExpect(authenticated().withRoles("USER")); });
// @formatter:on
this.mvc.perform(request).andExpect(authenticated().withRoles("USER"));
} }
@EnableWebSecurity @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.config.test.SpringTestRule;
import org.springframework.security.test.context.annotation.SecurityTestExecutionListeners; import org.springframework.security.test.context.annotation.SecurityTestExecutionListeners;
import org.springframework.security.test.context.support.WithMockUser; 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.authentication.logout.HeaderWriterLogoutHandler;
import org.springframework.security.web.header.writers.ClearSiteDataHeaderWriter; import org.springframework.security.web.header.writers.ClearSiteDataHeaderWriter;
import org.springframework.security.web.header.writers.ClearSiteDataHeaderWriter.Directive; import org.springframework.security.web.header.writers.ClearSiteDataHeaderWriter.Directive;
import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc; 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.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
@ -67,24 +68,24 @@ public class LogoutConfigurerClearSiteDataTests {
@WithMockUser @WithMockUser
public void logoutWhenRequestTypeGetThenHeaderNotPresentt() throws Exception { public void logoutWhenRequestTypeGetThenHeaderNotPresentt() throws Exception {
this.spring.register(HttpLogoutConfig.class).autowire(); this.spring.register(HttpLogoutConfig.class).autowire();
this.mvc.perform(get("/logout").secure(true).with(SecurityMockMvcRequestPostProcessors.csrf())) MockHttpServletRequestBuilder logoutRequest = get("/logout").secure(true).with(csrf());
.andExpect(header().doesNotExist(CLEAR_SITE_DATA_HEADER)); this.mvc.perform(logoutRequest).andExpect(header().doesNotExist(CLEAR_SITE_DATA_HEADER));
} }
@Test @Test
@WithMockUser @WithMockUser
public void logoutWhenRequestTypePostAndNotSecureThenHeaderNotPresent() throws Exception { public void logoutWhenRequestTypePostAndNotSecureThenHeaderNotPresent() throws Exception {
this.spring.register(HttpLogoutConfig.class).autowire(); this.spring.register(HttpLogoutConfig.class).autowire();
this.mvc.perform(post("/logout").with(SecurityMockMvcRequestPostProcessors.csrf())) MockHttpServletRequestBuilder logoutRequest = post("/logout").with(csrf());
.andExpect(header().doesNotExist(CLEAR_SITE_DATA_HEADER)); this.mvc.perform(logoutRequest).andExpect(header().doesNotExist(CLEAR_SITE_DATA_HEADER));
} }
@Test @Test
@WithMockUser @WithMockUser
public void logoutWhenRequestTypePostAndSecureThenHeaderIsPresent() throws Exception { public void logoutWhenRequestTypePostAndSecureThenHeaderIsPresent() throws Exception {
this.spring.register(HttpLogoutConfig.class).autowire(); this.spring.register(HttpLogoutConfig.class).autowire();
this.mvc.perform(post("/logout").secure(true).with(SecurityMockMvcRequestPostProcessors.csrf())) MockHttpServletRequestBuilder logoutRequest = post("/logout").secure(true).with(csrf());
.andExpect(header().stringValues(CLEAR_SITE_DATA_HEADER, HEADER_VALUE)); this.mvc.perform(logoutRequest).andExpect(header().stringValues(CLEAR_SITE_DATA_HEADER, HEADER_VALUE));
} }
@EnableWebSecurity @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.authentication.logout.LogoutSuccessHandler;
import org.springframework.security.web.util.matcher.RequestMatcher; import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.test.web.servlet.MockMvc; 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.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
@ -101,65 +102,103 @@ public class LogoutConfigurerTests {
@Test @Test
public void logoutWhenInvokedTwiceThenUsesOriginalLogoutUrl() throws Exception { public void logoutWhenInvokedTwiceThenUsesOriginalLogoutUrl() throws Exception {
this.spring.register(DuplicateDoesNotOverrideConfig.class).autowire(); 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")); .andExpect(redirectedUrl("/login?logout"));
// @formatter:on
} }
// SEC-2311 // SEC-2311
@Test @Test
public void logoutWhenGetRequestAndCsrfDisabledThenRedirectsToLogin() throws Exception { public void logoutWhenGetRequestAndCsrfDisabledThenRedirectsToLogin() throws Exception {
this.spring.register(CsrfDisabledConfig.class).autowire(); 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 @Test
public void logoutWhenPostRequestAndCsrfDisabledThenRedirectsToLogin() throws Exception { public void logoutWhenPostRequestAndCsrfDisabledThenRedirectsToLogin() throws Exception {
this.spring.register(CsrfDisabledConfig.class).autowire(); 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 @Test
public void logoutWhenPutRequestAndCsrfDisabledThenRedirectsToLogin() throws Exception { public void logoutWhenPutRequestAndCsrfDisabledThenRedirectsToLogin() throws Exception {
this.spring.register(CsrfDisabledConfig.class).autowire(); 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 @Test
public void logoutWhenDeleteRequestAndCsrfDisabledThenRedirectsToLogin() throws Exception { public void logoutWhenDeleteRequestAndCsrfDisabledThenRedirectsToLogin() throws Exception {
this.spring.register(CsrfDisabledConfig.class).autowire(); 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 @Test
public void logoutWhenGetRequestAndCsrfDisabledAndCustomLogoutUrlThenRedirectsToLogin() throws Exception { public void logoutWhenGetRequestAndCsrfDisabledAndCustomLogoutUrlThenRedirectsToLogin() throws Exception {
this.spring.register(CsrfDisabledAndCustomLogoutConfig.class).autowire(); 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 @Test
public void logoutWhenPostRequestAndCsrfDisabledAndCustomLogoutUrlThenRedirectsToLogin() throws Exception { public void logoutWhenPostRequestAndCsrfDisabledAndCustomLogoutUrlThenRedirectsToLogin() throws Exception {
this.spring.register(CsrfDisabledAndCustomLogoutConfig.class).autowire(); 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")); .andExpect(redirectedUrl("/login?logout"));
// @formatter:on
} }
@Test @Test
public void logoutWhenPutRequestAndCsrfDisabledAndCustomLogoutUrlThenRedirectsToLogin() throws Exception { public void logoutWhenPutRequestAndCsrfDisabledAndCustomLogoutUrlThenRedirectsToLogin() throws Exception {
this.spring.register(CsrfDisabledAndCustomLogoutConfig.class).autowire(); 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 @Test
public void logoutWhenDeleteRequestAndCsrfDisabledAndCustomLogoutUrlThenRedirectsToLogin() throws Exception { public void logoutWhenDeleteRequestAndCsrfDisabledAndCustomLogoutUrlThenRedirectsToLogin() throws Exception {
this.spring.register(CsrfDisabledAndCustomLogoutConfig.class).autowire(); 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")); .andExpect(redirectedUrl("/login?logout"));
// @formatter:on
} }
@Test @Test
public void logoutWhenCustomLogoutUrlInLambdaThenRedirectsToLogin() throws Exception { public void logoutWhenCustomLogoutUrlInLambdaThenRedirectsToLogin() throws Exception {
this.spring.register(CsrfDisabledAndCustomLogoutInLambdaConfig.class).autowire(); 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 // SEC-3170
@ -188,44 +227,70 @@ public class LogoutConfigurerTests {
@Test @Test
public void logoutWhenAcceptTextHtmlThenRedirectsToLogin() throws Exception { public void logoutWhenAcceptTextHtmlThenRedirectsToLogin() throws Exception {
this.spring.register(BasicSecurityConfig.class).autowire(); this.spring.register(BasicSecurityConfig.class).autowire();
this.mvc.perform( // @formatter:off
post("/logout").with(csrf()).with(user("user")).header(HttpHeaders.ACCEPT, MediaType.TEXT_HTML_VALUE)) MockHttpServletRequestBuilder logoutRequest = post("/logout")
.andExpect(status().isFound()).andExpect(redirectedUrl("/login?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 // gh-3282
@Test @Test
public void logoutWhenAcceptApplicationJsonThenReturnsStatusNoContent() throws Exception { public void logoutWhenAcceptApplicationJsonThenReturnsStatusNoContent() throws Exception {
this.spring.register(BasicSecurityConfig.class).autowire(); this.spring.register(BasicSecurityConfig.class).autowire();
this.mvc.perform(post("/logout").with(csrf()).with(user("user")).header(HttpHeaders.ACCEPT, // @formatter:off
MediaType.APPLICATION_JSON_VALUE)).andExpect(status().isNoContent()); 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 // gh-4831
@Test @Test
public void logoutWhenAcceptAllThenReturnsStatusNoContent() throws Exception { public void logoutWhenAcceptAllThenReturnsStatusNoContent() throws Exception {
this.spring.register(BasicSecurityConfig.class).autowire(); this.spring.register(BasicSecurityConfig.class).autowire();
this.mvc.perform( // @formatter:off
post("/logout").with(csrf()).with(user("user")).header(HttpHeaders.ACCEPT, MediaType.ALL_VALUE)) MockHttpServletRequestBuilder logoutRequest = post("/logout")
.andExpect(status().isNoContent()); .with(csrf())
.with(user("user"))
.header(HttpHeaders.ACCEPT, MediaType.ALL_VALUE);
// @formatter:on
this.mvc.perform(logoutRequest).andExpect(status().isNoContent());
} }
// gh-3902 // gh-3902
@Test @Test
public void logoutWhenAcceptFromChromeThenRedirectsToLogin() throws Exception { public void logoutWhenAcceptFromChromeThenRedirectsToLogin() throws Exception {
this.spring.register(BasicSecurityConfig.class).autowire(); this.spring.register(BasicSecurityConfig.class).autowire();
this.mvc.perform(post("/logout").with(csrf()).with(user("user")).header(HttpHeaders.ACCEPT, // @formatter:off
"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8")) MockHttpServletRequestBuilder request = post("/logout")
.andExpect(status().isFound()).andExpect(redirectedUrl("/login?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 // gh-3997
@Test @Test
public void logoutWhenXMLHttpRequestThenReturnsStatusNoContent() throws Exception { public void logoutWhenXMLHttpRequestThenReturnsStatusNoContent() throws Exception {
this.spring.register(BasicSecurityConfig.class).autowire(); this.spring.register(BasicSecurityConfig.class).autowire();
this.mvc.perform(post("/logout").with(csrf()).with(user("user")) // @formatter:off
.header(HttpHeaders.ACCEPT, "text/html,application/json").header("X-Requested-With", "XMLHttpRequest")) MockHttpServletRequestBuilder request = post("/logout")
.andExpect(status().isNoContent()); .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 @Test

View File

@ -35,6 +35,7 @@ import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager; import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.test.web.servlet.MockMvc; 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.ArgumentMatchers.any;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
@ -66,18 +67,28 @@ public class NamespaceHttpBasicTests {
public void basicAuthenticationWhenUsingDefaultsThenMatchesNamespace() throws Exception { public void basicAuthenticationWhenUsingDefaultsThenMatchesNamespace() throws Exception {
this.spring.register(HttpBasicConfig.class, UserConfig.class).autowire(); this.spring.register(HttpBasicConfig.class, UserConfig.class).autowire();
this.mvc.perform(get("/")).andExpect(status().isUnauthorized()); 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\"")); .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 @Test
public void basicAuthenticationWhenUsingDefaultsInLambdaThenMatchesNamespace() throws Exception { public void basicAuthenticationWhenUsingDefaultsInLambdaThenMatchesNamespace() throws Exception {
this.spring.register(HttpBasicLambdaConfig.class, UserConfig.class).autowire(); this.spring.register(HttpBasicLambdaConfig.class, UserConfig.class).autowire();
this.mvc.perform(get("/")).andExpect(status().isUnauthorized()); 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\"")); .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 @Test
public void basicAuthenticationWhenUsingCustomRealmThenMatchesNamespace() throws Exception { public void basicAuthenticationWhenUsingCustomRealmThenMatchesNamespace() throws Exception {
this.spring.register(CustomHttpBasicConfig.class, UserConfig.class).autowire(); 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\"")); .andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, "Basic realm=\"Custom Realm\""));
// @formatter:on
} }
@Test @Test
public void basicAuthenticationWhenUsingCustomRealmInLambdaThenMatchesNamespace() throws Exception { public void basicAuthenticationWhenUsingCustomRealmInLambdaThenMatchesNamespace() throws Exception {
this.spring.register(CustomHttpBasicLambdaConfig.class, UserConfig.class).autowire(); 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\"")); .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.Authentication;
import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.User; 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.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager; import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.FilterChainProxy; import org.springframework.security.web.FilterChainProxy;
@ -193,8 +194,14 @@ public class NamespaceHttpCustomFilterTests {
@Bean @Bean
UserDetailsService userDetailsService() { UserDetailsService userDetailsService() {
return new InMemoryUserDetailsManager( // @formatter:off
User.withDefaultPasswordEncoder().username("user").password("password").roles("USER").build()); 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.SimpleUrlAuthenticationFailureHandler;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.test.web.servlet.MockMvc; 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.ArgumentMatchers.any;
import static org.mockito.Mockito.spy; import static org.mockito.Mockito.spy;
@ -65,8 +66,13 @@ public class NamespaceHttpFormLoginTests {
this.spring.register(FormLoginConfig.class, UserDetailsServiceConfig.class).autowire(); this.spring.register(FormLoginConfig.class, UserDetailsServiceConfig.class).autowire();
this.mvc.perform(get("/")).andExpect(redirectedUrl("http://localhost/login")); 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").with(csrf())).andExpect(redirectedUrl("/login?error"));
this.mvc.perform(post("/login").param("username", "user").param("password", "password").with(csrf())) // @formatter:off
.andExpect(redirectedUrl("/")); MockHttpServletRequestBuilder loginRequest = post("/login")
.param("username", "user")
.param("password", "password")
.with(csrf());
// @formatter:on
this.mvc.perform(loginRequest).andExpect(redirectedUrl("/"));
} }
@Test @Test
@ -75,8 +81,13 @@ public class NamespaceHttpFormLoginTests {
this.mvc.perform(get("/")).andExpect(redirectedUrl("http://localhost/authentication/login")); this.mvc.perform(get("/")).andExpect(redirectedUrl("http://localhost/authentication/login"));
this.mvc.perform(post("/authentication/login/process").with(csrf())) this.mvc.perform(post("/authentication/login/process").with(csrf()))
.andExpect(redirectedUrl("/authentication/login?failed")); .andExpect(redirectedUrl("/authentication/login?failed"));
this.mvc.perform(post("/authentication/login/process").param("username", "user").param("password", "password") // @formatter:off
.with(csrf())).andExpect(redirectedUrl("/default")); MockHttpServletRequestBuilder request = post("/authentication/login/process")
.param("username", "user")
.param("password", "password")
.with(csrf());
// @formatter:on
this.mvc.perform(request).andExpect(redirectedUrl("/default"));
} }
@Test @Test
@ -85,8 +96,13 @@ public class NamespaceHttpFormLoginTests {
this.mvc.perform(get("/")).andExpect(redirectedUrl("http://localhost/login")); this.mvc.perform(get("/")).andExpect(redirectedUrl("http://localhost/login"));
this.mvc.perform(post("/login").with(csrf())).andExpect(redirectedUrl("/custom/failure")); this.mvc.perform(post("/login").with(csrf())).andExpect(redirectedUrl("/custom/failure"));
verifyBean(WebAuthenticationDetailsSource.class).buildDetails(any(HttpServletRequest.class)); verifyBean(WebAuthenticationDetailsSource.class).buildDetails(any(HttpServletRequest.class));
this.mvc.perform(post("/login").param("username", "user").param("password", "password").with(csrf())) // @formatter:off
.andExpect(redirectedUrl("/custom/targetUrl")); 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) { 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.Authentication;
import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.test.web.servlet.MockMvc; 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.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
@ -66,22 +67,26 @@ public class NamespaceHttpInterceptUrlTests {
@Test @Test
public void authenticatedRequestWhenUrlRequiresElevatedPrivilegesThenBehaviorMatchesNamespace() throws Exception { public void authenticatedRequestWhenUrlRequiresElevatedPrivilegesThenBehaviorMatchesNamespace() throws Exception {
this.spring.register(HttpInterceptUrlConfig.class).autowire(); 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 @Test
public void authenticatedRequestWhenAuthorizedThenBehaviorMatchesNamespace() throws Exception { public void authenticatedRequestWhenAuthorizedThenBehaviorMatchesNamespace() throws Exception {
this.spring.register(HttpInterceptUrlConfig.class, BaseController.class).autowire(); 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 @Test
public void requestWhenMappedByPostInterceptUrlThenBehaviorMatchesNamespace() throws Exception { public void requestWhenMappedByPostInterceptUrlThenBehaviorMatchesNamespace() throws Exception {
this.spring.register(HttpInterceptUrlConfig.class, BaseController.class).autowire(); this.spring.register(HttpInterceptUrlConfig.class, BaseController.class).autowire();
this.mvc.perform(get("/admin/post").with(authentication(user("ROLE_USER")))).andExpect(status().isOk()); MockHttpServletRequestBuilder getWithUser = get("/admin/post").with(authentication(user("ROLE_USER")));
this.mvc.perform(post("/admin/post").with(authentication(user("ROLE_USER")))).andExpect(status().isForbidden()); this.mvc.perform(getWithUser).andExpect(status().isOk());
this.mvc.perform(post("/admin/post").with(csrf()).with(authentication(user("ROLE_ADMIN")))) MockHttpServletRequestBuilder postWithUser = post("/admin/post").with(authentication(user("ROLE_USER")));
.andExpect(status().isOk()); 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 @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.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultMatcher; 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.assertj.core.api.Assertions.assertThat;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
@ -72,15 +73,21 @@ public class NamespaceHttpLogoutTests {
@WithMockUser @WithMockUser
public void logoutWhenUsingDefaultsThenMatchesNamespace() throws Exception { public void logoutWhenUsingDefaultsThenMatchesNamespace() throws Exception {
this.spring.register(HttpLogoutConfig.class).autowire(); this.spring.register(HttpLogoutConfig.class).autowire();
this.mvc.perform(post("/logout").with(csrf())).andExpect(authenticated(false)) // @formatter:off
.andExpect(redirectedUrl("/login?logout")).andExpect(noCookies()).andExpect(session(Objects::isNull)); this.mvc.perform(post("/logout").with(csrf()))
.andExpect(authenticated(false))
.andExpect(redirectedUrl("/login?logout"))
.andExpect(noCookies())
.andExpect(session(Objects::isNull));
// @formatter:on
} }
@Test @Test
@WithMockUser @WithMockUser
public void logoutWhenDisabledInLambdaThenRespondsWithNotFound() throws Exception { public void logoutWhenDisabledInLambdaThenRespondsWithNotFound() throws Exception {
this.spring.register(HttpLogoutDisabledInLambdaConfig.class).autowire(); 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 @WithMockUser
public void logoutWhenUsingVariousCustomizationsMatchesNamespace() throws Exception { public void logoutWhenUsingVariousCustomizationsMatchesNamespace() throws Exception {
this.spring.register(CustomHttpLogoutConfig.class).autowire(); 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(redirectedUrl("/logout-success"))
.andExpect((result) -> assertThat(result.getResponse().getCookies()).hasSize(1)) .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 @Test
@WithMockUser @WithMockUser
public void logoutWhenUsingVariousCustomizationsInLambdaThenMatchesNamespace() throws Exception { public void logoutWhenUsingVariousCustomizationsInLambdaThenMatchesNamespace() throws Exception {
this.spring.register(CustomHttpLogoutInLambdaConfig.class).autowire(); 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(redirectedUrl("/logout-success"))
.andExpect((result) -> assertThat(result.getResponse().getCookies()).hasSize(1)) .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 @WithMockUser
public void logoutWhenUsingSuccessHandlerRefThenMatchesNamespace() throws Exception { public void logoutWhenUsingSuccessHandlerRefThenMatchesNamespace() throws Exception {
this.spring.register(SuccessHandlerRefHttpLogoutConfig.class).autowire(); this.spring.register(SuccessHandlerRefHttpLogoutConfig.class).autowire();
this.mvc.perform(post("/logout").with(csrf())).andExpect(authenticated(false)) // @formatter:off
.andExpect(redirectedUrl("/SuccessHandlerRefHttpLogoutConfig")).andExpect(noCookies()) this.mvc.perform(post("/logout").with(csrf()))
.andExpect(authenticated(false))
.andExpect(redirectedUrl("/SuccessHandlerRefHttpLogoutConfig"))
.andExpect(noCookies())
.andExpect(session(Objects::isNull)); .andExpect(session(Objects::isNull));
// @formatter:on
} }
@Test @Test
@WithMockUser @WithMockUser
public void logoutWhenUsingSuccessHandlerRefInLambdaThenMatchesNamespace() throws Exception { public void logoutWhenUsingSuccessHandlerRefInLambdaThenMatchesNamespace() throws Exception {
this.spring.register(SuccessHandlerRefHttpLogoutInLambdaConfig.class).autowire(); this.spring.register(SuccessHandlerRefHttpLogoutInLambdaConfig.class).autowire();
this.mvc.perform(post("/logout").with(csrf())).andExpect(authenticated(false)) // @formatter:off
.andExpect(redirectedUrl("/SuccessHandlerRefHttpLogoutConfig")).andExpect(noCookies()) this.mvc.perform(post("/logout").with(csrf()))
.andExpect(authenticated(false))
.andExpect(redirectedUrl("/SuccessHandlerRefHttpLogoutConfig"))
.andExpect(noCookies())
.andExpect(session(Objects::isNull)); .andExpect(session(Objects::isNull));
// @formatter:on
} }
ResultMatcher authenticated(boolean authenticated) { 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.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult; 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.assertThat;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
@ -141,19 +142,22 @@ public class NamespaceHttpOpenIDLoginTests {
OpenIDAuthenticationToken token = new OpenIDAuthenticationToken(OpenIDAuthenticationStatus.SUCCESS, OpenIDAuthenticationToken token = new OpenIDAuthenticationToken(OpenIDAuthenticationStatus.SUCCESS,
"identityUrl", "message", Arrays.asList(new OpenIDAttribute("name", "type"))); "identityUrl", "message", Arrays.asList(new OpenIDAttribute("name", "type")));
OpenIDLoginCustomRefsConfig.AUDS = mock(AuthenticationUserDetailsService.class); OpenIDLoginCustomRefsConfig.AUDS = mock(AuthenticationUserDetailsService.class);
given(OpenIDLoginCustomRefsConfig.AUDS.loadUserDetails(any(Authentication.class))) User user = new User("user", "password", AuthorityUtils.createAuthorityList("ROLE_USER"));
.willReturn(new User("user", "password", AuthorityUtils.createAuthorityList("ROLE_USER"))); given(OpenIDLoginCustomRefsConfig.AUDS.loadUserDetails(any(Authentication.class))).willReturn(user);
OpenIDLoginCustomRefsConfig.ADS = spy(new WebAuthenticationDetailsSource()); OpenIDLoginCustomRefsConfig.ADS = spy(new WebAuthenticationDetailsSource());
OpenIDLoginCustomRefsConfig.CONSUMER = mock(OpenIDConsumer.class); OpenIDLoginCustomRefsConfig.CONSUMER = mock(OpenIDConsumer.class);
this.spring.register(OpenIDLoginCustomRefsConfig.class, UserDetailsServiceConfig.class).autowire(); this.spring.register(OpenIDLoginCustomRefsConfig.class, UserDetailsServiceConfig.class).autowire();
given(OpenIDLoginCustomRefsConfig.CONSUMER.endConsumption(any(HttpServletRequest.class))) given(OpenIDLoginCustomRefsConfig.CONSUMER.endConsumption(any(HttpServletRequest.class)))
.willThrow(new AuthenticationServiceException("boom")); .willThrow(new AuthenticationServiceException("boom"));
this.mvc.perform(post("/login/openid").with(csrf()).param("openid.identity", "identity")) // @formatter:off
.andExpect(redirectedUrl("/custom/failure")); MockHttpServletRequestBuilder login = post("/login/openid")
.with(csrf())
.param("openid.identity", "identity");
// @formatter:on
this.mvc.perform(login).andExpect(redirectedUrl("/custom/failure"));
reset(OpenIDLoginCustomRefsConfig.CONSUMER); reset(OpenIDLoginCustomRefsConfig.CONSUMER);
given(OpenIDLoginCustomRefsConfig.CONSUMER.endConsumption(any(HttpServletRequest.class))).willReturn(token); given(OpenIDLoginCustomRefsConfig.CONSUMER.endConsumption(any(HttpServletRequest.class))).willReturn(token);
this.mvc.perform(post("/login/openid").with(csrf()).param("openid.identity", "identity")) this.mvc.perform(login).andExpect(redirectedUrl("/custom/targetUrl"));
.andExpect(redirectedUrl("/custom/targetUrl"));
verify(OpenIDLoginCustomRefsConfig.AUDS).loadUserDetails(any(Authentication.class)); verify(OpenIDLoginCustomRefsConfig.AUDS).loadUserDetails(any(Authentication.class));
verify(OpenIDLoginCustomRefsConfig.ADS).buildDetails(any(Object.class)); verify(OpenIDLoginCustomRefsConfig.ADS).buildDetails(any(Object.class));
} }

View File

@ -62,15 +62,21 @@ public class NamespaceHttpServerAccessDeniedHandlerTests {
@Test @Test
public void requestWhenCustomAccessDeniedPageThenBehaviorMatchesNamespace() throws Exception { public void requestWhenCustomAccessDeniedPageThenBehaviorMatchesNamespace() throws Exception {
this.spring.register(AccessDeniedPageConfig.class).autowire(); 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")); .andExpect(forwardedUrl("/AccessDeniedPageConfig"));
// @formatter:on
} }
@Test @Test
public void requestWhenCustomAccessDeniedPageInLambdaThenForwardedToCustomPage() throws Exception { public void requestWhenCustomAccessDeniedPageInLambdaThenForwardedToCustomPage() throws Exception {
this.spring.register(AccessDeniedPageInLambdaConfig.class).autowire(); 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")); .andExpect(forwardedUrl("/AccessDeniedPageConfig"));
// @formatter:on
} }
@Test @Test

View File

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

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.MockMvc;
import org.springframework.test.web.servlet.MvcResult; import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.ResultMatcher; 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.GetMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
@ -84,19 +85,24 @@ public class NamespaceSessionManagementTests {
.autowire(); .autowire();
MockHttpSession session = new MockHttpSession(); MockHttpSession session = new MockHttpSession();
String sessionId = session.getId(); String sessionId = session.getId();
MvcResult result = this.mvc.perform(get("/auth").session(session).with(httpBasic("user", "password"))) MockHttpServletRequestBuilder request = get("/auth").session(session).with(httpBasic("user", "password"));
.andExpect(session()).andReturn(); // @formatter:off
MvcResult result = this.mvc.perform(request)
.andExpect(session())
.andReturn();
// @formatter:on
assertThat(result.getRequest().getSession(false).getId()).isNotEqualTo(sessionId); assertThat(result.getRequest().getSession(false).getId()).isNotEqualTo(sessionId);
} }
@Test @Test
public void authenticateWhenUsingInvalidSessionUrlThenMatchesNamespace() throws Exception { public void authenticateWhenUsingInvalidSessionUrlThenMatchesNamespace() throws Exception {
this.spring.register(CustomSessionManagementConfig.class).autowire(); this.spring.register(CustomSessionManagementConfig.class).autowire();
this.mvc.perform(get("/auth").with((request) -> { MockHttpServletRequestBuilder request = get("/auth").with((request) -> {
request.setRequestedSessionIdValid(false); request.setRequestedSessionIdValid(false);
request.setRequestedSessionId("id"); request.setRequestedSessionId("id");
return request; return request;
})).andExpect(redirectedUrl("/invalid-session")); });
this.mvc.perform(request).andExpect(redirectedUrl("/invalid-session"));
} }
@Test @Test
@ -127,8 +133,12 @@ public class NamespaceSessionManagementTests {
mock.setSession(new MockHttpSession()); mock.setSession(new MockHttpSession());
given(mock.changeSessionId()).willThrow(SessionAuthenticationException.class); given(mock.changeSessionId()).willThrow(SessionAuthenticationException.class);
mock.setMethod("GET"); mock.setMethod("GET");
this.mvc.perform(get("/auth").with((request) -> mock).with(httpBasic("user", "password"))) // @formatter:off
.andExpect(redirectedUrl("/session-auth-error")); MockHttpServletRequestBuilder request = get("/auth")
.with((request) -> mock)
.with(httpBasic("user", "password"));
// @formatter:on
this.mvc.perform(request).andExpect(redirectedUrl("/session-auth-error"));
} }
@Test @Test
@ -136,7 +146,8 @@ public class NamespaceSessionManagementTests {
this.spring.register(CustomSessionManagementConfig.class, BasicController.class, UserDetailsServiceConfig.class) this.spring.register(CustomSessionManagementConfig.class, BasicController.class, UserDetailsServiceConfig.class)
.autowire(); .autowire();
SessionRegistry sessionRegistry = this.spring.getContext().getBean(SessionRegistry.class); 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)); verify(sessionRegistry).registerNewSession(any(String.class), any(Object.class));
} }
@ -144,11 +155,12 @@ public class NamespaceSessionManagementTests {
@Test @Test
public void authenticateWhenUsingCustomInvalidSessionStrategyThenMatchesNamespace() throws Exception { public void authenticateWhenUsingCustomInvalidSessionStrategyThenMatchesNamespace() throws Exception {
this.spring.register(InvalidSessionStrategyConfig.class).autowire(); this.spring.register(InvalidSessionStrategyConfig.class).autowire();
this.mvc.perform(get("/auth").with((request) -> { MockHttpServletRequestBuilder request = get("/auth").with((request) -> {
request.setRequestedSessionIdValid(false); request.setRequestedSessionIdValid(false);
request.setRequestedSessionId("id"); request.setRequestedSessionId("id");
return request; return request;
})).andExpect(status().isOk()); });
this.mvc.perform(request).andExpect(status().isOk());
verifyBean(InvalidSessionStrategy.class).onInvalidSessionDetected(any(HttpServletRequest.class), verifyBean(InvalidSessionStrategy.class).onInvalidSessionDetected(any(HttpServletRequest.class),
any(HttpServletResponse.class)); any(HttpServletResponse.class));
} }
@ -157,7 +169,8 @@ public class NamespaceSessionManagementTests {
public void authenticateWhenUsingCustomSessionAuthenticationStrategyThenMatchesNamespace() throws Exception { public void authenticateWhenUsingCustomSessionAuthenticationStrategyThenMatchesNamespace() throws Exception {
this.spring.register(RefsSessionManagementConfig.class, BasicController.class, UserDetailsServiceConfig.class) this.spring.register(RefsSessionManagementConfig.class, BasicController.class, UserDetailsServiceConfig.class)
.autowire(); .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), verifyBean(SessionAuthenticationStrategy.class).onAuthentication(any(Authentication.class),
any(HttpServletRequest.class), any(HttpServletResponse.class)); any(HttpServletRequest.class), any(HttpServletResponse.class));
} }
@ -169,9 +182,16 @@ public class NamespaceSessionManagementTests {
.autowire(); .autowire();
MockHttpSession givenSession = new MockHttpSession(); MockHttpSession givenSession = new MockHttpSession();
String givenSessionId = givenSession.getId(); String givenSessionId = givenSession.getId();
MockHttpSession resultingSession = (MockHttpSession) this.mvc // @formatter:off
.perform(get("/auth").session(givenSession).with(httpBasic("user", "password"))) MockHttpServletRequestBuilder request = get("/auth")
.andExpect(status().isOk()).andReturn().getRequest().getSession(false); .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()); assertThat(givenSessionId).isEqualTo(resultingSession.getId());
} }
@ -182,9 +202,15 @@ public class NamespaceSessionManagementTests {
MockHttpSession givenSession = new MockHttpSession(); MockHttpSession givenSession = new MockHttpSession();
String givenSessionId = givenSession.getId(); String givenSessionId = givenSession.getId();
givenSession.setAttribute("name", "value"); givenSession.setAttribute("name", "value");
MockHttpSession resultingSession = (MockHttpSession) this.mvc // @formatter:off
.perform(get("/auth").session(givenSession).with(httpBasic("user", "password"))) MockHttpSession resultingSession = (MockHttpSession) this.mvc.perform(get("/auth")
.andExpect(status().isOk()).andReturn().getRequest().getSession(false); .session(givenSession)
.with(httpBasic("user", "password")))
.andExpect(status().isOk())
.andReturn()
.getRequest()
.getSession(false);
// @formatter:on
assertThat(givenSessionId).isNotEqualTo(resultingSession.getId()); assertThat(givenSessionId).isNotEqualTo(resultingSession.getId());
assertThat(resultingSession.getAttribute("name")).isEqualTo("value"); assertThat(resultingSession.getAttribute("name")).isEqualTo("value");
} }
@ -193,8 +219,12 @@ public class NamespaceSessionManagementTests {
@Test @Test
public void authenticateWhenUsingSessionFixationProtectionThenUsesNonNullEventPublisher() throws Exception { public void authenticateWhenUsingSessionFixationProtectionThenUsesNonNullEventPublisher() throws Exception {
this.spring.register(SFPPostProcessedConfig.class, UserDetailsServiceConfig.class).autowire(); this.spring.register(SFPPostProcessedConfig.class, UserDetailsServiceConfig.class).autowire();
this.mvc.perform(get("/auth").session(new MockHttpSession()).with(httpBasic("user", "password"))) // @formatter:off
.andExpect(status().isNotFound()); 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)); verifyBean(MockEventListener.class).onApplicationEvent(any(SessionFixationProtectionEvent.class));
} }
@ -204,9 +234,15 @@ public class NamespaceSessionManagementTests {
MockHttpSession givenSession = new MockHttpSession(); MockHttpSession givenSession = new MockHttpSession();
String givenSessionId = givenSession.getId(); String givenSessionId = givenSession.getId();
givenSession.setAttribute("name", "value"); givenSession.setAttribute("name", "value");
MockHttpSession resultingSession = (MockHttpSession) this.mvc MockHttpServletRequestBuilder request = get("/auth").session(givenSession)
.perform(get("/auth").session(givenSession).with(httpBasic("user", "password"))) .with(httpBasic("user", "password"));
.andExpect(status().isNotFound()).andReturn().getRequest().getSession(false); // @formatter:off
MockHttpSession resultingSession = (MockHttpSession) this.mvc.perform(request)
.andExpect(status().isNotFound())
.andReturn()
.getRequest()
.getSession(false);
// @formatter:on
assertThat(givenSessionId).isNotEqualTo(resultingSession.getId()); assertThat(givenSessionId).isNotEqualTo(resultingSession.getId());
assertThat(resultingSession.getAttribute("name")).isNull(); 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.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.test.SpringTestRule; import org.springframework.security.config.test.SpringTestRule;
import org.springframework.test.web.servlet.MockMvc; 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.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
@ -49,10 +50,14 @@ public class PermitAllSupportTests {
@Test @Test
public void performWhenUsingPermitAllExactUrlRequestMatcherThenMatchesExactUrl() throws Exception { public void performWhenUsingPermitAllExactUrlRequestMatcherThenMatchesExactUrl() throws Exception {
this.spring.register(PermitAllConfig.class).autowire(); this.spring.register(PermitAllConfig.class).autowire();
this.mvc.perform(get("/app/xyz").contextPath("/app")).andExpect(status().isNotFound()); MockHttpServletRequestBuilder request = get("/app/xyz").contextPath("/app");
this.mvc.perform(get("/app/xyz?def").contextPath("/app")).andExpect(status().isFound()); this.mvc.perform(request).andExpect(status().isNotFound());
this.mvc.perform(post("/app/abc?def").with(csrf()).contextPath("/app")).andExpect(status().isNotFound()); MockHttpServletRequestBuilder getWithQuery = get("/app/xyz?def").contextPath("/app");
this.mvc.perform(get("/app/abc").with(csrf()).contextPath("/app")).andExpect(status().isFound()); 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 @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.User;
import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager; 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.RememberMeServices;
import org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter; import org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter;
import org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices; import org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices;
import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult; 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.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
@ -83,8 +85,16 @@ public class RememberMeConfigurerTests {
public void postWhenNoUserDetailsServiceThenException() { public void postWhenNoUserDetailsServiceThenException() {
this.spring.register(NullUserDetailsConfig.class).autowire(); this.spring.register(NullUserDetailsConfig.class).autowire();
assertThatIllegalStateException() assertThatIllegalStateException()
.isThrownBy(() -> this.mvc.perform(post("/login").param("username", "user") .isThrownBy(() -> {
.param("password", "password").param("remember-me", "true").with(csrf()))) // @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"); .withMessageContaining("UserDetailsService is required");
} }
@ -99,15 +109,26 @@ public class RememberMeConfigurerTests {
given(DuplicateDoesNotOverrideConfig.userDetailsService.loadUserByUsername(anyString())) given(DuplicateDoesNotOverrideConfig.userDetailsService.loadUserByUsername(anyString()))
.willReturn(new User("user", "password", Collections.emptyList())); .willReturn(new User("user", "password", Collections.emptyList()));
this.spring.register(DuplicateDoesNotOverrideConfig.class).autowire(); 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"); verify(DuplicateDoesNotOverrideConfig.userDetailsService).loadUserByUsername("user");
} }
@Test @Test
public void loginWhenRememberMeTrueThenRespondsWithRememberMeCookie() throws Exception { public void loginWhenRememberMeTrueThenRespondsWithRememberMeCookie() throws Exception {
this.spring.register(RememberMeConfig.class).autowire(); this.spring.register(RememberMeConfig.class).autowire();
this.mvc.perform(post("/login").with(csrf()).param("username", "user").param("password", "password") // @formatter:off
.param("remember-me", "true")).andExpect(cookie().exists("remember-me")); 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 @Test
@ -116,57 +137,108 @@ public class RememberMeConfigurerTests {
MvcResult mvcResult = this.mvc.perform(post("/login").with(csrf()).param("username", "user") MvcResult mvcResult = this.mvc.perform(post("/login").with(csrf()).param("username", "user")
.param("password", "password").param("remember-me", "true")).andReturn(); .param("password", "password").param("remember-me", "true")).andReturn();
Cookie rememberMeCookie = mvcResult.getResponse().getCookie("remember-me"); Cookie rememberMeCookie = mvcResult.getResponse().getCookie("remember-me");
this.mvc.perform(get("/abc").cookie(rememberMeCookie)).andExpect(authenticated() // @formatter:off
.withAuthentication((auth) -> assertThat(auth).isInstanceOf(RememberMeAuthenticationToken.class))); 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 @Test
public void logoutWhenRememberMeCookieThenAuthenticationIsRememberMeCookieExpired() throws Exception { public void logoutWhenRememberMeCookieThenAuthenticationIsRememberMeCookieExpired() throws Exception {
this.spring.register(RememberMeConfig.class).autowire(); this.spring.register(RememberMeConfig.class).autowire();
MvcResult mvcResult = this.mvc.perform(post("/login").with(csrf()).param("username", "user") // @formatter:off
.param("password", "password").param("remember-me", "true")).andReturn(); 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"); Cookie rememberMeCookie = mvcResult.getResponse().getCookie("remember-me");
HttpSession session = mvcResult.getRequest().getSession(); HttpSession session = mvcResult.getRequest().getSession();
this.mvc.perform(post("/logout").with(csrf()).cookie(rememberMeCookie).session((MockHttpSession) session)) // @formatter:off
.andExpect(redirectedUrl("/login?logout")).andExpect(cookie().maxAge("remember-me", 0)); 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 @Test
public void getWhenRememberMeCookieAndLoggedOutThenRedirectsToLogin() throws Exception { public void getWhenRememberMeCookieAndLoggedOutThenRedirectsToLogin() throws Exception {
this.spring.register(RememberMeConfig.class).autowire(); this.spring.register(RememberMeConfig.class).autowire();
MvcResult loginMvcResult = this.mvc.perform(post("/login").with(csrf()).param("username", "user") // @formatter:off
.param("password", "password").param("remember-me", "true")).andReturn(); 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"); Cookie rememberMeCookie = loginMvcResult.getResponse().getCookie("remember-me");
HttpSession session = loginMvcResult.getRequest().getSession(); HttpSession session = loginMvcResult.getRequest().getSession();
MvcResult logoutMvcResult = this.mvc // @formatter:off
.perform(post("/logout").with(csrf()).cookie(rememberMeCookie).session((MockHttpSession) session)) MockHttpServletRequestBuilder logoutRequest = post("/logout")
.andReturn(); .with(csrf())
.cookie(rememberMeCookie)
.session((MockHttpSession) session);
// @formatter:on
MvcResult logoutMvcResult = this.mvc.perform(logoutRequest).andReturn();
Cookie expiredRememberMeCookie = logoutMvcResult.getResponse().getCookie("remember-me"); Cookie expiredRememberMeCookie = logoutMvcResult.getResponse().getCookie("remember-me");
this.mvc.perform(get("/abc").with(csrf()).cookie(expiredRememberMeCookie)) // @formatter:off
.andExpect(redirectedUrl("http://localhost/login")); MockHttpServletRequestBuilder expiredRequest = get("/abc")
.with(csrf())
.cookie(expiredRememberMeCookie);
// @formatter:on
this.mvc.perform(expiredRequest).andExpect(redirectedUrl("http://localhost/login"));
} }
@Test @Test
public void loginWhenRememberMeConfiguredInLambdaThenRespondsWithRememberMeCookie() throws Exception { public void loginWhenRememberMeConfiguredInLambdaThenRespondsWithRememberMeCookie() throws Exception {
this.spring.register(RememberMeInLambdaConfig.class).autowire(); this.spring.register(RememberMeInLambdaConfig.class).autowire();
this.mvc.perform(post("/login").with(csrf()).param("username", "user").param("password", "password") // @formatter:off
.param("remember-me", "true")).andExpect(cookie().exists("remember-me")); 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 @Test
public void loginWhenRememberMeTrueAndCookieDomainThenRememberMeCookieHasDomain() throws Exception { public void loginWhenRememberMeTrueAndCookieDomainThenRememberMeCookieHasDomain() throws Exception {
this.spring.register(RememberMeCookieDomainConfig.class).autowire(); this.spring.register(RememberMeCookieDomainConfig.class).autowire();
this.mvc.perform(post("/login").with(csrf()).param("username", "user").param("password", "password") // @formatter:off
.param("remember-me", "true")).andExpect(cookie().exists("remember-me")) 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")); .andExpect(cookie().domain("remember-me", "spring.io"));
// @formatter:on
} }
@Test @Test
public void loginWhenRememberMeTrueAndCookieDomainInLambdaThenRememberMeCookieHasDomain() throws Exception { public void loginWhenRememberMeTrueAndCookieDomainInLambdaThenRememberMeCookieHasDomain() throws Exception {
this.spring.register(RememberMeCookieDomainInLambdaConfig.class).autowire(); this.spring.register(RememberMeCookieDomainInLambdaConfig.class).autowire();
this.mvc.perform(post("/login").with(csrf()).param("username", "user").param("password", "password") // @formatter:off
.param("remember-me", "true")).andExpect(cookie().exists("remember-me")) 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")); .andExpect(cookie().domain("remember-me", "spring.io"));
// @formatter:on
} }
@Test @Test
@ -181,11 +253,21 @@ public class RememberMeConfigurerTests {
@Test @Test
public void getWhenRememberMeCookieAndNoKeyConfiguredThenKeyFromRememberMeServicesIsUsed() throws Exception { public void getWhenRememberMeCookieAndNoKeyConfiguredThenKeyFromRememberMeServicesIsUsed() throws Exception {
this.spring.register(FallbackRememberMeKeyConfig.class).autowire(); this.spring.register(FallbackRememberMeKeyConfig.class).autowire();
MvcResult mvcResult = this.mvc.perform(post("/login").with(csrf()).param("username", "user") // @formatter:off
.param("password", "password").param("remember-me", "true")).andReturn(); 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"); Cookie rememberMeCookie = mvcResult.getResponse().getCookie("remember-me");
this.mvc.perform(get("/abc").cookie(rememberMeCookie)).andExpect(authenticated() MockHttpServletRequestBuilder requestWithRememberme = get("/abc").cookie(rememberMeCookie);
.withAuthentication((auth) -> assertThat(auth).isInstanceOf(RememberMeAuthenticationToken.class))); // @formatter:off
SecurityMockMvcResultMatchers.AuthenticatedMatcher remembermeAuthentication = authenticated()
.withAuthentication((auth) -> assertThat(auth).isInstanceOf(RememberMeAuthenticationToken.class));
// @formatter:on
this.mvc.perform(requestWithRememberme).andExpect(remembermeAuthentication);
} }
@EnableWebSecurity @EnableWebSecurity

View File

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

View File

@ -47,15 +47,23 @@ public class RequestMatcherConfigurerTests {
@Test @Test
public void authorizeRequestsWhenInvokedMultipleTimesThenChainsPaths() throws Exception { public void authorizeRequestsWhenInvokedMultipleTimesThenChainsPaths() throws Exception {
this.spring.register(Sec2908Config.class).autowire(); this.spring.register(Sec2908Config.class).autowire();
this.mvc.perform(get("/oauth/abc")).andExpect(status().isForbidden()); // @formatter:off
this.mvc.perform(get("/api/abc")).andExpect(status().isForbidden()); this.mvc.perform(get("/oauth/abc"))
.andExpect(status().isForbidden());
this.mvc.perform(get("/api/abc"))
.andExpect(status().isForbidden());
// @formatter:on
} }
@Test @Test
public void authorizeRequestsWhenInvokedMultipleTimesInLambdaThenChainsPaths() throws Exception { public void authorizeRequestsWhenInvokedMultipleTimesInLambdaThenChainsPaths() throws Exception {
this.spring.register(AuthorizeRequestInLambdaConfig.class).autowire(); this.spring.register(AuthorizeRequestInLambdaConfig.class).autowire();
this.mvc.perform(get("/oauth/abc")).andExpect(status().isForbidden()); // @formatter:off
this.mvc.perform(get("/api/abc")).andExpect(status().isForbidden()); this.mvc.perform(get("/oauth/abc"))
.andExpect(status().isForbidden());
this.mvc.perform(get("/api/abc"))
.andExpect(status().isForbidden());
// @formatter:on
} }
@EnableWebSecurity @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.AuthenticationException;
import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.PasswordEncodedUser; 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.util.FieldUtils;
import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.FilterChainProxy; 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.security.web.servletapi.SecurityContextHolderAwareRequestFilter;
import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult; 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.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
@ -109,9 +111,9 @@ public class ServletApiConfigurerTests {
@Test @Test
public void configureWhenUsingDefaultsThenRolePrefixIsSet() throws Exception { public void configureWhenUsingDefaultsThenRolePrefixIsSet() throws Exception {
this.spring.register(ServletApiConfig.class, AdminController.class).autowire(); this.spring.register(ServletApiConfig.class, AdminController.class).autowire();
this.mvc.perform( TestingAuthenticationToken user = new TestingAuthenticationToken("user", "pass", "ROLE_ADMIN");
get("/admin").with(authentication(new TestingAuthenticationToken("user", "pass", "ROLE_ADMIN")))) MockHttpServletRequestBuilder request = get("/admin").with(authentication(user));
.andExpect(status().isOk()); this.mvc.perform(request).andExpect(status().isOk());
} }
@Test @Test
@ -125,11 +127,18 @@ public class ServletApiConfigurerTests {
@Test @Test
public void servletApiWhenInvokedTwiceThenUsesOriginalRole() throws Exception { public void servletApiWhenInvokedTwiceThenUsesOriginalRole() throws Exception {
this.spring.register(DuplicateInvocationsDoesNotOverrideConfig.class, AdminController.class).autowire(); this.spring.register(DuplicateInvocationsDoesNotOverrideConfig.class, AdminController.class).autowire();
this.mvc.perform( // @formatter:off
get("/admin").with(user("user").authorities(AuthorityUtils.createAuthorityList("PERMISSION_ADMIN")))) MockHttpServletRequestBuilder request = get("/admin")
.with(user("user").authorities(AuthorityUtils.createAuthorityList("PERMISSION_ADMIN")));
this.mvc.perform(request)
.andExpect(status().isOk()); .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()); .andExpect(status().isForbidden());
// @formatter:on
} }
@Test @Test
@ -142,18 +151,25 @@ public class ServletApiConfigurerTests {
@Test @Test
public void requestWhenServletApiWithDefaultsInLambdaThenUsesDefaultRolePrefix() throws Exception { public void requestWhenServletApiWithDefaultsInLambdaThenUsesDefaultRolePrefix() throws Exception {
this.spring.register(ServletApiWithDefaultsInLambdaConfig.class, AdminController.class).autowire(); 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()); .andExpect(status().isOk());
} }
@Test @Test
public void requestWhenRolePrefixInLambdaThenUsesCustomRolePrefix() throws Exception { public void requestWhenRolePrefixInLambdaThenUsesCustomRolePrefix() throws Exception {
this.spring.register(RolePrefixInLambdaConfig.class, AdminController.class).autowire(); this.spring.register(RolePrefixInLambdaConfig.class, AdminController.class).autowire();
this.mvc.perform( // @formatter:off
get("/admin").with(user("user").authorities(AuthorityUtils.createAuthorityList("PERMISSION_ADMIN")))) MockHttpServletRequestBuilder requestWithAdminPermission = get("/admin")
.with(user("user").authorities(AuthorityUtils.createAuthorityList("PERMISSION_ADMIN")));
this.mvc.perform(requestWithAdminPermission)
.andExpect(status().isOk()); .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()); .andExpect(status().isForbidden());
// @formatter:on
} }
@Test @Test

View File

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

View File

@ -61,42 +61,60 @@ public class UrlAuthorizationsTests {
@WithMockUser(authorities = "ROLE_USER") @WithMockUser(authorities = "ROLE_USER")
public void hasAnyAuthorityWhenAuthoritySpecifiedThenMatchesAuthority() throws Exception { public void hasAnyAuthorityWhenAuthoritySpecifiedThenMatchesAuthority() throws Exception {
this.spring.register(RoleConfig.class).autowire(); this.spring.register(RoleConfig.class).autowire();
this.mvc.perform(get("/role-user-authority")).andExpect(status().isNotFound()); // @formatter:off
this.mvc.perform(get("/role-user")).andExpect(status().isNotFound()); this.mvc.perform(get("/role-user-authority"))
this.mvc.perform(get("/role-admin-authority")).andExpect(status().isForbidden()); .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 @Test
@WithMockUser(authorities = "ROLE_ADMIN") @WithMockUser(authorities = "ROLE_ADMIN")
public void hasAnyAuthorityWhenAuthoritiesSpecifiedThenMatchesAuthority() throws Exception { public void hasAnyAuthorityWhenAuthoritiesSpecifiedThenMatchesAuthority() throws Exception {
this.spring.register(RoleConfig.class).autowire(); this.spring.register(RoleConfig.class).autowire();
this.mvc.perform(get("/role-user-admin-authority")).andExpect(status().isNotFound()); this.mvc.perform(get("/role-user-admin-authority"))
this.mvc.perform(get("/role-user-admin")).andExpect(status().isNotFound()); .andExpect(status().isNotFound());
this.mvc.perform(get("/role-user-authority")).andExpect(status().isForbidden()); this.mvc.perform(get("/role-user-admin"))
.andExpect(status().isNotFound());
this.mvc.perform(get("/role-user-authority"))
.andExpect(status().isForbidden());
} }
@Test @Test
@WithMockUser(roles = "USER") @WithMockUser(roles = "USER")
public void hasAnyRoleWhenRoleSpecifiedThenMatchesRole() throws Exception { public void hasAnyRoleWhenRoleSpecifiedThenMatchesRole() throws Exception {
this.spring.register(RoleConfig.class).autowire(); this.spring.register(RoleConfig.class).autowire();
this.mvc.perform(get("/role-user")).andExpect(status().isNotFound()); // @formatter:off
this.mvc.perform(get("/role-admin")).andExpect(status().isForbidden()); this.mvc.perform(get("/role-user"))
.andExpect(status().isNotFound());
this.mvc.perform(get("/role-admin"))
.andExpect(status().isForbidden());
// @formatter:on
} }
@Test @Test
@WithMockUser(roles = "ADMIN") @WithMockUser(roles = "ADMIN")
public void hasAnyRoleWhenRolesSpecifiedThenMatchesRole() throws Exception { public void hasAnyRoleWhenRolesSpecifiedThenMatchesRole() throws Exception {
this.spring.register(RoleConfig.class).autowire(); this.spring.register(RoleConfig.class).autowire();
this.mvc.perform(get("/role-admin-user")).andExpect(status().isNotFound()); this.mvc.perform(get("/role-admin-user"))
this.mvc.perform(get("/role-user")).andExpect(status().isForbidden()); .andExpect(status().isNotFound());
this.mvc.perform(get("/role-user"))
.andExpect(status().isForbidden());
} }
@Test @Test
@WithMockUser(authorities = "USER") @WithMockUser(authorities = "USER")
public void hasAnyRoleWhenRoleSpecifiedThenDoesNotMatchAuthority() throws Exception { public void hasAnyRoleWhenRoleSpecifiedThenDoesNotMatchAuthority() throws Exception {
this.spring.register(RoleConfig.class).autowire(); this.spring.register(RoleConfig.class).autowire();
this.mvc.perform(get("/role-user")).andExpect(status().isForbidden()); // @formatter:off
this.mvc.perform(get("/role-admin")).andExpect(status().isForbidden()); this.mvc.perform(get("/role-user"))
.andExpect(status().isForbidden());
this.mvc.perform(get("/role-admin"))
.andExpect(status().isForbidden());
// @formatter:on
} }
@Test @Test
@ -145,7 +163,11 @@ public class UrlAuthorizationsTests {
ApplicationContext context = getApplicationContext(); ApplicationContext context = getApplicationContext();
UrlAuthorizationConfigurer<HttpSecurity>.StandardInterceptUrlRegistry registry = http UrlAuthorizationConfigurer<HttpSecurity>.StandardInterceptUrlRegistry registry = http
.apply(new UrlAuthorizationConfigurer(context)).getRegistry(); .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 { public void x509WhenInvokedTwiceThenUsesOriginalSubjectPrincipalRegex() throws Exception {
this.spring.register(DuplicateDoesNotOverrideConfig.class).autowire(); this.spring.register(DuplicateDoesNotOverrideConfig.class).autowire();
X509Certificate certificate = loadCert("rodatexampledotcom.cer"); 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 @Test
public void x509WhenConfiguredInLambdaThenUsesDefaults() throws Exception { public void x509WhenConfiguredInLambdaThenUsesDefaults() throws Exception {
this.spring.register(DefaultsInLambdaConfig.class).autowire(); this.spring.register(DefaultsInLambdaConfig.class).autowire();
X509Certificate certificate = loadCert("rod.cer"); 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 @Test
public void x509WhenSubjectPrincipalRegexInLambdaThenUsesRegexToExtractPrincipal() throws Exception { public void x509WhenSubjectPrincipalRegexInLambdaThenUsesRegexToExtractPrincipal() throws Exception {
this.spring.register(SubjectPrincipalRegexInLambdaConfig.class).autowire(); this.spring.register(SubjectPrincipalRegexInLambdaConfig.class).autowire();
X509Certificate certificate = loadCert("rodatexampledotcom.cer"); 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) { 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.security.web.savedrequest.RequestCache;
import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult; 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.GetMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.EnableWebMvc;
@ -107,13 +108,22 @@ public class OAuth2ClientConfigurerTests {
@Before @Before
public void setup() { public void setup() {
this.registration1 = TestClientRegistrations.clientRegistration().registrationId("registration-1") // @formatter:off
.clientId("client-1").clientSecret("secret") this.registration1 = TestClientRegistrations.clientRegistration()
.registrationId("registration-1")
.clientId("client-1")
.clientSecret("secret")
.clientAuthenticationMethod(ClientAuthenticationMethod.BASIC) .clientAuthenticationMethod(ClientAuthenticationMethod.BASIC)
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE).redirectUri("{baseUrl}/client-1") .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.scope("user").authorizationUri("https://provider.com/oauth2/authorize") .redirectUri("{baseUrl}/client-1")
.tokenUri("https://provider.com/oauth2/token").userInfoUri("https://provider.com/oauth2/user") .scope("user")
.userNameAttributeName("id").clientName("client-1").build(); .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); clientRegistrationRepository = new InMemoryClientRegistrationRepository(this.registration1);
authorizedClientService = new InMemoryOAuth2AuthorizedClientService(clientRegistrationRepository); authorizedClientService = new InMemoryOAuth2AuthorizedClientService(clientRegistrationRepository);
authorizedClientRepository = new AuthenticatedPrincipalOAuth2AuthorizedClientRepository( authorizedClientRepository = new AuthenticatedPrincipalOAuth2AuthorizedClientRepository(
@ -131,11 +141,13 @@ public class OAuth2ClientConfigurerTests {
@Test @Test
public void configureWhenAuthorizationCodeRequestThenRedirectForAuthorization() throws Exception { public void configureWhenAuthorizationCodeRequestThenRedirectForAuthorization() throws Exception {
this.spring.register(OAuth2ClientConfig.class).autowire(); this.spring.register(OAuth2ClientConfig.class).autowire();
// @formatter:off
MvcResult mvcResult = this.mockMvc.perform(get("/oauth2/authorization/registration-1")) MvcResult mvcResult = this.mockMvc.perform(get("/oauth2/authorization/registration-1"))
.andExpect(status().is3xxRedirection()).andReturn(); .andExpect(status().is3xxRedirection()).andReturn();
assertThat(mvcResult.getResponse().getRedirectedUrl()) assertThat(mvcResult.getResponse().getRedirectedUrl())
.matches("https://provider.com/oauth2/authorize\\?" + "response_type=code&client_id=client-1&" .matches("https://provider.com/oauth2/authorize\\?" + "response_type=code&client_id=client-1&"
+ "scope=user&state=.{15,}&" + "redirect_uri=http://localhost/client-1"); + "scope=user&state=.{15,}&" + "redirect_uri=http://localhost/client-1");
// @formatter:on
} }
@Test @Test
@ -154,10 +166,15 @@ public class OAuth2ClientConfigurerTests {
// Setup the Authorization Request in the session // Setup the Authorization Request in the session
Map<String, Object> attributes = new HashMap<>(); Map<String, Object> attributes = new HashMap<>();
attributes.put(OAuth2ParameterNames.REGISTRATION_ID, this.registration1.getRegistrationId()); attributes.put(OAuth2ParameterNames.REGISTRATION_ID, this.registration1.getRegistrationId());
// @formatter:off
OAuth2AuthorizationRequest authorizationRequest = OAuth2AuthorizationRequest.authorizationCode() OAuth2AuthorizationRequest authorizationRequest = OAuth2AuthorizationRequest.authorizationCode()
.authorizationUri(this.registration1.getProviderDetails().getAuthorizationUri()) .authorizationUri(this.registration1.getProviderDetails().getAuthorizationUri())
.clientId(this.registration1.getClientId()).redirectUri("http://localhost/client-1").state("state") .clientId(this.registration1.getClientId())
.attributes(attributes).build(); .redirectUri("http://localhost/client-1")
.state("state")
.attributes(attributes)
.build();
// @formatter:on
AuthorizationRequestRepository<OAuth2AuthorizationRequest> authorizationRequestRepository = new HttpSessionOAuth2AuthorizationRequestRepository(); AuthorizationRequestRepository<OAuth2AuthorizationRequest> authorizationRequestRepository = new HttpSessionOAuth2AuthorizationRequestRepository();
MockHttpServletRequest request = new MockHttpServletRequest("GET", ""); MockHttpServletRequest request = new MockHttpServletRequest("GET", "");
MockHttpServletResponse response = new MockHttpServletResponse(); MockHttpServletResponse response = new MockHttpServletResponse();
@ -165,9 +182,16 @@ public class OAuth2ClientConfigurerTests {
MockHttpSession session = (MockHttpSession) request.getSession(); MockHttpSession session = (MockHttpSession) request.getSession();
String principalName = "user1"; String principalName = "user1";
TestingAuthenticationToken authentication = new TestingAuthenticationToken(principalName, "password"); TestingAuthenticationToken authentication = new TestingAuthenticationToken(principalName, "password");
this.mockMvc.perform(get("/client-1").param(OAuth2ParameterNames.CODE, "code") // @formatter:off
.param(OAuth2ParameterNames.STATE, "state").with(authentication(authentication)).session(session)) MockHttpServletRequestBuilder clientRequest = get("/client-1")
.andExpect(status().is3xxRedirection()).andExpect(redirectedUrl("http://localhost/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 OAuth2AuthorizedClient authorizedClient = authorizedClientRepository
.loadAuthorizedClient(this.registration1.getRegistrationId(), authentication, request); .loadAuthorizedClient(this.registration1.getRegistrationId(), authentication, request);
assertThat(authorizedClient).isNotNull(); assertThat(authorizedClient).isNotNull();
@ -191,10 +215,14 @@ public class OAuth2ClientConfigurerTests {
// Setup the Authorization Request in the session // Setup the Authorization Request in the session
Map<String, Object> attributes = new HashMap<>(); Map<String, Object> attributes = new HashMap<>();
attributes.put(OAuth2ParameterNames.REGISTRATION_ID, this.registration1.getRegistrationId()); attributes.put(OAuth2ParameterNames.REGISTRATION_ID, this.registration1.getRegistrationId());
// @formatter:off
OAuth2AuthorizationRequest authorizationRequest = OAuth2AuthorizationRequest.authorizationCode() OAuth2AuthorizationRequest authorizationRequest = OAuth2AuthorizationRequest.authorizationCode()
.authorizationUri(this.registration1.getProviderDetails().getAuthorizationUri()) .authorizationUri(this.registration1.getProviderDetails().getAuthorizationUri())
.clientId(this.registration1.getClientId()).redirectUri("http://localhost/client-1").state("state") .clientId(this.registration1.getClientId()).redirectUri("http://localhost/client-1")
.attributes(attributes).build(); .state("state")
.attributes(attributes)
.build();
// @formatter:on
AuthorizationRequestRepository<OAuth2AuthorizationRequest> authorizationRequestRepository = new HttpSessionOAuth2AuthorizationRequestRepository(); AuthorizationRequestRepository<OAuth2AuthorizationRequest> authorizationRequestRepository = new HttpSessionOAuth2AuthorizationRequestRepository();
MockHttpServletRequest request = new MockHttpServletRequest("GET", ""); MockHttpServletRequest request = new MockHttpServletRequest("GET", "");
MockHttpServletResponse response = new MockHttpServletResponse(); MockHttpServletResponse response = new MockHttpServletResponse();
@ -202,9 +230,16 @@ public class OAuth2ClientConfigurerTests {
MockHttpSession session = (MockHttpSession) request.getSession(); MockHttpSession session = (MockHttpSession) request.getSession();
String principalName = "user1"; String principalName = "user1";
TestingAuthenticationToken authentication = new TestingAuthenticationToken(principalName, "password"); TestingAuthenticationToken authentication = new TestingAuthenticationToken(principalName, "password");
this.mockMvc.perform(get("/client-1").param(OAuth2ParameterNames.CODE, "code") // @formatter:off
.param(OAuth2ParameterNames.STATE, "state").with(authentication(authentication)).session(session)) MockHttpServletRequestBuilder clientRequest = get("/client-1")
.andExpect(status().is3xxRedirection()).andExpect(redirectedUrl("http://localhost/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)); verify(requestCache).getRequest(any(HttpServletRequest.class), any(HttpServletResponse.class));
} }
@ -218,8 +253,11 @@ public class OAuth2ClientConfigurerTests {
given(authorizationRequestResolver.resolve(any())) given(authorizationRequestResolver.resolve(any()))
.willAnswer((invocation) -> defaultAuthorizationRequestResolver.resolve(invocation.getArgument(0))); .willAnswer((invocation) -> defaultAuthorizationRequestResolver.resolve(invocation.getArgument(0)));
this.spring.register(OAuth2ClientConfig.class).autowire(); 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(); .andReturn();
// @formatter:on
verify(authorizationRequestResolver).resolve(any()); verify(authorizationRequestResolver).resolve(any());
} }

View File

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

View File

@ -40,6 +40,7 @@ import org.springframework.security.openid.OpenIDAuthenticationFilter;
import org.springframework.security.openid.OpenIDAuthenticationProvider; import org.springframework.security.openid.OpenIDAuthenticationProvider;
import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult; 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.assertThat;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
@ -84,15 +85,21 @@ public class OpenIDLoginConfigurerTests {
@Test @Test
public void openidLoginWhenInvokedTwiceThenUsesOriginalLoginPage() throws Exception { public void openidLoginWhenInvokedTwiceThenUsesOriginalLoginPage() throws Exception {
this.spring.register(InvokeTwiceDoesNotOverrideConfig.class).autowire(); 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")); .andExpect(redirectedUrl("http://localhost/login/custom"));
// @formatter:on
} }
@Test @Test
public void requestWhenOpenIdLoginPageInLambdaThenRedirectsToLoginPAge() throws Exception { public void requestWhenOpenIdLoginPageInLambdaThenRedirectsToLoginPAge() throws Exception {
this.spring.register(OpenIdLoginPageInLambdaConfig.class).autowire(); 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")); .andExpect(redirectedUrl("http://localhost/login/custom"));
// @formatter:on
} }
@Test @Test
@ -144,11 +151,15 @@ public class OpenIDLoginConfigurerTests {
server.enqueue(new MockResponse().addHeader(YadisResolver.YADIS_XRDS_LOCATION, endpoint)); server.enqueue(new MockResponse().addHeader(YadisResolver.YADIS_XRDS_LOCATION, endpoint));
server.enqueue(new MockResponse() server.enqueue(new MockResponse()
.setBody(String.format("<XRDS><XRD><Service><URI>%s</URI></Service></XRD></XRDS>", endpoint))); .setBody(String.format("<XRDS><XRD><Service><URI>%s</URI></Service></XRD></XRDS>", endpoint)));
MvcResult mvcResult = this.mvc.perform( // @formatter:off
get("/login/openid").param(OpenIDAuthenticationFilter.DEFAULT_CLAIMED_IDENTITY_FIELD, endpoint)) MockHttpServletRequestBuilder request = get("/login/openid")
.andExpect(status().isFound()).andReturn(); .param(OpenIDAuthenticationFilter.DEFAULT_CLAIMED_IDENTITY_FIELD, endpoint);
MvcResult mvcResult = this.mvc.perform(request)
.andExpect(status().isFound())
.andReturn();
Object attributeObject = mvcResult.getRequest().getSession() Object attributeObject = mvcResult.getRequest().getSession()
.getAttribute("SPRING_SECURITY_OPEN_ID_ATTRIBUTES_FETCH_LIST"); .getAttribute("SPRING_SECURITY_OPEN_ID_ATTRIBUTES_FETCH_LIST");
// @formatter:on
assertThat(attributeObject).isInstanceOf(List.class); assertThat(attributeObject).isInstanceOf(List.class);
List<OpenIDAttribute> attributeList = (List<OpenIDAttribute>) attributeObject; List<OpenIDAttribute> attributeList = (List<OpenIDAttribute>) attributeObject;
assertThat(attributeList).hasSize(1); 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.util.ReflectionTestUtils;
import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult; 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.UriComponents;
import org.springframework.web.util.UriComponentsBuilder; import org.springframework.web.util.UriComponentsBuilder;
@ -198,8 +199,11 @@ public class Saml2LoginConfigurerTests {
String response = new String(samlDecode(SIGNED_RESPONSE)); String response = new String(samlDecode(SIGNED_RESPONSE));
given(CustomAuthenticationConverter.authenticationConverter.convert(any(HttpServletRequest.class))) given(CustomAuthenticationConverter.authenticationConverter.convert(any(HttpServletRequest.class)))
.willReturn(new Saml2AuthenticationToken(relyingPartyRegistration, response)); .willReturn(new Saml2AuthenticationToken(relyingPartyRegistration, response));
this.mvc.perform(post("/login/saml2/sso/" + relyingPartyRegistration.getRegistrationId()).param("SAMLResponse", // @formatter:off
SIGNED_RESPONSE)).andExpect(redirectedUrl("/")); 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)); verify(CustomAuthenticationConverter.authenticationConverter).convert(any(HttpServletRequest.class));
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -51,73 +51,107 @@ public class AuthenticationProviderBeanDefinitionParserTests {
@Test @Test
public void worksWithEmbeddedUserService() { 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 name='bob' password='{noop}bobspassword' authorities='ROLE_A' />"
+ " </user-service>" + " </authentication-provider>"); + " </user-service>"
+ " </authentication-provider>");
// @formatter:on
getProvider().authenticate(this.bob); getProvider().authenticate(this.bob);
} }
@Test @Test
public void externalUserServiceRefWorks() { public void externalUserServiceRefWorks() {
// @formatter:off
this.appContext = new InMemoryXmlApplicationContext( this.appContext = new InMemoryXmlApplicationContext(
" <authentication-manager>" + " <authentication-provider user-service-ref='myUserService' />" " <authentication-manager>"
+ " <authentication-provider user-service-ref='myUserService' />"
+ " </authentication-manager>" + " <user-service id='myUserService'>" + " </authentication-manager>" + " <user-service id='myUserService'>"
+ " <user name='bob' password='{noop}bobspassword' authorities='ROLE_A' />" + " <user name='bob' password='{noop}bobspassword' authorities='ROLE_A' />"
+ " </user-service>"); + " </user-service>");
// @formatter:on
getProvider().authenticate(this.bob); getProvider().authenticate(this.bob);
} }
@Test @Test
public void providerWithBCryptPasswordEncoderWorks() { 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 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); getProvider().authenticate(this.bob);
} }
@Test @Test
public void providerWithMd5PasswordEncoderWorks() { public void providerWithMd5PasswordEncoderWorks() {
this.appContext = new InMemoryXmlApplicationContext(" <authentication-manager>" + " <authentication-provider>" // @formatter:off
+ " <password-encoder ref='passwordEncoder'/>" + " <user-service>" this.appContext = new InMemoryXmlApplicationContext(" <authentication-manager>"
+ " <authentication-provider>"
+ " <password-encoder ref='passwordEncoder'/>"
+ " <user-service>"
+ " <user name='bob' password='12b141f35d58b8b3a46eea65e6ac179e' authorities='ROLE_A' />" + " <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: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); getProvider().authenticate(this.bob);
} }
@Test @Test
public void providerWithShaPasswordEncoderWorks() { public void providerWithShaPasswordEncoderWorks() {
this.appContext = new InMemoryXmlApplicationContext(" <authentication-manager>" + " <authentication-provider>" // @formatter:off
+ " <password-encoder ref='passwordEncoder'/>" + " <user-service>" 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 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() + "'/>"); + " <b:bean id='passwordEncoder' class='" + LdapShaPasswordEncoder.class.getName() + "'/>");
// @formatter:on
getProvider().authenticate(this.bob); getProvider().authenticate(this.bob);
} }
@Test @Test
public void passwordIsBase64EncodedWhenBase64IsEnabled() { public void passwordIsBase64EncodedWhenBase64IsEnabled() {
this.appContext = new InMemoryXmlApplicationContext(" <authentication-manager>" + " <authentication-provider>" // @formatter:off
+ " <password-encoder ref='passwordEncoder'/>" + " <user-service>" this.appContext = new InMemoryXmlApplicationContext(" <authentication-manager>"
+ " <authentication-provider>"
+ " <password-encoder ref='passwordEncoder'/>"
+ " <user-service>"
+ " <user name='bob' password='ErFB811YuLOkbupl5qwXng==' authorities='ROLE_A' />" + " <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:bean id='passwordEncoder' class='" + MessageDigestPasswordEncoder.class.getName() + "'>"
+ " <b:constructor-arg value='MD5'/>" + " <b:property name='encodeHashAsBase64' value='true'/>" + " <b:constructor-arg value='MD5'/>" + " <b:property name='encodeHashAsBase64' value='true'/>"
+ " </b:bean>"); + " </b:bean>");
// @formatter:on
getProvider().authenticate(this.bob); getProvider().authenticate(this.bob);
} }
// SEC-1466 // SEC-1466
@Test(expected = BeanDefinitionParsingException.class) @Test(expected = BeanDefinitionParsingException.class)
public void exernalProviderDoesNotSupportChildElements() { public void exernalProviderDoesNotSupportChildElements() {
// @formatter:off
this.appContext = new InMemoryXmlApplicationContext(" <authentication-manager>" this.appContext = new InMemoryXmlApplicationContext(" <authentication-manager>"
+ " <authentication-provider ref='aProvider'> " + " <authentication-provider ref='aProvider'> "
+ " <password-encoder ref='customPasswordEncoder'/>" + " </authentication-provider>" + " <password-encoder ref='customPasswordEncoder'/>"
+ " </authentication-provider>"
+ " </authentication-manager>" + " </authentication-manager>"
+ " <b:bean id='aProvider' class='org.springframework.security.authentication.TestingAuthenticationProvider'/>" + " <b:bean id='aProvider' class='org.springframework.security.authentication.TestingAuthenticationProvider'/>"
+ " <b:bean id='customPasswordEncoder' " + " <b:bean id='customPasswordEncoder' "
+ " class='org.springframework.security.authentication.encoding.Md5PasswordEncoder'/>"); + " class='org.springframework.security.authentication.encoding.Md5PasswordEncoder'/>");
// @formatter:on
} }
private AuthenticationProvider getProvider() { 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'/>"; 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'>" 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: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; private InMemoryXmlApplicationContext appContext;
@ -81,9 +85,13 @@ public class JdbcUserServiceBeanDefinitionParserTests {
public void usernameAndAuthorityQueriesAreParsedCorrectly() throws Exception { public void usernameAndAuthorityQueriesAreParsedCorrectly() throws Exception {
String userQuery = "select username, password, true from users where username = ?"; String userQuery = "select username, password, true from users where username = ?";
String authoritiesQuery = "select username, authority from authorities where username = ? and 1 = 1"; String authoritiesQuery = "select username, authority from authorities where username = ? and 1 = 1";
setContext("<jdbc-user-service id='myUserService' " + "data-source-ref='dataSource' " // @formatter:off
+ "users-by-username-query='" + userQuery + "' " + "authorities-by-username-query='" + authoritiesQuery setContext("<jdbc-user-service id='myUserService' "
+ "data-source-ref='dataSource' "
+ "users-by-username-query='" + userQuery + "' "
+ "authorities-by-username-query='" + authoritiesQuery
+ "'/>" + DATA_SOURCE); + "'/>" + DATA_SOURCE);
// @formatter:on
JdbcUserDetailsManager mgr = (JdbcUserDetailsManager) this.appContext.getBean("myUserService"); JdbcUserDetailsManager mgr = (JdbcUserDetailsManager) this.appContext.getBean("myUserService");
assertThat(FieldUtils.getFieldValue(mgr, "usersByUsernameQuery")).isEqualTo(userQuery); assertThat(FieldUtils.getFieldValue(mgr, "usersByUsernameQuery")).isEqualTo(userQuery);
assertThat(FieldUtils.getFieldValue(mgr, "authoritiesByUsernameQuery")).isEqualTo(authoritiesQuery); assertThat(FieldUtils.getFieldValue(mgr, "authoritiesByUsernameQuery")).isEqualTo(authoritiesQuery);
@ -112,18 +120,29 @@ public class JdbcUserServiceBeanDefinitionParserTests {
@Test @Test
public void isSupportedByAuthenticationProviderElement() { public void isSupportedByAuthenticationProviderElement() {
setContext("<authentication-manager>" + " <authentication-provider>" // @formatter:off
+ " <jdbc-user-service data-source-ref='dataSource'/>" + " </authentication-provider>" setContext("<authentication-manager>"
+ "</authentication-manager>" + DATA_SOURCE); + " <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); AuthenticationManager mgr = (AuthenticationManager) this.appContext.getBean(BeanIds.AUTHENTICATION_MANAGER);
mgr.authenticate(new UsernamePasswordAuthenticationToken("rod", "koala")); mgr.authenticate(new UsernamePasswordAuthenticationToken("rod", "koala"));
} }
@Test @Test
public void cacheIsInjectedIntoAuthenticationProvider() { 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'/>" + " <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); ProviderManager mgr = (ProviderManager) this.appContext.getBean(BeanIds.AUTHENTICATION_MANAGER);
DaoAuthenticationProvider provider = (DaoAuthenticationProvider) mgr.getProviders().get(0); DaoAuthenticationProvider provider = (DaoAuthenticationProvider) mgr.getProviders().get(0);
assertThat(this.appContext.getBean("userCache")).isSameAs(provider.getUserCache()); assertThat(this.appContext.getBean("userCache")).isSameAs(provider.getUserCache());

View File

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

View File

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

View File

@ -45,6 +45,7 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
*/ */
public class RsaKeyConversionServicePostProcessorTests { public class RsaKeyConversionServicePostProcessorTests {
// @formatter:off
private static final String PKCS8_PRIVATE_KEY = "-----BEGIN PRIVATE KEY-----\n" private static final String PKCS8_PRIVATE_KEY = "-----BEGIN PRIVATE KEY-----\n"
+ "MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCMk7CKSTfu3QoV\n" + "MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCMk7CKSTfu3QoV\n"
+ "HoPVXxwZO+qweztd36cVWYqGOZinrOR2crWFu50AgR2CsdIH0+cqo7F4Vx7/3O8i\n" + "HoPVXxwZO+qweztd36cVWYqGOZinrOR2crWFu50AgR2CsdIH0+cqo7F4Vx7/3O8i\n"
@ -70,8 +71,10 @@ public class RsaKeyConversionServicePostProcessorTests {
+ "OHjxffBM0hH+fySx8m53gFfr2BpaqDX5f6ZGBlly1SlsWZ4CchCVsc71nshipi7I\n" + "OHjxffBM0hH+fySx8m53gFfr2BpaqDX5f6ZGBlly1SlsWZ4CchCVsc71nshipi7I\n"
+ "k8HL9F5/OpQdDNprJ5RMBNfkWE65Nrcsb1e6oPkCgYAxwgdiSOtNg8PjDVDmAhwT\n" + "k8HL9F5/OpQdDNprJ5RMBNfkWE65Nrcsb1e6oPkCgYAxwgdiSOtNg8PjDVDmAhwT\n"
+ "Mxj0Dtwi2fAqQ76RVrrXpNp3uCOIAu4CfruIb5llcJ3uak0ZbnWri32AxSgk80y3\n" + "Mxj0Dtwi2fAqQ76RVrrXpNp3uCOIAu4CfruIb5llcJ3uak0ZbnWri32AxSgk80y3\n"
+ "EWiRX/WEDu5znejF+5O3pI02atWWcnxifEKGGlxwkcMbQdA67MlrJLFaSnnGpNXo\n" + "yPfcul058SOqhafIZQMEKQ==\n" + "EWiRX/WEDu5znejF+5O3pI02atWWcnxifEKGGlxwkcMbQdA67MlrJLFaSnnGpNXo\n"
+ "yPfcul058SOqhafIZQMEKQ==\n"
+ "-----END PRIVATE KEY-----"; + "-----END PRIVATE KEY-----";
// @formatter:on
private static final String X509_PUBLIC_KEY_LOCATION = "classpath:org/springframework/security/config/annotation/web/configuration/simple.pub"; 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())) { while (!"schema".equals(root.simpleName())) {
root = root.parent().get(); 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); .orElseThrow(IllegalArgumentException::new);
// @formatter:on
} }
private Stream<XmlNode> expand(XmlNode root) { 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() { public Stream<XmlNode> children() {
NodeList children = this.node.getChildNodes(); 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) { 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() { 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) { public String attribute(String name) {
return Optional.ofNullable(this.node.getAttributes()).map((attrs) -> attrs.getNamedItem(name)) // @formatter:off
.map((attr) -> attr.getTextContent()).orElse(null); return Optional.ofNullable(this.node.getAttributes())
.map((attrs) -> attrs.getNamedItem(name))
.map((attr) -> attr.getTextContent())
.orElse(null);
// @formatter:on
} }
public Node node() { public Node node() {

View File

@ -46,11 +46,20 @@ import static org.assertj.core.api.Assertions.assertThat;
*/ */
public class XsdDocumentedTests { public class XsdDocumentedTests {
Collection<String> ignoredIds = Arrays.asList("nsa-any-user-service", "nsa-any-user-service-parents", // @formatter:off
"nsa-authentication", "nsa-websocket-security", "nsa-ldap", "nsa-method-security", "nsa-web", 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 // 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"); "nsa-frame-options-from-parameter");
// @formatter:on
String referenceLocation = "../docs/manual/src/docs/asciidoc/_includes/servlet/appendix/namespace.adoc"; String referenceLocation = "../docs/manual/src/docs/asciidoc/_includes/servlet/appendix/namespace.adoc";
@ -68,28 +77,61 @@ public class XsdDocumentedTests {
@Test @Test
public void parseWhenLatestXsdThenAllNamedSecurityFiltersAreDefinedAndOrderedProperly() throws IOException { public void parseWhenLatestXsdThenAllNamedSecurityFiltersAreDefinedAndOrderedProperly() throws IOException {
XmlNode root = this.xml.parse(this.schemaDocumentLocation); 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()) .filter((node) -> "simpleType".equals(node.simpleName())
&& "named-security-filter".equals(node.attribute("name"))) && "named-security-filter".equals(node.attribute("name")))
.flatMap(XmlNode::children).flatMap(XmlNode::children).map((node) -> node.attribute("value")) .flatMap(XmlNode::children)
.filter(StringUtils::isNotEmpty).collect(Collectors.toList()); .flatMap(XmlNode::children)
.map((node) -> node.attribute("value"))
.filter(StringUtils::isNotEmpty)
.collect(Collectors.toList());
// @formatter:on
SecurityFiltersAssertions.assertEquals(nodes); SecurityFiltersAssertions.assertEquals(nodes);
} }
@Test @Test
public void parseWhen31XsdThenAllNamedSecurityFiltersAreDefinedAndOrderedProperly() throws IOException { public void parseWhen31XsdThenAllNamedSecurityFiltersAreDefinedAndOrderedProperly() throws IOException {
List<String> expected = Arrays.asList("FIRST", "CHANNEL_FILTER", "SECURITY_CONTEXT_FILTER", // @formatter:off
"CONCURRENT_SESSION_FILTER", "LOGOUT_FILTER", "X509_FILTER", "PRE_AUTH_FILTER", "CAS_FILTER", List<String> expected = Arrays.asList("FIRST",
"FORM_LOGIN_FILTER", "OPENID_FILTER", "LOGIN_PAGE_FILTER", "DIGEST_AUTH_FILTER", "BASIC_AUTH_FILTER", "CHANNEL_FILTER",
"REQUEST_CACHE_FILTER", "SERVLET_API_SUPPORT_FILTER", "JAAS_API_SUPPORT_FILTER", "REMEMBER_ME_FILTER", "SECURITY_CONTEXT_FILTER",
"ANONYMOUS_FILTER", "SESSION_MANAGEMENT_FILTER", "EXCEPTION_TRANSLATION_FILTER", "CONCURRENT_SESSION_FILTER",
"FILTER_SECURITY_INTERCEPTOR", "SWITCH_USER_FILTER", "LAST"); "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); 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()) .filter((node) -> "simpleType".equals(node.simpleName())
&& "named-security-filter".equals(node.attribute("name"))) && "named-security-filter".equals(node.attribute("name")))
.flatMap(XmlNode::children).flatMap(XmlNode::children).map((node) -> node.attribute("value")) .flatMap(XmlNode::children)
.filter(StringUtils::isNotEmpty).collect(Collectors.toList()); .flatMap(XmlNode::children)
.map((node) -> node.attribute("value"))
.filter(StringUtils::isNotEmpty)
.collect(Collectors.toList());
// @formatter:on
assertThat(nodes).isEqualTo(expected); assertThat(nodes).isEqualTo(expected);
} }
@ -103,7 +145,11 @@ public class XsdDocumentedTests {
@Test @Test
public void sizeWhenReadingFilesystemThenIsCorrectNumberOfSchemaFiles() throws IOException { public void sizeWhenReadingFilesystemThenIsCorrectNumberOfSchemaFiles() throws IOException {
ClassPathResource resource = new ClassPathResource(this.schemaDocumentLocation); 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) assertThat(schemas.length).isEqualTo(16)
.withFailMessage("the count is equal to 16, if not then schemaDocument needs updating"); .withFailMessage("the count is equal to 16, if not then schemaDocument needs updating");
} }
@ -117,11 +163,16 @@ public class XsdDocumentedTests {
@Test @Test
public void countReferencesWhenReviewingDocumentationThenEntireSchemaIsIncluded() throws IOException { public void countReferencesWhenReviewingDocumentationThenEntireSchemaIsIncluded() throws IOException {
Map<String, Element> elementsByElementName = this.xml.elementsByElementName(this.schemaDocumentLocation); Map<String, Element> elementsByElementName = this.xml.elementsByElementName(this.schemaDocumentLocation);
// @formatter:off
List<String> documentIds = Files.lines(Paths.get(this.referenceLocation)) List<String> documentIds = Files.lines(Paths.get(this.referenceLocation))
.filter((line) -> line.matches("\\[\\[(nsa-.*)\\]\\]")) .filter((line) -> line.matches("\\[\\[(nsa-.*)\\]\\]"))
.map((line) -> line.substring(2, line.length() - 2)).collect(Collectors.toList()); .map((line) -> line.substring(2, line.length() - 2))
Set<String> expectedIds = elementsByElementName.values().stream() .collect(Collectors.toList());
.flatMap((element) -> element.getIds().stream()).collect(Collectors.toSet()); Set<String> expectedIds = elementsByElementName.values()
.stream()
.flatMap((element) -> element.getIds().stream())
.collect(Collectors.toSet());
// @formatter:on
documentIds.removeAll(this.ignoredIds); documentIds.removeAll(this.ignoredIds);
expectedIds.removeAll(this.ignoredIds); expectedIds.removeAll(this.ignoredIds);
assertThat(documentIds).containsAll(expectedIds); assertThat(documentIds).containsAll(expectedIds);
@ -172,15 +223,28 @@ public class XsdDocumentedTests {
if (this.ignoredIds.contains(key)) { if (this.ignoredIds.contains(key)) {
return; return;
} }
List<String> parentIds = entry.getValue().getAllParentElmts().values().stream() // @formatter:off
.filter((element) -> !this.ignoredIds.contains(element.getId())).map((element) -> element.getId()) List<String> parentIds = entry.getValue()
.sorted().collect(Collectors.toList()); .getAllParentElmts()
.values()
.stream()
.filter((element) -> !this.ignoredIds.contains(element.getId()))
.map((element) -> element.getId())
.sorted()
.collect(Collectors.toList());
// @formatter:on
if (!parentIds.isEmpty()) { if (!parentIds.isEmpty()) {
schemaAttrNameToParents.put(key, parentIds); 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()) .filter((element) -> !this.ignoredIds.contains(element.getId())).map((element) -> element.getId())
.sorted().collect(Collectors.toList()); .sorted()
.collect(Collectors.toList());
// @formatter:on
if (!childIds.isEmpty()) { if (!childIds.isEmpty()) {
schemaAttrNameToChildren.put(key, childIds); schemaAttrNameToChildren.put(key, childIds);
} }
@ -196,14 +260,23 @@ public class XsdDocumentedTests {
@Test @Test
public void countWhenReviewingDocumentationThenAllElementsDocumented() throws IOException { public void countWhenReviewingDocumentationThenAllElementsDocumented() throws IOException {
Map<String, Element> elementNameToElement = this.xml.elementsByElementName(this.schemaDocumentLocation); 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()) .filter((element) -> StringUtils.isEmpty(element.getDesc())
&& !this.ignoredIds.contains(element.getId())) && !this.ignoredIds.contains(element.getId()))
.map((element) -> element.getId()).sorted().collect(Collectors.joining("\n")); .map((element) -> element.getId())
String notDocAttrIds = elementNameToElement.values().stream().flatMap((element) -> element.getAttrs().stream()) .sorted()
.collect(Collectors.joining("\n"));
String notDocAttrIds = elementNameToElement.values()
.stream()
.flatMap((element) -> element.getAttrs().stream())
.filter((element) -> StringUtils.isEmpty(element.getDesc()) .filter((element) -> StringUtils.isEmpty(element.getDesc())
&& !this.ignoredIds.contains(element.getId())) && !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(notDocElmtIds).isEmpty();
assertThat(notDocAttrIds).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.MockMvc;
import org.springframework.test.web.servlet.MvcResult; import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.ResultMatcher; 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.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
@ -90,124 +91,190 @@ public class CsrfConfigTests {
@Test @Test
public void postWhenDefaultConfigurationThenForbiddenSinceCsrfIsEnabled() throws Exception { public void postWhenDefaultConfigurationThenForbiddenSinceCsrfIsEnabled() throws Exception {
this.spring.configLocations(this.xml("AutoConfig")).autowire(); 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 @Test
public void putWhenDefaultConfigurationThenForbiddenSinceCsrfIsEnabled() throws Exception { public void putWhenDefaultConfigurationThenForbiddenSinceCsrfIsEnabled() throws Exception {
this.spring.configLocations(this.xml("AutoConfig")).autowire(); 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 @Test
public void patchWhenDefaultConfigurationThenForbiddenSinceCsrfIsEnabled() throws Exception { public void patchWhenDefaultConfigurationThenForbiddenSinceCsrfIsEnabled() throws Exception {
this.spring.configLocations(this.xml("AutoConfig")).autowire(); 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 @Test
public void deleteWhenDefaultConfigurationThenForbiddenSinceCsrfIsEnabled() throws Exception { public void deleteWhenDefaultConfigurationThenForbiddenSinceCsrfIsEnabled() throws Exception {
this.spring.configLocations(this.xml("AutoConfig")).autowire(); 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 @Test
public void invalidWhenDefaultConfigurationThenForbiddenSinceCsrfIsEnabled() throws Exception { public void invalidWhenDefaultConfigurationThenForbiddenSinceCsrfIsEnabled() throws Exception {
this.spring.configLocations(this.xml("AutoConfig")).autowire(); 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()); .andExpect(csrfCreated());
// @formatter:on
} }
@Test @Test
public void getWhenDefaultConfigurationThenCsrfIsEnabled() throws Exception { public void getWhenDefaultConfigurationThenCsrfIsEnabled() throws Exception {
this.spring.configLocations(this.xml("shared-controllers"), this.xml("AutoConfig")).autowire(); 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 @Test
public void headWhenDefaultConfigurationThenCsrfIsEnabled() throws Exception { public void headWhenDefaultConfigurationThenCsrfIsEnabled() throws Exception {
this.spring.configLocations(this.xml("shared-controllers"), this.xml("AutoConfig")).autowire(); 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 @Test
public void traceWhenDefaultConfigurationThenCsrfIsEnabled() throws Exception { public void traceWhenDefaultConfigurationThenCsrfIsEnabled() throws Exception {
this.spring.configLocations(this.xml("shared-controllers"), this.xml("AutoConfig")).autowire(); 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)) .addDispatcherServletCustomizer((dispatcherServlet) -> dispatcherServlet.setDispatchTraceRequest(true))
.build(); .build();
traceEnabled.perform(request(HttpMethod.TRACE, "/csrf-in-header")).andExpect(csrfInHeader()); traceEnabled.perform(request(HttpMethod.TRACE, "/csrf-in-header"))
.andExpect(csrfInHeader());
// @formatter:on
} }
@Test @Test
public void optionsWhenDefaultConfigurationThenCsrfIsEnabled() throws Exception { public void optionsWhenDefaultConfigurationThenCsrfIsEnabled() throws Exception {
this.spring.configLocations(this.xml("shared-controllers"), this.xml("AutoConfig")).autowire(); 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 @Test
public void postWhenCsrfDisabledThenRequestAllowed() throws Exception { public void postWhenCsrfDisabledThenRequestAllowed() throws Exception {
this.spring.configLocations(this.xml("shared-controllers"), this.xml("CsrfDisabled")).autowire(); 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(); assertThat(getFilter(this.spring, CsrfFilter.class)).isNull();
} }
@Test @Test
public void postWhenCsrfElementEnabledThenForbidden() throws Exception { public void postWhenCsrfElementEnabledThenForbidden() throws Exception {
this.spring.configLocations(this.xml("CsrfEnabled")).autowire(); 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 @Test
public void putWhenCsrfElementEnabledThenForbidden() throws Exception { public void putWhenCsrfElementEnabledThenForbidden() throws Exception {
this.spring.configLocations(this.xml("CsrfEnabled")).autowire(); 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 @Test
public void patchWhenCsrfElementEnabledThenForbidden() throws Exception { public void patchWhenCsrfElementEnabledThenForbidden() throws Exception {
this.spring.configLocations(this.xml("CsrfEnabled")).autowire(); 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 @Test
public void deleteWhenCsrfElementEnabledThenForbidden() throws Exception { public void deleteWhenCsrfElementEnabledThenForbidden() throws Exception {
this.spring.configLocations(this.xml("CsrfEnabled")).autowire(); 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 @Test
public void invalidWhenCsrfElementEnabledThenForbidden() throws Exception { public void invalidWhenCsrfElementEnabledThenForbidden() throws Exception {
this.spring.configLocations(this.xml("CsrfEnabled")).autowire(); 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()); .andExpect(csrfCreated());
// @formatter:on
} }
@Test @Test
public void getWhenCsrfElementEnabledThenOk() throws Exception { public void getWhenCsrfElementEnabledThenOk() throws Exception {
this.spring.configLocations(this.xml("shared-controllers"), this.xml("CsrfEnabled")).autowire(); 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 @Test
public void headWhenCsrfElementEnabledThenOk() throws Exception { public void headWhenCsrfElementEnabledThenOk() throws Exception {
this.spring.configLocations(this.xml("shared-controllers"), this.xml("CsrfEnabled")).autowire(); 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 @Test
public void traceWhenCsrfElementEnabledThenOk() throws Exception { public void traceWhenCsrfElementEnabledThenOk() throws Exception {
this.spring.configLocations(this.xml("shared-controllers"), this.xml("CsrfEnabled")).autowire(); 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)) .addDispatcherServletCustomizer((dispatcherServlet) -> dispatcherServlet.setDispatchTraceRequest(true))
.build(); .build();
// @formatter:on
traceEnabled.perform(request(HttpMethod.TRACE, "/csrf-in-header")).andExpect(csrfInHeader()); traceEnabled.perform(request(HttpMethod.TRACE, "/csrf-in-header")).andExpect(csrfInHeader());
} }
@Test @Test
public void optionsWhenCsrfElementEnabledThenOk() throws Exception { public void optionsWhenCsrfElementEnabledThenOk() throws Exception {
this.spring.configLocations(this.xml("shared-controllers"), this.xml("CsrfEnabled")).autowire(); 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 @Test
@ -220,7 +287,10 @@ public class CsrfConfigTests {
public void postWhenUsingCsrfAndCustomAccessDeniedHandlerThenTheHandlerIsAppropriatelyEngaged() throws Exception { public void postWhenUsingCsrfAndCustomAccessDeniedHandlerThenTheHandlerIsAppropriatelyEngaged() throws Exception {
this.spring.configLocations(this.xml("WithAccessDeniedHandler"), this.xml("shared-access-denied-handler")) this.spring.configLocations(this.xml("WithAccessDeniedHandler"), this.xml("shared-access-denied-handler"))
.autowire(); .autowire();
this.mvc.perform(post("/ok")).andExpect(status().isIAmATeapot()); // @formatter:off
this.mvc.perform(post("/ok"))
.andExpect(status().isIAmATeapot());
// @formatter:on
} }
@Test @Test
@ -233,9 +303,15 @@ public class CsrfConfigTests {
MockHttpSession session = (MockHttpSession) result.getRequest().getSession(); MockHttpSession session = (MockHttpSession) result.getRequest().getSession();
// if the request cache is consulted, then it will redirect back to /some-url, // if the request cache is consulted, then it will redirect back to /some-url,
// which we don't want // which we don't want
this.mvc.perform( // @formatter:off
post("/login").param("username", "user").param("password", "password").session(session).with(csrf())) MockHttpServletRequestBuilder login = post("/login")
.param("username", "user")
.param("password", "password")
.session(session)
.with(csrf());
this.mvc.perform(login)
.andExpect(redirectedUrl("/")); .andExpect(redirectedUrl("/"));
// @formatter:on
} }
@Test @Test
@ -248,9 +324,15 @@ public class CsrfConfigTests {
MockHttpSession session = (MockHttpSession) result.getRequest().getSession(); MockHttpSession session = (MockHttpSession) result.getRequest().getSession();
// if the request cache is consulted, then it will redirect back to /some-url, // if the request cache is consulted, then it will redirect back to /some-url,
// which we do want // which we do want
this.mvc.perform( // @formatter:off
post("/login").param("username", "user").param("password", "password").session(session).with(csrf())) MockHttpServletRequestBuilder login = post("/login")
.param("username", "user")
.param("password", "password")
.session(session)
.with(csrf());
this.mvc.perform(login)
.andExpect(redirectedUrl("http://localhost/authenticated")); .andExpect(redirectedUrl("http://localhost/authenticated"));
// @formatter:on
} }
/** /**
@ -260,10 +342,16 @@ public class CsrfConfigTests {
public void postWhenUsingCsrfAndCustomSessionManagementAndNoSessionThenStillRedirectsToInvalidSessionUrl() public void postWhenUsingCsrfAndCustomSessionManagementAndNoSessionThenStillRedirectsToInvalidSessionUrl()
throws Exception { throws Exception {
this.spring.configLocations(this.xml("WithSessionManagement")).autowire(); this.spring.configLocations(this.xml("WithSessionManagement")).autowire();
MvcResult result = this.mvc.perform(post("/ok").param("_csrf", "abc")) // @formatter:off
.andExpect(redirectedUrl("/error/sessionError")).andReturn(); MockHttpServletRequestBuilder postToOk = post("/ok")
.param("_csrf", "abc");
MvcResult result = this.mvc.perform(postToOk)
.andExpect(redirectedUrl("/error/sessionError"))
.andReturn();
MockHttpSession session = (MockHttpSession) result.getRequest().getSession(); 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 @Test
@ -273,15 +361,24 @@ public class CsrfConfigTests {
context.autowire(); context.autowire();
RequestMatcher matcher = context.getContext().getBean(RequestMatcher.class); RequestMatcher matcher = context.getContext().getBean(RequestMatcher.class);
given(matcher.matches(any(HttpServletRequest.class))).willReturn(false); 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); 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 @Test
public void getWhenDefaultConfigurationThenSessionNotImmediatelyCreated() throws Exception { public void getWhenDefaultConfigurationThenSessionNotImmediatelyCreated() throws Exception {
this.spring.configLocations(this.xml("shared-controllers"), this.xml("AutoConfig")).autowire(); 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(); assertThat(result.getRequest().getSession(false)).isNull();
} }
@ -291,7 +388,13 @@ public class CsrfConfigTests {
this.spring.configLocations(this.xml("shared-controllers"), this.xml("AutoConfig")).autowire(); this.spring.configLocations(this.xml("shared-controllers"), this.xml("AutoConfig")).autowire();
MvcResult result = this.mvc.perform(get("/ok")).andReturn(); MvcResult result = this.mvc.perform(get("/ok")).andReturn();
MockHttpSession session = (MockHttpSession) result.getRequest().getSession(); 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 @Test
@ -299,10 +402,17 @@ public class CsrfConfigTests {
this.spring.configLocations(this.xml("shared-controllers"), this.xml("AutoConfig")).autowire(); this.spring.configLocations(this.xml("shared-controllers"), this.xml("AutoConfig")).autowire();
MvcResult result = this.mvc.perform(get("/csrf")).andReturn(); MvcResult result = this.mvc.perform(get("/csrf")).andReturn();
MockHttpSession session = (MockHttpSession) result.getRequest().getSession(); MockHttpSession session = (MockHttpSession) result.getRequest().getSession();
this.mvc.perform( // @formatter:off
post("/login").param("username", "user").param("password", "password").session(session).with(csrf())) MockHttpServletRequestBuilder loginRequest = post("/login")
.param("username", "user")
.param("password", "password")
.session(session)
.with(csrf());
this.mvc.perform(loginRequest)
.andExpect(status().isFound()); .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 @Test
@ -310,8 +420,12 @@ public class CsrfConfigTests {
this.spring.configLocations(this.xml("shared-controllers"), this.xml("AutoConfig")).autowire(); this.spring.configLocations(this.xml("shared-controllers"), this.xml("AutoConfig")).autowire();
MvcResult result = this.mvc.perform(get("/csrf")).andReturn(); MvcResult result = this.mvc.perform(get("/csrf")).andReturn();
MockHttpSession session = (MockHttpSession) result.getRequest().getSession(); MockHttpSession session = (MockHttpSession) result.getRequest().getSession();
this.mvc.perform(post("/logout").session(session).with(csrf())).andExpect(status().isFound()); // @formatter:off
this.mvc.perform(get("/csrf").session(session)).andExpect(csrfChanged(result)); 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 @WithMockUser
public void logoutWhenDefaultConfigurationThenDisabled() throws Exception { public void logoutWhenDefaultConfigurationThenDisabled() throws Exception {
this.spring.configLocations(this.xml("shared-controllers"), this.xml("CsrfEnabled")).autowire(); this.spring.configLocations(this.xml("shared-controllers"), this.xml("CsrfEnabled")).autowire();
this.mvc.perform(get("/logout")).andExpect(status().isOk()); // renders form to // renders form to log out but does not perform a redirect
// log out but // @formatter:off
// does not this.mvc.perform(get("/logout"))
// perform a .andExpect(status().isOk());
// redirect // @formatter:on
// still logged in // 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) { private <T extends Filter> T getFilter(SpringTestContext context, Class<T> type) {

View File

@ -60,8 +60,11 @@ public class FilterSecurityMetadataSourceBeanDefinitionParserTests {
@Test @Test
public void parsingMinimalConfigurationIsSuccessful() { public void parsingMinimalConfigurationIsSuccessful() {
// @formatter:off
setContext("<filter-security-metadata-source id='fids' use-expressions='false'>" 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 DefaultFilterInvocationSecurityMetadataSource fids = (DefaultFilterInvocationSecurityMetadataSource) this.appContext
.getBean("fids"); .getBean("fids");
Collection<ConfigAttribute> cad = fids.getAttributes(createFilterInvocation("/anything", "GET")); Collection<ConfigAttribute> cad = fids.getAttributes(createFilterInvocation("/anything", "GET"));
@ -70,9 +73,11 @@ public class FilterSecurityMetadataSourceBeanDefinitionParserTests {
@Test @Test
public void expressionsAreSupported() { public void expressionsAreSupported() {
// @formatter:off
setContext("<filter-security-metadata-source id='fids'>" setContext("<filter-security-metadata-source id='fids'>"
+ " <intercept-url pattern='/**' access=\"hasRole('ROLE_A')\" />" + " <intercept-url pattern='/**' access=\"hasRole('ROLE_A')\" />"
+ "</filter-security-metadata-source>"); + "</filter-security-metadata-source>");
// @formatter:on
ExpressionBasedFilterInvocationSecurityMetadataSource fids = (ExpressionBasedFilterInvocationSecurityMetadataSource) this.appContext ExpressionBasedFilterInvocationSecurityMetadataSource fids = (ExpressionBasedFilterInvocationSecurityMetadataSource) this.appContext
.getBean("fids"); .getBean("fids");
ConfigAttribute[] cad = fids.getAttributes(createFilterInvocation("/anything", "GET")) ConfigAttribute[] cad = fids.getAttributes(createFilterInvocation("/anything", "GET"))
@ -98,6 +103,7 @@ public class FilterSecurityMetadataSourceBeanDefinitionParserTests {
@Test @Test
public void parsingWithinFilterSecurityInterceptorIsSuccessful() { public void parsingWithinFilterSecurityInterceptorIsSuccessful() {
// @formatter:off
setContext("<http auto-config='true' use-expressions='false'/>" setContext("<http auto-config='true' use-expressions='false'/>"
+ "<b:bean id='fsi' class='org.springframework.security.web.access.intercept.FilterSecurityInterceptor' autowire='byType'>" + "<b:bean id='fsi' class='org.springframework.security.web.access.intercept.FilterSecurityInterceptor' autowire='byType'>"
+ " <b:property name='securityMetadataSource'>" + " <b:property name='securityMetadataSource'>"
@ -105,9 +111,12 @@ public class FilterSecurityMetadataSourceBeanDefinitionParserTests {
+ " <intercept-url pattern='/secure/extreme/**' access='ROLE_SUPERVISOR'/>" + " <intercept-url pattern='/secure/extreme/**' access='ROLE_SUPERVISOR'/>"
+ " <intercept-url pattern='/secure/**' access='ROLE_USER'/>" + " <intercept-url pattern='/secure/**' access='ROLE_USER'/>"
+ " <intercept-url pattern='/**' 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: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) @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.config.test.SpringTestRule;
import org.springframework.security.web.WebAttributes; import org.springframework.security.web.WebAttributes;
import org.springframework.test.web.servlet.MockMvc; 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.containsString;
import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.CoreMatchers.not;
@ -51,24 +52,35 @@ public class FormLoginBeanDefinitionParserTests {
@Test @Test
public void getLoginWhenAutoConfigThenShowsDefaultLoginPage() throws Exception { public void getLoginWhenAutoConfigThenShowsDefaultLoginPage() throws Exception {
this.spring.configLocations(this.xml("Simple")).autowire(); 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 charset=\"utf-8\">\n"
+ " <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\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" + " <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://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" + " <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" + " <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" + " <label for=\"username\" class=\"sr-only\">Username</label>\n"
+ " <input type=\"text\" id=\"username\" name=\"username\" class=\"form-control\" placeholder=\"Username\" required autofocus>\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" + " <label for=\"password\" class=\"sr-only\">Password</label>\n"
+ " <input type=\"password\" id=\"password\" name=\"password\" class=\"form-control\" placeholder=\"Password\" required>\n" + " <input type=\"password\" id=\"password\" name=\"password\" class=\"form-control\" placeholder=\"Password\" required>\n"
+ " </p>\n" + " </p>\n"
+ " <button class=\"btn btn-lg btn-primary btn-block\" type=\"submit\">Sign in</button>\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)); this.mvc.perform(get("/login")).andExpect(content().string(expectedContent));
} }
@ -81,75 +93,108 @@ public class FormLoginBeanDefinitionParserTests {
@Test @Test
public void getLoginWhenConfiguredWithCustomAttributesThenLoginPageReflects() throws Exception { public void getLoginWhenConfiguredWithCustomAttributesThenLoginPageReflects() throws Exception {
this.spring.configLocations(this.xml("WithCustomAttributes")).autowire(); 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 charset=\"utf-8\">\n"
+ " <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\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" + " <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://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" + " <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" + " <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" + " <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" + " <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" + " <label for=\"password\" class=\"sr-only\">Password</label>\n"
+ " <input type=\"password\" id=\"password\" name=\"custom_pass\" class=\"form-control\" placeholder=\"Password\" required>\n" + " <input type=\"password\" id=\"password\" name=\"custom_pass\" class=\"form-control\" placeholder=\"Password\" required>\n"
+ " </p>\n" + " </p>\n"
+ " <button class=\"btn btn-lg btn-primary btn-block\" type=\"submit\">Sign in</button>\n" + " <button class=\"btn btn-lg btn-primary btn-block\" type=\"submit\">Sign in</button>\n"
+ " </form>\n" + "</div>\n" + "</body></html>"; + " </form>\n"
this.mvc.perform(get("/login")).andExpect(content().string(expectedContent)); + "</div>\n"
this.mvc.perform(get("/logout")).andExpect(status().is3xxRedirection()); + "</body></html>";
this.mvc.perform(get("/login"))
.andExpect(content().string(expectedContent));
this.mvc.perform(get("/logout"))
.andExpect(status().is3xxRedirection());
// @formatter:on
} }
@Test @Test
public void getLoginWhenConfiguredForOpenIdThenLoginPageReflects() throws Exception { public void getLoginWhenConfiguredForOpenIdThenLoginPageReflects() throws Exception {
this.spring.configLocations(this.xml("WithOpenId")).autowire(); 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 charset=\"utf-8\">\n"
+ " <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\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" + " <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://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" + " <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" + " <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" + " <label for=\"username\" class=\"sr-only\">Username</label>\n"
+ " <input type=\"text\" id=\"username\" name=\"username\" class=\"form-control\" placeholder=\"Username\" required autofocus>\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" + " <label for=\"password\" class=\"sr-only\">Password</label>\n"
+ " <input type=\"password\" id=\"password\" name=\"password\" class=\"form-control\" placeholder=\"Password\" required>\n" + " <input type=\"password\" id=\"password\" name=\"password\" class=\"form-control\" placeholder=\"Password\" required>\n"
+ " </p>\n" + " </p>\n"
+ " <button class=\"btn btn-lg btn-primary btn-block\" type=\"submit\">Sign in</button>\n" + " <button class=\"btn btn-lg btn-primary btn-block\" type=\"submit\">Sign in</button>\n"
+ " </form>\n" + " </form>\n"
+ " <form name=\"oidf\" class=\"form-signin\" method=\"post\" action=\"/login/openid\">\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" + " <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" + " <input type=\"text\" id=\"username\" name=\"openid_identifier\" class=\"form-control\" placeholder=\"Username\" required autofocus>\n"
+ " </p>\n" + " </p>\n"
+ " <button class=\"btn btn-lg btn-primary btn-block\" type=\"submit\">Sign in</button>\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)); this.mvc.perform(get("/login")).andExpect(content().string(expectedContent));
} }
@Test @Test
public void getLoginWhenConfiguredForOpenIdWithCustomAttributesThenLoginPageReflects() throws Exception { public void getLoginWhenConfiguredForOpenIdWithCustomAttributesThenLoginPageReflects() throws Exception {
this.spring.configLocations(this.xml("WithOpenIdCustomAttributes")).autowire(); 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 charset=\"utf-8\">\n"
+ " <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\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" + " <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://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" + " <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" + " <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" + " <label for=\"username\" class=\"sr-only\">Username</label>\n"
+ " <input type=\"text\" id=\"username\" name=\"username\" class=\"form-control\" placeholder=\"Username\" required autofocus>\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" + " <label for=\"password\" class=\"sr-only\">Password</label>\n"
+ " <input type=\"password\" id=\"password\" name=\"password\" class=\"form-control\" placeholder=\"Password\" required>\n" + " <input type=\"password\" id=\"password\" name=\"password\" class=\"form-control\" placeholder=\"Password\" required>\n"
+ " </p>\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" + " <input type=\"text\" id=\"username\" name=\"openid_identifier\" class=\"form-control\" placeholder=\"Username\" required autofocus>\n"
+ " </p>\n" + " </p>\n"
+ " <button class=\"btn btn-lg btn-primary btn-block\" type=\"submit\">Sign in</button>\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)); this.mvc.perform(get("/login")).andExpect(content().string(expectedContent));
} }
@Test @Test
public void failedLoginWhenConfiguredWithCustomAuthenticationFailureThenForwardsAccordingly() throws Exception { public void failedLoginWhenConfiguredWithCustomAuthenticationFailureThenForwardsAccordingly() throws Exception {
this.spring.configLocations(this.xml("WithAuthenticationFailureForwardUrl")).autowire(); this.spring.configLocations(this.xml("WithAuthenticationFailureForwardUrl")).autowire();
this.mvc.perform(post("/login").param("username", "bob").param("password", "invalidpassword")) // @formatter:off
.andExpect(status().isOk()).andExpect(forwardedUrl("/failure_forward_url")) 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()))); .andExpect(request().attribute(WebAttributes.AUTHENTICATION_EXCEPTION, not(nullValue())));
// @formatter:on
} }
@Test @Test
public void successfulLoginWhenConfiguredWithCustomAuthenticationSuccessThenForwardsAccordingly() throws Exception { public void successfulLoginWhenConfiguredWithCustomAuthenticationSuccessThenForwardsAccordingly() throws Exception {
this.spring.configLocations(this.xml("WithAuthenticationSuccessForwardUrl")).autowire(); this.spring.configLocations(this.xml("WithAuthenticationSuccessForwardUrl")).autowire();
this.mvc.perform(post("/login").param("username", "user").param("password", "password")) // @formatter:off
.andExpect(status().isOk()).andExpect(forwardedUrl("/success_forward_url")); 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) { 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.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter; import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;
import org.springframework.test.web.servlet.MockMvc; 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.GetMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
@ -67,24 +68,44 @@ public class FormLoginConfigTests {
@Test @Test
public void getProtectedPageWhenFormLoginConfiguredThenRedirectsToDefaultLoginPage() throws Exception { public void getProtectedPageWhenFormLoginConfiguredThenRedirectsToDefaultLoginPage() throws Exception {
this.spring.configLocations(this.xml("WithAntRequestMatcher")).autowire(); 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 @Test
public void authenticateWhenDefaultTargetUrlConfiguredThenRedirectsAccordingly() throws Exception { public void authenticateWhenDefaultTargetUrlConfiguredThenRedirectsAccordingly() throws Exception {
this.spring.configLocations(this.xml("WithDefaultTargetUrl")).autowire(); 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")); .andExpect(redirectedUrl("/default"));
// @formatter:on
} }
@Test @Test
public void authenticateWhenConfiguredWithSpelThenRedirectsAccordingly() throws Exception { public void authenticateWhenConfiguredWithSpelThenRedirectsAccordingly() throws Exception {
this.spring.configLocations(this.xml("UsingSpel")).autowire(); 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")); .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")); .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 @Test
@ -102,10 +123,20 @@ public class FormLoginConfigTests {
@Test @Test
public void authenticateWhenCustomHandlerBeansConfiguredThenInvokesAccordingly() throws Exception { public void authenticateWhenCustomHandlerBeansConfiguredThenInvokesAccordingly() throws Exception {
this.spring.configLocations(this.xml("WithSuccessAndFailureHandlers")).autowire(); 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()); .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()); .andExpect(status().isIAmATeapot());
// @formatter:on
} }
@Test @Test
@ -129,15 +160,25 @@ public class FormLoginConfigTests {
@Test @Test
public void authenticateWhenCsrfIsEnabledThenRequiresToken() throws Exception { public void authenticateWhenCsrfIsEnabledThenRequiresToken() throws Exception {
this.spring.configLocations(this.xml("WithCsrfEnabled")).autowire(); 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()); .andExpect(status().isForbidden());
// @formatter:on
} }
@Test @Test
public void authenticateWhenCsrfIsDisabledThenDoesNotRequireToken() throws Exception { public void authenticateWhenCsrfIsDisabledThenDoesNotRequireToken() throws Exception {
this.spring.configLocations(this.xml("WithCsrfDisabled")).autowire(); 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()); .andExpect(status().isFound());
// @formatter:on
} }
/** /**
@ -148,8 +189,14 @@ public class FormLoginConfigTests {
public void authenticateWhenLoginPageIsSlashLoginAndAuthenticationFailsThenRedirectContainsErrorParameter() public void authenticateWhenLoginPageIsSlashLoginAndAuthenticationFailsThenRedirectContainsErrorParameter()
throws Exception { throws Exception {
this.spring.configLocations(this.xml("ForSec3147")).autowire(); 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")); .andExpect(redirectedUrl("/login?error"));
// @formatter:on
} }
private Filter getFilter(ApplicationContext context, Class<? extends Filter> filterClass) { private Filter getFilter(ApplicationContext context, Class<? extends Filter> filterClass) {

View File

@ -52,7 +52,11 @@ public class HttpConfigTests {
@Test @Test
public void getWhenUsingMinimalConfigurationThenRedirectsToLogin() throws Exception { public void getWhenUsingMinimalConfigurationThenRedirectsToLogin() throws Exception {
this.spring.configLocations(this.xml("Minimal")).autowire(); 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 @Test

View File

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

View File

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

View File

@ -48,9 +48,14 @@ public class HttpInterceptUrlTests {
@Test @Test
public void interceptUrlWhenRequestMatcherRefThenWorks() throws Exception { public void interceptUrlWhenRequestMatcherRefThenWorks() throws Exception {
loadConfig("interceptUrlWhenRequestMatcherRefThenWorks.xml"); loadConfig("interceptUrlWhenRequestMatcherRefThenWorks.xml");
this.mockMvc.perform(get("/foo")).andExpect(status().isUnauthorized()); // @formatter:off
this.mockMvc.perform(get("/FOO")).andExpect(status().isUnauthorized()); this.mockMvc.perform(get("/foo"))
this.mockMvc.perform(get("/other")).andExpect(status().isOk()); .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) { 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.mock.web.MockServletContext;
import org.springframework.security.config.test.SpringTestRule; import org.springframework.security.config.test.SpringTestRule;
import org.springframework.test.web.servlet.MockMvc; 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.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
@ -65,8 +66,12 @@ public class InterceptUrlConfigTests {
@Test @Test
public void requestWhenMethodIsSpecifiedThenItIsNotGivenPriority() throws Exception { public void requestWhenMethodIsSpecifiedThenItIsNotGivenPriority() throws Exception {
this.spring.configLocations(this.xml("Sec2256")).autowire(); this.spring.configLocations(this.xml("Sec2256")).autowire();
this.mvc.perform(post("/path").with(httpBasic("user", "password"))).andExpect(status().isOk()); // @formatter:off
this.mvc.perform(get("/path").with(httpBasic("user", "password"))).andExpect(status().isOk()); 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 @Test
public void requestWhenUsingPatchThenAuthorizesRequestsAccordingly() throws Exception { public void requestWhenUsingPatchThenAuthorizesRequestsAccordingly() throws Exception {
this.spring.configLocations(this.xml("PatchMethod")).autowire(); this.spring.configLocations(this.xml("PatchMethod")).autowire();
this.mvc.perform(get("/path").with(httpBasic("user", "password"))).andExpect(status().isOk()); // @formatter:off
this.mvc.perform(patch("/path").with(httpBasic("user", "password"))).andExpect(status().isForbidden()); this.mvc.perform(get("/path").with(userCredentials()))
this.mvc.perform(patch("/path").with(httpBasic("admin", "password"))).andExpect(status().isOk()); .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 @Test
public void requestWhenUsingHasAnyRoleThenAuthorizesRequestsAccordingly() throws Exception { public void requestWhenUsingHasAnyRoleThenAuthorizesRequestsAccordingly() throws Exception {
this.spring.configLocations(this.xml("HasAnyRole")).autowire(); this.spring.configLocations(this.xml("HasAnyRole")).autowire();
this.mvc.perform(get("/path").with(httpBasic("user", "password"))).andExpect(status().isOk()); // @formatter:off
this.mvc.perform(get("/path").with(httpBasic("admin", "password"))).andExpect(status().isForbidden()); 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 @Test
public void requestWhenUsingPathVariablesThenAuthorizesRequestsAccordingly() throws Exception { public void requestWhenUsingPathVariablesThenAuthorizesRequestsAccordingly() throws Exception {
this.spring.configLocations(this.xml("PathVariables")).autowire(); this.spring.configLocations(this.xml("PathVariables")).autowire();
this.mvc.perform(get("/path/user/path").with(httpBasic("user", "password"))).andExpect(status().isOk()); // @formatter:off
this.mvc.perform(get("/path/otheruser/path").with(httpBasic("user", "password"))) this.mvc.perform(get("/path/user/path").with(userCredentials()))
.andExpect(status().isOk());
this.mvc.perform(get("/path/otheruser/path").with(userCredentials()))
.andExpect(status().isForbidden()); .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 @Test
public void requestWhenUsingCamelCasePathVariablesThenAuthorizesRequestsAccordingly() throws Exception { public void requestWhenUsingCamelCasePathVariablesThenAuthorizesRequestsAccordingly() throws Exception {
this.spring.configLocations(this.xml("CamelCasePathVariables")).autowire(); this.spring.configLocations(this.xml("CamelCasePathVariables")).autowire();
this.mvc.perform(get("/path/user/path").with(httpBasic("user", "password"))).andExpect(status().isOk()); // @formatter:off
this.mvc.perform(get("/path/otheruser/path").with(httpBasic("user", "password"))) this.mvc.perform(get("/path/user/path").with(userCredentials()))
.andExpect(status().isOk());
this.mvc.perform(get("/path/otheruser/path").with(userCredentials()))
.andExpect(status().isForbidden()); .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 @Test
public void requestWhenUsingPathVariablesAndTypeConversionThenAuthorizesRequestsAccordingly() throws Exception { public void requestWhenUsingPathVariablesAndTypeConversionThenAuthorizesRequestsAccordingly() throws Exception {
this.spring.configLocations(this.xml("TypeConversionPathVariables")).autowire(); this.spring.configLocations(this.xml("TypeConversionPathVariables")).autowire();
this.mvc.perform(get("/path/1/path").with(httpBasic("user", "password"))).andExpect(status().isOk()); // @formatter:off
this.mvc.perform(get("/path/2/path").with(httpBasic("user", "password"))).andExpect(status().isForbidden()); 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 @Test
public void requestWhenUsingMvcMatchersThenAuthorizesRequestsAccordingly() throws Exception { public void requestWhenUsingMvcMatchersThenAuthorizesRequestsAccordingly() throws Exception {
this.spring.configLocations(this.xml("MvcMatchers")).autowire(); this.spring.configLocations(this.xml("MvcMatchers")).autowire();
this.mvc.perform(get("/path")).andExpect(status().isUnauthorized()); this.mvc.perform(get("/path"))
this.mvc.perform(get("/path.html")).andExpect(status().isUnauthorized()); .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 @Test
public void requestWhenUsingMvcMatchersAndPathVariablesThenAuthorizesRequestsAccordingly() throws Exception { public void requestWhenUsingMvcMatchersAndPathVariablesThenAuthorizesRequestsAccordingly() throws Exception {
this.spring.configLocations(this.xml("MvcMatchersPathVariables")).autowire(); this.spring.configLocations(this.xml("MvcMatchersPathVariables")).autowire();
this.mvc.perform(get("/path/user/path").with(httpBasic("user", "password"))).andExpect(status().isOk()); // @formatter:off
this.mvc.perform(get("/path/otheruser/path").with(httpBasic("user", "password"))) this.mvc.perform(get("/path/user/path").with(userCredentials()))
.andExpect(status().isOk());
this.mvc.perform(get("/path/otheruser/path").with(userCredentials()))
.andExpect(status().isForbidden()); .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 @Test
@ -144,9 +177,14 @@ public class InterceptUrlConfigTests {
MockServletContext servletContext = mockServletContext("/spring"); MockServletContext servletContext = mockServletContext("/spring");
ConfigurableWebApplicationContext context = this.spring.getContext(); ConfigurableWebApplicationContext context = this.spring.getContext();
context.setServletContext(servletContext); context.setServletContext(servletContext);
this.mvc.perform(get("/spring/path").servletPath("/spring")).andExpect(status().isUnauthorized()); // @formatter:off
this.mvc.perform(get("/spring/path.html").servletPath("/spring")).andExpect(status().isUnauthorized()); this.mvc.perform(get("/spring/path").servletPath("/spring"))
this.mvc.perform(get("/spring/path/").servletPath("/spring")).andExpect(status().isUnauthorized()); .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 @Test
@ -173,6 +211,14 @@ public class InterceptUrlConfigTests {
.isThrownBy(() -> this.spring.configLocations(this.xml("DefaultMatcherServletPath")).autowire()); .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) { private MockServletContext mockServletContext(String servletPath) {
MockServletContext servletContext = spy(new MockServletContext()); MockServletContext servletContext = spy(new MockServletContext());
final ServletRegistration registration = mock(ServletRegistration.class); 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 ch.qos.logback.core.Appender;
import org.apache.http.HttpStatus; import org.apache.http.HttpStatus;
import org.assertj.core.api.iterable.Extractor; import org.assertj.core.api.iterable.Extractor;
import org.jetbrains.annotations.NotNull;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.mockito.stubbing.Answer; 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.util.ReflectionTestUtils;
import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult; 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.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
@ -162,29 +165,45 @@ public class MiscHttpConfigTests {
@Test @Test
public void requestWhenUsingDebugFilterAndPatternIsNotConfigureForSecurityThenRespondsOk() throws Exception { public void requestWhenUsingDebugFilterAndPatternIsNotConfigureForSecurityThenRespondsOk() throws Exception {
this.spring.configLocations(xml("NoSecurityForPattern")).autowire(); this.spring.configLocations(xml("NoSecurityForPattern")).autowire();
this.mvc.perform(get("/unprotected")).andExpect(status().isNotFound()); // @formatter:off
this.mvc.perform(get("/nomatch")).andExpect(status().isNotFound()); this.mvc.perform(get("/unprotected"))
.andExpect(status().isNotFound());
this.mvc.perform(get("/nomatch"))
.andExpect(status().isNotFound());
// @formatter:on
} }
@Test @Test
public void requestWhenHttpPatternUsesRegexMatchingThenMatchesAccordingly() throws Exception { public void requestWhenHttpPatternUsesRegexMatchingThenMatchesAccordingly() throws Exception {
this.spring.configLocations(xml("RegexSecurityPattern")).autowire(); this.spring.configLocations(xml("RegexSecurityPattern")).autowire();
this.mvc.perform(get("/protected")).andExpect(status().isUnauthorized()); // @formatter:off
this.mvc.perform(get("/unprotected")).andExpect(status().isNotFound()); this.mvc.perform(get("/protected"))
.andExpect(status().isUnauthorized());
this.mvc.perform(get("/unprotected"))
.andExpect(status().isNotFound());
// @formatter:on
} }
@Test @Test
public void requestWhenHttpPatternUsesCiRegexMatchingThenMatchesAccordingly() throws Exception { public void requestWhenHttpPatternUsesCiRegexMatchingThenMatchesAccordingly() throws Exception {
this.spring.configLocations(xml("CiRegexSecurityPattern")).autowire(); this.spring.configLocations(xml("CiRegexSecurityPattern")).autowire();
this.mvc.perform(get("/ProTectEd")).andExpect(status().isUnauthorized()); // @formatter:off
this.mvc.perform(get("/UnProTectEd")).andExpect(status().isNotFound()); this.mvc.perform(get("/ProTectEd"))
.andExpect(status().isUnauthorized());
this.mvc.perform(get("/UnProTectEd"))
.andExpect(status().isNotFound());
// @formatter:on
} }
@Test @Test
public void requestWhenHttpPatternUsesCustomRequestMatcherThenMatchesAccordingly() throws Exception { public void requestWhenHttpPatternUsesCustomRequestMatcherThenMatchesAccordingly() throws Exception {
this.spring.configLocations(xml("CustomRequestMatcher")).autowire(); this.spring.configLocations(xml("CustomRequestMatcher")).autowire();
this.mvc.perform(get("/protected")).andExpect(status().isUnauthorized()); // @formatter:off
this.mvc.perform(get("/unprotected")).andExpect(status().isNotFound()); 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 @Test
public void requestWhenUsingMinimalConfigurationThenHonorsAnonymousEndpoints() throws Exception { public void requestWhenUsingMinimalConfigurationThenHonorsAnonymousEndpoints() throws Exception {
this.spring.configLocations(xml("AnonymousEndpoints")).autowire(); this.spring.configLocations(xml("AnonymousEndpoints")).autowire();
this.mvc.perform(get("/protected")).andExpect(status().isUnauthorized()); // @formatter:off
this.mvc.perform(get("/unprotected")).andExpect(status().isNotFound()); this.mvc.perform(get("/protected"))
.andExpect(status().isUnauthorized());
this.mvc.perform(get("/unprotected"))
.andExpect(status().isNotFound());
// @formatter:on
assertThat(getFilter(AnonymousAuthenticationFilter.class)).isNotNull(); assertThat(getFilter(AnonymousAuthenticationFilter.class)).isNotNull();
} }
@Test @Test
public void requestWhenAnonymousIsDisabledThenRejectsAnonymousEndpoints() throws Exception { public void requestWhenAnonymousIsDisabledThenRejectsAnonymousEndpoints() throws Exception {
this.spring.configLocations(xml("AnonymousDisabled")).autowire(); this.spring.configLocations(xml("AnonymousDisabled")).autowire();
this.mvc.perform(get("/protected")).andExpect(status().isUnauthorized()); // @formatter:off
this.mvc.perform(get("/unprotected")).andExpect(status().isUnauthorized()); this.mvc.perform(get("/protected"))
.andExpect(status().isUnauthorized());
this.mvc.perform(get("/unprotected"))
.andExpect(status().isUnauthorized());
// @formatter:on
assertThat(getFilter(AnonymousAuthenticationFilter.class)).isNull(); assertThat(getFilter(AnonymousAuthenticationFilter.class)).isNull();
} }
@Test @Test
public void requestWhenAnonymousUsesCustomAttributesThenRespondsWithThoseAttributes() throws Exception { public void requestWhenAnonymousUsesCustomAttributesThenRespondsWithThoseAttributes() throws Exception {
this.spring.configLocations(xml("AnonymousCustomAttributes")).autowire(); this.spring.configLocations(xml("AnonymousCustomAttributes")).autowire();
this.mvc.perform(get("/protected").with(httpBasic("user", "password"))).andExpect(status().isForbidden()); // @formatter:off
this.mvc.perform(get("/protected")).andExpect(status().isOk()).andExpect(content().string("josh")); this.mvc.perform(get("/protected").with(userCredentials()))
this.mvc.perform(get("/customKey")).andExpect(status().isOk()) .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()))); .andExpect(content().string(String.valueOf("myCustomKey".hashCode())));
// @formatter:on
} }
@Test @Test
public void requestWhenAnonymousUsesMultipleGrantedAuthoritiesThenRespondsWithThoseAttributes() throws Exception { public void requestWhenAnonymousUsesMultipleGrantedAuthoritiesThenRespondsWithThoseAttributes() throws Exception {
this.spring.configLocations(xml("AnonymousMultipleAuthorities")).autowire(); this.spring.configLocations(xml("AnonymousMultipleAuthorities")).autowire();
this.mvc.perform(get("/protected").with(httpBasic("user", "password"))).andExpect(status().isForbidden()); // @formatter:off
this.mvc.perform(get("/protected")).andExpect(status().isOk()).andExpect(content().string("josh")); this.mvc.perform(get("/protected").with(userCredentials()))
this.mvc.perform(get("/customKey")).andExpect(status().isOk()) .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()))); .andExpect(content().string(String.valueOf("myCustomKey".hashCode())));
// @formatter:on
} }
@Test @Test
public void requestWhenInterceptUrlMatchesMethodThenSecuresAccordingly() throws Exception { public void requestWhenInterceptUrlMatchesMethodThenSecuresAccordingly() throws Exception {
this.spring.configLocations(xml("InterceptUrlMethod")).autowire(); this.spring.configLocations(xml("InterceptUrlMethod")).autowire();
this.mvc.perform(get("/protected").with(httpBasic("user", "password"))).andExpect(status().isOk()); // @formatter:off
this.mvc.perform(post("/protected").with(httpBasic("user", "password"))).andExpect(status().isForbidden()); this.mvc.perform(get("/protected").with(userCredentials()))
this.mvc.perform(post("/protected").with(httpBasic("poster", "password"))).andExpect(status().isOk()); .andExpect(status().isOk());
this.mvc.perform(delete("/protected").with(httpBasic("poster", "password"))).andExpect(status().isForbidden()); this.mvc.perform(post("/protected").with(userCredentials()))
this.mvc.perform(delete("/protected").with(httpBasic("admin", "password"))).andExpect(status().isOk()); .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 @Test
public void requestWhenInterceptUrlMatchesMethodAndRequiresHttpsThenSecuresAccordingly() throws Exception { public void requestWhenInterceptUrlMatchesMethodAndRequiresHttpsThenSecuresAccordingly() throws Exception {
this.spring.configLocations(xml("InterceptUrlMethodRequiresHttps")).autowire(); this.spring.configLocations(xml("InterceptUrlMethodRequiresHttps")).autowire();
this.mvc.perform(post("/protected").with(csrf())).andExpect(status().isOk()); // @formatter:off
this.mvc.perform(get("/protected").secure(true).with(httpBasic("user", "password"))) this.mvc.perform(post("/protected").with(csrf()))
.andExpect(status().isForbidden());
this.mvc.perform(get("/protected").secure(true).with(httpBasic("admin", "password")))
.andExpect(status().isOk()); .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 @Test
public void requestWhenInterceptUrlMatchesAnyPatternAndRequiresHttpsThenSecuresAccordingly() throws Exception { public void requestWhenInterceptUrlMatchesAnyPatternAndRequiresHttpsThenSecuresAccordingly() throws Exception {
this.spring.configLocations(xml("InterceptUrlMethodRequiresHttpsAny")).autowire(); this.spring.configLocations(xml("InterceptUrlMethodRequiresHttpsAny")).autowire();
this.mvc.perform(post("/protected").with(csrf())).andExpect(status().isOk()); // @formatter:off
this.mvc.perform(get("/protected").secure(true).with(httpBasic("user", "password"))) this.mvc.perform(post("/protected").with(csrf()))
.andExpect(status().isForbidden());
this.mvc.perform(get("/protected").secure(true).with(httpBasic("admin", "password")))
.andExpect(status().isOk()); .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 @Test
@ -265,7 +317,10 @@ public class MiscHttpConfigTests {
public void requestWhenCustomHttpBasicEntryPointRefThenInvokesOnCommence() throws Exception { public void requestWhenCustomHttpBasicEntryPointRefThenInvokesOnCommence() throws Exception {
this.spring.configLocations(xml("CustomHttpBasicEntryPointRef")).autowire(); this.spring.configLocations(xml("CustomHttpBasicEntryPointRef")).autowire();
AuthenticationEntryPoint entryPoint = this.spring.getContext().getBean(AuthenticationEntryPoint.class); 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), verify(entryPoint).commence(any(HttpServletRequest.class), any(HttpServletResponse.class),
any(AuthenticationException.class)); any(AuthenticationException.class));
} }
@ -279,8 +334,10 @@ public class MiscHttpConfigTests {
@Test @Test
public void getWhenPortsMappedThenRedirectedAccordingly() throws Exception { public void getWhenPortsMappedThenRedirectedAccordingly() throws Exception {
this.spring.configLocations(xml("PortsMappedInterceptUrlMethodRequiresAny")).autowire(); this.spring.configLocations(xml("PortsMappedInterceptUrlMethodRequiresAny")).autowire();
// @formatter:off
this.mvc.perform(get("http://localhost:9080/protected")) this.mvc.perform(get("http://localhost:9080/protected"))
.andExpect(redirectedUrl("https://localhost:9443/protected")); .andExpect(redirectedUrl("https://localhost:9443/protected"));
// @formatter:on
} }
@Test @Test
@ -312,9 +369,11 @@ public class MiscHttpConfigTests {
public void getWhenUsingX509AndPropertyPlaceholderThenSubjectPrincipalRegexIsConfigured() throws Exception { public void getWhenUsingX509AndPropertyPlaceholderThenSubjectPrincipalRegexIsConfigured() throws Exception {
System.setProperty("subject_principal_regex", "OU=(.*?)(?:,|$)"); System.setProperty("subject_principal_regex", "OU=(.*?)(?:,|$)");
this.spring.configLocations(xml("X509")).autowire(); this.spring.configLocations(xml("X509")).autowire();
this.mvc.perform(get("/protected") RequestPostProcessor x509 = x509("classpath:org/springframework/security/config/http/MiscHttpConfigTests-certificate.pem");
.with(x509("classpath:org/springframework/security/config/http/MiscHttpConfigTests-certificate.pem"))) // @formatter:off
this.mvc.perform(get("/protected").with(x509))
.andExpect(status().isOk()); .andExpect(status().isOk());
// @formatter:on
} }
@Test @Test
@ -335,7 +394,10 @@ public class MiscHttpConfigTests {
@Test @Test
public void logoutWhenSpecifyingSuccessHandlerRefThenResponseHandledAccordingly() throws Exception { public void logoutWhenSpecifyingSuccessHandlerRefThenResponseHandledAccordingly() throws Exception {
this.spring.configLocations(xml("LogoutSuccessHandlerRef")).autowire(); 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 @Test
@ -374,8 +436,12 @@ public class MiscHttpConfigTests {
@Test @Test
public void getWhenUsingTwoIdenticalInterceptUrlsThenTheSecondTakesPrecedence() throws Exception { public void getWhenUsingTwoIdenticalInterceptUrlsThenTheSecondTakesPrecedence() throws Exception {
this.spring.configLocations(xml("Sec934")).autowire(); this.spring.configLocations(xml("Sec934")).autowire();
this.mvc.perform(get("/protected").with(httpBasic("user", "password"))).andExpect(status().isOk()); // @formatter:off
this.mvc.perform(get("/protected").with(httpBasic("admin", "password"))).andExpect(status().isForbidden()); this.mvc.perform(get("/protected").with(userCredentials()))
.andExpect(status().isOk());
this.mvc.perform(get("/protected").with(adminCredentials()))
.andExpect(status().isForbidden());
// @formatter:on
} }
@Test @Test
@ -384,8 +450,11 @@ public class MiscHttpConfigTests {
SecurityContextRepository repository = this.spring.getContext().getBean(SecurityContextRepository.class); SecurityContextRepository repository = this.spring.getContext().getBean(SecurityContextRepository.class);
SecurityContext context = new SecurityContextImpl(new TestingAuthenticationToken("user", "password")); SecurityContext context = new SecurityContextImpl(new TestingAuthenticationToken("user", "password"));
given(repository.loadContext(any(HttpRequestResponseHolder.class))).willReturn(context); given(repository.loadContext(any(HttpRequestResponseHolder.class))).willReturn(context);
MvcResult result = this.mvc.perform(get("/protected").with(httpBasic("user", "password"))) // @formatter:off
.andExpect(status().isOk()).andReturn(); MvcResult result = this.mvc.perform(get("/protected").with(userCredentials()))
.andExpect(status().isOk())
.andReturn();
// @formatter:on
assertThat(result.getRequest().getSession(false)).isNotNull(); assertThat(result.getRequest().getSession(false)).isNotNull();
verify(repository, atLeastOnce()).saveContext(any(SecurityContext.class), any(HttpServletRequest.class), verify(repository, atLeastOnce()).saveContext(any(SecurityContext.class), any(HttpServletRequest.class),
any(HttpServletResponse.class)); any(HttpServletResponse.class));
@ -394,9 +463,14 @@ public class MiscHttpConfigTests {
@Test @Test
public void getWhenUsingInterceptUrlExpressionsThenAuthorizesAccordingly() throws Exception { public void getWhenUsingInterceptUrlExpressionsThenAuthorizesAccordingly() throws Exception {
this.spring.configLocations(xml("InterceptUrlExpressions")).autowire(); this.spring.configLocations(xml("InterceptUrlExpressions")).autowire();
this.mvc.perform(get("/protected").with(httpBasic("admin", "password"))).andExpect(status().isOk()); // @formatter:off
this.mvc.perform(get("/protected").with(httpBasic("user", "password"))).andExpect(status().isForbidden()); this.mvc.perform(get("/protected").with(adminCredentials()))
this.mvc.perform(get("/unprotected").with(httpBasic("user", "password"))).andExpect(status().isOk()); .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 @Test
@ -405,7 +479,10 @@ public class MiscHttpConfigTests {
PermissionEvaluator permissionEvaluator = this.spring.getContext().getBean(PermissionEvaluator.class); PermissionEvaluator permissionEvaluator = this.spring.getContext().getBean(PermissionEvaluator.class);
given(permissionEvaluator.hasPermission(any(Authentication.class), any(Object.class), any(Object.class))) given(permissionEvaluator.hasPermission(any(Authentication.class), any(Object.class), any(Object.class)))
.willReturn(false); .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)); verify(permissionEvaluator).hasPermission(any(Authentication.class), any(Object.class), any(Object.class));
} }
@ -449,21 +526,32 @@ public class MiscHttpConfigTests {
public void loginWhenConfiguredWithNoInternalAuthenticationProvidersThenSuccessfullyAuthenticates() public void loginWhenConfiguredWithNoInternalAuthenticationProvidersThenSuccessfullyAuthenticates()
throws Exception { throws Exception {
this.spring.configLocations(xml("NoInternalAuthenticationProviders")).autowire(); 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("/")); .andExpect(redirectedUrl("/"));
// @formatter:on
} }
@Test @Test
public void loginWhenUsingDefaultsThenErasesCredentialsAfterAuthentication() throws Exception { public void loginWhenUsingDefaultsThenErasesCredentialsAfterAuthentication() throws Exception {
this.spring.configLocations(xml("HttpBasic")).autowire(); 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 @Test
public void loginWhenAuthenticationManagerConfiguredToEraseCredentialsThenErasesCredentialsAfterAuthentication() public void loginWhenAuthenticationManagerConfiguredToEraseCredentialsThenErasesCredentialsAfterAuthentication()
throws Exception { throws Exception {
this.spring.configLocations(xml("AuthenticationManagerEraseCredentials")).autowire(); 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() public void loginWhenAuthenticationManagerRefConfiguredToKeepCredentialsThenKeepsCredentialsAfterAuthentication()
throws Exception { throws Exception {
this.spring.configLocations(xml("AuthenticationManagerRefKeepCredentials")).autowire(); 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 @Test
public void loginWhenAuthenticationManagerRefIsNotAProviderManagerThenKeepsCredentialsAccordingly() public void loginWhenAuthenticationManagerRefIsNotAProviderManagerThenKeepsCredentialsAccordingly()
throws Exception { throws Exception {
this.spring.configLocations(xml("AuthenticationManagerRefNotProviderManager")).autowire(); 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 @Test
@ -488,12 +582,18 @@ public class MiscHttpConfigTests {
this.spring.configLocations(xml("JeeFilter")).autowire(); this.spring.configLocations(xml("JeeFilter")).autowire();
Principal user = mock(Principal.class); Principal user = mock(Principal.class);
given(user.getName()).willReturn("joe"); given(user.getName()).willReturn("joe");
this.mvc.perform(get("/roles").principal(user).with((request) -> { // @formatter:off
MockHttpServletRequestBuilder rolesRequest = get("/roles")
.principal(user)
.with((request) -> {
request.addUserRole("admin"); request.addUserRole("admin");
request.addUserRole("user"); request.addUserRole("user");
request.addUserRole("unmapped"); request.addUserRole("unmapped");
return request; return request;
})).andExpect(content().string("ROLE_admin,ROLE_user")); });
this.mvc.perform(rolesRequest)
.andExpect(content().string("ROLE_admin,ROLE_user"));
// @formatter:on
} }
@Test @Test
@ -503,15 +603,23 @@ public class MiscHttpConfigTests {
Object details = mock(Object.class); Object details = mock(Object.class);
AuthenticationDetailsSource source = this.spring.getContext().getBean(AuthenticationDetailsSource.class); AuthenticationDetailsSource source = this.spring.getContext().getBean(AuthenticationDetailsSource.class);
given(source.buildDetails(any(Object.class))).willReturn(details); 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())); .andExpect(content().string(details.getClass().getName()));
this.mvc.perform(get("/details") this.mvc.perform(get("/details").with(x509))
.with(x509("classpath:org/springframework/security/config/http/MiscHttpConfigTests-certificate.pem")))
.andExpect(content().string(details.getClass().getName())); .andExpect(content().string(details.getClass().getName()));
MockHttpSession session = (MockHttpSession) this.mvc MockHttpServletRequestBuilder loginRequest = post("/login")
.perform(post("/login").param("username", "user").param("password", "password").with(csrf())) .param("username", "user")
.andReturn().getRequest().getSession(false); .param("password", "password")
this.mvc.perform(get("/details").session(session)).andExpect(content().string(details.getClass().getName())); .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), assertThat(ReflectionTestUtils.getField(getFilter(OpenIDAuthenticationFilter.class),
"authenticationDetailsSource")).isEqualTo(source); "authenticationDetailsSource")).isEqualTo(source);
} }
@ -521,7 +629,10 @@ public class MiscHttpConfigTests {
this.spring.configLocations(xml("Jaas")).autowire(); this.spring.configLocations(xml("Jaas")).autowire();
AuthorityGranter granter = this.spring.getContext().getBean(AuthorityGranter.class); AuthorityGranter granter = this.spring.getContext().getBean(AuthorityGranter.class);
given(granter.grant(any(Principal.class))).willReturn(new HashSet<>(Arrays.asList("USER"))); 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 @Test
@ -556,7 +667,10 @@ public class MiscHttpConfigTests {
@Test @Test
public void getWhenUsingCustomAccessDecisionManagerThenAuthorizesAccordingly() throws Exception { public void getWhenUsingCustomAccessDecisionManagerThenAuthorizesAccordingly() throws Exception {
this.spring.configLocations(xml("CustomAccessDecisionManager")).autowire(); 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 @Test
public void authenticateWhenUsingPortMapperThenRedirectsAppropriately() throws Exception { public void authenticateWhenUsingPortMapperThenRedirectsAppropriately() throws Exception {
this.spring.configLocations(xml("PortsMappedRequiresHttps")).autowire(); this.spring.configLocations(xml("PortsMappedRequiresHttps")).autowire();
// @formatter:off
MockHttpSession session = (MockHttpSession) this.mvc.perform(get("https://localhost:9080/protected")) MockHttpSession session = (MockHttpSession) this.mvc.perform(get("https://localhost:9080/protected"))
.andExpect(redirectedUrl("https://localhost:9443/login")).andReturn().getRequest().getSession(false); .andExpect(redirectedUrl("https://localhost:9443/login"))
session = (MockHttpSession) this.mvc .andReturn()
.perform(post("/login").param("username", "user").param("password", "password").session(session) .getRequest()
.with(csrf())) .getSession(false);
.andExpect(redirectedUrl("https://localhost:9443/protected")).andReturn().getRequest() 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); .getSession(false);
this.mvc.perform(get("http://localhost:9080/protected").session(session)) this.mvc.perform(get("http://localhost:9080/protected").session(session))
.andExpect(redirectedUrl("https://localhost:9443/protected")); .andExpect(redirectedUrl("https://localhost:9443/protected"));
// @formatter:on
} }
private void redirectLogsTo(OutputStream os, Class<?> clazz) { private void redirectLogsTo(OutputStream os, Class<?> clazz) {
@ -624,6 +748,21 @@ public class MiscHttpConfigTests {
return proxy.getFilters(url); 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) { private static String xml(String configName) {
return CONFIG_LOCATION_PREFIX + "-" + configName + ".xml"; 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.security.config.test.SpringTestRule;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.test.web.servlet.MockMvc; 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 org.springframework.web.bind.annotation.GetMapping;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
@ -53,10 +53,17 @@ public class MultiHttpBlockConfigTests {
@Test @Test
public void requestWhenUsingMutuallyExclusiveHttpElementsThenIsRoutedAccordingly() throws Exception { public void requestWhenUsingMutuallyExclusiveHttpElementsThenIsRoutedAccordingly() throws Exception {
this.spring.configLocations(this.xml("DistinctHttpElements")).autowire(); 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()); .andExpect(status().isOk());
this.mvc.perform(post("/second/login").param("username", "user").param("password", "password").with(csrf())) MockHttpServletRequestBuilder formLoginRequest = post("/second/login")
.andExpect(status().isFound()).andExpect(redirectedUrl("/")); .param("username", "user")
.param("password", "password")
.with(csrf());
this.mvc.perform(formLoginRequest)
.andExpect(status().isFound())
.andExpect(redirectedUrl("/"));
// @formatter:on
} }
@Test @Test
@ -80,9 +87,19 @@ public class MultiHttpBlockConfigTests {
public void requestWhenTargettingAuthenticationManagersToCorrespondingHttpElementsThenAuthenticationProceeds() public void requestWhenTargettingAuthenticationManagersToCorrespondingHttpElementsThenAuthenticationProceeds()
throws Exception { throws Exception {
this.spring.configLocations(this.xml("Sec1937")).autowire(); this.spring.configLocations(this.xml("Sec1937")).autowire();
this.mvc.perform(get("/first").with(httpBasic("first", "password")).with(csrf())).andExpect(status().isOk()); // @formatter:off
this.mvc.perform(post("/second/login").param("username", "second").param("password", "password").with(csrf())) 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("/")); .andExpect(redirectedUrl("/"));
// @formatter:on
} }
private String xml(String configName) { private String xml(String configName) {

View File

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

View File

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

View File

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

View File

@ -50,6 +50,7 @@ import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.Mockito; import org.mockito.Mockito;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.w3c.dom.Element; import org.w3c.dom.Element;
import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.DisposableBean;
@ -137,7 +138,10 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
this.spring.configLocations(xml("JwtRestOperations"), xml("Jwt")).autowire(); this.spring.configLocations(xml("JwtRestOperations"), xml("Jwt")).autowire();
mockRestOperations(jwks("Default")); mockRestOperations(jwks("Default"));
String token = this.token("ValidNoScopes"); 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 @Test
@ -145,7 +149,10 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
this.spring.configLocations(xml("WebServer"), xml("JwkSetUri")).autowire(); this.spring.configLocations(xml("WebServer"), xml("JwkSetUri")).autowire();
mockWebServer(jwks("Default")); mockWebServer(jwks("Default"));
String token = this.token("ValidNoScopes"); 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 @Test
@ -153,8 +160,11 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
this.spring.configLocations(xml("JwtRestOperations"), xml("Jwt")).autowire(); this.spring.configLocations(xml("JwtRestOperations"), xml("Jwt")).autowire();
mockRestOperations(jwks("Default")); mockRestOperations(jwks("Default"));
String token = this.token("Expired"); 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")); .andExpect(invalidTokenHeader("An error occurred while attempting to decode the Jwt"));
// @formatter:on
} }
@Test @Test
@ -162,8 +172,11 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
this.spring.configLocations(xml("JwtRestOperations"), xml("Jwt")).autowire(); this.spring.configLocations(xml("JwtRestOperations"), xml("Jwt")).autowire();
mockRestOperations("malformed"); mockRestOperations("malformed");
String token = this.token("ValidNoScopes"); 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")); .andExpect(header().string("WWW-Authenticate", "Bearer"));
// @formatter:on
} }
@Test @Test
@ -171,15 +184,21 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
this.spring.configLocations(xml("WebServer"), xml("JwkSetUri")).autowire(); this.spring.configLocations(xml("WebServer"), xml("JwkSetUri")).autowire();
this.web.shutdown(); this.web.shutdown();
String token = this.token("ValidNoScopes"); 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")); .andExpect(header().string("WWW-Authenticate", "Bearer"));
// @formatter:on
} }
@Test @Test
public void getWhenMalformedBearerTokenThenInvalidToken() throws Exception { public void getWhenMalformedBearerTokenThenInvalidToken() throws Exception {
this.spring.configLocations(xml("JwkSetUri")).autowire(); this.spring.configLocations(xml("JwkSetUri")).autowire();
// @formatter:off
this.mvc.perform(get("/").header("Authorization", "Bearer an\"invalid\"token")) 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 @Test
@ -187,17 +206,22 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
this.spring.configLocations(xml("JwtRestOperations"), xml("Jwt")).autowire(); this.spring.configLocations(xml("JwtRestOperations"), xml("Jwt")).autowire();
mockRestOperations(jwks("Default")); mockRestOperations(jwks("Default"));
String token = this.token("MalformedPayload"); String token = this.token("MalformedPayload");
this.mvc.perform(get("/").header("Authorization", "Bearer " + token)).andExpect(status().isUnauthorized()) // @formatter:off
.andExpect( this.mvc.perform(get("/").header("Authorization", "Bearer " + token))
invalidTokenHeader("An error occurred while attempting to decode the Jwt: Malformed payload")); .andExpect(status().isUnauthorized())
.andExpect(invalidTokenHeader("An error occurred while attempting to decode the Jwt: Malformed payload"));
// @formatter:on
} }
@Test @Test
public void getWhenUnsignedBearerTokenThenInvalidToken() throws Exception { public void getWhenUnsignedBearerTokenThenInvalidToken() throws Exception {
this.spring.configLocations(xml("JwkSetUri")).autowire(); this.spring.configLocations(xml("JwkSetUri")).autowire();
String token = this.token("Unsigned"); 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")); .andExpect(invalidTokenHeader("Unsupported algorithm of none"));
// @formatter:on
} }
@Test @Test
@ -205,16 +229,21 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
this.spring.configLocations(xml("JwtRestOperations"), xml("Jwt")).autowire(); this.spring.configLocations(xml("JwtRestOperations"), xml("Jwt")).autowire();
this.mockRestOperations(jwks("Default")); this.mockRestOperations(jwks("Default"));
String token = this.token("TooEarly"); 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")); .andExpect(invalidTokenHeader("An error occurred while attempting to decode the Jwt"));
// @formatter:on
} }
@Test @Test
public void getWhenBearerTokenInTwoPlacesThenInvalidRequest() throws Exception { public void getWhenBearerTokenInTwoPlacesThenInvalidRequest() throws Exception {
this.spring.configLocations(xml("JwkSetUri")).autowire(); this.spring.configLocations(xml("JwkSetUri")).autowire();
// @formatter:off
this.mvc.perform(get("/").header("Authorization", "Bearer token").param("access_token", "token")) this.mvc.perform(get("/").header("Authorization", "Bearer token").param("access_token", "token"))
.andExpect(status().isBadRequest()) .andExpect(status().isBadRequest())
.andExpect(invalidRequestHeader("Found multiple bearer tokens in the request")); .andExpect(invalidRequestHeader("Found multiple bearer tokens in the request"));
// @formatter:on
} }
@Test @Test
@ -223,8 +252,11 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
MultiValueMap<String, String> params = new LinkedMultiValueMap<>(); MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("access_token", "token1"); params.add("access_token", "token1");
params.add("access_token", "token2"); 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")); .andExpect(invalidRequestHeader("Found multiple bearer tokens in the request"));
// @formatter:on
} }
@Test @Test
@ -240,8 +272,11 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
@Test @Test
public void getWhenNoBearerTokenThenUnauthorized() throws Exception { public void getWhenNoBearerTokenThenUnauthorized() throws Exception {
this.spring.configLocations(xml("JwkSetUri")).autowire(); 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")); .andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, "Bearer"));
// @formatter:on
} }
@Test @Test
@ -249,8 +284,10 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
this.spring.configLocations(xml("JwtRestOperations"), xml("Jwt")).autowire(); this.spring.configLocations(xml("JwtRestOperations"), xml("Jwt")).autowire();
mockRestOperations(jwks("Default")); mockRestOperations(jwks("Default"));
String token = this.token("ValidMessageReadScope"); String token = this.token("ValidMessageReadScope");
// @formatter:off
this.mvc.perform(get("/requires-read-scope").header("Authorization", "Bearer " + token)) this.mvc.perform(get("/requires-read-scope").header("Authorization", "Bearer " + token))
.andExpect(status().isNotFound()); .andExpect(status().isNotFound());
// @formatter:on
} }
@Test @Test
@ -258,8 +295,11 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
this.spring.configLocations(xml("JwtRestOperations"), xml("Jwt")).autowire(); this.spring.configLocations(xml("JwtRestOperations"), xml("Jwt")).autowire();
mockRestOperations(jwks("Default")); mockRestOperations(jwks("Default"));
String token = this.token("ValidNoScopes"); String token = this.token("ValidNoScopes");
// @formatter:off
this.mvc.perform(get("/requires-read-scope").header("Authorization", "Bearer " + token)) this.mvc.perform(get("/requires-read-scope").header("Authorization", "Bearer " + token))
.andExpect(status().isForbidden()).andExpect(insufficientScopeHeader()); .andExpect(status().isForbidden())
.andExpect(insufficientScopeHeader());
// @formatter:on
} }
@Test @Test
@ -267,8 +307,11 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
this.spring.configLocations(xml("JwtRestOperations"), xml("Jwt")).autowire(); this.spring.configLocations(xml("JwtRestOperations"), xml("Jwt")).autowire();
mockRestOperations(jwks("Default")); mockRestOperations(jwks("Default"));
String token = this.token("ValidMessageWriteScp"); String token = this.token("ValidMessageWriteScp");
// @formatter:off
this.mvc.perform(get("/requires-read-scope").header("Authorization", "Bearer " + token)) this.mvc.perform(get("/requires-read-scope").header("Authorization", "Bearer " + token))
.andExpect(status().isForbidden()).andExpect(insufficientScopeHeader()); .andExpect(status().isForbidden())
.andExpect(insufficientScopeHeader());
// @formatter:on
} }
@Test @Test
@ -276,8 +319,11 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
this.spring.configLocations(xml("JwtRestOperations"), xml("Jwt")).autowire(); this.spring.configLocations(xml("JwtRestOperations"), xml("Jwt")).autowire();
mockRestOperations(jwks("Empty")); mockRestOperations(jwks("Empty"));
String token = this.token("ValidNoScopes"); 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")); .andExpect(invalidTokenHeader("An error occurred while attempting to decode the Jwt"));
// @formatter:on
} }
@Test @Test
@ -285,8 +331,10 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
this.spring.configLocations(xml("JwtRestOperations"), xml("Jwt")).autowire(); this.spring.configLocations(xml("JwtRestOperations"), xml("Jwt")).autowire();
mockRestOperations(jwks("TwoKeys")); mockRestOperations(jwks("TwoKeys"));
String token = this.token("ValidNoScopes"); String token = this.token("ValidNoScopes");
// @formatter:off
this.mvc.perform(get("/authenticated").header("Authorization", "Bearer " + token)) this.mvc.perform(get("/authenticated").header("Authorization", "Bearer " + token))
.andExpect(status().isNotFound()); .andExpect(status().isNotFound());
// @formatter:on
} }
@Test @Test
@ -294,8 +342,10 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
this.spring.configLocations(xml("JwtRestOperations"), xml("Jwt")).autowire(); this.spring.configLocations(xml("JwtRestOperations"), xml("Jwt")).autowire();
mockRestOperations(jwks("TwoKeys")); mockRestOperations(jwks("TwoKeys"));
String token = this.token("Kid"); String token = this.token("Kid");
// @formatter:off
this.mvc.perform(get("/authenticated").header("Authorization", "Bearer " + token)) this.mvc.perform(get("/authenticated").header("Authorization", "Bearer " + token))
.andExpect(status().isNotFound()); .andExpect(status().isNotFound());
// @formatter:on
} }
@Test @Test
@ -303,17 +353,21 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
this.spring.configLocations(xml("JwtRestOperations"), xml("Jwt")).autowire(); this.spring.configLocations(xml("JwtRestOperations"), xml("Jwt")).autowire();
mockRestOperations(jwks("Default")); mockRestOperations(jwks("Default"));
String token = this.token("ValidNoScopes"); String token = this.token("ValidNoScopes");
// @formatter:off
this.mvc.perform(post("/authenticated").header("Authorization", "Bearer " + token)) this.mvc.perform(post("/authenticated").header("Authorization", "Bearer " + token))
.andExpect(status().isNotFound()); .andExpect(status().isNotFound());
// @formatter:on
} }
@Test @Test
public void postWhenNoBearerTokenThenCsrfDenies() throws Exception { public void postWhenNoBearerTokenThenCsrfDenies() throws Exception {
this.spring.configLocations(xml("JwkSetUri")).autowire(); this.spring.configLocations(xml("JwkSetUri")).autowire();
this.mvc.perform(post("/authenticated")).andExpect(status().isForbidden()) // @formatter:off
.andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, "Bearer")); // different this.mvc.perform(post("/authenticated"))
// from .andExpect(status().isForbidden())
// DSL // different from DSL
.andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, "Bearer"));
// @formatter:on
} }
@Test @Test
@ -321,9 +375,11 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
this.spring.configLocations(xml("JwtRestOperations"), xml("Jwt")).autowire(); this.spring.configLocations(xml("JwtRestOperations"), xml("Jwt")).autowire();
mockRestOperations(jwks("Default")); mockRestOperations(jwks("Default"));
String token = this.token("Expired"); String token = this.token("Expired");
// @formatter:off
this.mvc.perform(post("/authenticated").header("Authorization", "Bearer " + token)) this.mvc.perform(post("/authenticated").header("Authorization", "Bearer " + token))
.andExpect(status().isUnauthorized()) .andExpect(status().isUnauthorized())
.andExpect(invalidTokenHeader("An error occurred while attempting to decode the Jwt")); .andExpect(invalidTokenHeader("An error occurred while attempting to decode the Jwt"));
// @formatter:on
} }
@Test @Test
@ -331,8 +387,11 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
this.spring.configLocations(xml("JwtRestOperations"), xml("Jwt")).autowire(); this.spring.configLocations(xml("JwtRestOperations"), xml("Jwt")).autowire();
mockRestOperations(jwks("Default")); mockRestOperations(jwks("Default"));
String token = this.token("ValidNoScopes"); String token = this.token("ValidNoScopes");
// @formatter:off
MvcResult result = this.mvc.perform(get("/").header("Authorization", "Bearer " + token)) 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(); assertThat(result.getRequest().getSession(false)).isNull();
} }
@ -340,15 +399,22 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
public void requestWhenIntrospectionThenSessionIsNotCreated() throws Exception { public void requestWhenIntrospectionThenSessionIsNotCreated() throws Exception {
this.spring.configLocations(xml("WebServer"), xml("IntrospectionUri")).autowire(); this.spring.configLocations(xml("WebServer"), xml("IntrospectionUri")).autowire();
mockWebServer(json("Active")); mockWebServer(json("Active"));
// @formatter:off
MvcResult result = this.mvc.perform(get("/authenticated").header("Authorization", "Bearer token")) 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(); assertThat(result.getRequest().getSession(false)).isNull();
} }
@Test @Test
public void requestWhenNoBearerTokenThenSessionIsCreated() throws Exception { public void requestWhenNoBearerTokenThenSessionIsCreated() throws Exception {
this.spring.configLocations(xml("JwkSetUri")).autowire(); 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(); assertThat(result.getRequest().getSession(false)).isNotNull();
} }
@ -357,8 +423,11 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
this.spring.configLocations(xml("JwtRestOperations"), xml("AlwaysSessionCreation")).autowire(); this.spring.configLocations(xml("JwtRestOperations"), xml("AlwaysSessionCreation")).autowire();
mockRestOperations(jwks("Default")); mockRestOperations(jwks("Default"));
String token = this.token("ValidNoScopes"); String token = this.token("ValidNoScopes");
// @formatter:off
MvcResult result = this.mvc.perform(get("/").header("Authorization", "Bearer " + token)) 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(); assertThat(result.getRequest().getSession(false)).isNotNull();
} }
@ -381,9 +450,12 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
this.spring.configLocations(xml("MockJwtDecoder"), xml("AllowBearerTokenInBody")).autowire(); this.spring.configLocations(xml("MockJwtDecoder"), xml("AllowBearerTokenInBody")).autowire();
JwtDecoder decoder = this.spring.getContext().getBean(JwtDecoder.class); JwtDecoder decoder = this.spring.getContext().getBean(JwtDecoder.class);
given(decoder.decode(anyString())).willReturn(TestJwts.jwt().build()); given(decoder.decode(anyString())).willReturn(TestJwts.jwt().build());
// @formatter:off
this.mvc.perform(get("/authenticated").header("Authorization", "Bearer token")) this.mvc.perform(get("/authenticated").header("Authorization", "Bearer token"))
.andExpect(status().isNotFound()); .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 @Test
@ -392,9 +464,12 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
this.spring.configLocations(xml("MockJwtDecoder"), xml("AllowBearerTokenInQuery")).autowire(); this.spring.configLocations(xml("MockJwtDecoder"), xml("AllowBearerTokenInQuery")).autowire();
JwtDecoder decoder = this.spring.getContext().getBean(JwtDecoder.class); JwtDecoder decoder = this.spring.getContext().getBean(JwtDecoder.class);
given(decoder.decode(anyString())).willReturn(TestJwts.jwt().build()); given(decoder.decode(anyString())).willReturn(TestJwts.jwt().build());
// @formatter:off
this.mvc.perform(get("/authenticated").header("Authorization", "Bearer token")) this.mvc.perform(get("/authenticated").header("Authorization", "Bearer token"))
.andExpect(status().isNotFound()); .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"); verify(decoder, times(2)).decode("token");
} }
@ -402,18 +477,29 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
public void requestWhenBearerTokenResolverAllowsRequestBodyAndRequestContainsTwoTokensThenInvalidRequest() public void requestWhenBearerTokenResolverAllowsRequestBodyAndRequestContainsTwoTokensThenInvalidRequest()
throws Exception { throws Exception {
this.spring.configLocations(xml("MockJwtDecoder"), xml("AllowBearerTokenInBody")).autowire(); this.spring.configLocations(xml("MockJwtDecoder"), xml("AllowBearerTokenInBody")).autowire();
this.mvc.perform(post("/authenticated").param("access_token", "token").header("Authorization", "Bearer token") // @formatter:off
.with(csrf())).andExpect(status().isBadRequest()) 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"))); .andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, containsString("invalid_request")));
// @formatter:on
} }
@Test @Test
public void requestWhenBearerTokenResolverAllowsQueryParameterAndRequestContainsTwoTokensThenInvalidRequest() public void requestWhenBearerTokenResolverAllowsQueryParameterAndRequestContainsTwoTokensThenInvalidRequest()
throws Exception { throws Exception {
this.spring.configLocations(xml("MockJwtDecoder"), xml("AllowBearerTokenInQuery")).autowire(); 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(status().isBadRequest())
.andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, containsString("invalid_request"))); .andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, containsString("invalid_request")));
// @formatter:on
} }
@Test @Test
@ -444,9 +530,11 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
this.spring.configLocations(xml("MockJwtDecoder"), xml("AuthenticationEntryPoint")).autowire(); this.spring.configLocations(xml("MockJwtDecoder"), xml("AuthenticationEntryPoint")).autowire();
JwtDecoder decoder = this.spring.getContext().getBean(JwtDecoder.class); JwtDecoder decoder = this.spring.getContext().getBean(JwtDecoder.class);
Mockito.when(decoder.decode(anyString())).thenThrow(JwtException.class); Mockito.when(decoder.decode(anyString())).thenThrow(JwtException.class);
// @formatter:off
this.mvc.perform(get("/authenticated").header("Authorization", "Bearer invalid_token")) this.mvc.perform(get("/authenticated").header("Authorization", "Bearer invalid_token"))
.andExpect(status().isUnauthorized()) .andExpect(status().isUnauthorized())
.andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, startsWith("Bearer realm=\"myRealm\""))); .andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, startsWith("Bearer realm=\"myRealm\"")));
// @formatter:on
} }
@Test @Test
@ -454,9 +542,11 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
this.spring.configLocations(xml("MockJwtDecoder"), xml("AccessDeniedHandler")).autowire(); this.spring.configLocations(xml("MockJwtDecoder"), xml("AccessDeniedHandler")).autowire();
JwtDecoder decoder = this.spring.getContext().getBean(JwtDecoder.class); JwtDecoder decoder = this.spring.getContext().getBean(JwtDecoder.class);
given(decoder.decode(anyString())).willReturn(TestJwts.jwt().build()); given(decoder.decode(anyString())).willReturn(TestJwts.jwt().build());
// @formatter:off
this.mvc.perform(get("/authenticated").header("Authorization", "Bearer insufficiently_scoped")) this.mvc.perform(get("/authenticated").header("Authorization", "Bearer insufficiently_scoped"))
.andExpect(status().isForbidden()) .andExpect(status().isForbidden())
.andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, startsWith("Bearer realm=\"myRealm\""))); .andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, startsWith("Bearer realm=\"myRealm\"")));
// @formatter:on
} }
@Test @Test
@ -467,8 +557,11 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
OAuth2TokenValidator<Jwt> jwtValidator = this.spring.getContext().getBean(OAuth2TokenValidator.class); OAuth2TokenValidator<Jwt> jwtValidator = this.spring.getContext().getBean(OAuth2TokenValidator.class);
OAuth2Error error = new OAuth2Error("custom-error", "custom-description", "custom-uri"); OAuth2Error error = new OAuth2Error("custom-error", "custom-description", "custom-uri");
given(jwtValidator.validate(any(Jwt.class))).willReturn(OAuth2TokenValidatorResult.failure(error)); 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"))); .andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, containsString("custom-description")));
// @formatter:on
} }
@Test @Test
@ -476,7 +569,10 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
this.spring.configLocations(xml("UnexpiredJwtClockSkew"), xml("Jwt")).autowire(); this.spring.configLocations(xml("UnexpiredJwtClockSkew"), xml("Jwt")).autowire();
mockRestOperations(jwks("Default")); mockRestOperations(jwks("Default"));
String token = this.token("ExpiresAt4687177990"); 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 @Test
@ -484,8 +580,11 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
this.spring.configLocations(xml("ExpiredJwtClockSkew"), xml("Jwt")).autowire(); this.spring.configLocations(xml("ExpiredJwtClockSkew"), xml("Jwt")).autowire();
mockRestOperations(jwks("Default")); mockRestOperations(jwks("Default"));
String token = this.token("ExpiresAt4687177990"); 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")); .andExpect(invalidTokenHeader("Jwt expired at"));
// @formatter:on
} }
@Test @Test
@ -498,7 +597,10 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
.willReturn(new JwtAuthenticationToken(TestJwts.jwt().build(), Collections.emptyList())); .willReturn(new JwtAuthenticationToken(TestJwts.jwt().build(), Collections.emptyList()));
JwtDecoder jwtDecoder = this.spring.getContext().getBean(JwtDecoder.class); JwtDecoder jwtDecoder = this.spring.getContext().getBean(JwtDecoder.class);
given(jwtDecoder.decode(anyString())).willReturn(TestJwts.jwt().build()); 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)); verify(jwtAuthenticationConverter).convert(any(Jwt.class));
} }
@ -506,49 +608,64 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
public void requestWhenUsingPublicKeyAndValidTokenThenAuthenticates() throws Exception { public void requestWhenUsingPublicKeyAndValidTokenThenAuthenticates() throws Exception {
this.spring.configLocations(xml("SingleKey"), xml("Jwt")).autowire(); this.spring.configLocations(xml("SingleKey"), xml("Jwt")).autowire();
String token = this.token("ValidNoScopes"); 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 @Test
public void requestWhenUsingPublicKeyAndSignatureFailsThenReturnsInvalidToken() throws Exception { public void requestWhenUsingPublicKeyAndSignatureFailsThenReturnsInvalidToken() throws Exception {
this.spring.configLocations(xml("SingleKey"), xml("Jwt")).autowire(); this.spring.configLocations(xml("SingleKey"), xml("Jwt")).autowire();
String token = this.token("WrongSignature"); String token = this.token("WrongSignature");
// @formatter:off
this.mvc.perform(get("/").header("Authorization", "Bearer " + token)) this.mvc.perform(get("/").header("Authorization", "Bearer " + token))
.andExpect(invalidTokenHeader("signature")); .andExpect(invalidTokenHeader("signature"));
// @formatter:on
} }
@Test @Test
public void requestWhenUsingPublicKeyAlgorithmDoesNotMatchThenReturnsInvalidToken() throws Exception { public void requestWhenUsingPublicKeyAlgorithmDoesNotMatchThenReturnsInvalidToken() throws Exception {
this.spring.configLocations(xml("SingleKey"), xml("Jwt")).autowire(); this.spring.configLocations(xml("SingleKey"), xml("Jwt")).autowire();
String token = this.token("WrongAlgorithm"); String token = this.token("WrongAlgorithm");
// @formatter:off
this.mvc.perform(get("/").header("Authorization", "Bearer " + token)) this.mvc.perform(get("/").header("Authorization", "Bearer " + token))
.andExpect(invalidTokenHeader("algorithm")); .andExpect(invalidTokenHeader("algorithm"));
// @formatter:on
} }
@Test @Test
public void getWhenIntrospectingThenOk() throws Exception { public void getWhenIntrospectingThenOk() throws Exception {
this.spring.configLocations(xml("OpaqueTokenRestOperations"), xml("OpaqueToken")).autowire(); this.spring.configLocations(xml("OpaqueTokenRestOperations"), xml("OpaqueToken")).autowire();
mockRestOperations(json("Active")); mockRestOperations(json("Active"));
// @formatter:off
this.mvc.perform(get("/authenticated").header("Authorization", "Bearer token")) this.mvc.perform(get("/authenticated").header("Authorization", "Bearer token"))
.andExpect(status().isNotFound()); .andExpect(status().isNotFound());
// @formatter:on
} }
@Test @Test
public void getWhenIntrospectionFailsThenUnauthorized() throws Exception { public void getWhenIntrospectionFailsThenUnauthorized() throws Exception {
this.spring.configLocations(xml("OpaqueTokenRestOperations"), xml("OpaqueToken")).autowire(); this.spring.configLocations(xml("OpaqueTokenRestOperations"), xml("OpaqueToken")).autowire();
mockRestOperations(json("Inactive")); mockRestOperations(json("Inactive"));
this.mvc.perform(get("/").header("Authorization", "Bearer token")).andExpect(status().isUnauthorized()) // @formatter:off
.andExpect( MockHttpServletRequestBuilder request = get("/")
header().string(HttpHeaders.WWW_AUTHENTICATE, containsString("Provided token isn't active"))); .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 @Test
public void getWhenIntrospectionLacksScopeThenForbidden() throws Exception { public void getWhenIntrospectionLacksScopeThenForbidden() throws Exception {
this.spring.configLocations(xml("OpaqueTokenRestOperations"), xml("OpaqueToken")).autowire(); this.spring.configLocations(xml("OpaqueTokenRestOperations"), xml("OpaqueToken")).autowire();
mockRestOperations(json("ActiveNoScopes")); mockRestOperations(json("ActiveNoScopes"));
// @formatter:off
this.mvc.perform(get("/requires-read-scope").header("Authorization", "Bearer token")) this.mvc.perform(get("/requires-read-scope").header("Authorization", "Bearer token"))
.andExpect(status().isForbidden()) .andExpect(status().isForbidden())
.andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, containsString("scope"))); .andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, containsString("scope")));
// @formatter:on
} }
@Test @Test
@ -570,7 +687,10 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
.getBean(AuthenticationManagerResolver.class); .getBean(AuthenticationManagerResolver.class);
given(authenticationManagerResolver.resolve(any(HttpServletRequest.class))).willReturn( given(authenticationManagerResolver.resolve(any(HttpServletRequest.class))).willReturn(
(authentication) -> new JwtAuthenticationToken(TestJwts.jwt().build(), Collections.emptyList())); (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)); verify(authenticationManagerResolver).resolve(any(HttpServletRequest.class));
} }
@ -589,16 +709,23 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
String jwtThree = jwtFromIssuer(issuerThree); String jwtThree = jwtFromIssuer(issuerThree);
mockWebServer(String.format(metadata, issuerOne, issuerOne)); mockWebServer(String.format(metadata, issuerOne, issuerOne));
mockWebServer(jwkSet); mockWebServer(jwkSet);
// @formatter:off
this.mvc.perform(get("/authenticated").header("Authorization", "Bearer " + jwtOne)) this.mvc.perform(get("/authenticated").header("Authorization", "Bearer " + jwtOne))
.andExpect(status().isNotFound()); .andExpect(status().isNotFound());
// @formatter:on
mockWebServer(String.format(metadata, issuerTwo, issuerTwo)); mockWebServer(String.format(metadata, issuerTwo, issuerTwo));
mockWebServer(jwkSet); mockWebServer(jwkSet);
// @formatter:off
this.mvc.perform(get("/authenticated").header("Authorization", "Bearer " + jwtTwo)) this.mvc.perform(get("/authenticated").header("Authorization", "Bearer " + jwtTwo))
.andExpect(status().isNotFound()); .andExpect(status().isNotFound());
// @formatter:on
mockWebServer(String.format(metadata, issuerThree, issuerThree)); mockWebServer(String.format(metadata, issuerThree, issuerThree));
mockWebServer(jwkSet); mockWebServer(jwkSet);
// @formatter:off
this.mvc.perform(get("/authenticated").header("Authorization", "Bearer " + jwtThree)) 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 @Test
@ -607,13 +734,17 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
this.spring.configLocations(xml("MockJwtDecoder"), xml("BasicAndResourceServer")).autowire(); this.spring.configLocations(xml("MockJwtDecoder"), xml("BasicAndResourceServer")).autowire();
JwtDecoder decoder = this.spring.getContext().getBean(JwtDecoder.class); JwtDecoder decoder = this.spring.getContext().getBean(JwtDecoder.class);
given(decoder.decode(anyString())).willThrow(JwtException.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"))); .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"))); .andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, startsWith("Bearer")));
this.mvc.perform(get("/authenticated").header("Authorization", "Bearer invalid_token")) this.mvc.perform(get("/authenticated").header("Authorization", "Bearer invalid_token"))
.andExpect(status().isUnauthorized()) .andExpect(status().isUnauthorized())
.andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, startsWith("Bearer"))); .andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, startsWith("Bearer")));
// @formatter:on
} }
@Test @Test
@ -624,8 +755,11 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
given(decoder.decode(anyString())).willThrow(JwtException.class); given(decoder.decode(anyString())).willThrow(JwtException.class);
MvcResult result = this.mvc.perform(get("/authenticated")).andExpect(status().isUnauthorized()).andReturn(); MvcResult result = this.mvc.perform(get("/authenticated")).andExpect(status().isUnauthorized()).andReturn();
assertThat(result.getRequest().getSession(false)).isNotNull(); assertThat(result.getRequest().getSession(false)).isNotNull();
// @formatter:off
result = this.mvc.perform(get("/authenticated").header("Authorization", "Bearer token")) 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(); assertThat(result.getRequest().getSession(false)).isNull();
} }
@ -634,9 +768,12 @@ public class OAuth2ResourceServerBeanDefinitionParserTests {
this.spring.configLocations(xml("JwtRestOperations"), xml("BasicAndResourceServer")).autowire(); this.spring.configLocations(xml("JwtRestOperations"), xml("BasicAndResourceServer")).autowire();
mockRestOperations(jwks("Default")); mockRestOperations(jwks("Default"));
String token = this.token("ValidNoScopes"); String token = this.token("ValidNoScopes");
// @formatter:off
this.mvc.perform(get("/authenticated").header("Authorization", "Bearer " + token)) this.mvc.perform(get("/authenticated").header("Authorization", "Bearer " + token))
.andExpect(status().isNotFound()); .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 @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.rememberme.AbstractRememberMeServices;
import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter; import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;
import org.springframework.test.web.servlet.MockMvc; 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.GetMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
@ -73,21 +74,32 @@ public class OpenIDConfigTests {
@Test @Test
public void requestWhenOpenIDAndFormLoginBothConfiguredThenRedirectsToGeneratedLoginPage() throws Exception { public void requestWhenOpenIDAndFormLoginBothConfiguredThenRedirectsToGeneratedLoginPage() throws Exception {
this.spring.configLocations(this.xml("WithFormLogin")).autowire(); 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(); assertThat(getFilter(DefaultLoginPageGeneratingFilter.class)).isNotNull();
} }
@Test @Test
public void requestWhenOpenIDAndFormLoginWithFormLoginPageConfiguredThenFormLoginPageWins() throws Exception { public void requestWhenOpenIDAndFormLoginWithFormLoginPageConfiguredThenFormLoginPageWins() throws Exception {
this.spring.configLocations(this.xml("WithFormLoginPage")).autowire(); 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 @Test
public void requestWhenOpenIDAndFormLoginWithOpenIDLoginPageConfiguredThenOpenIDLoginPageWins() throws Exception { public void requestWhenOpenIDAndFormLoginWithOpenIDLoginPageConfiguredThenOpenIDLoginPageWins() throws Exception {
this.spring.configLocations(this.xml("WithOpenIDLoginPageAndFormLogin")).autowire(); 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")); .andExpect(redirectedUrl("http://localhost/openid-page"));
// @formatter:on
} }
@Test @Test
@ -110,13 +122,20 @@ public class OpenIDConfigTests {
openIDFilter.setConsumer(consumer); openIDFilter.setConsumer(consumer);
String expectedReturnTo = new StringBuilder("http://localhost/login/openid").append("?") String expectedReturnTo = new StringBuilder("http://localhost/login/openid").append("?")
.append(AbstractRememberMeServices.DEFAULT_PARAMETER).append("=").append("on").toString(); .append(AbstractRememberMeServices.DEFAULT_PARAMETER).append("=").append("on").toString();
this.mvc.perform(get("/")).andExpect(status().isFound()).andExpect(redirectedUrl("http://localhost/login")); // @formatter:off
this.mvc.perform(get("/login")).andExpect(status().isOk()) 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))); .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(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)); .andExpect(redirectedUrl(openIdEndpointUrl + expectedReturnTo));
// @formatter:on
} }
@Test @Test
@ -131,8 +150,7 @@ public class OpenIDConfigTests {
server.enqueue(new MockResponse().addHeader(YadisResolver.YADIS_XRDS_LOCATION, endpoint)); server.enqueue(new MockResponse().addHeader(YadisResolver.YADIS_XRDS_LOCATION, endpoint));
server.enqueue(new MockResponse() server.enqueue(new MockResponse()
.setBody(String.format("<XRDS><XRD><Service><URI>%s</URI></Service></XRD></XRDS>", endpoint))); .setBody(String.format("<XRDS><XRD><Service><URI>%s</URI></Service></XRD></XRDS>", endpoint)));
this.mvc.perform( this.mvc.perform(get("/login/openid").param(OpenIDAuthenticationFilter.DEFAULT_CLAIMED_IDENTITY_FIELD, endpoint))
get("/login/openid").param(OpenIDAuthenticationFilter.DEFAULT_CLAIMED_IDENTITY_FIELD, endpoint))
.andExpect(status().isFound()) .andExpect(status().isFound())
.andExpect((result) -> result.getResponse().getRedirectedUrl().endsWith( .andExpect((result) -> result.getResponse().getRedirectedUrl().endsWith(
"openid.ext1.type.nickname=http%3A%2F%2Fschema.openid.net%2FnamePerson%2Ffriendly&" "openid.ext1.type.nickname=http%3A%2F%2Fschema.openid.net%2FnamePerson%2Ffriendly&"
@ -150,7 +168,11 @@ public class OpenIDConfigTests {
throws Exception { throws Exception {
this.spring.configLocations(this.xml("Sec2919")).autowire(); this.spring.configLocations(this.xml("Sec2919")).autowire();
assertThat(getFilter(DefaultLoginPageGeneratingFilter.class)).isNull(); 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) { private <T extends Filter> T getFilter(Class<T> clazz) {

View File

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

View File

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

View File

@ -67,14 +67,21 @@ public class SecurityContextHolderAwareRequestConfigTests {
@Test @Test
public void servletLoginWhenUsingDefaultConfigurationThenUsesSpringSecurity() throws Exception { public void servletLoginWhenUsingDefaultConfigurationThenUsesSpringSecurity() throws Exception {
this.spring.configLocations(this.xml("Simple")).autowire(); 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 @Test
public void servletAuthenticateWhenUsingDefaultConfigurationThenUsesSpringSecurity() throws Exception { public void servletAuthenticateWhenUsingDefaultConfigurationThenUsesSpringSecurity() throws Exception {
this.spring.configLocations(this.xml("Simple")).autowire(); 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")); .andExpect(redirectedUrl("http://localhost/login"));
// @formatter:on
} }
@Test @Test
@ -83,8 +90,12 @@ public class SecurityContextHolderAwareRequestConfigTests {
MvcResult result = this.mvc.perform(get("/good-login")).andReturn(); MvcResult result = this.mvc.perform(get("/good-login")).andReturn();
MockHttpSession session = (MockHttpSession) result.getRequest().getSession(false); MockHttpSession session = (MockHttpSession) result.getRequest().getSession(false);
assertThat(session).isNotNull(); assertThat(session).isNotNull();
result = this.mvc.perform(get("/do-logout").session(session)).andExpect(status().isOk()) // @formatter:off
.andExpect(content().string("")).andReturn(); result = this.mvc.perform(get("/do-logout").session(session))
.andExpect(status().isOk())
.andExpect(content().string(""))
.andReturn();
// @formatter:on
session = (MockHttpSession) result.getRequest().getSession(false); session = (MockHttpSession) result.getRequest().getSession(false);
assertThat(session).isNull(); assertThat(session).isNull();
} }
@ -92,31 +103,47 @@ public class SecurityContextHolderAwareRequestConfigTests {
@Test @Test
public void servletAuthenticateWhenUsingHttpBasicThenUsesSpringSecurity() throws Exception { public void servletAuthenticateWhenUsingHttpBasicThenUsesSpringSecurity() throws Exception {
this.spring.configLocations(this.xml("HttpBasic")).autowire(); 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"))); .andExpect(header().string(HttpHeaders.WWW_AUTHENTICATE, containsString("discworld")));
// @formatter:on
} }
@Test @Test
public void servletAuthenticateWhenUsingFormLoginThenUsesSpringSecurity() throws Exception { public void servletAuthenticateWhenUsingFormLoginThenUsesSpringSecurity() throws Exception {
this.spring.configLocations(this.xml("FormLogin")).autowire(); 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")); .andExpect(redirectedUrl("http://localhost/login"));
// @formatter:on
} }
@Test @Test
public void servletLoginWhenUsingMultipleHttpConfigsThenUsesSpringSecurity() throws Exception { public void servletLoginWhenUsingMultipleHttpConfigsThenUsesSpringSecurity() throws Exception {
this.spring.configLocations(this.xml("MultiHttp")).autowire(); this.spring.configLocations(this.xml("MultiHttp")).autowire();
this.mvc.perform(get("/good-login")).andExpect(status().isOk()).andExpect(content().string("user")); // @formatter:off
this.mvc.perform(get("/v2/good-login")).andExpect(status().isOk()).andExpect(content().string("user2")); 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 @Test
public void servletAuthenticateWhenUsingMultipleHttpConfigsThenUsesSpringSecurity() throws Exception { public void servletAuthenticateWhenUsingMultipleHttpConfigsThenUsesSpringSecurity() throws Exception {
this.spring.configLocations(this.xml("MultiHttp")).autowire(); 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")); .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")); .andExpect(redirectedUrl("http://localhost/login2"));
// @formatter:on
} }
@Test @Test
@ -125,15 +152,26 @@ public class SecurityContextHolderAwareRequestConfigTests {
MvcResult result = this.mvc.perform(get("/good-login")).andReturn(); MvcResult result = this.mvc.perform(get("/good-login")).andReturn();
MockHttpSession session = (MockHttpSession) result.getRequest().getSession(false); MockHttpSession session = (MockHttpSession) result.getRequest().getSession(false);
assertThat(session).isNotNull(); assertThat(session).isNotNull();
result = this.mvc.perform(get("/do-logout").session(session)).andExpect(status().isOk()) // @formatter:off
.andExpect(content().string("")).andReturn(); result = this.mvc.perform(get("/do-logout").session(session))
.andExpect(status().isOk())
.andExpect(content().string(""))
.andReturn();
// @formatter:on
session = (MockHttpSession) result.getRequest().getSession(false); session = (MockHttpSession) result.getRequest().getSession(false);
assertThat(session).isNotNull(); 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); session = (MockHttpSession) result.getRequest().getSession(false);
assertThat(session).isNotNull(); assertThat(session).isNotNull();
result = this.mvc.perform(get("/v2/do-logout").session(session)).andExpect(status().isOk()) // @formatter:off
.andExpect(content().string("")).andReturn(); 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); session = (MockHttpSession) result.getRequest().getSession(false);
assertThat(session).isNull(); assertThat(session).isNull();
} }
@ -143,11 +181,19 @@ public class SecurityContextHolderAwareRequestConfigTests {
this.spring.configLocations(this.xml("Logout")).autowire(); this.spring.configLocations(this.xml("Logout")).autowire();
this.mvc.perform(get("/authenticate")).andExpect(status().isFound()) this.mvc.perform(get("/authenticate")).andExpect(status().isFound())
.andExpect(redirectedUrl("http://localhost/signin")); .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); MockHttpSession session = (MockHttpSession) result.getRequest().getSession(false);
assertThat(session).isNotNull(); assertThat(session).isNotNull();
result = this.mvc.perform(get("/do-logout").session(session)).andExpect(status().isOk()) // @formatter:off
.andExpect(content().string("")).andExpect(cookie().maxAge("JSESSIONID", 0)).andReturn(); 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); session = (MockHttpSession) result.getRequest().getSession(false);
assertThat(session).isNotNull(); assertThat(session).isNotNull();
} }
@ -159,7 +205,10 @@ public class SecurityContextHolderAwareRequestConfigTests {
@WithMockUser @WithMockUser
public void servletIsUserInRoleWhenUsingDefaultConfigThenRoleIsSet() throws Exception { public void servletIsUserInRoleWhenUsingDefaultConfigThenRoleIsSet() throws Exception {
this.spring.configLocations(this.xml("Simple")).autowire(); 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) { 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.*" }) @PowerMockIgnore({ "org.w3c.dom.*", "org.xml.sax.*", "org.apache.xerces.*", "javax.xml.parsers.*" })
public class SessionManagementConfigServlet31Tests { public class SessionManagementConfigServlet31Tests {
private static final String XML_AUTHENTICATION_MANAGER = "<authentication-manager>" + " <authentication-provider>" // @formatter:off
+ " <user-service>" + " <user name='user' password='{noop}password' authorities='ROLE_USER' />" private static final String XML_AUTHENTICATION_MANAGER = "<authentication-manager>"
+ " </user-service>" + " </authentication-provider>" + "</authentication-manager>"; + " <authentication-provider>"
+ " <user-service>"
+ " <user name='user' password='{noop}password' authorities='ROLE_USER' />"
+ " </user-service>"
+ " </authentication-provider>"
+ "</authentication-manager>";
// @formatter:on
@Mock @Mock
Method method; Method method;
@ -92,8 +98,14 @@ public class SessionManagementConfigServlet31Tests {
request.setParameter("password", "password"); request.setParameter("password", "password");
request.getSession().setAttribute("attribute1", "value1"); request.getSession().setAttribute("attribute1", "value1");
String id = request.getSession().getId(); String id = request.getSession().getId();
loadContext("<http>\n" + " <form-login/>\n" + " <session-management/>\n" // @formatter:off
+ " <csrf disabled='true'/>\n" + " </http>" + XML_AUTHENTICATION_MANAGER); 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); this.springSecurityFilterChain.doFilter(request, this.response, this.chain);
assertThat(request.getSession().getId()).isNotEqualTo(id); assertThat(request.getSession().getId()).isNotEqualTo(id);
assertThat(request.getSession().getAttribute("attribute1")).isEqualTo("value1"); assertThat(request.getSession().getAttribute("attribute1")).isEqualTo("value1");
@ -108,9 +120,14 @@ public class SessionManagementConfigServlet31Tests {
request.setParameter("username", "user"); request.setParameter("username", "user");
request.setParameter("password", "password"); request.setParameter("password", "password");
String id = request.getSession().getId(); 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" + " <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); this.springSecurityFilterChain.doFilter(request, this.response, this.chain);
assertThat(request.getSession().getId()).isNotEqualTo(id); 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.MockMvc;
import org.springframework.test.web.servlet.MvcResult; import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.ResultMatcher; 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.GetMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.WebApplicationContext;
@ -91,7 +92,7 @@ public class SessionManagementConfigTests {
@Test @Test
public void requestWhenCreateSessionAlwaysThenAlwaysCreatesSession() throws Exception { public void requestWhenCreateSessionAlwaysThenAlwaysCreatesSession() throws Exception {
this.spring.configLocations(this.xml("CreateSessionAlways")).autowire(); this.spring.configLocations(xml("CreateSessionAlways")).autowire();
MockHttpServletRequest request = get("/").buildRequest(this.servletContext()); MockHttpServletRequest request = get("/").buildRequest(this.servletContext());
MockHttpServletResponse response = request(request, this.spring.getContext()); MockHttpServletResponse response = request(request, this.spring.getContext());
assertThat(response.getStatus()).isEqualTo(HttpStatus.SC_OK); assertThat(response.getStatus()).isEqualTo(HttpStatus.SC_OK);
@ -100,7 +101,7 @@ public class SessionManagementConfigTests {
@Test @Test
public void requestWhenCreateSessionIsSetToNeverThenDoesNotCreateSessionOnLoginChallenge() throws Exception { 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()); MockHttpServletRequest request = get("/auth").buildRequest(this.servletContext());
MockHttpServletResponse response = request(request, this.spring.getContext()); MockHttpServletResponse response = request(request, this.spring.getContext());
assertThat(response.getStatus()).isEqualTo(HttpStatus.SC_MOVED_TEMPORARILY); assertThat(response.getStatus()).isEqualTo(HttpStatus.SC_MOVED_TEMPORARILY);
@ -109,9 +110,13 @@ public class SessionManagementConfigTests {
@Test @Test
public void requestWhenCreateSessionIsSetToNeverThenDoesNotCreateSessionOnLogin() throws Exception { public void requestWhenCreateSessionIsSetToNeverThenDoesNotCreateSessionOnLogin() throws Exception {
this.spring.configLocations(this.xml("CreateSessionNever")).autowire(); this.spring.configLocations(xml("CreateSessionNever")).autowire();
MockHttpServletRequest request = post("/login").param("username", "user").param("password", "password") // @formatter:off
MockHttpServletRequest request = post("/login")
.param("username", "user")
.param("password", "password")
.buildRequest(this.servletContext()); .buildRequest(this.servletContext());
// @formatter:on
request = csrf().postProcessRequest(request); request = csrf().postProcessRequest(request);
MockHttpServletResponse response = request(request, this.spring.getContext()); MockHttpServletResponse response = request(request, this.spring.getContext());
assertThat(response.getStatus()).isEqualTo(HttpStatus.SC_MOVED_TEMPORARILY); assertThat(response.getStatus()).isEqualTo(HttpStatus.SC_MOVED_TEMPORARILY);
@ -120,9 +125,13 @@ public class SessionManagementConfigTests {
@Test @Test
public void requestWhenCreateSessionIsSetToNeverThenUsesExistingSession() throws Exception { public void requestWhenCreateSessionIsSetToNeverThenUsesExistingSession() throws Exception {
this.spring.configLocations(this.xml("CreateSessionNever")).autowire(); this.spring.configLocations(xml("CreateSessionNever")).autowire();
MockHttpServletRequest request = post("/login").param("username", "user").param("password", "password") // @formatter:off
MockHttpServletRequest request = post("/login")
.param("username", "user")
.param("password", "password")
.buildRequest(this.servletContext()); .buildRequest(this.servletContext());
// @formatter:on
request = csrf().postProcessRequest(request); request = csrf().postProcessRequest(request);
MockHttpSession session = new MockHttpSession(); MockHttpSession session = new MockHttpSession();
request.setSession(session); request.setSession(session);
@ -135,31 +144,48 @@ public class SessionManagementConfigTests {
@Test @Test
public void requestWhenCreateSessionIsSetToStatelessThenDoesNotCreateSessionOnLoginChallenge() throws Exception { public void requestWhenCreateSessionIsSetToStatelessThenDoesNotCreateSessionOnLoginChallenge() throws Exception {
this.spring.configLocations(this.xml("CreateSessionStateless")).autowire(); this.spring.configLocations(xml("CreateSessionStateless")).autowire();
this.mvc.perform(get("/auth")).andExpect(status().isFound()).andExpect(session().exists(false)); // @formatter:off
this.mvc.perform(get("/auth"))
.andExpect(status().isFound())
.andExpect(session().exists(false));
// @formatter:on
} }
@Test @Test
public void requestWhenCreateSessionIsSetToStatelessThenDoesNotCreateSessionOnLogin() throws Exception { public void requestWhenCreateSessionIsSetToStatelessThenDoesNotCreateSessionOnLogin() throws Exception {
this.spring.configLocations(this.xml("CreateSessionStateless")).autowire(); this.spring.configLocations(xml("CreateSessionStateless")).autowire();
this.mvc.perform(post("/login").param("username", "user").param("password", "password").with(csrf())) // @formatter:off
.andExpect(status().isFound()).andExpect(session().exists(false)); 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 @Test
public void requestWhenCreateSessionIsSetToStatelessThenIgnoresExistingSession() throws Exception { public void requestWhenCreateSessionIsSetToStatelessThenIgnoresExistingSession() throws Exception {
this.spring.configLocations(this.xml("CreateSessionStateless")).autowire(); this.spring.configLocations(xml("CreateSessionStateless")).autowire();
MvcResult result = this.mvc // @formatter:off
.perform(post("/login").param("username", "user").param("password", "password") MockHttpServletRequestBuilder loginRequest = post("/login")
.session(new MockHttpSession()).with(csrf())) .param("username", "user")
.andExpect(status().isFound()).andExpect(session()).andReturn(); .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) assertThat(result.getRequest().getSession(false)
.getAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY)).isNull(); .getAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY)).isNull();
} }
@Test @Test
public void requestWhenCreateSessionIsSetToIfRequiredThenDoesNotCreateSessionOnPublicInvocation() throws Exception { public void requestWhenCreateSessionIsSetToIfRequiredThenDoesNotCreateSessionOnPublicInvocation() throws Exception {
this.spring.configLocations(this.xml("CreateSessionIfRequired")).autowire(); this.spring.configLocations(xml("CreateSessionIfRequired")).autowire();
ServletContext servletContext = this.mvc.getDispatcherServlet().getServletContext(); ServletContext servletContext = this.mvc.getDispatcherServlet().getServletContext();
MockHttpServletRequest request = get("/").buildRequest(servletContext); MockHttpServletRequest request = get("/").buildRequest(servletContext);
MockHttpServletResponse response = request(request, this.spring.getContext()); MockHttpServletResponse response = request(request, this.spring.getContext());
@ -169,7 +195,7 @@ public class SessionManagementConfigTests {
@Test @Test
public void requestWhenCreateSessionIsSetToIfRequiredThenCreatesSessionOnLoginChallenge() throws Exception { public void requestWhenCreateSessionIsSetToIfRequiredThenCreatesSessionOnLoginChallenge() throws Exception {
this.spring.configLocations(this.xml("CreateSessionIfRequired")).autowire(); this.spring.configLocations(xml("CreateSessionIfRequired")).autowire();
ServletContext servletContext = this.mvc.getDispatcherServlet().getServletContext(); ServletContext servletContext = this.mvc.getDispatcherServlet().getServletContext();
MockHttpServletRequest request = get("/auth").buildRequest(servletContext); MockHttpServletRequest request = get("/auth").buildRequest(servletContext);
MockHttpServletResponse response = request(request, this.spring.getContext()); MockHttpServletResponse response = request(request, this.spring.getContext());
@ -179,10 +205,14 @@ public class SessionManagementConfigTests {
@Test @Test
public void requestWhenCreateSessionIsSetToIfRequiredThenCreatesSessionOnLogin() throws Exception { public void requestWhenCreateSessionIsSetToIfRequiredThenCreatesSessionOnLogin() throws Exception {
this.spring.configLocations(this.xml("CreateSessionIfRequired")).autowire(); this.spring.configLocations(xml("CreateSessionIfRequired")).autowire();
ServletContext servletContext = this.mvc.getDispatcherServlet().getServletContext(); 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); .buildRequest(servletContext);
// @formatter:on
request = csrf().postProcessRequest(request); request = csrf().postProcessRequest(request);
MockHttpServletResponse response = request(request, this.spring.getContext()); MockHttpServletResponse response = request(request, this.spring.getContext());
assertThat(response.getStatus()).isEqualTo(HttpStatus.SC_MOVED_TEMPORARILY); assertThat(response.getStatus()).isEqualTo(HttpStatus.SC_MOVED_TEMPORARILY);
@ -194,11 +224,15 @@ public class SessionManagementConfigTests {
*/ */
@Test @Test
public void requestWhenRejectingUserBasedOnMaxSessionsExceededThenDoesNotCreateSession() throws Exception { public void requestWhenRejectingUserBasedOnMaxSessionsExceededThenDoesNotCreateSession() throws Exception {
this.spring.configLocations(this.xml("Sec1208")).autowire(); this.spring.configLocations(xml("Sec1208")).autowire();
this.mvc.perform(get("/auth").with(httpBasic("user", "password"))).andExpect(status().isOk()) // @formatter:off
this.mvc.perform(get("/auth").with(httpBasic("user", "password")))
.andExpect(status().isOk())
.andExpect(session()); .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)); .andExpect(session().exists(false));
// @formatter:on
} }
/** /**
@ -207,40 +241,61 @@ public class SessionManagementConfigTests {
@Test @Test
public void requestWhenSessionFixationProtectionDisabledAndConcurrencyControlEnabledThenSessionNotInvalidated() public void requestWhenSessionFixationProtectionDisabledAndConcurrencyControlEnabledThenSessionNotInvalidated()
throws Exception { throws Exception {
this.spring.configLocations(this.xml("Sec2137")).autowire(); this.spring.configLocations(xml("Sec2137")).autowire();
MockHttpSession session = new MockHttpSession(); 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())); .andExpect(session().id(session.getId()));
// @formatter:on
} }
@Test @Test
public void autowireWhenExportingSessionRegistryBeanThenAvailableForWiring() { public void autowireWhenExportingSessionRegistryBeanThenAvailableForWiring() {
this.spring.configLocations(this.xml("ConcurrencyControlSessionRegistryAlias")).autowire(); this.spring.configLocations(xml("ConcurrencyControlSessionRegistryAlias")).autowire();
this.sessionRegistryIsValid(); this.sessionRegistryIsValid();
} }
@Test @Test
public void requestWhenExpiredUrlIsSetThenInvalidatesSessionAndRedirects() throws Exception { public void requestWhenExpiredUrlIsSetThenInvalidatesSessionAndRedirects() throws Exception {
this.spring.configLocations(this.xml("ConcurrencyControlExpiredUrl")).autowire(); this.spring.configLocations(xml("ConcurrencyControlExpiredUrl")).autowire();
this.mvc.perform(get("/auth").session(this.expiredSession()).with(httpBasic("user", "password"))) // @formatter:off
.andExpect(redirectedUrl("/expired")).andExpect(session().exists(false)); MockHttpServletRequestBuilder request = get("/auth")
.session(expiredSession())
.with(httpBasic("user", "password"));
this.mvc.perform(request)
.andExpect(redirectedUrl("/expired"))
.andExpect(session().exists(false));
// @formatter:on
} }
@Test @Test
public void requestWhenConcurrencyControlAndCustomLogoutHandlersAreSetThenAllAreInvokedWhenSessionExpires() public void requestWhenConcurrencyControlAndCustomLogoutHandlersAreSetThenAllAreInvokedWhenSessionExpires()
throws Exception { throws Exception {
this.spring.configLocations(this.xml("ConcurrencyControlLogoutAndRememberMeHandlers")).autowire(); this.spring.configLocations(xml("ConcurrencyControlLogoutAndRememberMeHandlers")).autowire();
this.mvc.perform(get("/auth").session(this.expiredSession()).with(httpBasic("user", "password"))) // @formatter:off
.andExpect(status().isOk()).andExpect(cookie().maxAge("testCookie", 0)) MockHttpServletRequestBuilder request = get("/auth")
.andExpect(cookie().exists("rememberMeCookie")).andExpect(session().valid(true)); .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 @Test
public void requestWhenConcurrencyControlAndRememberMeAreSetThenInvokedWhenSessionExpires() throws Exception { public void requestWhenConcurrencyControlAndRememberMeAreSetThenInvokedWhenSessionExpires() throws Exception {
this.spring.configLocations(this.xml("ConcurrencyControlRememberMeHandler")).autowire(); this.spring.configLocations(xml("ConcurrencyControlRememberMeHandler")).autowire();
this.mvc.perform(get("/auth").session(this.expiredSession()).with(httpBasic("user", "password"))) // @formatter:off
MockHttpServletRequestBuilder request = get("/auth")
.session(expiredSession())
.with(httpBasic("user", "password"));
this.mvc.perform(request)
.andExpect(status().isOk()).andExpect(cookie().exists("rememberMeCookie")) .andExpect(status().isOk()).andExpect(cookie().exists("rememberMeCookie"))
.andExpect(session().exists(false)); .andExpect(session().exists(false));
// @formatter:on
} }
/** /**
@ -248,77 +303,104 @@ public class SessionManagementConfigTests {
*/ */
@Test @Test
public void autowireWhenConcurrencyControlIsSetThenLogoutHandlersGetAuthenticationObject() throws Exception { public void autowireWhenConcurrencyControlIsSetThenLogoutHandlersGetAuthenticationObject() throws Exception {
this.spring.configLocations(this.xml("ConcurrencyControlCustomLogoutHandler")).autowire(); this.spring.configLocations(xml("ConcurrencyControlCustomLogoutHandler")).autowire();
MvcResult result = this.mvc.perform(get("/auth").with(httpBasic("user", "password"))).andExpect(session()) MvcResult result = this.mvc.perform(get("/auth").with(httpBasic("user", "password")))
.andExpect(session())
.andReturn(); .andReturn();
MockHttpSession session = (MockHttpSession) result.getRequest().getSession(false); MockHttpSession session = (MockHttpSession) result.getRequest().getSession(false);
SessionRegistry sessionRegistry = this.spring.getContext().getBean(SessionRegistry.class); SessionRegistry sessionRegistry = this.spring.getContext().getBean(SessionRegistry.class);
sessionRegistry.getSessionInformation(session.getId()).expireNow(); 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 @Test
public void requestWhenConcurrencyControlIsSetThenDefaultsToResponseBodyExpirationResponse() throws Exception { public void requestWhenConcurrencyControlIsSetThenDefaultsToResponseBodyExpirationResponse() throws Exception {
this.spring.configLocations(this.xml("ConcurrencyControlSessionRegistryAlias")).autowire(); this.spring.configLocations(xml("ConcurrencyControlSessionRegistryAlias")).autowire();
this.mvc.perform(get("/auth").session(this.expiredSession()).with(httpBasic("user", "password"))) // @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 " .andExpect(content().string("This session has been expired (possibly due to multiple concurrent "
+ "logins being attempted as the same user).")); + "logins being attempted as the same user)."));
// @formatter:on
} }
@Test @Test
public void requestWhenCustomSessionAuthenticationStrategyThenInvokesOnAuthentication() throws Exception { public void requestWhenCustomSessionAuthenticationStrategyThenInvokesOnAuthentication() throws Exception {
this.spring.configLocations(this.xml("SessionAuthenticationStrategyRef")).autowire(); this.spring.configLocations(xml("SessionAuthenticationStrategyRef")).autowire();
this.mvc.perform(get("/auth").with(httpBasic("user", "password"))).andExpect(status().isIAmATeapot()); // @formatter:off
this.mvc.perform(get("/auth").with(httpBasic("user", "password")))
.andExpect(status().isIAmATeapot());
// @formatter:on
} }
@Test @Test
public void autowireWhenSessionRegistryRefIsSetThenAvailableForWiring() { public void autowireWhenSessionRegistryRefIsSetThenAvailableForWiring() {
this.spring.configLocations(this.xml("ConcurrencyControlSessionRegistryRef")).autowire(); this.spring.configLocations(xml("ConcurrencyControlSessionRegistryRef")).autowire();
this.sessionRegistryIsValid(); this.sessionRegistryIsValid();
} }
@Test @Test
public void requestWhenMaxSessionsIsSetThenErrorsWhenExceeded() throws Exception { public void requestWhenMaxSessionsIsSetThenErrorsWhenExceeded() throws Exception {
this.spring.configLocations(this.xml("ConcurrencyControlMaxSessions")).autowire(); this.spring.configLocations(xml("ConcurrencyControlMaxSessions")).autowire();
this.mvc.perform(get("/auth").with(httpBasic("user", "password"))).andExpect(status().isOk()); // @formatter:off
this.mvc.perform(get("/auth").with(httpBasic("user", "password"))).andExpect(status().isOk()); this.mvc.perform(get("/auth").with(httpBasic("user", "password")))
this.mvc.perform(get("/auth").with(httpBasic("user", "password"))).andExpect(redirectedUrl("/max-exceeded")); .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 @Test
public void autowireWhenSessionFixationProtectionIsNoneAndCsrfDisabledThenSessionManagementFilterIsNotWired() { public void autowireWhenSessionFixationProtectionIsNoneAndCsrfDisabledThenSessionManagementFilterIsNotWired() {
this.spring.configLocations(this.xml("NoSessionManagementFilter")).autowire(); this.spring.configLocations(xml("NoSessionManagementFilter")).autowire();
assertThat(this.getFilter(SessionManagementFilter.class)).isNull(); assertThat(this.getFilter(SessionManagementFilter.class)).isNull();
} }
@Test @Test
public void requestWhenSessionFixationProtectionIsNoneThenSessionNotInvalidated() throws Exception { public void requestWhenSessionFixationProtectionIsNoneThenSessionNotInvalidated() throws Exception {
this.spring.configLocations(this.xml("SessionFixationProtectionNone")).autowire(); this.spring.configLocations(xml("SessionFixationProtectionNone")).autowire();
MockHttpSession session = new MockHttpSession(); MockHttpSession session = new MockHttpSession();
String sessionId = session.getId(); String sessionId = session.getId();
// @formatter:off
this.mvc.perform(get("/auth").session(session).with(httpBasic("user", "password"))) this.mvc.perform(get("/auth").session(session).with(httpBasic("user", "password")))
.andExpect(session().id(sessionId)); .andExpect(session().id(sessionId));
// @formatter:on
} }
@Test @Test
public void requestWhenSessionFixationProtectionIsMigrateSessionThenSessionIsReplaced() throws Exception { public void requestWhenSessionFixationProtectionIsMigrateSessionThenSessionIsReplaced() throws Exception {
this.spring.configLocations(this.xml("SessionFixationProtectionMigrateSession")).autowire(); this.spring.configLocations(xml("SessionFixationProtectionMigrateSession")).autowire();
MockHttpSession session = new MockHttpSession(); MockHttpSession session = new MockHttpSession();
String sessionId = session.getId(); String sessionId = session.getId();
// @formatter:off
MvcResult result = this.mvc.perform(get("/auth").session(session).with(httpBasic("user", "password"))) 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); assertThat(result.getRequest().getSession(false).getId()).isNotEqualTo(sessionId);
} }
@Test @Test
public void requestWhenSessionFixationProtectionIsNoneAndInvalidSessionUrlIsSetThenStillRedirectsOnInvalidSession() public void requestWhenSessionFixationProtectionIsNoneAndInvalidSessionUrlIsSetThenStillRedirectsOnInvalidSession()
throws Exception { throws Exception {
this.spring.configLocations(this.xml("SessionFixationProtectionNoneWithInvalidSessionUrl")).autowire(); this.spring.configLocations(xml("SessionFixationProtectionNoneWithInvalidSessionUrl")).autowire();
this.mvc.perform(get("/auth").with((request) -> { // @formatter:off
MockHttpServletRequestBuilder request = get("/auth")
.with((request) -> {
request.setRequestedSessionId("1"); request.setRequestedSessionId("1");
request.setRequestedSessionIdValid(false); request.setRequestedSessionIdValid(false);
return request; return request;
})).andExpect(redirectedUrl("/timeoutUrl")); });
this.mvc.perform(request)
.andExpect(redirectedUrl("/timeoutUrl"));
// @formatter:on
} }
private void sessionRegistryIsValid() { private void sessionRegistryIsValid() {
@ -367,7 +449,7 @@ public class SessionManagementConfigTests {
*/ */
@Test @Test
public void checkConcurrencyAndLogoutFilterHasSameSizeAndHasLogoutSuccessEventPublishingLogoutHandler() { public void checkConcurrencyAndLogoutFilterHasSameSizeAndHasLogoutSuccessEventPublishingLogoutHandler() {
this.spring.configLocations(this.xml("ConcurrencyControlLogoutAndRememberMeHandlers")).autowire(); this.spring.configLocations(xml("ConcurrencyControlLogoutAndRememberMeHandlers")).autowire();
ConcurrentSessionFilter concurrentSessionFilter = getFilter(ConcurrentSessionFilter.class); ConcurrentSessionFilter concurrentSessionFilter = getFilter(ConcurrentSessionFilter.class);
LogoutFilter logoutFilter = getFilter(LogoutFilter.class); LogoutFilter logoutFilter = getFilter(LogoutFilter.class);
LogoutHandler csfLogoutHandler = getFieldValue(concurrentSessionFilter, "handlers"); LogoutHandler csfLogoutHandler = getFieldValue(concurrentSessionFilter, "handlers");

View File

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

View File

@ -40,9 +40,12 @@ public class Jsr250AnnotationDrivenBeanDefinitionParserTests {
@Before @Before
public void loadContext() { public void loadContext() {
// @formatter:off
this.appContext = new InMemoryXmlApplicationContext( this.appContext = new InMemoryXmlApplicationContext(
"<b:bean id='target' class='org.springframework.security.access.annotation.Jsr250BusinessServiceImpl'/>" "<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"); 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"; 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" 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" + " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
+ "\t\txmlns=\"http://www.springframework.org/schema/security\"\n" + "\t\txsi:schemaLocation=\"\n" + " xmlns=\"http://www.springframework.org/schema/security\"\n"
+ "\t\t\thttp://www.springframework.org/schema/security\n" + " xsi:schemaLocation=\"\n"
+ "\t\t\thttps://www.springframework.org/schema/security/spring-security.xsd\n" + " http://www.springframework.org/schema/security\n"
+ "\t\t\thttp://www.springframework.org/schema/beans\n" + " https://www.springframework.org/schema/security/spring-security.xsd\n"
+ "\t\t\thttps://www.springframework.org/schema/beans/spring-beans.xsd\">\n" + "\n" + " http://www.springframework.org/schema/beans\n"
+ "\t<client-registrations>\n" + " https://www.springframework.org/schema/beans/spring-beans.xsd\">\n"
+ "\t\t<client-registration registration-id=\"google-login\" client-id=\"google-client-id\" \n" + "\n"
+ "\t\t\t\t\t\t\t client-secret=\"google-client-secret\" provider-id=\"google\"/>\n" + " <client-registrations>\n"
+ "\t\t<provider provider-id=\"google\" issuer-uri=\"${issuer-uri}\"/>\n" + "\t</client-registrations>\n" + " <client-registration registration-id=\"google-login\" client-id=\"google-client-id\" \n"
+ "\n" + "</b:beans>\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" private static final String OIDC_DISCOVERY_RESPONSE = "{\n"
+ " \"authorization_endpoint\": \"https://example.com/o/oauth2/v2/auth\", \n" + " \"authorization_endpoint\": \"https://example.com/o/oauth2/v2/auth\", \n"
+ " \"claims_supported\": [\n" + " \"aud\", \n" + " \"email\", \n" + " \"claims_supported\": [\n"
+ " \"email_verified\", \n" + " \"exp\", \n" + " \"family_name\", \n" + " \"aud\", \n"
+ " \"given_name\", \n" + " \"iat\", \n" + " \"iss\", \n" + " \"locale\", \n" + " \"email\", \n"
+ " \"name\", \n" + " \"picture\", \n" + " \"sub\"\n" + " ], \n" + " \"email_verified\", \n"
+ " \"code_challenge_methods_supported\": [\n" + " \"plain\", \n" + " \"S256\"\n" + " \"exp\", \n"
+ " ], \n" + " \"id_token_signing_alg_values_supported\": [\n" + " \"RS256\"\n" + " ], \n" + " \"family_name\", \n"
+ " \"issuer\": \"${issuer-uri}\", \n" + " \"jwks_uri\": \"https://example.com/oauth2/v3/certs\", \n" + " \"given_name\", \n"
+ " \"response_types_supported\": [\n" + " \"code\", \n" + " \"token\", \n" + " \"iat\", \n"
+ " \"id_token\", \n" + " \"code token\", \n" + " \"code id_token\", \n" + " \"iss\", \n"
+ " \"token id_token\", \n" + " \"code token id_token\", \n" + " \"none\"\n" + " \"locale\", \n"
+ " ], \n" + " \"revocation_endpoint\": \"https://example.com/o/oauth2/revoke\", \n" + " \"name\", \n"
+ " \"scopes_supported\": [\n" + " \"openid\", \n" + " \"email\", \n" + " \"picture\", \n"
+ " \"profile\"\n" + " ], \n" + " \"subject_types_supported\": [\n" + " \"public\"\n" + " \"sub\"\n"
+ " ], \n" + " \"grant_types_supported\" : [\"authorization_code\"], \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\": \"https://example.com/oauth2/v4/token\", \n"
+ " \"token_endpoint_auth_methods_supported\": [\n" + " \"client_secret_post\", \n" + " \"token_endpoint_auth_methods_supported\": [\n"
+ " \"client_secret_basic\", \n" + " \"none\"\n" + " ], \n" + " \"client_secret_post\", \n"
+ " \"userinfo_endpoint\": \"https://example.com/oauth2/v3/userinfo\"\n" + "}"; + " \"client_secret_basic\", \n"
+ " \"none\"\n"
+ " ], \n"
+ " \"userinfo_endpoint\": \"https://example.com/oauth2/v3/userinfo\"\n"
+ "}";
// @formatter:on
@Autowired @Autowired
private ClientRegistrationRepository clientRegistrationRepository; private ClientRegistrationRepository clientRegistrationRepository;
@ -183,7 +224,10 @@ public class ClientRegistrationsBeanDefinitionParserTests {
} }
private static String xml(String configName) { 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.setServletConfig(new MockServletConfig());
this.context.refresh(); this.context.refresh();
if (this.context.containsBean(BeanIds.SPRING_SECURITY_FILTER_CHAIN)) { if (this.context.containsBean(BeanIds.SPRING_SECURITY_FILTER_CHAIN)) {
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context).apply(springSecurity()) // @formatter:off
.apply(new AddFilter()).build(); MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(this.context).
apply(springSecurity())
.apply(new AddFilter())
.build();
// @formatter:on
this.context.getBeanFactory().registerResolvableDependency(MockMvc.class, mockMvc); this.context.getBeanFactory().registerResolvableDependency(MockMvc.class, mockMvc);
} }
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor(); AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();

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