Last active
July 13, 2018 14:15
-
-
Save anthavio/9748558 to your computer and use it in GitHub Desktop.
spring-security java exploded configuration
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@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