Skip to content

Commit

Permalink
Fixes spring-attic#226 - Configure filterProcessesUrl via SpringSocia…
Browse files Browse the repository at this point in the history
…lConfigurer

- Add the ability to configure filterProcessesUrl of SocialAuthentication
via SpringSocialConfigurer
- Add SpringSocialConfigurer#configure test
  • Loading branch information
f-lopes committed Dec 17, 2017
1 parent 7934198 commit 112480a
Show file tree
Hide file tree
Showing 2 changed files with 141 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
/**
* Configurer that adds {@link SocialAuthenticationFilter} to Spring Security's filter chain.
* Used with Spring Security 3.2's Java-based configuration support, when overriding WebSecurityConfigurerAdapter#configure(HttpSecurity):
*
*
* <pre>
* protected void configure(HttpSecurity http) throws Exception {
* http.
Expand All @@ -38,21 +38,23 @@
* .apply(new SpringSocialConfigurer());
* }
* </pre>
*
*
* @author Craig Walls
*/
public class SpringSocialConfigurer extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {

private UserIdSource userIdSource;

private String postLoginUrl;

private String postFailureUrl;

private String signupUrl;

private String connectionAddedRedirectUrl;

private String filterProcessesUrl;

private boolean alwaysUsePostLoginUrl = false;

/**
Expand All @@ -62,30 +64,30 @@ public class SpringSocialConfigurer extends SecurityConfigurerAdapter<DefaultSec
*/
public SpringSocialConfigurer() {
}

@Override
public void configure(HttpSecurity http) throws Exception {
public void configure(HttpSecurity http) throws Exception {
ApplicationContext applicationContext = http.getSharedObject(ApplicationContext.class);
UsersConnectionRepository usersConnectionRepository = getDependency(applicationContext, UsersConnectionRepository.class);
SocialAuthenticationServiceLocator authServiceLocator = getDependency(applicationContext, SocialAuthenticationServiceLocator.class);
SocialUserDetailsService socialUsersDetailsService = getDependency(applicationContext, SocialUserDetailsService.class);

SocialAuthenticationFilter filter = new SocialAuthenticationFilter(
http.getSharedObject(AuthenticationManager.class),
userIdSource != null ? userIdSource : new AuthenticationNameUserIdSource(),
usersConnectionRepository,
http.getSharedObject(AuthenticationManager.class),
userIdSource != null ? userIdSource : new AuthenticationNameUserIdSource(),
usersConnectionRepository,
authServiceLocator);

RememberMeServices rememberMe = http.getSharedObject(RememberMeServices.class);
if (rememberMe != null) {
filter.setRememberMeServices(rememberMe);
}

if (postLoginUrl != null) {
filter.setPostLoginUrl(postLoginUrl);
filter.setAlwaysUsePostLoginUrl(alwaysUsePostLoginUrl);
}

if (postFailureUrl != null) {
filter.setPostFailureUrl(postFailureUrl);
}
Expand All @@ -97,7 +99,11 @@ public void configure(HttpSecurity http) throws Exception {
if (connectionAddedRedirectUrl != null) {
filter.setConnectionAddedRedirectUrl(connectionAddedRedirectUrl);
}


if (filterProcessesUrl != null) {
filter.setFilterProcessesUrl(filterProcessesUrl);
}

http.authenticationProvider(
new SocialAuthenticationProvider(usersConnectionRepository, socialUsersDetailsService))
.addFilterBefore(postProcess(filter), AbstractPreAuthenticatedProcessingFilter.class);
Expand All @@ -111,7 +117,7 @@ private <T> T getDependency(ApplicationContext applicationContext, Class<T> depe
throw new IllegalStateException("SpringSocialConfigurer depends on " + dependencyType.getName() +". No single bean of that type found in application context.", e);
}
}

/**
* Sets the {@link UserIdSource} to use for authentication. Defaults to {@link AuthenticationNameUserIdSource}.
* @param userIdSource the UserIdSource to use when authenticating
Expand All @@ -121,27 +127,27 @@ public SpringSocialConfigurer userIdSource(UserIdSource userIdSource) {
this.userIdSource = userIdSource;
return this;
}

/**
* Sets the URL to land on after a successful login.
* @param postLoginUrl the URL to redirect to after a successful login
* @return this SpringSocialConfigurer for chained configuration
* @return this SpringSocialConfigurer for chained configuration
*/
public SpringSocialConfigurer postLoginUrl(String postLoginUrl) {
this.postLoginUrl = postLoginUrl;
return this;
}

/**
* If true, always redirect to postLoginUrl, even if a pre-signin target is in the request cache.
* @param alwaysUsePostLoginUrl if true, always redirect to the postLoginUrl
* @return this SpringSocialConfigurer for chained configuration
* @return this SpringSocialConfigurer for chained configuration
*/
public SpringSocialConfigurer alwaysUsePostLoginUrl(boolean alwaysUsePostLoginUrl) {
this.alwaysUsePostLoginUrl = alwaysUsePostLoginUrl;
return this;
}

/**
* Sets the URL to redirect to if authentication fails or if authorization is denied by the user.
* @param postFailureUrl the URL to redirect to after an authentication fail or authorization deny
Expand Down Expand Up @@ -172,4 +178,13 @@ public SpringSocialConfigurer connectionAddedRedirectUrl(String connectionAddedR
return this;
}

/**
* Sets the URL that determines if social authentication is required.
* @param filterProcessesUrl the URL that will initiate the social authentication process
* @return this SpringSocialConfigurer for chained configuration
*/
public SpringSocialConfigurer filterProcessesUrl(String filterProcessesUrl) {
this.filterProcessesUrl = filterProcessesUrl;
return this;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package org.springframework.social.security;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.mockito.Mockito.mock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.FilterChainProxy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.social.connect.UsersConnectionRepository;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.util.ReflectionTestUtils;

/**
* @author Florian Lopes
*/
@RunWith(SpringRunner.class)
public class SpringSocialConfigurerTest {

@Autowired
private FilterChainProxy springSecurityFilterChain;

@Autowired
private UsersConnectionRepository usersConnectionRepository;

@Autowired
private SocialAuthenticationServiceLocator socialAuthenticationServiceLocator;

@Test
public void testConfigure() {
final SecurityFilterChain defaultFilterChain = this.springSecurityFilterChain.getFilterChains().get(0);
assertTrue(defaultFilterChain.getFilters().stream().anyMatch(filter -> filter instanceof SocialAuthenticationFilter));

final SocialAuthenticationFilter socialAuthenticationFilter =
(SocialAuthenticationFilter) defaultFilterChain.getFilters()
.stream().filter(filter -> filter instanceof SocialAuthenticationFilter).findFirst().orElse(null);
assertNotNull(socialAuthenticationFilter);

assertTrue(ReflectionTestUtils.getField(socialAuthenticationFilter, "userIdSource") instanceof AuthenticationNameUserIdSource);

final ProviderManager providerManager =
(ProviderManager) ReflectionTestUtils.getField(socialAuthenticationFilter, "authenticationManager");
assertTrue(providerManager.getProviders().stream().anyMatch(authenticationProvider -> authenticationProvider instanceof SocialAuthenticationProvider));

assertNotNull(ReflectionTestUtils.getField(socialAuthenticationFilter, "rememberMeServices"));
final SocialAuthenticationFailureHandler failureHandler =
(SocialAuthenticationFailureHandler) ReflectionTestUtils.getField(socialAuthenticationFilter, "failureHandler");

assertEquals("/postFailure", ReflectionTestUtils.getField(failureHandler.getDelegate(), "defaultFailureUrl"));
final AuthenticationSuccessHandler successHandler =
(AuthenticationSuccessHandler) ReflectionTestUtils.getField(socialAuthenticationFilter, "successHandler");
assertEquals("/postLogin", ReflectionTestUtils.getField(successHandler, "defaultTargetUrl"));
assertEquals("/social-login", ReflectionTestUtils.getField(socialAuthenticationFilter, "filterProcessesUrl"));
assertEquals("/connectionAdded", ReflectionTestUtils.getField(socialAuthenticationFilter, "connectionAddedRedirectUrl"));
assertEquals("/signup", ReflectionTestUtils.getField(socialAuthenticationFilter, "signupUrl"));

assertSame(this.usersConnectionRepository, socialAuthenticationFilter.getUsersConnectionRepository());
assertSame(this.socialAuthenticationServiceLocator, socialAuthenticationFilter.getAuthServiceLocator());
}

@EnableWebSecurity
@Configuration
static class SpringSocialSecurityConfig extends WebSecurityConfigurerAdapter {

// @formatter:off
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.rememberMe()
.and()
.apply(new SpringSocialConfigurer()
.userIdSource(new AuthenticationNameUserIdSource())
.postLoginUrl("/postLogin")
.postFailureUrl("/postFailure")
.signupUrl("/signup")
.connectionAddedRedirectUrl("/connectionAdded")
.filterProcessesUrl("/social-login"));
}
// @formatter:on

@Bean
public UsersConnectionRepository usersConnectionRepository() {
return mock(UsersConnectionRepository.class);
}

@Bean
public SocialUserDetailsService socialUserDetailsService() {
return mock(SocialUserDetailsService.class);
}

@Bean
public SocialAuthenticationServiceLocator socialAuthenticationServiceLocator() {
return mock(SocialAuthenticationServiceLocator.class);
}
}
}

0 comments on commit 112480a

Please sign in to comment.