<?xml version="1.0" encoding="UTF-8"?>

<!--
  - Application context representing the application WITH security services.
  -
  -->

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:s="http://www.springframework.org/schema/security"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    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.0.xsd">

    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
        <property name="url" value="jdbc:hsqldb:mem:securedms"/>
        <property name="username" value="sa"/>
        <property name="password" value=""/>
    </bean>

    <bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
        <property name="transactionAttributeSource">
            <value>
                sample.dms.secured.SecureDocumentDao.*=PROPAGATION_REQUIRED
                sample.dms.DocumentDao.*=PROPAGATION_REQUIRED
                org.springframework.security.acls.model.AclService.*=PROPAGATION_REQUIRED
                org.springframework.security.acls.model.MutableAclService.*=PROPAGATION_REQUIRED
                org.springframework.security.acls.jdbc.JdbcMutableAclService.*=PROPAGATION_REQUIRED
                org.springframework.security.acls.jdbc.JdbcAclService.*=PROPAGATION_REQUIRED
            </value>
        </property>
        <property name="transactionManager" ref="transactionManager" />
    </bean>

    <bean id="documentDao" class="sample.dms.secured.SecureDocumentDaoImpl">
        <constructor-arg ref="aclService"/>
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <bean id="dataSourcePopulator" class="sample.dms.secured.SecureDataSourcePopulator">
        <constructor-arg ref="dataSource"/>
        <constructor-arg ref="documentDao"/>
        <constructor-arg ref="transactionManager"/>
        <constructor-arg ref="aclService"/>
    </bean>

    <!-- ===================================  SECURITY DEFINITION BEANS ======================================== -->

   <!-- ======================== AUTHENTICATION (note there is no UI and this is for integration tests only) ======================= -->

    <s:authentication-manager alias="authenticationManager">
        <s:authentication-provider ref="daoAuthenticationProvider"/>
    </s:authentication-manager>


   <bean id="jdbcDaoImpl" class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl">
      <property name="dataSource" ref="dataSource"/>
   </bean>

   <bean id="daoAuthenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
      <property name="userDetailsService" ref="jdbcDaoImpl"/>
      <property name="userCache" ref="userCache"/>
      <property name="passwordEncoder">
        <bean class="org.springframework.security.authentication.encoding.Md5PasswordEncoder"/>
      </property>
   </bean>

   <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"/>

   <bean id="userCacheBackend" class="org.springframework.cache.ehcache.EhCacheFactoryBean">
      <property name="cacheManager" ref="cacheManager"/>
      <property name="cacheName" value="userCache"/>
   </bean>

   <bean id="userCache" class="org.springframework.security.core.userdetails.cache.EhCacheBasedUserCache">
      <property name="cache" ref="userCacheBackend"/>
   </bean>

   <!-- Automatically receives AuthenticationEvent messages -->
   <bean id="loggerListener" class="org.springframework.security.authentication.event.LoggerListener"/>

   <!-- ========================= "BEFORE INVOCATION" AUTHORIZATION DEFINITIONS ============================== -->

   <!-- ACL permission masks used by this application -->
   <bean id="org.springframework.security.acls.domain.BasePermission.ADMINISTRATION" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
      <property name="staticField"><value>org.springframework.security.acls.domain.BasePermission.ADMINISTRATION</value></property>
   </bean>
   <bean id="org.springframework.security.acls.domain.BasePermission.READ" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
      <property name="staticField"><value>org.springframework.security.acls.domain.BasePermission.READ</value></property>
   </bean>
   <bean id="org.springframework.security.acls.domain.BasePermission.WRITE" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
      <property name="staticField"><value>org.springframework.security.acls.domain.BasePermission.WRITE</value></property>
   </bean>


   <!-- An access decision voter that reads ROLE_* configuration settings -->
   <bean id="roleVoter" class="org.springframework.security.access.vote.RoleVoter"/>

   <!-- An access decision voter that reads ACL_ABSTRACT_ELEMENT_WRITE_PARENT configuration settings -->
   <bean id="aclAbstractElementWriteParentVoter" class="org.springframework.security.acls.AclEntryVoter">
      <constructor-arg ref="aclService"/>
      <constructor-arg value="ACL_ABSTRACT_ELEMENT_WRITE_PARENT"/>
      <constructor-arg>
          <list>
          <ref local="org.springframework.security.acls.domain.BasePermission.ADMINISTRATION"/>
          <ref local="org.springframework.security.acls.domain.BasePermission.WRITE"/>
          </list>
      </constructor-arg>
      <property name="processDomainObjectClass" value="sample.dms.AbstractElement"/>
      <property name="internalMethod" value="getParent"/>
   </bean>

   <!-- An access decision voter that reads ACL_ABSTRACT_ELEMENT_WRITE configuration settings -->
   <bean id="aclAbstractElementWriteVoter" class="org.springframework.security.acls.AclEntryVoter">
      <constructor-arg ref="aclService"/>
      <constructor-arg value="ACL_ABSTRACT_ELEMENT_WRITE"/>
      <constructor-arg>
          <list>
          <ref local="org.springframework.security.acls.domain.BasePermission.ADMINISTRATION"/>
          <ref local="org.springframework.security.acls.domain.BasePermission.WRITE"/>
          </list>
      </constructor-arg>
      <property name="processDomainObjectClass"><value>sample.dms.AbstractElement</value></property>
   </bean>

   <!-- An access decision manager used by the business objects -->
   <bean id="businessAccessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
      <property name="allowIfAllAbstainDecisions" value="true"/>
      <property name="decisionVoters">
         <list>
            <ref local="roleVoter"/>
            <ref local="aclAbstractElementWriteParentVoter"/>
            <ref local="aclAbstractElementWriteVoter"/>
         </list>
      </property>
   </bean>

   <!-- ========= ACCESS CONTROL LIST LOOKUP MANAGER DEFINITIONS ========= -->

    <bean id="aclCache" class="org.springframework.security.acls.domain.EhCacheBasedAclCache">
        <constructor-arg>
           <bean class="org.springframework.cache.ehcache.EhCacheFactoryBean">
              <property name="cacheManager">
                <bean class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"/>
              </property>
              <property name="cacheName" value="aclCache"/>
           </bean>
        </constructor-arg>
    </bean>

    <bean id="lookupStrategy" class="org.springframework.security.acls.jdbc.BasicLookupStrategy">
        <constructor-arg ref="dataSource"/>
        <constructor-arg ref="aclCache"/>
        <constructor-arg ref="aclAuthorizationStrategy"/>
        <constructor-arg>
            <bean class="org.springframework.security.acls.domain.ConsoleAuditLogger"/>
        </constructor-arg>
    </bean>

    <bean id="aclAuthorizationStrategy" class="org.springframework.security.acls.domain.AclAuthorizationStrategyImpl">
        <constructor-arg>
            <list>
                <bean class="org.springframework.security.core.authority.GrantedAuthorityImpl">
                    <constructor-arg value="ROLE_ADMINISTRATOR"/>
                </bean>
                <bean class="org.springframework.security.core.authority.GrantedAuthorityImpl">
                    <constructor-arg value="ROLE_ADMINISTRATOR"/>
                </bean>
                <bean class="org.springframework.security.core.authority.GrantedAuthorityImpl">
                    <constructor-arg value="ROLE_ADMINISTRATOR"/>
                </bean>
            </list>
        </constructor-arg>
    </bean>

    <bean id="aclService" class="org.springframework.security.acls.jdbc.JdbcMutableAclService">
        <constructor-arg ref="dataSource"/>
        <constructor-arg ref="lookupStrategy"/>
        <constructor-arg ref="aclCache"/>
    </bean>

   <!-- ============== "AFTER INTERCEPTION" AUTHORIZATION DEFINITIONS =========== -->

   <bean id="afterInvocationManager" class="org.springframework.security.access.intercept.AfterInvocationProviderManager">
      <property name="providers">
         <list>
            <ref local="afterAclCollectionRead"/>
         </list>
      </property>
   </bean>

   <!-- Processes AFTER_ACL_COLLECTION_READ configuration settings -->
   <bean id="afterAclCollectionRead" class="org.springframework.security.acls.afterinvocation.AclEntryAfterInvocationCollectionFilteringProvider">
      <constructor-arg ref="aclService"/>
      <constructor-arg>
          <list>
          <ref local="org.springframework.security.acls.domain.BasePermission.ADMINISTRATION"/>
          <ref local="org.springframework.security.acls.domain.BasePermission.READ"/>
          </list>
      </constructor-arg>
   </bean>

   <!-- ================= METHOD INVOCATION AUTHORIZATION ==================== -->

   <bean id="methodSecurityAdvisor" class="org.springframework.security.access.intercept.aopalliance.MethodSecurityMetadataSourceAdvisor" autowire="constructor"/>

   <bean id="methodSecurityInterceptor" class="org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor">
      <property name="authenticationManager"><ref bean="authenticationManager"/></property>
      <property name="accessDecisionManager"><ref local="businessAccessDecisionManager"/></property>
      <property name="afterInvocationManager"><ref local="afterInvocationManager"/></property>
      <property name="securityMetadataSource">
         <value>
            sample.dms.DocumentDao.create=ACL_ABSTRACT_ELEMENT_WRITE_PARENT
            sample.dms.DocumentDao.delete=ACL_ABSTRACT_ELEMENT_WRITE
            sample.dms.DocumentDao.update=ACL_ABSTRACT_ELEMENT_WRITE
            sample.dms.DocumentDao.findElements=AFTER_ACL_COLLECTION_READ
            sample.dms.secured.SecureDocumentDao.getUsers=ROLE_USER
         </value>
      </property>
   </bean>

</beans>
