<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
             xmlns:beans="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns:context="http://www.springframework.org/schema/context"
             xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
           http://www.springframework.org/schema/security
           http://www.springframework.org/schema/security/spring-security-3.1.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-3.1.xsd">

    <!-- Enable auto-wiring (the SAML extension requires this to initialise its components) -->
    <context:annotation-config/>
    <context:component-scan base-package="org.springframework.security.saml"/>

    <!-- standard Appkit security exceptions -->
    <http pattern="/styles/**" security="none"/>
    <http pattern="/assets/**" security="none"/>
    <http pattern="/javascript/**" security="none"/>
    <http pattern="/wro/**" security="none"/>

    <!-- SAML extension security exception -->
    <http security="none" pattern="/saml/web/**"/>

    <!-- Appkit security URL configuration with SAML extension filters added -->
    <http use-expressions="true" disable-url-rewriting="true" entry-point-ref="samlEntryPoint">
        <intercept-url pattern="/login/" access="isAnonymous()"/>
        <intercept-url pattern="/twigkit/resources/**" access="isAnonymous() or isAuthenticated()"/>
        <intercept-url pattern="/twigkit/services/gsa/auth/**" access="isAnonymous() or isAuthenticated()"/>
        <intercept-url pattern="/mock-response/search" access="isAnonymous() or isAuthenticated()"/>
        <!-- Add 'or isAnonymous()' to the below condition (/**) if you wish to allow anonymous access (if whole site not to be secured by SAML) -->
        <intercept-url pattern="/**" access="isAuthenticated()"/>
        <custom-filter before="FIRST" ref="metadataGeneratorFilter"/>
        <custom-filter after="BASIC_AUTH_FILTER" ref="samlFilter"/>
        <!-- The success URL can be customised - in this case it points to the IDP SLO endpoint to ensure the IDP carries out Single Logout and user is presented with the IDP's login form -->
        <!-- The initial /logout/ URL is required by Appkit -->
        <logout logout-url="/logout/" logout-success-url="https://localhost:9031/idp/startSLO.ping"/>
    </http>

    <!-- Mapping each of the Spring SAML filters to specific endpoints, modification not recommended (configure at IDP instead) -->
    <beans:bean id="samlFilter" class="org.springframework.security.web.FilterChainProxy">
        <filter-chain-map request-matcher="ant">
            <filter-chain pattern="/saml/login/**" filters="samlEntryPoint"/>
            <filter-chain pattern="/saml/logout/**" filters="samlLogoutFilter"/>
            <filter-chain pattern="/saml/SSO/**" filters="samlWebSSOProcessingFilter"/>
            <filter-chain pattern="/saml/SSOHoK/**" filters="samlWebSSOHoKProcessingFilter"/>
            <filter-chain pattern="/saml/SingleLogout/**" filters="samlLogoutProcessingFilter"/>
        </filter-chain-map>
    </beans:bean>

    <!-- Handler deciding where to redirect user when not logged in / after unsuccessful login -->
    <beans:bean id="unauthenticatedRedirectHandler"
          class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
        <!-- Use this URL to configure the IDP's entrypoint for login (SSO login form location) -->
        <beans:property name="defaultFailureUrl" value="https://localhost:9031/idp/startSSO.ping?PartnerSpId=SAMMY"/>
    </beans:bean>

    <!-- Handler deciding where to redirect user after successful login -->
    <beans:bean id="successRedirectHandler"
                class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
        <beans:property name="defaultTargetUrl" value="/"/>
    </beans:bean>
    <!--
    Use the following for interpreting RelayState coming from unsolicited response as redirect URL:
    <bean id="successRedirectHandler" class="org.springframework.security.saml.SAMLRelayStateSuccessHandler">
       <property name="defaultTargetUrl" value="/" />
    </bean>
    -->

    <!-- Handler for successful logout -->
    <beans:bean id="successLogoutHandler" class="org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler">
        <beans:property name="defaultTargetUrl" value="/logoutSuccess/"/>
    </beans:bean>

    <!-- Register authentication manager with SAML provider -->
    <authentication-manager alias="authenticationManager">
        <authentication-provider ref="samlAuthenticationProvider"/>
    </authentication-manager>

    <!-- Logger for SAML messages and events -->
    <beans:bean id="samlLogger" class="org.springframework.security.saml.log.SAMLDefaultLogger"/>


    <!-- Central storage of cryptographic keys -->
    <beans:bean id="keyManager" class="org.springframework.security.saml.key.JKSKeyManager">
        <!-- In the default example (IDP initiated SSO) this configuration can remain, and the IDP public keys imported into the key store file (samlKeystore.jks) -->
        <beans:constructor-arg value="classpath:samlKeystore.jks"/>
        <beans:constructor-arg type="java.lang.String" value="nalle123"/>
        <beans:constructor-arg>
            <beans:map>
                <!-- At least one private key must be included for Spring SAML to work -->
                <!-- If the login is SP initiated (by the application) this can be replaced with a private key generated specifically for this application (SP), and the public key is distributed to the IDP  -->
                <beans:entry key="apollo" value="nalle123"/> <!-- default private key alias and password -->
            </beans:map>
        </beans:constructor-arg>
        <beans:constructor-arg type="java.lang.String" value="apollo"/>
    </beans:bean>


    <!-- ########################################################################################################### -->
    <!-- ## REQUIRED BY SPRING SAML EXTENSION -                                                                   ## -->
    <!-- ## Only requires modification of entity ID under *metadataGeneratorFilter* in most cases                 ## -->
    <!-- ########################################################################################################### -->

    <!-- Entry point to initialize authentication, default values taken from properties file -->
    <beans:bean id="samlEntryPoint" class="org.springframework.security.saml.SAMLEntryPoint">
        <beans:property name="defaultProfileOptions">
            <beans:bean class="org.springframework.security.saml.websso.WebSSOProfileOptions">
                <beans:property name="includeScoping" value="false"/>
            </beans:bean>
        </beans:property>
    </beans:bean>

    <!-- Filter automatically generates default SP metadata -->
    <beans:bean id="metadataGeneratorFilter" class="org.springframework.security.saml.metadata.MetadataGeneratorFilter">
        <beans:constructor-arg>
            <beans:bean class="org.springframework.security.saml.metadata.MetadataGenerator">
                <!-- ### Configure this to correspond to entity ID for this SP (application) configured in the IDP ### -->
                <beans:property name="entityId" value="SAMMY"/>
                <beans:property name="extendedMetadata">
                    <beans:bean class="org.springframework.security.saml.metadata.ExtendedMetadata">
                        <beans:property name="signMetadata" value="false"/>
                        <!--<beans:property name="idpDiscoveryEnabled" value="true"/>-->
                    </beans:bean>
                </beans:property>
            </beans:bean>
        </beans:constructor-arg>
    </beans:bean>

    <!-- IDP Metadata configuration - paths to metadata of IDPs in circle of trust is here -->
    <!-- Do no forget to call initialize method on providers -->
    <beans:bean id="metadata" class="org.springframework.security.saml.metadata.CachingMetadataManager">
        <beans:constructor-arg>
            <beans:list>
                <beans:bean class="org.springframework.security.saml.metadata.ExtendedMetadataDelegate">
                    <beans:constructor-arg>
                        <beans:bean class="org.opensaml.saml2.metadata.provider.FilesystemMetadataProvider">
                            <beans:constructor-arg>
                                <!-- Use the specified file to configure the IDP (this can be exported from most IDP products)  -->
                                <beans:value type="java.io.File">classpath:idp-metadata.xml</beans:value>
                            </beans:constructor-arg>
                            <beans:property name="parserPool" ref="parserPool"/>
                        </beans:bean>
                    </beans:constructor-arg>
                    <beans:constructor-arg>
                        <beans:bean class="org.springframework.security.saml.metadata.ExtendedMetadata">
                        </beans:bean>
                    </beans:constructor-arg>
                </beans:bean>
            </beans:list>
        </beans:constructor-arg>
        <!-- OPTIONAL used when one of the metadata files contains information about this service provider -->
        <!-- <property name="hostedSPName" value=""/> -->
        <!-- OPTIONAL property: can tell the system which IDP should be used for authenticating user by default. -->
        <!-- <property name="defaultIDP" value="http://localhost:8080/opensso"/> -->
    </beans:bean>

    <!-- SAML Authentication Provider responsible for validating of received SAML messages -->
    <beans:bean id="samlAuthenticationProvider" class="org.springframework.security.saml.SAMLAuthenticationProvider">
        <!-- OPTIONAL property: can be used to store/load user data after login -->
        <!--
        <property name="userDetails" ref="bean" />
        -->
    </beans:bean>

    <!-- Provider of default SAML Context -->
    <beans:bean id="contextProvider" class="org.springframework.security.saml.context.SAMLContextProviderImpl"/>

    <!-- Processing filter for WebSSO profile messages -->
    <beans:bean id="samlWebSSOProcessingFilter" class="org.springframework.security.saml.SAMLProcessingFilter">
        <beans:property name="authenticationManager" ref="authenticationManager"/>
        <beans:property name="authenticationSuccessHandler" ref="successRedirectHandler"/>
        <beans:property name="authenticationFailureHandler" ref="unauthenticatedRedirectHandler"/>

    </beans:bean>

    <!-- Processing filter for WebSSO Holder-of-Key profile -->
    <beans:bean id="samlWebSSOHoKProcessingFilter" class="org.springframework.security.saml.SAMLWebSSOHoKProcessingFilter">
        <beans:property name="authenticationManager" ref="authenticationManager"/>
        <beans:property name="authenticationSuccessHandler" ref="successRedirectHandler"/>
    </beans:bean>

    <!-- Logout handler terminating local session -->
    <beans:bean id="logoutHandler"
          class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler">
        <beans:property name="invalidateHttpSession" value="true"/>
    </beans:bean>

    <!-- Override default logout processing filter with the one processing SAML messages -->
    <beans:bean id="samlLogoutFilter" class="org.springframework.security.saml.SAMLLogoutFilter">
        <beans:constructor-arg ref="successLogoutHandler"/>
        <beans:constructor-arg ref="logoutHandler"/>
        <beans:constructor-arg ref="logoutHandler"/>
    </beans:bean>

    <!-- Filter processing incoming logout messages -->
    <!-- First argument determines URL user will be redirected to after successful global logout -->
    <beans:bean id="samlLogoutProcessingFilter" class="org.springframework.security.saml.SAMLLogoutProcessingFilter">
        <beans:constructor-arg ref="successLogoutHandler"/>
        <beans:constructor-arg ref="logoutHandler"/>
    </beans:bean>

    <!-- Class loading incoming SAML messages from httpRequest stream -->
    <beans:bean id="processor" class="org.springframework.security.saml.processor.SAMLProcessorImpl">
        <beans:constructor-arg>
            <beans:list>
                <beans:ref bean="redirectBinding"/>
                <beans:ref bean="postBinding"/>
                <beans:ref bean="artifactBinding"/>
                <beans:ref bean="soapBinding"/>
            </beans:list>
        </beans:constructor-arg>
    </beans:bean>

    <!-- SAML 2.0 WebSSO Assertion Consumer -->
    <beans:bean id="webSSOprofileConsumer" class="org.springframework.security.saml.websso.WebSSOProfileConsumerImpl"/>

    <!-- SAML 2.0 Holder-of-Key WebSSO Assertion Consumer -->
    <beans:bean id="hokWebSSOprofileConsumer" class="org.springframework.security.saml.websso.WebSSOProfileConsumerHoKImpl"/>

    <!-- SAML 2.0 Web SSO profile -->
    <beans:bean id="webSSOprofile" class="org.springframework.security.saml.websso.WebSSOProfileImpl"/>

    <!-- SAML 2.0 Holder-of-Key Web SSO profile -->
    <beans:bean id="hokWebSSOProfile" class="org.springframework.security.saml.websso.WebSSOProfileConsumerHoKImpl"/>

    <!-- SAML 2.0 Logout Profile -->
    <beans:bean id="logoutprofile" class="org.springframework.security.saml.websso.SingleLogoutProfileImpl"/>

    <!-- Bindings, encoders and decoders used for creating and parsing messages -->
    <beans:bean id="postBinding" class="org.springframework.security.saml.processor.HTTPPostBinding">
        <beans:constructor-arg ref="parserPool"/>
        <beans:constructor-arg ref="velocityEngine"/>
    </beans:bean>

    <beans:bean id="redirectBinding" class="org.springframework.security.saml.processor.HTTPRedirectDeflateBinding">
        <beans:constructor-arg ref="parserPool"/>
    </beans:bean>

    <beans:bean id="artifactBinding" class="org.springframework.security.saml.processor.HTTPArtifactBinding">
        <beans:constructor-arg ref="parserPool"/>
        <beans:constructor-arg ref="velocityEngine"/>
        <beans:constructor-arg>
            <beans:bean class="org.springframework.security.saml.websso.ArtifactResolutionProfileImpl">
                <beans:constructor-arg>
                    <beans:bean class="org.apache.commons.httpclient.HttpClient"/>
                </beans:constructor-arg>
                <beans:property name="processor">
                    <beans:bean id="soapProcessor" class="org.springframework.security.saml.processor.SAMLProcessorImpl">
                        <beans:constructor-arg ref="soapBinding"/>
                    </beans:bean>
                </beans:property>
            </beans:bean>
        </beans:constructor-arg>
    </beans:bean>

    <beans:bean id="soapBinding" class="org.springframework.security.saml.processor.HTTPSOAP11Binding">
        <beans:constructor-arg ref="parserPool"/>
    </beans:bean>

    <!-- Initialization of OpenSAML library-->
    <beans:bean class="org.springframework.security.saml.SAMLBootstrap"/>

    <!-- Initialization of the velocity engine -->
    <beans:bean id="velocityEngine" class="org.springframework.security.saml.util.VelocityFactory" factory-method="getEngine"/>

    <!-- XML parser pool needed for OpenSAML parsing -->
    <beans:bean id="parserPool" class="org.opensaml.xml.parse.StaticBasicParserPool" scope="singleton" init-method="initialize"/>
    <beans:bean id="parserPoolHolder" class="org.springframework.security.saml.parser.ParserPoolHolder" scope="singleton"/>

</beans:beans>
