Skip to content

Instantly share code, notes, and snippets.

@anthavio
Last active July 13, 2018 14:15
Show Gist options
  • Save anthavio/9748558 to your computer and use it in GitHub Desktop.
Save anthavio/9748558 to your computer and use it in GitHub Desktop.
spring-security java exploded configuration
@Configuration
@PropertySource(CoreSpringConfig.PROPERTIES)
public class WebappSpringConfig {
@Autowired
private Environment environment;
/**
* 'springSecurityFilterChain' is Magic ID and it is required by Spring Security DelegatingFilterProxy in web.xml
*
* We cannot use @EnableWebSecurity with WebSecurityConfigurerAdapter because they allows only single
* SecurityFilterChain fore whole web application, but we have 2 chains
* - Active Directory/LDAP backed for Admin web application
* - Properties backed for REST endpoints
*/
@Bean(name = "springSecurityFilterChain")
public FilterChainProxy springSecurityFilterChain() throws Exception {
List<SecurityFilterChain> filterChains = new ArrayList<>();
filterChains.add(restSecurityChain("/api/**"));
filterChains.add(adminSecurityChain("/admin/**"));
FilterChainProxy filterChainProxy = new FilterChainProxy(filterChains);
return filterChainProxy;
}
public SecurityFilterChain restSecurityChain(String pattern) throws Exception {
//Don't create session for REST caller
SecurityContextPersistenceFilter persistenceFilter = buildPersistenceFilter(false);
AuthenticationManager authenticationManager = buildRestAuthenticationManager();
BasicAuthenticationEntryPoint entryPoint = new BasicAuthenticationEntryPoint();
entryPoint.setRealmName("Rest Realm");
BasicAuthenticationFilter basicFilter = new BasicAuthenticationFilter(authenticationManager, entryPoint);
basicFilter.afterPropertiesSet();
AccessDecisionManager accessDecisionManager = buildAccessDecisionManager();
AnonymousAuthenticationFilter anonymousFilter = buildAnonymousAuthenticationFilter("ROLE_ANONYMOUS");
FilterSecurityInterceptor securityInterceptor = new FilterSecurityInterceptor();
securityInterceptor.setAuthenticationManager(authenticationManager);
securityInterceptor.setAccessDecisionManager(accessDecisionManager);
LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> requestMap = new LinkedHashMap<>();
requestMap.put(AntMatcher("/api/xxx/**"), SecurityConfig.createList("ROLE_XXX_REST"));
requestMap.put(AntMatcher("/api/yyy/**"), SecurityConfig.createList("ROLE_YYY_REST"));
DefaultFilterInvocationSecurityMetadataSource metadataSource = new DefaultFilterInvocationSecurityMetadataSource(
requestMap);
securityInterceptor.setSecurityMetadataSource(metadataSource);
securityInterceptor.afterPropertiesSet();
//Send 403 directly to REST caller - Http403ForbiddenEntryPoint
ExceptionTranslationFilter exceptionFilter = new ExceptionTranslationFilter(entryPoint);
return new DefaultSecurityFilterChain(AntMatcher(pattern), persistenceFilter, basicFilter, anonymousFilter,
exceptionFilter, securityInterceptor);
}
/**
* We store XXX and YYY credentials in confidential.properties
*/
private AuthenticationManager buildRestAuthenticationManager() throws Exception {
Collection<UserDetails> users = new ArrayList<>();
String xxxUsername = environment.getRequiredProperty("authenticate.xxx.username");
String xxxPassword = environment.getRequiredProperty("authenticate.xxx.password");
users.add(new User(xxxUsername, xxxPassword, Arrays.asList(new SimpleGrantedAuthority("ROLE_XXX_REST"))));
String yyyUsername = environment.getRequiredProperty("authenticate.yyy.username");
String yyyPassword = environment.getRequiredProperty("authenticate.yyy.password");
users.add(new User(yyyUsername, yyyPassword, Arrays.asList(new SimpleGrantedAuthority("ROLE_YYY_REST"))));
InMemoryUserDetailsManager userDetailsService = new InMemoryUserDetailsManager(users);
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setUserDetailsService(userDetailsService);
authenticationProvider.afterPropertiesSet();
AuthenticationManager authenticationManager = new ProviderManager(
Arrays.asList((AuthenticationProvider) authenticationProvider));
return authenticationManager;
}
private AccessDecisionManager buildAccessDecisionManager() {
List<AccessDecisionVoter> voters = new ArrayList<>();
voters.add(new RoleVoter());//RoleHierarchyVoter
//voters.add(new WebExpressionVoter());
AccessDecisionManager accessDecisionManager = new AffirmativeBased(voters);
return accessDecisionManager;
}
public SecurityFilterChain adminSecurityChain(String pattern) throws Exception {
//Allow session for Interactive users
SecurityContextPersistenceFilter persistenceFilter = buildPersistenceFilter(true);
//Interactive user can logout
SimpleUrlLogoutSuccessHandler successHandler = new SimpleUrlLogoutSuccessHandler();
successHandler.setDefaultTargetUrl("/");
SecurityContextLogoutHandler logoutHandler = new SecurityContextLogoutHandler();
logoutHandler.setClearAuthentication(true);
logoutHandler.setInvalidateHttpSession(true);
LogoutFilter logoutFilter = new LogoutFilter(successHandler, logoutHandler);
//Build AuthenticationManager from provided LDAP AuthenticationProvider
AuthenticationManager authenticationManager = new ProviderManager(Arrays.asList(adminAuthenticationProvider()));
BasicAuthenticationEntryPoint entryPoint = new BasicAuthenticationEntryPoint();
entryPoint.setRealmName("Admin Realm");
BasicAuthenticationFilter basicFilter = new BasicAuthenticationFilter(authenticationManager, entryPoint);
basicFilter.afterPropertiesSet();
AnonymousAuthenticationFilter anonymousFilter = buildAnonymousAuthenticationFilter("ROLE_ANONYMOUS");
AccessDecisionManager accessDecisionManager = buildAccessDecisionManager();
FilterSecurityInterceptor securityInterceptor = new FilterSecurityInterceptor();
securityInterceptor.setAuthenticationManager(authenticationManager);
securityInterceptor.setAccessDecisionManager(accessDecisionManager);
//Single role to cover whole application
LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> requestMap = new LinkedHashMap<>();
requestMap.put(AntMatcher("/admin/**"), SecurityConfig.createList("ROLE_ADMIN"));
DefaultFilterInvocationSecurityMetadataSource metadataSource = new DefaultFilterInvocationSecurityMetadataSource(
requestMap);
securityInterceptor.setSecurityMetadataSource(metadataSource);
securityInterceptor.afterPropertiesSet();
//Send BASIC challenge to interactive users
ExceptionTranslationFilter exceptionFilter = new ExceptionTranslationFilter(entryPoint);
//org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@5d4971e
//org.springframework.security.web.context.SecurityContextPersistenceFilter@39f7e368
//org.springframework.security.web.header.HeaderWriterFilter@392a028f
//org.springframework.security.web.authentication.logout.LogoutFilter@7dab317
//org.springframework.security.web.authentication.www.BasicAuthenticationFilter@240b6882
//org.springframework.security.web.savedrequest.RequestCacheAwareFilter@5c72a676
//org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@14728025
//org.springframework.security.web.authentication.AnonymousAuthenticationFilter@480d358f
//org.springframework.security.web.session.SessionManagementFilter@f72ebc1
//org.springframework.security.web.access.ExceptionTranslationFilter@6f4809f6
//org.springframework.security.web.access.intercept.FilterSecurityInterceptor@3dbe15bc
return new DefaultSecurityFilterChain(AntMatcher(pattern), persistenceFilter, logoutFilter, basicFilter,
anonymousFilter, exceptionFilter, securityInterceptor);
}
private AuthenticationProvider adminAuthenticationProvider() {
String domain = environment.getRequiredProperty("ldap.domain");
String url = environment.getRequiredProperty("ldap.url");
ActiveDirectoryLdapAuthenticationProvider provider = new ActiveDirectoryLdapAuthenticationProvider(domain, url);
provider.setAuthoritiesMapper(new SimpleAuthorityMapper()); //add ROLE_ prefix
return provider;
}
public static RequestMatcher AntMatcher(String pattern) {
if (pattern == null || pattern.isEmpty()) {
throw new IllegalArgumentException("Null or empty pattern");
}
return new AntPathRequestMatcher(pattern);
}
private AnonymousAuthenticationFilter buildAnonymousAuthenticationFilter(String anonymousRole) {
AnonymousAuthenticationFilter filter = new AnonymousAuthenticationFilter("anonymous-key", "AnonymousUser",
AuthorityUtils.createAuthorityList(anonymousRole));
return filter;
}
private SecurityContextPersistenceFilter buildPersistenceFilter(boolean allowSessions) throws ServletException {
HttpSessionSecurityContextRepository repository = new HttpSessionSecurityContextRepository();
repository.setAllowSessionCreation(allowSessions);
SecurityContextPersistenceFilter persistenceFilter = new SecurityContextPersistenceFilter(repository);
persistenceFilter.afterPropertiesSet();
return persistenceFilter;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment