Reformat code using spring-javaformat
Run `./gradlew format` to reformat all java files. Issue gh-8945
This commit is contained in:
@@ -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 <global-method-security>
|
||||
* xml support.
|
||||
* Enables Spring Security global method security similar to the
|
||||
* <global-method-security> 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) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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("/static/**");
|
||||
* // 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 & cryptographic hash algorithm pairs.
|
||||
* @param pins the map of base64-encoded SPKI fingerprint & 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
Reference in New Issue
Block a user