Created
January 14, 2016 18:02
-
-
Save mc-suchecki/671ecb4d5ae4bae17f81 to your computer and use it in GitHub Desktop.
Spring Security config for SAML plugin
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 | |
@EnableWebSecurity | |
@EnableGlobalMethodSecurity(securedEnabled = true) | |
public class SecurityConfig extends WebSecurityConfigurerAdapter { | |
@Configuration | |
@Profile("prod") | |
@PropertySource("classpath:/.../resources/server-prod.properties") | |
static class ProductionProperties { | |
} | |
@Configuration | |
@Profile("test") | |
@PropertySource("classpath:/.../resources/server-test.properties") | |
static class TestingProperties { | |
} | |
@Configuration | |
@Profile("dev") | |
@PropertySource("classpath:/.../resources/server-dev.properties") | |
static class DeveloperProperties { | |
} | |
@Autowired | |
private SAMLUserDetailsServiceImpl samlUserDetailsServiceImpl; | |
@Autowired | |
private Environment environment; | |
/** | |
* Define the security filter chain in order to support SSO Auth by using SAML 2.0 | |
* @return Filter chain proxy | |
* @throws Exception | |
*/ | |
@Bean(name="samlFilter") | |
public FilterChainProxy samlFilter() throws Exception { | |
List<SecurityFilterChain> chains = new ArrayList<SecurityFilterChain>(); | |
chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/login/**"), samlEntryPoint())); | |
chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/logout/**"), samlLogoutFilter())); | |
chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/metadata/**"), | |
metadataDisplayFilter())); | |
chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/SSO/**"), | |
samlWebSSOProcessingFilter())); | |
chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/SSOHoK/**"), | |
samlWebSSOHoKProcessingFilter())); | |
chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/SingleLogout/**"), | |
samlLogoutProcessingFilter())); | |
chains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher("/saml/discovery/**"), samlIDPDiscovery())); | |
return new FilterChainProxy(chains); | |
} | |
/** | |
* Returns the authentication manager currently used by Spring. | |
* It represents a bean definition with the aim allow wiring from | |
* other classes performing the Inversion of Control (IoC). | |
* | |
* @throws Exception | |
*/ | |
@Bean | |
@Override | |
public AuthenticationManager authenticationManagerBean() throws Exception { | |
return super.authenticationManagerBean(); | |
} | |
/** | |
* Defines the web based security configuration. | |
* @param http allows configuring web based security for specific http requests. | |
* @throws Exception | |
*/ | |
@Override | |
protected void configure(HttpSecurity http) throws Exception { | |
http.httpBasic().authenticationEntryPoint(samlEntryPoint()); | |
http.csrf().disable(); | |
http.addFilterBefore(metadataGeneratorFilter(), ChannelProcessingFilter.class) | |
.addFilterAfter(samlFilter(), BasicAuthenticationFilter.class); | |
http.authorizeRequests().antMatchers("/").permitAll().antMatchers("/error").permitAll() | |
.antMatchers("/saml/**").permitAll().anyRequest().authenticated(); | |
http.logout().logoutSuccessUrl("/"); | |
} | |
/** | |
* Sets a custom authentication provider. | |
* | |
* @param auth SecurityBuilder used to create an AuthenticationManager. | |
* @throws Exception | |
*/ | |
@Override | |
protected void configure(AuthenticationManagerBuilder auth) throws Exception { | |
auth.authenticationProvider(samlAuthenticationProvider()); | |
} | |
// Initialisation of the velocity engine | |
@Bean | |
public VelocityEngine velocityEngine() { | |
return VelocityFactory.getEngine(); | |
} | |
// XML parser pool needed for OpenSAML parsing | |
@Bean(initMethod = "initialize") | |
public StaticBasicParserPool parserPool() { | |
return new StaticBasicParserPool(); | |
} | |
@Bean(name = "parserPoolHolder") | |
public ParserPoolHolder parserPoolHolder() { | |
return new ParserPoolHolder(); | |
} | |
// Bindings, encoders and decoders used for creating and parsing messages | |
@Bean | |
public MultiThreadedHttpConnectionManager multiThreadedHttpConnectionManager() { | |
return new MultiThreadedHttpConnectionManager(); | |
} | |
@Bean | |
public HttpClient httpClient() { | |
return new HttpClient(multiThreadedHttpConnectionManager()); | |
} | |
// SAML Authentication Provider responsible for validating of received SAML messages | |
@Bean | |
public SAMLAuthenticationProvider samlAuthenticationProvider() { | |
SAMLAuthenticationProvider samlAuthenticationProvider = new SAMLAuthenticationProvider(); | |
samlAuthenticationProvider.setUserDetails(samlUserDetailsServiceImpl); | |
samlAuthenticationProvider.setForcePrincipalAsString(false); | |
return samlAuthenticationProvider; | |
} | |
// Provider of default SAML Context | |
@Bean | |
public SAMLContextProviderImpl contextProvider() { | |
return new SAMLContextProviderImpl(); | |
} | |
// Initialization of OpenSAML library | |
@Bean | |
public static SAMLBootstrap sAMLBootstrap() { | |
return new SAMLBootstrap(); | |
} | |
// Logger for SAML messages and events | |
@Bean | |
public SAMLDefaultLogger samlLogger() { | |
return new SAMLDefaultLogger(); | |
} | |
// SAML 2.0 WebSSO Assertion Consumer | |
@Bean | |
public WebSSOProfileConsumer webSSOprofileConsumer() { | |
return new WebSSOProfileConsumerImpl(); | |
} | |
// SAML 2.0 Holder-of-Key WebSSO Assertion Consumer | |
@Bean | |
public WebSSOProfileConsumerHoKImpl hokWebSSOprofileConsumer() { | |
return new WebSSOProfileConsumerHoKImpl(); | |
} | |
// SAML 2.0 Web SSO profile | |
@Bean | |
public WebSSOProfile webSSOprofile() { | |
return new WebSSOProfileImpl(); | |
} | |
// SAML 2.0 Holder-of-Key Web SSO profile | |
@Bean | |
public WebSSOProfileConsumerHoKImpl hokWebSSOProfile() { | |
return new WebSSOProfileConsumerHoKImpl(); | |
} | |
// SAML 2.0 ECP profile | |
@Bean | |
public WebSSOProfileECPImpl ecpprofile() { | |
return new WebSSOProfileECPImpl(); | |
} | |
@Bean | |
public SingleLogoutProfile logoutprofile() { | |
return new SingleLogoutProfileImpl(); | |
} | |
// Central storage of cryptographic keys | |
@Bean | |
public static KeyManager keyManager() { | |
DefaultResourceLoader loader = new DefaultResourceLoader(); | |
Resource storeFile = loader.getResource(environment.getRequiredProperty("server.ssl.key-store")); | |
String storePass = environment.getRequiredProperty("server.ssl.key-store-password"); | |
Map<String, String> passwords = new HashMap<String, String>(); | |
passwords.put(environment.getRequiredProperty("server.ssl.key-alias"), environment.getRequiredProperty("server.ssl.key-password")); | |
String defaultKey = environment.getRequiredProperty("server.ssl.key-alias"); | |
return new JKSKeyManager(storeFile, storePass, passwords, defaultKey); | |
} | |
// Setup TLS Socket Factory | |
@Bean | |
public TLSProtocolConfigurer tlsProtocolConfigurer() { | |
return new TLSProtocolConfigurer(); | |
} | |
@Bean | |
public ProtocolSocketFactory socketFactory() { | |
return new TLSProtocolSocketFactory(keyManager(), null, "default"); | |
} | |
@Bean | |
public Protocol socketFactoryProtocol() { | |
return new Protocol("https", socketFactory(), 443); | |
} | |
@Bean | |
public MethodInvokingFactoryBean socketFactoryInitialization() { | |
MethodInvokingFactoryBean methodInvokingFactoryBean = new MethodInvokingFactoryBean(); | |
methodInvokingFactoryBean.setTargetClass(Protocol.class); | |
methodInvokingFactoryBean.setTargetMethod("registerProtocol"); | |
Object[] args = {"https", socketFactoryProtocol()}; | |
methodInvokingFactoryBean.setArguments(args); | |
return methodInvokingFactoryBean; | |
} | |
@Bean | |
public WebSSOProfileOptions defaultWebSSOProfileOptions() { | |
WebSSOProfileOptions webSSOProfileOptions = new WebSSOProfileOptions(); | |
webSSOProfileOptions.setIncludeScoping(false); | |
return webSSOProfileOptions; | |
} | |
// Entry point to initialize authentication, default values taken from properties file | |
@Bean | |
public SAMLEntryPoint samlEntryPoint() { | |
SAMLEntryPoint samlEntryPoint = new SAMLEntryPoint(); | |
samlEntryPoint.setDefaultProfileOptions(defaultWebSSOProfileOptions()); | |
return samlEntryPoint; | |
} | |
// Setup advanced info about metadata | |
@Bean | |
public ExtendedMetadata extendedMetadata() { | |
ExtendedMetadata extendedMetadata = new ExtendedMetadata(); | |
extendedMetadata.setIdpDiscoveryEnabled(true); | |
extendedMetadata.setSignMetadata(true); | |
return extendedMetadata; | |
} | |
// IDP Discovery Service | |
@Bean | |
public SAMLDiscovery samlIDPDiscovery() { | |
SAMLDiscovery idpDiscovery = new SAMLDiscovery(); | |
idpDiscovery.setIdpSelectionPath("/saml/idpSelection"); | |
return idpDiscovery; | |
} | |
@Bean(name = "idp") | |
public ExtendedMetadataDelegate extendedMetadataProvider() throws MetadataProviderException { | |
HTTPMetadataProvider metadataProvider = new HTTPMetadataProvider(new Timer(), new HttpClient(), | |
environment.getRequiredProperty("saml.idp.metadata-url")); | |
metadataProvider.setParserPool(parserPool()); | |
ExtendedMetadataDelegate extendedMetadataDelegate = | |
new ExtendedMetadataDelegate(metadataProvider, extendedMetadata()); | |
extendedMetadataDelegate.setMetadataTrustCheck(false); | |
extendedMetadataDelegate.setMetadataRequireSignature(false); | |
return extendedMetadataDelegate; | |
} | |
// IDP Metadata configuration - paths to metadata of IDPs in circle of trust is here | |
// Do not forget to call initialize method on providers | |
@Bean | |
@Qualifier("metadata") | |
public CachingMetadataManager metadata() throws MetadataProviderException { | |
List<MetadataProvider> providers = new ArrayList<MetadataProvider>(); | |
providers.add(extendedMetadataProvider()); | |
return new CachingMetadataManager(providers); | |
} | |
// Filter automatically generates default SP metadata | |
@Bean | |
public MetadataGenerator metadataGenerator() { | |
MetadataGenerator metadataGenerator = new MetadataGenerator(); | |
metadataGenerator.setEntityId(environment.getRequiredProperty("saml.entity-id")); | |
metadataGenerator.setEntityBaseURL("URL is here"); | |
metadataGenerator.setExtendedMetadata(extendedMetadata()); | |
metadataGenerator.setIncludeDiscoveryExtension(false); | |
metadataGenerator.setKeyManager(keyManager()); | |
return metadataGenerator; | |
} | |
// The filter is waiting for connections on URL suffixed with filterSuffix | |
// and presents SP metadata there | |
@Bean | |
public MetadataDisplayFilter metadataDisplayFilter() { | |
return new MetadataDisplayFilter(); | |
} | |
// Handler deciding where to redirect user after successful login | |
@Bean | |
public SavedRequestAwareAuthenticationSuccessHandler successRedirectHandler() { | |
SavedRequestAwareAuthenticationSuccessHandler successRedirectHandler = | |
new SavedRequestAwareAuthenticationSuccessHandler(); | |
successRedirectHandler.setDefaultTargetUrl("/landing"); | |
return successRedirectHandler; | |
} | |
// Handler deciding where to redirect user after failed login | |
@Bean | |
public SimpleUrlAuthenticationFailureHandler authenticationFailureHandler() { | |
SimpleUrlAuthenticationFailureHandler failureHandler = | |
new SimpleUrlAuthenticationFailureHandler(); | |
failureHandler.setUseForward(true); | |
failureHandler.setDefaultFailureUrl("/error"); | |
return failureHandler; | |
} | |
@Bean | |
public SAMLWebSSOHoKProcessingFilter samlWebSSOHoKProcessingFilter() throws Exception { | |
SAMLWebSSOHoKProcessingFilter samlWebSSOHoKProcessingFilter = new SAMLWebSSOHoKProcessingFilter(); | |
samlWebSSOHoKProcessingFilter.setAuthenticationSuccessHandler(successRedirectHandler()); | |
samlWebSSOHoKProcessingFilter.setAuthenticationManager(authenticationManager()); | |
samlWebSSOHoKProcessingFilter.setAuthenticationFailureHandler(authenticationFailureHandler()); | |
return samlWebSSOHoKProcessingFilter; | |
} | |
// Processing filter for WebSSO profile messages | |
@Bean | |
public SAMLProcessingFilter samlWebSSOProcessingFilter() throws Exception { | |
SAMLProcessingFilter samlWebSSOProcessingFilter = new SAMLProcessingFilter(); | |
samlWebSSOProcessingFilter.setAuthenticationManager(authenticationManager()); | |
samlWebSSOProcessingFilter.setAuthenticationSuccessHandler(successRedirectHandler()); | |
samlWebSSOProcessingFilter.setAuthenticationFailureHandler(authenticationFailureHandler()); | |
return samlWebSSOProcessingFilter; | |
} | |
@Bean | |
public MetadataGeneratorFilter metadataGeneratorFilter() { | |
return new MetadataGeneratorFilter(metadataGenerator()); | |
} | |
// Handler for successful logout | |
@Bean | |
public SimpleUrlLogoutSuccessHandler successLogoutHandler() { | |
SimpleUrlLogoutSuccessHandler successLogoutHandler = new SimpleUrlLogoutSuccessHandler(); | |
successLogoutHandler.setDefaultTargetUrl("/"); | |
return successLogoutHandler; | |
} | |
// Logout handler terminating local session | |
@Bean | |
public SecurityContextLogoutHandler logoutHandler() { | |
SecurityContextLogoutHandler logoutHandler = | |
new SecurityContextLogoutHandler(); | |
logoutHandler.setInvalidateHttpSession(true); | |
logoutHandler.setClearAuthentication(true); | |
return logoutHandler; | |
} | |
// Filter processing incoming logout messages | |
// First argument determines URL user will be redirected to after successful global logout | |
@Bean | |
public SAMLLogoutProcessingFilter samlLogoutProcessingFilter() { | |
return new SAMLLogoutProcessingFilter(successLogoutHandler(), | |
logoutHandler()); | |
} | |
// Overrides default logout processing filter with the one processing SAML messages | |
@Bean | |
public SAMLLogoutFilter samlLogoutFilter() { | |
return new SAMLLogoutFilter(successLogoutHandler(), | |
new LogoutHandler[]{logoutHandler()}, | |
new LogoutHandler[]{logoutHandler()}); | |
} | |
// Bindings | |
private ArtifactResolutionProfile artifactResolutionProfile() { | |
final ArtifactResolutionProfileImpl artifactResolutionProfile = | |
new ArtifactResolutionProfileImpl(httpClient()); | |
artifactResolutionProfile.setProcessor(new SAMLProcessorImpl(soapBinding())); | |
return artifactResolutionProfile; | |
} | |
@Bean | |
public HTTPArtifactBinding artifactBinding(ParserPool parserPool, VelocityEngine velocityEngine) { | |
return new HTTPArtifactBinding(parserPool, velocityEngine, artifactResolutionProfile()); | |
} | |
@Bean | |
public HTTPSOAP11Binding soapBinding() { | |
return new HTTPSOAP11Binding(parserPool()); | |
} | |
@Bean | |
public HTTPPostBinding httpPostBinding() { | |
return new HTTPPostBinding(parserPool(), velocityEngine()); | |
} | |
@Bean | |
public HTTPRedirectDeflateBinding httpRedirectDeflateBinding() { | |
return new HTTPRedirectDeflateBinding(parserPool()); | |
} | |
@Bean | |
public HTTPSOAP11Binding httpSOAP11Binding() { | |
return new HTTPSOAP11Binding(parserPool()); | |
} | |
@Bean | |
public HTTPPAOS11Binding httpPAOS11Binding() { | |
return new HTTPPAOS11Binding(parserPool()); | |
} | |
// Processor | |
@Bean | |
public SAMLProcessorImpl processor() { | |
Collection<SAMLBinding> bindings = new ArrayList<SAMLBinding>(); | |
bindings.add(httpRedirectDeflateBinding()); | |
bindings.add(httpPostBinding()); | |
bindings.add(artifactBinding(parserPool(), velocityEngine())); | |
bindings.add(httpSOAP11Binding()); | |
bindings.add(httpPAOS11Binding()); | |
return new SAMLProcessorImpl(bindings); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment