1
0
mirror of synced 2026-08-31 22:46:02 +00:00

Reformat code using spring-javaformat

Run `./gradlew format` to reformat all java files.

Issue gh-8945
This commit is contained in:
Phillip Webb
2020-08-10 16:39:17 -05:00
committed by Rob Winch
parent 81d9c6cac5
commit b7fc18262d
2487 changed files with 41506 additions and 46548 deletions
@@ -49,6 +49,7 @@ import static org.springframework.security.test.web.servlet.request.SecurityMock
import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated;
public class LdapAuthenticationProviderBuilderSecurityBuilderTests {
@Rule
public final SpringTestRule spring = new SpringTestRule();
@@ -74,6 +75,7 @@ public class LdapAuthenticationProviderBuilderSecurityBuilderTests {
@EnableWebSecurity
static class DefaultLdapConfig extends BaseLdapProviderConfig {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
@@ -82,6 +84,7 @@ public class LdapAuthenticationProviderBuilderSecurityBuilderTests {
.userDnPatterns("uid={0},ou=people");
// @formatter:on
}
}
@Test
@@ -89,11 +92,13 @@ public class LdapAuthenticationProviderBuilderSecurityBuilderTests {
this.spring.register(GroupRolesConfig.class).autowire();
LdapAuthenticationProvider provider = ldapProvider();
assertThat(ReflectionTestUtils.getField(getAuthoritiesPopulator(provider), "groupRoleAttribute")).isEqualTo("group");
assertThat(ReflectionTestUtils.getField(getAuthoritiesPopulator(provider), "groupRoleAttribute"))
.isEqualTo("group");
}
@EnableWebSecurity
static class GroupRolesConfig extends BaseLdapProviderConfig {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
@@ -103,6 +108,7 @@ public class LdapAuthenticationProviderBuilderSecurityBuilderTests {
.groupRoleAttribute("group");
// @formatter:on
}
}
@Test
@@ -110,11 +116,13 @@ public class LdapAuthenticationProviderBuilderSecurityBuilderTests {
this.spring.register(GroupSearchConfig.class).autowire();
LdapAuthenticationProvider provider = ldapProvider();
assertThat(ReflectionTestUtils.getField(getAuthoritiesPopulator(provider), "groupSearchFilter")).isEqualTo("ou=groupName");
assertThat(ReflectionTestUtils.getField(getAuthoritiesPopulator(provider), "groupSearchFilter"))
.isEqualTo("ou=groupName");
}
@EnableWebSecurity
static class GroupSearchConfig extends BaseLdapProviderConfig {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
@@ -124,6 +132,7 @@ public class LdapAuthenticationProviderBuilderSecurityBuilderTests {
.groupSearchFilter("ou=groupName");
// @formatter:on
}
}
@Test
@@ -137,6 +146,7 @@ public class LdapAuthenticationProviderBuilderSecurityBuilderTests {
@EnableWebSecurity
static class GroupSubtreeSearchConfig extends BaseLdapProviderConfig {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
@@ -147,6 +157,7 @@ public class LdapAuthenticationProviderBuilderSecurityBuilderTests {
.groupSearchSubtree(true);
// @formatter:on
}
}
@Test
@@ -159,6 +170,7 @@ public class LdapAuthenticationProviderBuilderSecurityBuilderTests {
@EnableWebSecurity
static class RolePrefixConfig extends BaseLdapProviderConfig {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
@@ -168,18 +180,20 @@ public class LdapAuthenticationProviderBuilderSecurityBuilderTests {
.rolePrefix("role_");
// @formatter:on
}
}
@Test
public void bindAuthentication() throws Exception {
this.spring.register(BindAuthenticationConfig.class).autowire();
this.mockMvc.perform(formLogin().user("bob").password("bobspassword"))
.andExpect(authenticated().withUsername("bob").withAuthorities(singleton(new SimpleGrantedAuthority("ROLE_DEVELOPERS"))));
this.mockMvc.perform(formLogin().user("bob").password("bobspassword")).andExpect(authenticated()
.withUsername("bob").withAuthorities(singleton(new SimpleGrantedAuthority("ROLE_DEVELOPERS"))));
}
@EnableWebSecurity
static class BindAuthenticationConfig extends BaseLdapServerConfig {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
@@ -190,6 +204,7 @@ public class LdapAuthenticationProviderBuilderSecurityBuilderTests {
.userDnPatterns("uid={0},ou=people");
// @formatter:on
}
}
// SEC-2472
@@ -197,12 +212,13 @@ public class LdapAuthenticationProviderBuilderSecurityBuilderTests {
public void canUseCryptoPasswordEncoder() throws Exception {
this.spring.register(PasswordEncoderConfig.class).autowire();
this.mockMvc.perform(formLogin().user("bcrypt").password("password"))
.andExpect(authenticated().withUsername("bcrypt").withAuthorities(singleton(new SimpleGrantedAuthority("ROLE_DEVELOPERS"))));
this.mockMvc.perform(formLogin().user("bcrypt").password("password")).andExpect(authenticated()
.withUsername("bcrypt").withAuthorities(singleton(new SimpleGrantedAuthority("ROLE_DEVELOPERS"))));
}
@EnableWebSecurity
static class PasswordEncoderConfig extends BaseLdapServerConfig {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
@@ -214,10 +230,12 @@ public class LdapAuthenticationProviderBuilderSecurityBuilderTests {
.userDnPatterns("uid={0},ou=people");
// @formatter:on
}
}
private LdapAuthenticationProvider ldapProvider() {
return ((List<LdapAuthenticationProvider>) ReflectionTestUtils.getField(authenticationManager, "providers")).get(0);
return ((List<LdapAuthenticationProvider>) ReflectionTestUtils.getField(authenticationManager, "providers"))
.get(0);
}
private LdapAuthoritiesPopulator getAuthoritiesPopulator(LdapAuthenticationProvider provider) {
@@ -230,12 +248,15 @@ public class LdapAuthenticationProviderBuilderSecurityBuilderTests {
@EnableWebSecurity
static abstract class BaseLdapServerConfig extends BaseLdapProviderConfig {
@Bean
public ApacheDSContainer ldapServer() throws Exception {
ApacheDSContainer apacheDSContainer = new ApacheDSContainer("dc=springframework,dc=org", "classpath:/test-server.ldif");
ApacheDSContainer apacheDSContainer = new ApacheDSContainer("dc=springframework,dc=org",
"classpath:/test-server.ldif");
apacheDSContainer.setPort(getPort());
return apacheDSContainer;
}
}
@EnableWebSecurity
@@ -260,6 +281,7 @@ public class LdapAuthenticationProviderBuilderSecurityBuilderTests {
}
abstract protected void configure(AuthenticationManagerBuilder auth) throws Exception;
}
static Integer port;
@@ -272,4 +294,5 @@ public class LdapAuthenticationProviderBuilderSecurityBuilderTests {
}
return port;
}
}
@@ -34,6 +34,7 @@ import static org.springframework.security.test.web.servlet.request.SecurityMock
import static org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated;
public class LdapAuthenticationProviderConfigurerTests {
@Rule
public final SpringTestRule spring = new SpringTestRule();
@@ -41,7 +42,8 @@ public class LdapAuthenticationProviderConfigurerTests {
private MockMvc mockMvc;
@Test
public void authenticationManagerSupportMultipleDefaultLdapContextsWithPortsDynamicallyAllocated() throws Exception {
public void authenticationManagerSupportMultipleDefaultLdapContextsWithPortsDynamicallyAllocated()
throws Exception {
this.spring.register(MultiLdapAuthenticationProvidersConfig.class).autowire();
this.mockMvc.perform(formLogin().user("bob").password("bobspassword"))
@@ -52,16 +54,16 @@ public class LdapAuthenticationProviderConfigurerTests {
public void authenticationManagerSupportMultipleLdapContextWithDefaultRolePrefix() throws Exception {
this.spring.register(MultiLdapAuthenticationProvidersConfig.class).autowire();
this.mockMvc.perform(formLogin().user("bob").password("bobspassword"))
.andExpect(authenticated().withUsername("bob").withAuthorities(singleton(new SimpleGrantedAuthority("ROLE_DEVELOPERS"))));
this.mockMvc.perform(formLogin().user("bob").password("bobspassword")).andExpect(authenticated()
.withUsername("bob").withAuthorities(singleton(new SimpleGrantedAuthority("ROLE_DEVELOPERS"))));
}
@Test
public void authenticationManagerSupportMultipleLdapContextWithCustomRolePrefix() throws Exception {
this.spring.register(MultiLdapWithCustomRolePrefixAuthenticationProvidersConfig.class).autowire();
this.mockMvc.perform(formLogin().user("bob").password("bobspassword"))
.andExpect(authenticated().withUsername("bob").withAuthorities(singleton(new SimpleGrantedAuthority("ROL_DEVELOPERS"))));
this.mockMvc.perform(formLogin().user("bob").password("bobspassword")).andExpect(authenticated()
.withUsername("bob").withAuthorities(singleton(new SimpleGrantedAuthority("ROL_DEVELOPERS"))));
}
@Test
@@ -83,6 +85,7 @@ public class LdapAuthenticationProviderConfigurerTests {
@EnableWebSecurity
static class MultiLdapAuthenticationProvidersConfig extends WebSecurityConfigurerAdapter {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
@@ -97,10 +100,12 @@ public class LdapAuthenticationProviderConfigurerTests {
.userDnPatterns("uid={0},ou=people");
// @formatter:on
}
}
@EnableWebSecurity
static class MultiLdapWithCustomRolePrefixAuthenticationProvidersConfig extends WebSecurityConfigurerAdapter {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
@@ -117,10 +122,12 @@ public class LdapAuthenticationProviderConfigurerTests {
.rolePrefix("RUOLO_");
// @formatter:on
}
}
@EnableWebSecurity
static class LdapWithRandomPortConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
@@ -133,10 +140,12 @@ public class LdapAuthenticationProviderConfigurerTests {
.port(0);
// @formatter:on
}
}
@EnableWebSecurity
static class GroupSubtreeSearchConfig extends BaseLdapProviderConfig {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
@@ -147,5 +156,7 @@ public class LdapAuthenticationProviderConfigurerTests {
.userDnPatterns("uid={0},ou=people");
// @formatter:on
}
}
}
@@ -64,14 +64,15 @@ public class NamespaceLdapAuthenticationProviderTests {
public void ldapAuthenticationProviderCustom() throws Exception {
this.spring.register(CustomLdapAuthenticationProviderConfig.class).autowire();
this.mockMvc.perform(formLogin().user("bob").password("bobspassword"))
.andExpect(authenticated().withAuthorities(Collections.singleton(new SimpleGrantedAuthority("PREFIX_DEVELOPERS"))));
this.mockMvc.perform(formLogin().user("bob").password("bobspassword")).andExpect(authenticated()
.withAuthorities(Collections.singleton(new SimpleGrantedAuthority("PREFIX_DEVELOPERS"))));
}
// SEC-2490
@Test
public void ldapAuthenticationProviderCustomLdapAuthoritiesPopulator() throws Exception {
LdapContextSource contextSource = new DefaultSpringSecurityContextSource("ldap://blah.example.com:789/dc=springframework,dc=org");
LdapContextSource contextSource = new DefaultSpringSecurityContextSource(
"ldap://blah.example.com:789/dc=springframework,dc=org");
CustomAuthoritiesPopulatorConfig.LAP = new DefaultLdapAuthoritiesPopulator(contextSource, null) {
@Override
protected Set<GrantedAuthority> getAdditionalRoles(DirContextOperations user, String username) {
@@ -81,8 +82,8 @@ public class NamespaceLdapAuthenticationProviderTests {
this.spring.register(CustomAuthoritiesPopulatorConfig.class).autowire();
this.mockMvc.perform(formLogin().user("bob").password("bobspassword"))
.andExpect(authenticated().withAuthorities(Collections.singleton(new SimpleGrantedAuthority("ROLE_EXTRA"))));
this.mockMvc.perform(formLogin().user("bob").password("bobspassword")).andExpect(
authenticated().withAuthorities(Collections.singleton(new SimpleGrantedAuthority("ROLE_EXTRA"))));
}
@Test
@@ -92,4 +93,5 @@ public class NamespaceLdapAuthenticationProviderTests {
this.mockMvc.perform(formLogin().user("bcrypt").password("password"))
.andExpect(authenticated().withUsername("bcrypt"));
}
}
@@ -27,8 +27,10 @@ import org.springframework.security.ldap.userdetails.PersonContextMapper;
*
*/
public class NamespaceLdapAuthenticationProviderTestsConfigs {
@EnableWebSecurity
static class LdapAuthenticationProviderConfig extends WebSecurityConfigurerAdapter {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
@@ -37,11 +39,12 @@ public class NamespaceLdapAuthenticationProviderTestsConfigs {
.userDnPatterns("uid={0},ou=people"); // ldap-server@user-dn-pattern
// @formatter:on
}
}
@EnableWebSecurity
static class CustomLdapAuthenticationProviderConfig extends
WebSecurityConfigurerAdapter {
static class CustomLdapAuthenticationProviderConfig extends WebSecurityConfigurerAdapter {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
@@ -65,10 +68,12 @@ public class NamespaceLdapAuthenticationProviderTestsConfigs {
;
// @formatter:on
}
}
@EnableWebSecurity
static class CustomAuthoritiesPopulatorConfig extends WebSecurityConfigurerAdapter {
static LdapAuthoritiesPopulator LAP;
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
@@ -79,10 +84,12 @@ public class NamespaceLdapAuthenticationProviderTestsConfigs {
.ldapAuthoritiesPopulator(LAP);
// @formatter:on
}
}
@EnableWebSecurity
static class PasswordCompareLdapConfig extends WebSecurityConfigurerAdapter {
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter:off
auth
@@ -94,5 +101,7 @@ public class NamespaceLdapAuthenticationProviderTestsConfigs {
.passwordAttribute("userPassword"); // ldap-authentication-provider/password-compare@password-attribute
// @formatter:on
}
}
}
@@ -27,15 +27,15 @@ public class HelloHandler implements SocketAcceptor {
@Override
public Mono<RSocket> accept(ConnectionSetupPayload setup, RSocket sendingSocket) {
return Mono.just(
new AbstractRSocket() {
@Override
public Mono<Payload> requestResponse(Payload payload) {
String data = payload.getDataUtf8();
payload.release();
System.out.println("Got " + data);
return Mono.just(ByteBufPayload.create("Hello " + data));
}
});
return Mono.just(new AbstractRSocket() {
@Override
public Mono<Payload> requestResponse(Payload payload) {
String data = payload.getDataUtf8();
payload.release();
System.out.println("Got " + data);
return Mono.just(ByteBufPayload.create("Hello " + data));
}
});
}
}
@@ -53,6 +53,7 @@ import static org.assertj.core.api.Assertions.assertThatCode;
@ContextConfiguration
@RunWith(SpringRunner.class)
public class HelloRSocketITests {
@Autowired
RSocketMessageHandler handler;
@@ -68,13 +69,9 @@ public class HelloRSocketITests {
@Before
public void setup() {
this.server = RSocketFactory.receive()
.frameDecoder(PayloadDecoder.ZERO_COPY)
.addSocketAcceptorPlugin(this.interceptor)
.acceptor(this.handler.responder())
.transport(TcpServerTransport.create("localhost", 0))
.start()
.block();
this.server = RSocketFactory.receive().frameDecoder(PayloadDecoder.ZERO_COPY)
.addSocketAcceptorPlugin(this.interceptor).acceptor(this.handler.responder())
.transport(TcpServerTransport.create("localhost", 0)).start().block();
}
@After
@@ -86,20 +83,14 @@ public class HelloRSocketITests {
@Test
public void retrieveMonoWhenSecureThenDenied() throws Exception {
this.requester = RSocketRequester.builder()
.rsocketStrategies(this.handler.getRSocketStrategies())
.connectTcp("localhost", this.server.address().getPort())
.block();
this.requester = RSocketRequester.builder().rsocketStrategies(this.handler.getRSocketStrategies())
.connectTcp("localhost", this.server.address().getPort()).block();
String data = "rob";
assertThatCode(() -> this.requester.route("secure.retrieve-mono")
.data(data)
.retrieveMono(String.class)
.block()
)
.isNotNull();
assertThatCode(() -> this.requester.route("secure.retrieve-mono").data(data).retrieveMono(String.class).block())
.isNotNull();
// FIXME: https://github.com/rsocket/rsocket-java/issues/686
// .isInstanceOf(RejectedSetupException.class);
// .isInstanceOf(RejectedSetupException.class);
assertThat(this.controller.payloads).isEmpty();
}
@@ -109,14 +100,11 @@ public class HelloRSocketITests {
this.requester = RSocketRequester.builder()
.setupMetadata(credentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.rsocketStrategies(this.handler.getRSocketStrategies())
.connectTcp("localhost", this.server.address().getPort())
.block();
.connectTcp("localhost", this.server.address().getPort()).block();
String data = "rob";
String hiRob = this.requester.route("secure.retrieve-mono")
.metadata(credentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.data(data)
.retrieveMono(String.class)
.block();
.metadata(credentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE).data(data)
.retrieveMono(String.class).block();
assertThat(hiRob).isEqualTo("Hi rob");
assertThat(this.controller.payloads).containsOnly(data);
@@ -140,9 +128,7 @@ public class HelloRSocketITests {
@Bean
public RSocketStrategies rsocketStrategies() {
return RSocketStrategies.builder()
.encoder(new BasicAuthenticationEncoder())
.build();
return RSocketStrategies.builder().encoder(new BasicAuthenticationEncoder()).build();
}
@Bean
@@ -156,10 +142,12 @@ public class HelloRSocketITests {
// @formatter:on
return new MapReactiveUserDetailsService(rob);
}
}
@Controller
static class ServerController {
private List<String> payloads = new ArrayList<>();
@MessageMapping("**")
@@ -171,6 +159,7 @@ public class HelloRSocketITests {
private void add(String p) {
this.payloads.add(p);
}
}
}
@@ -62,6 +62,7 @@ import static org.mockito.Mockito.when;
@ContextConfiguration
@RunWith(SpringRunner.class)
public class JwtITests {
@Autowired
RSocketMessageHandler handler;
@@ -80,13 +81,9 @@ public class JwtITests {
@Before
public void setup() {
this.server = RSocketFactory.receive()
.frameDecoder(PayloadDecoder.ZERO_COPY)
.addSocketAcceptorPlugin(this.interceptor)
.acceptor(this.handler.responder())
.transport(TcpServerTransport.create("localhost", 0))
.start()
.block();
this.server = RSocketFactory.receive().frameDecoder(PayloadDecoder.ZERO_COPY)
.addSocketAcceptorPlugin(this.interceptor).acceptor(this.handler.responder())
.transport(TcpServerTransport.create("localhost", 0)).start().block();
}
@After
@@ -98,18 +95,13 @@ public class JwtITests {
@Test
public void routeWhenBearerThenAuthorized() {
BearerTokenMetadata credentials =
new BearerTokenMetadata("token");
BearerTokenMetadata credentials = new BearerTokenMetadata("token");
when(this.decoder.decode(any())).thenReturn(Mono.just(jwt()));
this.requester = requester()
.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()).block();
String hiRob = this.requester.route("secure.retrieve-mono")
.data("rob")
.retrieveMono(String.class)
.block();
String hiRob = this.requester.route("secure.retrieve-mono").data("rob").retrieveMono(String.class).block();
assertThat(hiRob).isEqualTo("Hi rob");
}
@@ -118,36 +110,25 @@ public class JwtITests {
public void routeWhenAuthenticationBearerThenAuthorized() {
MimeType authenticationMimeType = MimeTypeUtils.parseMimeType(MESSAGE_RSOCKET_AUTHENTICATION.getString());
BearerTokenMetadata credentials =
new BearerTokenMetadata("token");
BearerTokenMetadata credentials = new BearerTokenMetadata("token");
when(this.decoder.decode(any())).thenReturn(Mono.just(jwt()));
this.requester = requester()
.setupMetadata(credentials, authenticationMimeType)
.connectTcp(this.server.address().getHostName(), this.server.address().getPort())
.block();
this.requester = requester().setupMetadata(credentials, authenticationMimeType)
.connectTcp(this.server.address().getHostName(), this.server.address().getPort()).block();
String hiRob = this.requester.route("secure.retrieve-mono")
.data("rob")
.retrieveMono(String.class)
.block();
String hiRob = this.requester.route("secure.retrieve-mono").data("rob").retrieveMono(String.class).block();
assertThat(hiRob).isEqualTo("Hi rob");
}
private Jwt jwt() {
return TestJwts.jwt()
.claim(IdTokenClaimNames.ISS, "https://issuer.example.com")
.claim(IdTokenClaimNames.SUB, "rob")
.claim(IdTokenClaimNames.AUD, Arrays.asList("client-id"))
.build();
return TestJwts.jwt().claim(IdTokenClaimNames.ISS, "https://issuer.example.com")
.claim(IdTokenClaimNames.SUB, "rob").claim(IdTokenClaimNames.AUD, Arrays.asList("client-id")).build();
}
private RSocketRequester.Builder requester() {
return RSocketRequester.builder()
.rsocketStrategies(this.handler.getRSocketStrategies());
return RSocketRequester.builder().rsocketStrategies(this.handler.getRSocketStrategies());
}
@Configuration
@EnableRSocketSecurity
static class Config {
@@ -166,20 +147,13 @@ public class JwtITests {
@Bean
public RSocketStrategies rsocketStrategies() {
return RSocketStrategies.builder()
.encoder(new BearerTokenAuthenticationEncoder())
.build();
return RSocketStrategies.builder().encoder(new BearerTokenAuthenticationEncoder()).build();
}
@Bean
PayloadSocketAcceptorInterceptor rsocketInterceptor(RSocketSecurity rsocket) {
rsocket
.authorizePayload(authorize ->
authorize
.anyRequest().authenticated()
.anyExchange().permitAll()
)
.jwt(Customizer.withDefaults());
rsocket.authorizePayload(authorize -> authorize.anyRequest().authenticated().anyExchange().permitAll())
.jwt(Customizer.withDefaults());
return rsocket.build();
}
@@ -187,16 +161,19 @@ public class JwtITests {
ReactiveJwtDecoder jwtDecoder() {
return mock(ReactiveJwtDecoder.class);
}
}
@Controller
static class ServerController {
private List<String> payloads = new ArrayList<>();
@MessageMapping("**")
String connect(String payload) {
return "Hi " + payload;
}
}
}
@@ -59,6 +59,7 @@ import static org.assertj.core.api.Assertions.assertThatCode;
@ContextConfiguration
@RunWith(SpringRunner.class)
public class RSocketMessageHandlerConnectionITests {
@Autowired
RSocketMessageHandler handler;
@@ -74,13 +75,9 @@ public class RSocketMessageHandlerConnectionITests {
@Before
public void setup() {
this.server = RSocketFactory.receive()
.frameDecoder(PayloadDecoder.ZERO_COPY)
.addSocketAcceptorPlugin(this.interceptor)
.acceptor(this.handler.responder())
.transport(TcpServerTransport.create("localhost", 0))
.start()
.block();
this.server = RSocketFactory.receive().frameDecoder(PayloadDecoder.ZERO_COPY)
.addSocketAcceptorPlugin(this.interceptor).acceptor(this.handler.responder())
.transport(TcpServerTransport.create("localhost", 0)).start().block();
}
@After
@@ -92,17 +89,11 @@ public class RSocketMessageHandlerConnectionITests {
@Test
public void routeWhenAuthorized() {
UsernamePasswordMetadata credentials =
new UsernamePasswordMetadata("user", "password");
this.requester = requester()
.setupMetadata(credentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.connectTcp(this.server.address().getHostName(), this.server.address().getPort())
.block();
UsernamePasswordMetadata credentials = new UsernamePasswordMetadata("user", "password");
this.requester = requester().setupMetadata(credentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.connectTcp(this.server.address().getHostName(), this.server.address().getPort()).block();
String hiRob = this.requester.route("secure.retrieve-mono")
.data("rob")
.retrieveMono(String.class)
.block();
String hiRob = this.requester.route("secure.retrieve-mono").data("rob").retrieveMono(String.class).block();
assertThat(hiRob).isEqualTo("Hi rob");
}
@@ -110,16 +101,11 @@ public class RSocketMessageHandlerConnectionITests {
@Test
public void routeWhenNotAuthorized() {
UsernamePasswordMetadata credentials = new UsernamePasswordMetadata("user", "password");
this.requester = requester()
.setupMetadata(credentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.connectTcp(this.server.address().getHostName(), this.server.address().getPort())
.block();
this.requester = requester().setupMetadata(credentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.connectTcp(this.server.address().getHostName(), this.server.address().getPort()).block();
assertThatCode(() -> this.requester.route("secure.admin.retrieve-mono")
.data("data")
.retrieveMono(String.class)
.block())
.isInstanceOf(ApplicationErrorException.class);
assertThatCode(() -> this.requester.route("secure.admin.retrieve-mono").data("data").retrieveMono(String.class)
.block()).isInstanceOf(ApplicationErrorException.class);
}
@Test
@@ -127,14 +113,12 @@ public class RSocketMessageHandlerConnectionITests {
UsernamePasswordMetadata connectCredentials = new UsernamePasswordMetadata("user", "password");
this.requester = requester()
.setupMetadata(connectCredentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.connectTcp(this.server.address().getHostName(), this.server.address().getPort())
.block();
.connectTcp(this.server.address().getHostName(), this.server.address().getPort()).block();
String hiRob = this.requester.route("secure.admin.retrieve-mono")
.metadata(new UsernamePasswordMetadata("admin", "password"), UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.data("rob")
.retrieveMono(String.class)
.block();
.metadata(new UsernamePasswordMetadata("admin", "password"),
UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.data("rob").retrieveMono(String.class).block();
assertThat(hiRob).isEqualTo("Hi rob");
}
@@ -144,105 +128,75 @@ public class RSocketMessageHandlerConnectionITests {
UsernamePasswordMetadata connectCredentials = new UsernamePasswordMetadata("user", "password");
this.requester = requester()
.setupMetadata(connectCredentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.connectTcp(this.server.address().getHostName(), this.server.address().getPort())
.block();
.connectTcp(this.server.address().getHostName(), this.server.address().getPort()).block();
String hiUser = this.requester.route("secure.authority.retrieve-mono")
.metadata(new UsernamePasswordMetadata("admin", "password"), UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.data("Felipe")
.retrieveMono(String.class)
.block();
.metadata(new UsernamePasswordMetadata("admin", "password"),
UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.data("Felipe").retrieveMono(String.class).block();
assertThat(hiUser).isEqualTo("Hi Felipe");
}
@Test
public void connectWhenNotAuthenticated() {
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();
assertThatCode(() -> this.requester.route("retrieve-mono")
.data("data")
.retrieveMono(String.class)
.block())
assertThatCode(() -> this.requester.route("retrieve-mono").data("data").retrieveMono(String.class).block())
.isNotNull();
// FIXME: https://github.com/rsocket/rsocket-java/issues/686
// .isInstanceOf(RejectedSetupException.class);
// .isInstanceOf(RejectedSetupException.class);
}
@Test
public void connectWhenNotAuthorized() {
UsernamePasswordMetadata credentials = new UsernamePasswordMetadata("evil", "password");
this.requester = requester()
.setupMetadata(credentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.connectTcp(this.server.address().getHostName(), this.server.address().getPort())
.block();
this.requester = requester().setupMetadata(credentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.connectTcp(this.server.address().getHostName(), this.server.address().getPort()).block();
assertThatCode(() -> this.requester.route("retrieve-mono")
.data("data")
.retrieveMono(String.class)
.block())
.isNotNull();
// FIXME: https://github.com/rsocket/rsocket-java/issues/686
// .isInstanceOf(RejectedSetupException.class);
assertThatCode(() -> this.requester.route("retrieve-mono").data("data").retrieveMono(String.class).block())
.isNotNull();
// FIXME: https://github.com/rsocket/rsocket-java/issues/686
// .isInstanceOf(RejectedSetupException.class);
}
@Test
public void connectionDenied() {
UsernamePasswordMetadata credentials = new UsernamePasswordMetadata("user", "password");
this.requester = requester()
.setupMetadata(credentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.connectTcp(this.server.address().getHostName(), this.server.address().getPort())
.block();
this.requester = requester().setupMetadata(credentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.connectTcp(this.server.address().getHostName(), this.server.address().getPort()).block();
assertThatCode(() -> this.requester.route("prohibit")
.data("data")
.retrieveMono(String.class)
.block())
assertThatCode(() -> this.requester.route("prohibit").data("data").retrieveMono(String.class).block())
.isInstanceOf(ApplicationErrorException.class);
}
@Test
public void connectWithAnyRole() {
UsernamePasswordMetadata credentials =
new UsernamePasswordMetadata("user", "password");
this.requester = requester()
.setupMetadata(credentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.connectTcp(this.server.address().getHostName(), this.server.address().getPort())
.block();
UsernamePasswordMetadata credentials = new UsernamePasswordMetadata("user", "password");
this.requester = requester().setupMetadata(credentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.connectTcp(this.server.address().getHostName(), this.server.address().getPort()).block();
String hiRob = this.requester.route("anyroute")
.data("rob")
.retrieveMono(String.class)
.block();
String hiRob = this.requester.route("anyroute").data("rob").retrieveMono(String.class).block();
assertThat(hiRob).isEqualTo("Hi rob");
}
@Test
public void connectWithAnyAuthority() {
UsernamePasswordMetadata credentials =
new UsernamePasswordMetadata("admin", "password");
this.requester = requester()
.setupMetadata(credentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.connectTcp(this.server.address().getHostName(), this.server.address().getPort())
.block();
UsernamePasswordMetadata credentials = new UsernamePasswordMetadata("admin", "password");
this.requester = requester().setupMetadata(credentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.connectTcp(this.server.address().getHostName(), this.server.address().getPort()).block();
String hiEbert = this.requester.route("management.users")
.data("admin")
.retrieveMono(String.class)
.block();
String hiEbert = this.requester.route("management.users").data("admin").retrieveMono(String.class).block();
assertThat(hiEbert).isEqualTo("Hi admin");
}
private RSocketRequester.Builder requester() {
return RSocketRequester.builder()
.rsocketStrategies(this.handler.getRSocketStrategies());
return RSocketRequester.builder().rsocketStrategies(this.handler.getRSocketStrategies());
}
@Configuration
@EnableRSocketSecurity
static class Config {
@@ -261,9 +215,7 @@ public class RSocketMessageHandlerConnectionITests {
@Bean
public RSocketStrategies rsocketStrategies() {
return RSocketStrategies.builder()
.encoder(new BasicAuthenticationEncoder())
.build();
return RSocketStrategies.builder().encoder(new BasicAuthenticationEncoder()).build();
}
@Bean
@@ -290,30 +242,25 @@ public class RSocketMessageHandlerConnectionITests {
@Bean
PayloadSocketAcceptorInterceptor rsocketInterceptor(RSocketSecurity rsocket) {
rsocket
.authorizePayload(authorize ->
authorize
.setup().hasRole("SETUP")
.route("secure.admin.*").hasRole("ADMIN")
.route("secure.**").hasRole("USER")
.route("secure.authority.*").hasAuthority("ROLE_USER")
.route("management.*").hasAnyAuthority("ROLE_ADMIN")
.route("prohibit").denyAll()
.anyRequest().permitAll()
)
.basicAuthentication(Customizer.withDefaults());
rsocket.authorizePayload(authorize -> authorize.setup().hasRole("SETUP").route("secure.admin.*")
.hasRole("ADMIN").route("secure.**").hasRole("USER").route("secure.authority.*")
.hasAuthority("ROLE_USER").route("management.*").hasAnyAuthority("ROLE_ADMIN").route("prohibit")
.denyAll().anyRequest().permitAll()).basicAuthentication(Customizer.withDefaults());
return rsocket.build();
}
}
@Controller
static class ServerController {
private List<String> payloads = new ArrayList<>();
@MessageMapping("**")
String connect(String payload) {
return "Hi " + payload;
}
}
}
@@ -59,6 +59,7 @@ import static org.assertj.core.api.Assertions.assertThatCode;
@ContextConfiguration
@RunWith(SpringRunner.class)
public class RSocketMessageHandlerITests {
@Autowired
RSocketMessageHandler handler;
@@ -74,19 +75,15 @@ public class RSocketMessageHandlerITests {
@Before
public void setup() {
this.server = RSocketFactory.receive()
.frameDecoder(PayloadDecoder.ZERO_COPY)
.addSocketAcceptorPlugin(this.interceptor)
.acceptor(this.handler.responder())
.transport(TcpServerTransport.create("localhost", 0))
.start()
.block();
this.server = RSocketFactory.receive().frameDecoder(PayloadDecoder.ZERO_COPY)
.addSocketAcceptorPlugin(this.interceptor).acceptor(this.handler.responder())
.transport(TcpServerTransport.create("localhost", 0)).start().block();
this.requester = RSocketRequester.builder()
// .rsocketFactory(factory -> factory.addRequesterPlugin(payloadInterceptor))
// .rsocketFactory(factory ->
// factory.addRequesterPlugin(payloadInterceptor))
.rsocketStrategies(this.handler.getRSocketStrategies())
.connectTcp("localhost", this.server.address().getPort())
.block();
.connectTcp("localhost", this.server.address().getPort()).block();
}
@After
@@ -99,12 +96,8 @@ public class RSocketMessageHandlerITests {
@Test
public void retrieveMonoWhenSecureThenDenied() throws Exception {
String data = "rob";
assertThatCode(() -> this.requester.route("secure.retrieve-mono")
.data(data)
.retrieveMono(String.class)
.block()
).isInstanceOf(ApplicationErrorException.class)
.hasMessageContaining("Access Denied");
assertThatCode(() -> this.requester.route("secure.retrieve-mono").data(data).retrieveMono(String.class).block())
.isInstanceOf(ApplicationErrorException.class).hasMessageContaining("Access Denied");
assertThat(this.controller.payloads).isEmpty();
}
@@ -114,12 +107,9 @@ public class RSocketMessageHandlerITests {
String data = "rob";
UsernamePasswordMetadata credentials = new UsernamePasswordMetadata("invalid", "password");
assertThatCode(() -> this.requester.route("secure.retrieve-mono")
.metadata(credentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.data(data)
.retrieveMono(String.class)
.block()
).isInstanceOf(ApplicationErrorException.class)
.hasMessageContaining("Invalid Credentials");
.metadata(credentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE).data(data)
.retrieveMono(String.class).block()).isInstanceOf(ApplicationErrorException.class)
.hasMessageContaining("Invalid Credentials");
assertThat(this.controller.payloads).isEmpty();
}
@@ -129,10 +119,8 @@ public class RSocketMessageHandlerITests {
String data = "rob";
UsernamePasswordMetadata credentials = new UsernamePasswordMetadata("rob", "password");
String hiRob = this.requester.route("secure.retrieve-mono")
.metadata(credentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE)
.data(data)
.retrieveMono(String.class)
.block();
.metadata(credentials, UsernamePasswordMetadata.BASIC_AUTHENTICATION_MIME_TYPE).data(data)
.retrieveMono(String.class).block();
assertThat(hiRob).isEqualTo("Hi rob");
assertThat(this.controller.payloads).containsOnly(data);
@@ -141,10 +129,7 @@ public class RSocketMessageHandlerITests {
@Test
public void retrieveMonoWhenPublicThenGranted() throws Exception {
String data = "rob";
String hiRob = this.requester.route("retrieve-mono")
.data(data)
.retrieveMono(String.class)
.block();
String hiRob = this.requester.route("retrieve-mono").data(data).retrieveMono(String.class).block();
assertThat(hiRob).isEqualTo("Hi rob");
assertThat(this.controller.payloads).containsOnly(data);
@@ -153,13 +138,9 @@ public class RSocketMessageHandlerITests {
@Test
public void retrieveFluxWhenDataFluxAndSecureThenDenied() throws Exception {
Flux<String> data = Flux.just("a", "b", "c");
assertThatCode(() -> this.requester.route("secure.retrieve-flux")
.data(data, String.class)
.retrieveFlux(String.class)
.collectList()
.block()
).isInstanceOf(ApplicationErrorException.class)
.hasMessageContaining("Access Denied");
assertThatCode(() -> this.requester.route("secure.retrieve-flux").data(data, String.class)
.retrieveFlux(String.class).collectList().block()).isInstanceOf(ApplicationErrorException.class)
.hasMessageContaining("Access Denied");
assertThat(this.controller.payloads).isEmpty();
}
@@ -167,11 +148,8 @@ public class RSocketMessageHandlerITests {
@Test
public void retrieveFluxWhenDataFluxAndPublicThenGranted() throws Exception {
Flux<String> data = Flux.just("a", "b", "c");
List<String> hi = this.requester.route("retrieve-flux")
.data(data, String.class)
.retrieveFlux(String.class)
.collectList()
.block();
List<String> hi = this.requester.route("retrieve-flux").data(data, String.class).retrieveFlux(String.class)
.collectList().block();
assertThat(hi).containsOnly("hello a", "hello b", "hello c");
assertThat(this.controller.payloads).containsOnlyElementsOf(data.collectList().block());
@@ -180,13 +158,9 @@ public class RSocketMessageHandlerITests {
@Test
public void retrieveFluxWhenDataStringAndSecureThenDenied() throws Exception {
String data = "a";
assertThatCode(() -> this.requester.route("secure.hello")
.data(data)
.retrieveFlux(String.class)
.collectList()
.block()
).isInstanceOf(ApplicationErrorException.class)
.hasMessageContaining("Access Denied");
assertThatCode(
() -> this.requester.route("secure.hello").data(data).retrieveFlux(String.class).collectList().block())
.isInstanceOf(ApplicationErrorException.class).hasMessageContaining("Access Denied");
assertThat(this.controller.payloads).isEmpty();
}
@@ -194,10 +168,7 @@ public class RSocketMessageHandlerITests {
@Test
public void sendWhenSecureThenDenied() throws Exception {
String data = "hi";
this.requester.route("secure.send")
.data(data)
.send()
.block();
this.requester.route("secure.send").data(data).send().block();
assertThat(this.controller.payloads).isEmpty();
}
@@ -205,10 +176,7 @@ public class RSocketMessageHandlerITests {
@Test
public void sendWhenPublicThenGranted() throws Exception {
String data = "hi";
this.requester.route("send")
.data(data)
.send()
.block();
this.requester.route("send").data(data).send().block();
assertThat(this.controller.awaitPayloads()).containsOnly("hi");
}
@@ -230,9 +198,7 @@ public class RSocketMessageHandlerITests {
@Bean
public RSocketStrategies rsocketStrategies() {
return RSocketStrategies.builder()
.encoder(new BasicAuthenticationEncoder())
.build();
return RSocketStrategies.builder().encoder(new BasicAuthenticationEncoder()).build();
}
@Bean
@@ -254,40 +220,35 @@ public class RSocketMessageHandlerITests {
@Bean
PayloadSocketAcceptorInterceptor rsocketInterceptor(RSocketSecurity rsocket) {
rsocket
.authorizePayload(authorize -> {
authorize
.route("secure.*").authenticated()
.anyExchange().permitAll();
})
.basicAuthentication(Customizer.withDefaults());
rsocket.authorizePayload(authorize -> {
authorize.route("secure.*").authenticated().anyExchange().permitAll();
}).basicAuthentication(Customizer.withDefaults());
return rsocket.build();
}
}
@Controller
static class ServerController {
private List<String> payloads = new ArrayList<>();
@MessageMapping({"secure.retrieve-mono", "retrieve-mono"})
@MessageMapping({ "secure.retrieve-mono", "retrieve-mono" })
String retrieveMono(String payload) {
add(payload);
return "Hi " + payload;
}
@MessageMapping({"secure.retrieve-flux", "retrieve-flux"})
@MessageMapping({ "secure.retrieve-flux", "retrieve-flux" })
Flux<String> retrieveFlux(Flux<String> payload) {
return payload.doOnNext(this::add)
.map(p -> "hello " + p);
return payload.doOnNext(this::add).map(p -> "hello " + p);
}
@MessageMapping({"secure.send", "send"})
@MessageMapping({ "secure.send", "send" })
Mono<Void> send(Mono<String> payload) {
return payload
.doOnNext(this::add)
.then(Mono.fromRunnable(() -> {
doNotifyAll();
}));
return payload.doOnNext(this::add).then(Mono.fromRunnable(() -> {
doNotifyAll();
}));
}
private synchronized void doNotifyAll() {
@@ -302,6 +263,7 @@ public class RSocketMessageHandlerITests {
private void add(String p) {
this.payloads.add(p);
}
}
}
@@ -59,6 +59,7 @@ import static org.assertj.core.api.Assertions.assertThatCode;
@ContextConfiguration
@RunWith(SpringRunner.class)
public class SimpleAuthenticationITests {
@Autowired
RSocketMessageHandler handler;
@@ -74,13 +75,9 @@ public class SimpleAuthenticationITests {
@Before
public void setup() {
this.server = RSocketFactory.receive()
.frameDecoder(PayloadDecoder.ZERO_COPY)
.addSocketAcceptorPlugin(this.interceptor)
.acceptor(this.handler.responder())
.transport(TcpServerTransport.create("localhost", 0))
.start()
.block();
this.server = RSocketFactory.receive().frameDecoder(PayloadDecoder.ZERO_COPY)
.addSocketAcceptorPlugin(this.interceptor).acceptor(this.handler.responder())
.transport(TcpServerTransport.create("localhost", 0)).start().block();
}
@After
@@ -92,18 +89,12 @@ public class SimpleAuthenticationITests {
@Test
public void retrieveMonoWhenSecureThenDenied() throws Exception {
this.requester = RSocketRequester.builder()
.rsocketStrategies(this.handler.getRSocketStrategies())
.connectTcp("localhost", this.server.address().getPort())
.block();
this.requester = RSocketRequester.builder().rsocketStrategies(this.handler.getRSocketStrategies())
.connectTcp("localhost", this.server.address().getPort()).block();
String data = "rob";
assertThatCode(() -> this.requester.route("secure.retrieve-mono")
.data(data)
.retrieveMono(String.class)
.block()
)
.isInstanceOf(ApplicationErrorException.class);
assertThatCode(() -> this.requester.route("secure.retrieve-mono").data(data).retrieveMono(String.class).block())
.isInstanceOf(ApplicationErrorException.class);
assertThat(this.controller.payloads).isEmpty();
}
@@ -112,17 +103,12 @@ public class SimpleAuthenticationITests {
MimeType authenticationMimeType = MimeTypeUtils.parseMimeType(MESSAGE_RSOCKET_AUTHENTICATION.getString());
UsernamePasswordMetadata credentials = new UsernamePasswordMetadata("rob", "password");
this.requester = RSocketRequester.builder()
.setupMetadata(credentials, authenticationMimeType)
this.requester = RSocketRequester.builder().setupMetadata(credentials, authenticationMimeType)
.rsocketStrategies(this.handler.getRSocketStrategies())
.connectTcp("localhost", this.server.address().getPort())
.block();
.connectTcp("localhost", this.server.address().getPort()).block();
String data = "rob";
String hiRob = this.requester.route("secure.retrieve-mono")
.metadata(credentials, authenticationMimeType)
.data(data)
.retrieveMono(String.class)
.block();
String hiRob = this.requester.route("secure.retrieve-mono").metadata(credentials, authenticationMimeType)
.data(data).retrieveMono(String.class).block();
assertThat(hiRob).isEqualTo("Hi rob");
assertThat(this.controller.payloads).containsOnly(data);
@@ -146,19 +132,12 @@ public class SimpleAuthenticationITests {
@Bean
public RSocketStrategies rsocketStrategies() {
return RSocketStrategies.builder()
.encoder(new SimpleAuthenticationEncoder())
.build();
return RSocketStrategies.builder().encoder(new SimpleAuthenticationEncoder()).build();
}
@Bean
PayloadSocketAcceptorInterceptor rsocketInterceptor(RSocketSecurity rsocket) {
rsocket
.authorizePayload(authorize ->
authorize
.anyRequest().authenticated()
.anyExchange().permitAll()
)
rsocket.authorizePayload(authorize -> authorize.anyRequest().authenticated().anyExchange().permitAll())
.simpleAuthentication(Customizer.withDefaults());
return rsocket.build();
}
@@ -174,10 +153,12 @@ public class SimpleAuthenticationITests {
// @formatter:on
return new MapReactiveUserDetailsService(rob);
}
}
@Controller
static class ServerController {
private List<String> payloads = new ArrayList<>();
@MessageMapping("**")
@@ -189,6 +170,7 @@ public class SimpleAuthenticationITests {
private void add(String p) {
this.payloads.add(p);
}
}
}
@@ -35,6 +35,7 @@ import org.springframework.security.ldap.userdetails.InetOrgPersonContextMapper;
import static org.assertj.core.api.Assertions.assertThat;
public class LdapProviderBeanDefinitionParserTests {
InMemoryXmlApplicationContext appCtx;
@After
@@ -48,13 +49,13 @@ public class LdapProviderBeanDefinitionParserTests {
@Test
public void simpleProviderAuthenticatesCorrectly() {
appCtx = new InMemoryXmlApplicationContext("<ldap-server ldif='classpath:test-server.ldif' port='0'/>"
+ "<authentication-manager>"
+ " <ldap-authentication-provider group-search-filter='member={0}' />"
+ "</authentication-manager>"
);
+ "<authentication-manager>" + " <ldap-authentication-provider group-search-filter='member={0}' />"
+ "</authentication-manager>");
AuthenticationManager authenticationManager = appCtx.getBean(BeanIds.AUTHENTICATION_MANAGER, AuthenticationManager.class);
Authentication auth = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("ben", "benspassword"));
AuthenticationManager authenticationManager = appCtx.getBean(BeanIds.AUTHENTICATION_MANAGER,
AuthenticationManager.class);
Authentication auth = authenticationManager
.authenticate(new UsernamePasswordAuthenticationToken("ben", "benspassword"));
UserDetails ben = (UserDetails) auth.getPrincipal();
assertThat(ben.getAuthorities()).hasSize(3);
}
@@ -62,39 +63,32 @@ public class LdapProviderBeanDefinitionParserTests {
@Test
public void multipleProvidersAreSupported() {
appCtx = new InMemoryXmlApplicationContext("<ldap-server ldif='classpath:test-server.ldif' port='0'/>"
+ "<authentication-manager>"
+ " <ldap-authentication-provider group-search-filter='member={0}' />"
+ "<authentication-manager>" + " <ldap-authentication-provider group-search-filter='member={0}' />"
+ " <ldap-authentication-provider group-search-filter='uniqueMember={0}' />"
+ "</authentication-manager>"
);
+ "</authentication-manager>");
ProviderManager providerManager = appCtx.getBean(BeanIds.AUTHENTICATION_MANAGER, ProviderManager.class);
assertThat(providerManager.getProviders()).hasSize(2);
assertThat(providerManager.getProviders())
.extracting("authoritiesPopulator.groupSearchFilter")
assertThat(providerManager.getProviders()).extracting("authoritiesPopulator.groupSearchFilter")
.containsExactly("member={0}", "uniqueMember={0}");
}
@Test(expected = ApplicationContextException.class)
public void missingServerEltCausesConfigException() {
new InMemoryXmlApplicationContext("<authentication-manager>"
+ " <ldap-authentication-provider />"
+ "</authentication-manager>"
);
new InMemoryXmlApplicationContext(
"<authentication-manager>" + " <ldap-authentication-provider />" + "</authentication-manager>");
}
@Test
public void supportsPasswordComparisonAuthentication() {
appCtx = new InMemoryXmlApplicationContext("<ldap-server ldif='classpath:test-server.ldif' port='0'/>"
+ "<authentication-manager>"
+ " <ldap-authentication-provider user-dn-pattern='uid={0},ou=people'>"
+ " <password-compare />"
+ " </ldap-authentication-provider>"
+ "</authentication-manager>"
);
+ "<authentication-manager>" + " <ldap-authentication-provider user-dn-pattern='uid={0},ou=people'>"
+ " <password-compare />" + " </ldap-authentication-provider>" + "</authentication-manager>");
AuthenticationManager authenticationManager = appCtx.getBean(BeanIds.AUTHENTICATION_MANAGER, AuthenticationManager.class);
Authentication auth = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("ben", "benspassword"));
AuthenticationManager authenticationManager = appCtx.getBean(BeanIds.AUTHENTICATION_MANAGER,
AuthenticationManager.class);
Authentication auth = authenticationManager
.authenticate(new UsernamePasswordAuthenticationToken("ben", "benspassword"));
assertThat(auth).isNotNull();
}
@@ -102,17 +96,13 @@ public class LdapProviderBeanDefinitionParserTests {
@Test
public void supportsPasswordComparisonAuthenticationWithPasswordEncoder() {
appCtx = new InMemoryXmlApplicationContext("<ldap-server ldif='classpath:test-server.ldif' port='0'/>"
+ "<authentication-manager>"
+ " <ldap-authentication-provider user-dn-pattern='uid={0},ou=people'>"
+ " <password-compare password-attribute='uid'>"
+ " <password-encoder ref='passwordEncoder' />"
+ " </password-compare>"
+ " </ldap-authentication-provider>"
+ "</authentication-manager>"
+ "<b:bean id='passwordEncoder' class='org.springframework.security.crypto.password.NoOpPasswordEncoder' factory-method='getInstance' />"
);
+ "<authentication-manager>" + " <ldap-authentication-provider user-dn-pattern='uid={0},ou=people'>"
+ " <password-compare password-attribute='uid'>" + " <password-encoder ref='passwordEncoder' />"
+ " </password-compare>" + " </ldap-authentication-provider>" + "</authentication-manager>"
+ "<b:bean id='passwordEncoder' class='org.springframework.security.crypto.password.NoOpPasswordEncoder' factory-method='getInstance' />");
AuthenticationManager authenticationManager = appCtx.getBean(BeanIds.AUTHENTICATION_MANAGER, AuthenticationManager.class);
AuthenticationManager authenticationManager = appCtx.getBean(BeanIds.AUTHENTICATION_MANAGER,
AuthenticationManager.class);
Authentication auth = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("ben", "ben"));
assertThat(auth).isNotNull();
@@ -122,34 +112,30 @@ public class LdapProviderBeanDefinitionParserTests {
@Test
public void supportsCryptoPasswordEncoder() {
appCtx = new InMemoryXmlApplicationContext("<ldap-server ldif='classpath:test-server.ldif' port='0'/>"
+ "<authentication-manager>"
+ " <ldap-authentication-provider user-dn-pattern='uid={0},ou=people'>"
+ " <password-compare>"
+ " <password-encoder ref='pe' />"
+ " </password-compare>"
+ " </ldap-authentication-provider>"
+ "</authentication-manager>"
+ "<b:bean id='pe' class='org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder' />"
);
+ "<authentication-manager>" + " <ldap-authentication-provider user-dn-pattern='uid={0},ou=people'>"
+ " <password-compare>" + " <password-encoder ref='pe' />" + " </password-compare>"
+ " </ldap-authentication-provider>" + "</authentication-manager>"
+ "<b:bean id='pe' class='org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder' />");
AuthenticationManager authenticationManager = appCtx.getBean(BeanIds.AUTHENTICATION_MANAGER, AuthenticationManager.class);
Authentication auth = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("bcrypt", "password"));
AuthenticationManager authenticationManager = appCtx.getBean(BeanIds.AUTHENTICATION_MANAGER,
AuthenticationManager.class);
Authentication auth = authenticationManager
.authenticate(new UsernamePasswordAuthenticationToken("bcrypt", "password"));
assertThat(auth).isNotNull();
}
@Test
public void inetOrgContextMapperIsSupported() {
appCtx = new InMemoryXmlApplicationContext("<ldap-server url='ldap://127.0.0.1:343/dc=springframework,dc=org' port='0'/>"
+ "<authentication-manager>"
+ " <ldap-authentication-provider user-details-class='inetOrgPerson' />"
+ "</authentication-manager>"
);
appCtx = new InMemoryXmlApplicationContext(
"<ldap-server url='ldap://127.0.0.1:343/dc=springframework,dc=org' port='0'/>"
+ "<authentication-manager>"
+ " <ldap-authentication-provider user-details-class='inetOrgPerson' />"
+ "</authentication-manager>");
ProviderManager providerManager = appCtx.getBean(BeanIds.AUTHENTICATION_MANAGER, ProviderManager.class);
assertThat(providerManager.getProviders()).hasSize(1);
assertThat(providerManager.getProviders())
.extracting("userDetailsContextMapper")
assertThat(providerManager.getProviders()).extracting("userDetailsContextMapper")
.allSatisfy(contextMapper -> assertThat(contextMapper).isInstanceOf(InetOrgPersonContextMapper.class));
}
@@ -157,22 +143,20 @@ public class LdapProviderBeanDefinitionParserTests {
public void ldapAuthenticationProviderWorksWithPlaceholders() {
System.setProperty("udp", "people");
System.setProperty("gsf", "member");
appCtx = new InMemoryXmlApplicationContext("<ldap-server />"
+ "<authentication-manager>"
appCtx = new InMemoryXmlApplicationContext("<ldap-server />" + "<authentication-manager>"
+ " <ldap-authentication-provider user-dn-pattern='uid={0},ou=${udp}' group-search-filter='${gsf}={0}' />"
+ "</authentication-manager>"
+ "<b:bean id='org.springframework.beans.factory.config.PropertyPlaceholderConfigurer' class='org.springframework.beans.factory.config.PropertyPlaceholderConfigurer' />"
);
+ "<b:bean id='org.springframework.beans.factory.config.PropertyPlaceholderConfigurer' class='org.springframework.beans.factory.config.PropertyPlaceholderConfigurer' />");
ProviderManager providerManager = appCtx.getBean(BeanIds.AUTHENTICATION_MANAGER, ProviderManager.class);
assertThat(providerManager.getProviders()).hasSize(1);
AuthenticationProvider authenticationProvider = providerManager.getProviders().get(0);
assertThat(authenticationProvider)
.extracting("authenticator.userDnFormat")
.satisfies(messageFormats -> assertThat(messageFormats).isEqualTo(new MessageFormat[]{new MessageFormat("uid={0},ou=people")}));
assertThat(authenticationProvider)
.extracting("authoritiesPopulator.groupSearchFilter")
assertThat(authenticationProvider).extracting("authenticator.userDnFormat")
.satisfies(messageFormats -> assertThat(messageFormats)
.isEqualTo(new MessageFormat[] { new MessageFormat("uid={0},ou=people") }));
assertThat(authenticationProvider).extracting("authoritiesPopulator.groupSearchFilter")
.satisfies(searchFilter -> assertThat(searchFilter).isEqualTo("member={0}"));
}
}
@@ -35,6 +35,7 @@ import static org.assertj.core.api.Assertions.assertThat;
* @author Rob Winch
*/
public class LdapServerBeanDefinitionParserTests {
InMemoryXmlApplicationContext appCtx;
@After
@@ -47,8 +48,7 @@ public class LdapServerBeanDefinitionParserTests {
@Test
public void embeddedServerCreationContainsExpectedContextSourceAndData() {
appCtx = new InMemoryXmlApplicationContext(
"<ldap-server ldif='classpath:test-server.ldif' port='0'/>");
appCtx = new InMemoryXmlApplicationContext("<ldap-server ldif='classpath:test-server.ldif' port='0'/>");
DefaultSpringSecurityContextSource contextSource = (DefaultSpringSecurityContextSource) appCtx
.getBean(BeanIds.CONTEXT_SOURCE);
@@ -62,18 +62,14 @@ public class LdapServerBeanDefinitionParserTests {
public void useOfUrlAttributeCreatesCorrectContextSource() throws Exception {
int port = getDefaultPort();
// Create second "server" with a url pointing at embedded one
appCtx = new InMemoryXmlApplicationContext(
"<ldap-server ldif='classpath:test-server.ldif' port='"
+ port
+ "'/>"
+ "<ldap-server ldif='classpath:test-server.ldif' id='blah' url='ldap://127.0.0.1:"
+ port + "/dc=springframework,dc=org' />");
appCtx = new InMemoryXmlApplicationContext("<ldap-server ldif='classpath:test-server.ldif' port='" + port
+ "'/>" + "<ldap-server ldif='classpath:test-server.ldif' id='blah' url='ldap://127.0.0.1:" + port
+ "/dc=springframework,dc=org' />");
// Check the default context source is still there.
appCtx.getBean(BeanIds.CONTEXT_SOURCE);
DefaultSpringSecurityContextSource contextSource = (DefaultSpringSecurityContextSource) appCtx
.getBean("blah");
DefaultSpringSecurityContextSource contextSource = (DefaultSpringSecurityContextSource) appCtx.getBean("blah");
// Check data is loaded as before
LdapTemplate template = new LdapTemplate(contextSource);
@@ -104,4 +100,5 @@ public class LdapServerBeanDefinitionParserTests {
return server.getLocalPort();
}
}
}
@@ -48,6 +48,7 @@ import static org.springframework.security.config.ldap.LdapUserServiceBeanDefini
* @author Eddú Meléndez
*/
public class LdapUserServiceBeanDefinitionParserTests {
private InMemoryXmlApplicationContext appCtx;
@After
@@ -65,17 +66,20 @@ public class LdapUserServiceBeanDefinitionParserTests {
assertThat(InetOrgPersonContextMapper.class.getName()).isEqualTo(INET_ORG_PERSON_MAPPER_CLASS);
assertThat(LdapUserDetailsMapper.class.getName()).isEqualTo(LDAP_USER_MAPPER_CLASS);
assertThat(DefaultLdapAuthoritiesPopulator.class.getName()).isEqualTo(LDAP_AUTHORITIES_POPULATOR_CLASS);
assertThat(new LdapUserServiceBeanDefinitionParser().getBeanClassName(mock(Element.class))).isEqualTo(LdapUserDetailsService.class.getName());
assertThat(new LdapUserServiceBeanDefinitionParser().getBeanClassName(mock(Element.class)))
.isEqualTo(LdapUserDetailsService.class.getName());
}
@Test
public void minimalConfigurationIsParsedOk() {
setContext("<ldap-user-service user-search-filter='(uid={0})' /><ldap-server ldif='classpath:test-server.ldif' url='ldap://127.0.0.1:343/dc=springframework,dc=org' />");
setContext(
"<ldap-user-service user-search-filter='(uid={0})' /><ldap-server ldif='classpath:test-server.ldif' url='ldap://127.0.0.1:343/dc=springframework,dc=org' />");
}
@Test
public void userServiceReturnsExpectedData() {
setContext("<ldap-user-service id='ldapUDS' user-search-filter='(uid={0})' group-search-filter='member={0}' /><ldap-server ldif='classpath:test-server.ldif'/>");
setContext(
"<ldap-user-service id='ldapUDS' user-search-filter='(uid={0})' group-search-filter='member={0}' /><ldap-server ldif='classpath:test-server.ldif'/>");
UserDetailsService uds = (UserDetailsService) appCtx.getBean("ldapUDS");
UserDetails ben = uds.loadUserByUsername("ben");
@@ -87,8 +91,7 @@ public class LdapUserServiceBeanDefinitionParserTests {
@Test
public void differentUserSearchBaseWorksAsExpected() {
setContext("<ldap-user-service id='ldapUDS' "
+ " user-search-base='ou=otherpeople' "
setContext("<ldap-user-service id='ldapUDS' " + " user-search-base='ou=otherpeople' "
+ " user-search-filter='(cn={0})' "
+ " group-search-filter='member={0}' /><ldap-server ldif='classpath:test-server.ldif'/>");
@@ -100,11 +103,9 @@ public class LdapUserServiceBeanDefinitionParserTests {
@Test
public void rolePrefixIsSupported() {
setContext("<ldap-user-service id='ldapUDS' "
+ " user-search-filter='(uid={0})' "
setContext("<ldap-user-service id='ldapUDS' " + " user-search-filter='(uid={0})' "
+ " group-search-filter='member={0}' role-prefix='PREFIX_'/>"
+ "<ldap-user-service id='ldapUDSNoPrefix' "
+ " user-search-filter='(uid={0})' "
+ "<ldap-user-service id='ldapUDSNoPrefix' " + " user-search-filter='(uid={0})' "
+ " group-search-filter='member={0}' role-prefix='none'/><ldap-server ldif='classpath:test-server.ldif'/>");
UserDetailsService uds = (UserDetailsService) appCtx.getBean("ldapUDS");
@@ -118,7 +119,8 @@ public class LdapUserServiceBeanDefinitionParserTests {
@Test
public void differentGroupRoleAttributeWorksAsExpected() {
setContext("<ldap-user-service id='ldapUDS' user-search-filter='(uid={0})' group-role-attribute='ou' group-search-filter='member={0}' /><ldap-server ldif='classpath:test-server.ldif'/>");
setContext(
"<ldap-user-service id='ldapUDS' user-search-filter='(uid={0})' group-role-attribute='ou' group-search-filter='member={0}' /><ldap-server ldif='classpath:test-server.ldif'/>");
UserDetailsService uds = (UserDetailsService) appCtx.getBean("ldapUDS");
UserDetails ben = uds.loadUserByUsername("ben");
@@ -131,11 +133,11 @@ public class LdapUserServiceBeanDefinitionParserTests {
@Test
public void isSupportedByAuthenticationProviderElement() {
setContext("<ldap-server url='ldap://127.0.0.1:343/dc=springframework,dc=org' ldif='classpath:test-server.ldif'/>"
+ "<authentication-manager>"
+ " <authentication-provider>"
+ " <ldap-user-service user-search-filter='(uid={0})' />"
+ " </authentication-provider>" + "</authentication-manager>");
setContext(
"<ldap-server url='ldap://127.0.0.1:343/dc=springframework,dc=org' ldif='classpath:test-server.ldif'/>"
+ "<authentication-manager>" + " <authentication-provider>"
+ " <ldap-user-service user-search-filter='(uid={0})' />" + " </authentication-provider>"
+ "</authentication-manager>");
}
@Test
@@ -160,8 +162,7 @@ public class LdapUserServiceBeanDefinitionParserTests {
public void externalContextMapperIsSupported() {
setContext("<ldap-server id='someServer' ldif='classpath:test-server.ldif'/>"
+ "<ldap-user-service id='ldapUDS' user-search-filter='(uid={0})' user-context-mapper-ref='mapper'/>"
+ "<b:bean id='mapper' class='"
+ InetOrgPersonContextMapper.class.getName() + "'/>");
+ "<b:bean id='mapper' class='" + InetOrgPersonContextMapper.class.getName() + "'/>");
UserDetailsService uds = (UserDetailsService) appCtx.getBean("ldapUDS");
UserDetails ben = uds.loadUserByUsername("ben");
@@ -171,4 +172,5 @@ public class LdapUserServiceBeanDefinitionParserTests {
private void setContext(String context) {
appCtx = new InMemoryXmlApplicationContext(context);
}
}
@@ -25,6 +25,7 @@ package org.springframework.security.config;
* @author Luke Taylor
*/
public abstract class BeanIds {
private static final String PREFIX = "org.springframework.security.";
/**
@@ -36,26 +37,26 @@ public abstract class BeanIds {
/** External alias for FilterChainProxy bean, for use in web.xml files */
public static final String SPRING_SECURITY_FILTER_CHAIN = "springSecurityFilterChain";
public static final String CONTEXT_SOURCE_SETTING_POST_PROCESSOR = PREFIX
+ "contextSettingPostProcessor";
public static final String CONTEXT_SOURCE_SETTING_POST_PROCESSOR = PREFIX + "contextSettingPostProcessor";
public static final String USER_DETAILS_SERVICE = PREFIX + "userDetailsService";
public static final String USER_DETAILS_SERVICE_FACTORY = PREFIX
+ "userDetailsServiceFactory";
public static final String METHOD_ACCESS_MANAGER = PREFIX
+ "defaultMethodAccessManager";
public static final String USER_DETAILS_SERVICE_FACTORY = PREFIX + "userDetailsServiceFactory";
public static final String METHOD_ACCESS_MANAGER = PREFIX + "defaultMethodAccessManager";
public static final String FILTER_CHAIN_PROXY = PREFIX + "filterChainProxy";
public static final String FILTER_CHAINS = PREFIX + "filterChains";
public static final String METHOD_SECURITY_METADATA_SOURCE_ADVISOR = PREFIX
+ "methodSecurityMetadataSourceAdvisor";
public static final String EMBEDDED_APACHE_DS = PREFIX
+ "apacheDirectoryServerContainer";
public static final String EMBEDDED_UNBOUNDID = PREFIX
+ "unboundidServerContainer";
public static final String METHOD_SECURITY_METADATA_SOURCE_ADVISOR = PREFIX + "methodSecurityMetadataSourceAdvisor";
public static final String EMBEDDED_APACHE_DS = PREFIX + "apacheDirectoryServerContainer";
public static final String EMBEDDED_UNBOUNDID = PREFIX + "unboundidServerContainer";
public static final String CONTEXT_SOURCE = PREFIX + "securityContextSource";
public static final String DEBUG_FILTER = PREFIX + "debugFilter";
}
@@ -28,17 +28,17 @@ public interface Customizer<T> {
/**
* Performs the customizations on the input argument.
*
* @param t the input argument
*/
void customize(T t);
/**
* Returns a {@link Customizer} that does not alter the input argument.
*
* @return a {@link Customizer} that does not alter the input argument.
*/
static <T> Customizer<T> withDefaults() {
return t -> {};
return t -> {
};
}
}
@@ -26,11 +26,12 @@ import org.w3c.dom.Element;
* @author Luke Taylor
*/
public class DebugBeanDefinitionParser implements BeanDefinitionParser {
public BeanDefinition parse(Element element, ParserContext parserContext) {
RootBeanDefinition debugPP = new RootBeanDefinition(
SecurityDebugBeanFactoryPostProcessor.class);
RootBeanDefinition debugPP = new RootBeanDefinition(SecurityDebugBeanFactoryPostProcessor.class);
parserContext.getReaderContext().registerWithGeneratedName(debugPP);
return null;
}
}
@@ -23,61 +23,113 @@ package org.springframework.security.config;
public abstract class Elements {
public static final String ACCESS_DENIED_HANDLER = "access-denied-handler";
public static final String AUTHENTICATION_MANAGER = "authentication-manager";
public static final String AFTER_INVOCATION_PROVIDER = "after-invocation-provider";
public static final String USER_SERVICE = "user-service";
public static final String JDBC_USER_SERVICE = "jdbc-user-service";
public static final String FILTER_CHAIN_MAP = "filter-chain-map";
public static final String INTERCEPT_METHODS = "intercept-methods";
public static final String INTERCEPT_URL = "intercept-url";
public static final String AUTHENTICATION_PROVIDER = "authentication-provider";
public static final String HTTP = "http";
public static final String LDAP_PROVIDER = "ldap-authentication-provider";
public static final String LDAP_SERVER = "ldap-server";
public static final String LDAP_USER_SERVICE = "ldap-user-service";
public static final String PROTECT_POINTCUT = "protect-pointcut";
public static final String EXPRESSION_HANDLER = "expression-handler";
public static final String INVOCATION_HANDLING = "pre-post-annotation-handling";
public static final String INVOCATION_ATTRIBUTE_FACTORY = "invocation-attribute-factory";
public static final String PRE_INVOCATION_ADVICE = "pre-invocation-advice";
public static final String POST_INVOCATION_ADVICE = "post-invocation-advice";
public static final String PROTECT = "protect";
public static final String SESSION_MANAGEMENT = "session-management";
public static final String CONCURRENT_SESSIONS = "concurrency-control";
public static final String LOGOUT = "logout";
public static final String FORM_LOGIN = "form-login";
public static final String OPENID_LOGIN = "openid-login";
public static final String OPENID_ATTRIBUTE_EXCHANGE = "attribute-exchange";
public static final String OPENID_ATTRIBUTE = "openid-attribute";
public static final String BASIC_AUTH = "http-basic";
public static final String REMEMBER_ME = "remember-me";
public static final String ANONYMOUS = "anonymous";
public static final String FILTER_CHAIN = "filter-chain";
public static final String GLOBAL_METHOD_SECURITY = "global-method-security";
public static final String PASSWORD_ENCODER = "password-encoder";
public static final String PORT_MAPPINGS = "port-mappings";
public static final String PORT_MAPPING = "port-mapping";
public static final String CUSTOM_FILTER = "custom-filter";
public static final String REQUEST_CACHE = "request-cache";
public static final String X509 = "x509";
public static final String JEE = "jee";
public static final String FILTER_SECURITY_METADATA_SOURCE = "filter-security-metadata-source";
public static final String METHOD_SECURITY_METADATA_SOURCE = "method-security-metadata-source";
public static final String LDAP_PASSWORD_COMPARE = "password-compare";
public static final String DEBUG = "debug";
public static final String HTTP_FIREWALL = "http-firewall";
public static final String HEADERS = "headers";
public static final String CORS = "cors";
public static final String CSRF = "csrf";
public static final String OAUTH2_RESOURCE_SERVER = "oauth2-resource-server";
public static final String JWT = "jwt";
public static final String OPAQUE_TOKEN = "opaque-token";
public static final String WEBSOCKET_MESSAGE_BROKER = "websocket-message-broker";
public static final String INTERCEPT_MESSAGE = "intercept-message";
public static final String OAUTH2_LOGIN = "oauth2-login";
public static final String OAUTH2_CLIENT = "oauth2-client";
public static final String CLIENT_REGISTRATIONS = "client-registrations";
}
@@ -59,11 +59,17 @@ import org.springframework.util.ClassUtils;
* @since 2.0
*/
public final class SecurityNamespaceHandler implements NamespaceHandler {
private static final String FILTER_CHAIN_PROXY_CLASSNAME = "org.springframework.security.web.FilterChainProxy";
private static final String MESSAGE_CLASSNAME = "org.springframework.messaging.Message";
private final Log logger = LogFactory.getLog(getClass());
private final Map<String, BeanDefinitionParser> parsers = new HashMap<>();
private final BeanDefinitionDecorator interceptMethodsBDD = new InterceptMethodsBeanDefinitionDecorator();
private BeanDefinitionDecorator filterChainMapBDD;
public SecurityNamespaceHandler() {
@@ -86,10 +92,10 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
public BeanDefinition parse(Element element, ParserContext pc) {
if (!namespaceMatchesVersion(element)) {
pc.getReaderContext()
.fatal("You cannot use a spring-security-2.0.xsd or spring-security-3.0.xsd or spring-security-3.1.xsd schema or spring-security-3.2.xsd schema or spring-security-4.0.xsd schema "
pc.getReaderContext().fatal(
"You cannot use a spring-security-2.0.xsd or spring-security-3.0.xsd or spring-security-3.1.xsd schema or spring-security-3.2.xsd schema or spring-security-4.0.xsd schema "
+ "with Spring Security 5.4. Please update your schema declarations to the 5.4 schema.",
element);
element);
}
String name = pc.getDelegate().getLocalName(element);
BeanDefinitionParser parser = parsers.get(name);
@@ -100,10 +106,8 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
}
if (parser == null) {
if (Elements.HTTP.equals(name)
|| Elements.FILTER_SECURITY_METADATA_SOURCE.equals(name)
|| Elements.FILTER_CHAIN_MAP.equals(name)
|| Elements.FILTER_CHAIN.equals(name)) {
if (Elements.HTTP.equals(name) || Elements.FILTER_SECURITY_METADATA_SOURCE.equals(name)
|| Elements.FILTER_CHAIN_MAP.equals(name) || Elements.FILTER_CHAIN.equals(name)) {
reportMissingWebClasses(name, pc, element);
}
else {
@@ -116,8 +120,7 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
return parser.parse(element, pc);
}
public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder definition,
ParserContext pc) {
public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder definition, ParserContext pc) {
String name = pc.getDelegate().getLocalName(node);
// We only handle elements
@@ -143,16 +146,13 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
}
private void reportUnsupportedNodeType(String name, ParserContext pc, Node node) {
pc.getReaderContext().fatal(
"Security namespace does not support decoration of "
+ (node instanceof Element ? "element" : "attribute") + " ["
+ name + "]", node);
pc.getReaderContext().fatal("Security namespace does not support decoration of "
+ (node instanceof Element ? "element" : "attribute") + " [" + name + "]", node);
}
private void reportMissingWebClasses(String nodeName, ParserContext pc, Node node) {
String errorMessage = "The classes from the spring-security-web jar "
+ "(or one of its dependencies) are not available. You need these to use <"
+ nodeName + ">";
+ "(or one of its dependencies) are not available. You need these to use <" + nodeName + ">";
try {
ClassUtils.forName(FILTER_CHAIN_PROXY_CLASSNAME, getClass().getClassLoader());
// no details available
@@ -175,31 +175,24 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
parsers.put(Elements.LDAP_USER_SERVICE, new LdapUserServiceBeanDefinitionParser());
parsers.put(Elements.USER_SERVICE, new UserServiceBeanDefinitionParser());
parsers.put(Elements.JDBC_USER_SERVICE, new JdbcUserServiceBeanDefinitionParser());
parsers.put(Elements.AUTHENTICATION_PROVIDER,
new AuthenticationProviderBeanDefinitionParser());
parsers.put(Elements.GLOBAL_METHOD_SECURITY,
new GlobalMethodSecurityBeanDefinitionParser());
parsers.put(Elements.AUTHENTICATION_MANAGER,
new AuthenticationManagerBeanDefinitionParser());
parsers.put(Elements.METHOD_SECURITY_METADATA_SOURCE,
new MethodSecurityMetadataSourceBeanDefinitionParser());
parsers.put(Elements.AUTHENTICATION_PROVIDER, new AuthenticationProviderBeanDefinitionParser());
parsers.put(Elements.GLOBAL_METHOD_SECURITY, new GlobalMethodSecurityBeanDefinitionParser());
parsers.put(Elements.AUTHENTICATION_MANAGER, new AuthenticationManagerBeanDefinitionParser());
parsers.put(Elements.METHOD_SECURITY_METADATA_SOURCE, new MethodSecurityMetadataSourceBeanDefinitionParser());
// Only load the web-namespace parsers if the web classes are available
if (ClassUtils.isPresent(FILTER_CHAIN_PROXY_CLASSNAME, getClass()
.getClassLoader())) {
if (ClassUtils.isPresent(FILTER_CHAIN_PROXY_CLASSNAME, getClass().getClassLoader())) {
parsers.put(Elements.DEBUG, new DebugBeanDefinitionParser());
parsers.put(Elements.HTTP, new HttpSecurityBeanDefinitionParser());
parsers.put(Elements.HTTP_FIREWALL, new HttpFirewallBeanDefinitionParser());
parsers.put(Elements.FILTER_SECURITY_METADATA_SOURCE,
new FilterInvocationSecurityMetadataSourceParser());
parsers.put(Elements.FILTER_SECURITY_METADATA_SOURCE, new FilterInvocationSecurityMetadataSourceParser());
parsers.put(Elements.FILTER_CHAIN, new FilterChainBeanDefinitionParser());
filterChainMapBDD = new FilterChainMapBeanDefinitionDecorator();
parsers.put(Elements.CLIENT_REGISTRATIONS, new ClientRegistrationsBeanDefinitionParser());
}
if (ClassUtils.isPresent(MESSAGE_CLASSNAME, getClass().getClassLoader())) {
parsers.put(Elements.WEBSOCKET_MESSAGE_BROKER,
new WebSocketMessageBrokerSecurityBeanDefinitionParser());
parsers.put(Elements.WEBSOCKET_MESSAGE_BROKER, new WebSocketMessageBrokerSecurityBeanDefinitionParser());
}
}
@@ -212,7 +205,6 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
* using 3.0 as an error too. It might be an error to declare spring-security.xsd as
* an alias, but you are only going to find that out when one of the sub parsers
* breaks.
*
* @param element the element that is to be parsed next
* @return true if we find a schema declaration that matches
*/
@@ -222,8 +214,7 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
}
private boolean matchesVersionInternal(Element element) {
String schemaLocation = element.getAttributeNS(
"http://www.w3.org/2001/XMLSchema-instance", "schemaLocation");
String schemaLocation = element.getAttributeNS("http://www.w3.org/2001/XMLSchema-instance", "schemaLocation");
return schemaLocation.matches("(?m).*spring-security-5\\.4.*.xsd.*")
|| schemaLocation.matches("(?m).*spring-security.xsd.*")
|| !schemaLocation.matches("(?m).*spring-security.*");
@@ -45,17 +45,17 @@ import org.springframework.web.filter.DelegatingFilterProxy;
* </p>
*
* @see WebSecurity
*
* @author Rob Winch
*
* @param <O> The object that this builder returns
* @param <B> The type of this builder (that is returned by the base class)
*/
public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBuilder<O>>
extends AbstractSecurityBuilder<O> {
private final Log logger = LogFactory.getLog(getClass());
private final LinkedHashMap<Class<? extends SecurityConfigurer<O, B>>, List<SecurityConfigurer<O, B>>> configurers = new LinkedHashMap<>();
private final List<SecurityConfigurer<O, B>> configurersAddedInInitializing = new ArrayList<>();
private final Map<Class<?>, Object> sharedObjects = new HashMap<>();
@@ -70,11 +70,9 @@ public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBui
* Creates a new instance with the provided {@link ObjectPostProcessor}. This post
* processor must support Object since there are many types of objects that may be
* post processed.
*
* @param objectPostProcessor the {@link ObjectPostProcessor} to use
*/
protected AbstractConfiguredSecurityBuilder(
ObjectPostProcessor<Object> objectPostProcessor) {
protected AbstractConfiguredSecurityBuilder(ObjectPostProcessor<Object> objectPostProcessor) {
this(objectPostProcessor, false);
}
@@ -82,13 +80,11 @@ public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBui
* Creates a new instance with the provided {@link ObjectPostProcessor}. This post
* processor must support Object since there are many types of objects that may be
* post processed.
*
* @param objectPostProcessor the {@link ObjectPostProcessor} to use
* @param allowConfigurersOfSameType if true, will not override other
* {@link SecurityConfigurer}'s when performing apply
*/
protected AbstractConfiguredSecurityBuilder(
ObjectPostProcessor<Object> objectPostProcessor,
protected AbstractConfiguredSecurityBuilder(ObjectPostProcessor<Object> objectPostProcessor,
boolean allowConfigurersOfSameType) {
Assert.notNull(objectPostProcessor, "objectPostProcessor cannot be null");
this.objectPostProcessor = objectPostProcessor;
@@ -98,7 +94,6 @@ public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBui
/**
* Similar to {@link #build()} and {@link #getObject()} but checks the state to
* determine if {@link #build()} needs to be called first.
*
* @return the result of {@link #build()} or {@link #getObject()}. If an error occurs
* while building, returns null.
*/
@@ -120,14 +115,12 @@ public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBui
/**
* Applies a {@link SecurityConfigurerAdapter} to this {@link SecurityBuilder} and
* invokes {@link SecurityConfigurerAdapter#setBuilder(SecurityBuilder)}.
*
* @param configurer
* @return the {@link SecurityConfigurerAdapter} for further customizations
* @throws Exception
*/
@SuppressWarnings("unchecked")
public <C extends SecurityConfigurerAdapter<O, B>> C apply(C configurer)
throws Exception {
public <C extends SecurityConfigurerAdapter<O, B>> C apply(C configurer) throws Exception {
configurer.addObjectPostProcessor(objectPostProcessor);
configurer.setBuilder((B) this);
add(configurer);
@@ -138,7 +131,6 @@ public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBui
* Applies a {@link SecurityConfigurer} to this {@link SecurityBuilder} overriding any
* {@link SecurityConfigurer} of the exact same class. Note that object hierarchies
* are not considered.
*
* @param configurer
* @return the {@link SecurityConfigurerAdapter} for further customizations
* @throws Exception
@@ -150,7 +142,6 @@ public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBui
/**
* Sets an object that is shared by multiple {@link SecurityConfigurer}.
*
* @param sharedType the Class to key the shared object by.
* @param object the Object to store
*/
@@ -161,7 +152,6 @@ public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBui
/**
* Gets a shared Object. Note that object heirarchies are not considered.
*
* @param sharedType the type of the shared Object
* @return the shared Object or null if it is not found
*/
@@ -181,7 +171,6 @@ public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBui
/**
* Adds {@link SecurityConfigurer} ensuring that it is allowed and invoking
* {@link SecurityConfigurer#init(SecurityBuilder)} immediately if necessary.
*
* @param configurer the {@link SecurityConfigurer} to add
*/
@SuppressWarnings("unchecked")
@@ -192,11 +181,9 @@ public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBui
.getClass();
synchronized (configurers) {
if (buildState.isConfigured()) {
throw new IllegalStateException("Cannot apply " + configurer
+ " to already built object");
throw new IllegalStateException("Cannot apply " + configurer + " to already built object");
}
List<SecurityConfigurer<O, B>> configs = allowConfigurersOfSameType ? this.configurers
.get(clazz) : null;
List<SecurityConfigurer<O, B>> configs = allowConfigurersOfSameType ? this.configurers.get(clazz) : null;
if (configs == null) {
configs = new ArrayList<>(1);
}
@@ -211,7 +198,6 @@ public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBui
/**
* Gets all the {@link SecurityConfigurer} instances by its class name or an empty
* List if not found. Note that object hierarchies are not considered.
*
* @param clazz the {@link SecurityConfigurer} class to look for
* @return a list of {@link SecurityConfigurer}s for further customization
*/
@@ -227,7 +213,6 @@ public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBui
/**
* Removes all the {@link SecurityConfigurer} instances by its class name or an empty
* List if not found. Note that object hierarchies are not considered.
*
* @param clazz the {@link SecurityConfigurer} class to look for
* @return a list of {@link SecurityConfigurer}s for further customization
*/
@@ -243,7 +228,6 @@ public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBui
/**
* Gets the {@link SecurityConfigurer} by its class name or <code>null</code> if not
* found. Note that object hierarchies are not considered.
*
* @param clazz
* @return the {@link SecurityConfigurer} for further customizations
*/
@@ -254,8 +238,7 @@ public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBui
return null;
}
if (configs.size() != 1) {
throw new IllegalStateException("Only one configurer expected for type "
+ clazz + ", but got " + configs);
throw new IllegalStateException("Only one configurer expected for type " + clazz + ", but got " + configs);
}
return (C) configs.get(0);
}
@@ -263,7 +246,6 @@ public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBui
/**
* Removes and returns the {@link SecurityConfigurer} by its class name or
* <code>null</code> if not found. Note that object hierarchies are not considered.
*
* @param clazz
* @return
*/
@@ -274,8 +256,7 @@ public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBui
return null;
}
if (configs.size() != 1) {
throw new IllegalStateException("Only one configurer expected for type "
+ clazz + ", but got " + configs);
throw new IllegalStateException("Only one configurer expected for type " + clazz + ", but got " + configs);
}
return (C) configs.get(0);
}
@@ -295,7 +276,6 @@ public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBui
/**
* Performs post processing of an object. The default is to delegate to the
* {@link ObjectPostProcessor}.
*
* @param object the Object to post process
* @return the possibly modified Object to use
*/
@@ -357,7 +337,6 @@ public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBui
/**
* Subclasses must implement this method to build the object that is being returned.
*
* @return the Object to be buit or null if the implementation allows it
*/
protected abstract O performBuild() throws Exception;
@@ -409,6 +388,7 @@ public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBui
* @since 3.2
*/
private enum BuildState {
/**
* This is the state before the {@link Builder#build()} is invoked
*/
@@ -457,5 +437,7 @@ public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBui
public boolean isConfigured() {
return order >= CONFIGURING.order;
}
}
}
@@ -22,11 +22,11 @@ import java.util.concurrent.atomic.AtomicBoolean;
* time.
*
* @param <O> the type of Object that is being built
*
* @author Rob Winch
*
*/
public abstract class AbstractSecurityBuilder<O> implements SecurityBuilder<O> {
private AtomicBoolean building = new AtomicBoolean();
private O object;
@@ -47,7 +47,6 @@ public abstract class AbstractSecurityBuilder<O> implements SecurityBuilder<O> {
/**
* Gets the object that was built. If it has not been built yet an Exception is
* thrown.
*
* @return the Object that was built
*/
public final O getObject() {
@@ -59,10 +58,9 @@ public abstract class AbstractSecurityBuilder<O> implements SecurityBuilder<O> {
/**
* Subclasses should implement this to perform the build.
*
* @return the object that should be returned by {@link #build()}.
*
* @throws Exception if an error occurs
*/
protected abstract O doBuild() throws Exception;
}
@@ -28,4 +28,5 @@ public class AlreadyBuiltException extends IllegalStateException {
}
private static final long serialVersionUID = -5891004752785553015L;
}
@@ -25,7 +25,6 @@ import org.springframework.beans.factory.InitializingBean;
* {@link DisposableBean#destroy()} has been invoked.
*
* @param <T> the bound of the types of Objects this {@link ObjectPostProcessor} supports.
*
* @author Rob Winch
* @since 3.2
*/
@@ -34,9 +33,9 @@ public interface ObjectPostProcessor<T> {
/**
* Initialize the object possibly returning a modified instance that should be used
* instead.
*
* @param object the object to initialize
* @return the initialized version of the object
*/
<O extends T> O postProcess(O object);
}
@@ -20,16 +20,15 @@ package org.springframework.security.config.annotation;
*
* @author Rob Winch
* @since 3.2
*
* @param <O> The type of the Object being built
*/
public interface SecurityBuilder<O> {
/**
* Builds the object and returns it or null.
*
* @return the Object to be built or null if the implementation allows it.
* @throws Exception if an error occurred when building the Object
*/
O build() throws Exception;
}
@@ -22,20 +22,18 @@ package org.springframework.security.config.annotation;
* {@link #configure(SecurityBuilder)} method is invoked.
*
* @see AbstractConfiguredSecurityBuilder
*
* @author Rob Winch
*
* @param <O> The object being built by the {@link SecurityBuilder} B
* @param <B> The {@link SecurityBuilder} that builds objects of type O. This is also the
* {@link SecurityBuilder} that is being configured.
*/
public interface SecurityConfigurer<O, B extends SecurityBuilder<O>> {
/**
* Initialize the {@link SecurityBuilder}. Here only shared state should be created
* and modified, but not properties on the {@link SecurityBuilder} used for building
* the object. This ensures that the {@link #configure(SecurityBuilder)} method uses
* the correct shared objects when building. Configurers should be applied here.
*
* @param builder
* @throws Exception
*/
@@ -44,9 +42,9 @@ public interface SecurityConfigurer<O, B extends SecurityBuilder<O>> {
/**
* Configure the {@link SecurityBuilder} by setting the necessary properties on the
* {@link SecurityBuilder}.
*
* @param builder
* @throws Exception
*/
void configure(B builder) throws Exception;
}
@@ -29,13 +29,12 @@ import org.springframework.core.annotation.AnnotationAwareOrderComparator;
*
* @author Rob Winch
* @author Wallace Wadge
*
* @param <O> The Object being built by B
* @param <B> The Builder that is building O and is configured by
* {@link SecurityConfigurerAdapter}
*/
public abstract class SecurityConfigurerAdapter<O, B extends SecurityBuilder<O>>
implements SecurityConfigurer<O, B> {
public abstract class SecurityConfigurerAdapter<O, B extends SecurityBuilder<O>> implements SecurityConfigurer<O, B> {
private B securityBuilder;
private CompositeObjectPostProcessor objectPostProcessor = new CompositeObjectPostProcessor();
@@ -49,7 +48,6 @@ public abstract class SecurityConfigurerAdapter<O, B extends SecurityBuilder<O>>
/**
* Return the {@link SecurityBuilder} when done using the {@link SecurityConfigurer}.
* This is useful for method chaining.
*
* @return the {@link SecurityBuilder} for further customizations
*/
public B and() {
@@ -58,7 +56,6 @@ public abstract class SecurityConfigurerAdapter<O, B extends SecurityBuilder<O>>
/**
* Gets the {@link SecurityBuilder}. Cannot be null.
*
* @return the {@link SecurityBuilder}
* @throws IllegalStateException if {@link SecurityBuilder} is null
*/
@@ -72,7 +69,6 @@ public abstract class SecurityConfigurerAdapter<O, B extends SecurityBuilder<O>>
/**
* Performs post processing of an object. The default is to delegate to the
* {@link ObjectPostProcessor}.
*
* @param object the Object to post process
* @return the possibly modified Object to use
*/
@@ -85,7 +81,6 @@ public abstract class SecurityConfigurerAdapter<O, B extends SecurityBuilder<O>>
* Adds an {@link ObjectPostProcessor} to be used for this
* {@link SecurityConfigurerAdapter}. The default implementation does nothing to the
* object.
*
* @param objectPostProcessor the {@link ObjectPostProcessor} to use
*/
public void addObjectPostProcessor(ObjectPostProcessor<?> objectPostProcessor) {
@@ -95,7 +90,6 @@ public abstract class SecurityConfigurerAdapter<O, B extends SecurityBuilder<O>>
/**
* Sets the {@link SecurityBuilder} to be used. This is automatically set when using
* {@link AbstractConfiguredSecurityBuilder#apply(SecurityConfigurerAdapter)}
*
* @param builder the {@link SecurityBuilder} to set
*/
public void setBuilder(B builder) {
@@ -108,16 +102,15 @@ public abstract class SecurityConfigurerAdapter<O, B extends SecurityBuilder<O>>
*
* @author Rob Winch
*/
private static final class CompositeObjectPostProcessor implements
ObjectPostProcessor<Object> {
private static final class CompositeObjectPostProcessor implements ObjectPostProcessor<Object> {
private List<ObjectPostProcessor<?>> postProcessors = new ArrayList<>();
@SuppressWarnings({ "rawtypes", "unchecked" })
public Object postProcess(Object object) {
for (ObjectPostProcessor opp : postProcessors) {
Class<?> oppClass = opp.getClass();
Class<?> oppType = GenericTypeResolver.resolveTypeArgument(oppClass,
ObjectPostProcessor.class);
Class<?> oppType = GenericTypeResolver.resolveTypeArgument(oppClass, ObjectPostProcessor.class);
if (oppType == null || oppType.isAssignableFrom(object.getClass())) {
object = opp.postProcess(object);
}
@@ -130,11 +123,12 @@ public abstract class SecurityConfigurerAdapter<O, B extends SecurityBuilder<O>>
* @param objectPostProcessor the {@link ObjectPostProcessor} to add
* @return true if the {@link ObjectPostProcessor} was added, else false
*/
private boolean addObjectPostProcessor(
ObjectPostProcessor<?> objectPostProcessor) {
private boolean addObjectPostProcessor(ObjectPostProcessor<?> objectPostProcessor) {
boolean result = this.postProcessors.add(objectPostProcessor);
postProcessors.sort(AnnotationAwareOrderComparator.INSTANCE);
return result;
}
}
}
@@ -24,11 +24,10 @@ import org.springframework.security.config.annotation.SecurityBuilder;
* Interface for operating on a SecurityBuilder that creates a {@link ProviderManager}
*
* @author Rob Winch
*
* @param <B> the type of the {@link SecurityBuilder}
*/
public interface ProviderManagerBuilder<B extends ProviderManagerBuilder<B>> extends
SecurityBuilder<AuthenticationManager> {
public interface ProviderManagerBuilder<B extends ProviderManagerBuilder<B>>
extends SecurityBuilder<AuthenticationManager> {
/**
* Add authentication based upon the custom {@link AuthenticationProvider} that is
@@ -36,10 +35,11 @@ public interface ProviderManagerBuilder<B extends ProviderManagerBuilder<B>> ext
* customizations must be done externally and the {@link ProviderManagerBuilder} is
* returned immediately.
*
* Note that an Exception is thrown if an error occurs when adding the {@link AuthenticationProvider}.
*
* Note that an Exception is thrown if an error occurs when adding the
* {@link AuthenticationProvider}.
* @return a {@link ProviderManagerBuilder} to allow further authentication to be
* provided to the {@link ProviderManagerBuilder}
*/
B authenticationProvider(AuthenticationProvider authenticationProvider);
}
@@ -48,15 +48,19 @@ import org.springframework.util.Assert;
* @since 3.2
*/
public class AuthenticationManagerBuilder
extends
AbstractConfiguredSecurityBuilder<AuthenticationManager, AuthenticationManagerBuilder>
extends AbstractConfiguredSecurityBuilder<AuthenticationManager, AuthenticationManagerBuilder>
implements ProviderManagerBuilder<AuthenticationManagerBuilder> {
private final Log logger = LogFactory.getLog(getClass());
private AuthenticationManager parentAuthenticationManager;
private List<AuthenticationProvider> authenticationProviders = new ArrayList<>();
private UserDetailsService defaultUserDetailsService;
private Boolean eraseCredentials;
private AuthenticationEventPublisher eventPublisher;
/**
@@ -71,18 +75,15 @@ public class AuthenticationManagerBuilder
* Allows providing a parent {@link AuthenticationManager} that will be tried if this
* {@link AuthenticationManager} was unable to attempt to authenticate the provided
* {@link Authentication}.
*
* @param authenticationManager the {@link AuthenticationManager} that should be used
* if the current {@link AuthenticationManager} was unable to attempt to authenticate
* the provided {@link Authentication}.
* @return the {@link AuthenticationManagerBuilder} for further adding types of
* authentication
*/
public AuthenticationManagerBuilder parentAuthenticationManager(
AuthenticationManager authenticationManager) {
public AuthenticationManagerBuilder parentAuthenticationManager(AuthenticationManager authenticationManager) {
if (authenticationManager instanceof ProviderManager) {
eraseCredentials(((ProviderManager) authenticationManager)
.isEraseCredentialsAfterAuthentication());
eraseCredentials(((ProviderManager) authenticationManager).isEraseCredentialsAfterAuthentication());
}
this.parentAuthenticationManager = authenticationManager;
return this;
@@ -90,20 +91,16 @@ public class AuthenticationManagerBuilder
/**
* Sets the {@link AuthenticationEventPublisher}
*
* @param eventPublisher the {@link AuthenticationEventPublisher} to use
* @return the {@link AuthenticationManagerBuilder} for further customizations
*/
public AuthenticationManagerBuilder authenticationEventPublisher(
AuthenticationEventPublisher eventPublisher) {
public AuthenticationManagerBuilder authenticationEventPublisher(AuthenticationEventPublisher eventPublisher) {
Assert.notNull(eventPublisher, "AuthenticationEventPublisher cannot be null");
this.eventPublisher = eventPublisher;
return this;
}
/**
*
*
* @param eraseCredentials true if {@link AuthenticationManager} should clear the
* credentials from the {@link Authentication} object after authenticating
* @return the {@link AuthenticationManagerBuilder} for further customizations
@@ -124,7 +121,6 @@ public class AuthenticationManagerBuilder
* {@link UserDetailsService}'s may override this {@link UserDetailsService} as the
* default.
* </p>
*
* @return a {@link InMemoryUserDetailsManagerConfigurer} to allow customization of
* the in memory authentication
* @throws Exception if an error occurs when adding the in memory authentication
@@ -141,8 +137,8 @@ public class AuthenticationManagerBuilder
*
* <p>
* When using with a persistent data store, it is best to add users external of
* configuration using something like <a href="https://flywaydb.org/">Flyway</a> or <a
* href="https://www.liquibase.org/">Liquibase</a> to create the schema and adding
* configuration using something like <a href="https://flywaydb.org/">Flyway</a> or
* <a href="https://www.liquibase.org/">Liquibase</a> to create the schema and adding
* users to ensure these steps are only done once and that the optimal SQL is used.
* </p>
*
@@ -154,13 +150,11 @@ public class AuthenticationManagerBuilder
* "https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#user-schema"
* >User Schema</a> section of the reference for the default schema.
* </p>
*
* @return a {@link JdbcUserDetailsManagerConfigurer} to allow customization of the
* JDBC authentication
* @throws Exception if an error occurs when adding the JDBC authentication
*/
public JdbcUserDetailsManagerConfigurer<AuthenticationManagerBuilder> jdbcAuthentication()
throws Exception {
public JdbcUserDetailsManagerConfigurer<AuthenticationManagerBuilder> jdbcAuthentication() throws Exception {
return apply(new JdbcUserDetailsManagerConfigurer<>());
}
@@ -175,7 +169,6 @@ public class AuthenticationManagerBuilder
* {@link UserDetailsService}'s may override this {@link UserDetailsService} as the
* default.
* </p>
*
* @return a {@link DaoAuthenticationConfigurer} to allow customization of the DAO
* authentication
* @throws Exception if an error occurs when adding the {@link UserDetailsService}
@@ -184,8 +177,7 @@ public class AuthenticationManagerBuilder
public <T extends UserDetailsService> DaoAuthenticationConfigurer<AuthenticationManagerBuilder, T> userDetailsService(
T userDetailsService) throws Exception {
this.defaultUserDetailsService = userDetailsService;
return apply(new DaoAuthenticationConfigurer<>(
userDetailsService));
return apply(new DaoAuthenticationConfigurer<>(userDetailsService));
}
/**
@@ -196,13 +188,11 @@ public class AuthenticationManagerBuilder
* <p>
* This method <b>does NOT</b> ensure that a {@link UserDetailsService} is available
* for the {@link #getDefaultUserDetailsService()} method.
*
* @return a {@link LdapAuthenticationProviderConfigurer} to allow customization of
* the LDAP authentication
* @throws Exception if an error occurs when adding the LDAP authentication
*/
public LdapAuthenticationProviderConfigurer<AuthenticationManagerBuilder> ldapAuthentication()
throws Exception {
public LdapAuthenticationProviderConfigurer<AuthenticationManagerBuilder> ldapAuthentication() throws Exception {
return apply(new LdapAuthenticationProviderConfigurer<>());
}
@@ -216,13 +206,12 @@ public class AuthenticationManagerBuilder
* This method <b>does NOT</b> ensure that the {@link UserDetailsService} is available
* for the {@link #getDefaultUserDetailsService()} method.
*
* Note that an {@link Exception} might be thrown if an error occurs when adding the {@link AuthenticationProvider}.
*
* Note that an {@link Exception} might be thrown if an error occurs when adding the
* {@link AuthenticationProvider}.
* @return a {@link AuthenticationManagerBuilder} to allow further authentication to
* be provided to the {@link AuthenticationManagerBuilder}
*/
public AuthenticationManagerBuilder authenticationProvider(
AuthenticationProvider authenticationProvider) {
public AuthenticationManagerBuilder authenticationProvider(AuthenticationProvider authenticationProvider) {
this.authenticationProviders.add(authenticationProvider);
return this;
}
@@ -233,8 +222,7 @@ public class AuthenticationManagerBuilder
logger.debug("No authenticationProviders and no parentAuthenticationManager defined. Returning null.");
return null;
}
ProviderManager providerManager = new ProviderManager(authenticationProviders,
parentAuthenticationManager);
ProviderManager providerManager = new ProviderManager(authenticationProviders, parentAuthenticationManager);
if (eraseCredentials != null) {
providerManager.setEraseCredentialsAfterAuthentication(eraseCredentials);
}
@@ -257,8 +245,8 @@ public class AuthenticationManagerBuilder
* {@link SecurityConfigurer} that is last could check this method and provide a
* default configuration in the {@link SecurityConfigurer#configure(SecurityBuilder)}
* method.
*
* @return true, if {@link AuthenticationManagerBuilder} is configured, otherwise false
* @return true, if {@link AuthenticationManagerBuilder} is configured, otherwise
* false
*/
public boolean isConfigured() {
return !authenticationProviders.isEmpty() || parentAuthenticationManager != null;
@@ -267,7 +255,6 @@ public class AuthenticationManagerBuilder
/**
* Gets the default {@link UserDetailsService} for the
* {@link AuthenticationManagerBuilder}. The result may be null in some circumstances.
*
* @return the default {@link UserDetailsService} for the
* {@link AuthenticationManagerBuilder}
*/
@@ -278,7 +265,6 @@ public class AuthenticationManagerBuilder
/**
* Captures the {@link UserDetailsService} from any {@link UserDetailsAwareConfigurer}
* .
*
* @param configurer the {@link UserDetailsAwareConfigurer} to capture the
* {@link UserDetailsService} from.
* @return the {@link UserDetailsAwareConfigurer} for further customizations
@@ -289,4 +275,5 @@ public class AuthenticationManagerBuilder
this.defaultUserDetailsService = configurer.getUserDetailsService();
return super.apply(configurer);
}
}
@@ -68,18 +68,19 @@ public class AuthenticationConfiguration {
private boolean authenticationManagerInitialized;
private List<GlobalAuthenticationConfigurerAdapter> globalAuthConfigurers = Collections
.emptyList();
private List<GlobalAuthenticationConfigurerAdapter> globalAuthConfigurers = Collections.emptyList();
private ObjectPostProcessor<Object> objectPostProcessor;
@Bean
public AuthenticationManagerBuilder authenticationManagerBuilder(
ObjectPostProcessor<Object> objectPostProcessor, ApplicationContext context) {
public AuthenticationManagerBuilder authenticationManagerBuilder(ObjectPostProcessor<Object> objectPostProcessor,
ApplicationContext context) {
LazyPasswordEncoder defaultPasswordEncoder = new LazyPasswordEncoder(context);
AuthenticationEventPublisher authenticationEventPublisher = getBeanOrNull(context, AuthenticationEventPublisher.class);
AuthenticationEventPublisher authenticationEventPublisher = getBeanOrNull(context,
AuthenticationEventPublisher.class);
DefaultPasswordEncoderAuthenticationManagerBuilder result = new DefaultPasswordEncoderAuthenticationManagerBuilder(objectPostProcessor, defaultPasswordEncoder);
DefaultPasswordEncoderAuthenticationManagerBuilder result = new DefaultPasswordEncoderAuthenticationManagerBuilder(
objectPostProcessor, defaultPasswordEncoder);
if (authenticationEventPublisher != null) {
result.authenticationEventPublisher(authenticationEventPublisher);
}
@@ -93,12 +94,14 @@ public class AuthenticationConfiguration {
}
@Bean
public static InitializeUserDetailsBeanManagerConfigurer initializeUserDetailsBeanManagerConfigurer(ApplicationContext context) {
public static InitializeUserDetailsBeanManagerConfigurer initializeUserDetailsBeanManagerConfigurer(
ApplicationContext context) {
return new InitializeUserDetailsBeanManagerConfigurer(context);
}
@Bean
public static InitializeAuthenticationProviderBeanManagerConfigurer initializeAuthenticationProviderBeanManagerConfigurer(ApplicationContext context) {
public static InitializeAuthenticationProviderBeanManagerConfigurer initializeAuthenticationProviderBeanManagerConfigurer(
ApplicationContext context) {
return new InitializeAuthenticationProviderBeanManagerConfigurer(context);
}
@@ -126,8 +129,7 @@ public class AuthenticationConfiguration {
}
@Autowired(required = false)
public void setGlobalAuthenticationConfigurers(
List<GlobalAuthenticationConfigurerAdapter> configurers) {
public void setGlobalAuthenticationConfigurers(List<GlobalAuthenticationConfigurerAdapter> configurers) {
configurers.sort(AnnotationAwareOrderComparator.INSTANCE);
this.globalAuthConfigurers = configurers;
}
@@ -145,8 +147,8 @@ public class AuthenticationConfiguration {
@SuppressWarnings("unchecked")
private <T> T lazyBean(Class<T> interfaceName) {
LazyInitTargetSource lazyTargetSource = new LazyInitTargetSource();
String[] beanNamesForType = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
applicationContext, interfaceName);
String[] beanNamesForType = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(applicationContext,
interfaceName);
if (beanNamesForType.length == 0) {
return null;
}
@@ -154,12 +156,13 @@ public class AuthenticationConfiguration {
if (beanNamesForType.length > 1) {
List<String> primaryBeanNames = getPrimaryBeanNames(beanNamesForType);
Assert.isTrue(primaryBeanNames.size() != 0, () -> "Found " + beanNamesForType.length
+ " beans for type " + interfaceName + ", but none marked as primary");
Assert.isTrue(primaryBeanNames.size() == 1, () -> "Found " + primaryBeanNames.size()
+ " beans for type " + interfaceName + " marked as primary");
Assert.isTrue(primaryBeanNames.size() != 0, () -> "Found " + beanNamesForType.length + " beans for type "
+ interfaceName + ", but none marked as primary");
Assert.isTrue(primaryBeanNames.size() == 1, () -> "Found " + primaryBeanNames.size() + " beans for type "
+ interfaceName + " marked as primary");
beanName = primaryBeanNames.get(0);
} else {
}
else {
beanName = beanNamesForType[0];
}
@@ -177,8 +180,8 @@ public class AuthenticationConfiguration {
return Collections.emptyList();
}
for (String beanName : beanNamesForType) {
if (((ConfigurableApplicationContext) applicationContext).getBeanFactory()
.getBeanDefinition(beanName).isPrimary()) {
if (((ConfigurableApplicationContext) applicationContext).getBeanFactory().getBeanDefinition(beanName)
.isPrimary()) {
list.add(beanName);
}
}
@@ -192,16 +195,17 @@ public class AuthenticationConfiguration {
private static <T> T getBeanOrNull(ApplicationContext applicationContext, Class<T> type) {
try {
return applicationContext.getBean(type);
} catch(NoSuchBeanDefinitionException notFound) {
}
catch (NoSuchBeanDefinitionException notFound) {
return null;
}
}
private static class EnableGlobalAuthenticationAutowiredConfigurer extends
GlobalAuthenticationConfigurerAdapter {
private static class EnableGlobalAuthenticationAutowiredConfigurer extends GlobalAuthenticationConfigurerAdapter {
private final ApplicationContext context;
private static final Log logger = LogFactory
.getLog(EnableGlobalAuthenticationAutowiredConfigurer.class);
private static final Log logger = LogFactory.getLog(EnableGlobalAuthenticationAutowiredConfigurer.class);
EnableGlobalAuthenticationAutowiredConfigurer(ApplicationContext context) {
this.context = context;
@@ -209,12 +213,12 @@ public class AuthenticationConfiguration {
@Override
public void init(AuthenticationManagerBuilder auth) {
Map<String, Object> beansWithAnnotation = context
.getBeansWithAnnotation(EnableGlobalAuthentication.class);
Map<String, Object> beansWithAnnotation = context.getBeansWithAnnotation(EnableGlobalAuthentication.class);
if (logger.isDebugEnabled()) {
logger.debug("Eagerly initializing " + beansWithAnnotation);
}
}
}
/**
@@ -225,8 +229,11 @@ public class AuthenticationConfiguration {
* @since 4.1.1
*/
static final class AuthenticationManagerDelegator implements AuthenticationManager {
private AuthenticationManagerBuilder delegateBuilder;
private AuthenticationManager delegate;
private final Object delegateMonitor = new Object();
AuthenticationManagerDelegator(AuthenticationManagerBuilder delegateBuilder) {
@@ -235,8 +242,7 @@ public class AuthenticationConfiguration {
}
@Override
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
if (this.delegate != null) {
return this.delegate.authenticate(authentication);
}
@@ -255,46 +261,46 @@ public class AuthenticationConfiguration {
public String toString() {
return "AuthenticationManagerDelegator [delegate=" + this.delegate + "]";
}
}
static class DefaultPasswordEncoderAuthenticationManagerBuilder extends AuthenticationManagerBuilder {
private PasswordEncoder defaultPasswordEncoder;
/**
* Creates a new instance
*
* @param objectPostProcessor the {@link ObjectPostProcessor} instance to use.
*/
DefaultPasswordEncoderAuthenticationManagerBuilder(
ObjectPostProcessor<Object> objectPostProcessor, PasswordEncoder defaultPasswordEncoder) {
DefaultPasswordEncoderAuthenticationManagerBuilder(ObjectPostProcessor<Object> objectPostProcessor,
PasswordEncoder defaultPasswordEncoder) {
super(objectPostProcessor);
this.defaultPasswordEncoder = defaultPasswordEncoder;
}
@Override
public InMemoryUserDetailsManagerConfigurer<AuthenticationManagerBuilder> inMemoryAuthentication()
throws Exception {
return super.inMemoryAuthentication()
.passwordEncoder(this.defaultPasswordEncoder);
throws Exception {
return super.inMemoryAuthentication().passwordEncoder(this.defaultPasswordEncoder);
}
@Override
public JdbcUserDetailsManagerConfigurer<AuthenticationManagerBuilder> jdbcAuthentication()
throws Exception {
return super.jdbcAuthentication()
.passwordEncoder(this.defaultPasswordEncoder);
public JdbcUserDetailsManagerConfigurer<AuthenticationManagerBuilder> jdbcAuthentication() throws Exception {
return super.jdbcAuthentication().passwordEncoder(this.defaultPasswordEncoder);
}
@Override
public <T extends UserDetailsService> DaoAuthenticationConfigurer<AuthenticationManagerBuilder, T> userDetailsService(
T userDetailsService) throws Exception {
return super.userDetailsService(userDetailsService)
.passwordEncoder(this.defaultPasswordEncoder);
T userDetailsService) throws Exception {
return super.userDetailsService(userDetailsService).passwordEncoder(this.defaultPasswordEncoder);
}
}
static class LazyPasswordEncoder implements PasswordEncoder {
private ApplicationContext applicationContext;
private PasswordEncoder passwordEncoder;
LazyPasswordEncoder(ApplicationContext applicationContext) {
@@ -307,8 +313,7 @@ public class AuthenticationConfiguration {
}
@Override
public boolean matches(CharSequence rawPassword,
String encodedPassword) {
public boolean matches(CharSequence rawPassword, String encodedPassword) {
return getPasswordEncoder().matches(rawPassword, encodedPassword);
}
@@ -333,5 +338,7 @@ public class AuthenticationConfiguration {
public String toString() {
return getPasswordEncoder().toString();
}
}
}
@@ -87,4 +87,5 @@ import org.springframework.security.config.annotation.web.servlet.configuration.
@Import(AuthenticationConfiguration.class)
@Configuration
public @interface EnableGlobalAuthentication {
}
@@ -31,12 +31,13 @@ import org.springframework.security.config.annotation.authentication.configurati
* @author Rob Winch
*/
@Order(100)
public abstract class GlobalAuthenticationConfigurerAdapter implements
SecurityConfigurer<AuthenticationManager, AuthenticationManagerBuilder> {
public abstract class GlobalAuthenticationConfigurerAdapter
implements SecurityConfigurer<AuthenticationManager, AuthenticationManagerBuilder> {
public void init(AuthenticationManagerBuilder auth) throws Exception {
}
public void configure(AuthenticationManagerBuilder auth) throws Exception {
}
}
@@ -21,26 +21,23 @@ import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
/**
* Lazily initializes the global authentication with an {@link AuthenticationProvider} if it is
* not yet configured and there is only a single Bean of that type.
* Lazily initializes the global authentication with an {@link AuthenticationProvider} if
* it is not yet configured and there is only a single Bean of that type.
*
* @author Rob Winch
* @since 4.1
*/
@Order(InitializeAuthenticationProviderBeanManagerConfigurer.DEFAULT_ORDER)
class InitializeAuthenticationProviderBeanManagerConfigurer
extends GlobalAuthenticationConfigurerAdapter {
class InitializeAuthenticationProviderBeanManagerConfigurer extends GlobalAuthenticationConfigurerAdapter {
static final int DEFAULT_ORDER = InitializeUserDetailsBeanManagerConfigurer.DEFAULT_ORDER
- 100;
static final int DEFAULT_ORDER = InitializeUserDetailsBeanManagerConfigurer.DEFAULT_ORDER - 100;
private final ApplicationContext context;
/**
* @param context the ApplicationContext to look up beans.
*/
InitializeAuthenticationProviderBeanManagerConfigurer(
ApplicationContext context) {
InitializeAuthenticationProviderBeanManagerConfigurer(ApplicationContext context) {
this.context = context;
}
@@ -49,25 +46,24 @@ class InitializeAuthenticationProviderBeanManagerConfigurer
auth.apply(new InitializeAuthenticationProviderManagerConfigurer());
}
class InitializeAuthenticationProviderManagerConfigurer
extends GlobalAuthenticationConfigurerAdapter {
class InitializeAuthenticationProviderManagerConfigurer extends GlobalAuthenticationConfigurerAdapter {
@Override
public void configure(AuthenticationManagerBuilder auth) {
if (auth.isConfigured()) {
return;
}
AuthenticationProvider authenticationProvider = getBeanOrNull(
AuthenticationProvider.class);
AuthenticationProvider authenticationProvider = getBeanOrNull(AuthenticationProvider.class);
if (authenticationProvider == null) {
return;
}
auth.authenticationProvider(authenticationProvider);
}
/**
* @return a bean of the requested class if there's just a single registered component, null otherwise.
* @return a bean of the requested class if there's just a single registered
* component, null otherwise.
*/
private <T> T getBeanOrNull(Class<T> type) {
String[] beanNames = InitializeAuthenticationProviderBeanManagerConfigurer.this.context
@@ -76,8 +72,9 @@ class InitializeAuthenticationProviderBeanManagerConfigurer
return null;
}
return InitializeAuthenticationProviderBeanManagerConfigurer.this.context
.getBean(beanNames[0], type);
return InitializeAuthenticationProviderBeanManagerConfigurer.this.context.getBean(beanNames[0], type);
}
}
}
@@ -33,8 +33,7 @@ import org.springframework.security.core.userdetails.UserDetailsPasswordService;
* @since 4.1
*/
@Order(InitializeUserDetailsBeanManagerConfigurer.DEFAULT_ORDER)
class InitializeUserDetailsBeanManagerConfigurer
extends GlobalAuthenticationConfigurerAdapter {
class InitializeUserDetailsBeanManagerConfigurer extends GlobalAuthenticationConfigurerAdapter {
static final int DEFAULT_ORDER = Ordered.LOWEST_PRECEDENCE - 5000;
@@ -52,15 +51,14 @@ class InitializeUserDetailsBeanManagerConfigurer
auth.apply(new InitializeUserDetailsManagerConfigurer());
}
class InitializeUserDetailsManagerConfigurer
extends GlobalAuthenticationConfigurerAdapter {
class InitializeUserDetailsManagerConfigurer extends GlobalAuthenticationConfigurerAdapter {
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
if (auth.isConfigured()) {
return;
}
UserDetailsService userDetailsService = getBeanOrNull(
UserDetailsService.class);
UserDetailsService userDetailsService = getBeanOrNull(UserDetailsService.class);
if (userDetailsService == null) {
return;
}
@@ -82,17 +80,18 @@ class InitializeUserDetailsBeanManagerConfigurer
}
/**
* @return a bean of the requested class if there's just a single registered component, null otherwise.
* @return a bean of the requested class if there's just a single registered
* component, null otherwise.
*/
private <T> T getBeanOrNull(Class<T> type) {
String[] beanNames = InitializeUserDetailsBeanManagerConfigurer.this.context
.getBeanNamesForType(type);
String[] beanNames = InitializeUserDetailsBeanManagerConfigurer.this.context.getBeanNamesForType(type);
if (beanNames.length != 1) {
return null;
}
return InitializeUserDetailsBeanManagerConfigurer.this.context
.getBean(beanNames[0], type);
return InitializeUserDetailsBeanManagerConfigurer.this.context.getBean(beanNames[0], type);
}
}
}
@@ -52,27 +52,41 @@ import org.springframework.util.ClassUtils;
* Configures LDAP {@link AuthenticationProvider} in the {@link ProviderManagerBuilder}.
*
* @param <B> the {@link ProviderManagerBuilder} type that this is configuring.
*
* @author Rob Winch
* @author Eddú Meléndez
* @since 3.2
*/
public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuilder<B>>
extends SecurityConfigurerAdapter<AuthenticationManager, B> {
private String groupRoleAttribute = "cn";
private String groupSearchBase = "";
private boolean groupSearchSubtree = false;
private String groupSearchFilter = "(uniqueMember={0})";
private String rolePrefix = "ROLE_";
private String userSearchBase = ""; // only for search
private String userSearchFilter = null; // "uid={0}"; // only for search
private String[] userDnPatterns;
private BaseLdapPathContextSource contextSource;
private ContextSourceBuilder contextSourceBuilder = new ContextSourceBuilder();
private UserDetailsContextMapper userDetailsContextMapper;
private PasswordEncoder passwordEncoder;
private String passwordAttribute;
private LdapAuthoritiesPopulator ldapAuthoritiesPopulator;
private GrantedAuthoritiesMapper authoritiesMapper;
private LdapAuthenticationProvider build() throws Exception {
@@ -81,19 +95,17 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
LdapAuthoritiesPopulator authoritiesPopulator = getLdapAuthoritiesPopulator();
LdapAuthenticationProvider ldapAuthenticationProvider = new LdapAuthenticationProvider(
ldapAuthenticator, authoritiesPopulator);
LdapAuthenticationProvider ldapAuthenticationProvider = new LdapAuthenticationProvider(ldapAuthenticator,
authoritiesPopulator);
ldapAuthenticationProvider.setAuthoritiesMapper(getAuthoritiesMapper());
if (userDetailsContextMapper != null) {
ldapAuthenticationProvider
.setUserDetailsContextMapper(userDetailsContextMapper);
ldapAuthenticationProvider.setUserDetailsContextMapper(userDetailsContextMapper);
}
return ldapAuthenticationProvider;
}
/**
* Specifies the {@link LdapAuthoritiesPopulator}.
*
* @param ldapAuthoritiesPopulator the {@link LdapAuthoritiesPopulator} the default is
* {@link DefaultLdapAuthoritiesPopulator}
* @return the {@link LdapAuthenticationProviderConfigurer} for further customizations
@@ -106,12 +118,10 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
/**
* Adds an {@link ObjectPostProcessor} for this class.
*
* @param objectPostProcessor
* @return the {@link ChannelSecurityConfigurer} for further customizations
*/
public LdapAuthenticationProviderConfigurer<B> withObjectPostProcessor(
ObjectPostProcessor<?> objectPostProcessor) {
public LdapAuthenticationProviderConfigurer<B> withObjectPostProcessor(ObjectPostProcessor<?> objectPostProcessor) {
addObjectPostProcessor(objectPostProcessor);
return this;
}
@@ -119,7 +129,6 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
/**
* Gets the {@link LdapAuthoritiesPopulator} and defaults to
* {@link DefaultLdapAuthoritiesPopulator}
*
* @return the {@link LdapAuthoritiesPopulator}
*/
private LdapAuthoritiesPopulator getLdapAuthoritiesPopulator() {
@@ -127,8 +136,8 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
return ldapAuthoritiesPopulator;
}
DefaultLdapAuthoritiesPopulator defaultAuthoritiesPopulator = new DefaultLdapAuthoritiesPopulator(
contextSource, groupSearchBase);
DefaultLdapAuthoritiesPopulator defaultAuthoritiesPopulator = new DefaultLdapAuthoritiesPopulator(contextSource,
groupSearchBase);
defaultAuthoritiesPopulator.setGroupRoleAttribute(groupRoleAttribute);
defaultAuthoritiesPopulator.setGroupSearchFilter(groupSearchFilter);
defaultAuthoritiesPopulator.setSearchSubtree(groupSearchSubtree);
@@ -138,24 +147,24 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
return defaultAuthoritiesPopulator;
}
/**
* Specifies the {@link GrantedAuthoritiesMapper}.
*
* @param grantedAuthoritiesMapper the {@link GrantedAuthoritiesMapper} the default is {@link SimpleAuthorityMapper}
* @param grantedAuthoritiesMapper the {@link GrantedAuthoritiesMapper} the default is
* {@link SimpleAuthorityMapper}
* @return the {@link LdapAuthenticationProviderConfigurer} for further customizations
*
* @author Tony Dalbrekt
* @since 4.1.1
*/
public LdapAuthenticationProviderConfigurer<B> authoritiesMapper(GrantedAuthoritiesMapper grantedAuthoritiesMapper) {
public LdapAuthenticationProviderConfigurer<B> authoritiesMapper(
GrantedAuthoritiesMapper grantedAuthoritiesMapper) {
this.authoritiesMapper = grantedAuthoritiesMapper;
return this;
}
/**
* Gets the {@link GrantedAuthoritiesMapper} and defaults to {@link SimpleAuthorityMapper}.
*
* Gets the {@link GrantedAuthoritiesMapper} and defaults to
* {@link SimpleAuthorityMapper}.
* @return the {@link GrantedAuthoritiesMapper}
* @throws Exception if errors in {@link SimpleAuthorityMapper#afterPropertiesSet()}
*/
@@ -173,12 +182,10 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
/**
* Creates the {@link LdapAuthenticator} to use
*
* @param contextSource the {@link BaseLdapPathContextSource} to use
* @return the {@link LdapAuthenticator} to use
*/
private LdapAuthenticator createLdapAuthenticator(
BaseLdapPathContextSource contextSource) {
private LdapAuthenticator createLdapAuthenticator(BaseLdapPathContextSource contextSource) {
AbstractLdapAuthenticator ldapAuthenticator = passwordEncoder == null ? createBindAuthenticator(contextSource)
: createPasswordCompareAuthenticator(contextSource);
LdapUserSearch userSearch = createUserSearch();
@@ -193,14 +200,12 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
/**
* Creates {@link PasswordComparisonAuthenticator}
*
* @param contextSource the {@link BaseLdapPathContextSource} to use
* @return
*/
private PasswordComparisonAuthenticator createPasswordCompareAuthenticator(
BaseLdapPathContextSource contextSource) {
PasswordComparisonAuthenticator ldapAuthenticator = new PasswordComparisonAuthenticator(
contextSource);
PasswordComparisonAuthenticator ldapAuthenticator = new PasswordComparisonAuthenticator(contextSource);
if (passwordAttribute != null) {
ldapAuthenticator.setPasswordAttributeName(passwordAttribute);
}
@@ -210,12 +215,10 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
/**
* Creates a {@link BindAuthenticator}
*
* @param contextSource the {@link BaseLdapPathContextSource} to use
* @return the {@link BindAuthenticator} to use
*/
private BindAuthenticator createBindAuthenticator(
BaseLdapPathContextSource contextSource) {
private BindAuthenticator createBindAuthenticator(BaseLdapPathContextSource contextSource) {
return new BindAuthenticator(contextSource);
}
@@ -223,20 +226,17 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
if (userSearchFilter == null) {
return null;
}
return new FilterBasedLdapUserSearch(userSearchBase, userSearchFilter,
contextSource);
return new FilterBasedLdapUserSearch(userSearchBase, userSearchFilter, contextSource);
}
/**
* Specifies the {@link BaseLdapPathContextSource} to be used. If not specified, an
* embedded LDAP server will be created using {@link #contextSource()}.
*
* @param contextSource the {@link BaseLdapPathContextSource} to use
* @return the {@link LdapAuthenticationProviderConfigurer} for further customizations
* @see #contextSource()
*/
public LdapAuthenticationProviderConfigurer<B> contextSource(
BaseLdapPathContextSource contextSource) {
public LdapAuthenticationProviderConfigurer<B> contextSource(BaseLdapPathContextSource contextSource) {
this.contextSource = contextSource;
return this;
}
@@ -244,7 +244,6 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
/**
* Allows easily configuring of a {@link BaseLdapPathContextSource} with defaults
* pointing to an embedded LDAP server that is created.
*
* @return the {@link ContextSourceBuilder} for further customizations
*/
public ContextSourceBuilder contextSource() {
@@ -254,7 +253,6 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
/**
* Specifies the {@link org.springframework.security.crypto.password.PasswordEncoder}
* to be used when authenticating with password comparison.
*
* @param passwordEncoder the
* {@link org.springframework.security.crypto.password.PasswordEncoder} to use
* @return the {@link LdapAuthenticationProviderConfigurer} for further customization
@@ -273,12 +271,10 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
* property of AbstractLdapAuthenticator. The value is a specific pattern used to
* build the user's DN, for example "uid={0},ou=people". The key "{0}" must be present
* and will be substituted with the username.
*
* @param userDnPatterns the LDAP patterns for finding the usernames
* @return the {@link LdapAuthenticationProviderConfigurer} for further customizations
*/
public LdapAuthenticationProviderConfigurer<B> userDnPatterns(
String... userDnPatterns) {
public LdapAuthenticationProviderConfigurer<B> userDnPatterns(String... userDnPatterns) {
this.userDnPatterns = userDnPatterns;
return this;
}
@@ -287,7 +283,6 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
* Allows explicit customization of the loaded user object by specifying a
* UserDetailsContextMapper bean which will be called with the context information
* from the user's directory entry.
*
* @param userDetailsContextMapper the {@link UserDetailsContextMapper} to use
* @return the {@link LdapAuthenticationProviderConfigurer} for further customizations
*
@@ -306,8 +301,7 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
* @param groupRoleAttribute the attribute name that maps a group to a role.
* @return the {@link LdapAuthenticationProviderConfigurer} for further customizations
*/
public LdapAuthenticationProviderConfigurer<B> groupRoleAttribute(
String groupRoleAttribute) {
public LdapAuthenticationProviderConfigurer<B> groupRoleAttribute(String groupRoleAttribute) {
this.groupRoleAttribute = groupRoleAttribute;
return this;
}
@@ -323,11 +317,10 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
}
/**
* If set to true, a subtree scope search will be performed for group membership. If false a
* single-level search is used.
*
* If set to true, a subtree scope search will be performed for group membership. If
* false a single-level search is used.
* @param searchSubtree set to true to enable searching of the entire tree below the
* <tt>groupSearchBase</tt>.
* <tt>groupSearchBase</tt>.
* @return the {@link LdapAuthenticationProviderConfigurer} for further customizations
*/
public LdapAuthenticationProviderConfigurer<B> groupSearchSubtree(boolean groupSearchSubtree) {
@@ -338,12 +331,10 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
/**
* The LDAP filter to search for groups. Defaults to "(uniqueMember={0})". The
* substituted parameter is the DN of the user.
*
* @param groupSearchFilter the LDAP filter to search for groups
* @return the {@link LdapAuthenticationProviderConfigurer} for further customizations
*/
public LdapAuthenticationProviderConfigurer<B> groupSearchFilter(
String groupSearchFilter) {
public LdapAuthenticationProviderConfigurer<B> groupSearchFilter(String groupSearchFilter) {
this.groupSearchFilter = groupSearchFilter;
return this;
}
@@ -351,7 +342,6 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
/**
* A non-empty string prefix that will be added as a prefix to the existing roles. The
* default is "ROLE_".
*
* @param rolePrefix the prefix to be added to the roles that are loaded.
* @return the {@link LdapAuthenticationProviderConfigurer} for further customizations
* @see SimpleAuthorityMapper#setPrefix(String)
@@ -364,7 +354,6 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
/**
* Search base for user searches. Defaults to "". Only used with
* {@link #userSearchFilter(String)}.
*
* @param userSearchBase search base for user searches
* @return the {@link LdapAuthenticationProviderConfigurer} for further customizations
*/
@@ -376,12 +365,10 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
/**
* The LDAP filter used to search for users (optional). For example "(uid={0})". The
* substituted parameter is the user's login name.
*
* @param userSearchFilter the LDAP filter used to search for users
* @return the {@link LdapAuthenticationProviderConfigurer} for further customizations
*/
public LdapAuthenticationProviderConfigurer<B> userSearchFilter(
String userSearchFilter) {
public LdapAuthenticationProviderConfigurer<B> userSearchFilter(String userSearchFilter) {
this.userSearchFilter = userSearchFilter;
return this;
}
@@ -413,7 +400,6 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
/**
* The attribute in the directory which contains the user password. Defaults to
* "userPassword".
*
* @param passwordAttribute the attribute in the directory which contains the user
* password
* @return the {@link PasswordCompareConfigurer} for further customizations
@@ -426,7 +412,6 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
/**
* Allows obtaining a reference to the
* {@link LdapAuthenticationProviderConfigurer} for further customizations
*
* @return attribute in the directory which contains the user password
*/
public LdapAuthenticationProviderConfigurer<B> and() {
@@ -435,6 +420,7 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
private PasswordCompareConfigurer() {
}
}
/**
@@ -446,23 +432,30 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
* @since 3.2
*/
public final class ContextSourceBuilder {
private static final String APACHEDS_CLASSNAME = "org.apache.directory.server.core.DefaultDirectoryService";
private static final String UNBOUNDID_CLASSNAME = "com.unboundid.ldap.listener.InMemoryDirectoryServer";
private static final int DEFAULT_PORT = 33389;
private static final int RANDOM_PORT = 0;
private String ldif = "classpath*:*.ldif";
private String managerPassword;
private String managerDn;
private Integer port;
private String root = "dc=springframework,dc=org";
private String url;
/**
* Specifies an ldif to load at startup for an embedded LDAP server. This only
* loads if using an embedded instance. The default is "classpath*:*.ldif".
*
* @param ldif the ldif to load at startup for an embedded LDAP server.
* @return the {@link ContextSourceBuilder} for further customization
*/
@@ -475,7 +468,6 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
* Username (DN) of the "manager" user identity (i.e. "uid=admin,ou=system") which
* will be used to authenticate to a (non-embedded) LDAP server. If omitted,
* anonymous access will be used.
*
* @param managerDn the username (DN) of the "manager" user identity used to
* authenticate to a LDAP server.
* @return the {@link ContextSourceBuilder} for further customization
@@ -500,8 +492,8 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
* The port to connect to LDAP to (the default is 33389 or random available port
* if unavailable).
*
* Supplying 0 as the port indicates that a random available port should be selected.
*
* Supplying 0 as the port indicates that a random available port should be
* selected.
* @param port the port to connect to
* @return the {@link ContextSourceBuilder} for further customization
*/
@@ -513,7 +505,6 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
/**
* Optional root suffix for the embedded LDAP server. Default is
* "dc=springframework,dc=org"
*
* @param root root suffix for the embedded LDAP server
* @return the {@link ContextSourceBuilder} for further customization
*/
@@ -525,7 +516,6 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
/**
* Specifies the ldap server URL when not using the embedded LDAP server. For
* example, "ldaps://ldap.example.com:33389/dc=myco,dc=org".
*
* @param url the ldap server URL
* @return the {@link ContextSourceBuilder} for further customization
*/
@@ -537,7 +527,6 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
/**
* Gets the {@link LdapAuthenticationProviderConfigurer} for further
* customizations
*
* @return the {@link LdapAuthenticationProviderConfigurer} for further
* customizations
*/
@@ -550,13 +539,11 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
startEmbeddedLdapServer();
}
DefaultSpringSecurityContextSource contextSource = new DefaultSpringSecurityContextSource(
getProviderUrl());
DefaultSpringSecurityContextSource contextSource = new DefaultSpringSecurityContextSource(getProviderUrl());
if (managerDn != null) {
contextSource.setUserDn(managerDn);
if (managerPassword == null) {
throw new IllegalStateException(
"managerPassword is required if managerDn is supplied");
throw new IllegalStateException("managerPassword is required if managerDn is supplied");
}
contextSource.setPassword(managerPassword);
}
@@ -592,7 +579,8 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
private int getDefaultPort() {
try (ServerSocket serverSocket = new ServerSocket(DEFAULT_PORT)) {
return serverSocket.getLocalPort();
} catch (IOException e) {
}
catch (IOException e) {
return RANDOM_PORT;
}
}
@@ -606,6 +594,7 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
private ContextSourceBuilder() {
}
}
private BaseLdapPathContextSource getContextSource() throws Exception {
@@ -622,4 +611,5 @@ public class LdapAuthenticationProviderConfigurer<B extends ProviderManagerBuild
return new PasswordCompareConfigurer().passwordAttribute("password")
.passwordEncoder(NoOpPasswordEncoder.getInstance());
}
}
@@ -27,7 +27,6 @@ import org.springframework.security.provisioning.InMemoryUserDetailsManager;
* authentication.
*
* @param <B> the type of the {@link ProviderManagerBuilder} that is being configured
*
* @author Rob Winch
* @since 3.2
*/
@@ -40,4 +39,5 @@ public class InMemoryUserDetailsManagerConfigurer<B extends ProviderManagerBuild
public InMemoryUserDetailsManagerConfigurer() {
super(new InMemoryUserDetailsManager(new ArrayList<>()));
}
}
@@ -40,7 +40,6 @@ import org.springframework.security.provisioning.JdbcUserDetailsManager;
* methods have reasonable defaults.
*
* @param <B> the type of the {@link ProviderManagerBuilder} that is being configured
*
* @author Rob Winch
* @since 3.2
*/
@@ -61,9 +60,9 @@ public class JdbcUserDetailsManagerConfigurer<B extends ProviderManagerBuilder<B
/**
* Populates the {@link DataSource} to be used. This is the only required attribute.
*
* @param dataSource the {@link DataSource} to be used. Cannot be null.
* @return The {@link JdbcUserDetailsManagerConfigurer} used for additional customizations
* @return The {@link JdbcUserDetailsManagerConfigurer} used for additional
* customizations
*/
public JdbcUserDetailsManagerConfigurer<B> dataSource(DataSource dataSource) {
this.dataSource = dataSource;
@@ -94,7 +93,6 @@ public class JdbcUserDetailsManagerConfigurer<B extends ProviderManagerBuilder<B
* <code>
* select username,authority from authorities where username = ?
* </code>
*
* @param query The query to use for selecting the username, authority by username.
* Must contain a single parameter for the username.
* @return The {@link JdbcUserDetailsManagerConfigurer} used for additional
@@ -116,7 +114,6 @@ public class JdbcUserDetailsManagerConfigurer<B extends ProviderManagerBuilder<B
* where
* gm.username = ? and g.id = ga.group_id and g.id = gm.group_id
* </code>
*
* @param query The query to use for selecting the authorities by group. Must contain
* a single parameter for the username.
* @return The {@link JdbcUserDetailsManagerConfigurer} used for additional
@@ -132,9 +129,9 @@ public class JdbcUserDetailsManagerConfigurer<B extends ProviderManagerBuilder<B
/**
* A non-empty string prefix that will be added to role strings loaded from persistent
* storage (default is "").
*
* @param rolePrefix
* @return The {@link JdbcUserDetailsManagerConfigurer} used for additional customizations
* @return The {@link JdbcUserDetailsManagerConfigurer} used for additional
* customizations
*/
public JdbcUserDetailsManagerConfigurer<B> rolePrefix(String rolePrefix) {
getUserDetailsService().setRolePrefix(rolePrefix);
@@ -143,7 +140,6 @@ public class JdbcUserDetailsManagerConfigurer<B extends ProviderManagerBuilder<B
/**
* Defines the {@link UserCache} to use
*
* @param userCache the {@link UserCache} to use
* @return the {@link JdbcUserDetailsManagerConfigurer} for further customizations
*/
@@ -167,13 +163,11 @@ public class JdbcUserDetailsManagerConfigurer<B extends ProviderManagerBuilder<B
/**
* Populates the default schema that allows users and authorities to be stored.
*
* @return The {@link JdbcUserDetailsManagerConfigurer} used for additional
* customizations
*/
public JdbcUserDetailsManagerConfigurer<B> withDefaultSchema() {
this.initScripts.add(new ClassPathResource(
"org/springframework/security/core/userdetails/jdbc/users.ddl"));
this.initScripts.add(new ClassPathResource("org/springframework/security/core/userdetails/jdbc/users.ddl"));
return this;
}
@@ -189,4 +183,5 @@ public class JdbcUserDetailsManagerConfigurer<B extends ProviderManagerBuilder<B
dsi.setDataSource(dataSource);
return dsi;
}
}
@@ -34,7 +34,6 @@ import org.springframework.security.provisioning.UserDetailsManager;
*
* @param <B> the type of the {@link SecurityBuilder} that is being configured
* @param <C> the type of {@link UserDetailsManagerConfigurer}
*
* @author Rob Winch
* @since 3.2
*/
@@ -51,7 +50,6 @@ public class UserDetailsManagerConfigurer<B extends ProviderManagerBuilder<B>, C
/**
* Populates the users that have been added.
*
* @throws Exception
*/
@Override
@@ -67,7 +65,6 @@ public class UserDetailsManagerConfigurer<B extends ProviderManagerBuilder<B>, C
/**
* Allows adding a user to the {@link UserDetailsManager} that is being created. This
* method can be invoked multiple times to add multiple users.
*
* @param userDetails the user to add. Cannot be null.
* @return the {@link UserDetailsBuilder} for further customizations
*/
@@ -80,7 +77,6 @@ public class UserDetailsManagerConfigurer<B extends ProviderManagerBuilder<B>, C
/**
* Allows adding a user to the {@link UserDetailsManager} that is being created. This
* method can be invoked multiple times to add multiple users.
*
* @param userBuilder the user to add. Cannot be null.
* @return the {@link UserDetailsBuilder} for further customizations
*/
@@ -93,7 +89,6 @@ public class UserDetailsManagerConfigurer<B extends ProviderManagerBuilder<B>, C
/**
* Allows adding a user to the {@link UserDetailsManager} that is being created. This
* method can be invoked multiple times to add multiple users.
*
* @param username the username for the user being added. Cannot be null.
* @return the {@link UserDetailsBuilder} for further customizations
*/
@@ -110,7 +105,9 @@ public class UserDetailsManagerConfigurer<B extends ProviderManagerBuilder<B>, C
* should provided. The remaining attributes have reasonable defaults.
*/
public class UserDetailsBuilder {
private UserBuilder user;
private final C builder;
/**
@@ -122,9 +119,8 @@ public class UserDetailsManagerConfigurer<B extends ProviderManagerBuilder<B>, C
}
/**
* Returns the {@link UserDetailsManagerConfigurer} for method chaining (i.e. to add
* another user)
*
* Returns the {@link UserDetailsManagerConfigurer} for method chaining (i.e. to
* add another user)
* @return the {@link UserDetailsManagerConfigurer} for method chaining
*/
public C and() {
@@ -133,7 +129,6 @@ public class UserDetailsManagerConfigurer<B extends ProviderManagerBuilder<B>, C
/**
* Populates the username. This attribute is required.
*
* @param username the username. Cannot be null.
* @return the {@link UserDetailsBuilder} for method chaining (i.e. to populate
* additional attributes for this user)
@@ -145,7 +140,6 @@ public class UserDetailsManagerConfigurer<B extends ProviderManagerBuilder<B>, C
/**
* Populates the password. This attribute is required.
*
* @param password the password. Cannot be null.
* @return the {@link UserDetailsBuilder} for method chaining (i.e. to populate
* additional attributes for this user)
@@ -174,7 +168,6 @@ public class UserDetailsManagerConfigurer<B extends ProviderManagerBuilder<B>, C
* This attribute is required, but can also be populated with
* {@link #authorities(String...)}.
* </p>
*
* @param roles the roles for this user (i.e. USER, ADMIN, etc). Cannot be null,
* contain null values or start with "ROLE_"
* @return the {@link UserDetailsBuilder} for method chaining (i.e. to populate
@@ -187,7 +180,6 @@ public class UserDetailsManagerConfigurer<B extends ProviderManagerBuilder<B>, C
/**
* Populates the authorities. This attribute is required.
*
* @param authorities the authorities for this user. Cannot be null, or contain
* null values
* @return the {@link UserDetailsBuilder} for method chaining (i.e. to populate
@@ -201,7 +193,6 @@ public class UserDetailsManagerConfigurer<B extends ProviderManagerBuilder<B>, C
/**
* Populates the authorities. This attribute is required.
*
* @param authorities the authorities for this user. Cannot be null, or contain
* null values
* @return the {@link UserDetailsBuilder} for method chaining (i.e. to populate
@@ -215,7 +206,6 @@ public class UserDetailsManagerConfigurer<B extends ProviderManagerBuilder<B>, C
/**
* Populates the authorities. This attribute is required.
*
* @param authorities the authorities for this user (i.e. ROLE_USER, ROLE_ADMIN,
* etc). Cannot be null, or contain null values
* @return the {@link UserDetailsBuilder} for method chaining (i.e. to populate
@@ -229,7 +219,6 @@ public class UserDetailsManagerConfigurer<B extends ProviderManagerBuilder<B>, C
/**
* Defines if the account is expired or not. Default is false.
*
* @param accountExpired true if the account is expired, false otherwise
* @return the {@link UserDetailsBuilder} for method chaining (i.e. to populate
* additional attributes for this user)
@@ -241,7 +230,6 @@ public class UserDetailsManagerConfigurer<B extends ProviderManagerBuilder<B>, C
/**
* Defines if the account is locked or not. Default is false.
*
* @param accountLocked true if the account is locked, false otherwise
* @return the {@link UserDetailsBuilder} for method chaining (i.e. to populate
* additional attributes for this user)
@@ -253,7 +241,6 @@ public class UserDetailsManagerConfigurer<B extends ProviderManagerBuilder<B>, C
/**
* Defines if the credentials are expired or not. Default is false.
*
* @param credentialsExpired true if the credentials are expired, false otherwise
* @return the {@link UserDetailsBuilder} for method chaining (i.e. to populate
* additional attributes for this user)
@@ -265,7 +252,6 @@ public class UserDetailsManagerConfigurer<B extends ProviderManagerBuilder<B>, C
/**
* Defines if the account is disabled or not. Default is false.
*
* @param disabled true if the account is disabled, false otherwise
* @return the {@link UserDetailsBuilder} for method chaining (i.e. to populate
* additional attributes for this user)
@@ -278,5 +264,7 @@ public class UserDetailsManagerConfigurer<B extends ProviderManagerBuilder<B>, C
UserDetails build() {
return this.user.build();
}
}
}
@@ -28,7 +28,6 @@ import org.springframework.security.core.userdetails.UserDetailsPasswordService;
*
* @author Rob Winch
* @since 3.2
*
* @param <B> the type of the {@link SecurityBuilder}
* @param <C> the type of {@link AbstractDaoAuthenticationConfigurer} this is
* @param <U> The type of {@link UserDetailsService} that is being used
@@ -36,12 +35,13 @@ import org.springframework.security.core.userdetails.UserDetailsPasswordService;
*/
abstract class AbstractDaoAuthenticationConfigurer<B extends ProviderManagerBuilder<B>, C extends AbstractDaoAuthenticationConfigurer<B, C, U>, U extends UserDetailsService>
extends UserDetailsAwareConfigurer<B, U> {
private DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
private final U userDetailsService;
/**
* Creates a new instance
*
* @param userDetailsService
*/
protected AbstractDaoAuthenticationConfigurer(U userDetailsService) {
@@ -54,7 +54,6 @@ abstract class AbstractDaoAuthenticationConfigurer<B extends ProviderManagerBuil
/**
* Adds an {@link ObjectPostProcessor} for this class.
*
* @param objectPostProcessor
* @return the {@link AbstractDaoAuthenticationConfigurer} for further customizations
*/
@@ -67,7 +66,6 @@ abstract class AbstractDaoAuthenticationConfigurer<B extends ProviderManagerBuil
/**
* Allows specifying the {@link PasswordEncoder} to use with the
* {@link DaoAuthenticationProvider}. The default is to use plain text.
*
* @param passwordEncoder The {@link PasswordEncoder} to use.
* @return the {@link AbstractDaoAuthenticationConfigurer} for further customizations
*/
@@ -91,11 +89,11 @@ abstract class AbstractDaoAuthenticationConfigurer<B extends ProviderManagerBuil
/**
* Gets the {@link UserDetailsService} that is used with the
* {@link DaoAuthenticationProvider}
*
* @return the {@link UserDetailsService} that is used with the
* {@link DaoAuthenticationProvider}
*/
public U getUserDetailsService() {
return userDetailsService;
}
}
@@ -24,14 +24,12 @@ import org.springframework.security.core.userdetails.UserDetailsService;
*
* @author Rob Winch
* @since 3.2
*
* @param <B> The type of {@link ProviderManagerBuilder} this is
* @param <U> The type of {@link UserDetailsService} that is being used
*
*/
public class DaoAuthenticationConfigurer<B extends ProviderManagerBuilder<B>, U extends UserDetailsService>
extends
AbstractDaoAuthenticationConfigurer<B, DaoAuthenticationConfigurer<B, U>, U> {
extends AbstractDaoAuthenticationConfigurer<B, DaoAuthenticationConfigurer<B, U>, U> {
/**
* Creates a new instance
@@ -40,4 +38,5 @@ public class DaoAuthenticationConfigurer<B extends ProviderManagerBuilder<B>, U
public DaoAuthenticationConfigurer(U userDetailsService) {
super(userDetailsService);
}
}
@@ -26,7 +26,6 @@ import org.springframework.security.core.userdetails.UserDetailsService;
* value with {@link AuthenticationManagerBuilder}.
*
* @author Rob Winch
*
* @param <B> the type of the {@link ProviderManagerBuilder}
* @param <U> the type of {@link UserDetailsService}
*/
@@ -38,4 +37,5 @@ public abstract class UserDetailsAwareConfigurer<B extends ProviderManagerBuilde
* @return the {@link UserDetailsService} or null if it is not available
*/
public abstract U getUserDetailsService();
}
@@ -25,7 +25,6 @@ import org.springframework.security.core.userdetails.UserDetailsService;
*
* @author Rob Winch
* @since 3.2
*
* @param <B> the type of the {@link ProviderManagerBuilder}
* @param <C> the {@link UserDetailsServiceConfigurer} (or this)
* @param <U> the type of UserDetailsService being used to allow for returning the
@@ -55,4 +54,5 @@ public class UserDetailsServiceConfigurer<B extends ProviderManagerBuilder<B>, C
*/
protected void initUserDetailsService() throws Exception {
}
}
@@ -39,13 +39,16 @@ import org.springframework.util.Assert;
*/
final class AutowireBeanFactoryObjectPostProcessor
implements ObjectPostProcessor<Object>, DisposableBean, SmartInitializingSingleton {
private final Log logger = LogFactory.getLog(getClass());
private final AutowireCapableBeanFactory autowireBeanFactory;
private final List<DisposableBean> disposableBeans = new ArrayList<>();
private final List<SmartInitializingSingleton> smartSingletons = new ArrayList<>();
AutowireBeanFactoryObjectPostProcessor(
AutowireCapableBeanFactory autowireBeanFactory) {
AutowireBeanFactoryObjectPostProcessor(AutowireCapableBeanFactory autowireBeanFactory) {
Assert.notNull(autowireBeanFactory, "autowireBeanFactory cannot be null");
this.autowireBeanFactory = autowireBeanFactory;
}
@@ -64,13 +67,11 @@ final class AutowireBeanFactoryObjectPostProcessor
}
T result = null;
try {
result = (T) this.autowireBeanFactory.initializeBean(object,
object.toString());
result = (T) this.autowireBeanFactory.initializeBean(object, object.toString());
}
catch (RuntimeException e) {
Class<?> type = object.getClass();
throw new RuntimeException(
"Could not postProcess " + object + " of type " + type, e);
throw new RuntimeException("Could not postProcess " + object + " of type " + type, e);
}
this.autowireBeanFactory.autowireBean(object);
if (result instanceof DisposableBean) {
@@ -82,8 +83,11 @@ final class AutowireBeanFactoryObjectPostProcessor
return result;
}
/* (non-Javadoc)
* @see org.springframework.beans.factory.SmartInitializingSingleton#afterSingletonsInstantiated()
/*
* (non-Javadoc)
*
* @see org.springframework.beans.factory.SmartInitializingSingleton#
* afterSingletonsInstantiated()
*/
@Override
public void afterSingletonsInstantiated() {
@@ -31,7 +31,6 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe
*
* @see EnableWebSecurity
* @see EnableGlobalMethodSecurity
*
* @author Rob Winch
* @since 3.2
*/
@@ -41,8 +40,8 @@ public class ObjectPostProcessorConfiguration {
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public ObjectPostProcessor<Object> objectPostProcessor(
AutowireCapableBeanFactory beanFactory) {
public ObjectPostProcessor<Object> objectPostProcessor(AutowireCapableBeanFactory beanFactory) {
return new AutowireBeanFactoryObjectPostProcessor(beanFactory);
}
}
@@ -28,8 +28,8 @@ import org.springframework.security.config.annotation.authentication.configurati
/**
* <p>
* Enables Spring Security global method security similar to the &lt;global-method-security&gt;
* xml support.
* Enables Spring Security global method security similar to the
* &lt;global-method-security&gt; xml support.
*
* <p>
* More advanced configurations may wish to extend
@@ -82,7 +82,6 @@ public @interface EnableGlobalMethodSecurity {
* annotation will be upgraded to subclass proxying at the same time. This approach
* has no negative impact in practice unless one is explicitly expecting one type of
* proxy vs another, e.g. in tests.
*
* @return true if CGILIB proxies should be created instead of interface based
* proxies, else false
*/
@@ -92,7 +91,6 @@ public @interface EnableGlobalMethodSecurity {
* Indicate how security advice should be applied. The default is
* {@link AdviceMode#PROXY}.
* @see AdviceMode
*
* @return the {@link AdviceMode} to use
*/
AdviceMode mode() default AdviceMode.PROXY;
@@ -101,8 +99,8 @@ public @interface EnableGlobalMethodSecurity {
* Indicate the ordering of the execution of the security advisor when multiple
* advices are applied at a specific joinpoint. The default is
* {@link Ordered#LOWEST_PRECEDENCE}.
*
* @return the order the security advisor should be applied
*/
int order() default Ordered.LOWEST_PRECEDENCE;
}
@@ -36,16 +36,18 @@ import java.lang.annotation.Target;
@Import({ ReactiveMethodSecuritySelector.class })
@Configuration
public @interface EnableReactiveMethodSecurity {
/**
* Indicate whether subclass-based (CGLIB) proxies are to be created as opposed
* to standard Java interface-based proxies. The default is {@code false}. <strong>
* Indicate whether subclass-based (CGLIB) proxies are to be created as opposed to
* standard Java interface-based proxies. The default is {@code false}. <strong>
* Applicable only if {@link #mode()} is set to {@link AdviceMode#PROXY}</strong>.
* <p>Note that setting this attribute to {@code true} will affect <em>all</em>
* Spring-managed beans requiring proxying, not just those marked with {@code @Cacheable}.
* For example, other beans marked with Spring's {@code @Transactional} annotation will
* be upgraded to subclass proxying at the same time. This approach has no negative
* impact in practice unless one is explicitly expecting one type of proxy vs another,
* e.g. in tests.
* <p>
* Note that setting this attribute to {@code true} will affect <em>all</em>
* Spring-managed beans requiring proxying, not just those marked with
* {@code @Cacheable}. For example, other beans marked with Spring's
* {@code @Transactional} annotation will be upgraded to subclass proxying at the same
* time. This approach has no negative impact in practice unless one is explicitly
* expecting one type of proxy vs another, e.g. in tests.
*/
boolean proxyTargetClass() default false;
@@ -53,7 +55,6 @@ public @interface EnableReactiveMethodSecurity {
* Indicate how security advice should be applied. The default is
* {@link AdviceMode#PROXY}.
* @see AdviceMode
*
* @return the {@link AdviceMode} to use
*/
AdviceMode mode() default AdviceMode.PROXY;
@@ -62,8 +63,8 @@ public @interface EnableReactiveMethodSecurity {
* Indicate the ordering of the execution of the security advisor when multiple
* advices are applied at a specific joinpoint. The default is
* {@link Ordered#LOWEST_PRECEDENCE}.
*
* @return the order the security advisor should be applied
*/
int order() default Ordered.LOWEST_PRECEDENCE;
}
@@ -36,28 +36,24 @@ import org.springframework.core.type.AnnotationMetadata;
* @author Rob Winch
* @since 3.2
*/
class GlobalMethodSecurityAspectJAutoProxyRegistrar implements
ImportBeanDefinitionRegistrar {
class GlobalMethodSecurityAspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
/**
* Register, escalate, and configure the AspectJ auto proxy creator based on the value
* of the @{@link EnableGlobalMethodSecurity#proxyTargetClass()} attribute on the
* importing {@code @Configuration} class.
*/
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
BeanDefinition interceptor = registry
.getBeanDefinition("methodSecurityInterceptor");
BeanDefinition interceptor = registry.getBeanDefinition("methodSecurityInterceptor");
BeanDefinitionBuilder aspect = BeanDefinitionBuilder
.rootBeanDefinition("org.springframework.security.access.intercept.aspectj.aspect.AnnotationSecurityAspect");
BeanDefinitionBuilder aspect = BeanDefinitionBuilder.rootBeanDefinition(
"org.springframework.security.access.intercept.aspectj.aspect.AnnotationSecurityAspect");
aspect.setFactoryMethod("aspectOf");
aspect.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
aspect.addPropertyValue("securityInterceptor", interceptor);
registry.registerBeanDefinition("annotationSecurityAspect$0",
aspect.getBeanDefinition());
registry.registerBeanDefinition("annotationSecurityAspect$0", aspect.getBeanDefinition());
}
}
@@ -82,24 +82,31 @@ import org.springframework.util.Assert;
*/
@Configuration(proxyBeanMethods = false)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class GlobalMethodSecurityConfiguration
implements ImportAware, SmartInitializingSingleton, BeanFactoryAware {
private static final Log logger = LogFactory
.getLog(GlobalMethodSecurityConfiguration.class);
public class GlobalMethodSecurityConfiguration implements ImportAware, SmartInitializingSingleton, BeanFactoryAware {
private static final Log logger = LogFactory.getLog(GlobalMethodSecurityConfiguration.class);
private ObjectPostProcessor<Object> objectPostProcessor = new ObjectPostProcessor<Object>() {
public <T> T postProcess(T object) {
throw new IllegalStateException(ObjectPostProcessor.class.getName()
+ " is a required bean. Ensure you have used @"
+ EnableGlobalMethodSecurity.class.getName());
+ " is a required bean. Ensure you have used @" + EnableGlobalMethodSecurity.class.getName());
}
};
private DefaultMethodSecurityExpressionHandler defaultMethodExpressionHandler = new DefaultMethodSecurityExpressionHandler();
private AuthenticationManager authenticationManager;
private AuthenticationManagerBuilder auth;
private boolean disableAuthenticationRegistry;
private AnnotationAttributes enableMethodSecurity;
private BeanFactory context;
private MethodSecurityExpressionHandler expressionHandler;
private MethodSecurityInterceptor methodSecurityInterceptor;
/**
@@ -117,19 +124,17 @@ public class GlobalMethodSecurityConfiguration
* Subclasses can override this method to provide a different
* {@link MethodInterceptor}.
* </p>
* @param methodSecurityMetadataSource the default {@link MethodSecurityMetadataSource}.
*
* @param methodSecurityMetadataSource the default
* {@link MethodSecurityMetadataSource}.
* @return the {@link MethodInterceptor}.
*/
@Bean
public MethodInterceptor methodSecurityInterceptor(MethodSecurityMetadataSource methodSecurityMetadataSource) {
this.methodSecurityInterceptor = isAspectJ()
? new AspectJMethodSecurityInterceptor()
this.methodSecurityInterceptor = isAspectJ() ? new AspectJMethodSecurityInterceptor()
: new MethodSecurityInterceptor();
methodSecurityInterceptor.setAccessDecisionManager(accessDecisionManager());
methodSecurityInterceptor.setAfterInvocationManager(afterInvocationManager());
methodSecurityInterceptor
.setSecurityMetadataSource(methodSecurityMetadataSource);
methodSecurityInterceptor.setSecurityMetadataSource(methodSecurityMetadataSource);
RunAsManager runAsManager = runAsManager();
if (runAsManager != null) {
methodSecurityInterceptor.setRunAsManager(runAsManager);
@@ -153,11 +158,9 @@ public class GlobalMethodSecurityConfiguration
throw new RuntimeException(e);
}
PermissionEvaluator permissionEvaluator = getSingleBeanOrNull(
PermissionEvaluator.class);
PermissionEvaluator permissionEvaluator = getSingleBeanOrNull(PermissionEvaluator.class);
if (permissionEvaluator != null) {
this.defaultMethodExpressionHandler
.setPermissionEvaluator(permissionEvaluator);
this.defaultMethodExpressionHandler.setPermissionEvaluator(permissionEvaluator);
}
RoleHierarchy roleHierarchy = getSingleBeanOrNull(RoleHierarchy.class);
@@ -165,24 +168,23 @@ public class GlobalMethodSecurityConfiguration
this.defaultMethodExpressionHandler.setRoleHierarchy(roleHierarchy);
}
AuthenticationTrustResolver trustResolver = getSingleBeanOrNull(
AuthenticationTrustResolver.class);
AuthenticationTrustResolver trustResolver = getSingleBeanOrNull(AuthenticationTrustResolver.class);
if (trustResolver != null) {
this.defaultMethodExpressionHandler.setTrustResolver(trustResolver);
}
GrantedAuthorityDefaults grantedAuthorityDefaults = getSingleBeanOrNull(
GrantedAuthorityDefaults.class);
GrantedAuthorityDefaults grantedAuthorityDefaults = getSingleBeanOrNull(GrantedAuthorityDefaults.class);
if (grantedAuthorityDefaults != null) {
this.defaultMethodExpressionHandler.setDefaultRolePrefix(
grantedAuthorityDefaults.getRolePrefix());
this.defaultMethodExpressionHandler.setDefaultRolePrefix(grantedAuthorityDefaults.getRolePrefix());
}
}
private <T> T getSingleBeanOrNull(Class<T> type) {
try {
return context.getBean(type);
} catch (NoSuchBeanDefinitionException e) {}
}
catch (NoSuchBeanDefinitionException e) {
}
return null;
}
@@ -195,14 +197,14 @@ public class GlobalMethodSecurityConfiguration
/**
* Provide a custom {@link AfterInvocationManager} for the default implementation of
* {@link #methodSecurityInterceptor(MethodSecurityMetadataSource)}. The default is null
* if pre post is not enabled. Otherwise, it returns a {@link AfterInvocationProviderManager}.
* {@link #methodSecurityInterceptor(MethodSecurityMetadataSource)}. The default is
* null if pre post is not enabled. Otherwise, it returns a
* {@link AfterInvocationProviderManager}.
*
* <p>
* Subclasses should override this method to provide a custom
* {@link AfterInvocationManager}
* </p>
*
* @return the {@link AfterInvocationManager} to use
*/
protected AfterInvocationManager afterInvocationManager() {
@@ -210,8 +212,7 @@ public class GlobalMethodSecurityConfiguration
AfterInvocationProviderManager invocationProviderManager = new AfterInvocationProviderManager();
ExpressionBasedPostInvocationAdvice postAdvice = new ExpressionBasedPostInvocationAdvice(
getExpressionHandler());
PostInvocationAdviceProvider postInvocationAdviceProvider = new PostInvocationAdviceProvider(
postAdvice);
PostInvocationAdviceProvider postInvocationAdviceProvider = new PostInvocationAdviceProvider(postAdvice);
List<AfterInvocationProvider> afterInvocationProviders = new ArrayList<>();
afterInvocationProviders.add(postInvocationAdviceProvider);
invocationProviderManager.setProviders(afterInvocationProviders);
@@ -222,8 +223,8 @@ public class GlobalMethodSecurityConfiguration
/**
* Provide a custom {@link RunAsManager} for the default implementation of
* {@link #methodSecurityInterceptor(MethodSecurityMetadataSource)}. The default is null.
*
* {@link #methodSecurityInterceptor(MethodSecurityMetadataSource)}. The default is
* null.
* @return the {@link RunAsManager} to use
*/
protected RunAsManager runAsManager() {
@@ -239,24 +240,20 @@ public class GlobalMethodSecurityConfiguration
* <li>{@link RoleVoter}</li>
* <li>{@link AuthenticatedVoter}</li>
* </ul>
*
* @return the {@link AccessDecisionManager} to use
*/
protected AccessDecisionManager accessDecisionManager() {
List<AccessDecisionVoter<?>> decisionVoters = new ArrayList<>();
if (prePostEnabled()) {
ExpressionBasedPreInvocationAdvice expressionAdvice =
new ExpressionBasedPreInvocationAdvice();
ExpressionBasedPreInvocationAdvice expressionAdvice = new ExpressionBasedPreInvocationAdvice();
expressionAdvice.setExpressionHandler(getExpressionHandler());
decisionVoters
.add(new PreInvocationAuthorizationAdviceVoter(expressionAdvice));
decisionVoters.add(new PreInvocationAuthorizationAdviceVoter(expressionAdvice));
}
if (jsr250Enabled()) {
decisionVoters.add(new Jsr250Voter());
}
RoleVoter roleVoter = new RoleVoter();
GrantedAuthorityDefaults grantedAuthorityDefaults =
getSingleBeanOrNull(GrantedAuthorityDefaults.class);
GrantedAuthorityDefaults grantedAuthorityDefaults = getSingleBeanOrNull(GrantedAuthorityDefaults.class);
if (grantedAuthorityDefaults != null) {
roleVoter.setRolePrefix(grantedAuthorityDefaults.getRolePrefix());
}
@@ -275,7 +272,6 @@ public class GlobalMethodSecurityConfiguration
* Subclasses may override this method to provide a custom
* {@link MethodSecurityExpressionHandler}
* </p>
*
* @return the {@link MethodSecurityExpressionHandler} to use
*/
protected MethodSecurityExpressionHandler createExpressionHandler() {
@@ -285,7 +281,6 @@ public class GlobalMethodSecurityConfiguration
/**
* Gets the {@link MethodSecurityExpressionHandler} or creates it using
* {@link #expressionHandler}.
*
* @return a non {@code null} {@link MethodSecurityExpressionHandler}
*/
protected final MethodSecurityExpressionHandler getExpressionHandler() {
@@ -298,7 +293,6 @@ public class GlobalMethodSecurityConfiguration
/**
* Provides a custom {@link MethodSecurityMetadataSource} that is registered with the
* {@link #methodSecurityMetadataSource()}. Default is null.
*
* @return a custom {@link MethodSecurityMetadataSource} that is registered with the
* {@link #methodSecurityMetadataSource()}
*/
@@ -312,7 +306,6 @@ public class GlobalMethodSecurityConfiguration
* {@link #configure(AuthenticationManagerBuilder)}. If
* {@link #configure(AuthenticationManagerBuilder)} was not overridden, then an
* {@link AuthenticationManager} is attempted to be autowired by type.
*
* @return the {@link AuthenticationManager} to use
*/
protected AuthenticationManager authenticationManager() throws Exception {
@@ -323,8 +316,7 @@ public class GlobalMethodSecurityConfiguration
auth.authenticationEventPublisher(eventPublisher);
configure(auth);
if (disableAuthenticationRegistry) {
authenticationManager = getAuthenticationConfiguration()
.getAuthenticationManager();
authenticationManager = getAuthenticationConfiguration().getAuthenticationManager();
}
else {
authenticationManager = auth.build();
@@ -337,7 +329,6 @@ public class GlobalMethodSecurityConfiguration
* Sub classes can override this method to register different types of authentication.
* If not overridden, {@link #configure(AuthenticationManagerBuilder)} will attempt to
* autowire by type.
*
* @param auth the {@link AuthenticationManagerBuilder} used to register different
* authentication mechanisms for the global method security.
* @throws Exception
@@ -351,7 +342,6 @@ public class GlobalMethodSecurityConfiguration
* creates a {@link DelegatingMethodSecurityMetadataSource} based upon
* {@link #customMethodSecurityMetadataSource()} and the attributes on
* {@link EnableGlobalMethodSecurity}.
*
* @return the {@link MethodSecurityMetadataSource}
*/
@Bean
@@ -370,8 +360,8 @@ public class GlobalMethodSecurityConfiguration
boolean isJsr250Enabled = jsr250Enabled();
if (!isPrePostEnabled && !isSecuredEnabled && !isJsr250Enabled && !hasCustom) {
throw new IllegalStateException("In the composition of all global method configuration, " +
"no annotation support was actually activated");
throw new IllegalStateException("In the composition of all global method configuration, "
+ "no annotation support was actually activated");
}
if (isPrePostEnabled) {
@@ -381,12 +371,11 @@ public class GlobalMethodSecurityConfiguration
sources.add(new SecuredAnnotationSecurityMetadataSource());
}
if (isJsr250Enabled) {
GrantedAuthorityDefaults grantedAuthorityDefaults =
getSingleBeanOrNull(GrantedAuthorityDefaults.class);
Jsr250MethodSecurityMetadataSource jsr250MethodSecurityMetadataSource = this.context.getBean(Jsr250MethodSecurityMetadataSource.class);
GrantedAuthorityDefaults grantedAuthorityDefaults = getSingleBeanOrNull(GrantedAuthorityDefaults.class);
Jsr250MethodSecurityMetadataSource jsr250MethodSecurityMetadataSource = this.context
.getBean(Jsr250MethodSecurityMetadataSource.class);
if (grantedAuthorityDefaults != null) {
jsr250MethodSecurityMetadataSource.setDefaultRolePrefix(
grantedAuthorityDefaults.getRolePrefix());
jsr250MethodSecurityMetadataSource.setDefaultRolePrefix(grantedAuthorityDefaults.getRolePrefix());
}
sources.add(jsr250MethodSecurityMetadataSource);
}
@@ -396,7 +385,6 @@ public class GlobalMethodSecurityConfiguration
/**
* Creates the {@link PreInvocationAuthorizationAdvice} to be used. The default is
* {@link ExpressionBasedPreInvocationAdvice}.
*
* @return the {@link PreInvocationAuthorizationAdvice}
*/
@Bean
@@ -419,16 +407,13 @@ public class GlobalMethodSecurityConfiguration
@Autowired(required = false)
public void setObjectPostProcessor(ObjectPostProcessor<Object> objectPostProcessor) {
this.objectPostProcessor = objectPostProcessor;
this.defaultMethodExpressionHandler = objectPostProcessor
.postProcess(defaultMethodExpressionHandler);
this.defaultMethodExpressionHandler = objectPostProcessor.postProcess(defaultMethodExpressionHandler);
}
@Autowired(required = false)
public void setMethodSecurityExpressionHandler(
List<MethodSecurityExpressionHandler> handlers) {
public void setMethodSecurityExpressionHandler(List<MethodSecurityExpressionHandler> handlers) {
if (handlers.size() != 1) {
logger.debug("Not autowiring MethodSecurityExpressionHandler since size != 1. Got "
+ handlers);
logger.debug("Not autowiring MethodSecurityExpressionHandler since size != 1. Got " + handlers);
return;
}
this.expressionHandler = handlers.get(0);
@@ -466,14 +451,13 @@ public class GlobalMethodSecurityConfiguration
private AnnotationAttributes enableMethodSecurity() {
if (enableMethodSecurity == null) {
// if it is null look at this instance (i.e. a subclass was used)
EnableGlobalMethodSecurity methodSecurityAnnotation = AnnotationUtils
.findAnnotation(getClass(), EnableGlobalMethodSecurity.class);
Assert.notNull(methodSecurityAnnotation,
() -> EnableGlobalMethodSecurity.class.getName() + " is required");
Map<String, Object> methodSecurityAttrs = AnnotationUtils
.getAnnotationAttributes(methodSecurityAnnotation);
EnableGlobalMethodSecurity methodSecurityAnnotation = AnnotationUtils.findAnnotation(getClass(),
EnableGlobalMethodSecurity.class);
Assert.notNull(methodSecurityAnnotation, () -> EnableGlobalMethodSecurity.class.getName() + " is required");
Map<String, Object> methodSecurityAttrs = AnnotationUtils.getAnnotationAttributes(methodSecurityAnnotation);
this.enableMethodSecurity = AnnotationAttributes.fromMap(methodSecurityAttrs);
}
return this.enableMethodSecurity;
}
}
@@ -38,26 +38,22 @@ final class GlobalMethodSecuritySelector implements ImportSelector {
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
Class<EnableGlobalMethodSecurity> annoType = EnableGlobalMethodSecurity.class;
Map<String, Object> annotationAttributes = importingClassMetadata
.getAnnotationAttributes(annoType.getName(), false);
AnnotationAttributes attributes = AnnotationAttributes
.fromMap(annotationAttributes);
Assert.notNull(attributes, () -> String.format(
"@%s is not present on importing class '%s' as expected",
Map<String, Object> annotationAttributes = importingClassMetadata.getAnnotationAttributes(annoType.getName(),
false);
AnnotationAttributes attributes = AnnotationAttributes.fromMap(annotationAttributes);
Assert.notNull(attributes, () -> String.format("@%s is not present on importing class '%s' as expected",
annoType.getSimpleName(), importingClassMetadata.getClassName()));
// TODO would be nice if could use BeanClassLoaderAware (does not work)
Class<?> importingClass = ClassUtils
.resolveClassName(importingClassMetadata.getClassName(),
ClassUtils.getDefaultClassLoader());
Class<?> importingClass = ClassUtils.resolveClassName(importingClassMetadata.getClassName(),
ClassUtils.getDefaultClassLoader());
boolean skipMethodSecurityConfiguration = GlobalMethodSecurityConfiguration.class
.isAssignableFrom(importingClass);
AdviceMode mode = attributes.getEnum("mode");
boolean isProxy = AdviceMode.PROXY == mode;
String autoProxyClassName = isProxy ? AutoProxyRegistrar.class
.getName() : GlobalMethodSecurityAspectJAutoProxyRegistrar.class
.getName();
String autoProxyClassName = isProxy ? AutoProxyRegistrar.class.getName()
: GlobalMethodSecurityAspectJAutoProxyRegistrar.class.getName();
boolean jsr250Enabled = attributes.getBoolean("jsr250Enabled");
@@ -78,4 +74,5 @@ final class GlobalMethodSecuritySelector implements ImportSelector {
return classNames.toArray(new String[0]);
}
}
@@ -30,4 +30,5 @@ class Jsr250MetadataSourceConfiguration {
public Jsr250MethodSecurityMetadataSource jsr250MethodSecurityMetadataSource() {
return new Jsr250MethodSecurityMetadataSource();
}
}
@@ -24,24 +24,22 @@ import org.springframework.security.access.intercept.aopalliance.MethodSecurityM
import org.springframework.util.MultiValueMap;
/**
* Creates Spring Security's MethodSecurityMetadataSourceAdvisor only when
* using proxy based method security (i.e. do not do it when using ASPECTJ).
* The conditional logic is controlled through {@link GlobalMethodSecuritySelector}.
* Creates Spring Security's MethodSecurityMetadataSourceAdvisor only when using proxy
* based method security (i.e. do not do it when using ASPECTJ). The conditional logic is
* controlled through {@link GlobalMethodSecuritySelector}.
*
* @author Rob Winch
* @since 4.0.2
* @see GlobalMethodSecuritySelector
*/
class MethodSecurityMetadataSourceAdvisorRegistrar implements
ImportBeanDefinitionRegistrar {
class MethodSecurityMetadataSourceAdvisorRegistrar implements ImportBeanDefinitionRegistrar {
/**
* Register, escalate, and configure the AspectJ auto proxy creator based on the value
* of the @{@link EnableGlobalMethodSecurity#proxyTargetClass()} attribute on the
* importing {@code @Configuration} class.
*/
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
BeanDefinitionBuilder advisor = BeanDefinitionBuilder
.rootBeanDefinition(MethodSecurityMetadataSourceAdvisor.class);
@@ -50,13 +48,14 @@ class MethodSecurityMetadataSourceAdvisorRegistrar implements
advisor.addConstructorArgReference("methodSecurityMetadataSource");
advisor.addConstructorArgValue("methodSecurityMetadataSource");
MultiValueMap<String, Object> attributes = importingClassMetadata.getAllAnnotationAttributes(EnableGlobalMethodSecurity.class.getName());
MultiValueMap<String, Object> attributes = importingClassMetadata
.getAllAnnotationAttributes(EnableGlobalMethodSecurity.class.getName());
Integer order = (Integer) attributes.getFirst("order");
if (order != null) {
advisor.addPropertyValue("order", order);
}
registry.registerBeanDefinition("metaDataSourceAdvisor",
advisor.getBeanDefinition());
registry.registerBeanDefinition("metaDataSourceAdvisor", advisor.getBeanDefinition());
}
}
@@ -40,6 +40,7 @@ import java.util.Arrays;
*/
@Configuration(proxyBeanMethods = false)
class ReactiveMethodSecurityConfiguration implements ImportAware {
private int advisorOrder;
private GrantedAuthorityDefaults grantedAuthorityDefaults;
@@ -48,26 +49,27 @@ class ReactiveMethodSecurityConfiguration implements ImportAware {
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public MethodSecurityMetadataSourceAdvisor methodSecurityInterceptor(AbstractMethodSecurityMetadataSource source) {
MethodSecurityMetadataSourceAdvisor advisor = new MethodSecurityMetadataSourceAdvisor(
"securityMethodInterceptor", source, "methodMetadataSource");
"securityMethodInterceptor", source, "methodMetadataSource");
advisor.setOrder(advisorOrder);
return advisor;
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public DelegatingMethodSecurityMetadataSource methodMetadataSource(MethodSecurityExpressionHandler methodSecurityExpressionHandler) {
public DelegatingMethodSecurityMetadataSource methodMetadataSource(
MethodSecurityExpressionHandler methodSecurityExpressionHandler) {
ExpressionBasedAnnotationAttributeFactory attributeFactory = new ExpressionBasedAnnotationAttributeFactory(
methodSecurityExpressionHandler);
PrePostAnnotationSecurityMetadataSource prePostSource = new PrePostAnnotationSecurityMetadataSource(
attributeFactory);
attributeFactory);
return new DelegatingMethodSecurityMetadataSource(Arrays.asList(prePostSource));
}
@Bean
public PrePostAdviceReactiveMethodInterceptor securityMethodInterceptor(AbstractMethodSecurityMetadataSource source, MethodSecurityExpressionHandler handler) {
public PrePostAdviceReactiveMethodInterceptor securityMethodInterceptor(AbstractMethodSecurityMetadataSource source,
MethodSecurityExpressionHandler handler) {
ExpressionBasedPostInvocationAdvice postAdvice = new ExpressionBasedPostInvocationAdvice(
handler);
ExpressionBasedPostInvocationAdvice postAdvice = new ExpressionBasedPostInvocationAdvice(handler);
ExpressionBasedPreInvocationAdvice preAdvice = new ExpressionBasedPreInvocationAdvice();
preAdvice.setExpressionHandler(handler);
@@ -86,7 +88,8 @@ class ReactiveMethodSecurityConfiguration implements ImportAware {
@Override
public void setImportMetadata(AnnotationMetadata importMetadata) {
this.advisorOrder = (int) importMetadata.getAnnotationAttributes(EnableReactiveMethodSecurity.class.getName()).get("order");
this.advisorOrder = (int) importMetadata.getAnnotationAttributes(EnableReactiveMethodSecurity.class.getName())
.get("order");
}
@Autowired(required = false)
@@ -27,22 +27,23 @@ import java.util.List;
* @author Rob Winch
* @since 5.0
*/
class ReactiveMethodSecuritySelector extends
AdviceModeImportSelector<EnableReactiveMethodSecurity> {
class ReactiveMethodSecuritySelector extends AdviceModeImportSelector<EnableReactiveMethodSecurity> {
@Override
protected String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
case PROXY:
return getProxyImports();
default:
throw new IllegalStateException("AdviceMode " + adviceMode + " is not supported");
case PROXY:
return getProxyImports();
default:
throw new IllegalStateException("AdviceMode " + adviceMode + " is not supported");
}
}
/**
* Return the imports to use if the {@link AdviceMode} is set to {@link AdviceMode#PROXY}.
* <p>Take care of adding the necessary JSR-107 import if it is available.
* Return the imports to use if the {@link AdviceMode} is set to
* {@link AdviceMode#PROXY}.
* <p>
* Take care of adding the necessary JSR-107 import if it is available.
*/
private String[] getProxyImports() {
List<String> result = new ArrayList<>();
@@ -50,4 +51,5 @@ class ReactiveMethodSecuritySelector extends
result.add(ReactiveMethodSecurityConfiguration.class.getName());
return result.toArray(new String[0]);
}
}
@@ -36,4 +36,6 @@ import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import({ RSocketSecurityConfiguration.class, SecuritySocketAcceptorInterceptorConfiguration.class })
public @interface EnableRSocketSecurity { }
public @interface EnableRSocketSecurity {
}
@@ -21,14 +21,15 @@ import org.springframework.security.config.Customizer;
import org.springframework.security.rsocket.api.PayloadInterceptor;
/**
* The standard order for {@link PayloadInterceptor} to be
* sorted. The actual values might change, so users should use the {@link #getOrder()} method to
* calculate the position dynamically rather than copy values.
* The standard order for {@link PayloadInterceptor} to be sorted. The actual values might
* change, so users should use the {@link #getOrder()} method to calculate the position
* dynamically rather than copy values.
*
* @author Rob Winch
* @since 5.2
*/
public enum PayloadInterceptorOrder implements Ordered {
/**
* Where basic authentication is placed.
* @see RSocketSecurity#basicAuthentication(Customizer)
@@ -65,4 +66,5 @@ public enum PayloadInterceptorOrder implements Ordered {
public int getOrder() {
return this.order;
}
}
@@ -99,6 +99,7 @@ import java.util.List;
* }
* }
* </pre>
*
* @author Rob Winch
* @author Jesús Ascama Arias
* @author Luis Felipe Vega
@@ -123,12 +124,12 @@ public class RSocketSecurity {
private ReactiveAuthenticationManager authenticationManager;
/**
* Adds a {@link PayloadInterceptor} to be used. This is typically only used
* when using the DSL does not meet a users needs. In order to ensure the
* {@link PayloadInterceptor} is done in the proper order the {@link PayloadInterceptor} should
* either implement {@link org.springframework.core.Ordered} or be annotated with
* Adds a {@link PayloadInterceptor} to be used. This is typically only used when
* using the DSL does not meet a users needs. In order to ensure the
* {@link PayloadInterceptor} is done in the proper order the
* {@link PayloadInterceptor} should either implement
* {@link org.springframework.core.Ordered} or be annotated with
* {@link org.springframework.core.annotation.Order}.
*
* @param interceptor
* @return the builder for additional customizations
* @see PayloadInterceptorOrder
@@ -144,8 +145,9 @@ public class RSocketSecurity {
}
/**
* Adds support for validating a username and password using
* <a href="https://github.com/rsocket/rsocket/blob/5920ed374d008abb712cb1fd7c9d91778b2f4a68/Extensions/Security/Simple.md">Simple Authentication</a>
* Adds support for validating a username and password using <a href=
* "https://github.com/rsocket/rsocket/blob/5920ed374d008abb712cb1fd7c9d91778b2f4a68/Extensions/Security/Simple.md">Simple
* Authentication</a>
* @param simple a customizer
* @return RSocketSecurity for additional configuration
* @since 5.3
@@ -162,6 +164,7 @@ public class RSocketSecurity {
* @since 5.3
*/
public class SimpleAuthenticationSpec {
private ReactiveAuthenticationManager authenticationManager;
public SimpleAuthenticationSpec authenticationManager(ReactiveAuthenticationManager authenticationManager) {
@@ -184,12 +187,13 @@ public class RSocketSecurity {
return result;
}
private SimpleAuthenticationSpec() {}
private SimpleAuthenticationSpec() {
}
}
/**
* Adds authentication with BasicAuthenticationPayloadExchangeConverter.
*
* @param basic
* @return
* @deprecated Use {@link #simpleAuthentication(Customizer)}
@@ -204,6 +208,7 @@ public class RSocketSecurity {
}
public class BasicAuthenticationSpec {
private ReactiveAuthenticationManager authenticationManager;
public BasicAuthenticationSpec authenticationManager(ReactiveAuthenticationManager authenticationManager) {
@@ -225,7 +230,9 @@ public class RSocketSecurity {
return result;
}
private BasicAuthenticationSpec() {}
private BasicAuthenticationSpec() {
}
}
public RSocketSecurity jwt(Customizer<JwtSpec> jwt) {
@@ -237,6 +244,7 @@ public class RSocketSecurity {
}
public class JwtSpec {
private ReactiveAuthenticationManager authenticationManager;
public JwtSpec authenticationManager(ReactiveAuthenticationManager authenticationManager) {
@@ -269,7 +277,9 @@ public class RSocketSecurity {
return Arrays.asList(standard, legacy);
}
private JwtSpec() {}
private JwtSpec() {
}
}
public RSocketSecurity authorizePayload(Customizer<AuthorizePayloadsSpec> authorize) {
@@ -281,8 +291,7 @@ public class RSocketSecurity {
}
public PayloadSocketAcceptorInterceptor build() {
PayloadSocketAcceptorInterceptor interceptor = new PayloadSocketAcceptorInterceptor(
payloadInterceptors());
PayloadSocketAcceptorInterceptor interceptor = new PayloadSocketAcceptorInterceptor(payloadInterceptors());
RSocketMessageHandler handler = getBean(RSocketMessageHandler.class);
interceptor.setDefaultDataMimeType(handler.getDefaultDataMimeType());
interceptor.setDefaultMetadataMimeType(handler.getDefaultMetadataMimeType());
@@ -318,16 +327,17 @@ public class RSocketSecurity {
public class AuthorizePayloadsSpec {
private PayloadExchangeMatcherReactiveAuthorizationManager.Builder authzBuilder =
PayloadExchangeMatcherReactiveAuthorizationManager.builder();
private PayloadExchangeMatcherReactiveAuthorizationManager.Builder authzBuilder = PayloadExchangeMatcherReactiveAuthorizationManager
.builder();
public Access setup() {
return matcher(PayloadExchangeMatchers.setup());
}
/**
* Matches if {@link org.springframework.security.rsocket.api.PayloadExchangeType#isRequest()} is true, else
* not a match
* Matches if
* {@link org.springframework.security.rsocket.api.PayloadExchangeType#isRequest()}
* is true, else not a match
* @return the Access to set up the authorization rule.
*/
public Access anyRequest() {
@@ -350,10 +360,8 @@ public class RSocketSecurity {
public Access route(String pattern) {
RSocketMessageHandler handler = getBean(RSocketMessageHandler.class);
PayloadExchangeMatcher matcher = new RoutePayloadExchangeMatcher(
handler.getMetadataExtractor(),
handler.getRouteMatcher(),
pattern);
PayloadExchangeMatcher matcher = new RoutePayloadExchangeMatcher(handler.getMetadataExtractor(),
handler.getRouteMatcher(), pattern);
return matcher(matcher);
}
@@ -386,8 +394,7 @@ public class RSocketSecurity {
}
public AuthorizePayloadsSpec permitAll() {
return access((a, ctx) -> Mono
.just(new AuthorizationDecision(true)));
return access((a, ctx) -> Mono.just(new AuthorizationDecision(true)));
}
public AuthorizePayloadsSpec hasAnyAuthority(String... authorities) {
@@ -396,15 +403,17 @@ public class RSocketSecurity {
public AuthorizePayloadsSpec access(
ReactiveAuthorizationManager<PayloadExchangeAuthorizationContext> authorization) {
AuthorizePayloadsSpec.this.authzBuilder.add(new PayloadExchangeMatcherEntry<>(this.matcher, authorization));
AuthorizePayloadsSpec.this.authzBuilder
.add(new PayloadExchangeMatcherEntry<>(this.matcher, authorization));
return AuthorizePayloadsSpec.this;
}
public AuthorizePayloadsSpec denyAll() {
return access((a, ctx) -> Mono
.just(new AuthorizationDecision(false)));
return access((a, ctx) -> Mono.just(new AuthorizationDecision(false)));
}
}
}
private <T> T getBean(Class<T> beanClass) {
@@ -422,15 +431,15 @@ public class RSocketSecurity {
if (this.context == null) {
return null;
}
String[] names = this.context.getBeanNamesForType(type);
String[] names = this.context.getBeanNamesForType(type);
if (names.length == 1) {
return (T) this.context.getBean(names[0]);
}
return null;
}
protected void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
protected void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.context = applicationContext;
}
}
@@ -34,6 +34,7 @@ import org.springframework.security.crypto.password.PasswordEncoder;
class RSocketSecurityConfiguration {
private static final String BEAN_NAME_PREFIX = "org.springframework.security.config.annotation.rsocket.RSocketSecurityConfiguration.";
private static final String RSOCKET_SECURITY_BEAN_NAME = BEAN_NAME_PREFIX + "rsocketSecurity";
private ReactiveAuthenticationManager authenticationManager;
@@ -43,8 +44,7 @@ class RSocketSecurityConfiguration {
private PasswordEncoder passwordEncoder;
@Autowired(required = false)
void setAuthenticationManager(
ReactiveAuthenticationManager authenticationManager) {
void setAuthenticationManager(ReactiveAuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
@@ -61,8 +61,7 @@ class RSocketSecurityConfiguration {
@Bean(name = RSOCKET_SECURITY_BEAN_NAME)
@Scope("prototype")
public RSocketSecurity rsocketSecurity(ApplicationContext context) {
RSocketSecurity security = new RSocketSecurity()
.authenticationManager(authenticationManager());
RSocketSecurity security = new RSocketSecurity().authenticationManager(authenticationManager());
security.setApplicationContext(context);
return security;
}
@@ -72,8 +71,8 @@ class RSocketSecurityConfiguration {
return this.authenticationManager;
}
if (this.reactiveUserDetailsService != null) {
UserDetailsRepositoryReactiveAuthenticationManager manager =
new UserDetailsRepositoryReactiveAuthenticationManager(this.reactiveUserDetailsService);
UserDetailsRepositoryReactiveAuthenticationManager manager = new UserDetailsRepositoryReactiveAuthenticationManager(
this.reactiveUserDetailsService);
if (this.passwordEncoder != null) {
manager.setPasswordEncoder(this.passwordEncoder);
}
@@ -81,4 +80,5 @@ class RSocketSecurityConfiguration {
}
return null;
}
}
@@ -31,29 +31,25 @@ import org.springframework.security.rsocket.util.matcher.PayloadExchangeMatcher.
*/
@Configuration(proxyBeanMethods = false)
class SecuritySocketAcceptorInterceptorConfiguration {
@Bean
SecuritySocketAcceptorInterceptor securitySocketAcceptorInterceptor(
ObjectProvider<PayloadSocketAcceptorInterceptor> rsocketInterceptor, ObjectProvider<RSocketSecurity> rsocketSecurity) {
ObjectProvider<PayloadSocketAcceptorInterceptor> rsocketInterceptor,
ObjectProvider<RSocketSecurity> rsocketSecurity) {
PayloadSocketAcceptorInterceptor delegate = rsocketInterceptor
.getIfAvailable(() -> defaultInterceptor(rsocketSecurity));
return new SecuritySocketAcceptorInterceptor(delegate);
}
private PayloadSocketAcceptorInterceptor defaultInterceptor(
ObjectProvider<RSocketSecurity> rsocketSecurity) {
private PayloadSocketAcceptorInterceptor defaultInterceptor(ObjectProvider<RSocketSecurity> rsocketSecurity) {
RSocketSecurity rsocket = rsocketSecurity.getIfAvailable();
if (rsocket == null) {
throw new NoSuchBeanDefinitionException("No RSocketSecurity defined");
}
rsocket
.basicAuthentication(Customizer.withDefaults())
.simpleAuthentication(Customizer.withDefaults())
.authorizePayload(authz ->
authz
.setup().authenticated()
.anyRequest().authenticated()
.matcher(e -> MatchResult.match()).permitAll()
);
rsocket.basicAuthentication(Customizer.withDefaults()).simpleAuthentication(Customizer.withDefaults())
.authorizePayload(authz -> authz.setup().authenticated().anyRequest().authenticated()
.matcher(e -> MatchResult.match()).permitAll());
return rsocket.build();
}
}
@@ -36,14 +36,13 @@ import java.util.List;
* A base class for registering {@link RequestMatcher}'s. For example, it might allow for
* specifying which {@link RequestMatcher} require a certain level of authorization.
*
*
* @param <C> The object that is returned or Chained after creating the RequestMatcher
*
* @author Rob Winch
* @author Ankur Pathak
* @since 3.2
*/
public abstract class AbstractRequestMatcherRegistry<C> {
private static final String HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME = "mvcHandlerMappingIntrospector";
private static final RequestMatcher ANY_REQUEST = AnyRequestMatcher.INSTANCE;
@@ -58,7 +57,6 @@ public abstract class AbstractRequestMatcherRegistry<C> {
/**
* Gets the {@link ApplicationContext}
*
* @return the {@link ApplicationContext}
*/
protected final ApplicationContext getApplicationContext() {
@@ -67,7 +65,6 @@ public abstract class AbstractRequestMatcherRegistry<C> {
/**
* Maps any request.
*
* @return the object that is chained after creating the {@link RequestMatcher}
*/
public C anyRequest() {
@@ -81,10 +78,7 @@ public abstract class AbstractRequestMatcherRegistry<C> {
* Maps a {@link List} of
* {@link org.springframework.security.web.util.matcher.AntPathRequestMatcher}
* instances.
*
* @param method the {@link HttpMethod} to use for any
* {@link HttpMethod}.
*
* @param method the {@link HttpMethod} to use for any {@link HttpMethod}.
* @return the object that is chained after creating the {@link RequestMatcher}
*/
public C antMatchers(HttpMethod method) {
@@ -95,12 +89,11 @@ public abstract class AbstractRequestMatcherRegistry<C> {
* Maps a {@link List} of
* {@link org.springframework.security.web.util.matcher.AntPathRequestMatcher}
* instances.
*
* @param method the {@link HttpMethod} to use or {@code null} for any
* {@link HttpMethod}.
* @param antPatterns the ant patterns to create. If {@code null} or empty, then matches on nothing.
* @param antPatterns the ant patterns to create. If {@code null} or empty, then
* matches on nothing.
* {@link org.springframework.security.web.util.matcher.AntPathRequestMatcher} from
*
* @return the object that is chained after creating the {@link RequestMatcher}
*/
public C antMatchers(HttpMethod method, String... antPatterns) {
@@ -112,10 +105,8 @@ public abstract class AbstractRequestMatcherRegistry<C> {
* Maps a {@link List} of
* {@link org.springframework.security.web.util.matcher.AntPathRequestMatcher}
* instances that do not care which {@link HttpMethod} is used.
*
* @param antPatterns the ant patterns to create
* {@link org.springframework.security.web.util.matcher.AntPathRequestMatcher} from
*
* @return the object that is chained after creating the {@link RequestMatcher}
*/
public C antMatchers(String... antPatterns) {
@@ -134,7 +125,6 @@ public abstract class AbstractRequestMatcherRegistry<C> {
* If the current request will not be processed by Spring MVC, a reasonable default
* using the pattern as a ant pattern will be used.
* </p>
*
* @param mvcPatterns the patterns to match on. The rules for matching are defined by
* Spring MVC
* @return the object that is chained after creating the {@link RequestMatcher}.
@@ -152,7 +142,6 @@ public abstract class AbstractRequestMatcherRegistry<C> {
* If the current request will not be processed by Spring MVC, a reasonable default
* using the pattern as a ant pattern will be used.
* </p>
*
* @param method the HTTP method to match on
* @param mvcPatterns the patterns to match on. The rules for matching are defined by
* Spring MVC
@@ -162,23 +151,21 @@ public abstract class AbstractRequestMatcherRegistry<C> {
/**
* Creates {@link MvcRequestMatcher} instances for the method and patterns passed in
*
* @param method the HTTP method to use or null if any should be used
* @param mvcPatterns the Spring MVC patterns to match on
* @return a List of {@link MvcRequestMatcher} instances
*/
protected final List<MvcRequestMatcher> createMvcMatchers(HttpMethod method,
String... mvcPatterns) {
protected final List<MvcRequestMatcher> createMvcMatchers(HttpMethod method, String... mvcPatterns) {
Assert.state(!this.anyRequestConfigured, "Can't configure mvcMatchers after anyRequest");
ObjectPostProcessor<Object> opp = this.context.getBean(ObjectPostProcessor.class);
if (!this.context.containsBean(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME)) {
throw new NoSuchBeanDefinitionException("A Bean named " + HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME +" of type " + HandlerMappingIntrospector.class.getName()
+ " is required to use MvcRequestMatcher. Please ensure Spring Security & Spring MVC are configured in a shared ApplicationContext.");
throw new NoSuchBeanDefinitionException("A Bean named " + HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME
+ " of type " + HandlerMappingIntrospector.class.getName()
+ " is required to use MvcRequestMatcher. Please ensure Spring Security & Spring MVC are configured in a shared ApplicationContext.");
}
HandlerMappingIntrospector introspector = this.context.getBean(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME,
HandlerMappingIntrospector.class);
List<MvcRequestMatcher> matchers = new ArrayList<>(
mvcPatterns.length);
HandlerMappingIntrospector.class);
List<MvcRequestMatcher> matchers = new ArrayList<>(mvcPatterns.length);
for (String mvcPattern : mvcPatterns) {
MvcRequestMatcher matcher = new MvcRequestMatcher(introspector, mvcPattern);
opp.postProcess(matcher);
@@ -195,12 +182,10 @@ public abstract class AbstractRequestMatcherRegistry<C> {
* Maps a {@link List} of
* {@link org.springframework.security.web.util.matcher.RegexRequestMatcher}
* instances.
*
* @param method the {@link HttpMethod} to use or {@code null} for any
* {@link HttpMethod}.
* @param regexPatterns the regular expressions to create
* {@link org.springframework.security.web.util.matcher.RegexRequestMatcher} from
*
* @return the object that is chained after creating the {@link RequestMatcher}
*/
public C regexMatchers(HttpMethod method, String... regexPatterns) {
@@ -212,10 +197,8 @@ public abstract class AbstractRequestMatcherRegistry<C> {
* Create a {@link List} of
* {@link org.springframework.security.web.util.matcher.RegexRequestMatcher} instances
* that do not specify an {@link HttpMethod}.
*
* @param regexPatterns the regular expressions to create
* {@link org.springframework.security.web.util.matcher.RegexRequestMatcher} from
*
* @return the object that is chained after creating the {@link RequestMatcher}
*/
public C regexMatchers(String... regexPatterns) {
@@ -226,9 +209,7 @@ public abstract class AbstractRequestMatcherRegistry<C> {
/**
* Associates a list of {@link RequestMatcher} instances with the
* {@link AbstractConfigAttributeRequestMatcherRegistry}
*
* @param requestMatchers the {@link RequestMatcher} instances
*
* @return the object that is chained after creating the {@link RequestMatcher}
*/
public C requestMatchers(RequestMatcher... requestMatchers) {
@@ -239,7 +220,6 @@ public abstract class AbstractRequestMatcherRegistry<C> {
/**
* Subclasses should implement this method for returning the object that is chained to
* the creation of the {@link RequestMatcher} instances.
*
* @param requestMatchers the {@link RequestMatcher} instances that were created
* @return the chained Object for the subclass which allows association of something
* else to the {@link RequestMatcher}
@@ -256,16 +236,13 @@ public abstract class AbstractRequestMatcherRegistry<C> {
/**
* Create a {@link List} of {@link AntPathRequestMatcher} instances.
*
* @param httpMethod the {@link HttpMethod} to use or {@code null} for any
* {@link HttpMethod}.
* @param antPatterns the ant patterns to create {@link AntPathRequestMatcher}
* from
*
* @return a {@link List} of {@link AntPathRequestMatcher} instances
*/
public static List<RequestMatcher> antMatchers(HttpMethod httpMethod,
String... antPatterns) {
public static List<RequestMatcher> antMatchers(HttpMethod httpMethod, String... antPatterns) {
String method = httpMethod == null ? null : httpMethod.toString();
List<RequestMatcher> matchers = new ArrayList<>();
for (String pattern : antPatterns) {
@@ -277,10 +254,8 @@ public abstract class AbstractRequestMatcherRegistry<C> {
/**
* Create a {@link List} of {@link AntPathRequestMatcher} instances that do not
* specify an {@link HttpMethod}.
*
* @param antPatterns the ant patterns to create {@link AntPathRequestMatcher}
* from
*
* @return a {@link List} of {@link AntPathRequestMatcher} instances
*/
public static List<RequestMatcher> antMatchers(String... antPatterns) {
@@ -289,16 +264,13 @@ public abstract class AbstractRequestMatcherRegistry<C> {
/**
* Create a {@link List} of {@link RegexRequestMatcher} instances.
*
* @param httpMethod the {@link HttpMethod} to use or {@code null} for any
* {@link HttpMethod}.
* @param regexPatterns the regular expressions to create
* {@link RegexRequestMatcher} from
*
* @return a {@link List} of {@link RegexRequestMatcher} instances
*/
public static List<RequestMatcher> regexMatchers(HttpMethod httpMethod,
String... regexPatterns) {
public static List<RequestMatcher> regexMatchers(HttpMethod httpMethod, String... regexPatterns) {
String method = httpMethod == null ? null : httpMethod.toString();
List<RequestMatcher> matchers = new ArrayList<>();
for (String pattern : regexPatterns) {
@@ -310,10 +282,8 @@ public abstract class AbstractRequestMatcherRegistry<C> {
/**
* Create a {@link List} of {@link RegexRequestMatcher} instances that do not
* specify an {@link HttpMethod}.
*
* @param regexPatterns the regular expressions to create
* {@link RegexRequestMatcher} from
*
* @return a {@link List} of {@link RegexRequestMatcher} instances
*/
public static List<RequestMatcher> regexMatchers(String... regexPatterns) {
@@ -322,6 +292,7 @@ public abstract class AbstractRequestMatcherRegistry<C> {
private RequestMatchers() {
}
}
}
@@ -44,36 +44,29 @@ import org.springframework.security.web.session.ConcurrentSessionFilter;
import org.springframework.security.web.session.SessionManagementFilter;
/**
*
* @author Rob Winch
*
* @param <H>
*/
public interface HttpSecurityBuilder<H extends HttpSecurityBuilder<H>> extends
SecurityBuilder<DefaultSecurityFilterChain> {
public interface HttpSecurityBuilder<H extends HttpSecurityBuilder<H>>
extends SecurityBuilder<DefaultSecurityFilterChain> {
/**
* Gets the {@link SecurityConfigurer} by its class name or <code>null</code> if not
* found. Note that object hierarchies are not considered.
*
* @param clazz the Class of the {@link SecurityConfigurer} to attempt to get.
*/
<C extends SecurityConfigurer<DefaultSecurityFilterChain, H>> C getConfigurer(
Class<C> clazz);
<C extends SecurityConfigurer<DefaultSecurityFilterChain, H>> C getConfigurer(Class<C> clazz);
/**
* Removes the {@link SecurityConfigurer} by its class name or <code>null</code> if
* not found. Note that object hierarchies are not considered.
*
* @param clazz the Class of the {@link SecurityConfigurer} to attempt to remove.
* @return the {@link SecurityConfigurer} that was removed or null if not found
*/
<C extends SecurityConfigurer<DefaultSecurityFilterChain, H>> C removeConfigurer(
Class<C> clazz);
<C extends SecurityConfigurer<DefaultSecurityFilterChain, H>> C removeConfigurer(Class<C> clazz);
/**
* Sets an object that is shared by multiple {@link SecurityConfigurer}.
*
* @param sharedType the Class to key the shared object by.
* @param object the Object to store
*/
@@ -81,7 +74,6 @@ public interface HttpSecurityBuilder<H extends HttpSecurityBuilder<H>> extends
/**
* Gets a shared Object. Note that object heirarchies are not considered.
*
* @param sharedType the type of the shared Object
* @return the shared Object or null if it is not found
*/
@@ -89,7 +81,6 @@ public interface HttpSecurityBuilder<H extends HttpSecurityBuilder<H>> extends
/**
* Allows adding an additional {@link AuthenticationProvider} to be used
*
* @param authenticationProvider the {@link AuthenticationProvider} to be added
* @return the {@link HttpSecurity} for further customizations
*/
@@ -97,7 +88,6 @@ public interface HttpSecurityBuilder<H extends HttpSecurityBuilder<H>> extends
/**
* Allows adding an additional {@link UserDetailsService} to be used
*
* @param userDetailsService the {@link UserDetailsService} to be added
* @return the {@link HttpSecurity} for further customizations
*/
@@ -108,7 +98,6 @@ public interface HttpSecurityBuilder<H extends HttpSecurityBuilder<H>> extends
* known {@link Filter} instances are either a {@link Filter} listed in
* {@link #addFilter(Filter)} or a {@link Filter} that has already been added using
* {@link #addFilterAfter(Filter, Class)} or {@link #addFilterBefore(Filter, Class)}.
*
* @param filter the {@link Filter} to register after the type {@code afterFilter}
* @param afterFilter the Class of the known {@link Filter}.
* @return the {@link HttpSecurity} for further customizations
@@ -120,7 +109,6 @@ public interface HttpSecurityBuilder<H extends HttpSecurityBuilder<H>> extends
* known {@link Filter} instances are either a {@link Filter} listed in
* {@link #addFilter(Filter)} or a {@link Filter} that has already been added using
* {@link #addFilterAfter(Filter, Class)} or {@link #addFilterBefore(Filter, Class)}.
*
* @param filter the {@link Filter} to register before the type {@code beforeFilter}
* @param beforeFilter the Class of the known {@link Filter}.
* @return the {@link HttpSecurity} for further customizations
@@ -140,7 +128,8 @@ public interface HttpSecurityBuilder<H extends HttpSecurityBuilder<H>> extends
* <li>{@link LogoutFilter}</li>
* <li>{@link X509AuthenticationFilter}</li>
* <li>{@link AbstractPreAuthenticatedProcessingFilter}</li>
* <li><a href="{@docRoot}/org/springframework/security/cas/web/CasAuthenticationFilter.html">CasAuthenticationFilter</a></li>
* <li><a href="
* {@docRoot}/org/springframework/security/cas/web/CasAuthenticationFilter.html">CasAuthenticationFilter</a></li>
* <li>{@link UsernamePasswordAuthenticationFilter}</li>
* <li>{@link OpenIDAuthenticationFilter}</li>
* <li>{@link org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter}</li>
@@ -159,9 +148,9 @@ public interface HttpSecurityBuilder<H extends HttpSecurityBuilder<H>> extends
* <li>{@link FilterSecurityInterceptor}</li>
* <li>{@link SwitchUserFilter}</li>
* </ul>
*
* @param filter the {@link Filter} to add
* @return the {@link HttpSecurity} for further customizations
*/
H addFilter(Filter filter);
}
@@ -28,17 +28,15 @@ import org.springframework.security.web.SecurityFilterChain;
/**
* Allows customization to the {@link WebSecurity}. In most instances users will use
* {@link EnableWebSecurity} and either create a {@link Configuration} that extends
* {@link WebSecurityConfigurerAdapter} or expose a {@link SecurityFilterChain} bean.
* Both will automatically be applied to the {@link WebSecurity} by the
* {@link WebSecurityConfigurerAdapter} or expose a {@link SecurityFilterChain} bean. Both
* will automatically be applied to the {@link WebSecurity} by the
* {@link EnableWebSecurity} annotation.
*
* @see WebSecurityConfigurerAdapter
* @see SecurityFilterChain
*
* @author Rob Winch
* @since 3.2
*/
public interface WebSecurityConfigurer<T extends SecurityBuilder<Filter>> extends
SecurityConfigurer<Filter, T> {
public interface WebSecurityConfigurer<T extends SecurityBuilder<Filter>> extends SecurityConfigurer<Filter, T> {
}
@@ -56,8 +56,11 @@ import org.springframework.web.filter.CorsFilter;
@SuppressWarnings("serial")
final class FilterComparator implements Comparator<Filter>, Serializable {
private static final int INITIAL_ORDER = 100;
private static final int ORDER_STEP = 100;
private final Map<String, Integer> filterToOrder = new HashMap<>();
FilterComparator() {
@@ -70,40 +73,35 @@ final class FilterComparator implements Comparator<Filter>, Serializable {
put(CorsFilter.class, order.next());
put(CsrfFilter.class, order.next());
put(LogoutFilter.class, order.next());
filterToOrder.put(
"org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter",
filterToOrder.put("org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter",
order.next());
filterToOrder.put(
"org.springframework.security.saml2.provider.service.servlet.filter.Saml2WebSsoAuthenticationRequestFilter",
order.next());
put(X509AuthenticationFilter.class, order.next());
put(AbstractPreAuthenticatedProcessingFilter.class, order.next());
filterToOrder.put("org.springframework.security.cas.web.CasAuthenticationFilter",
order.next());
filterToOrder.put(
"org.springframework.security.oauth2.client.web.OAuth2LoginAuthenticationFilter",
filterToOrder.put("org.springframework.security.cas.web.CasAuthenticationFilter", order.next());
filterToOrder.put("org.springframework.security.oauth2.client.web.OAuth2LoginAuthenticationFilter",
order.next());
filterToOrder.put(
"org.springframework.security.saml2.provider.service.servlet.filter.Saml2WebSsoAuthenticationFilter",
order.next());
put(UsernamePasswordAuthenticationFilter.class, order.next());
order.next(); // gh-8105
filterToOrder.put(
"org.springframework.security.openid.OpenIDAuthenticationFilter", order.next());
filterToOrder.put("org.springframework.security.openid.OpenIDAuthenticationFilter", order.next());
put(DefaultLoginPageGeneratingFilter.class, order.next());
put(DefaultLogoutPageGeneratingFilter.class, order.next());
put(ConcurrentSessionFilter.class, order.next());
put(DigestAuthenticationFilter.class, order.next());
filterToOrder.put(
"org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationFilter", order.next());
filterToOrder.put("org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationFilter",
order.next());
put(BasicAuthenticationFilter.class, order.next());
put(RequestCacheAwareFilter.class, order.next());
put(SecurityContextHolderAwareRequestFilter.class, order.next());
put(JaasApiIntegrationFilter.class, order.next());
put(RememberMeAuthenticationFilter.class, order.next());
put(AnonymousAuthenticationFilter.class, order.next());
filterToOrder.put(
"org.springframework.security.oauth2.client.web.OAuth2AuthorizationCodeGrantFilter",
filterToOrder.put("org.springframework.security.oauth2.client.web.OAuth2AuthorizationCodeGrantFilter",
order.next());
put(SessionManagementFilter.class, order.next());
put(ExceptionTranslationFilter.class, order.next());
@@ -119,7 +117,6 @@ final class FilterComparator implements Comparator<Filter>, Serializable {
/**
* Determines if a particular {@link Filter} is registered to be sorted
*
* @param filter
* @return
*/
@@ -134,12 +131,10 @@ final class FilterComparator implements Comparator<Filter>, Serializable {
* @param afterFilter the {@link Filter} that is already registered and that
* {@code filter} should be placed after.
*/
public void registerAfter(Class<? extends Filter> filter,
Class<? extends Filter> afterFilter) {
public void registerAfter(Class<? extends Filter> filter, Class<? extends Filter> afterFilter) {
Integer position = getOrder(afterFilter);
if (position == null) {
throw new IllegalArgumentException(
"Cannot register after unregistered Filter " + afterFilter);
throw new IllegalArgumentException("Cannot register after unregistered Filter " + afterFilter);
}
put(filter, position + 1);
@@ -151,12 +146,10 @@ final class FilterComparator implements Comparator<Filter>, Serializable {
* @param atFilter the {@link Filter} that is already registered and that
* {@code filter} should be placed at.
*/
public void registerAt(Class<? extends Filter> filter,
Class<? extends Filter> atFilter) {
public void registerAt(Class<? extends Filter> filter, Class<? extends Filter> atFilter) {
Integer position = getOrder(atFilter);
if (position == null) {
throw new IllegalArgumentException(
"Cannot register after unregistered Filter " + atFilter);
throw new IllegalArgumentException("Cannot register after unregistered Filter " + atFilter);
}
put(filter, position);
@@ -169,12 +162,10 @@ final class FilterComparator implements Comparator<Filter>, Serializable {
* @param beforeFilter the {@link Filter} that is already registered and that
* {@code filter} should be placed before.
*/
public void registerBefore(Class<? extends Filter> filter,
Class<? extends Filter> beforeFilter) {
public void registerBefore(Class<? extends Filter> filter, Class<? extends Filter> beforeFilter) {
Integer position = getOrder(beforeFilter);
if (position == null) {
throw new IllegalArgumentException(
"Cannot register after unregistered Filter " + beforeFilter);
throw new IllegalArgumentException("Cannot register after unregistered Filter " + beforeFilter);
}
put(filter, position - 1);
@@ -188,7 +179,6 @@ final class FilterComparator implements Comparator<Filter>, Serializable {
/**
* Gets the order of a particular {@link Filter} class taking into consideration
* superclasses.
*
* @param clazz the {@link Filter} class to determine the sort order
* @return the sort order or null if not defined
*/
@@ -206,6 +196,7 @@ final class FilterComparator implements Comparator<Filter>, Serializable {
private static class Step {
private int value;
private final int stepSize;
Step(int initialValue, int stepSize) {
@@ -74,14 +74,13 @@ import org.springframework.web.filter.DelegatingFilterProxy;
*
* @see EnableWebSecurity
* @see WebSecurityConfiguration
*
* @author Rob Winch
* @author Evgeniy Cheban
* @since 3.2
*/
public final class WebSecurity extends
AbstractConfiguredSecurityBuilder<Filter, WebSecurity> implements
SecurityBuilder<Filter>, ApplicationContextAware {
public final class WebSecurity extends AbstractConfiguredSecurityBuilder<Filter, WebSecurity>
implements SecurityBuilder<Filter>, ApplicationContextAware {
private final Log logger = LogFactory.getLog(getClass());
private final List<RequestMatcher> ignoredRequests = new ArrayList<>();
@@ -118,12 +117,11 @@ public final class WebSecurity extends
/**
* <p>
* Allows adding {@link RequestMatcher} instances that Spring Security
* should ignore. Web Security provided by Spring Security (including the
* {@link SecurityContext}) will not be available on {@link HttpServletRequest} that
* match. Typically the requests that are registered should be that of only static
* resources. For requests that are dynamic, consider mapping the request to allow all
* users instead.
* Allows adding {@link RequestMatcher} instances that Spring Security should ignore.
* Web Security provided by Spring Security (including the {@link SecurityContext})
* will not be available on {@link HttpServletRequest} that match. Typically the
* requests that are registered should be that of only static resources. For requests
* that are dynamic, consider mapping the request to allow all users instead.
* </p>
*
* Example Usage:
@@ -154,7 +152,6 @@ public final class WebSecurity extends
* .antMatchers(&quot;/static/**&quot;);
* // now both URLs that start with /resources/ and /static/ will be ignored
* </pre>
*
* @return the {@link IgnoredRequestConfigurer} to use for registering request that
* should be ignored
*/
@@ -165,7 +162,6 @@ public final class WebSecurity extends
/**
* Allows customizing the {@link HttpFirewall}. The default is
* {@link StrictHttpFirewall}.
*
* @param httpFirewall the custom {@link HttpFirewall}
* @return the {@link WebSecurity} for further customizations
*/
@@ -176,10 +172,8 @@ public final class WebSecurity extends
/**
* Controls debugging support for Spring Security.
*
* @param debugEnabled if true, enables debug support with Spring Security. Default is
* false.
*
* @return the {@link WebSecurity} for further customization.
* @see EnableWebSecurity#debug()
*/
@@ -197,7 +191,6 @@ public final class WebSecurity extends
* Typically this method is invoked automatically within the framework from
* {@link WebSecurityConfigurerAdapter#init(WebSecurity)}
* </p>
*
* @param securityFilterChainBuilder the builder to use to create the
* {@link SecurityFilterChain} instances
* @return the {@link WebSecurity} for further customizations
@@ -209,15 +202,13 @@ public final class WebSecurity extends
}
/**
* Set the {@link WebInvocationPrivilegeEvaluator} to be used. If this is not specified,
* then a {@link DefaultWebInvocationPrivilegeEvaluator} will be created when
* {@link #securityInterceptor(FilterSecurityInterceptor)} is non null.
*
* Set the {@link WebInvocationPrivilegeEvaluator} to be used. If this is not
* specified, then a {@link DefaultWebInvocationPrivilegeEvaluator} will be created
* when {@link #securityInterceptor(FilterSecurityInterceptor)} is non null.
* @param privilegeEvaluator the {@link WebInvocationPrivilegeEvaluator} to use
* @return the {@link WebSecurity} for further customizations
*/
public WebSecurity privilegeEvaluator(
WebInvocationPrivilegeEvaluator privilegeEvaluator) {
public WebSecurity privilegeEvaluator(WebInvocationPrivilegeEvaluator privilegeEvaluator) {
this.privilegeEvaluator = privilegeEvaluator;
return this;
}
@@ -225,12 +216,10 @@ public final class WebSecurity extends
/**
* Set the {@link SecurityExpressionHandler} to be used. If this is not specified,
* then a {@link DefaultWebSecurityExpressionHandler} will be used.
*
* @param expressionHandler the {@link SecurityExpressionHandler} to use
* @return the {@link WebSecurity} for further customizations
*/
public WebSecurity expressionHandler(
SecurityExpressionHandler<FilterInvocation> expressionHandler) {
public WebSecurity expressionHandler(SecurityExpressionHandler<FilterInvocation> expressionHandler) {
Assert.notNull(expressionHandler, "expressionHandler cannot be null");
this.expressionHandler = expressionHandler;
return this;
@@ -269,7 +258,6 @@ public final class WebSecurity extends
/**
* Executes the Runnable immediately after the build takes place
*
* @param postBuildAction
* @return the {@link WebSecurity} for further customizations
*/
@@ -280,17 +268,14 @@ public final class WebSecurity extends
@Override
protected Filter performBuild() throws Exception {
Assert.state(
!securityFilterChainBuilders.isEmpty(),
Assert.state(!securityFilterChainBuilders.isEmpty(),
() -> "At least one SecurityBuilder<? extends SecurityFilterChain> needs to be specified. "
+ "Typically this is done by exposing a SecurityFilterChain bean "
+ "or by adding a @Configuration that extends WebSecurityConfigurerAdapter. "
+ "More advanced users can invoke "
+ WebSecurity.class.getSimpleName()
+ "More advanced users can invoke " + WebSecurity.class.getSimpleName()
+ ".addSecurityFilterChainBuilder directly");
int chainSize = ignoredRequests.size() + securityFilterChainBuilders.size();
List<SecurityFilterChain> securityFilterChains = new ArrayList<>(
chainSize);
List<SecurityFilterChain> securityFilterChains = new ArrayList<>(chainSize);
for (RequestMatcher ignoredRequest : ignoredRequests) {
securityFilterChains.add(new DefaultSecurityFilterChain(ignoredRequest));
}
@@ -308,8 +293,7 @@ public final class WebSecurity extends
Filter result = filterChainProxy;
if (debugEnabled) {
logger.warn("\n\n"
+ "********************************************************************\n"
logger.warn("\n\n" + "********************************************************************\n"
+ "********** Security debugging is enabled. *************\n"
+ "********** This may include sensitive information. *************\n"
+ "********** Do not use in a production system! *************\n"
@@ -326,12 +310,11 @@ public final class WebSecurity extends
*
* @author Rob Winch
*/
public final class MvcMatchersIgnoredRequestConfigurer
extends IgnoredRequestConfigurer {
public final class MvcMatchersIgnoredRequestConfigurer extends IgnoredRequestConfigurer {
private final List<MvcRequestMatcher> mvcMatchers;
private MvcMatchersIgnoredRequestConfigurer(ApplicationContext context,
List<MvcRequestMatcher> mvcMatchers) {
private MvcMatchersIgnoredRequestConfigurer(ApplicationContext context, List<MvcRequestMatcher> mvcMatchers) {
super(context);
this.mvcMatchers = mvcMatchers;
}
@@ -342,6 +325,7 @@ public final class WebSecurity extends
}
return this;
}
}
/**
@@ -351,20 +335,17 @@ public final class WebSecurity extends
* @author Rob Winch
* @since 3.2
*/
public class IgnoredRequestConfigurer
extends AbstractRequestMatcherRegistry<IgnoredRequestConfigurer> {
public class IgnoredRequestConfigurer extends AbstractRequestMatcherRegistry<IgnoredRequestConfigurer> {
private IgnoredRequestConfigurer(ApplicationContext context) {
setApplicationContext(context);
}
@Override
public MvcMatchersIgnoredRequestConfigurer mvcMatchers(HttpMethod method,
String... mvcPatterns) {
public MvcMatchersIgnoredRequestConfigurer mvcMatchers(HttpMethod method, String... mvcPatterns) {
List<MvcRequestMatcher> mvcMatchers = createMvcMatchers(method, mvcPatterns);
WebSecurity.this.ignoredRequests.addAll(mvcMatchers);
return new MvcMatchersIgnoredRequestConfigurer(getApplicationContext(),
mvcMatchers);
return new MvcMatchersIgnoredRequestConfigurer(getApplicationContext(), mvcMatchers);
}
@Override
@@ -373,8 +354,7 @@ public final class WebSecurity extends
}
@Override
protected IgnoredRequestConfigurer chainRequestMatchers(
List<RequestMatcher> requestMatchers) {
protected IgnoredRequestConfigurer chainRequestMatchers(List<RequestMatcher> requestMatchers) {
WebSecurity.this.ignoredRequests.addAll(requestMatchers);
return this;
}
@@ -385,29 +365,37 @@ public final class WebSecurity extends
public WebSecurity and() {
return WebSecurity.this;
}
}
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.defaultWebSecurityExpressionHandler
.setApplicationContext(applicationContext);
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.defaultWebSecurityExpressionHandler.setApplicationContext(applicationContext);
try {
this.defaultWebSecurityExpressionHandler.setRoleHierarchy(applicationContext.getBean(RoleHierarchy.class));
} catch (NoSuchBeanDefinitionException e) {}
}
catch (NoSuchBeanDefinitionException e) {
}
try {
this.defaultWebSecurityExpressionHandler.setPermissionEvaluator(applicationContext.getBean(
PermissionEvaluator.class));
} catch(NoSuchBeanDefinitionException e) {}
this.defaultWebSecurityExpressionHandler
.setPermissionEvaluator(applicationContext.getBean(PermissionEvaluator.class));
}
catch (NoSuchBeanDefinitionException e) {
}
this.ignoredRequestRegistry = new IgnoredRequestConfigurer(applicationContext);
try {
this.httpFirewall = applicationContext.getBean(HttpFirewall.class);
} catch(NoSuchBeanDefinitionException e) {}
}
catch (NoSuchBeanDefinitionException e) {
}
try {
this.requestRejectedHandler = applicationContext.getBean(RequestRejectedHandler.class);
} catch(NoSuchBeanDefinitionException e) {}
}
catch (NoSuchBeanDefinitionException e) {
}
}
}
@@ -40,8 +40,7 @@ final class AutowiredWebSecurityConfigurersIgnoreParents {
private final ConfigurableListableBeanFactory beanFactory;
AutowiredWebSecurityConfigurersIgnoreParents(
ConfigurableListableBeanFactory beanFactory) {
AutowiredWebSecurityConfigurersIgnoreParents(ConfigurableListableBeanFactory beanFactory) {
Assert.notNull(beanFactory, "beanFactory cannot be null");
this.beanFactory = beanFactory;
}
@@ -49,11 +48,11 @@ final class AutowiredWebSecurityConfigurersIgnoreParents {
@SuppressWarnings({ "rawtypes", "unchecked" })
public List<SecurityConfigurer<Filter, WebSecurity>> getWebSecurityConfigurers() {
List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers = new ArrayList<>();
Map<String, WebSecurityConfigurer> beansOfType = beanFactory
.getBeansOfType(WebSecurityConfigurer.class);
Map<String, WebSecurityConfigurer> beansOfType = beanFactory.getBeansOfType(WebSecurityConfigurer.class);
for (Entry<String, WebSecurityConfigurer> entry : beansOfType.entrySet()) {
webSecurityConfigurers.add(entry.getValue());
}
return webSecurityConfigurers;
}
}
@@ -72,10 +72,8 @@ import org.springframework.security.config.annotation.web.WebSecurityConfigurer;
@Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
@Target(value = { java.lang.annotation.ElementType.TYPE })
@Documented
@Import({ WebSecurityConfiguration.class,
SpringWebMvcImportSelector.class,
OAuth2ImportSelector.class,
HttpSecurityConfiguration.class})
@Import({ WebSecurityConfiguration.class, SpringWebMvcImportSelector.class, OAuth2ImportSelector.class,
HttpSecurityConfiguration.class })
@EnableGlobalAuthentication
@Configuration
public @interface EnableWebSecurity {
@@ -85,4 +83,5 @@ public @interface EnableWebSecurity {
* @return if true, enables debug support with Spring Security
*/
boolean debug() default false;
}
@@ -42,7 +42,9 @@ import static org.springframework.security.config.Customizer.withDefaults;
*/
@Configuration(proxyBeanMethods = false)
class HttpSecurityConfiguration {
private static final String BEAN_NAME_PREFIX = "org.springframework.security.config.annotation.web.configuration.HttpSecurityConfiguration.";
private static final String HTTPSECURITY_BEAN_NAME = BEAN_NAME_PREFIX + "httpSecurity";
private ObjectPostProcessor<Object> objectPostProcessor;
@@ -64,8 +66,7 @@ class HttpSecurityConfiguration {
}
@Autowired
public void setAuthenticationConfiguration(
AuthenticationConfiguration authenticationConfiguration) {
public void setAuthenticationConfiguration(AuthenticationConfiguration authenticationConfiguration) {
this.authenticationConfiguration = authenticationConfiguration;
}
@@ -77,26 +78,18 @@ class HttpSecurityConfiguration {
@Bean(HTTPSECURITY_BEAN_NAME)
@Scope("prototype")
public HttpSecurity httpSecurity() throws Exception {
WebSecurityConfigurerAdapter.LazyPasswordEncoder passwordEncoder =
new WebSecurityConfigurerAdapter.LazyPasswordEncoder(this.context);
WebSecurityConfigurerAdapter.LazyPasswordEncoder passwordEncoder = new WebSecurityConfigurerAdapter.LazyPasswordEncoder(
this.context);
AuthenticationManagerBuilder authenticationBuilder =
new WebSecurityConfigurerAdapter.DefaultPasswordEncoderAuthenticationManagerBuilder(this.objectPostProcessor, passwordEncoder);
AuthenticationManagerBuilder authenticationBuilder = new WebSecurityConfigurerAdapter.DefaultPasswordEncoderAuthenticationManagerBuilder(
this.objectPostProcessor, passwordEncoder);
authenticationBuilder.parentAuthenticationManager(authenticationManager());
HttpSecurity http = new HttpSecurity(objectPostProcessor, authenticationBuilder, createSharedObjects());
http
.csrf(withDefaults())
.addFilter(new WebAsyncManagerIntegrationFilter())
.exceptionHandling(withDefaults())
.headers(withDefaults())
.sessionManagement(withDefaults())
.securityContext(withDefaults())
.requestCache(withDefaults())
.anonymous(withDefaults())
.servletApi(withDefaults())
.logout(withDefaults())
.apply(new DefaultLoginPageConfigurer<>());
http.csrf(withDefaults()).addFilter(new WebAsyncManagerIntegrationFilter()).exceptionHandling(withDefaults())
.headers(withDefaults()).sessionManagement(withDefaults()).securityContext(withDefaults())
.requestCache(withDefaults()).anonymous(withDefaults()).servletApi(withDefaults())
.logout(withDefaults()).apply(new DefaultLoginPageConfigurer<>());
return http;
}
@@ -104,7 +97,8 @@ class HttpSecurityConfiguration {
private AuthenticationManager authenticationManager() throws Exception {
if (this.authenticationManager != null) {
return this.authenticationManager;
} else {
}
else {
return this.authenticationConfiguration.getAuthenticationManager();
}
}
@@ -114,4 +108,5 @@ class HttpSecurityConfiguration {
sharedObjects.put(ApplicationContext.class, context);
return sharedObjects;
}
}
@@ -53,20 +53,25 @@ final class OAuth2ClientConfiguration {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
boolean webmvcPresent = ClassUtils.isPresent(
"org.springframework.web.servlet.DispatcherServlet", getClass().getClassLoader());
boolean webmvcPresent = ClassUtils.isPresent("org.springframework.web.servlet.DispatcherServlet",
getClass().getClassLoader());
return webmvcPresent ?
new String[] { "org.springframework.security.config.annotation.web.configuration.OAuth2ClientConfiguration.OAuth2ClientWebMvcSecurityConfiguration" } :
new String[] {};
return webmvcPresent ? new String[] {
"org.springframework.security.config.annotation.web.configuration.OAuth2ClientConfiguration.OAuth2ClientWebMvcSecurityConfiguration" }
: new String[] {};
}
}
@Configuration(proxyBeanMethods = false)
static class OAuth2ClientWebMvcSecurityConfiguration implements WebMvcConfigurer {
private ClientRegistrationRepository clientRegistrationRepository;
private OAuth2AuthorizedClientRepository authorizedClientRepository;
private OAuth2AccessTokenResponseClient<OAuth2ClientCredentialsGrantRequest> accessTokenResponseClient;
private OAuth2AuthorizedClientManager authorizedClientManager;
@Override
@@ -92,7 +97,8 @@ final class OAuth2ClientConfiguration {
}
@Autowired(required = false)
void setAccessTokenResponseClient(OAuth2AccessTokenResponseClient<OAuth2ClientCredentialsGrantRequest> accessTokenResponseClient) {
void setAccessTokenResponseClient(
OAuth2AccessTokenResponseClient<OAuth2ClientCredentialsGrantRequest> accessTokenResponseClient) {
this.accessTokenResponseClient = accessTokenResponseClient;
}
@@ -111,25 +117,24 @@ final class OAuth2ClientConfiguration {
OAuth2AuthorizedClientManager authorizedClientManager = null;
if (this.clientRegistrationRepository != null && this.authorizedClientRepository != null) {
if (this.accessTokenResponseClient != null) {
OAuth2AuthorizedClientProvider authorizedClientProvider =
OAuth2AuthorizedClientProviderBuilder.builder()
.authorizationCode()
.refreshToken()
.clientCredentials(configurer ->
configurer.accessTokenResponseClient(this.accessTokenResponseClient))
.password()
.build();
DefaultOAuth2AuthorizedClientManager defaultAuthorizedClientManager =
new DefaultOAuth2AuthorizedClientManager(
this.clientRegistrationRepository, this.authorizedClientRepository);
OAuth2AuthorizedClientProvider authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder
.builder().authorizationCode().refreshToken()
.clientCredentials(
configurer -> configurer.accessTokenResponseClient(this.accessTokenResponseClient))
.password().build();
DefaultOAuth2AuthorizedClientManager defaultAuthorizedClientManager = new DefaultOAuth2AuthorizedClientManager(
this.clientRegistrationRepository, this.authorizedClientRepository);
defaultAuthorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
authorizedClientManager = defaultAuthorizedClientManager;
} else {
}
else {
authorizedClientManager = new DefaultOAuth2AuthorizedClientManager(
this.clientRegistrationRepository, this.authorizedClientRepository);
}
}
return authorizedClientManager;
}
}
}
@@ -26,10 +26,11 @@ import org.springframework.util.ClassUtils;
* Used by {@link EnableWebSecurity} to conditionally import:
*
* <ul>
* <li>{@link OAuth2ClientConfiguration} when the {@code spring-security-oauth2-client} module is present on the classpath</li>
* <li>{@link SecurityReactorContextConfiguration} when either the {@code spring-security-oauth2-client} or
* {@code spring-security-oauth2-resource-server} module as well as the {@code spring-webflux} module
* are present on the classpath</li>
* <li>{@link OAuth2ClientConfiguration} when the {@code spring-security-oauth2-client}
* module is present on the classpath</li>
* <li>{@link SecurityReactorContextConfiguration} when either the
* {@code spring-security-oauth2-client} or {@code spring-security-oauth2-resource-server}
* module as well as the {@code spring-webflux} module are present on the classpath</li>
* </ul>
*
* @author Joe Grandja
@@ -45,7 +46,8 @@ final class OAuth2ImportSelector implements ImportSelector {
Set<String> imports = new LinkedHashSet<>();
boolean oauth2ClientPresent = ClassUtils.isPresent(
"org.springframework.security.oauth2.client.registration.ClientRegistration", getClass().getClassLoader());
"org.springframework.security.oauth2.client.registration.ClientRegistration",
getClass().getClassLoader());
if (oauth2ClientPresent) {
imports.add("org.springframework.security.config.annotation.web.configuration.OAuth2ClientConfiguration");
}
@@ -53,15 +55,18 @@ final class OAuth2ImportSelector implements ImportSelector {
boolean webfluxPresent = ClassUtils.isPresent(
"org.springframework.web.reactive.function.client.ExchangeFilterFunction", getClass().getClassLoader());
if (webfluxPresent && oauth2ClientPresent) {
imports.add("org.springframework.security.config.annotation.web.configuration.SecurityReactorContextConfiguration");
imports.add(
"org.springframework.security.config.annotation.web.configuration.SecurityReactorContextConfiguration");
}
boolean oauth2ResourceServerPresent = ClassUtils.isPresent(
"org.springframework.security.oauth2.server.resource.BearerTokenError", getClass().getClassLoader());
if (webfluxPresent && oauth2ResourceServerPresent) {
imports.add("org.springframework.security.config.annotation.web.configuration.SecurityReactorContextConfiguration");
imports.add(
"org.springframework.security.config.annotation.web.configuration.SecurityReactorContextConfiguration");
}
return imports.toArray(new String[0]);
}
}
@@ -41,13 +41,13 @@ import java.util.function.Function;
import static org.springframework.security.config.annotation.web.configuration.SecurityReactorContextConfiguration.SecurityReactorContextSubscriber.SECURITY_CONTEXT_ATTRIBUTES;
/**
* {@link Configuration} that (potentially) adds a "decorating" {@code Publisher}
* for the last operator created in every {@code Mono} or {@code Flux}.
* {@link Configuration} that (potentially) adds a "decorating" {@code Publisher} for the
* last operator created in every {@code Mono} or {@code Flux}.
*
* <p>
* The {@code Publisher} is solely responsible for adding
* the current {@code HttpServletRequest}, {@code HttpServletResponse} and {@code Authentication}
* to the Reactor {@code Context} so that it's accessible in every flow, if required.
* The {@code Publisher} is solely responsible for adding the current
* {@code HttpServletRequest}, {@code HttpServletResponse} and {@code Authentication} to
* the Reactor {@code Context} so that it's accessible in every flow, if required.
*
* @author Joe Grandja
* @author Roman Matiushchenko
@@ -63,12 +63,13 @@ class SecurityReactorContextConfiguration {
}
static class SecurityReactorContextSubscriberRegistrar implements InitializingBean, DisposableBean {
private static final String SECURITY_REACTOR_CONTEXT_OPERATOR_KEY = "org.springframework.security.SECURITY_REACTOR_CONTEXT_OPERATOR";
@Override
public void afterPropertiesSet() throws Exception {
Function<? super Publisher<Object>, ? extends Publisher<Object>> lifter =
Operators.liftPublisher((pub, sub) -> createSubscriberIfNecessary(sub));
Function<? super Publisher<Object>, ? extends Publisher<Object>> lifter = Operators
.liftPublisher((pub, sub) -> createSubscriberIfNecessary(sub));
Hooks.onLastOperator(SECURITY_REACTOR_CONTEXT_OPERATOR_KEY, pub -> {
if (!contextAttributesAvailable()) {
@@ -93,8 +94,8 @@ class SecurityReactorContextConfiguration {
}
private static boolean contextAttributesAvailable() {
return SecurityContextHolder.getContext().getAuthentication() != null ||
RequestContextHolder.getRequestAttributes() instanceof ServletRequestAttributes;
return SecurityContextHolder.getContext().getAuthentication() != null
|| RequestContextHolder.getRequestAttributes() instanceof ServletRequestAttributes;
}
private static Map<Object, Object> getContextAttributes() {
@@ -104,7 +105,7 @@ class SecurityReactorContextConfiguration {
if (requestAttributes instanceof ServletRequestAttributes) {
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;
servletRequest = servletRequestAttributes.getRequest();
servletResponse = servletRequestAttributes.getResponse(); // possible null
servletResponse = servletRequestAttributes.getResponse(); // possible null
}
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null && servletRequest == null) {
@@ -124,11 +125,15 @@ class SecurityReactorContextConfiguration {
return contextAttributes;
}
}
static class SecurityReactorContextSubscriber<T> implements CoreSubscriber<T> {
static final String SECURITY_CONTEXT_ATTRIBUTES = "org.springframework.security.SECURITY_CONTEXT_ATTRIBUTES";
private final CoreSubscriber<T> delegate;
private final Context context;
SecurityReactorContextSubscriber(CoreSubscriber<T> delegate, Map<Object, Object> attributes) {
@@ -137,7 +142,8 @@ class SecurityReactorContextConfiguration {
Context context;
if (currentContext.hasKey(SECURITY_CONTEXT_ATTRIBUTES)) {
context = currentContext;
} else {
}
else {
context = currentContext.put(SECURITY_CONTEXT_ATTRIBUTES, attributes);
}
this.context = context;
@@ -167,5 +173,7 @@ class SecurityReactorContextConfiguration {
public void onComplete() {
this.delegate.onComplete();
}
}
}
@@ -36,12 +36,12 @@ class SpringWebMvcImportSelector implements ImportSelector {
* springframework .core.type.AnnotationMetadata)
*/
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
boolean webmvcPresent = ClassUtils.isPresent(
"org.springframework.web.servlet.DispatcherServlet",
boolean webmvcPresent = ClassUtils.isPresent("org.springframework.web.servlet.DispatcherServlet",
getClass().getClassLoader());
return webmvcPresent
? new String[] {
"org.springframework.security.config.annotation.web.configuration.WebMvcSecurityConfiguration" }
: new String[] {};
}
}
@@ -35,8 +35,10 @@ import java.util.List;
/**
* Used to add a {@link RequestDataValueProcessor} for Spring MVC and Spring Security CSRF
* integration. This configuration is added whenever {@link EnableWebMvc} is added by
* <a href="{@docRoot}/org/springframework/security/config/annotation/web/configuration/SpringWebMvcImportSelector.html">SpringWebMvcImportSelector</a> and the DispatcherServlet is present on the
* classpath. It also adds the {@link AuthenticationPrincipalArgumentResolver} as a
* <a href="
* {@docRoot}/org/springframework/security/config/annotation/web/configuration/SpringWebMvcImportSelector.html">SpringWebMvcImportSelector</a>
* and the DispatcherServlet is present on the classpath. It also adds the
* {@link AuthenticationPrincipalArgumentResolver} as a
* {@link HandlerMethodArgumentResolver}.
*
* @author Rob Winch
@@ -44,6 +46,7 @@ import java.util.List;
* @since 3.2
*/
class WebMvcSecurityConfiguration implements WebMvcConfigurer, ApplicationContextAware {
private BeanResolver beanResolver;
@Override
@@ -70,4 +73,5 @@ class WebMvcSecurityConfiguration implements WebMvcConfigurer, ApplicationContex
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.beanResolver = new BeanFactoryResolver(applicationContext.getAutowireCapableBeanFactory());
}
}
@@ -49,7 +49,6 @@ import org.springframework.security.web.access.WebInvocationPrivilegeEvaluator;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
/**
* Uses a {@link WebSecurity} to create the {@link FilterChainProxy} that performs the web
* based security for Spring Security. It then exports the necessary beans. Customizations
@@ -60,13 +59,13 @@ import org.springframework.security.web.context.AbstractSecurityWebApplicationIn
*
* @see EnableWebSecurity
* @see WebSecurity
*
* @author Rob Winch
* @author Keesun Baik
* @since 3.2
*/
@Configuration(proxyBeanMethods = false)
public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAware {
private WebSecurity webSecurity;
private Boolean debugEnabled;
@@ -98,13 +97,11 @@ public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAwa
*/
@Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
public Filter springSecurityFilterChain() throws Exception {
boolean hasConfigurers = webSecurityConfigurers != null
&& !webSecurityConfigurers.isEmpty();
boolean hasConfigurers = webSecurityConfigurers != null && !webSecurityConfigurers.isEmpty();
boolean hasFilterChain = !securityFilterChains.isEmpty();
if (hasConfigurers && hasFilterChain) {
throw new IllegalStateException(
"Found WebSecurityConfigurerAdapter as well as SecurityFilterChain." +
"Please select just one.");
"Found WebSecurityConfigurerAdapter as well as SecurityFilterChain." + "Please select just one.");
}
if (!hasConfigurers && !hasFilterChain) {
WebSecurityConfigurerAdapter adapter = objectObjectPostProcessor
@@ -138,7 +135,6 @@ public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAwa
/**
* Sets the {@code <SecurityConfigurer<FilterChainProxy, WebSecurityBuilder>}
* instances used to create the web configuration.
*
* @param objectPostProcessor the {@link ObjectPostProcessor} used to create a
* {@link WebSecurity} instance
* @param webSecurityConfigurers the
@@ -147,12 +143,10 @@ public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAwa
* @throws Exception
*/
@Autowired(required = false)
public void setFilterChainProxySecurityConfigurer(
ObjectPostProcessor<Object> objectPostProcessor,
public void setFilterChainProxySecurityConfigurer(ObjectPostProcessor<Object> objectPostProcessor,
@Value("#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}") List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers)
throws Exception {
webSecurity = objectPostProcessor
.postProcess(new WebSecurity(objectPostProcessor));
webSecurity = objectPostProcessor.postProcess(new WebSecurity(objectPostProcessor));
if (debugEnabled != null) {
webSecurity.debug(debugEnabled);
}
@@ -164,10 +158,8 @@ public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAwa
for (SecurityConfigurer<Filter, WebSecurity> config : webSecurityConfigurers) {
Integer order = AnnotationAwareOrderComparator.lookupOrder(config);
if (previousOrder != null && previousOrder.equals(order)) {
throw new IllegalStateException(
"@Order on WebSecurityConfigurers must be unique. Order of "
+ order + " was already used on " + previousConfig + ", so it cannot be used on "
+ config + " too.");
throw new IllegalStateException("@Order on WebSecurityConfigurers must be unique. Order of " + order
+ " was already used on " + previousConfig + ", so it cannot be used on " + config + " too.");
}
previousOrder = order;
previousConfig = config;
@@ -204,6 +196,7 @@ public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAwa
* @since 3.2
*/
private static class AnnotationAwareOrderComparator extends OrderComparator {
private static final AnnotationAwareOrderComparator INSTANCE = new AnnotationAwareOrderComparator();
@Override
@@ -224,6 +217,7 @@ public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAwa
}
return Ordered.LOWEST_PRECEDENCE;
}
}
/*
@@ -235,8 +229,7 @@ public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAwa
public void setImportMetadata(AnnotationMetadata importMetadata) {
Map<String, Object> enableWebSecurityAttrMap = importMetadata
.getAnnotationAttributes(EnableWebSecurity.class.getName());
AnnotationAttributes enableWebSecurityAttrs = AnnotationAttributes
.fromMap(enableWebSecurityAttrMap);
AnnotationAttributes enableWebSecurityAttrs = AnnotationAttributes.fromMap(enableWebSecurityAttrMap);
debugEnabled = enableWebSecurityAttrs.getBoolean("debug");
if (webSecurity != null) {
webSecurity.debug(debugEnabled);
@@ -253,4 +246,5 @@ public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAwa
public void setBeanClassLoader(ClassLoader classLoader) {
this.beanClassLoader = classLoader;
}
}
@@ -69,31 +69,30 @@ import org.springframework.web.accept.ContentNegotiationStrategy;
import org.springframework.web.accept.HeaderContentNegotiationStrategy;
/**
* Provides a convenient base class for creating a {@link WebSecurityConfigurer}
* instance. The implementation allows customization by overriding methods.
* Provides a convenient base class for creating a {@link WebSecurityConfigurer} instance.
* The implementation allows customization by overriding methods.
*
* <p>
* Will automatically apply the result of looking up
* {@link AbstractHttpConfigurer} from {@link SpringFactoriesLoader} to allow
* developers to extend the defaults.
* To do this, you must create a class that extends AbstractHttpConfigurer and then create a file in the classpath at "META-INF/spring.factories" that looks something like:
* Will automatically apply the result of looking up {@link AbstractHttpConfigurer} from
* {@link SpringFactoriesLoader} to allow developers to extend the defaults. To do this,
* you must create a class that extends AbstractHttpConfigurer and then create a file in
* the classpath at "META-INF/spring.factories" that looks something like:
* </p>
* <pre>
* org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer = sample.MyClassThatExtendsAbstractHttpConfigurer
* </pre>
* If you have multiple classes that should be added you can use "," to separate the values. For example:
* </pre> If you have multiple classes that should be added you can use "," to separate
* the values. For example:
*
* <pre>
* org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer = sample.MyClassThatExtendsAbstractHttpConfigurer, sample.OtherThatExtendsAbstractHttpConfigurer
* </pre>
*
* @see EnableWebSecurity
*
* @author Rob Winch
*/
@Order(100)
public abstract class WebSecurityConfigurerAdapter implements
WebSecurityConfigurer<WebSecurity> {
public abstract class WebSecurityConfigurerAdapter implements WebSecurityConfigurer<WebSecurity> {
private final Log logger = LogFactory.getLog(WebSecurityConfigurerAdapter.class);
private ApplicationContext context;
@@ -102,20 +101,27 @@ public abstract class WebSecurityConfigurerAdapter implements
private ObjectPostProcessor<Object> objectPostProcessor = new ObjectPostProcessor<Object>() {
public <T> T postProcess(T object) {
throw new IllegalStateException(
ObjectPostProcessor.class.getName()
+ " is a required bean. Ensure you have used @EnableWebSecurity and @Configuration");
throw new IllegalStateException(ObjectPostProcessor.class.getName()
+ " is a required bean. Ensure you have used @EnableWebSecurity and @Configuration");
}
};
private AuthenticationConfiguration authenticationConfiguration;
private AuthenticationManagerBuilder authenticationBuilder;
private AuthenticationManagerBuilder localConfigureAuthenticationBldr;
private boolean disableLocalConfigureAuthenticationBldr;
private boolean authenticationManagerInitialized;
private AuthenticationManager authenticationManager;
private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
private HttpSecurity http;
private boolean disableDefaults;
/**
@@ -129,7 +135,6 @@ public abstract class WebSecurityConfigurerAdapter implements
* Creates an instance which allows specifying if the default configuration should be
* enabled. Disabling the default configuration should be considered more advanced
* usage as it requires more understanding of how the framework is implemented.
*
* @param disableDefaults true if the default configuration should be disabled, else
* false
*/
@@ -176,7 +181,6 @@ public abstract class WebSecurityConfigurerAdapter implements
* }
*
* </pre>
*
* @param auth the {@link AuthenticationManagerBuilder} to use
* @throws Exception
*/
@@ -186,7 +190,6 @@ public abstract class WebSecurityConfigurerAdapter implements
/**
* Creates the {@link HttpSecurity} or returns the current instance
*
* @return the {@link HttpSecurity}
* @throws Exception
*/
@@ -203,8 +206,7 @@ public abstract class WebSecurityConfigurerAdapter implements
authenticationBuilder.parentAuthenticationManager(authenticationManager);
Map<Class<?>, Object> sharedObjects = createSharedObjects();
http = new HttpSecurity(objectPostProcessor, authenticationBuilder,
sharedObjects);
http = new HttpSecurity(objectPostProcessor, authenticationBuilder, sharedObjects);
if (!disableDefaults) {
// @formatter:off
http
@@ -221,8 +223,8 @@ public abstract class WebSecurityConfigurerAdapter implements
.logout();
// @formatter:on
ClassLoader classLoader = this.context.getClassLoader();
List<AbstractHttpConfigurer> defaultHttpConfigurers =
SpringFactoriesLoader.loadFactories(AbstractHttpConfigurer.class, classLoader);
List<AbstractHttpConfigurer> defaultHttpConfigurers = SpringFactoriesLoader
.loadFactories(AbstractHttpConfigurer.class, classLoader);
for (AbstractHttpConfigurer configurer : defaultHttpConfigurers) {
http.apply(configurer);
@@ -244,7 +246,6 @@ public abstract class WebSecurityConfigurerAdapter implements
* return super.authenticationManagerBean();
* }
* </pre>
*
* @return the {@link AuthenticationManager}
* @throws Exception
*/
@@ -257,7 +258,6 @@ public abstract class WebSecurityConfigurerAdapter implements
* {@link #configure(AuthenticationManagerBuilder)} method is overridden to use the
* {@link AuthenticationManagerBuilder} that was passed in. Otherwise, autowire the
* {@link AuthenticationManager} by type.
*
* @return the {@link AuthenticationManager} to use
* @throws Exception
*/
@@ -265,8 +265,7 @@ public abstract class WebSecurityConfigurerAdapter implements
if (!authenticationManagerInitialized) {
configure(localConfigureAuthenticationBldr);
if (disableLocalConfigureAuthenticationBldr) {
authenticationManager = authenticationConfiguration
.getAuthenticationManager();
authenticationManager = authenticationConfiguration.getAuthenticationManager();
}
else {
authenticationManager = localConfigureAuthenticationBldr.build();
@@ -297,10 +296,8 @@ public abstract class WebSecurityConfigurerAdapter implements
* @see #userDetailsService()
*/
public UserDetailsService userDetailsServiceBean() throws Exception {
AuthenticationManagerBuilder globalAuthBuilder = context
.getBean(AuthenticationManagerBuilder.class);
return new UserDetailsServiceDelegator(Arrays.asList(
localConfigureAuthenticationBldr, globalAuthBuilder));
AuthenticationManagerBuilder globalAuthBuilder = context.getBean(AuthenticationManagerBuilder.class);
return new UserDetailsServiceDelegator(Arrays.asList(localConfigureAuthenticationBldr, globalAuthBuilder));
}
/**
@@ -308,21 +305,17 @@ public abstract class WebSecurityConfigurerAdapter implements
* {@link #userDetailsServiceBean()} without interacting with the
* {@link ApplicationContext}. Developers should override this method when changing
* the instance of {@link #userDetailsServiceBean()}.
*
* @return the {@link UserDetailsService} to use
*/
protected UserDetailsService userDetailsService() {
AuthenticationManagerBuilder globalAuthBuilder = context
.getBean(AuthenticationManagerBuilder.class);
return new UserDetailsServiceDelegator(Arrays.asList(
localConfigureAuthenticationBldr, globalAuthBuilder));
AuthenticationManagerBuilder globalAuthBuilder = context.getBean(AuthenticationManagerBuilder.class);
return new UserDetailsServiceDelegator(Arrays.asList(localConfigureAuthenticationBldr, globalAuthBuilder));
}
public void init(final WebSecurity web) throws Exception {
final HttpSecurity http = getHttp();
web.addSecurityFilterChainBuilder(http).postBuildAction(() -> {
FilterSecurityInterceptor securityInterceptor = http
.getSharedObject(FilterSecurityInterceptor.class);
FilterSecurityInterceptor securityInterceptor = http.getSharedObject(FilterSecurityInterceptor.class);
web.securityInterceptor(securityInterceptor);
});
}
@@ -350,15 +343,15 @@ public abstract class WebSecurityConfigurerAdapter implements
* http.authorizeRequests().anyRequest().authenticated().and().formLogin().and().httpBasic();
* </pre>
*
* Any endpoint that requires defense against common vulnerabilities can be specified here, including public ones.
* See {@link HttpSecurity#authorizeRequests} and the `permitAll()` authorization rule
* for more details on public endpoints.
*
* Any endpoint that requires defense against common vulnerabilities can be specified
* here, including public ones. See {@link HttpSecurity#authorizeRequests} and the
* `permitAll()` authorization rule for more details on public endpoints.
* @param http the {@link HttpSecurity} to modify
* @throws Exception if an error occurs
*/
protected void configure(HttpSecurity http) throws Exception {
logger.debug("Using default configure(HttpSecurity). If subclassed this will potentially override subclass configure(HttpSecurity).");
logger.debug(
"Using default configure(HttpSecurity). If subclassed this will potentially override subclass configure(HttpSecurity).");
// @formatter:off
http
@@ -385,8 +378,10 @@ public abstract class WebSecurityConfigurerAdapter implements
ObjectPostProcessor<Object> objectPostProcessor = context.getBean(ObjectPostProcessor.class);
LazyPasswordEncoder passwordEncoder = new LazyPasswordEncoder(context);
authenticationBuilder = new DefaultPasswordEncoderAuthenticationManagerBuilder(objectPostProcessor, passwordEncoder);
localConfigureAuthenticationBldr = new DefaultPasswordEncoderAuthenticationManagerBuilder(objectPostProcessor, passwordEncoder) {
authenticationBuilder = new DefaultPasswordEncoderAuthenticationManagerBuilder(objectPostProcessor,
passwordEncoder);
localConfigureAuthenticationBldr = new DefaultPasswordEncoderAuthenticationManagerBuilder(objectPostProcessor,
passwordEncoder) {
@Override
public AuthenticationManagerBuilder eraseCredentials(boolean eraseCredentials) {
authenticationBuilder.eraseCredentials(eraseCredentials);
@@ -394,7 +389,8 @@ public abstract class WebSecurityConfigurerAdapter implements
}
@Override
public AuthenticationManagerBuilder authenticationEventPublisher(AuthenticationEventPublisher eventPublisher) {
public AuthenticationManagerBuilder authenticationEventPublisher(
AuthenticationEventPublisher eventPublisher) {
authenticationBuilder.authenticationEventPublisher(eventPublisher);
return super.authenticationEventPublisher(eventPublisher);
}
@@ -407,8 +403,7 @@ public abstract class WebSecurityConfigurerAdapter implements
}
@Autowired(required = false)
public void setContentNegotationStrategy(
ContentNegotiationStrategy contentNegotiationStrategy) {
public void setContentNegotationStrategy(ContentNegotiationStrategy contentNegotiationStrategy) {
this.contentNegotiationStrategy = contentNegotiationStrategy;
}
@@ -418,8 +413,7 @@ public abstract class WebSecurityConfigurerAdapter implements
}
@Autowired
public void setAuthenticationConfiguration(
AuthenticationConfiguration authenticationConfiguration) {
public void setAuthenticationConfiguration(AuthenticationConfiguration authenticationConfiguration) {
this.authenticationConfiguration = authenticationConfiguration;
}
@@ -432,7 +426,6 @@ public abstract class WebSecurityConfigurerAdapter implements
/**
* Creates the shared objects
*
* @return the shared Objects
*/
private Map<Class<?>, Object> createSharedObjects() {
@@ -453,21 +446,22 @@ public abstract class WebSecurityConfigurerAdapter implements
* @since 3.2
*/
static final class UserDetailsServiceDelegator implements UserDetailsService {
private List<AuthenticationManagerBuilder> delegateBuilders;
private UserDetailsService delegate;
private final Object delegateMonitor = new Object();
UserDetailsServiceDelegator(List<AuthenticationManagerBuilder> delegateBuilders) {
if (delegateBuilders.contains(null)) {
throw new IllegalArgumentException(
"delegateBuilders cannot contain null values. Got "
+ delegateBuilders);
"delegateBuilders cannot contain null values. Got " + delegateBuilders);
}
this.delegateBuilders = delegateBuilders;
}
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException {
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
if (delegate != null) {
return delegate.loadUserByUsername(username);
}
@@ -490,6 +484,7 @@ public abstract class WebSecurityConfigurerAdapter implements
return delegate.loadUserByUsername(username);
}
}
/**
@@ -500,26 +495,26 @@ public abstract class WebSecurityConfigurerAdapter implements
* @since 3.2
*/
static final class AuthenticationManagerDelegator implements AuthenticationManager {
private AuthenticationManagerBuilder delegateBuilder;
private AuthenticationManager delegate;
private final Object delegateMonitor = new Object();
private Set<String> beanNames;
AuthenticationManagerDelegator(AuthenticationManagerBuilder delegateBuilder,
ApplicationContext context) {
AuthenticationManagerDelegator(AuthenticationManagerBuilder delegateBuilder, ApplicationContext context) {
Assert.notNull(delegateBuilder, "delegateBuilder cannot be null");
Field parentAuthMgrField = ReflectionUtils.findField(
AuthenticationManagerBuilder.class, "parentAuthenticationManager");
Field parentAuthMgrField = ReflectionUtils.findField(AuthenticationManagerBuilder.class,
"parentAuthenticationManager");
ReflectionUtils.makeAccessible(parentAuthMgrField);
beanNames = getAuthenticationManagerBeanNames(context);
validateBeanCycle(
ReflectionUtils.getField(parentAuthMgrField, delegateBuilder),
beanNames);
validateBeanCycle(ReflectionUtils.getField(parentAuthMgrField, delegateBuilder), beanNames);
this.delegateBuilder = delegateBuilder;
}
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
if (delegate != null) {
return delegate.authenticate(authentication);
}
@@ -534,11 +529,9 @@ public abstract class WebSecurityConfigurerAdapter implements
return delegate.authenticate(authentication);
}
private static Set<String> getAuthenticationManagerBeanNames(
ApplicationContext applicationContext) {
String[] beanNamesForType = BeanFactoryUtils
.beanNamesForTypeIncludingAncestors(applicationContext,
AuthenticationManager.class);
private static Set<String> getAuthenticationManagerBeanNames(ApplicationContext applicationContext) {
String[] beanNamesForType = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(applicationContext,
AuthenticationManager.class);
return new HashSet<>(Arrays.asList(beanNamesForType));
}
@@ -558,46 +551,46 @@ public abstract class WebSecurityConfigurerAdapter implements
beanNames = Collections.emptySet();
}
}
}
static class DefaultPasswordEncoderAuthenticationManagerBuilder extends AuthenticationManagerBuilder {
private PasswordEncoder defaultPasswordEncoder;
/**
* Creates a new instance
*
* @param objectPostProcessor the {@link ObjectPostProcessor} instance to use.
*/
DefaultPasswordEncoderAuthenticationManagerBuilder(
ObjectPostProcessor<Object> objectPostProcessor, PasswordEncoder defaultPasswordEncoder) {
DefaultPasswordEncoderAuthenticationManagerBuilder(ObjectPostProcessor<Object> objectPostProcessor,
PasswordEncoder defaultPasswordEncoder) {
super(objectPostProcessor);
this.defaultPasswordEncoder = defaultPasswordEncoder;
}
@Override
public InMemoryUserDetailsManagerConfigurer<AuthenticationManagerBuilder> inMemoryAuthentication()
throws Exception {
return super.inMemoryAuthentication()
.passwordEncoder(this.defaultPasswordEncoder);
throws Exception {
return super.inMemoryAuthentication().passwordEncoder(this.defaultPasswordEncoder);
}
@Override
public JdbcUserDetailsManagerConfigurer<AuthenticationManagerBuilder> jdbcAuthentication()
throws Exception {
return super.jdbcAuthentication()
.passwordEncoder(this.defaultPasswordEncoder);
public JdbcUserDetailsManagerConfigurer<AuthenticationManagerBuilder> jdbcAuthentication() throws Exception {
return super.jdbcAuthentication().passwordEncoder(this.defaultPasswordEncoder);
}
@Override
public <T extends UserDetailsService> DaoAuthenticationConfigurer<AuthenticationManagerBuilder, T> userDetailsService(
T userDetailsService) throws Exception {
return super.userDetailsService(userDetailsService)
.passwordEncoder(this.defaultPasswordEncoder);
T userDetailsService) throws Exception {
return super.userDetailsService(userDetailsService).passwordEncoder(this.defaultPasswordEncoder);
}
}
static class LazyPasswordEncoder implements PasswordEncoder {
private ApplicationContext applicationContext;
private PasswordEncoder passwordEncoder;
LazyPasswordEncoder(ApplicationContext applicationContext) {
@@ -610,8 +603,7 @@ public abstract class WebSecurityConfigurerAdapter implements
}
@Override
public boolean matches(CharSequence rawPassword,
String encodedPassword) {
public boolean matches(CharSequence rawPassword, String encodedPassword) {
return getPasswordEncoder().matches(rawPassword, encodedPassword);
}
@@ -635,7 +627,8 @@ public abstract class WebSecurityConfigurerAdapter implements
private <T> T getBeanOrNull(Class<T> type) {
try {
return this.applicationContext.getBean(type);
} catch(NoSuchBeanDefinitionException notFound) {
}
catch (NoSuchBeanDefinitionException notFound) {
return null;
}
}
@@ -644,5 +637,7 @@ public abstract class WebSecurityConfigurerAdapter implements
public String toString() {
return getPasswordEncoder().toString();
}
}
}
@@ -51,11 +51,9 @@ import java.util.Collections;
*
* @see FormLoginConfigurer
* @see OpenIDLoginConfigurer
*
* @param T refers to "this" for returning the current configurer
* @param F refers to the {@link AbstractAuthenticationProcessingFilter} that is being
* built
*
* @author Rob Winch
* @since 3.2
*/
@@ -67,12 +65,15 @@ public abstract class AbstractAuthenticationFilterConfigurer<B extends HttpSecur
private AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource;
private SavedRequestAwareAuthenticationSuccessHandler defaultSuccessHandler = new SavedRequestAwareAuthenticationSuccessHandler();
private AuthenticationSuccessHandler successHandler = this.defaultSuccessHandler;
private LoginUrlAuthenticationEntryPoint authenticationEntryPoint;
private boolean customLoginPage;
private String loginPage;
private String loginProcessingUrl;
private AuthenticationFailureHandler failureHandler;
@@ -95,8 +96,7 @@ public abstract class AbstractAuthenticationFilterConfigurer<B extends HttpSecur
* @param defaultLoginProcessingUrl the default URL to use for
* {@link #loginProcessingUrl(String)}
*/
protected AbstractAuthenticationFilterConfigurer(F authenticationFilter,
String defaultLoginProcessingUrl) {
protected AbstractAuthenticationFilterConfigurer(F authenticationFilter, String defaultLoginProcessingUrl) {
this();
this.authFilter = authenticationFilter;
if (defaultLoginProcessingUrl != null) {
@@ -105,10 +105,9 @@ public abstract class AbstractAuthenticationFilterConfigurer<B extends HttpSecur
}
/**
* Specifies where users will be redirected after authenticating successfully if
* they have not visited a secured page prior to authenticating. This is a shortcut
* for calling {@link #defaultSuccessUrl(String, boolean)}.
*
* Specifies where users will be redirected after authenticating successfully if they
* have not visited a secured page prior to authenticating. This is a shortcut for
* calling {@link #defaultSuccessUrl(String, boolean)}.
* @param defaultSuccessUrl the default success url
* @return the {@link FormLoginConfigurer} for additional customization
*/
@@ -117,11 +116,10 @@ public abstract class AbstractAuthenticationFilterConfigurer<B extends HttpSecur
}
/**
* Specifies where users will be redirected after authenticating successfully if
* they have not visited a secured page prior to authenticating or {@code alwaysUse}
* is true. This is a shortcut for calling
* Specifies where users will be redirected after authenticating successfully if they
* have not visited a secured page prior to authenticating or {@code alwaysUse} is
* true. This is a shortcut for calling
* {@link #successHandler(AuthenticationSuccessHandler)}.
*
* @param defaultSuccessUrl the default success url
* @param alwaysUse true if the {@code defaultSuccesUrl} should be used after
* authentication despite if a protected page had been previously visited
@@ -137,14 +135,12 @@ public abstract class AbstractAuthenticationFilterConfigurer<B extends HttpSecur
/**
* Specifies the URL to validate the credentials.
*
* @param loginProcessingUrl the URL to validate username and password
* @return the {@link FormLoginConfigurer} for additional customization
*/
public T loginProcessingUrl(String loginProcessingUrl) {
this.loginProcessingUrl = loginProcessingUrl;
authFilter
.setRequiresAuthenticationRequestMatcher(createLoginProcessingUrlMatcher(loginProcessingUrl));
authFilter.setRequiresAuthenticationRequestMatcher(createLoginProcessingUrlMatcher(loginProcessingUrl));
return getSelf();
}
@@ -154,13 +150,11 @@ public abstract class AbstractAuthenticationFilterConfigurer<B extends HttpSecur
* loginProcessingUrl
* @return the {@link RequestMatcher} to use based upon the loginProcessingUrl
*/
protected abstract RequestMatcher createLoginProcessingUrlMatcher(
String loginProcessingUrl);
protected abstract RequestMatcher createLoginProcessingUrlMatcher(String loginProcessingUrl);
/**
* Specifies a custom {@link AuthenticationDetailsSource}. The default is
* {@link WebAuthenticationDetailsSource}.
*
* @param authenticationDetailsSource the custom {@link AuthenticationDetailsSource}
* @return the {@link FormLoginConfigurer} for additional customization
*/
@@ -174,7 +168,6 @@ public abstract class AbstractAuthenticationFilterConfigurer<B extends HttpSecur
* Specifies the {@link AuthenticationSuccessHandler} to be used. The default is
* {@link SavedRequestAwareAuthenticationSuccessHandler} with no additional properties
* set.
*
* @param successHandler the {@link AuthenticationSuccessHandler}.
* @return the {@link FormLoginConfigurer} for additional customization
*/
@@ -192,9 +185,9 @@ public abstract class AbstractAuthenticationFilterConfigurer<B extends HttpSecur
}
/**
* Ensures the urls for {@link #failureUrl(String)} as well as for the {@link HttpSecurityBuilder}, the
* {@link #getLoginPage} and {@link #getLoginProcessingUrl} are granted access to any user.
*
* Ensures the urls for {@link #failureUrl(String)} as well as for the
* {@link HttpSecurityBuilder}, the {@link #getLoginPage} and
* {@link #getLoginProcessingUrl} are granted access to any user.
* @param permitAll true to grant access to the URLs false to skip this step
* @return the {@link FormLoginConfigurer} for additional customization
*/
@@ -207,14 +200,12 @@ public abstract class AbstractAuthenticationFilterConfigurer<B extends HttpSecur
* The URL to send users if authentication fails. This is a shortcut for invoking
* {@link #failureHandler(AuthenticationFailureHandler)}. The default is
* "/login?error".
*
* @param authenticationFailureUrl the URL to send users if authentication fails (i.e.
* "/login?error").
* @return the {@link FormLoginConfigurer} for additional customization
*/
public final T failureUrl(String authenticationFailureUrl) {
T result = failureHandler(new SimpleUrlAuthenticationFailureHandler(
authenticationFailureUrl));
T result = failureHandler(new SimpleUrlAuthenticationFailureHandler(authenticationFailureUrl));
this.failureUrl = authenticationFailureUrl;
return result;
}
@@ -223,13 +214,11 @@ public abstract class AbstractAuthenticationFilterConfigurer<B extends HttpSecur
* Specifies the {@link AuthenticationFailureHandler} to use when authentication
* fails. The default is redirecting to "/login?error" using
* {@link SimpleUrlAuthenticationFailureHandler}
*
* @param authenticationFailureHandler the {@link AuthenticationFailureHandler} to use
* when authentication fails.
* @return the {@link FormLoginConfigurer} for additional customization
*/
public final T failureHandler(
AuthenticationFailureHandler authenticationFailureHandler) {
public final T failureHandler(AuthenticationFailureHandler authenticationFailureHandler) {
this.failureUrl = null;
this.failureHandler = authenticationFailureHandler;
return getSelf();
@@ -249,25 +238,23 @@ public abstract class AbstractAuthenticationFilterConfigurer<B extends HttpSecur
@SuppressWarnings("unchecked")
protected final void registerAuthenticationEntryPoint(B http, AuthenticationEntryPoint authenticationEntryPoint) {
ExceptionHandlingConfigurer<B> exceptionHandling = http
.getConfigurer(ExceptionHandlingConfigurer.class);
ExceptionHandlingConfigurer<B> exceptionHandling = http.getConfigurer(ExceptionHandlingConfigurer.class);
if (exceptionHandling == null) {
return;
}
exceptionHandling.defaultAuthenticationEntryPointFor(
postProcess(authenticationEntryPoint), getAuthenticationEntryPointMatcher(http));
exceptionHandling.defaultAuthenticationEntryPointFor(postProcess(authenticationEntryPoint),
getAuthenticationEntryPointMatcher(http));
}
protected final RequestMatcher getAuthenticationEntryPointMatcher(B http) {
ContentNegotiationStrategy contentNegotiationStrategy = http
.getSharedObject(ContentNegotiationStrategy.class);
ContentNegotiationStrategy contentNegotiationStrategy = http.getSharedObject(ContentNegotiationStrategy.class);
if (contentNegotiationStrategy == null) {
contentNegotiationStrategy = new HeaderContentNegotiationStrategy();
}
MediaTypeRequestMatcher mediaMatcher = new MediaTypeRequestMatcher(
contentNegotiationStrategy, MediaType.APPLICATION_XHTML_XML,
new MediaType("image", "*"), MediaType.TEXT_HTML, MediaType.TEXT_PLAIN);
MediaTypeRequestMatcher mediaMatcher = new MediaTypeRequestMatcher(contentNegotiationStrategy,
MediaType.APPLICATION_XHTML_XML, new MediaType("image", "*"), MediaType.TEXT_HTML,
MediaType.TEXT_PLAIN);
mediaMatcher.setIgnoredMediaTypes(Collections.singleton(MediaType.ALL));
RequestMatcher notXRequestedWith = new NegatedRequestMatcher(
@@ -288,8 +275,7 @@ public abstract class AbstractAuthenticationFilterConfigurer<B extends HttpSecur
this.defaultSuccessHandler.setRequestCache(requestCache);
}
authFilter.setAuthenticationManager(http
.getSharedObject(AuthenticationManager.class));
authFilter.setAuthenticationManager(http.getSharedObject(AuthenticationManager.class));
authFilter.setAuthenticationSuccessHandler(successHandler);
authFilter.setAuthenticationFailureHandler(failureHandler);
if (authenticationDetailsSource != null) {
@@ -300,8 +286,7 @@ public abstract class AbstractAuthenticationFilterConfigurer<B extends HttpSecur
if (sessionAuthenticationStrategy != null) {
authFilter.setSessionAuthenticationStrategy(sessionAuthenticationStrategy);
}
RememberMeServices rememberMeServices = http
.getSharedObject(RememberMeServices.class);
RememberMeServices rememberMeServices = http.getSharedObject(RememberMeServices.class);
if (rememberMeServices != null) {
authFilter.setRememberMeServices(rememberMeServices);
}
@@ -330,7 +315,6 @@ public abstract class AbstractAuthenticationFilterConfigurer<B extends HttpSecur
}
/**
*
* @return true if a custom login page has been specified, else false
*/
public final boolean isCustomLoginPage() {
@@ -339,7 +323,6 @@ public abstract class AbstractAuthenticationFilterConfigurer<B extends HttpSecur
/**
* Gets the Authentication Filter
*
* @return the Authentication Filter
*/
protected final F getAuthenticationFilter() {
@@ -348,7 +331,6 @@ public abstract class AbstractAuthenticationFilterConfigurer<B extends HttpSecur
/**
* Sets the Authentication Filter
*
* @param authFilter the Authentication Filter
*/
protected final void setAuthenticationFilter(F authFilter) {
@@ -357,7 +339,6 @@ public abstract class AbstractAuthenticationFilterConfigurer<B extends HttpSecur
/**
* Gets the login page
*
* @return the login page
*/
protected final String getLoginPage() {
@@ -366,7 +347,6 @@ public abstract class AbstractAuthenticationFilterConfigurer<B extends HttpSecur
/**
* Gets the Authentication Entry Point
*
* @return the Authentication Entry Point
*/
protected final AuthenticationEntryPoint getAuthenticationEntryPoint() {
@@ -376,7 +356,6 @@ public abstract class AbstractAuthenticationFilterConfigurer<B extends HttpSecur
/**
* Gets the URL to submit an authentication request to (i.e. where username/password
* must be submitted)
*
* @return the URL to submit an authentication request to
*/
protected final String getLoginProcessingUrl() {
@@ -385,7 +364,6 @@ public abstract class AbstractAuthenticationFilterConfigurer<B extends HttpSecur
/**
* Gets the URL to send users to if authentication fails
*
* @return the URL to send users if authentication fails (e.g. "/login?error").
*/
protected final String getFailureUrl() {
@@ -394,7 +372,6 @@ public abstract class AbstractAuthenticationFilterConfigurer<B extends HttpSecur
/**
* Updates the default values for authentication.
*
* @throws Exception
*/
protected final void updateAuthenticationDefaults() {
@@ -405,8 +382,7 @@ public abstract class AbstractAuthenticationFilterConfigurer<B extends HttpSecur
failureUrl(loginPage + "?error");
}
final LogoutConfigurer<B> logoutConfigurer = getBuilder().getConfigurer(
LogoutConfigurer.class);
final LogoutConfigurer<B> logoutConfigurer = getBuilder().getConfigurer(LogoutConfigurer.class);
if (logoutConfigurer != null && !logoutConfigurer.isCustomLogoutSuccess()) {
logoutConfigurer.logoutSuccessUrl(loginPage + "?logout");
}
@@ -434,4 +410,5 @@ public abstract class AbstractAuthenticationFilterConfigurer<B extends HttpSecur
private T getSelf() {
return (T) this;
}
}
@@ -30,22 +30,20 @@ import org.springframework.security.web.util.matcher.RequestMatcher;
*
* @author Rob Winch
* @since 3.2
*
* @param <C> The object that is returned or Chained after creating the RequestMatcher
*
* @see ChannelSecurityConfigurer
* @see UrlAuthorizationConfigurer
* @see ExpressionUrlAuthorizationConfigurer
*/
public abstract class AbstractConfigAttributeRequestMatcherRegistry<C> extends
AbstractRequestMatcherRegistry<C> {
public abstract class AbstractConfigAttributeRequestMatcherRegistry<C> extends AbstractRequestMatcherRegistry<C> {
private List<UrlMapping> urlMappings = new ArrayList<>();
private List<RequestMatcher> unmappedMatchers;
/**
* Gets the {@link UrlMapping} added by subclasses in
* {@link #chainRequestMatchers(java.util.List)}. May be empty.
*
* @return the {@link UrlMapping} added by subclasses in
* {@link #chainRequestMatchers(java.util.List)}
*/
@@ -57,7 +55,6 @@ public abstract class AbstractConfigAttributeRequestMatcherRegistry<C> extends
* Adds a {@link UrlMapping} added by subclasses in
* {@link #chainRequestMatchers(java.util.List)} and resets the unmapped
* {@link RequestMatcher}'s.
*
* @param urlMapping {@link UrlMapping} the mapping to add
*/
final void addMapping(UrlMapping urlMapping) {
@@ -68,7 +65,6 @@ public abstract class AbstractConfigAttributeRequestMatcherRegistry<C> extends
/**
* Marks the {@link RequestMatcher}'s as unmapped and then calls
* {@link #chainRequestMatchersInternal(List)}.
*
* @param requestMatchers the {@link RequestMatcher} instances that were created
* @return the chained Object for the subclass which allows association of something
* else to the {@link RequestMatcher}
@@ -81,7 +77,6 @@ public abstract class AbstractConfigAttributeRequestMatcherRegistry<C> extends
/**
* Subclasses should implement this method for returning the object that is chained to
* the creation of the {@link RequestMatcher} instances.
*
* @param requestMatchers the {@link RequestMatcher} instances that were created
* @return the chained Object for the subclass which allows association of something
* else to the {@link RequestMatcher}
@@ -91,7 +86,6 @@ public abstract class AbstractConfigAttributeRequestMatcherRegistry<C> extends
/**
* Adds a {@link UrlMapping} added by subclasses in
* {@link #chainRequestMatchers(java.util.List)} at a particular index.
*
* @param index the index to add a {@link UrlMapping}
* @param urlMapping {@link UrlMapping} the mapping to add
*/
@@ -102,16 +96,13 @@ public abstract class AbstractConfigAttributeRequestMatcherRegistry<C> extends
/**
* Creates the mapping of {@link RequestMatcher} to {@link Collection} of
* {@link ConfigAttribute} instances
*
* @return the mapping of {@link RequestMatcher} to {@link Collection} of
* {@link ConfigAttribute} instances. Cannot be null.
*/
final LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> createRequestMap() {
if (unmappedMatchers != null) {
throw new IllegalStateException(
"An incomplete mapping was found for "
+ unmappedMatchers
+ ". Try completing it with something like requestUrls().<something>.hasRole('USER')");
throw new IllegalStateException("An incomplete mapping was found for " + unmappedMatchers
+ ". Try completing it with something like requestUrls().<something>.hasRole('USER')");
}
LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> requestMap = new LinkedHashMap<>();
@@ -128,7 +119,9 @@ public abstract class AbstractConfigAttributeRequestMatcherRegistry<C> extends
* {@link ConfigAttribute} instances
*/
static final class UrlMapping {
private RequestMatcher requestMatcher;
private Collection<ConfigAttribute> configAttrs;
UrlMapping(RequestMatcher requestMatcher, Collection<ConfigAttribute> configAttrs) {
@@ -143,5 +136,7 @@ public abstract class AbstractConfigAttributeRequestMatcherRegistry<C> extends
public Collection<ConfigAttribute> getConfigAttrs() {
return configAttrs;
}
}
}
@@ -35,7 +35,6 @@ public abstract class AbstractHttpConfigurer<T extends AbstractHttpConfigurer<T,
/**
* Disables the {@link AbstractHttpConfigurer} by removing it. After doing so a fresh
* version of the configuration can be applied.
*
* @return the {@link HttpSecurityBuilder} for additional customizations
*/
@SuppressWarnings("unchecked")
@@ -49,4 +48,5 @@ public abstract class AbstractHttpConfigurer<T extends AbstractHttpConfigurer<T,
addObjectPostProcessor(objectPostProcessor);
return (T) this;
}
}
@@ -50,15 +50,11 @@ import org.springframework.security.web.access.intercept.FilterSecurityIntercept
* The following shared objects are used:
*
* <ul>
* <li>
* {@link AuthenticationManager}
* </li>
* <li>{@link AuthenticationManager}</li>
* </ul>
*
*
* @param <C> the AbstractInterceptUrlConfigurer
* @param <H> the type of {@link HttpSecurityBuilder} that is being configured
*
* @author Rob Winch
* @since 3.2
* @see ExpressionUrlAuthorizationConfigurer
@@ -66,6 +62,7 @@ import org.springframework.security.web.access.intercept.FilterSecurityIntercept
*/
abstract class AbstractInterceptUrlConfigurer<C extends AbstractInterceptUrlConfigurer<C, H>, H extends HttpSecurityBuilder<H>>
extends AbstractHttpConfigurer<C, H> {
private Boolean filterSecurityInterceptorOncePerRequest;
private AccessDecisionManager accessDecisionManager;
@@ -76,11 +73,10 @@ abstract class AbstractInterceptUrlConfigurer<C extends AbstractInterceptUrlConf
if (metadataSource == null) {
return;
}
FilterSecurityInterceptor securityInterceptor = createFilterSecurityInterceptor(
http, metadataSource, http.getSharedObject(AuthenticationManager.class));
FilterSecurityInterceptor securityInterceptor = createFilterSecurityInterceptor(http, metadataSource,
http.getSharedObject(AuthenticationManager.class));
if (filterSecurityInterceptorOncePerRequest != null) {
securityInterceptor
.setObserveOncePerRequest(filterSecurityInterceptorOncePerRequest);
securityInterceptor.setObserveOncePerRequest(filterSecurityInterceptorOncePerRequest);
}
securityInterceptor = postProcess(securityInterceptor);
http.addFilter(securityInterceptor);
@@ -91,9 +87,7 @@ abstract class AbstractInterceptUrlConfigurer<C extends AbstractInterceptUrlConf
* Subclasses should implement this method to provide a
* {@link FilterInvocationSecurityMetadataSource} for the
* {@link FilterSecurityInterceptor}.
*
* @param http the builder to use
*
* @return the {@link FilterInvocationSecurityMetadataSource} to set on the
* {@link FilterSecurityInterceptor}. Cannot be null.
*/
@@ -102,9 +96,7 @@ abstract class AbstractInterceptUrlConfigurer<C extends AbstractInterceptUrlConf
/**
* Subclasses should implement this method to provide the {@link AccessDecisionVoter}
* instances used to create the default {@link AccessDecisionManager}
*
* @param http the builder to use
*
* @return the {@link AccessDecisionVoter} instances used to create the default
* {@link AccessDecisionManager}
*/
@@ -116,7 +108,6 @@ abstract class AbstractInterceptUrlConfigurer<C extends AbstractInterceptUrlConf
/**
* Allows setting the {@link AccessDecisionManager}. If none is provided, a
* default {@link AccessDecisionManager} is created.
*
* @param accessDecisionManager the {@link AccessDecisionManager} to use
* @return the {@link AbstractInterceptUrlConfigurer} for further customization
*/
@@ -129,26 +120,24 @@ abstract class AbstractInterceptUrlConfigurer<C extends AbstractInterceptUrlConf
* Allows setting if the {@link FilterSecurityInterceptor} should be only applied
* once per request (i.e. if the filter intercepts on a forward, should it be
* applied again).
*
* @param filterSecurityInterceptorOncePerRequest if the
* {@link FilterSecurityInterceptor} should be only applied once per request
* @return the {@link AbstractInterceptUrlConfigurer} for further customization
*/
public R filterSecurityInterceptorOncePerRequest(
boolean filterSecurityInterceptorOncePerRequest) {
public R filterSecurityInterceptorOncePerRequest(boolean filterSecurityInterceptorOncePerRequest) {
AbstractInterceptUrlConfigurer.this.filterSecurityInterceptorOncePerRequest = filterSecurityInterceptorOncePerRequest;
return getSelf();
}
/**
* Returns a reference to the current object with a single suppression of the type
*
* @return a reference to the current object
*/
@SuppressWarnings("unchecked")
private R getSelf() {
return (R) this;
}
}
/**
@@ -162,11 +151,9 @@ abstract class AbstractInterceptUrlConfigurer<C extends AbstractInterceptUrlConf
/**
* If currently null, creates a default {@link AccessDecisionManager} using
* {@link #createDefaultAccessDecisionManager(HttpSecurityBuilder)}. Otherwise returns the
* {@link AccessDecisionManager}.
*
* {@link #createDefaultAccessDecisionManager(HttpSecurityBuilder)}. Otherwise returns
* the {@link AccessDecisionManager}.
* @param http the builder to use
*
* @return the {@link AccessDecisionManager} to use
*/
private AccessDecisionManager getAccessDecisionManager(H http) {
@@ -178,7 +165,6 @@ abstract class AbstractInterceptUrlConfigurer<C extends AbstractInterceptUrlConf
/**
* Creates the {@link FilterSecurityInterceptor}
*
* @param http the builder to use
* @param metadataSource the {@link FilterInvocationSecurityMetadataSource} to use
* @param authenticationManager the {@link AuthenticationManager} to use
@@ -186,8 +172,8 @@ abstract class AbstractInterceptUrlConfigurer<C extends AbstractInterceptUrlConf
* @throws Exception
*/
private FilterSecurityInterceptor createFilterSecurityInterceptor(H http,
FilterInvocationSecurityMetadataSource metadataSource,
AuthenticationManager authenticationManager) throws Exception {
FilterInvocationSecurityMetadataSource metadataSource, AuthenticationManager authenticationManager)
throws Exception {
FilterSecurityInterceptor securityInterceptor = new FilterSecurityInterceptor();
securityInterceptor.setSecurityMetadataSource(metadataSource);
securityInterceptor.setAccessDecisionManager(getAccessDecisionManager(http));
@@ -195,4 +181,5 @@ abstract class AbstractInterceptUrlConfigurer<C extends AbstractInterceptUrlConf
securityInterceptor.afterPropertiesSet();
return securityInterceptor;
}
}
@@ -39,14 +39,18 @@ import org.springframework.security.web.authentication.AnonymousAuthenticationFi
* @author Rob Winch
* @since 3.2
*/
public final class AnonymousConfigurer<H extends HttpSecurityBuilder<H>> extends
AbstractHttpConfigurer<AnonymousConfigurer<H>, H> {
public final class AnonymousConfigurer<H extends HttpSecurityBuilder<H>>
extends AbstractHttpConfigurer<AnonymousConfigurer<H>, H> {
private String key;
private AuthenticationProvider authenticationProvider;
private AnonymousAuthenticationFilter authenticationFilter;
private Object principal = "anonymousUser";
private List<GrantedAuthority> authorities = AuthorityUtils
.createAuthorityList("ROLE_ANONYMOUS");
private List<GrantedAuthority> authorities = AuthorityUtils.createAuthorityList("ROLE_ANONYMOUS");
/**
* Creates a new instance
@@ -58,7 +62,6 @@ public final class AnonymousConfigurer<H extends HttpSecurityBuilder<H>> extends
/**
* Sets the key to identify tokens created for anonymous authentication. Default is a
* secure randomly generated key.
*
* @param key the key to identify tokens created for anonymous authentication. Default
* is a secure randomly generated key.
* @return the {@link AnonymousConfigurer} for further customization of anonymous
@@ -71,7 +74,6 @@ public final class AnonymousConfigurer<H extends HttpSecurityBuilder<H>> extends
/**
* Sets the principal for {@link Authentication} objects of anonymous users
*
* @param principal used for the {@link Authentication} object of anonymous users
* @return the {@link AnonymousConfigurer} for further customization of anonymous
* authentication
@@ -84,7 +86,6 @@ public final class AnonymousConfigurer<H extends HttpSecurityBuilder<H>> extends
/**
* Sets the {@link org.springframework.security.core.Authentication#getAuthorities()}
* for anonymous users
*
* @param authorities Sets the
* {@link org.springframework.security.core.Authentication#getAuthorities()} for
* anonymous users
@@ -99,7 +100,6 @@ public final class AnonymousConfigurer<H extends HttpSecurityBuilder<H>> extends
/**
* Sets the {@link org.springframework.security.core.Authentication#getAuthorities()}
* for anonymous users
*
* @param authorities Sets the
* {@link org.springframework.security.core.Authentication#getAuthorities()} for
* anonymous users (i.e. "ROLE_ANONYMOUS")
@@ -114,15 +114,12 @@ public final class AnonymousConfigurer<H extends HttpSecurityBuilder<H>> extends
* Sets the {@link AuthenticationProvider} used to validate an anonymous user. If this
* is set, no attributes on the {@link AnonymousConfigurer} will be set on the
* {@link AuthenticationProvider}.
*
* @param authenticationProvider the {@link AuthenticationProvider} used to validate
* an anonymous user. Default is {@link AnonymousAuthenticationProvider}
*
* @return the {@link AnonymousConfigurer} for further customization of anonymous
* authentication
*/
public AnonymousConfigurer<H> authenticationProvider(
AuthenticationProvider authenticationProvider) {
public AnonymousConfigurer<H> authenticationProvider(AuthenticationProvider authenticationProvider) {
this.authenticationProvider = authenticationProvider;
return this;
}
@@ -131,15 +128,12 @@ public final class AnonymousConfigurer<H extends HttpSecurityBuilder<H>> extends
* Sets the {@link AnonymousAuthenticationFilter} used to populate an anonymous user.
* If this is set, no attributes on the {@link AnonymousConfigurer} will be set on the
* {@link AnonymousAuthenticationFilter}.
*
* @param authenticationFilter the {@link AnonymousAuthenticationFilter} used to
* populate an anonymous user.
*
* @return the {@link AnonymousConfigurer} for further customization of anonymous
* authentication
*/
public AnonymousConfigurer<H> authenticationFilter(
AnonymousAuthenticationFilter authenticationFilter) {
public AnonymousConfigurer<H> authenticationFilter(AnonymousAuthenticationFilter authenticationFilter) {
this.authenticationFilter = authenticationFilter;
return this;
}
@@ -150,8 +144,7 @@ public final class AnonymousConfigurer<H extends HttpSecurityBuilder<H>> extends
authenticationProvider = new AnonymousAuthenticationProvider(getKey());
}
if (authenticationFilter == null) {
authenticationFilter = new AnonymousAuthenticationFilter(getKey(), principal,
authorities);
authenticationFilter = new AnonymousAuthenticationFilter(getKey(), principal, authorities);
}
authenticationProvider = postProcess(authenticationProvider);
http.authenticationProvider(authenticationProvider);
@@ -169,4 +162,5 @@ public final class AnonymousConfigurer<H extends HttpSecurityBuilder<H>> extends
}
return key;
}
}
@@ -73,14 +73,16 @@ import org.springframework.security.web.util.matcher.RequestMatcher;
* </ul>
*
* @param <H> the type of {@link HttpSecurityBuilder} that is being configured
*
* @author Rob Winch
* @since 3.2
*/
public final class ChannelSecurityConfigurer<H extends HttpSecurityBuilder<H>> extends
AbstractHttpConfigurer<ChannelSecurityConfigurer<H>, H> {
public final class ChannelSecurityConfigurer<H extends HttpSecurityBuilder<H>>
extends AbstractHttpConfigurer<ChannelSecurityConfigurer<H>, H> {
private ChannelProcessingFilter channelFilter = new ChannelProcessingFilter();
private LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> requestMap = new LinkedHashMap<>();
private List<ChannelProcessor> channelProcessors;
private final ChannelRequestMatcherRegistry REGISTRY;
@@ -133,15 +135,12 @@ public final class ChannelSecurityConfigurer<H extends HttpSecurityBuilder<H>> e
}
insecureChannelProcessor = postProcess(insecureChannelProcessor);
secureChannelProcessor = postProcess(secureChannelProcessor);
return Arrays.<ChannelProcessor> asList(insecureChannelProcessor,
secureChannelProcessor);
return Arrays.<ChannelProcessor>asList(insecureChannelProcessor, secureChannelProcessor);
}
private ChannelRequestMatcherRegistry addAttribute(String attribute,
List<? extends RequestMatcher> matchers) {
private ChannelRequestMatcherRegistry addAttribute(String attribute, List<? extends RequestMatcher> matchers) {
for (RequestMatcher matcher : matchers) {
Collection<ConfigAttribute> attrs = Arrays
.<ConfigAttribute> asList(new SecurityConfig(attribute));
Collection<ConfigAttribute> attrs = Arrays.<ConfigAttribute>asList(new SecurityConfig(attribute));
requestMap.put(matcher, attrs);
}
return REGISTRY;
@@ -155,8 +154,7 @@ public final class ChannelSecurityConfigurer<H extends HttpSecurityBuilder<H>> e
}
@Override
public MvcMatchersRequiresChannelUrl mvcMatchers(HttpMethod method,
String... mvcPatterns) {
public MvcMatchersRequiresChannelUrl mvcMatchers(HttpMethod method, String... mvcPatterns) {
List<MvcRequestMatcher> mvcMatchers = createMvcMatchers(method, mvcPatterns);
return new MvcMatchersRequiresChannelUrl(mvcMatchers);
}
@@ -167,19 +165,16 @@ public final class ChannelSecurityConfigurer<H extends HttpSecurityBuilder<H>> e
}
@Override
protected RequiresChannelUrl chainRequestMatchersInternal(
List<RequestMatcher> requestMatchers) {
protected RequiresChannelUrl chainRequestMatchersInternal(List<RequestMatcher> requestMatchers) {
return new RequiresChannelUrl(requestMatchers);
}
/**
* Adds an {@link ObjectPostProcessor} for this class.
*
* @param objectPostProcessor
* @return the {@link ChannelSecurityConfigurer} for further customizations
*/
public ChannelRequestMatcherRegistry withObjectPostProcessor(
ObjectPostProcessor<?> objectPostProcessor) {
public ChannelRequestMatcherRegistry withObjectPostProcessor(ObjectPostProcessor<?> objectPostProcessor) {
addObjectPostProcessor(objectPostProcessor);
return this;
}
@@ -190,8 +185,7 @@ public final class ChannelSecurityConfigurer<H extends HttpSecurityBuilder<H>> e
* @param channelProcessors
* @return the {@link ChannelSecurityConfigurer} for further customizations
*/
public ChannelRequestMatcherRegistry channelProcessors(
List<ChannelProcessor> channelProcessors) {
public ChannelRequestMatcherRegistry channelProcessors(List<ChannelProcessor> channelProcessors) {
ChannelSecurityConfigurer.this.channelProcessors = channelProcessors;
return this;
}
@@ -199,12 +193,12 @@ public final class ChannelSecurityConfigurer<H extends HttpSecurityBuilder<H>> e
/**
* Return the {@link SecurityBuilder} when done using the
* {@link SecurityConfigurer}. This is useful for method chaining.
*
* @return the type of {@link HttpSecurityBuilder} that is being configured
*/
public H and() {
return ChannelSecurityConfigurer.this.and();
}
}
public final class MvcMatchersRequiresChannelUrl extends RequiresChannelUrl {
@@ -219,9 +213,11 @@ public final class ChannelSecurityConfigurer<H extends HttpSecurityBuilder<H>> e
}
return this;
}
}
public class RequiresChannelUrl {
protected List<? extends RequestMatcher> requestMatchers;
private RequiresChannelUrl(List<? extends RequestMatcher> requestMatchers) {
@@ -239,5 +235,7 @@ public final class ChannelSecurityConfigurer<H extends HttpSecurityBuilder<H>> e
public ChannelRequestMatcherRegistry requires(String attribute) {
return addAttribute(attribute, requestMatchers);
}
}
}
@@ -36,11 +36,12 @@ import org.springframework.web.servlet.handler.HandlerMappingIntrospector;
* @author Rob Winch
* @since 4.1.1
*/
public class CorsConfigurer<H extends HttpSecurityBuilder<H>>
extends AbstractHttpConfigurer<CorsConfigurer<H>, H> {
public class CorsConfigurer<H extends HttpSecurityBuilder<H>> extends AbstractHttpConfigurer<CorsConfigurer<H>, H> {
private static final String HANDLER_MAPPING_INTROSPECTOR = "org.springframework.web.servlet.handler.HandlerMappingIntrospector";
private static final String CORS_CONFIGURATION_SOURCE_BEAN_NAME = "corsConfigurationSource";
private static final String CORS_FILTER_BEAN_NAME = "corsFilter";
private CorsConfigurationSource configurationSource;
@@ -53,8 +54,7 @@ public class CorsConfigurer<H extends HttpSecurityBuilder<H>>
public CorsConfigurer() {
}
public CorsConfigurer<H> configurationSource(
CorsConfigurationSource configurationSource) {
public CorsConfigurer<H> configurationSource(CorsConfigurationSource configurationSource) {
this.configurationSource = configurationSource;
return this;
}
@@ -65,9 +65,8 @@ public class CorsConfigurer<H extends HttpSecurityBuilder<H>>
CorsFilter corsFilter = getCorsFilter(context);
if (corsFilter == null) {
throw new IllegalStateException(
"Please configure either a " + CORS_FILTER_BEAN_NAME + " bean or a "
+ CORS_CONFIGURATION_SOURCE_BEAN_NAME + "bean.");
throw new IllegalStateException("Please configure either a " + CORS_FILTER_BEAN_NAME + " bean or a "
+ CORS_CONFIGURATION_SOURCE_BEAN_NAME + "bean.");
}
http.addFilter(corsFilter);
}
@@ -77,31 +76,29 @@ public class CorsConfigurer<H extends HttpSecurityBuilder<H>>
return new CorsFilter(this.configurationSource);
}
boolean containsCorsFilter = context
.containsBeanDefinition(CORS_FILTER_BEAN_NAME);
boolean containsCorsFilter = context.containsBeanDefinition(CORS_FILTER_BEAN_NAME);
if (containsCorsFilter) {
return context.getBean(CORS_FILTER_BEAN_NAME, CorsFilter.class);
}
boolean containsCorsSource = context
.containsBean(CORS_CONFIGURATION_SOURCE_BEAN_NAME);
boolean containsCorsSource = context.containsBean(CORS_CONFIGURATION_SOURCE_BEAN_NAME);
if (containsCorsSource) {
CorsConfigurationSource configurationSource = context.getBean(
CORS_CONFIGURATION_SOURCE_BEAN_NAME, CorsConfigurationSource.class);
CorsConfigurationSource configurationSource = context.getBean(CORS_CONFIGURATION_SOURCE_BEAN_NAME,
CorsConfigurationSource.class);
return new CorsFilter(configurationSource);
}
boolean mvcPresent = ClassUtils.isPresent(HANDLER_MAPPING_INTROSPECTOR,
context.getClassLoader());
boolean mvcPresent = ClassUtils.isPresent(HANDLER_MAPPING_INTROSPECTOR, context.getClassLoader());
if (mvcPresent) {
return MvcCorsFilter.getMvcCorsFilter(context);
}
return null;
}
static class MvcCorsFilter {
private static final String HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME = "mvcHandlerMappingIntrospector";
/**
* This needs to be isolated into a separate class as Spring MVC is an optional
* dependency and will potentially cause ClassLoading issues
@@ -110,11 +107,16 @@ public class CorsConfigurer<H extends HttpSecurityBuilder<H>>
*/
private static CorsFilter getMvcCorsFilter(ApplicationContext context) {
if (!context.containsBean(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME)) {
throw new NoSuchBeanDefinitionException(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME, "A Bean named " + HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME +" of type " + HandlerMappingIntrospector.class.getName()
throw new NoSuchBeanDefinitionException(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME, "A Bean named "
+ HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME + " of type "
+ HandlerMappingIntrospector.class.getName()
+ " is required to use MvcRequestMatcher. Please ensure Spring Security & Spring MVC are configured in a shared ApplicationContext.");
}
HandlerMappingIntrospector mappingIntrospector = context.getBean(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME, HandlerMappingIntrospector.class);
HandlerMappingIntrospector mappingIntrospector = context.getBean(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME,
HandlerMappingIntrospector.class);
return new CorsFilter(mappingIntrospector);
}
}
}
@@ -78,11 +78,15 @@ import org.springframework.util.Assert;
*/
public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
extends AbstractHttpConfigurer<CsrfConfigurer<H>, H> {
private CsrfTokenRepository csrfTokenRepository = new LazyCsrfTokenRepository(
new HttpSessionCsrfTokenRepository());
private CsrfTokenRepository csrfTokenRepository = new LazyCsrfTokenRepository(new HttpSessionCsrfTokenRepository());
private RequestMatcher requireCsrfProtectionMatcher = CsrfFilter.DEFAULT_CSRF_MATCHER;
private List<RequestMatcher> ignoredCsrfProtectionMatchers = new ArrayList<>();
private SessionAuthenticationStrategy sessionAuthenticationStrategy;
private final ApplicationContext context;
/**
@@ -96,12 +100,10 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
/**
* Specify the {@link CsrfTokenRepository} to use. The default is an
* {@link HttpSessionCsrfTokenRepository} wrapped by {@link LazyCsrfTokenRepository}.
*
* @param csrfTokenRepository the {@link CsrfTokenRepository} to use
* @return the {@link CsrfConfigurer} for further customizations
*/
public CsrfConfigurer<H> csrfTokenRepository(
CsrfTokenRepository csrfTokenRepository) {
public CsrfConfigurer<H> csrfTokenRepository(CsrfTokenRepository csrfTokenRepository) {
Assert.notNull(csrfTokenRepository, "csrfTokenRepository cannot be null");
this.csrfTokenRepository = csrfTokenRepository;
return this;
@@ -111,14 +113,11 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
* Specify the {@link RequestMatcher} to use for determining when CSRF should be
* applied. The default is to ignore GET, HEAD, TRACE, OPTIONS and process all other
* requests.
*
* @param requireCsrfProtectionMatcher the {@link RequestMatcher} to use
* @return the {@link CsrfConfigurer} for further customizations
*/
public CsrfConfigurer<H> requireCsrfProtectionMatcher(
RequestMatcher requireCsrfProtectionMatcher) {
Assert.notNull(requireCsrfProtectionMatcher,
"requireCsrfProtectionMatcher cannot be null");
public CsrfConfigurer<H> requireCsrfProtectionMatcher(RequestMatcher requireCsrfProtectionMatcher) {
Assert.notNull(requireCsrfProtectionMatcher, "requireCsrfProtectionMatcher cannot be null");
this.requireCsrfProtectionMatcher = requireCsrfProtectionMatcher;
return this;
}
@@ -148,8 +147,7 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
* @since 4.0
*/
public CsrfConfigurer<H> ignoringAntMatchers(String... antPatterns) {
return new IgnoreCsrfProtectionRegistry(this.context).antMatchers(antPatterns)
.and();
return new IgnoreCsrfProtectionRegistry(this.context).antMatchers(antPatterns).and();
}
/**
@@ -163,7 +161,8 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
* </p>
* <ul>
* <li>Any GET, HEAD, TRACE, OPTIONS (this is the default)</li>
* <li>We also explicitly state to ignore any request that has a "X-Requested-With: XMLHttpRequest" header</li>
* <li>We also explicitly state to ignore any request that has a "X-Requested-With:
* XMLHttpRequest" header</li>
* </ul>
*
* <pre>
@@ -177,8 +176,7 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
* @since 5.1
*/
public CsrfConfigurer<H> ignoringRequestMatchers(RequestMatcher... requestMatchers) {
return new IgnoreCsrfProtectionRegistry(this.context).requestMatchers(requestMatchers)
.and();
return new IgnoreCsrfProtectionRegistry(this.context).requestMatchers(requestMatchers).and();
}
/**
@@ -189,14 +187,13 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
*
* @author Michael Vitz
* @since 5.2
*
* @param sessionAuthenticationStrategy the {@link SessionAuthenticationStrategy} to use
* @param sessionAuthenticationStrategy the {@link SessionAuthenticationStrategy} to
* use
* @return the {@link CsrfConfigurer} for further customizations
*/
public CsrfConfigurer<H> sessionAuthenticationStrategy(
SessionAuthenticationStrategy sessionAuthenticationStrategy) {
Assert.notNull(sessionAuthenticationStrategy,
"sessionAuthenticationStrategy cannot be null");
Assert.notNull(sessionAuthenticationStrategy, "sessionAuthenticationStrategy cannot be null");
this.sessionAuthenticationStrategy = sessionAuthenticationStrategy;
return this;
}
@@ -215,14 +212,11 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
}
LogoutConfigurer<H> logoutConfigurer = http.getConfigurer(LogoutConfigurer.class);
if (logoutConfigurer != null) {
logoutConfigurer
.addLogoutHandler(new CsrfLogoutHandler(this.csrfTokenRepository));
logoutConfigurer.addLogoutHandler(new CsrfLogoutHandler(this.csrfTokenRepository));
}
SessionManagementConfigurer<H> sessionConfigurer = http
.getConfigurer(SessionManagementConfigurer.class);
SessionManagementConfigurer<H> sessionConfigurer = http.getConfigurer(SessionManagementConfigurer.class);
if (sessionConfigurer != null) {
sessionConfigurer.addSessionAuthenticationStrategy(
getSessionAuthenticationStrategy());
sessionConfigurer.addSessionAuthenticationStrategy(getSessionAuthenticationStrategy());
}
filter = postProcess(filter);
http.addFilter(filter);
@@ -231,7 +225,6 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
/**
* Gets the final {@link RequestMatcher} to use by combining the
* {@link #requireCsrfProtectionMatcher(RequestMatcher)} and any {@link #ignore()}.
*
* @return the {@link RequestMatcher} to use
*/
private RequestMatcher getRequireCsrfProtectionMatcher() {
@@ -239,22 +232,19 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
return this.requireCsrfProtectionMatcher;
}
return new AndRequestMatcher(this.requireCsrfProtectionMatcher,
new NegatedRequestMatcher(
new OrRequestMatcher(this.ignoredCsrfProtectionMatchers)));
new NegatedRequestMatcher(new OrRequestMatcher(this.ignoredCsrfProtectionMatchers)));
}
/**
* Gets the default {@link AccessDeniedHandler} from the
* {@link ExceptionHandlingConfigurer#getAccessDeniedHandler()} or create a
* {@link AccessDeniedHandlerImpl} if not available.
*
* @param http the {@link HttpSecurityBuilder}
* @return the {@link AccessDeniedHandler}
*/
@SuppressWarnings("unchecked")
private AccessDeniedHandler getDefaultAccessDeniedHandler(H http) {
ExceptionHandlingConfigurer<H> exceptionConfig = http
.getConfigurer(ExceptionHandlingConfigurer.class);
ExceptionHandlingConfigurer<H> exceptionConfig = http.getConfigurer(ExceptionHandlingConfigurer.class);
AccessDeniedHandler handler = null;
if (exceptionConfig != null) {
handler = exceptionConfig.getAccessDeniedHandler();
@@ -269,14 +259,12 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
* Gets the default {@link InvalidSessionStrategy} from the
* {@link SessionManagementConfigurer#getInvalidSessionStrategy()} or null if not
* available.
*
* @param http the {@link HttpSecurityBuilder}
* @return the {@link InvalidSessionStrategy}
*/
@SuppressWarnings("unchecked")
private InvalidSessionStrategy getInvalidSessionStrategy(H http) {
SessionManagementConfigurer<H> sessionManagement = http
.getConfigurer(SessionManagementConfigurer.class);
SessionManagementConfigurer<H> sessionManagement = http.getConfigurer(SessionManagementConfigurer.class);
if (sessionManagement == null) {
return null;
}
@@ -292,14 +280,12 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
* {@link InvalidSessionAccessDeniedHandler} and the
* {@link #getDefaultAccessDeniedHandler(HttpSecurityBuilder)}. Otherwise, only
* {@link #getDefaultAccessDeniedHandler(HttpSecurityBuilder)} is used.
*
* @param http the {@link HttpSecurityBuilder}
* @return the {@link AccessDeniedHandler}
*/
private AccessDeniedHandler createAccessDeniedHandler(H http) {
InvalidSessionStrategy invalidSessionStrategy = getInvalidSessionStrategy(http);
AccessDeniedHandler defaultAccessDeniedHandler = getDefaultAccessDeniedHandler(
http);
AccessDeniedHandler defaultAccessDeniedHandler = getDefaultAccessDeniedHandler(http);
if (invalidSessionStrategy == null) {
return defaultAccessDeniedHandler;
}
@@ -312,18 +298,18 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
}
/**
* Gets the {@link SessionAuthenticationStrategy} to use. If none was set by the user a
* {@link CsrfAuthenticationStrategy} is created.
* Gets the {@link SessionAuthenticationStrategy} to use. If none was set by the user
* a {@link CsrfAuthenticationStrategy} is created.
*
* @author Michael Vitz
* @since 5.2
*
* @return the {@link SessionAuthenticationStrategy}
*/
private SessionAuthenticationStrategy getSessionAuthenticationStrategy() {
if (sessionAuthenticationStrategy != null) {
return sessionAuthenticationStrategy;
} else {
}
else {
return new CsrfAuthenticationStrategy(this.csrfTokenRepository);
}
}
@@ -336,8 +322,7 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
* @author Rob Winch
* @since 4.0
*/
private class IgnoreCsrfProtectionRegistry
extends AbstractRequestMatcherRegistry<IgnoreCsrfProtectionRegistry> {
private class IgnoreCsrfProtectionRegistry extends AbstractRequestMatcherRegistry<IgnoreCsrfProtectionRegistry> {
/**
* @param context
@@ -347,12 +332,10 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
}
@Override
public MvcMatchersIgnoreCsrfProtectionRegistry mvcMatchers(HttpMethod method,
String... mvcPatterns) {
public MvcMatchersIgnoreCsrfProtectionRegistry mvcMatchers(HttpMethod method, String... mvcPatterns) {
List<MvcRequestMatcher> mvcMatchers = createMvcMatchers(method, mvcPatterns);
CsrfConfigurer.this.ignoredCsrfProtectionMatchers.addAll(mvcMatchers);
return new MvcMatchersIgnoreCsrfProtectionRegistry(getApplicationContext(),
mvcMatchers);
return new MvcMatchersIgnoreCsrfProtectionRegistry(getApplicationContext(), mvcMatchers);
}
@Override
@@ -365,11 +348,11 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
}
@Override
protected IgnoreCsrfProtectionRegistry chainRequestMatchers(
List<RequestMatcher> requestMatchers) {
protected IgnoreCsrfProtectionRegistry chainRequestMatchers(List<RequestMatcher> requestMatchers) {
CsrfConfigurer.this.ignoredCsrfProtectionMatchers.addAll(requestMatchers);
return this;
}
}
/**
@@ -378,8 +361,8 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
*
* @author Rob Winch
*/
private final class MvcMatchersIgnoreCsrfProtectionRegistry
extends IgnoreCsrfProtectionRegistry {
private final class MvcMatchersIgnoreCsrfProtectionRegistry extends IgnoreCsrfProtectionRegistry {
private final List<MvcRequestMatcher> mvcMatchers;
private MvcMatchersIgnoreCsrfProtectionRegistry(ApplicationContext context,
@@ -394,5 +377,7 @@ public final class CsrfConfigurer<H extends HttpSecurityBuilder<H>>
}
return this;
}
}
}
@@ -49,7 +49,8 @@ import java.util.function.Function;
*
* <h2>Shared Objects Created</h2>
*
* No shared objects are created. isLogoutRequest <h2>Shared Objects Used</h2>
* No shared objects are created. isLogoutRequest
* <h2>Shared Objects Used</h2>
*
* The following shared objects are used:
*
@@ -61,12 +62,11 @@ import java.util.function.Function;
* </ul>
*
* @see WebSecurityConfigurerAdapter
*
* @author Rob Winch
* @since 3.2
*/
public final class DefaultLoginPageConfigurer<H extends HttpSecurityBuilder<H>> extends
AbstractHttpConfigurer<DefaultLoginPageConfigurer<H>, H> {
public final class DefaultLoginPageConfigurer<H extends HttpSecurityBuilder<H>>
extends AbstractHttpConfigurer<DefaultLoginPageConfigurer<H>, H> {
private DefaultLoginPageGeneratingFilter loginPageGeneratingFilter = new DefaultLoginPageGeneratingFilter();
@@ -83,16 +83,14 @@ public final class DefaultLoginPageConfigurer<H extends HttpSecurityBuilder<H>>
};
this.loginPageGeneratingFilter.setResolveHiddenInputs(hiddenInputs);
this.logoutPageGeneratingFilter.setResolveHiddenInputs(hiddenInputs);
http.setSharedObject(DefaultLoginPageGeneratingFilter.class,
loginPageGeneratingFilter);
http.setSharedObject(DefaultLoginPageGeneratingFilter.class, loginPageGeneratingFilter);
}
@Override
@SuppressWarnings("unchecked")
public void configure(H http) {
AuthenticationEntryPoint authenticationEntryPoint = null;
ExceptionHandlingConfigurer<?> exceptionConf = http
.getConfigurer(ExceptionHandlingConfigurer.class);
ExceptionHandlingConfigurer<?> exceptionConf = http.getConfigurer(ExceptionHandlingConfigurer.class);
if (exceptionConf != null) {
authenticationEntryPoint = exceptionConf.getAuthenticationEntryPoint();
}
@@ -62,8 +62,8 @@ import org.springframework.security.web.util.matcher.RequestMatcher;
* @author Rob Winch
* @since 3.2
*/
public final class ExceptionHandlingConfigurer<H extends HttpSecurityBuilder<H>> extends
AbstractHttpConfigurer<ExceptionHandlingConfigurer<H>, H> {
public final class ExceptionHandlingConfigurer<H extends HttpSecurityBuilder<H>>
extends AbstractHttpConfigurer<ExceptionHandlingConfigurer<H>, H> {
private AuthenticationEntryPoint authenticationEntryPoint;
@@ -83,7 +83,6 @@ public final class ExceptionHandlingConfigurer<H extends HttpSecurityBuilder<H>>
/**
* Shortcut to specify the {@link AccessDeniedHandler} to be used is a specific error
* page
*
* @param accessDeniedUrl the URL to the access denied page (i.e. /errors/401)
* @return the {@link ExceptionHandlingConfigurer} for further customization
* @see AccessDeniedHandlerImpl
@@ -97,32 +96,29 @@ public final class ExceptionHandlingConfigurer<H extends HttpSecurityBuilder<H>>
/**
* Specifies the {@link AccessDeniedHandler} to be used
*
* @param accessDeniedHandler the {@link AccessDeniedHandler} to be used
* @return the {@link ExceptionHandlingConfigurer} for further customization
*/
public ExceptionHandlingConfigurer<H> accessDeniedHandler(
AccessDeniedHandler accessDeniedHandler) {
public ExceptionHandlingConfigurer<H> accessDeniedHandler(AccessDeniedHandler accessDeniedHandler) {
this.accessDeniedHandler = accessDeniedHandler;
return this;
}
/**
* Sets a default {@link AccessDeniedHandler} to be used which prefers being
* invoked for the provided {@link RequestMatcher}. If only a single default
* {@link AccessDeniedHandler} is specified, it will be what is used for the
* default {@link AccessDeniedHandler}. If multiple default
* {@link AccessDeniedHandler} instances are configured, then a
* Sets a default {@link AccessDeniedHandler} to be used which prefers being invoked
* for the provided {@link RequestMatcher}. If only a single default
* {@link AccessDeniedHandler} is specified, it will be what is used for the default
* {@link AccessDeniedHandler}. If multiple default {@link AccessDeniedHandler}
* instances are configured, then a
* {@link RequestMatcherDelegatingAccessDeniedHandler} will be used.
*
* @param deniedHandler the {@link AccessDeniedHandler} to use
* @param preferredMatcher the {@link RequestMatcher} for this default
* {@link AccessDeniedHandler}
* @return the {@link ExceptionHandlingConfigurer} for further customizations
* @since 5.1
*/
public ExceptionHandlingConfigurer<H> defaultAccessDeniedHandlerFor(
AccessDeniedHandler deniedHandler, RequestMatcher preferredMatcher) {
public ExceptionHandlingConfigurer<H> defaultAccessDeniedHandlerFor(AccessDeniedHandler deniedHandler,
RequestMatcher preferredMatcher) {
this.defaultDeniedHandlerMappings.put(preferredMatcher, deniedHandler);
return this;
}
@@ -141,12 +137,10 @@ public final class ExceptionHandlingConfigurer<H extends HttpSecurityBuilder<H>>
* <p>
* If that is not provided defaults to {@link Http403ForbiddenEntryPoint}.
* </p>
*
* @param authenticationEntryPoint the {@link AuthenticationEntryPoint} to use
* @return the {@link ExceptionHandlingConfigurer} for further customizations
*/
public ExceptionHandlingConfigurer<H> authenticationEntryPoint(
AuthenticationEntryPoint authenticationEntryPoint) {
public ExceptionHandlingConfigurer<H> authenticationEntryPoint(AuthenticationEntryPoint authenticationEntryPoint) {
this.authenticationEntryPoint = authenticationEntryPoint;
return this;
}
@@ -158,14 +152,13 @@ public final class ExceptionHandlingConfigurer<H extends HttpSecurityBuilder<H>>
* default {@link AuthenticationEntryPoint}. If multiple default
* {@link AuthenticationEntryPoint} instances are configured, then a
* {@link DelegatingAuthenticationEntryPoint} will be used.
*
* @param entryPoint the {@link AuthenticationEntryPoint} to use
* @param preferredMatcher the {@link RequestMatcher} for this default
* {@link AuthenticationEntryPoint}
* @return the {@link ExceptionHandlingConfigurer} for further customizations
*/
public ExceptionHandlingConfigurer<H> defaultAuthenticationEntryPointFor(
AuthenticationEntryPoint entryPoint, RequestMatcher preferredMatcher) {
public ExceptionHandlingConfigurer<H> defaultAuthenticationEntryPointFor(AuthenticationEntryPoint entryPoint,
RequestMatcher preferredMatcher) {
this.defaultEntryPointMappings.put(preferredMatcher, entryPoint);
return this;
}
@@ -180,7 +173,6 @@ public final class ExceptionHandlingConfigurer<H extends HttpSecurityBuilder<H>>
/**
* Gets the {@link AccessDeniedHandler} that is configured.
*
* @return the {@link AccessDeniedHandler}
*/
AccessDeniedHandler getAccessDeniedHandler() {
@@ -190,8 +182,8 @@ public final class ExceptionHandlingConfigurer<H extends HttpSecurityBuilder<H>>
@Override
public void configure(H http) {
AuthenticationEntryPoint entryPoint = getAuthenticationEntryPoint(http);
ExceptionTranslationFilter exceptionTranslationFilter = new ExceptionTranslationFilter(
entryPoint, getRequestCache(http));
ExceptionTranslationFilter exceptionTranslationFilter = new ExceptionTranslationFilter(entryPoint,
getRequestCache(http));
AccessDeniedHandler deniedHandler = getAccessDeniedHandler(http);
exceptionTranslationFilter.setAccessDeniedHandler(deniedHandler);
exceptionTranslationFilter = postProcess(exceptionTranslationFilter);
@@ -235,8 +227,7 @@ public final class ExceptionHandlingConfigurer<H extends HttpSecurityBuilder<H>>
if (this.defaultDeniedHandlerMappings.size() == 1) {
return this.defaultDeniedHandlerMappings.values().iterator().next();
}
return new RequestMatcherDelegatingAccessDeniedHandler(
this.defaultDeniedHandlerMappings,
return new RequestMatcherDelegatingAccessDeniedHandler(this.defaultDeniedHandlerMappings,
new AccessDeniedHandlerImpl());
}
@@ -249,8 +240,7 @@ public final class ExceptionHandlingConfigurer<H extends HttpSecurityBuilder<H>>
}
DelegatingAuthenticationEntryPoint entryPoint = new DelegatingAuthenticationEntryPoint(
this.defaultEntryPointMappings);
entryPoint.setDefaultEntryPoint(this.defaultEntryPointMappings.values().iterator()
.next());
entryPoint.setDefaultEntryPoint(this.defaultEntryPointMappings.values().iterator().next());
return entryPoint;
}
@@ -259,7 +249,6 @@ public final class ExceptionHandlingConfigurer<H extends HttpSecurityBuilder<H>>
* {@link #requestCache(org.springframework.security.web.savedrequest.RequestCache)},
* then it is used. Otherwise, an attempt to find a {@link RequestCache} shared object
* is made. If that fails, an {@link HttpSessionRequestCache} is used
*
* @param http the {@link HttpSecurity} to attempt to fined the shared object
* @return the {@link RequestCache} to use
*/
@@ -270,4 +259,5 @@ public final class ExceptionHandlingConfigurer<H extends HttpSecurityBuilder<H>>
}
return new HttpSessionRequestCache();
}
}
@@ -46,7 +46,8 @@ import org.springframework.util.StringUtils;
* Adds URL based authorization based upon SpEL expressions to an application. At least
* one {@link org.springframework.web.bind.annotation.RequestMapping} needs to be mapped
* to {@link ConfigAttribute}'s for this {@link SecurityContextConfigurer} to have
* meaning. <h2>Security Filters</h2>
* meaning.
* <h2>Security Filters</h2>
*
* The following Filters are populated
*
@@ -73,19 +74,23 @@ import org.springframework.util.StringUtils;
* </ul>
*
* @param <H> the type of {@link HttpSecurityBuilder} that is being configured
*
* @author Rob Winch
* @since 3.2
* @see org.springframework.security.config.annotation.web.builders.HttpSecurity#authorizeRequests()
*/
public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBuilder<H>>
extends
AbstractInterceptUrlConfigurer<ExpressionUrlAuthorizationConfigurer<H>, H> {
extends AbstractInterceptUrlConfigurer<ExpressionUrlAuthorizationConfigurer<H>, H> {
static final String permitAll = "permitAll";
private static final String denyAll = "denyAll";
private static final String anonymous = "anonymous";
private static final String authenticated = "authenticated";
private static final String fullyAuthenticated = "fullyAuthenticated";
private static final String rememberMe = "rememberMe";
private final ExpressionInterceptUrlRegistry REGISTRY;
@@ -104,8 +109,7 @@ public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBu
return REGISTRY;
}
public class ExpressionInterceptUrlRegistry
extends
public class ExpressionInterceptUrlRegistry extends
ExpressionUrlAuthorizationConfigurer<H>.AbstractInterceptUrlRegistry<ExpressionInterceptUrlRegistry, AuthorizedUrl> {
/**
@@ -126,15 +130,13 @@ public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBu
}
@Override
protected final AuthorizedUrl chainRequestMatchersInternal(
List<RequestMatcher> requestMatchers) {
protected final AuthorizedUrl chainRequestMatchersInternal(List<RequestMatcher> requestMatchers) {
return new AuthorizedUrl(requestMatchers);
}
/**
* Allows customization of the {@link SecurityExpressionHandler} to be used. The
* default is {@link DefaultWebSecurityExpressionHandler}
*
* @param expressionHandler the {@link SecurityExpressionHandler} to be used
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further
* customization.
@@ -147,13 +149,11 @@ public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBu
/**
* Adds an {@link ObjectPostProcessor} for this class.
*
* @param objectPostProcessor
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further
* customizations
*/
public ExpressionInterceptUrlRegistry withObjectPostProcessor(
ObjectPostProcessor<?> objectPostProcessor) {
public ExpressionInterceptUrlRegistry withObjectPostProcessor(ObjectPostProcessor<?> objectPostProcessor) {
addObjectPostProcessor(objectPostProcessor);
return this;
}
@@ -167,7 +167,6 @@ public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBu
/**
* Allows registering multiple {@link RequestMatcher} instances to a collection of
* {@link ConfigAttribute} instances
*
* @param requestMatchers the {@link RequestMatcher} instances to register to the
* {@link ConfigAttribute} instances
* @param configAttributes the {@link ConfigAttribute} to be mapped by the
@@ -176,8 +175,8 @@ public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBu
private void interceptUrl(Iterable<? extends RequestMatcher> requestMatchers,
Collection<ConfigAttribute> configAttributes) {
for (RequestMatcher requestMatcher : requestMatchers) {
REGISTRY.addMapping(new AbstractConfigAttributeRequestMatcherRegistry.UrlMapping(
requestMatcher, configAttributes));
REGISTRY.addMapping(
new AbstractConfigAttributeRequestMatcherRegistry.UrlMapping(requestMatcher, configAttributes));
}
}
@@ -192,23 +191,19 @@ public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBu
}
@Override
ExpressionBasedFilterInvocationSecurityMetadataSource createMetadataSource(
H http) {
LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> requestMap = REGISTRY
.createRequestMap();
ExpressionBasedFilterInvocationSecurityMetadataSource createMetadataSource(H http) {
LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> requestMap = REGISTRY.createRequestMap();
if (requestMap.isEmpty()) {
throw new IllegalStateException(
"At least one mapping is required (i.e. authorizeRequests().anyRequest().authenticated())");
}
return new ExpressionBasedFilterInvocationSecurityMetadataSource(requestMap,
getExpressionHandler(http));
return new ExpressionBasedFilterInvocationSecurityMetadataSource(requestMap, getExpressionHandler(http));
}
private SecurityExpressionHandler<FilterInvocation> getExpressionHandler(H http) {
if (expressionHandler == null) {
DefaultWebSecurityExpressionHandler defaultHandler = new DefaultWebSecurityExpressionHandler();
AuthenticationTrustResolver trustResolver = http
.getSharedObject(AuthenticationTrustResolver.class);
AuthenticationTrustResolver trustResolver = http.getSharedObject(AuthenticationTrustResolver.class);
if (trustResolver != null) {
defaultHandler.setTrustResolver(trustResolver);
}
@@ -218,14 +213,17 @@ public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBu
if (roleHiearchyBeanNames.length == 1) {
defaultHandler.setRoleHierarchy(context.getBean(roleHiearchyBeanNames[0], RoleHierarchy.class));
}
String[] grantedAuthorityDefaultsBeanNames = context.getBeanNamesForType(GrantedAuthorityDefaults.class);
String[] grantedAuthorityDefaultsBeanNames = context
.getBeanNamesForType(GrantedAuthorityDefaults.class);
if (grantedAuthorityDefaultsBeanNames.length == 1) {
GrantedAuthorityDefaults grantedAuthorityDefaults = context.getBean(grantedAuthorityDefaultsBeanNames[0], GrantedAuthorityDefaults.class);
GrantedAuthorityDefaults grantedAuthorityDefaults = context
.getBean(grantedAuthorityDefaultsBeanNames[0], GrantedAuthorityDefaults.class);
defaultHandler.setDefaultRolePrefix(grantedAuthorityDefaults.getRolePrefix());
}
String[] permissionEvaluatorBeanNames = context.getBeanNamesForType(PermissionEvaluator.class);
if (permissionEvaluatorBeanNames.length == 1) {
PermissionEvaluator permissionEvaluator = context.getBean(permissionEvaluatorBeanNames[0], PermissionEvaluator.class);
PermissionEvaluator permissionEvaluator = context.getBean(permissionEvaluatorBeanNames[0],
PermissionEvaluator.class);
defaultHandler.setPermissionEvaluator(permissionEvaluator);
}
}
@@ -237,8 +235,7 @@ public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBu
}
private static String hasAnyRole(String... authorities) {
String anyAuthorities = StringUtils.arrayToDelimitedString(authorities,
"','ROLE_");
String anyAuthorities = StringUtils.arrayToDelimitedString(authorities, "','ROLE_");
return "hasAnyRole('ROLE_" + anyAuthorities + "')";
}
@@ -246,8 +243,7 @@ public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBu
Assert.notNull(role, "role cannot be null");
if (role.startsWith("ROLE_")) {
throw new IllegalArgumentException(
"role should not start with 'ROLE_' since it is automatically inserted. Got '"
+ role + "'");
"role should not start with 'ROLE_' since it is automatically inserted. Got '" + role + "'");
}
return "hasRole('ROLE_" + role + "')";
}
@@ -272,9 +268,9 @@ public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBu
* @author Rob Winch
*/
public class MvcMatchersAuthorizedUrl extends AuthorizedUrl {
/**
* Creates a new instance
*
* @param requestMatchers the {@link RequestMatcher} instances to map
*/
private MvcMatchersAuthorizedUrl(List<MvcRequestMatcher> requestMatchers) {
@@ -287,15 +283,17 @@ public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBu
}
return this;
}
}
public class AuthorizedUrl {
private List<? extends RequestMatcher> requestMatchers;
private boolean not;
/**
* Creates a new instance
*
* @param requestMatchers the {@link RequestMatcher} instances to map
*/
private AuthorizedUrl(List<? extends RequestMatcher> requestMatchers) {
@@ -308,7 +306,6 @@ public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBu
/**
* Negates the following expression.
*
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further
* customization
*/
@@ -320,7 +317,6 @@ public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBu
/**
* Shortcut for specifying URLs require a particular role. If you do not want to
* have "ROLE_" automatically inserted see {@link #hasAuthority(String)}.
*
* @param role the role to require (i.e. USER, ADMIN, etc). Note, it should not
* start with "ROLE_" as this is automatically inserted.
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further
@@ -334,7 +330,6 @@ public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBu
* Shortcut for specifying URLs require any of a number of roles. If you do not
* want to have "ROLE_" automatically inserted see
* {@link #hasAnyAuthority(String...)}
*
* @param roles the roles to require (i.e. USER, ADMIN, etc). Note, it should not
* start with "ROLE_" as this is automatically inserted.
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further
@@ -346,7 +341,6 @@ public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBu
/**
* Specify that URLs require a particular authority.
*
* @param authority the authority to require (i.e. ROLE_USER, ROLE_ADMIN, etc).
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further
* customization
@@ -357,7 +351,6 @@ public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBu
/**
* Specify that URLs requires any of a number authorities.
*
* @param authorities the requests require at least one of the authorities (i.e.
* "ROLE_USER","ROLE_ADMIN" would mean either "ROLE_USER" or "ROLE_ADMIN" is
* required).
@@ -365,28 +358,24 @@ public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBu
* customization
*/
public ExpressionInterceptUrlRegistry hasAnyAuthority(String... authorities) {
return access(ExpressionUrlAuthorizationConfigurer
.hasAnyAuthority(authorities));
return access(ExpressionUrlAuthorizationConfigurer.hasAnyAuthority(authorities));
}
/**
* Specify that URLs requires a specific IP Address or <a href=
* "https://forum.spring.io/showthread.php?102783-How-to-use-hasIpAddress&p=343971#post343971"
* >subnet</a>.
*
* @param ipaddressExpression the ipaddress (i.e. 192.168.1.79) or local subnet
* (i.e. 192.168.0/24)
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further
* customization
*/
public ExpressionInterceptUrlRegistry hasIpAddress(String ipaddressExpression) {
return access(ExpressionUrlAuthorizationConfigurer
.hasIpAddress(ipaddressExpression));
return access(ExpressionUrlAuthorizationConfigurer.hasIpAddress(ipaddressExpression));
}
/**
* Specify that URLs are allowed by anyone.
*
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further
* customization
*/
@@ -396,7 +385,6 @@ public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBu
/**
* Specify that URLs are allowed by anonymous users.
*
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further
* customization
*/
@@ -406,7 +394,6 @@ public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBu
/**
* Specify that URLs are allowed by users that have been remembered.
*
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further
* customization
* @see RememberMeConfigurer
@@ -417,7 +404,6 @@ public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBu
/**
* Specify that URLs are not allowed by anyone.
*
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further
* customization
*/
@@ -427,7 +413,6 @@ public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBu
/**
* Specify that URLs are allowed by any authenticated user.
*
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further
* customization
*/
@@ -438,7 +423,6 @@ public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBu
/**
* Specify that URLs are allowed by users who have authenticated and were not
* "remembered".
*
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further
* customization
* @see RememberMeConfigurer
@@ -449,9 +433,8 @@ public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBu
/**
* Allows specifying that URLs are secured by an arbitrary expression
*
* @param attribute the expression to secure the URLs (i.e.
* "hasRole('ROLE_USER') and hasRole('ROLE_SUPER')")
* @param attribute the expression to secure the URLs (i.e. "hasRole('ROLE_USER')
* and hasRole('ROLE_SUPER')")
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further
* customization
*/
@@ -462,5 +445,7 @@ public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBu
interceptUrl(requestMatchers, SecurityConfig.createList(attribute));
return ExpressionUrlAuthorizationConfigurer.this.REGISTRY;
}
}
}
@@ -172,8 +172,6 @@ public final class FormLoginConfigurer<H extends HttpSecurityBuilder<H>> extends
* <li>/authenticate?error GET - redirect here for failed authentication attempts</li>
* <li>/authenticate?logout GET - redirect here after successfully logging out</li>
* </ul>
*
*
* @param loginPage the login page to redirect to if authentication is required (i.e.
* "/login")
* @return the {@link FormLoginConfigurer} for additional customization
@@ -186,7 +184,6 @@ public final class FormLoginConfigurer<H extends HttpSecurityBuilder<H>> extends
/**
* The HTTP parameter to look for the username when performing authentication. Default
* is "username".
*
* @param usernameParameter the HTTP parameter to look for the username when
* performing authentication
* @return the {@link FormLoginConfigurer} for additional customization
@@ -199,7 +196,6 @@ public final class FormLoginConfigurer<H extends HttpSecurityBuilder<H>> extends
/**
* The HTTP parameter to look for the password when performing authentication. Default
* is "password".
*
* @param passwordParameter the HTTP parameter to look for the password when
* performing authentication
* @return the {@link FormLoginConfigurer} for additional customization
@@ -211,7 +207,6 @@ public final class FormLoginConfigurer<H extends HttpSecurityBuilder<H>> extends
/**
* Forward Authentication Failure Handler
*
* @param forwardUrl the target URL in case of failure
* @return the {@link FormLoginConfigurer} for additional customization
*/
@@ -222,7 +217,6 @@ public final class FormLoginConfigurer<H extends HttpSecurityBuilder<H>> extends
/**
* Forward Authentication Success Handler
*
* @param forwardUrl the target URL in case of success
* @return the {@link FormLoginConfigurer} for additional customization
*/
@@ -251,7 +245,6 @@ public final class FormLoginConfigurer<H extends HttpSecurityBuilder<H>> extends
/**
* Gets the HTTP parameter that is used to submit the username.
*
* @return the HTTP parameter that is used to submit the username
*/
private String getUsernameParameter() {
@@ -260,7 +253,6 @@ public final class FormLoginConfigurer<H extends HttpSecurityBuilder<H>> extends
/**
* Gets the HTTP parameter that is used to submit the password.
*
* @return the HTTP parameter that is used to submit the password
*/
private String getPasswordParameter() {
@@ -270,7 +262,6 @@ public final class FormLoginConfigurer<H extends HttpSecurityBuilder<H>> extends
/**
* If available, initializes the {@link DefaultLoginPageGeneratingFilter} shared
* object.
*
* @param http the {@link HttpSecurityBuilder} to use
*/
private void initDefaultLoginFilter(H http) {
@@ -285,4 +276,5 @@ public final class FormLoginConfigurer<H extends HttpSecurityBuilder<H>> extends
loginPageGeneratingFilter.setAuthenticationUrl(getLoginProcessingUrl());
}
}
}
@@ -63,8 +63,9 @@ import org.springframework.util.Assert;
* @author Vedran Pavic
* @since 3.2
*/
public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
AbstractHttpConfigurer<HeadersConfigurer<H>, H> {
public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
extends AbstractHttpConfigurer<HeadersConfigurer<H>, H> {
private List<HeaderWriter> headerWriters = new ArrayList<>();
// --- default header writers ---
@@ -97,7 +98,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
/**
* Adds a {@link HeaderWriter} instance
*
* @param headerWriter the {@link HeaderWriter} instance to add
* @return the {@link HeadersConfigurer} for additional customizations
*/
@@ -108,14 +108,13 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
}
/**
* Configures the {@link XContentTypeOptionsHeaderWriter} which inserts the <a href=
* "https://msdn.microsoft.com/en-us/library/ie/gg622941(v=vs.85).aspx"
* Configures the {@link XContentTypeOptionsHeaderWriter} which inserts the
* <a href= "https://msdn.microsoft.com/en-us/library/ie/gg622941(v=vs.85).aspx"
* >X-Content-Type-Options</a>:
*
* <pre>
* X-Content-Type-Options: nosniff
* </pre>
*
* @return the {@link ContentTypeOptionsConfig} for additional customizations
*/
public ContentTypeOptionsConfig contentTypeOptions() {
@@ -123,16 +122,15 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
}
/**
* Configures the {@link XContentTypeOptionsHeaderWriter} which inserts the <a href=
* "https://msdn.microsoft.com/en-us/library/ie/gg622941(v=vs.85).aspx"
* Configures the {@link XContentTypeOptionsHeaderWriter} which inserts the
* <a href= "https://msdn.microsoft.com/en-us/library/ie/gg622941(v=vs.85).aspx"
* >X-Content-Type-Options</a>:
*
* <pre>
* X-Content-Type-Options: nosniff
* </pre>
*
* @param contentTypeOptionsCustomizer the {@link Customizer} to provide more options for
* the {@link ContentTypeOptionsConfig}
* @param contentTypeOptionsCustomizer the {@link Customizer} to provide more options
* for the {@link ContentTypeOptionsConfig}
* @return the {@link HeadersConfigurer} for additional customizations
*/
public HeadersConfigurer<H> contentTypeOptions(Customizer<ContentTypeOptionsConfig> contentTypeOptionsCustomizer) {
@@ -141,6 +139,7 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
}
public final class ContentTypeOptionsConfig {
private XContentTypeOptionsHeaderWriter writer;
private ContentTypeOptionsConfig() {
@@ -149,7 +148,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
/**
* Removes the X-XSS-Protection header.
*
* @return {@link HeadersConfigurer} for additional customization.
*/
public HeadersConfigurer<H> disable() {
@@ -167,7 +165,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
/**
* Ensures that Content Type Options is enabled
*
* @return the {@link ContentTypeOptionsConfig} for additional customization
*/
private ContentTypeOptionsConfig enable() {
@@ -176,6 +173,7 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
}
return this;
}
}
/**
@@ -186,7 +184,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
* "https://blogs.msdn.com/b/ieinternals/archive/2011/01/31/controlling-the-internet-explorer-xss-filter-with-the-x-xss-protection-http-header.aspx"
* >X-XSS-Protection header</a>
* </p>
*
* @return the {@link XXssConfig} for additional customizations
*/
public XXssConfig xssProtection() {
@@ -201,9 +198,8 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
* "https://blogs.msdn.com/b/ieinternals/archive/2011/01/31/controlling-the-internet-explorer-xss-filter-with-the-x-xss-protection-http-header.aspx"
* >X-XSS-Protection header</a>
* </p>
*
* @param xssCustomizer the {@link Customizer} to provide more options for
* the {@link XXssConfig}
* @param xssCustomizer the {@link Customizer} to provide more options for the
* {@link XXssConfig}
* @return the {@link HeadersConfigurer} for additional customizations
*/
public HeadersConfigurer<H> xssProtection(Customizer<XXssConfig> xssCustomizer) {
@@ -212,6 +208,7 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
}
public final class XXssConfig {
private XXssProtectionHeaderWriter writer;
private XXssConfig() {
@@ -221,7 +218,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
/**
* If false, will not specify the mode as blocked. In this instance, any content
* will be attempted to be fixed. If true, the content will be replaced with "#".
*
* @param enabled the new value
*/
public XXssConfig block(boolean enabled) {
@@ -236,7 +232,8 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
* X-XSS-Protection: 1
* </pre>
*
* or if {@link XXssProtectionHeaderWriter#setBlock(boolean)} of the given {@link XXssProtectionHeaderWriter} is true
* or if {@link XXssProtectionHeaderWriter#setBlock(boolean)} of the given
* {@link XXssProtectionHeaderWriter} is true
*
*
* <pre>
@@ -249,7 +246,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
* <pre>
* X-XSS-Protection: 0
* </pre>
*
* @param enabled the new value
*/
public XXssConfig xssProtectionEnabled(boolean enabled) {
@@ -259,7 +255,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
/**
* Disables X-XSS-Protection header (does not include it)
*
* @return the {@link HeadersConfigurer} for additional configuration
*/
public HeadersConfigurer<H> disable() {
@@ -270,7 +265,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
/**
* Allows completing configuration of X-XSS-Protection and continuing
* configuration of headers.
*
* @return the {@link HeadersConfigurer} for additional configuration
*/
public HeadersConfigurer<H> and() {
@@ -279,7 +273,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
/**
* Ensures the X-XSS-Protection header is enabled if it is not already.
*
* @return the {@link XXssConfig} for additional customization
*/
private XXssConfig enable() {
@@ -288,6 +281,7 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
}
return this;
}
}
/**
@@ -298,7 +292,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
* <li>Pragma: no-cache</li>
* <li>Expires: 0</li>
* </ul>
*
* @return the {@link CacheControlConfig} for additional customizations
*/
public CacheControlConfig cacheControl() {
@@ -313,7 +306,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
* <li>Pragma: no-cache</li>
* <li>Expires: 0</li>
* </ul>
*
* @param cacheControlCustomizer the {@link Customizer} to provide more options for
* the {@link CacheControlConfig}
* @return the {@link HeadersConfigurer} for additional customizations
@@ -324,6 +316,7 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
}
public final class CacheControlConfig {
private CacheControlHeadersWriter writer;
private CacheControlConfig() {
@@ -332,7 +325,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
/**
* Disables Cache Control
*
* @return the {@link HeadersConfigurer} for additional configuration
*/
public HeadersConfigurer<H> disable() {
@@ -341,9 +333,8 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
}
/**
* Allows completing configuration of Cache Control and continuing
* configuration of headers.
*
* Allows completing configuration of Cache Control and continuing configuration
* of headers.
* @return the {@link HeadersConfigurer} for additional configuration
*/
public HeadersConfigurer<H> and() {
@@ -352,7 +343,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
/**
* Ensures the Cache Control headers are enabled if they are not already.
*
* @return the {@link CacheControlConfig} for additional customization
*/
private CacheControlConfig enable() {
@@ -361,13 +351,13 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
}
return this;
}
}
/**
* Allows customizing the {@link HstsHeaderWriter} which provides support for <a
* href="https://tools.ietf.org/html/rfc6797">HTTP Strict Transport Security
* Allows customizing the {@link HstsHeaderWriter} which provides support for
* <a href="https://tools.ietf.org/html/rfc6797">HTTP Strict Transport Security
* (HSTS)</a>.
*
* @return the {@link HstsConfig} for additional customizations
*/
public HstsConfig httpStrictTransportSecurity() {
@@ -375,12 +365,11 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
}
/**
* Allows customizing the {@link HstsHeaderWriter} which provides support for <a
* href="https://tools.ietf.org/html/rfc6797">HTTP Strict Transport Security
* Allows customizing the {@link HstsHeaderWriter} which provides support for
* <a href="https://tools.ietf.org/html/rfc6797">HTTP Strict Transport Security
* (HSTS)</a>.
*
* @param hstsCustomizer the {@link Customizer} to provide more options for
* the {@link HstsConfig}
* @param hstsCustomizer the {@link Customizer} to provide more options for the
* {@link HstsConfig}
* @return the {@link HeadersConfigurer} for additional customizations
*/
public HeadersConfigurer<H> httpStrictTransportSecurity(Customizer<HstsConfig> hstsCustomizer) {
@@ -389,6 +378,7 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
}
public final class HstsConfig {
private HstsHeaderWriter writer;
private HstsConfig() {
@@ -403,11 +393,10 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
*
* <p>
* This instructs browsers how long to remember to keep this domain as a known
* HSTS Host. See <a
* href="https://tools.ietf.org/html/rfc6797#section-6.1.1">Section 6.1.1</a> for
* additional details.
* HSTS Host. See
* <a href="https://tools.ietf.org/html/rfc6797#section-6.1.1">Section 6.1.1</a>
* for additional details.
* </p>
*
* @param maxAgeInSeconds the maximum amount of time (in seconds) to consider this
* domain as a known HSTS Host.
* @throws IllegalArgumentException if maxAgeInSeconds is negative
@@ -422,7 +411,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
* "Strict-Transport-Security" should be added. If true the header is added, else
* the header is not added. By default the header is added when
* {@link HttpServletRequest#isSecure()} returns true.
*
* @param requestMatcher the {@link RequestMatcher} to use.
* @throws IllegalArgumentException if {@link RequestMatcher} is null
*/
@@ -440,7 +428,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
* See <a href="https://tools.ietf.org/html/rfc6797#section-6.1.2">Section
* 6.1.2</a> for additional details.
* </p>
*
* @param includeSubDomains true to include subdomains, else false
*/
public HstsConfig includeSubDomains(boolean includeSubDomains) {
@@ -454,10 +441,9 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
* </p>
*
* <p>
* See <a href="https://hstspreload.org/">Website hstspreload.org</a>
* for additional details.
* See <a href="https://hstspreload.org/">Website hstspreload.org</a> for
* additional details.
* </p>
*
* @param preload true to include preload, else false
* @since 5.2.0
* @author Ankur Pathak
@@ -469,7 +455,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
/**
* Disables Strict Transport Security
*
* @return the {@link HeadersConfigurer} for additional configuration
*/
public HeadersConfigurer<H> disable() {
@@ -480,7 +465,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
/**
* Allows completing configuration of Strict Transport Security and continuing
* configuration of headers.
*
* @return the {@link HeadersConfigurer} for additional configuration
*/
public HeadersConfigurer<H> and() {
@@ -489,7 +473,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
/**
* Ensures that Strict-Transport-Security is enabled if it is not already
*
* @return the {@link HstsConfig} for additional customization
*/
private HstsConfig enable() {
@@ -498,11 +481,11 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
}
return this;
}
}
/**
* Allows customizing the {@link XFrameOptionsHeaderWriter}.
*
* @return the {@link FrameOptionsConfig} for additional customizations
*/
public FrameOptionsConfig frameOptions() {
@@ -511,7 +494,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
/**
* Allows customizing the {@link XFrameOptionsHeaderWriter}.
*
* @param frameOptionsCustomizer the {@link Customizer} to provide more options for
* the {@link FrameOptionsConfig}
* @return the {@link HeadersConfigurer} for additional customizations
@@ -522,6 +504,7 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
}
public final class FrameOptionsConfig {
private XFrameOptionsHeaderWriter writer;
private FrameOptionsConfig() {
@@ -530,7 +513,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
/**
* Specify to DENY framing any content from this application.
*
* @return the {@link HeadersConfigurer} for additional customization.
*/
public HeadersConfigurer<H> deny() {
@@ -545,7 +527,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
* example.com could frame the application, but evil.com could not frame the
* application.
* </p>
*
* @return the {@link HeadersConfigurer} for additional customization.
*/
public HeadersConfigurer<H> sameOrigin() {
@@ -555,7 +536,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
/**
* Prevents the header from being added to the response.
*
* @return the {@link HeadersConfigurer} for additional configuration.
*/
public HeadersConfigurer<H> disable() {
@@ -565,7 +545,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
/**
* Allows continuing customizing the headers configuration.
*
* @return the {@link HeadersConfigurer} for additional configuration
*/
public HeadersConfigurer<H> and() {
@@ -574,7 +553,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
/**
* Enables FrameOptionsConfig if it is not already enabled.
*
* @return the FrameOptionsConfig for additional customization.
*/
private FrameOptionsConfig enable() {
@@ -583,12 +561,12 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
}
return this;
}
}
/**
* Allows customizing the {@link HpkpHeaderWriter} which provides support for <a
* href="https://tools.ietf.org/html/rfc7469">HTTP Public Key Pinning (HPKP)</a>.
*
* Allows customizing the {@link HpkpHeaderWriter} which provides support for
* <a href="https://tools.ietf.org/html/rfc7469">HTTP Public Key Pinning (HPKP)</a>.
* @return the {@link HpkpConfig} for additional customizations
*
* @since 4.1
@@ -598,11 +576,10 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
}
/**
* Allows customizing the {@link HpkpHeaderWriter} which provides support for <a
* href="https://tools.ietf.org/html/rfc7469">HTTP Public Key Pinning (HPKP)</a>.
*
* @param hpkpCustomizer the {@link Customizer} to provide more options for
* the {@link HpkpConfig}
* Allows customizing the {@link HpkpHeaderWriter} which provides support for
* <a href="https://tools.ietf.org/html/rfc7469">HTTP Public Key Pinning (HPKP)</a>.
* @param hpkpCustomizer the {@link Customizer} to provide more options for the
* {@link HpkpConfig}
* @return the {@link HeadersConfigurer} for additional customizations
*/
public HeadersConfigurer<H> httpPublicKeyPinning(Customizer<HpkpConfig> hpkpCustomizer) {
@@ -611,9 +588,11 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
}
public final class HpkpConfig {
private HpkpHeaderWriter writer;
private HpkpConfig() {}
private HpkpConfig() {
}
/**
* <p>
@@ -621,12 +600,13 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
* </p>
*
* <p>
* The pin directive specifies a way for web host operators to indicate
* a cryptographic identity that should be bound to a given web host.
* See <a href="https://tools.ietf.org/html/rfc7469#section-2.1.1">Section 2.1.1</a> for additional details.
* The pin directive specifies a way for web host operators to indicate a
* cryptographic identity that should be bound to a given web host. See
* <a href="https://tools.ietf.org/html/rfc7469#section-2.1.1">Section 2.1.1</a>
* for additional details.
* </p>
*
* @param pins the map of base64-encoded SPKI fingerprint &amp; cryptographic hash algorithm pairs.
* @param pins the map of base64-encoded SPKI fingerprint &amp; cryptographic hash
* algorithm pairs.
* @throws IllegalArgumentException if pins is null
*/
public HpkpConfig withPins(Map<String, String> pins) {
@@ -636,37 +616,38 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
/**
* <p>
* Adds a list of SHA256 hashed pins for the pin- directive of the Public-Key-Pins header.
* Adds a list of SHA256 hashed pins for the pin- directive of the Public-Key-Pins
* header.
* </p>
*
* <p>
* The pin directive specifies a way for web host operators to indicate
* a cryptographic identity that should be bound to a given web host.
* See <a href="https://tools.ietf.org/html/rfc7469#section-2.1.1">Section 2.1.1</a> for additional details.
* The pin directive specifies a way for web host operators to indicate a
* cryptographic identity that should be bound to a given web host. See
* <a href="https://tools.ietf.org/html/rfc7469#section-2.1.1">Section 2.1.1</a>
* for additional details.
* </p>
*
* @param pins a list of base64-encoded SPKI fingerprints.
* @throws IllegalArgumentException if a pin is null
*/
public HpkpConfig addSha256Pins(String ... pins) {
public HpkpConfig addSha256Pins(String... pins) {
writer.addSha256Pins(pins);
return this;
}
/**
* <p>
* Sets the value (in seconds) for the max-age directive of the Public-Key-Pins header.
* The default is 60 days.
* Sets the value (in seconds) for the max-age directive of the Public-Key-Pins
* header. The default is 60 days.
* </p>
*
* <p>
* This instructs browsers how long they should regard the host (from whom the message was received)
* as a known pinned host. See <a href="https://tools.ietf.org/html/rfc7469#section-2.1.2">Section
* 2.1.2</a> for additional details.
* This instructs browsers how long they should regard the host (from whom the
* message was received) as a known pinned host. See
* <a href="https://tools.ietf.org/html/rfc7469#section-2.1.2">Section 2.1.2</a>
* for additional details.
* </p>
*
* @param maxAgeInSeconds the maximum amount of time (in seconds) to regard the host
* as a known pinned host.
* @param maxAgeInSeconds the maximum amount of time (in seconds) to regard the
* host as a known pinned host.
* @throws IllegalArgumentException if maxAgeInSeconds is negative
*/
public HpkpConfig maxAgeInSeconds(long maxAgeInSeconds) {
@@ -676,15 +657,14 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
/**
* <p>
* If true, the pinning policy applies to this pinned host as well as any subdomains
* of the host's domain name. The default is false.
* If true, the pinning policy applies to this pinned host as well as any
* subdomains of the host's domain name. The default is false.
* </p>
*
* <p>
* See <a href="https://tools.ietf.org/html/rfc7469#section-2.1.3">Section 2.1.3</a>
* for additional details.
* See <a href="https://tools.ietf.org/html/rfc7469#section-2.1.3">Section
* 2.1.3</a> for additional details.
* </p>
*
* @param includeSubDomains true to include subdomains, else false
*/
public HpkpConfig includeSubDomains(boolean includeSubDomains) {
@@ -694,14 +674,14 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
/**
* <p>
* If true, the browser should not terminate the connection with the server. The default is true.
* If true, the browser should not terminate the connection with the server. The
* default is true.
* </p>
*
* <p>
* See <a href="https://tools.ietf.org/html/rfc7469#section-2.1">Section 2.1</a>
* for additional details.
* </p>
*
* @param reportOnly true to report only, else false
*/
public HpkpConfig reportOnly(boolean reportOnly) {
@@ -715,10 +695,9 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
* </p>
*
* <p>
* See <a href="https://tools.ietf.org/html/rfc7469#section-2.1.4">Section 2.1.4</a>
* for additional details.
* See <a href="https://tools.ietf.org/html/rfc7469#section-2.1.4">Section
* 2.1.4</a> for additional details.
* </p>
*
* @param reportUri the URI where the browser should send the report to.
*/
public HpkpConfig reportUri(URI reportUri) {
@@ -732,10 +711,9 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
* </p>
*
* <p>
* See <a href="https://tools.ietf.org/html/rfc7469#section-2.1.4">Section 2.1.4</a>
* for additional details.
* See <a href="https://tools.ietf.org/html/rfc7469#section-2.1.4">Section
* 2.1.4</a> for additional details.
* </p>
*
* @param reportUri the URI where the browser should send the report to.
* @throws IllegalArgumentException if the reportUri is not a valid URI
*/
@@ -746,7 +724,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
/**
* Prevents the header from being added to the response.
*
* @return the {@link HeadersConfigurer} for additional configuration.
*/
public HeadersConfigurer<H> disable() {
@@ -757,7 +734,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
/**
* Allows completing configuration of Public Key Pinning and continuing
* configuration of headers.
*
* @return the {@link HeadersConfigurer} for additional configuration
*/
public HeadersConfigurer<H> and() {
@@ -765,8 +741,8 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
}
/**
* Ensures that Public-Key-Pins or Public-Key-Pins-Report-Only is enabled if it is not already
*
* Ensures that Public-Key-Pins or Public-Key-Pins-Report-Only is enabled if it is
* not already
* @return the {@link HstsConfig} for additional customization
*/
private HpkpConfig enable() {
@@ -775,25 +751,28 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
}
return this;
}
}
/**
* <p>
* Allows configuration for <a href="https://www.w3.org/TR/CSP2/">Content Security Policy (CSP) Level 2</a>.
* Allows configuration for <a href="https://www.w3.org/TR/CSP2/">Content Security
* Policy (CSP) Level 2</a>.
* </p>
*
* <p>
* Calling this method automatically enables (includes) the Content-Security-Policy header in the response
* using the supplied security policy directive(s).
* Calling this method automatically enables (includes) the Content-Security-Policy
* header in the response using the supplied security policy directive(s).
* </p>
*
* <p>
* Configuration is provided to the {@link ContentSecurityPolicyHeaderWriter} which supports the writing
* of the two headers as detailed in the W3C Candidate Recommendation:
* Configuration is provided to the {@link ContentSecurityPolicyHeaderWriter} which
* supports the writing of the two headers as detailed in the W3C Candidate
* Recommendation:
* </p>
* <ul>
* <li>Content-Security-Policy</li>
* <li>Content-Security-Policy-Report-Only</li>
* <li>Content-Security-Policy</li>
* <li>Content-Security-Policy-Report-Only</li>
* </ul>
*
* @see ContentSecurityPolicyHeaderWriter
@@ -802,28 +781,29 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
* @throws IllegalArgumentException if policyDirectives is null or empty
*/
public ContentSecurityPolicyConfig contentSecurityPolicy(String policyDirectives) {
this.contentSecurityPolicy.writer =
new ContentSecurityPolicyHeaderWriter(policyDirectives);
this.contentSecurityPolicy.writer = new ContentSecurityPolicyHeaderWriter(policyDirectives);
return contentSecurityPolicy;
}
/**
* <p>
* Allows configuration for <a href="https://www.w3.org/TR/CSP2/">Content Security Policy (CSP) Level 2</a>.
* Allows configuration for <a href="https://www.w3.org/TR/CSP2/">Content Security
* Policy (CSP) Level 2</a>.
* </p>
*
* <p>
* Calling this method automatically enables (includes) the Content-Security-Policy header in the response
* using the supplied security policy directive(s).
* Calling this method automatically enables (includes) the Content-Security-Policy
* header in the response using the supplied security policy directive(s).
* </p>
*
* <p>
* Configuration is provided to the {@link ContentSecurityPolicyHeaderWriter} which supports the writing
* of the two headers as detailed in the W3C Candidate Recommendation:
* Configuration is provided to the {@link ContentSecurityPolicyHeaderWriter} which
* supports the writing of the two headers as detailed in the W3C Candidate
* Recommendation:
* </p>
* <ul>
* <li>Content-Security-Policy</li>
* <li>Content-Security-Policy-Report-Only</li>
* <li>Content-Security-Policy</li>
* <li>Content-Security-Policy-Report-Only</li>
* </ul>
*
* @see ContentSecurityPolicyHeaderWriter
@@ -831,7 +811,8 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
* the {@link ContentSecurityPolicyConfig}
* @return the {@link HeadersConfigurer} for additional customizations
*/
public HeadersConfigurer<H> contentSecurityPolicy(Customizer<ContentSecurityPolicyConfig> contentSecurityCustomizer) {
public HeadersConfigurer<H> contentSecurityPolicy(
Customizer<ContentSecurityPolicyConfig> contentSecurityCustomizer) {
this.contentSecurityPolicy.writer = new ContentSecurityPolicyHeaderWriter();
contentSecurityCustomizer.customize(this.contentSecurityPolicy);
@@ -839,6 +820,7 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
}
public final class ContentSecurityPolicyConfig {
private ContentSecurityPolicyHeaderWriter writer;
private ContentSecurityPolicyConfig() {
@@ -846,7 +828,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
/**
* Sets the security policy directive(s) to be used in the response header.
*
* @param policyDirectives the security policy directive(s)
* @return the {@link ContentSecurityPolicyConfig} for additional configuration
* @throws IllegalArgumentException if policyDirectives is null or empty
@@ -857,8 +838,8 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
}
/**
* Enables (includes) the Content-Security-Policy-Report-Only header in the response.
*
* Enables (includes) the Content-Security-Policy-Report-Only header in the
* response.
* @return the {@link ContentSecurityPolicyConfig} for additional configuration
*/
public ContentSecurityPolicyConfig reportOnly() {
@@ -869,7 +850,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
/**
* Allows completing configuration of Content Security Policy and continuing
* configuration of headers.
*
* @return the {@link HeadersConfigurer} for additional configuration
*/
public HeadersConfigurer<H> and() {
@@ -886,7 +866,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
* <pre>
* http.headers().defaultsDisabled().cacheControl();
* </pre>
*
* @return the {@link HeadersConfigurer} for additional customization
*/
public HeadersConfigurer<H> defaultsDisabled() {
@@ -906,7 +885,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
/**
* Creates the {@link HeaderWriter}
*
* @return the {@link HeaderWriter}
*/
private HeaderWriterFilter createHeaderWriterFilter() {
@@ -922,7 +900,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
/**
* Gets the {@link HeaderWriter} instances and possibly initializes with the defaults.
*
* @return
*/
private List<HeaderWriter> getHeaderWriters() {
@@ -948,18 +925,21 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
/**
* <p>
* Allows configuration for <a href="https://www.w3.org/TR/referrer-policy/">Referrer Policy</a>.
* Allows configuration for <a href="https://www.w3.org/TR/referrer-policy/">Referrer
* Policy</a>.
* </p>
*
* <p>
* Configuration is provided to the {@link ReferrerPolicyHeaderWriter} which support the writing
* of the header as detailed in the W3C Technical Report:
* Configuration is provided to the {@link ReferrerPolicyHeaderWriter} which support
* the writing of the header as detailed in the W3C Technical Report:
* </p>
* <ul>
* <li>Referrer-Policy</li>
* <li>Referrer-Policy</li>
* </ul>
*
* <p>Default value is:</p>
* <p>
* Default value is:
* </p>
*
* <pre>
* Referrer-Policy: no-referrer
@@ -976,15 +956,16 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
/**
* <p>
* Allows configuration for <a href="https://www.w3.org/TR/referrer-policy/">Referrer Policy</a>.
* Allows configuration for <a href="https://www.w3.org/TR/referrer-policy/">Referrer
* Policy</a>.
* </p>
*
* <p>
* Configuration is provided to the {@link ReferrerPolicyHeaderWriter} which support the writing
* of the header as detailed in the W3C Technical Report:
* Configuration is provided to the {@link ReferrerPolicyHeaderWriter} which support
* the writing of the header as detailed in the W3C Technical Report:
* </p>
* <ul>
* <li>Referrer-Policy</li>
* <li>Referrer-Policy</li>
* </ul>
*
* @see ReferrerPolicyHeaderWriter
@@ -999,15 +980,16 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
/**
* <p>
* Allows configuration for <a href="https://www.w3.org/TR/referrer-policy/">Referrer Policy</a>.
* Allows configuration for <a href="https://www.w3.org/TR/referrer-policy/">Referrer
* Policy</a>.
* </p>
*
* <p>
* Configuration is provided to the {@link ReferrerPolicyHeaderWriter} which support the writing
* of the header as detailed in the W3C Technical Report:
* Configuration is provided to the {@link ReferrerPolicyHeaderWriter} which support
* the writing of the header as detailed in the W3C Technical Report:
* </p>
* <ul>
* <li>Referrer-Policy</li>
* <li>Referrer-Policy</li>
* </ul>
*
* @see ReferrerPolicyHeaderWriter
@@ -1030,7 +1012,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
/**
* Sets the policy to be used in the response header.
*
* @param policy a referrer policy
* @return the {@link ReferrerPolicyConfig} for additional configuration
* @throws IllegalArgumentException if policy is null
@@ -1076,7 +1057,6 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
/**
* Allows completing configuration of Feature Policy and continuing configuration
* of headers.
*
* @return the {@link HeadersConfigurer} for additional configuration
*/
public HeadersConfigurer<H> and() {
@@ -53,8 +53,7 @@ import org.springframework.web.accept.HeaderContentNegotiationStrategy;
* The following Filters are populated
*
* <ul>
* <li>
* {@link BasicAuthenticationFilter}</li>
* <li>{@link BasicAuthenticationFilter}</li>
* </ul>
*
* <h2>Shared Objects Created</h2>
@@ -77,16 +76,18 @@ import org.springframework.web.accept.HeaderContentNegotiationStrategy;
* @author Rob Winch
* @since 3.2
*/
public final class HttpBasicConfigurer<B extends HttpSecurityBuilder<B>> extends
AbstractHttpConfigurer<HttpBasicConfigurer<B>, B> {
public final class HttpBasicConfigurer<B extends HttpSecurityBuilder<B>>
extends AbstractHttpConfigurer<HttpBasicConfigurer<B>, B> {
private static final RequestHeaderRequestMatcher X_REQUESTED_WITH = new RequestHeaderRequestMatcher("X-Requested-With",
"XMLHttpRequest");
private static final RequestHeaderRequestMatcher X_REQUESTED_WITH = new RequestHeaderRequestMatcher(
"X-Requested-With", "XMLHttpRequest");
private static final String DEFAULT_REALM = "Realm";
private AuthenticationEntryPoint authenticationEntryPoint;
private AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource;
private BasicAuthenticationEntryPoint basicAuthEntryPoint = new BasicAuthenticationEntryPoint();
/**
@@ -99,8 +100,7 @@ public final class HttpBasicConfigurer<B extends HttpSecurityBuilder<B>> extends
LinkedHashMap<RequestMatcher, AuthenticationEntryPoint> entryPoints = new LinkedHashMap<>();
entryPoints.put(X_REQUESTED_WITH, new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED));
DelegatingAuthenticationEntryPoint defaultEntryPoint = new DelegatingAuthenticationEntryPoint(
entryPoints);
DelegatingAuthenticationEntryPoint defaultEntryPoint = new DelegatingAuthenticationEntryPoint(entryPoints);
defaultEntryPoint.setDefaultEntryPoint(this.basicAuthEntryPoint);
this.authenticationEntryPoint = defaultEntryPoint;
}
@@ -109,7 +109,6 @@ public final class HttpBasicConfigurer<B extends HttpSecurityBuilder<B>> extends
* Allows easily changing the realm, but leaving the remaining defaults in place. If
* {@link #authenticationEntryPoint(AuthenticationEntryPoint)} has been invoked,
* invoking this method will result in an error.
*
* @param realmName the HTTP Basic realm to use
* @return {@link HttpBasicConfigurer} for additional customization
*/
@@ -122,14 +121,11 @@ public final class HttpBasicConfigurer<B extends HttpSecurityBuilder<B>> extends
/**
* The {@link AuthenticationEntryPoint} to be populated on
* {@link BasicAuthenticationFilter} in the event that authentication fails. The
* default to use {@link BasicAuthenticationEntryPoint} with the realm
* "Realm".
*
* default to use {@link BasicAuthenticationEntryPoint} with the realm "Realm".
* @param authenticationEntryPoint the {@link AuthenticationEntryPoint} to use
* @return {@link HttpBasicConfigurer} for additional customization
*/
public HttpBasicConfigurer<B> authenticationEntryPoint(
AuthenticationEntryPoint authenticationEntryPoint) {
public HttpBasicConfigurer<B> authenticationEntryPoint(AuthenticationEntryPoint authenticationEntryPoint) {
this.authenticationEntryPoint = authenticationEntryPoint;
return this;
}
@@ -137,7 +133,6 @@ public final class HttpBasicConfigurer<B extends HttpSecurityBuilder<B>> extends
/**
* Specifies a custom {@link AuthenticationDetailsSource} to use for basic
* authentication. The default is {@link WebAuthenticationDetailsSource}.
*
* @param authenticationDetailsSource the custom {@link AuthenticationDetailsSource}
* to use
* @return {@link HttpBasicConfigurer} for additional customization
@@ -154,47 +149,43 @@ public final class HttpBasicConfigurer<B extends HttpSecurityBuilder<B>> extends
}
private void registerDefaults(B http) {
ContentNegotiationStrategy contentNegotiationStrategy = http
.getSharedObject(ContentNegotiationStrategy.class);
ContentNegotiationStrategy contentNegotiationStrategy = http.getSharedObject(ContentNegotiationStrategy.class);
if (contentNegotiationStrategy == null) {
contentNegotiationStrategy = new HeaderContentNegotiationStrategy();
}
MediaTypeRequestMatcher restMatcher = new MediaTypeRequestMatcher(
contentNegotiationStrategy, MediaType.APPLICATION_ATOM_XML,
MediaType.APPLICATION_FORM_URLENCODED, MediaType.APPLICATION_JSON,
MediaType.APPLICATION_OCTET_STREAM, MediaType.APPLICATION_XML,
MediaType.MULTIPART_FORM_DATA, MediaType.TEXT_XML);
MediaTypeRequestMatcher restMatcher = new MediaTypeRequestMatcher(contentNegotiationStrategy,
MediaType.APPLICATION_ATOM_XML, MediaType.APPLICATION_FORM_URLENCODED, MediaType.APPLICATION_JSON,
MediaType.APPLICATION_OCTET_STREAM, MediaType.APPLICATION_XML, MediaType.MULTIPART_FORM_DATA,
MediaType.TEXT_XML);
restMatcher.setIgnoredMediaTypes(Collections.singleton(MediaType.ALL));
MediaTypeRequestMatcher allMatcher = new MediaTypeRequestMatcher(contentNegotiationStrategy, MediaType.ALL);
allMatcher.setUseEquals(true);
RequestMatcher notHtmlMatcher = new NegatedRequestMatcher(
new MediaTypeRequestMatcher(contentNegotiationStrategy,
MediaType.TEXT_HTML));
new MediaTypeRequestMatcher(contentNegotiationStrategy, MediaType.TEXT_HTML));
RequestMatcher restNotHtmlMatcher = new AndRequestMatcher(
Arrays.<RequestMatcher>asList(notHtmlMatcher, restMatcher));
RequestMatcher preferredMatcher = new OrRequestMatcher(Arrays.asList(X_REQUESTED_WITH, restNotHtmlMatcher, allMatcher));
RequestMatcher preferredMatcher = new OrRequestMatcher(
Arrays.asList(X_REQUESTED_WITH, restNotHtmlMatcher, allMatcher));
registerDefaultEntryPoint(http, preferredMatcher);
registerDefaultLogoutSuccessHandler(http, preferredMatcher);
}
private void registerDefaultEntryPoint(B http, RequestMatcher preferredMatcher) {
ExceptionHandlingConfigurer<B> exceptionHandling = http
.getConfigurer(ExceptionHandlingConfigurer.class);
ExceptionHandlingConfigurer<B> exceptionHandling = http.getConfigurer(ExceptionHandlingConfigurer.class);
if (exceptionHandling == null) {
return;
}
exceptionHandling.defaultAuthenticationEntryPointFor(
postProcess(this.authenticationEntryPoint), preferredMatcher);
exceptionHandling.defaultAuthenticationEntryPointFor(postProcess(this.authenticationEntryPoint),
preferredMatcher);
}
private void registerDefaultLogoutSuccessHandler(B http, RequestMatcher preferredMatcher) {
LogoutConfigurer<B> logout = http
.getConfigurer(LogoutConfigurer.class);
LogoutConfigurer<B> logout = http.getConfigurer(LogoutConfigurer.class);
if (logout == null) {
return;
}
@@ -204,13 +195,11 @@ public final class HttpBasicConfigurer<B extends HttpSecurityBuilder<B>> extends
@Override
public void configure(B http) {
AuthenticationManager authenticationManager = http
.getSharedObject(AuthenticationManager.class);
BasicAuthenticationFilter basicAuthenticationFilter = new BasicAuthenticationFilter(
authenticationManager, this.authenticationEntryPoint);
AuthenticationManager authenticationManager = http.getSharedObject(AuthenticationManager.class);
BasicAuthenticationFilter basicAuthenticationFilter = new BasicAuthenticationFilter(authenticationManager,
this.authenticationEntryPoint);
if (this.authenticationDetailsSource != null) {
basicAuthenticationFilter
.setAuthenticationDetailsSource(this.authenticationDetailsSource);
basicAuthenticationFilter.setAuthenticationDetailsSource(this.authenticationDetailsSource);
}
RememberMeServices rememberMeServices = http.getSharedObject(RememberMeServices.class);
if (rememberMeServices != null) {
@@ -219,4 +208,5 @@ public final class HttpBasicConfigurer<B extends HttpSecurityBuilder<B>> extends
basicAuthenticationFilter = postProcess(basicAuthenticationFilter);
http.addFilter(basicAuthenticationFilter);
}
}
@@ -42,15 +42,13 @@ import org.springframework.security.web.authentication.preauth.j2ee.J2eePreAuthe
* The following Filters are populated
*
* <ul>
* <li>
* {@link J2eePreAuthenticatedProcessingFilter}</li>
* <li>{@link J2eePreAuthenticatedProcessingFilter}</li>
* </ul>
*
* <h2>Shared Objects Created</h2>
*
* <ul>
* <li>
* {@link AuthenticationEntryPoint} is populated with an
* <li>{@link AuthenticationEntryPoint} is populated with an
* {@link Http403ForbiddenEntryPoint}</li>
* <li>A {@link PreAuthenticatedAuthenticationProvider} is populated into
* {@link HttpSecurity#authenticationProvider(org.springframework.security.authentication.AuthenticationProvider)}
@@ -68,10 +66,12 @@ import org.springframework.security.web.authentication.preauth.j2ee.J2eePreAuthe
* @author Rob Winch
* @since 3.2
*/
public final class JeeConfigurer<H extends HttpSecurityBuilder<H>> extends
AbstractHttpConfigurer<JeeConfigurer<H>, H> {
public final class JeeConfigurer<H extends HttpSecurityBuilder<H>> extends AbstractHttpConfigurer<JeeConfigurer<H>, H> {
private J2eePreAuthenticatedProcessingFilter j2eePreAuthenticatedProcessingFilter;
private AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken> authenticationUserDetailsService;
private Set<String> mappableRoles = new HashSet<>();
/**
@@ -91,7 +91,6 @@ public final class JeeConfigurer<H extends HttpSecurityBuilder<H>> extends
* <p>
* There are no default roles that are mapped.
* </p>
*
* @param mappableRoles the roles to attempt to map to the {@link UserDetails} (i.e.
* "ROLE_USER", "ROLE_ADMIN", etc).
* @return the {@link JeeConfigurer} for further customizations
@@ -117,7 +116,6 @@ public final class JeeConfigurer<H extends HttpSecurityBuilder<H>> extends
* <p>
* There are no default roles that are mapped.
* </p>
*
* @param mappableRoles the roles to attempt to map to the {@link UserDetails} (i.e.
* "USER", "ADMIN", etc).
* @return the {@link JeeConfigurer} for further customizations
@@ -142,7 +140,6 @@ public final class JeeConfigurer<H extends HttpSecurityBuilder<H>> extends
* <p>
* There are no default roles that are mapped.
* </p>
*
* @param mappableRoles the roles to attempt to map to the {@link UserDetails}.
* @return the {@link JeeConfigurer} for further customizations
* @see SimpleMappableAttributesRetriever
@@ -156,7 +153,6 @@ public final class JeeConfigurer<H extends HttpSecurityBuilder<H>> extends
* Specifies the {@link AuthenticationUserDetailsService} that is used with the
* {@link PreAuthenticatedAuthenticationProvider}. The default is a
* {@link PreAuthenticatedGrantedAuthoritiesUserDetailsService}.
*
* @param authenticatedUserDetailsService the {@link AuthenticationUserDetailsService}
* to use.
* @return the {@link JeeConfigurer} for further configuration
@@ -172,7 +168,6 @@ public final class JeeConfigurer<H extends HttpSecurityBuilder<H>> extends
* {@link J2eePreAuthenticatedProcessingFilter} is provided, all of its attributes
* must also be configured manually (i.e. all attributes populated in the
* {@link JeeConfigurer} are not used).
*
* @param j2eePreAuthenticatedProcessingFilter the
* {@link J2eePreAuthenticatedProcessingFilter} to use.
* @return the {@link JeeConfigurer} for further configuration
@@ -194,8 +189,7 @@ public final class JeeConfigurer<H extends HttpSecurityBuilder<H>> extends
@Override
public void init(H http) {
PreAuthenticatedAuthenticationProvider authenticationProvider = new PreAuthenticatedAuthenticationProvider();
authenticationProvider
.setPreAuthenticatedUserDetailsService(getUserDetailsService());
authenticationProvider.setPreAuthenticatedUserDetailsService(getUserDetailsService());
authenticationProvider = postProcess(authenticationProvider);
// @formatter:off
@@ -207,8 +201,7 @@ public final class JeeConfigurer<H extends HttpSecurityBuilder<H>> extends
@Override
public void configure(H http) {
J2eePreAuthenticatedProcessingFilter filter = getFilter(http
.getSharedObject(AuthenticationManager.class));
J2eePreAuthenticatedProcessingFilter filter = getFilter(http.getSharedObject(AuthenticationManager.class));
http.addFilter(filter);
}
@@ -218,14 +211,11 @@ public final class JeeConfigurer<H extends HttpSecurityBuilder<H>> extends
* @param authenticationManager the {@link AuthenticationManager} to use.
* @return the {@link J2eePreAuthenticatedProcessingFilter} to use.
*/
private J2eePreAuthenticatedProcessingFilter getFilter(
AuthenticationManager authenticationManager) {
private J2eePreAuthenticatedProcessingFilter getFilter(AuthenticationManager authenticationManager) {
if (j2eePreAuthenticatedProcessingFilter == null) {
j2eePreAuthenticatedProcessingFilter = new J2eePreAuthenticatedProcessingFilter();
j2eePreAuthenticatedProcessingFilter
.setAuthenticationManager(authenticationManager);
j2eePreAuthenticatedProcessingFilter
.setAuthenticationDetailsSource(createWebAuthenticationDetailsSource());
j2eePreAuthenticatedProcessingFilter.setAuthenticationManager(authenticationManager);
j2eePreAuthenticatedProcessingFilter.setAuthenticationDetailsSource(createWebAuthenticationDetailsSource());
j2eePreAuthenticatedProcessingFilter = postProcess(j2eePreAuthenticatedProcessingFilter);
}
@@ -235,7 +225,6 @@ public final class JeeConfigurer<H extends HttpSecurityBuilder<H>> extends
/**
* Gets the {@link AuthenticationUserDetailsService} that was specified or defaults to
* {@link PreAuthenticatedGrantedAuthoritiesUserDetailsService}.
*
* @return the {@link AuthenticationUserDetailsService} to use
*/
private AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken> getUserDetailsService() {
@@ -247,7 +236,6 @@ public final class JeeConfigurer<H extends HttpSecurityBuilder<H>> extends
* Creates the {@link J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource} to set
* on the {@link J2eePreAuthenticatedProcessingFilter}. It is populated with a
* {@link SimpleMappableAttributesRetriever}.
*
* @return the {@link J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource} to use.
*/
private J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource createWebAuthenticationDetailsSource() {
@@ -259,4 +247,5 @@ public final class JeeConfigurer<H extends HttpSecurityBuilder<H>> extends
detailsSource = postProcess(detailsSource);
return detailsSource;
}
}
@@ -41,15 +41,15 @@ import org.springframework.util.Assert;
/**
* Adds logout support. Other {@link SecurityConfigurer} instances may invoke
* {@link #addLogoutHandler(LogoutHandler)} in the {@link #init(HttpSecurityBuilder)} phase.
* {@link #addLogoutHandler(LogoutHandler)} in the {@link #init(HttpSecurityBuilder)}
* phase.
*
* <h2>Security Filters</h2>
*
* The following Filters are populated
*
* <ul>
* <li>
* {@link LogoutFilter}</li>
* <li>{@link LogoutFilter}</li>
* </ul>
*
* <h2>Shared Objects Created</h2>
@@ -65,19 +65,26 @@ import org.springframework.util.Assert;
* @since 3.2
* @see RememberMeConfigurer
*/
public final class LogoutConfigurer<H extends HttpSecurityBuilder<H>> extends
AbstractHttpConfigurer<LogoutConfigurer<H>, H> {
public final class LogoutConfigurer<H extends HttpSecurityBuilder<H>>
extends AbstractHttpConfigurer<LogoutConfigurer<H>, H> {
private List<LogoutHandler> logoutHandlers = new ArrayList<>();
private SecurityContextLogoutHandler contextLogoutHandler = new SecurityContextLogoutHandler();
private String logoutSuccessUrl = "/login?logout";
private LogoutSuccessHandler logoutSuccessHandler;
private String logoutUrl = "/logout";
private RequestMatcher logoutRequestMatcher;
private boolean permitAll;
private boolean customLogoutSuccess;
private LinkedHashMap<RequestMatcher, LogoutSuccessHandler> defaultLogoutSuccessHandlerMappings =
new LinkedHashMap<>();
private LinkedHashMap<RequestMatcher, LogoutSuccessHandler> defaultLogoutSuccessHandlerMappings = new LinkedHashMap<>();
/**
* Creates a new instance
@@ -87,10 +94,9 @@ public final class LogoutConfigurer<H extends HttpSecurityBuilder<H>> extends
}
/**
* Adds a {@link LogoutHandler}.
* {@link SecurityContextLogoutHandler} and {@link LogoutSuccessEventPublishingLogoutHandler} are added as
* last {@link LogoutHandler} instances by default.
*
* Adds a {@link LogoutHandler}. {@link SecurityContextLogoutHandler} and
* {@link LogoutSuccessEventPublishingLogoutHandler} are added as last
* {@link LogoutHandler} instances by default.
* @param logoutHandler the {@link LogoutHandler} to add
* @return the {@link LogoutConfigurer} for further customization
*/
@@ -101,8 +107,10 @@ public final class LogoutConfigurer<H extends HttpSecurityBuilder<H>> extends
}
/**
* Specifies if {@link SecurityContextLogoutHandler} should clear the {@link Authentication} at the time of logout.
* @param clearAuthentication true {@link SecurityContextLogoutHandler} should clear the {@link Authentication} (default), or false otherwise.
* Specifies if {@link SecurityContextLogoutHandler} should clear the
* {@link Authentication} at the time of logout.
* @param clearAuthentication true {@link SecurityContextLogoutHandler} should clear
* the {@link Authentication} (default), or false otherwise.
* @return the {@link LogoutConfigurer} for further customization
*/
public LogoutConfigurer<H> clearAuthentication(boolean clearAuthentication) {
@@ -110,7 +118,6 @@ public final class LogoutConfigurer<H extends HttpSecurityBuilder<H>> extends
return this;
}
/**
* Configures {@link SecurityContextLogoutHandler} to invalidate the
* {@link HttpSession} at the time of logout.
@@ -131,15 +138,14 @@ public final class LogoutConfigurer<H extends HttpSecurityBuilder<H>> extends
*
* <p>
* It is considered best practice to use an HTTP POST on any action that changes state
* (i.e. log out) to protect against <a
* href="https://en.wikipedia.org/wiki/Cross-site_request_forgery">CSRF attacks</a>. If
* you really want to use an HTTP GET, you can use
* (i.e. log out) to protect against
* <a href="https://en.wikipedia.org/wiki/Cross-site_request_forgery">CSRF
* attacks</a>. If you really want to use an HTTP GET, you can use
* <code>logoutRequestMatcher(new AntPathRequestMatcher(logoutUrl, "GET"));</code>
* </p>
*
* @see #logoutRequestMatcher(RequestMatcher)
* @see HttpSecurity#csrf()
*
* @param logoutUrl the URL that will invoke logout.
* @return the {@link LogoutConfigurer} for further customization
*/
@@ -154,7 +160,6 @@ public final class LogoutConfigurer<H extends HttpSecurityBuilder<H>> extends
* use {@link #logoutUrl(String)} which helps enforce good practices.
*
* @see #logoutUrl(String)
*
* @param logoutRequestMatcher the RequestMatcher used to determine if logout should
* occur.
* @return the {@link LogoutConfigurer} for further customization
@@ -168,7 +173,6 @@ public final class LogoutConfigurer<H extends HttpSecurityBuilder<H>> extends
* The URL to redirect to after logout has occurred. The default is "/login?logout".
* This is a shortcut for invoking {@link #logoutSuccessHandler(LogoutSuccessHandler)}
* with a {@link SimpleUrlLogoutSuccessHandler}.
*
* @param logoutSuccessUrl the URL to redirect to after logout occurred
* @return the {@link LogoutConfigurer} for further customization
*/
@@ -190,7 +194,6 @@ public final class LogoutConfigurer<H extends HttpSecurityBuilder<H>> extends
* Allows specifying the names of cookies to be removed on logout success. This is a
* shortcut to easily invoke {@link #addLogoutHandler(LogoutHandler)} with a
* {@link CookieClearingLogoutHandler}.
*
* @param cookieNamesToClear the names of cookies to be removed on logout success.
* @return the {@link LogoutConfigurer} for further customization
*/
@@ -201,13 +204,11 @@ public final class LogoutConfigurer<H extends HttpSecurityBuilder<H>> extends
/**
* Sets the {@link LogoutSuccessHandler} to use. If this is specified,
* {@link #logoutSuccessUrl(String)} is ignored.
*
* @param logoutSuccessHandler the {@link LogoutSuccessHandler} to use after a user
* has been logged out.
* @return the {@link LogoutConfigurer} for further customizations
*/
public LogoutConfigurer<H> logoutSuccessHandler(
LogoutSuccessHandler logoutSuccessHandler) {
public LogoutConfigurer<H> logoutSuccessHandler(LogoutSuccessHandler logoutSuccessHandler) {
this.logoutSuccessUrl = null;
this.customLogoutSuccess = true;
this.logoutSuccessHandler = logoutSuccessHandler;
@@ -217,18 +218,17 @@ public final class LogoutConfigurer<H extends HttpSecurityBuilder<H>> extends
/**
* Sets a default {@link LogoutSuccessHandler} to be used which prefers being invoked
* for the provided {@link RequestMatcher}. If no {@link LogoutSuccessHandler} is
* specified a {@link SimpleUrlLogoutSuccessHandler} will be used.
* If any default {@link LogoutSuccessHandler} instances are configured, then a
* specified a {@link SimpleUrlLogoutSuccessHandler} will be used. If any default
* {@link LogoutSuccessHandler} instances are configured, then a
* {@link DelegatingLogoutSuccessHandler} will be used that defaults to a
* {@link SimpleUrlLogoutSuccessHandler}.
*
* @param handler the {@link LogoutSuccessHandler} to use
* @param preferredMatcher the {@link RequestMatcher} for this default
* {@link LogoutSuccessHandler}
* @return the {@link LogoutConfigurer} for further customizations
*/
public LogoutConfigurer<H> defaultLogoutSuccessHandlerFor(
LogoutSuccessHandler handler, RequestMatcher preferredMatcher) {
public LogoutConfigurer<H> defaultLogoutSuccessHandlerFor(LogoutSuccessHandler handler,
RequestMatcher preferredMatcher) {
Assert.notNull(handler, "handler cannot be null");
Assert.notNull(preferredMatcher, "preferredMatcher cannot be null");
this.defaultLogoutSuccessHandlerMappings.put(preferredMatcher, handler);
@@ -238,7 +238,6 @@ public final class LogoutConfigurer<H extends HttpSecurityBuilder<H>> extends
/**
* Grants access to the {@link #logoutSuccessUrl(String)} and the
* {@link #logoutUrl(String)} for every user.
*
* @param permitAll if true grants access, else nothing is done
* @return the {@link LogoutConfigurer} for further customization.
*/
@@ -250,7 +249,6 @@ public final class LogoutConfigurer<H extends HttpSecurityBuilder<H>> extends
/**
* Gets the {@link LogoutSuccessHandler} if not null, otherwise creates a new
* {@link SimpleUrlLogoutSuccessHandler} using the {@link #logoutSuccessUrl(String)}.
*
* @return the {@link LogoutSuccessHandler} to use
*/
private LogoutSuccessHandler getLogoutSuccessHandler() {
@@ -267,7 +265,8 @@ public final class LogoutConfigurer<H extends HttpSecurityBuilder<H>> extends
if (defaultLogoutSuccessHandlerMappings.isEmpty()) {
return urlLogoutHandler;
}
DelegatingLogoutSuccessHandler successHandler = new DelegatingLogoutSuccessHandler(defaultLogoutSuccessHandlerMappings);
DelegatingLogoutSuccessHandler successHandler = new DelegatingLogoutSuccessHandler(
defaultLogoutSuccessHandlerMappings);
successHandler.setDefaultLogoutSuccessHandler(urlLogoutHandler);
return successHandler;
}
@@ -296,7 +295,6 @@ public final class LogoutConfigurer<H extends HttpSecurityBuilder<H>> extends
* Returns true if the logout success has been customized via
* {@link #logoutSuccessUrl(String)} or
* {@link #logoutSuccessHandler(LogoutSuccessHandler)}.
*
* @return true if logout success handling has been customized, else false
*/
boolean isCustomLogoutSuccess() {
@@ -306,7 +304,6 @@ public final class LogoutConfigurer<H extends HttpSecurityBuilder<H>> extends
/**
* Gets the logoutSuccesUrl or null if a
* {@link #logoutSuccessHandler(LogoutSuccessHandler)} was configured.
*
* @return the logoutSuccessUrl
*/
private String getLogoutSuccessUrl() {
@@ -325,15 +322,13 @@ public final class LogoutConfigurer<H extends HttpSecurityBuilder<H>> extends
* Creates the {@link LogoutFilter} using the {@link LogoutHandler} instances, the
* {@link #logoutSuccessHandler(LogoutSuccessHandler)} and the
* {@link #logoutUrl(String)}.
*
* @param http the builder to use
* @return the {@link LogoutFilter} to use.
*/
private LogoutFilter createLogoutFilter(H http) {
logoutHandlers.add(contextLogoutHandler);
logoutHandlers.add(postProcess(new LogoutSuccessEventPublishingLogoutHandler()));
LogoutHandler[] handlers = logoutHandlers
.toArray(new LogoutHandler[0]);
LogoutHandler[] handlers = logoutHandlers.toArray(new LogoutHandler[0]);
LogoutFilter result = new LogoutFilter(getLogoutSuccessHandler(), handlers);
result.setLogoutRequestMatcher(getLogoutRequestMatcher(http));
result = postProcess(result);
@@ -349,13 +344,11 @@ public final class LogoutConfigurer<H extends HttpSecurityBuilder<H>> extends
this.logoutRequestMatcher = new AntPathRequestMatcher(this.logoutUrl, "POST");
}
else {
this.logoutRequestMatcher = new OrRequestMatcher(
new AntPathRequestMatcher(this.logoutUrl, "GET"),
new AntPathRequestMatcher(this.logoutUrl, "POST"),
new AntPathRequestMatcher(this.logoutUrl, "PUT"),
new AntPathRequestMatcher(this.logoutUrl, "DELETE")
);
this.logoutRequestMatcher = new OrRequestMatcher(new AntPathRequestMatcher(this.logoutUrl, "GET"),
new AntPathRequestMatcher(this.logoutUrl, "POST"), new AntPathRequestMatcher(this.logoutUrl, "PUT"),
new AntPathRequestMatcher(this.logoutUrl, "DELETE"));
}
return this.logoutRequestMatcher;
}
}
@@ -24,13 +24,13 @@ import org.springframework.security.web.util.matcher.RequestMatcher;
/**
* Configures non-null URL's to grant access to every URL
*
* @author Rob Winch
* @since 3.2
*/
final class PermitAllSupport {
public static void permitAll(
HttpSecurityBuilder<? extends HttpSecurityBuilder<?>> http, String... urls) {
public static void permitAll(HttpSecurityBuilder<? extends HttpSecurityBuilder<?>> http, String... urls) {
for (String url : urls) {
if (url != null) {
permitAll(http, new ExactUrlRequestMatcher(url));
@@ -39,32 +39,25 @@ final class PermitAllSupport {
}
@SuppressWarnings("unchecked")
public static void permitAll(
HttpSecurityBuilder<? extends HttpSecurityBuilder<?>> http,
public static void permitAll(HttpSecurityBuilder<? extends HttpSecurityBuilder<?>> http,
RequestMatcher... requestMatchers) {
ExpressionUrlAuthorizationConfigurer<?> configurer = http
.getConfigurer(ExpressionUrlAuthorizationConfigurer.class);
if (configurer == null) {
throw new IllegalStateException(
"permitAll only works with HttpSecurity.authorizeRequests()");
throw new IllegalStateException("permitAll only works with HttpSecurity.authorizeRequests()");
}
for (RequestMatcher matcher : requestMatchers) {
if (matcher != null) {
configurer
.getRegistry()
.addMapping(
0,
new UrlMapping(
matcher,
SecurityConfig
.createList(ExpressionUrlAuthorizationConfigurer.permitAll)));
configurer.getRegistry().addMapping(0, new UrlMapping(matcher,
SecurityConfig.createList(ExpressionUrlAuthorizationConfigurer.permitAll)));
}
}
}
private final static class ExactUrlRequestMatcher implements RequestMatcher {
private String processUrl;
private ExactUrlRequestMatcher(String processUrl) {
@@ -92,8 +85,10 @@ final class PermitAllSupport {
sb.append("ExactUrl [processUrl='").append(processUrl).append("']");
return sb.toString();
}
}
private PermitAllSupport() {
}
}
@@ -31,9 +31,11 @@ import org.springframework.security.web.PortMapperImpl;
* @author Rob Winch
* @since 3.2
*/
public final class PortMapperConfigurer<H extends HttpSecurityBuilder<H>> extends
AbstractHttpConfigurer<PortMapperConfigurer<H>, H> {
public final class PortMapperConfigurer<H extends HttpSecurityBuilder<H>>
extends AbstractHttpConfigurer<PortMapperConfigurer<H>, H> {
private PortMapper portMapper;
private Map<String, String> httpsPortMappings = new HashMap<>();
/**
@@ -70,7 +72,6 @@ public final class PortMapperConfigurer<H extends HttpSecurityBuilder<H>> extend
* Gets the {@link PortMapper} to use. If {@link #portMapper(PortMapper)} was not
* invoked, builds a {@link PortMapperImpl} using the port mappings specified with
* {@link #http(int)}.
*
* @return the {@link PortMapper} to use
*/
private PortMapper getPortMapper() {
@@ -90,6 +91,7 @@ public final class PortMapperConfigurer<H extends HttpSecurityBuilder<H>> extend
* @since 3.2
*/
public final class HttpPortMapping {
private final int httpPort;
/**
@@ -110,5 +112,7 @@ public final class PortMapperConfigurer<H extends HttpSecurityBuilder<H>> extend
httpsPortMappings.put(String.valueOf(httpPort), String.valueOf(httpsPort));
return PortMapperConfigurer.this;
}
}
}
@@ -79,21 +79,34 @@ import org.springframework.security.web.authentication.ui.DefaultLoginPageGenera
*/
public final class RememberMeConfigurer<H extends HttpSecurityBuilder<H>>
extends AbstractHttpConfigurer<RememberMeConfigurer<H>, H> {
/**
* The default name for remember me parameter name and remember me cookie name
*/
private static final String DEFAULT_REMEMBER_ME_NAME = "remember-me";
private AuthenticationSuccessHandler authenticationSuccessHandler;
private String key;
private RememberMeServices rememberMeServices;
private LogoutHandler logoutHandler;
private String rememberMeParameter = DEFAULT_REMEMBER_ME_NAME;
private String rememberMeCookieName = DEFAULT_REMEMBER_ME_NAME;
private String rememberMeCookieDomain;
private PersistentTokenRepository tokenRepository;
private UserDetailsService userDetailsService;
private Integer tokenValiditySeconds;
private Boolean useSecureCookie;
private Boolean alwaysRemember;
/**
@@ -104,7 +117,6 @@ public final class RememberMeConfigurer<H extends HttpSecurityBuilder<H>>
/**
* Allows specifying how long (in seconds) a token is valid for
*
* @param tokenValiditySeconds
* @return {@link RememberMeConfigurer} for further customization
* @see AbstractRememberMeServices#setTokenValiditySeconds(int)
@@ -122,7 +134,6 @@ public final class RememberMeConfigurer<H extends HttpSecurityBuilder<H>>
* By default the cookie will be secure if the request is secure. If you only want to
* use remember-me over HTTPS (recommended) you should set this property to
* {@code true}.
*
* @param useSecureCookie set to {@code true} to always user secure cookies,
* {@code false} to disable their use.
* @return the {@link RememberMeConfigurer} for further customization
@@ -140,13 +151,11 @@ public final class RememberMeConfigurer<H extends HttpSecurityBuilder<H>>
* {@link HttpSecurity#getSharedObject(Class)} which is set when using
* {@link WebSecurityConfigurerAdapter#configure(AuthenticationManagerBuilder)}.
* Alternatively, one can populate {@link #rememberMeServices(RememberMeServices)}.
*
* @param userDetailsService the {@link UserDetailsService} to configure
* @return the {@link RememberMeConfigurer} for further customization
* @see AbstractRememberMeServices
*/
public RememberMeConfigurer<H> userDetailsService(
UserDetailsService userDetailsService) {
public RememberMeConfigurer<H> userDetailsService(UserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
return this;
}
@@ -154,23 +163,19 @@ public final class RememberMeConfigurer<H extends HttpSecurityBuilder<H>>
/**
* Specifies the {@link PersistentTokenRepository} to use. The default is to use
* {@link TokenBasedRememberMeServices} instead.
*
* @param tokenRepository the {@link PersistentTokenRepository} to use
* @return the {@link RememberMeConfigurer} for further customization
*/
public RememberMeConfigurer<H> tokenRepository(
PersistentTokenRepository tokenRepository) {
public RememberMeConfigurer<H> tokenRepository(PersistentTokenRepository tokenRepository) {
this.tokenRepository = tokenRepository;
return this;
}
/**
* Sets the key to identify tokens created for remember me authentication. Default is
* a secure randomly generated key.
* If {@link #rememberMeServices(RememberMeServices)} is specified and is of type
* {@link AbstractRememberMeServices}, then the default is the key set in
* {@link AbstractRememberMeServices}.
*
* a secure randomly generated key. If {@link #rememberMeServices(RememberMeServices)}
* is specified and is of type {@link AbstractRememberMeServices}, then the default is
* the key set in {@link AbstractRememberMeServices}.
* @param key the key to identify tokens created for remember me authentication
* @return the {@link RememberMeConfigurer} for further customization
*/
@@ -181,7 +186,6 @@ public final class RememberMeConfigurer<H extends HttpSecurityBuilder<H>>
/**
* The HTTP parameter used to indicate to remember the user at time of login.
*
* @param rememberMeParameter the HTTP parameter used to indicate to remember the user
* @return the {@link RememberMeConfigurer} for further customization
*/
@@ -193,7 +197,6 @@ public final class RememberMeConfigurer<H extends HttpSecurityBuilder<H>>
/**
* The name of cookie which store the token for remember me authentication. Defaults
* to 'remember-me'.
*
* @param rememberMeCookieName the name of cookie which store the token for remember
* me authentication
* @return the {@link RememberMeConfigurer} for further customization
@@ -206,7 +209,6 @@ public final class RememberMeConfigurer<H extends HttpSecurityBuilder<H>>
/**
* The domain name within which the remember me cookie is visible.
*
* @param rememberMeCookieDomain the domain name within which the remember me cookie
* is visible.
* @return the {@link RememberMeConfigurer} for further customization
@@ -224,7 +226,6 @@ public final class RememberMeConfigurer<H extends HttpSecurityBuilder<H>>
* be invoked and the {@code doFilter()} method will return immediately, thus allowing
* the application to redirect the user to a specific URL, regardless of what the
* original request was for.
*
* @param authenticationSuccessHandler the strategy to invoke immediately before
* returning from {@code doFilter()}.
* @return {@link RememberMeConfigurer} for further customization
@@ -242,8 +243,7 @@ public final class RememberMeConfigurer<H extends HttpSecurityBuilder<H>>
* @return the {@link RememberMeConfigurer} for further customizations
* @see RememberMeServices
*/
public RememberMeConfigurer<H> rememberMeServices(
RememberMeServices rememberMeServices) {
public RememberMeConfigurer<H> rememberMeServices(RememberMeServices rememberMeServices) {
this.rememberMeServices = rememberMeServices;
return this;
}
@@ -253,7 +253,6 @@ public final class RememberMeConfigurer<H extends HttpSecurityBuilder<H>>
* not set.
* <p>
* By default this will be set to {@code false}.
*
* @param alwaysRemember set to {@code true} to always trigger remember me,
* {@code false} to use the remember-me parameter.
* @return the {@link RememberMeConfigurer} for further customization
@@ -276,8 +275,7 @@ public final class RememberMeConfigurer<H extends HttpSecurityBuilder<H>>
logoutConfigurer.addLogoutHandler(this.logoutHandler);
}
RememberMeAuthenticationProvider authenticationProvider = new RememberMeAuthenticationProvider(
key);
RememberMeAuthenticationProvider authenticationProvider = new RememberMeAuthenticationProvider(key);
authenticationProvider = postProcess(authenticationProvider);
http.authenticationProvider(authenticationProvider);
@@ -287,24 +285,21 @@ public final class RememberMeConfigurer<H extends HttpSecurityBuilder<H>>
@Override
public void configure(H http) {
RememberMeAuthenticationFilter rememberMeFilter = new RememberMeAuthenticationFilter(
http.getSharedObject(AuthenticationManager.class),
this.rememberMeServices);
http.getSharedObject(AuthenticationManager.class), this.rememberMeServices);
if (this.authenticationSuccessHandler != null) {
rememberMeFilter
.setAuthenticationSuccessHandler(this.authenticationSuccessHandler);
rememberMeFilter.setAuthenticationSuccessHandler(this.authenticationSuccessHandler);
}
rememberMeFilter = postProcess(rememberMeFilter);
http.addFilter(rememberMeFilter);
}
/**
* Validate rememberMeServices and rememberMeCookieName have not been set at
* the same time.
* Validate rememberMeServices and rememberMeCookieName have not been set at the same
* time.
*/
private void validateInput() {
if (this.rememberMeServices != null && this.rememberMeCookieName != DEFAULT_REMEMBER_ME_NAME) {
throw new IllegalArgumentException("Can not set rememberMeCookieName " +
"and custom rememberMeServices.");
throw new IllegalArgumentException("Can not set rememberMeCookieName " + "and custom rememberMeServices.");
}
}
@@ -319,7 +314,6 @@ public final class RememberMeConfigurer<H extends HttpSecurityBuilder<H>>
/**
* If available, initializes the {@link DefaultLoginPageGeneratingFilter} shared
* object.
*
* @param http the {@link HttpSecurityBuilder} to use
*/
private void initDefaultLoginFilter(H http) {
@@ -337,17 +331,14 @@ public final class RememberMeConfigurer<H extends HttpSecurityBuilder<H>>
* @return the {@link RememberMeServices} to use
* @throws Exception
*/
private RememberMeServices getRememberMeServices(H http, String key)
throws Exception {
private RememberMeServices getRememberMeServices(H http, String key) throws Exception {
if (this.rememberMeServices != null) {
if (this.rememberMeServices instanceof LogoutHandler
&& this.logoutHandler == null) {
if (this.rememberMeServices instanceof LogoutHandler && this.logoutHandler == null) {
this.logoutHandler = (LogoutHandler) this.rememberMeServices;
}
return this.rememberMeServices;
}
AbstractRememberMeServices tokenRememberMeServices = createRememberMeServices(
http, key);
AbstractRememberMeServices tokenRememberMeServices = createRememberMeServices(http, key);
tokenRememberMeServices.setParameter(this.rememberMeParameter);
tokenRememberMeServices.setCookieName(this.rememberMeCookieName);
if (this.rememberMeCookieDomain != null) {
@@ -372,49 +363,41 @@ public final class RememberMeConfigurer<H extends HttpSecurityBuilder<H>>
* Creates the {@link RememberMeServices} to use when none is provided. The result is
* either {@link PersistentTokenRepository} (if a {@link PersistentTokenRepository} is
* specified, else {@link TokenBasedRememberMeServices}.
*
* @param http the {@link HttpSecurity} to lookup shared objects
* @param key the {@link #key(String)}
* @return the {@link RememberMeServices} to use
*/
private AbstractRememberMeServices createRememberMeServices(H http, String key) {
return this.tokenRepository == null
? createTokenBasedRememberMeServices(http, key)
return this.tokenRepository == null ? createTokenBasedRememberMeServices(http, key)
: createPersistentRememberMeServices(http, key);
}
/**
* Creates {@link TokenBasedRememberMeServices}
*
* @param http the {@link HttpSecurity} to lookup shared objects
* @param key the {@link #key(String)}
* @return the {@link TokenBasedRememberMeServices}
*/
private AbstractRememberMeServices createTokenBasedRememberMeServices(H http,
String key) {
private AbstractRememberMeServices createTokenBasedRememberMeServices(H http, String key) {
UserDetailsService userDetailsService = getUserDetailsService(http);
return new TokenBasedRememberMeServices(key, userDetailsService);
}
/**
* Creates {@link PersistentTokenBasedRememberMeServices}
*
* @param http the {@link HttpSecurity} to lookup shared objects
* @param key the {@link #key(String)}
* @return the {@link PersistentTokenBasedRememberMeServices}
*/
private AbstractRememberMeServices createPersistentRememberMeServices(H http,
String key) {
private AbstractRememberMeServices createPersistentRememberMeServices(H http, String key) {
UserDetailsService userDetailsService = getUserDetailsService(http);
return new PersistentTokenBasedRememberMeServices(key, userDetailsService,
this.tokenRepository);
return new PersistentTokenBasedRememberMeServices(key, userDetailsService, this.tokenRepository);
}
/**
* Gets the {@link UserDetailsService} to use. Either the explicitly configure
* {@link UserDetailsService} from {@link #userDetailsService(UserDetailsService)} or
* a shared object from {@link HttpSecurity#getSharedObject(Class)}.
*
* @param http {@link HttpSecurity} to get the shared {@link UserDetailsService}
* @return the {@link UserDetailsService} to use
*/
@@ -423,31 +406,31 @@ public final class RememberMeConfigurer<H extends HttpSecurityBuilder<H>>
this.userDetailsService = http.getSharedObject(UserDetailsService.class);
}
if (this.userDetailsService == null) {
throw new IllegalStateException("userDetailsService cannot be null. Invoke "
+ RememberMeConfigurer.class.getSimpleName()
+ "#userDetailsService(UserDetailsService) or see its javadoc for alternative approaches.");
throw new IllegalStateException(
"userDetailsService cannot be null. Invoke " + RememberMeConfigurer.class.getSimpleName()
+ "#userDetailsService(UserDetailsService) or see its javadoc for alternative approaches.");
}
return this.userDetailsService;
}
/**
* Gets the key to use for validating remember me tokens. If a value was passed into
* {@link #key(String)}, then that is returned.
* Alternatively, if a key was specified in the
* {@link #rememberMeServices(RememberMeServices)}}, then that is returned.
* If no key was specified in either of those cases, then a secure random string is
* {@link #key(String)}, then that is returned. Alternatively, if a key was specified
* in the {@link #rememberMeServices(RememberMeServices)}}, then that is returned. If
* no key was specified in either of those cases, then a secure random string is
* generated.
*
* @return the remember me key to use
*/
private String getKey() {
if (this.key == null) {
if (this.rememberMeServices instanceof AbstractRememberMeServices) {
this.key = ((AbstractRememberMeServices) rememberMeServices).getKey();
} else {
}
else {
this.key = UUID.randomUUID().toString();
}
}
return this.key;
}
}
@@ -69,8 +69,8 @@ import org.springframework.web.accept.HeaderContentNegotiationStrategy;
* @since 3.2
* @see RequestCache
*/
public final class RequestCacheConfigurer<H extends HttpSecurityBuilder<H>> extends
AbstractHttpConfigurer<RequestCacheConfigurer<H>, H> {
public final class RequestCacheConfigurer<H extends HttpSecurityBuilder<H>>
extends AbstractHttpConfigurer<RequestCacheConfigurer<H>, H> {
public RequestCacheConfigurer() {
}
@@ -79,7 +79,6 @@ public final class RequestCacheConfigurer<H extends HttpSecurityBuilder<H>> exte
* Allows explicit configuration of the {@link RequestCache} to be used. Defaults to
* try finding a {@link RequestCache} as a shared object. Then falls back to a
* {@link HttpSessionRequestCache}.
*
* @param requestCache the explicit {@link RequestCache} to use
* @return the {@link RequestCacheConfigurer} for further customization
*/
@@ -102,8 +101,7 @@ public final class RequestCacheConfigurer<H extends HttpSecurityBuilder<H>> exte
@Override
public void configure(H http) {
RequestCache requestCache = getRequestCache(http);
RequestCacheAwareFilter requestCacheFilter = new RequestCacheAwareFilter(
requestCache);
RequestCacheAwareFilter requestCacheFilter = new RequestCacheAwareFilter(requestCache);
requestCacheFilter = postProcess(requestCacheFilter);
http.addFilter(requestCacheFilter);
}
@@ -113,7 +111,6 @@ public final class RequestCacheConfigurer<H extends HttpSecurityBuilder<H>> exte
* {@link #requestCache(org.springframework.security.web.savedrequest.RequestCache)},
* then it is used. Otherwise, an attempt to find a {@link RequestCache} shared object
* is made. If that fails, an {@link HttpSessionRequestCache} is used
*
* @param http the {@link HttpSecurity} to attempt to fined the shared object
* @return the {@link RequestCache} to use
*/
@@ -138,15 +135,15 @@ public final class RequestCacheConfigurer<H extends HttpSecurityBuilder<H>> exte
}
try {
return context.getBean(type);
} catch (NoSuchBeanDefinitionException e) {
}
catch (NoSuchBeanDefinitionException e) {
return null;
}
}
@SuppressWarnings("unchecked")
private RequestMatcher createDefaultSavedRequestMatcher(H http) {
RequestMatcher notFavIcon = new NegatedRequestMatcher(new AntPathRequestMatcher(
"/**/favicon.*"));
RequestMatcher notFavIcon = new NegatedRequestMatcher(new AntPathRequestMatcher("/**/favicon.*"));
RequestMatcher notXRequestedWith = new NegatedRequestMatcher(
new RequestHeaderRequestMatcher("X-Requested-With", "XMLHttpRequest"));
@@ -177,4 +174,5 @@ public final class RequestCacheConfigurer<H extends HttpSecurityBuilder<H>> exte
mediaRequest.setIgnoredMediaTypes(Collections.singleton(MediaType.ALL));
return new NegatedRequestMatcher(mediaRequest);
}
}
@@ -58,8 +58,8 @@ import org.springframework.security.web.context.SecurityContextRepository;
* @author Rob Winch
* @since 3.2
*/
public final class SecurityContextConfigurer<H extends HttpSecurityBuilder<H>> extends
AbstractHttpConfigurer<SecurityContextConfigurer<H>, H> {
public final class SecurityContextConfigurer<H extends HttpSecurityBuilder<H>>
extends AbstractHttpConfigurer<SecurityContextConfigurer<H>, H> {
/**
* Creates a new instance
@@ -73,10 +73,8 @@ public final class SecurityContextConfigurer<H extends HttpSecurityBuilder<H>> e
* @param securityContextRepository the {@link SecurityContextRepository} to use
* @return the {@link HttpSecurity} for further customizations
*/
public SecurityContextConfigurer<H> securityContextRepository(
SecurityContextRepository securityContextRepository) {
getBuilder().setSharedObject(SecurityContextRepository.class,
securityContextRepository);
public SecurityContextConfigurer<H> securityContextRepository(SecurityContextRepository securityContextRepository) {
getBuilder().setSharedObject(SecurityContextRepository.class, securityContextRepository);
return this;
}
@@ -84,15 +82,13 @@ public final class SecurityContextConfigurer<H extends HttpSecurityBuilder<H>> e
@SuppressWarnings("unchecked")
public void configure(H http) {
SecurityContextRepository securityContextRepository = http
.getSharedObject(SecurityContextRepository.class);
SecurityContextRepository securityContextRepository = http.getSharedObject(SecurityContextRepository.class);
if (securityContextRepository == null) {
securityContextRepository = new HttpSessionSecurityContextRepository();
}
SecurityContextPersistenceFilter securityContextFilter = new SecurityContextPersistenceFilter(
securityContextRepository);
SessionManagementConfigurer<?> sessionManagement = http
.getConfigurer(SessionManagementConfigurer.class);
SessionManagementConfigurer<?> sessionManagement = http.getConfigurer(SessionManagementConfigurer.class);
SessionCreationPolicy sessionCreationPolicy = sessionManagement == null ? null
: sessionManagement.getSessionCreationPolicy();
if (SessionCreationPolicy.ALWAYS == sessionCreationPolicy) {
@@ -101,4 +97,5 @@ public final class SecurityContextConfigurer<H extends HttpSecurityBuilder<H>> e
securityContextFilter = postProcess(securityContextFilter);
http.addFilter(securityContextFilter);
}
}
@@ -57,8 +57,9 @@ import org.springframework.security.web.servletapi.SecurityContextHolderAwareReq
* @author Rob Winch
* @since 3.2
*/
public final class ServletApiConfigurer<H extends HttpSecurityBuilder<H>> extends
AbstractHttpConfigurer<ServletApiConfigurer<H>, H> {
public final class ServletApiConfigurer<H extends HttpSecurityBuilder<H>>
extends AbstractHttpConfigurer<ServletApiConfigurer<H>, H> {
private SecurityContextHolderAwareRequestFilter securityContextRequestFilter = new SecurityContextHolderAwareRequestFilter();
/**
@@ -76,20 +77,15 @@ public final class ServletApiConfigurer<H extends HttpSecurityBuilder<H>> extend
@Override
@SuppressWarnings("unchecked")
public void configure(H http) {
securityContextRequestFilter.setAuthenticationManager(http
.getSharedObject(AuthenticationManager.class));
ExceptionHandlingConfigurer<H> exceptionConf = http
.getConfigurer(ExceptionHandlingConfigurer.class);
securityContextRequestFilter.setAuthenticationManager(http.getSharedObject(AuthenticationManager.class));
ExceptionHandlingConfigurer<H> exceptionConf = http.getConfigurer(ExceptionHandlingConfigurer.class);
AuthenticationEntryPoint authenticationEntryPoint = exceptionConf == null ? null
: exceptionConf.getAuthenticationEntryPoint(http);
securityContextRequestFilter
.setAuthenticationEntryPoint(authenticationEntryPoint);
securityContextRequestFilter.setAuthenticationEntryPoint(authenticationEntryPoint);
LogoutConfigurer<H> logoutConf = http.getConfigurer(LogoutConfigurer.class);
List<LogoutHandler> logoutHandlers = logoutConf == null ? null : logoutConf
.getLogoutHandlers();
List<LogoutHandler> logoutHandlers = logoutConf == null ? null : logoutConf.getLogoutHandlers();
securityContextRequestFilter.setLogoutHandlers(logoutHandlers);
AuthenticationTrustResolver trustResolver = http
.getSharedObject(AuthenticationTrustResolver.class);
AuthenticationTrustResolver trustResolver = http.getSharedObject(AuthenticationTrustResolver.class);
if (trustResolver != null) {
securityContextRequestFilter.setTrustResolver(trustResolver);
}
@@ -97,11 +93,13 @@ public final class ServletApiConfigurer<H extends HttpSecurityBuilder<H>> extend
if (context != null) {
String[] grantedAuthorityDefaultsBeanNames = context.getBeanNamesForType(GrantedAuthorityDefaults.class);
if (grantedAuthorityDefaultsBeanNames.length == 1) {
GrantedAuthorityDefaults grantedAuthorityDefaults = context.getBean(grantedAuthorityDefaultsBeanNames[0], GrantedAuthorityDefaults.class);
GrantedAuthorityDefaults grantedAuthorityDefaults = context
.getBean(grantedAuthorityDefaultsBeanNames[0], GrantedAuthorityDefaults.class);
securityContextRequestFilter.setRolePrefix(grantedAuthorityDefaults.getRolePrefix());
}
}
securityContextRequestFilter = postProcess(securityContextRequestFilter);
http.addFilter(securityContextRequestFilter);
}
}
@@ -98,21 +98,37 @@ import org.springframework.util.CollectionUtils;
*/
public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
extends AbstractHttpConfigurer<SessionManagementConfigurer<H>, H> {
private final SessionAuthenticationStrategy DEFAULT_SESSION_FIXATION_STRATEGY = createDefaultSessionFixationProtectionStrategy();
private SessionAuthenticationStrategy sessionFixationAuthenticationStrategy = this.DEFAULT_SESSION_FIXATION_STRATEGY;
private SessionAuthenticationStrategy sessionAuthenticationStrategy;
private SessionAuthenticationStrategy providedSessionAuthenticationStrategy;
private InvalidSessionStrategy invalidSessionStrategy;
private SessionInformationExpiredStrategy expiredSessionStrategy;
private List<SessionAuthenticationStrategy> sessionAuthenticationStrategies = new ArrayList<>();
private SessionRegistry sessionRegistry;
private Integer maximumSessions;
private String expiredUrl;
private boolean maxSessionsPreventsLogin;
private SessionCreationPolicy sessionPolicy;
private boolean enableSessionUrlRewriting;
private String invalidSessionUrl;
private String sessionAuthenticationErrorUrl;
private AuthenticationFailureHandler sessionAuthenticationFailureHandler;
/**
@@ -127,7 +143,6 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
* {@link SimpleRedirectInvalidSessionStrategy} configured with the attribute value.
* When an invalid session ID is submitted, the strategy will be invoked, redirecting
* to the configured URL.
*
* @param invalidSessionUrl the URL to redirect to when an invalid session is detected
* @return the {@link SessionManagementConfigurer} for further customization
*/
@@ -144,8 +159,7 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
* submitted.
* @return the {@link SessionManagementConfigurer} for further customization
*/
public SessionManagementConfigurer<H> invalidSessionStrategy(
InvalidSessionStrategy invalidSessionStrategy) {
public SessionManagementConfigurer<H> invalidSessionStrategy(InvalidSessionStrategy invalidSessionStrategy) {
Assert.notNull(invalidSessionStrategy, "invalidSessionStrategy");
this.invalidSessionStrategy = invalidSessionStrategy;
return this;
@@ -157,12 +171,10 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
* (402) error code will be returned to the client. Note that this attribute doesn't
* apply if the error occurs during a form-based login, where the URL for
* authentication failure will take precedence.
*
* @param sessionAuthenticationErrorUrl the URL to redirect to
* @return the {@link SessionManagementConfigurer} for further customization
*/
public SessionManagementConfigurer<H> sessionAuthenticationErrorUrl(
String sessionAuthenticationErrorUrl) {
public SessionManagementConfigurer<H> sessionAuthenticationErrorUrl(String sessionAuthenticationErrorUrl) {
this.sessionAuthenticationErrorUrl = sessionAuthenticationErrorUrl;
return this;
}
@@ -173,7 +185,6 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
* (402) error code will be returned to the client. Note that this attribute doesn't
* apply if the error occurs during a form-based login, where the URL for
* authentication failure will take precedence.
*
* @param sessionAuthenticationFailureHandler the handler to use
* @return the {@link SessionManagementConfigurer} for further customization
*/
@@ -188,14 +199,12 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
* {@link HttpServletResponse#encodeRedirectURL(String)} or
* {@link HttpServletResponse#encodeURL(String)}, otherwise disallows HTTP sessions to
* be included in the URL. This prevents leaking information to external domains.
*
* @param enableSessionUrlRewriting true if should allow the JSESSIONID to be
* rewritten into the URLs, else false (default)
* @return the {@link SessionManagementConfigurer} for further customization
* @see HttpSessionSecurityContextRepository#setDisableUrlRewriting(boolean)
*/
public SessionManagementConfigurer<H> enableSessionUrlRewriting(
boolean enableSessionUrlRewriting) {
public SessionManagementConfigurer<H> enableSessionUrlRewriting(boolean enableSessionUrlRewriting) {
this.enableSessionUrlRewriting = enableSessionUrlRewriting;
return this;
}
@@ -208,26 +217,24 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
* @see SessionCreationPolicy
* @throws IllegalArgumentException if {@link SessionCreationPolicy} is null.
*/
public SessionManagementConfigurer<H> sessionCreationPolicy(
SessionCreationPolicy sessionCreationPolicy) {
public SessionManagementConfigurer<H> sessionCreationPolicy(SessionCreationPolicy sessionCreationPolicy) {
Assert.notNull(sessionCreationPolicy, "sessionCreationPolicy cannot be null");
this.sessionPolicy = sessionCreationPolicy;
return this;
}
/**
* Allows explicitly specifying the {@link SessionAuthenticationStrategy}.
* The default is to use {@link ChangeSessionIdAuthenticationStrategy}.
* If restricting the maximum number of sessions is configured, then
* Allows explicitly specifying the {@link SessionAuthenticationStrategy}. The default
* is to use {@link ChangeSessionIdAuthenticationStrategy}. If restricting the maximum
* number of sessions is configured, then
* {@link CompositeSessionAuthenticationStrategy} delegating to
* {@link ConcurrentSessionControlAuthenticationStrategy},
* the default OR supplied {@code SessionAuthenticationStrategy} and
* {@link ConcurrentSessionControlAuthenticationStrategy}, the default OR supplied
* {@code SessionAuthenticationStrategy} and
* {@link RegisterSessionAuthenticationStrategy}.
*
* <p>
* NOTE: Supplying a custom {@link SessionAuthenticationStrategy} will override the
* default session fixation strategy.
*
* @param sessionAuthenticationStrategy
* @return the {@link SessionManagementConfigurer} for further customizations
*/
@@ -240,7 +247,6 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
/**
* Adds an additional {@link SessionAuthenticationStrategy} to be used within the
* {@link CompositeSessionAuthenticationStrategy}.
*
* @param sessionAuthenticationStrategy
* @return the {@link SessionManagementConfigurer} for further customizations
*/
@@ -252,7 +258,6 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
/**
* Allows changing the default {@link SessionFixationProtectionStrategy}.
*
* @return the {@link SessionFixationConfigurer} for further customizations
*/
public SessionFixationConfigurer sessionFixation() {
@@ -261,12 +266,12 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
/**
* Allows configuring session fixation protection.
*
* @param sessionFixationCustomizer the {@link Customizer} to provide more options for
* the {@link SessionFixationConfigurer}
* @return the {@link SessionManagementConfigurer} for further customizations
*/
public SessionManagementConfigurer<H> sessionFixation(Customizer<SessionFixationConfigurer> sessionFixationCustomizer) {
public SessionManagementConfigurer<H> sessionFixation(
Customizer<SessionFixationConfigurer> sessionFixationCustomizer) {
sessionFixationCustomizer.customize(new SessionFixationConfigurer());
return this;
}
@@ -285,12 +290,12 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
/**
* Controls the maximum number of sessions for a user. The default is to allow any
* number of users.
*
* @param sessionConcurrencyCustomizer the {@link Customizer} to provide more options for
* the {@link ConcurrencyControlConfigurer}
* @param sessionConcurrencyCustomizer the {@link Customizer} to provide more options
* for the {@link ConcurrencyControlConfigurer}
* @return the {@link SessionManagementConfigurer} for further customizations
*/
public SessionManagementConfigurer<H> sessionConcurrency(Customizer<ConcurrencyControlConfigurer> sessionConcurrencyCustomizer) {
public SessionManagementConfigurer<H> sessionConcurrency(
Customizer<ConcurrencyControlConfigurer> sessionConcurrencyCustomizer) {
sessionConcurrencyCustomizer.customize(new ConcurrencyControlConfigurer());
return this;
}
@@ -302,8 +307,7 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
*/
private void setSessionFixationAuthenticationStrategy(
SessionAuthenticationStrategy sessionFixationAuthenticationStrategy) {
this.sessionFixationAuthenticationStrategy = postProcess(
sessionFixationAuthenticationStrategy);
this.sessionFixationAuthenticationStrategy = postProcess(sessionFixationAuthenticationStrategy);
}
/**
@@ -312,10 +316,10 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
* @author Rob Winch
*/
public final class SessionFixationConfigurer {
/**
* Specifies that a new session should be created, but the session attributes from
* the original {@link HttpSession} should not be retained.
*
* @return the {@link SessionManagementConfigurer} for further customizations
*/
public SessionManagementConfigurer<H> newSession() {
@@ -328,12 +332,10 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
/**
* Specifies that a new session should be created and the session attributes from
* the original {@link HttpSession} should be retained.
*
* @return the {@link SessionManagementConfigurer} for further customizations
*/
public SessionManagementConfigurer<H> migrateSession() {
setSessionFixationAuthenticationStrategy(
new SessionFixationProtectionStrategy());
setSessionFixationAuthenticationStrategy(new SessionFixationProtectionStrategy());
return SessionManagementConfigurer.this;
}
@@ -342,12 +344,10 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
* should be used. When a session authenticates, the Servlet method
* {@code HttpServletRequest#changeSessionId()} is called to change the session ID
* and retain all session attributes.
*
* @return the {@link SessionManagementConfigurer} for further customizations
*/
public SessionManagementConfigurer<H> changeSessionId() {
setSessionFixationAuthenticationStrategy(
new ChangeSessionIdAuthenticationStrategy());
setSessionFixationAuthenticationStrategy(new ChangeSessionIdAuthenticationStrategy());
return SessionManagementConfigurer.this;
}
@@ -356,14 +356,13 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
* useful when utilizing other mechanisms for protecting against session fixation.
* For example, if application container session fixation protection is already in
* use. Otherwise, this option is not recommended.
*
* @return the {@link SessionManagementConfigurer} for further customizations
*/
public SessionManagementConfigurer<H> none() {
setSessionFixationAuthenticationStrategy(
new NullAuthenticatedSessionStrategy());
setSessionFixationAuthenticationStrategy(new NullAuthenticatedSessionStrategy());
return SessionManagementConfigurer.this;
}
}
/**
@@ -376,7 +375,6 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
/**
* Controls the maximum number of sessions for a user. The default is to allow any
* number of users.
*
* @param maximumSessions the maximum number of sessions for a user
* @return the {@link ConcurrencyControlConfigurer} for further customizations
*/
@@ -389,7 +387,6 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
* The URL to redirect to if a user tries to access a resource and their session
* has been expired due to too many sessions for the current user. The default is
* to write a simple error message to the response.
*
* @param expiredUrl the URL to redirect to
* @return the {@link ConcurrencyControlConfigurer} for further customizations
*/
@@ -400,7 +397,6 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
/**
* Determines the behaviour when an expired session is detected.
*
* @param expiredSessionStrategy the {@link SessionInformationExpiredStrategy} to
* use when an expired session is detected.
* @return the {@link ConcurrencyControlConfigurer} for further customizations
@@ -419,13 +415,11 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
* {@link #expiredUrl(String)}. The advantage of this approach is if a user
* accidentally does not log out, there is no need for an administrator to
* intervene or wait till their session expires.
*
* @param maxSessionsPreventsLogin true to have an error at time of
* authentication, else false (default)
* @return the {@link ConcurrencyControlConfigurer} for further customizations
*/
public ConcurrencyControlConfigurer maxSessionsPreventsLogin(
boolean maxSessionsPreventsLogin) {
public ConcurrencyControlConfigurer maxSessionsPreventsLogin(boolean maxSessionsPreventsLogin) {
SessionManagementConfigurer.this.maxSessionsPreventsLogin = maxSessionsPreventsLogin;
return this;
}
@@ -433,19 +427,16 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
/**
* Controls the {@link SessionRegistry} implementation used. The default is
* {@link SessionRegistryImpl} which is an in memory implementation.
*
* @param sessionRegistry the {@link SessionRegistry} to use
* @return the {@link ConcurrencyControlConfigurer} for further customizations
*/
public ConcurrencyControlConfigurer sessionRegistry(
SessionRegistry sessionRegistry) {
public ConcurrencyControlConfigurer sessionRegistry(SessionRegistry sessionRegistry) {
SessionManagementConfigurer.this.sessionRegistry = sessionRegistry;
return this;
}
/**
* Used to chain back to the {@link SessionManagementConfigurer}
*
* @return the {@link SessionManagementConfigurer} for further customizations
*/
public SessionManagementConfigurer<H> and() {
@@ -454,31 +445,27 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
private ConcurrencyControlConfigurer() {
}
}
@Override
public void init(H http) {
SecurityContextRepository securityContextRepository = http
.getSharedObject(SecurityContextRepository.class);
SecurityContextRepository securityContextRepository = http.getSharedObject(SecurityContextRepository.class);
boolean stateless = isStateless();
if (securityContextRepository == null) {
if (stateless) {
http.setSharedObject(SecurityContextRepository.class,
new NullSecurityContextRepository());
http.setSharedObject(SecurityContextRepository.class, new NullSecurityContextRepository());
}
else {
HttpSessionSecurityContextRepository httpSecurityRepository = new HttpSessionSecurityContextRepository();
httpSecurityRepository
.setDisableUrlRewriting(!this.enableSessionUrlRewriting);
httpSecurityRepository.setDisableUrlRewriting(!this.enableSessionUrlRewriting);
httpSecurityRepository.setAllowSessionCreation(isAllowSessionCreation());
AuthenticationTrustResolver trustResolver = http
.getSharedObject(AuthenticationTrustResolver.class);
AuthenticationTrustResolver trustResolver = http.getSharedObject(AuthenticationTrustResolver.class);
if (trustResolver != null) {
httpSecurityRepository.setTrustResolver(trustResolver);
}
http.setSharedObject(SecurityContextRepository.class,
httpSecurityRepository);
http.setSharedObject(SecurityContextRepository.class, httpSecurityRepository);
}
}
@@ -488,21 +475,18 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
http.setSharedObject(RequestCache.class, new NullRequestCache());
}
}
http.setSharedObject(SessionAuthenticationStrategy.class,
getSessionAuthenticationStrategy(http));
http.setSharedObject(SessionAuthenticationStrategy.class, getSessionAuthenticationStrategy(http));
http.setSharedObject(InvalidSessionStrategy.class, getInvalidSessionStrategy());
}
@Override
public void configure(H http) {
SecurityContextRepository securityContextRepository = http
.getSharedObject(SecurityContextRepository.class);
SessionManagementFilter sessionManagementFilter = new SessionManagementFilter(
securityContextRepository, getSessionAuthenticationStrategy(http));
SecurityContextRepository securityContextRepository = http.getSharedObject(SecurityContextRepository.class);
SessionManagementFilter sessionManagementFilter = new SessionManagementFilter(securityContextRepository,
getSessionAuthenticationStrategy(http));
if (this.sessionAuthenticationErrorUrl != null) {
sessionManagementFilter.setAuthenticationFailureHandler(
new SimpleUrlAuthenticationFailureHandler(
this.sessionAuthenticationErrorUrl));
new SimpleUrlAuthenticationFailureHandler(this.sessionAuthenticationErrorUrl));
}
InvalidSessionStrategy strategy = getInvalidSessionStrategy();
if (strategy != null) {
@@ -512,8 +496,7 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
if (failureHandler != null) {
sessionManagementFilter.setAuthenticationFailureHandler(failureHandler);
}
AuthenticationTrustResolver trustResolver = http
.getSharedObject(AuthenticationTrustResolver.class);
AuthenticationTrustResolver trustResolver = http.getSharedObject(AuthenticationTrustResolver.class);
if (trustResolver != null) {
sessionManagementFilter.setTrustResolver(trustResolver);
}
@@ -534,7 +517,8 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
ConcurrentSessionFilter concurrentSessionFilter;
if (expireStrategy == null) {
concurrentSessionFilter = new ConcurrentSessionFilter(sessionRegistry);
} else {
}
else {
concurrentSessionFilter = new ConcurrentSessionFilter(sessionRegistry, expireStrategy);
}
LogoutConfigurer<H> logoutConfigurer = http.getConfigurer(LogoutConfigurer.class);
@@ -551,7 +535,6 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
* Gets the {@link InvalidSessionStrategy} to use. If null and
* {@link #invalidSessionUrl} is not null defaults to
* {@link SimpleRedirectInvalidSessionStrategy}.
*
* @return the {@link InvalidSessionStrategy} to use
*/
InvalidSessionStrategy getInvalidSessionStrategy() {
@@ -563,8 +546,7 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
return null;
}
this.invalidSessionStrategy = new SimpleRedirectInvalidSessionStrategy(
this.invalidSessionUrl);
this.invalidSessionStrategy = new SimpleRedirectInvalidSessionStrategy(this.invalidSessionUrl);
return this.invalidSessionStrategy;
}
@@ -577,8 +559,7 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
return null;
}
this.expiredSessionStrategy = new SimpleRedirectSessionInformationExpiredStrategy(
this.expiredUrl);
this.expiredSessionStrategy = new SimpleRedirectSessionInformationExpiredStrategy(this.expiredUrl);
return this.expiredSessionStrategy;
}
@@ -605,10 +586,8 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
return this.sessionPolicy;
}
SessionCreationPolicy sessionPolicy =
getBuilder().getSharedObject(SessionCreationPolicy.class);
return sessionPolicy == null ?
SessionCreationPolicy.IF_REQUIRED : sessionPolicy;
SessionCreationPolicy sessionPolicy = getBuilder().getSharedObject(SessionCreationPolicy.class);
return sessionPolicy == null ? SessionCreationPolicy.IF_REQUIRED : sessionPolicy;
}
/**
@@ -618,8 +597,7 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
*/
private boolean isAllowSessionCreation() {
SessionCreationPolicy sessionPolicy = getSessionCreationPolicy();
return SessionCreationPolicy.ALWAYS == sessionPolicy
|| SessionCreationPolicy.IF_REQUIRED == sessionPolicy;
return SessionCreationPolicy.ALWAYS == sessionPolicy || SessionCreationPolicy.IF_REQUIRED == sessionPolicy;
}
/**
@@ -635,7 +613,6 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
* Gets the customized {@link SessionAuthenticationStrategy} if
* {@link #sessionAuthenticationStrategy(SessionAuthenticationStrategy)} was
* specified. Otherwise creates a default {@link SessionAuthenticationStrategy}.
*
* @return the {@link SessionAuthenticationStrategy} to use
*/
private SessionAuthenticationStrategy getSessionAuthenticationStrategy(H http) {
@@ -647,8 +624,7 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
if (this.providedSessionAuthenticationStrategy == null) {
// If the user did not provide a SessionAuthenticationStrategy
// then default to sessionFixationAuthenticationStrategy
defaultSessionAuthenticationStrategy = postProcess(
this.sessionFixationAuthenticationStrategy);
defaultSessionAuthenticationStrategy = postProcess(this.sessionFixationAuthenticationStrategy);
}
else {
defaultSessionAuthenticationStrategy = this.providedSessionAuthenticationStrategy;
@@ -658,10 +634,8 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
ConcurrentSessionControlAuthenticationStrategy concurrentSessionControlStrategy = new ConcurrentSessionControlAuthenticationStrategy(
sessionRegistry);
concurrentSessionControlStrategy.setMaximumSessions(this.maximumSessions);
concurrentSessionControlStrategy
.setExceptionIfMaximumExceeded(this.maxSessionsPreventsLogin);
concurrentSessionControlStrategy = postProcess(
concurrentSessionControlStrategy);
concurrentSessionControlStrategy.setExceptionIfMaximumExceeded(this.maxSessionsPreventsLogin);
concurrentSessionControlStrategy = postProcess(concurrentSessionControlStrategy);
RegisterSessionAuthenticationStrategy registerSessionStrategy = new RegisterSessionAuthenticationStrategy(
sessionRegistry);
@@ -690,14 +664,12 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
return this.sessionRegistry;
}
private void registerDelegateApplicationListener(H http,
ApplicationListener<?> delegate) {
private void registerDelegateApplicationListener(H http, ApplicationListener<?> delegate) {
DelegatingApplicationListener delegating = getBeanOrNull(DelegatingApplicationListener.class);
if (delegating == null) {
return;
}
SmartApplicationListener smartListener = new GenericApplicationListenerAdapter(
delegate);
SmartApplicationListener smartListener = new GenericApplicationListenerAdapter(delegate);
delegating.addListener(smartListener);
}
@@ -714,7 +686,7 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
* @return the default {@link SessionAuthenticationStrategy} for session fixation
*/
private static SessionAuthenticationStrategy createDefaultSessionFixationProtectionStrategy() {
return new ChangeSessionIdAuthenticationStrategy();
return new ChangeSessionIdAuthenticationStrategy();
}
private <T> T getBeanOrNull(Class<T> type) {
@@ -729,4 +701,5 @@ public final class SessionManagementConfigurer<H extends HttpSecurityBuilder<H>>
return null;
}
}
}
@@ -77,18 +77,17 @@ import org.springframework.util.Assert;
* The following shared objects are used:
*
* <ul>
* <li>
* AuthenticationManager</li>
* <li>AuthenticationManager</li>
* </ul>
*
* @param <H> the type of {@link HttpSecurityBuilder} that is being configured
*
* @author Rob Winch
* @since 3.2
* @see ExpressionUrlAuthorizationConfigurer
*/
public final class UrlAuthorizationConfigurer<H extends HttpSecurityBuilder<H>> extends
AbstractInterceptUrlConfigurer<UrlAuthorizationConfigurer<H>, H> {
public final class UrlAuthorizationConfigurer<H extends HttpSecurityBuilder<H>>
extends AbstractInterceptUrlConfigurer<UrlAuthorizationConfigurer<H>, H> {
private final StandardInterceptUrlRegistry REGISTRY;
public UrlAuthorizationConfigurer(ApplicationContext context) {
@@ -98,7 +97,6 @@ public final class UrlAuthorizationConfigurer<H extends HttpSecurityBuilder<H>>
/**
* The StandardInterceptUrlRegistry is what users will interact with after applying
* the {@link UrlAuthorizationConfigurer}.
*
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further customizations
*/
public StandardInterceptUrlRegistry getRegistry() {
@@ -107,18 +105,15 @@ public final class UrlAuthorizationConfigurer<H extends HttpSecurityBuilder<H>>
/**
* Adds an {@link ObjectPostProcessor} for this class.
*
* @param objectPostProcessor
* @return the {@link UrlAuthorizationConfigurer} for further customizations
*/
public UrlAuthorizationConfigurer<H> withObjectPostProcessor(
ObjectPostProcessor<?> objectPostProcessor) {
public UrlAuthorizationConfigurer<H> withObjectPostProcessor(ObjectPostProcessor<?> objectPostProcessor) {
addObjectPostProcessor(objectPostProcessor);
return this;
}
public class StandardInterceptUrlRegistry
extends
public class StandardInterceptUrlRegistry extends
ExpressionUrlAuthorizationConfigurer<H>.AbstractInterceptUrlRegistry<StandardInterceptUrlRegistry, AuthorizedUrl> {
/**
@@ -129,8 +124,7 @@ public final class UrlAuthorizationConfigurer<H extends HttpSecurityBuilder<H>>
}
@Override
public MvcMatchersAuthorizedUrl mvcMatchers(HttpMethod method,
String... mvcPatterns) {
public MvcMatchersAuthorizedUrl mvcMatchers(HttpMethod method, String... mvcPatterns) {
return new MvcMatchersAuthorizedUrl(createMvcMatchers(method, mvcPatterns));
}
@@ -140,20 +134,17 @@ public final class UrlAuthorizationConfigurer<H extends HttpSecurityBuilder<H>>
}
@Override
protected final AuthorizedUrl chainRequestMatchersInternal(
List<RequestMatcher> requestMatchers) {
protected final AuthorizedUrl chainRequestMatchersInternal(List<RequestMatcher> requestMatchers) {
return new AuthorizedUrl(requestMatchers);
}
/**
* Adds an {@link ObjectPostProcessor} for this class.
*
* @param objectPostProcessor
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further
* customizations
*/
public StandardInterceptUrlRegistry withObjectPostProcessor(
ObjectPostProcessor<?> objectPostProcessor) {
public StandardInterceptUrlRegistry withObjectPostProcessor(ObjectPostProcessor<?> objectPostProcessor) {
addObjectPostProcessor(objectPostProcessor);
return this;
}
@@ -167,7 +158,6 @@ public final class UrlAuthorizationConfigurer<H extends HttpSecurityBuilder<H>>
/**
* Creates the default {@link AccessDecisionVoter} instances used if an
* {@link AccessDecisionManager} was not specified.
*
* @param http the builder to use
*/
@Override
@@ -182,13 +172,11 @@ public final class UrlAuthorizationConfigurer<H extends HttpSecurityBuilder<H>>
/**
* Creates the {@link FilterInvocationSecurityMetadataSource} to use. The
* implementation is a {@link DefaultFilterInvocationSecurityMetadataSource}.
*
* @param http the builder to use
*/
@Override
FilterInvocationSecurityMetadataSource createMetadataSource(H http) {
return new DefaultFilterInvocationSecurityMetadataSource(
REGISTRY.createRequestMap());
return new DefaultFilterInvocationSecurityMetadataSource(REGISTRY.createRequestMap());
}
/**
@@ -200,34 +188,29 @@ public final class UrlAuthorizationConfigurer<H extends HttpSecurityBuilder<H>>
* by the {@link RequestMatcher} instances
* @return the {@link ExpressionUrlAuthorizationConfigurer} for further customizations
*/
private StandardInterceptUrlRegistry addMapping(
Iterable<? extends RequestMatcher> requestMatchers,
private StandardInterceptUrlRegistry addMapping(Iterable<? extends RequestMatcher> requestMatchers,
Collection<ConfigAttribute> configAttributes) {
for (RequestMatcher requestMatcher : requestMatchers) {
REGISTRY.addMapping(new AbstractConfigAttributeRequestMatcherRegistry.UrlMapping(
requestMatcher, configAttributes));
REGISTRY.addMapping(
new AbstractConfigAttributeRequestMatcherRegistry.UrlMapping(requestMatcher, configAttributes));
}
return REGISTRY;
}
/**
* Creates a String for specifying a user requires a role.
*
* @param role the role that should be required which is prepended with ROLE_
* automatically (i.e. USER, ADMIN, etc). It should not start with ROLE_
* @return the {@link ConfigAttribute} expressed as a String
*/
private static String hasRole(String role) {
Assert.isTrue(
!role.startsWith("ROLE_"),
() -> role
+ " should not start with ROLE_ since ROLE_ is automatically prepended when using hasRole. Consider using hasAuthority or access instead.");
Assert.isTrue(!role.startsWith("ROLE_"), () -> role
+ " should not start with ROLE_ since ROLE_ is automatically prepended when using hasRole. Consider using hasAuthority or access instead.");
return "ROLE_" + role;
}
/**
* Creates a String for specifying that a user requires one of many roles.
*
* @param roles the roles that the user should have at least one of (i.e. ADMIN, USER,
* etc). Each role should not start with ROLE_ since it is automatically prepended
* already.
@@ -257,9 +240,9 @@ public final class UrlAuthorizationConfigurer<H extends HttpSecurityBuilder<H>>
* @author Rob Winch
*/
public final class MvcMatchersAuthorizedUrl extends AuthorizedUrl {
/**
* Creates a new instance
*
* @param requestMatchers the {@link RequestMatcher} instances to map
*/
private MvcMatchersAuthorizedUrl(List<MvcRequestMatcher> requestMatchers) {
@@ -273,6 +256,7 @@ public final class UrlAuthorizationConfigurer<H extends HttpSecurityBuilder<H>>
}
return this;
}
}
/**
@@ -283,6 +267,7 @@ public final class UrlAuthorizationConfigurer<H extends HttpSecurityBuilder<H>>
* @since 3.2
*/
public class AuthorizedUrl {
private final List<? extends RequestMatcher> requestMatchers;
/**
@@ -291,14 +276,12 @@ public final class UrlAuthorizationConfigurer<H extends HttpSecurityBuilder<H>>
* {@link ConfigAttribute} instances.
*/
private AuthorizedUrl(List<? extends RequestMatcher> requestMatchers) {
Assert.notEmpty(requestMatchers,
"requestMatchers must contain at least one value");
Assert.notEmpty(requestMatchers, "requestMatchers must contain at least one value");
this.requestMatchers = requestMatchers;
}
/**
* Specifies a user requires a role.
*
* @param role the role that should be required which is prepended with ROLE_
* automatically (i.e. USER, ADMIN, etc). It should not start with ROLE_ the
* {@link UrlAuthorizationConfigurer} for further customization
@@ -309,7 +292,6 @@ public final class UrlAuthorizationConfigurer<H extends HttpSecurityBuilder<H>>
/**
* Specifies that a user requires one of many roles.
*
* @param roles the roles that the user should have at least one of (i.e. ADMIN,
* USER, etc). Each role should not start with ROLE_ since it is automatically
* prepended already.
@@ -321,7 +303,6 @@ public final class UrlAuthorizationConfigurer<H extends HttpSecurityBuilder<H>>
/**
* Specifies a user requires an authority.
*
* @param authority the authority that should be required
* @return the {@link UrlAuthorizationConfigurer} for further customization
*/
@@ -360,5 +341,7 @@ public final class UrlAuthorizationConfigurer<H extends HttpSecurityBuilder<H>>
protected List<? extends RequestMatcher> getMatchers() {
return this.requestMatchers;
}
}
}
@@ -53,8 +53,7 @@ import javax.servlet.http.HttpServletRequest;
* The following shared objects are created
*
* <ul>
* <li>
* {@link AuthenticationEntryPoint} is populated with an
* <li>{@link AuthenticationEntryPoint} is populated with an
* {@link Http403ForbiddenEntryPoint}</li>
* <li>A {@link PreAuthenticatedAuthenticationProvider} is populated into
* {@link HttpSecurity#authenticationProvider(org.springframework.security.authentication.AuthenticationProvider)}
@@ -73,11 +72,15 @@ import javax.servlet.http.HttpServletRequest;
* @author Rob Winch
* @since 3.2
*/
public final class X509Configurer<H extends HttpSecurityBuilder<H>> extends
AbstractHttpConfigurer<X509Configurer<H>, H> {
public final class X509Configurer<H extends HttpSecurityBuilder<H>>
extends AbstractHttpConfigurer<X509Configurer<H>, H> {
private X509AuthenticationFilter x509AuthenticationFilter;
private X509PrincipalExtractor x509PrincipalExtractor;
private AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken> authenticationUserDetailsService;
private AuthenticationDetailsSource<HttpServletRequest, PreAuthenticatedGrantedAuthoritiesWebAuthenticationDetails> authenticationDetailsSource;
/**
@@ -92,19 +95,16 @@ public final class X509Configurer<H extends HttpSecurityBuilder<H>> extends
* Allows specifying the entire {@link X509AuthenticationFilter}. If this is
* specified, the properties on {@link X509Configurer} will not be populated on the
* {@link X509AuthenticationFilter}.
*
* @param x509AuthenticationFilter the {@link X509AuthenticationFilter} to use
* @return the {@link X509Configurer} for further customizations
*/
public X509Configurer<H> x509AuthenticationFilter(
X509AuthenticationFilter x509AuthenticationFilter) {
public X509Configurer<H> x509AuthenticationFilter(X509AuthenticationFilter x509AuthenticationFilter) {
this.x509AuthenticationFilter = x509AuthenticationFilter;
return this;
}
/**
* Specifies the {@link X509PrincipalExtractor}
*
* @param x509PrincipalExtractor the {@link X509PrincipalExtractor} to use
* @return the {@link X509Configurer} to use
*/
@@ -115,7 +115,6 @@ public final class X509Configurer<H extends HttpSecurityBuilder<H>> extends
/**
* Specifies the {@link AuthenticationDetailsSource}
*
* @param authenticationDetailsSource the {@link AuthenticationDetailsSource} to use
* @return the {@link X509Configurer} to use
*/
@@ -129,7 +128,6 @@ public final class X509Configurer<H extends HttpSecurityBuilder<H>> extends
* Shortcut for invoking
* {@link #authenticationUserDetailsService(AuthenticationUserDetailsService)} with a
* {@link UserDetailsByNameServiceWrapper}.
*
* @param userDetailsService the {@link UserDetailsService} to use
* @return the {@link X509Configurer} for further customizations
*/
@@ -143,8 +141,8 @@ public final class X509Configurer<H extends HttpSecurityBuilder<H>> extends
* Specifies the {@link AuthenticationUserDetailsService} to use. If not specified,
* the shared {@link UserDetailsService} will be used to create a
* {@link UserDetailsByNameServiceWrapper}.
*
* @param authenticationUserDetailsService the {@link AuthenticationUserDetailsService} to use
* @param authenticationUserDetailsService the
* {@link AuthenticationUserDetailsService} to use
* @return the {@link X509Configurer} for further customizations
*/
public X509Configurer<H> authenticationUserDetailsService(
@@ -157,9 +155,8 @@ public final class X509Configurer<H extends HttpSecurityBuilder<H>> extends
* Specifies the regex to extract the principal from the certificate. If not
* specified, the default expression from {@link SubjectDnX509PrincipalExtractor} is
* used.
*
* @param subjectPrincipalRegex the regex to extract the user principal from the
* certificate (i.e. "CN=(.*?)(?:,|$)").
* certificate (i.e. "CN=(.*?)(?:,|$)").
* @return the {@link X509Configurer} for further customizations
*/
public X509Configurer<H> subjectPrincipalRegex(String subjectPrincipalRegex) {
@@ -183,8 +180,7 @@ public final class X509Configurer<H extends HttpSecurityBuilder<H>> extends
@Override
public void configure(H http) {
X509AuthenticationFilter filter = getFilter(http
.getSharedObject(AuthenticationManager.class));
X509AuthenticationFilter filter = getFilter(http.getSharedObject(AuthenticationManager.class));
http.addFilter(filter);
}
@@ -196,8 +192,7 @@ public final class X509Configurer<H extends HttpSecurityBuilder<H>> extends
x509AuthenticationFilter.setPrincipalExtractor(x509PrincipalExtractor);
}
if (authenticationDetailsSource != null) {
x509AuthenticationFilter
.setAuthenticationDetailsSource(authenticationDetailsSource);
x509AuthenticationFilter.setAuthenticationDetailsSource(authenticationDetailsSource);
}
x509AuthenticationFilter = postProcess(x509AuthenticationFilter);
}
@@ -48,26 +48,26 @@ import org.springframework.util.Assert;
* <li>{@link ClientRegistrationRepository}</li>
* </ul>
*
* @deprecated It is not recommended to use the implicit flow
* due to the inherent risks of returning access tokens in an HTTP redirect
* without any confirmation that it has been received by the client.
* See reference <a target="_blank" href="https://oauth.net/2/grant-types/implicit/">OAuth 2.0 Implicit Grant</a>.
*
* @deprecated It is not recommended to use the implicit flow due to the inherent risks of
* returning access tokens in an HTTP redirect without any confirmation that it has been
* received by the client. See reference
* <a target="_blank" href="https://oauth.net/2/grant-types/implicit/">OAuth 2.0 Implicit
* Grant</a>.
* @author Joe Grandja
* @since 5.0
* @see OAuth2AuthorizationRequestRedirectFilter
* @see ClientRegistrationRepository
*/
@Deprecated
public final class ImplicitGrantConfigurer<B extends HttpSecurityBuilder<B>> extends
AbstractHttpConfigurer<ImplicitGrantConfigurer<B>, B> {
public final class ImplicitGrantConfigurer<B extends HttpSecurityBuilder<B>>
extends AbstractHttpConfigurer<ImplicitGrantConfigurer<B>, B> {
private String authorizationRequestBaseUri;
/**
* Sets the base {@code URI} used for authorization requests.
*
* @param authorizationRequestBaseUri the base {@code URI} used for authorization requests
* @param authorizationRequestBaseUri the base {@code URI} used for authorization
* requests
* @return the {@link ImplicitGrantConfigurer} for further configuration
*/
public ImplicitGrantConfigurer<B> authorizationRequestBaseUri(String authorizationRequestBaseUri) {
@@ -78,11 +78,11 @@ public final class ImplicitGrantConfigurer<B extends HttpSecurityBuilder<B>> ext
/**
* Sets the repository of client registrations.
*
* @param clientRegistrationRepository the repository of client registrations
* @return the {@link ImplicitGrantConfigurer} for further configuration
*/
public ImplicitGrantConfigurer<B> clientRegistrationRepository(ClientRegistrationRepository clientRegistrationRepository) {
public ImplicitGrantConfigurer<B> clientRegistrationRepository(
ClientRegistrationRepository clientRegistrationRepository) {
Assert.notNull(clientRegistrationRepository, "clientRegistrationRepository cannot be null");
this.getBuilder().setSharedObject(ClientRegistrationRepository.class, clientRegistrationRepository);
return this;
@@ -91,13 +91,14 @@ public final class ImplicitGrantConfigurer<B extends HttpSecurityBuilder<B>> ext
@Override
public void configure(B http) {
OAuth2AuthorizationRequestRedirectFilter authorizationRequestFilter = new OAuth2AuthorizationRequestRedirectFilter(
OAuth2ClientConfigurerUtils.getClientRegistrationRepository(this.getBuilder()), this.getAuthorizationRequestBaseUri());
OAuth2ClientConfigurerUtils.getClientRegistrationRepository(this.getBuilder()),
this.getAuthorizationRequestBaseUri());
http.addFilter(this.postProcess(authorizationRequestFilter));
}
private String getAuthorizationRequestBaseUri() {
return this.authorizationRequestBaseUri != null ?
this.authorizationRequestBaseUri :
OAuth2AuthorizationRequestRedirectFilter.DEFAULT_AUTHORIZATION_REQUEST_BASE_URI;
return this.authorizationRequestBaseUri != null ? this.authorizationRequestBaseUri
: OAuth2AuthorizationRequestRedirectFilter.DEFAULT_AUTHORIZATION_REQUEST_BASE_URI;
}
}
@@ -43,13 +43,15 @@ import org.springframework.util.Assert;
* The following configuration options are available:
*
* <ul>
* <li>{@link #authorizationCodeGrant()} - support for the OAuth 2.0 Authorization Code Grant</li>
* <li>{@link #authorizationCodeGrant()} - support for the OAuth 2.0 Authorization Code
* Grant</li>
* </ul>
*
* <p>
* Defaults are provided for all configuration options with the only required configuration
* being {@link #clientRegistrationRepository(ClientRegistrationRepository)}.
* Alternatively, a {@link ClientRegistrationRepository} {@code @Bean} may be registered instead.
* Defaults are provided for all configuration options with the only required
* configuration being
* {@link #clientRegistrationRepository(ClientRegistrationRepository)}. Alternatively, a
* {@link ClientRegistrationRepository} {@code @Bean} may be registered instead.
*
* <h2>Security Filters</h2>
*
@@ -87,18 +89,18 @@ import org.springframework.util.Assert;
* @see OAuth2AuthorizedClientRepository
* @see AbstractHttpConfigurer
*/
public final class OAuth2ClientConfigurer<B extends HttpSecurityBuilder<B>> extends
AbstractHttpConfigurer<OAuth2ClientConfigurer<B>, B> {
public final class OAuth2ClientConfigurer<B extends HttpSecurityBuilder<B>>
extends AbstractHttpConfigurer<OAuth2ClientConfigurer<B>, B> {
private AuthorizationCodeGrantConfigurer authorizationCodeGrantConfigurer = new AuthorizationCodeGrantConfigurer();
/**
* Sets the repository of client registrations.
*
* @param clientRegistrationRepository the repository of client registrations
* @return the {@link OAuth2ClientConfigurer} for further configuration
*/
public OAuth2ClientConfigurer<B> clientRegistrationRepository(ClientRegistrationRepository clientRegistrationRepository) {
public OAuth2ClientConfigurer<B> clientRegistrationRepository(
ClientRegistrationRepository clientRegistrationRepository) {
Assert.notNull(clientRegistrationRepository, "clientRegistrationRepository cannot be null");
this.getBuilder().setSharedObject(ClientRegistrationRepository.class, clientRegistrationRepository);
return this;
@@ -106,11 +108,11 @@ public final class OAuth2ClientConfigurer<B extends HttpSecurityBuilder<B>> exte
/**
* Sets the repository for authorized client(s).
*
* @param authorizedClientRepository the authorized client repository
* @return the {@link OAuth2ClientConfigurer} for further configuration
*/
public OAuth2ClientConfigurer<B> authorizedClientRepository(OAuth2AuthorizedClientRepository authorizedClientRepository) {
public OAuth2ClientConfigurer<B> authorizedClientRepository(
OAuth2AuthorizedClientRepository authorizedClientRepository) {
Assert.notNull(authorizedClientRepository, "authorizedClientRepository cannot be null");
this.getBuilder().setSharedObject(OAuth2AuthorizedClientRepository.class, authorizedClientRepository);
return this;
@@ -118,19 +120,19 @@ public final class OAuth2ClientConfigurer<B extends HttpSecurityBuilder<B>> exte
/**
* Sets the service for authorized client(s).
*
* @param authorizedClientService the authorized client service
* @return the {@link OAuth2ClientConfigurer} for further configuration
*/
public OAuth2ClientConfigurer<B> authorizedClientService(OAuth2AuthorizedClientService authorizedClientService) {
Assert.notNull(authorizedClientService, "authorizedClientService cannot be null");
this.authorizedClientRepository(new AuthenticatedPrincipalOAuth2AuthorizedClientRepository(authorizedClientService));
this.authorizedClientRepository(
new AuthenticatedPrincipalOAuth2AuthorizedClientRepository(authorizedClientService));
return this;
}
/**
* Returns the {@link AuthorizationCodeGrantConfigurer} for configuring the OAuth 2.0 Authorization Code Grant.
*
* Returns the {@link AuthorizationCodeGrantConfigurer} for configuring the OAuth 2.0
* Authorization Code Grant.
* @return the {@link AuthorizationCodeGrantConfigurer}
*/
public AuthorizationCodeGrantConfigurer authorizationCodeGrant() {
@@ -139,12 +141,12 @@ public final class OAuth2ClientConfigurer<B extends HttpSecurityBuilder<B>> exte
/**
* Configures the OAuth 2.0 Authorization Code Grant.
*
* @param authorizationCodeGrantCustomizer the {@link Customizer} to provide more options for
* the {@link AuthorizationCodeGrantConfigurer}
* @param authorizationCodeGrantCustomizer the {@link Customizer} to provide more
* options for the {@link AuthorizationCodeGrantConfigurer}
* @return the {@link OAuth2ClientConfigurer} for further customizations
*/
public OAuth2ClientConfigurer<B> authorizationCodeGrant(Customizer<AuthorizationCodeGrantConfigurer> authorizationCodeGrantCustomizer) {
public OAuth2ClientConfigurer<B> authorizationCodeGrant(
Customizer<AuthorizationCodeGrantConfigurer> authorizationCodeGrantCustomizer) {
authorizationCodeGrantCustomizer.customize(this.authorizationCodeGrantConfigurer);
return this;
}
@@ -153,8 +155,11 @@ public final class OAuth2ClientConfigurer<B extends HttpSecurityBuilder<B>> exte
* Configuration options for the OAuth 2.0 Authorization Code Grant.
*/
public class AuthorizationCodeGrantConfigurer {
private OAuth2AuthorizationRequestResolver authorizationRequestResolver;
private AuthorizationRequestRepository<OAuth2AuthorizationRequest> authorizationRequestRepository;
private OAuth2AccessTokenResponseClient<OAuth2AuthorizationCodeGrantRequest> accessTokenResponseClient;
private AuthorizationCodeGrantConfigurer() {
@@ -162,11 +167,12 @@ public final class OAuth2ClientConfigurer<B extends HttpSecurityBuilder<B>> exte
/**
* Sets the resolver used for resolving {@link OAuth2AuthorizationRequest}'s.
*
* @param authorizationRequestResolver the resolver used for resolving {@link OAuth2AuthorizationRequest}'s
* @param authorizationRequestResolver the resolver used for resolving
* {@link OAuth2AuthorizationRequest}'s
* @return the {@link AuthorizationCodeGrantConfigurer} for further configuration
*/
public AuthorizationCodeGrantConfigurer authorizationRequestResolver(OAuth2AuthorizationRequestResolver authorizationRequestResolver) {
public AuthorizationCodeGrantConfigurer authorizationRequestResolver(
OAuth2AuthorizationRequestResolver authorizationRequestResolver) {
Assert.notNull(authorizationRequestResolver, "authorizationRequestResolver cannot be null");
this.authorizationRequestResolver = authorizationRequestResolver;
return this;
@@ -174,8 +180,8 @@ public final class OAuth2ClientConfigurer<B extends HttpSecurityBuilder<B>> exte
/**
* Sets the repository used for storing {@link OAuth2AuthorizationRequest}'s.
*
* @param authorizationRequestRepository the repository used for storing {@link OAuth2AuthorizationRequest}'s
* @param authorizationRequestRepository the repository used for storing
* {@link OAuth2AuthorizationRequest}'s
* @return the {@link AuthorizationCodeGrantConfigurer} for further configuration
*/
public AuthorizationCodeGrantConfigurer authorizationRequestRepository(
@@ -187,9 +193,10 @@ public final class OAuth2ClientConfigurer<B extends HttpSecurityBuilder<B>> exte
}
/**
* Sets the client used for requesting the access token credential from the Token Endpoint.
*
* @param accessTokenResponseClient the client used for requesting the access token credential from the Token Endpoint
* Sets the client used for requesting the access token credential from the Token
* Endpoint.
* @param accessTokenResponseClient the client used for requesting the access
* token credential from the Token Endpoint
* @return the {@link AuthorizationCodeGrantConfigurer} for further configuration
*/
public AuthorizationCodeGrantConfigurer accessTokenResponseClient(
@@ -202,7 +209,6 @@ public final class OAuth2ClientConfigurer<B extends HttpSecurityBuilder<B>> exte
/**
* Returns the {@link OAuth2ClientConfigurer} for further configuration.
*
* @return the {@link OAuth2ClientConfigurer}
*/
public OAuth2ClientConfigurer<B> and() {
@@ -210,25 +216,28 @@ public final class OAuth2ClientConfigurer<B extends HttpSecurityBuilder<B>> exte
}
private void init(B builder) {
OAuth2AuthorizationCodeAuthenticationProvider authorizationCodeAuthenticationProvider =
new OAuth2AuthorizationCodeAuthenticationProvider(getAccessTokenResponseClient());
OAuth2AuthorizationCodeAuthenticationProvider authorizationCodeAuthenticationProvider = new OAuth2AuthorizationCodeAuthenticationProvider(
getAccessTokenResponseClient());
builder.authenticationProvider(postProcess(authorizationCodeAuthenticationProvider));
}
private void configure(B builder) {
OAuth2AuthorizationRequestRedirectFilter authorizationRequestRedirectFilter = createAuthorizationRequestRedirectFilter(builder);
OAuth2AuthorizationRequestRedirectFilter authorizationRequestRedirectFilter = createAuthorizationRequestRedirectFilter(
builder);
builder.addFilter(postProcess(authorizationRequestRedirectFilter));
OAuth2AuthorizationCodeGrantFilter authorizationCodeGrantFilter = createAuthorizationCodeGrantFilter(builder);
OAuth2AuthorizationCodeGrantFilter authorizationCodeGrantFilter = createAuthorizationCodeGrantFilter(
builder);
builder.addFilter(postProcess(authorizationCodeGrantFilter));
}
private OAuth2AuthorizationRequestRedirectFilter createAuthorizationRequestRedirectFilter(B builder) {
OAuth2AuthorizationRequestResolver resolver = getAuthorizationRequestResolver();
OAuth2AuthorizationRequestRedirectFilter authorizationRequestRedirectFilter =
new OAuth2AuthorizationRequestRedirectFilter(resolver);
OAuth2AuthorizationRequestRedirectFilter authorizationRequestRedirectFilter = new OAuth2AuthorizationRequestRedirectFilter(
resolver);
if (this.authorizationRequestRepository != null) {
authorizationRequestRedirectFilter.setAuthorizationRequestRepository(this.authorizationRequestRepository);
authorizationRequestRedirectFilter
.setAuthorizationRequestRepository(this.authorizationRequestRepository);
}
RequestCache requestCache = builder.getSharedObject(RequestCache.class);
if (requestCache != null) {
@@ -251,8 +260,7 @@ public final class OAuth2ClientConfigurer<B extends HttpSecurityBuilder<B>> exte
AuthenticationManager authenticationManager = builder.getSharedObject(AuthenticationManager.class);
OAuth2AuthorizationCodeGrantFilter authorizationCodeGrantFilter = new OAuth2AuthorizationCodeGrantFilter(
OAuth2ClientConfigurerUtils.getClientRegistrationRepository(builder),
OAuth2ClientConfigurerUtils.getAuthorizedClientRepository(builder),
authenticationManager);
OAuth2ClientConfigurerUtils.getAuthorizedClientRepository(builder), authenticationManager);
if (this.authorizationRequestRepository != null) {
authorizationCodeGrantFilter.setAuthorizationRequestRepository(this.authorizationRequestRepository);
@@ -270,6 +278,7 @@ public final class OAuth2ClientConfigurer<B extends HttpSecurityBuilder<B>> exte
}
return new DefaultAuthorizationCodeTokenResponseClient();
}
}
@Override
@@ -281,4 +290,5 @@ public final class OAuth2ClientConfigurer<B extends HttpSecurityBuilder<B>> exte
public void configure(B builder) {
this.authorizationCodeGrantConfigurer.configure(builder);
}
}
@@ -41,7 +41,8 @@ final class OAuth2ClientConfigurerUtils {
}
static <B extends HttpSecurityBuilder<B>> ClientRegistrationRepository getClientRegistrationRepository(B builder) {
ClientRegistrationRepository clientRegistrationRepository = builder.getSharedObject(ClientRegistrationRepository.class);
ClientRegistrationRepository clientRegistrationRepository = builder
.getSharedObject(ClientRegistrationRepository.class);
if (clientRegistrationRepository == null) {
clientRegistrationRepository = getClientRegistrationRepositoryBean(builder);
builder.setSharedObject(ClientRegistrationRepository.class, clientRegistrationRepository);
@@ -49,12 +50,15 @@ final class OAuth2ClientConfigurerUtils {
return clientRegistrationRepository;
}
private static <B extends HttpSecurityBuilder<B>> ClientRegistrationRepository getClientRegistrationRepositoryBean(B builder) {
private static <B extends HttpSecurityBuilder<B>> ClientRegistrationRepository getClientRegistrationRepositoryBean(
B builder) {
return builder.getSharedObject(ApplicationContext.class).getBean(ClientRegistrationRepository.class);
}
static <B extends HttpSecurityBuilder<B>> OAuth2AuthorizedClientRepository getAuthorizedClientRepository(B builder) {
OAuth2AuthorizedClientRepository authorizedClientRepository = builder.getSharedObject(OAuth2AuthorizedClientRepository.class);
static <B extends HttpSecurityBuilder<B>> OAuth2AuthorizedClientRepository getAuthorizedClientRepository(
B builder) {
OAuth2AuthorizedClientRepository authorizedClientRepository = builder
.getSharedObject(OAuth2AuthorizedClientRepository.class);
if (authorizedClientRepository == null) {
authorizedClientRepository = getAuthorizedClientRepositoryBean(builder);
if (authorizedClientRepository == null) {
@@ -66,34 +70,45 @@ final class OAuth2ClientConfigurerUtils {
return authorizedClientRepository;
}
private static <B extends HttpSecurityBuilder<B>> OAuth2AuthorizedClientRepository getAuthorizedClientRepositoryBean(B builder) {
Map<String, OAuth2AuthorizedClientRepository> authorizedClientRepositoryMap = BeanFactoryUtils.beansOfTypeIncludingAncestors(
builder.getSharedObject(ApplicationContext.class), OAuth2AuthorizedClientRepository.class);
private static <B extends HttpSecurityBuilder<B>> OAuth2AuthorizedClientRepository getAuthorizedClientRepositoryBean(
B builder) {
Map<String, OAuth2AuthorizedClientRepository> authorizedClientRepositoryMap = BeanFactoryUtils
.beansOfTypeIncludingAncestors(builder.getSharedObject(ApplicationContext.class),
OAuth2AuthorizedClientRepository.class);
if (authorizedClientRepositoryMap.size() > 1) {
throw new NoUniqueBeanDefinitionException(OAuth2AuthorizedClientRepository.class, authorizedClientRepositoryMap.size(),
"Expected single matching bean of type '" + OAuth2AuthorizedClientRepository.class.getName() + "' but found " +
authorizedClientRepositoryMap.size() + ": " + StringUtils.collectionToCommaDelimitedString(authorizedClientRepositoryMap.keySet()));
throw new NoUniqueBeanDefinitionException(OAuth2AuthorizedClientRepository.class,
authorizedClientRepositoryMap.size(),
"Expected single matching bean of type '" + OAuth2AuthorizedClientRepository.class.getName()
+ "' but found " + authorizedClientRepositoryMap.size() + ": "
+ StringUtils.collectionToCommaDelimitedString(authorizedClientRepositoryMap.keySet()));
}
return (!authorizedClientRepositoryMap.isEmpty() ? authorizedClientRepositoryMap.values().iterator().next() : null);
return (!authorizedClientRepositoryMap.isEmpty() ? authorizedClientRepositoryMap.values().iterator().next()
: null);
}
private static <B extends HttpSecurityBuilder<B>> OAuth2AuthorizedClientService getAuthorizedClientService(B builder) {
private static <B extends HttpSecurityBuilder<B>> OAuth2AuthorizedClientService getAuthorizedClientService(
B builder) {
OAuth2AuthorizedClientService authorizedClientService = getAuthorizedClientServiceBean(builder);
if (authorizedClientService == null) {
authorizedClientService = new InMemoryOAuth2AuthorizedClientService(getClientRegistrationRepository(builder));
authorizedClientService = new InMemoryOAuth2AuthorizedClientService(
getClientRegistrationRepository(builder));
}
return authorizedClientService;
}
private static <B extends HttpSecurityBuilder<B>> OAuth2AuthorizedClientService getAuthorizedClientServiceBean(B builder) {
Map<String, OAuth2AuthorizedClientService> authorizedClientServiceMap = BeanFactoryUtils.beansOfTypeIncludingAncestors(
builder.getSharedObject(ApplicationContext.class), OAuth2AuthorizedClientService.class);
private static <B extends HttpSecurityBuilder<B>> OAuth2AuthorizedClientService getAuthorizedClientServiceBean(
B builder) {
Map<String, OAuth2AuthorizedClientService> authorizedClientServiceMap = BeanFactoryUtils
.beansOfTypeIncludingAncestors(builder.getSharedObject(ApplicationContext.class),
OAuth2AuthorizedClientService.class);
if (authorizedClientServiceMap.size() > 1) {
throw new NoUniqueBeanDefinitionException(OAuth2AuthorizedClientService.class, authorizedClientServiceMap.size(),
"Expected single matching bean of type '" + OAuth2AuthorizedClientService.class.getName() + "' but found " +
authorizedClientServiceMap.size() + ": " + StringUtils.collectionToCommaDelimitedString(authorizedClientServiceMap.keySet()));
throw new NoUniqueBeanDefinitionException(OAuth2AuthorizedClientService.class,
authorizedClientServiceMap.size(),
"Expected single matching bean of type '" + OAuth2AuthorizedClientService.class.getName()
+ "' but found " + authorizedClientServiceMap.size() + ": "
+ StringUtils.collectionToCommaDelimitedString(authorizedClientServiceMap.keySet()));
}
return (!authorizedClientServiceMap.isEmpty() ? authorizedClientServiceMap.values().iterator().next() : null);
}
}

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