<?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 https://www.springframework.org/schema/beans/spring-beans.xsd
						http://www.springframework.org/schema/security https://www.springframework.org/schema/security/spring-security.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="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="passwordEncoder">
		<bean class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/>
	  </property>
   </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"/>
   </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"/>
   </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"/>
   </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 bean="org.springframework.security.acls.domain.BasePermission.ADMINISTRATION"/>
		  <ref bean="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 bean="org.springframework.security.acls.domain.BasePermission.ADMINISTRATION"/>
		  <ref bean="org.springframework.security.acls.domain.BasePermission.WRITE"/>
		  </list>
	  </constructor-arg>
	  <property name="processDomainObjectClass" value="sample.dms.AbstractElement"/>
   </bean>

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

   <!-- ========= ACCESS CONTROL LIST LOOKUP MANAGER DEFINITIONS ========= -->
	<bean id="cacheManager" class="org.springframework.cache.concurrent.ConcurrentMapCacheManager"/>
	
	<bean id="userCacheBackend" class="org.springframework.cache.concurrent.ConcurrentMapCache">
		<constructor-arg name="name" value="userCache"/>
	</bean>

	<bean id="aclCache" class="org.springframework.security.acls.domain.SpringCacheBasedAclCache">
		<constructor-arg name="cache" ref="userCacheBackend"/>
		<constructor-arg>
			<bean class="org.springframework.security.acls.domain.DefaultPermissionGrantingStrategy">
				<constructor-arg>
					<bean class="org.springframework.security.acls.domain.ConsoleAuditLogger"/>
				</constructor-arg>
			</bean>
		</constructor-arg>
		<constructor-arg>
			<bean class="org.springframework.security.acls.domain.AclAuthorizationStrategyImpl">
				<constructor-arg>
					<list>
						<bean class="org.springframework.security.core.authority.SimpleGrantedAuthority">
							<constructor-arg value="ROLE_ACL_ADMIN"/>
						</bean>
					</list>
				</constructor-arg>
			</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.SimpleGrantedAuthority">
					<constructor-arg value="ROLE_ADMINISTRATOR"/>
				</bean>
				<bean class="org.springframework.security.core.authority.SimpleGrantedAuthority">
					<constructor-arg value="ROLE_ADMINISTRATOR"/>
				</bean>
				<bean class="org.springframework.security.core.authority.SimpleGrantedAuthority">
					<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 bean="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 bean="org.springframework.security.acls.domain.BasePermission.ADMINISTRATION"/>
		  <ref bean="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">
	   <constructor-arg value="methodSecurityInterceptor" />
	   <constructor-arg ref="msmds" />
	   <constructor-arg value="msmds" />
   </bean>

   <bean id="methodSecurityInterceptor" class="org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor">
	  <property name="authenticationManager" ref="authenticationManager"/>
	  <property name="accessDecisionManager" ref="businessAccessDecisionManager"/>
	  <property name="afterInvocationManager" ref="afterInvocationManager"/>
	  <property name="securityMetadataSource" ref="msmds" />
   </bean>

   <s:method-security-metadata-source id="msmds">
	  <s:protect method="sample.dms.DocumentDao.create" access="ACL_ABSTRACT_ELEMENT_WRITE_PARENT" />
	  <s:protect method="sample.dms.DocumentDao.delete" access="ACL_ABSTRACT_ELEMENT_WRITE" />
	  <s:protect method="sample.dms.DocumentDao.update" access="ACL_ABSTRACT_ELEMENT_WRITE" />
	  <s:protect method="sample.dms.DocumentDao.findElements" access="AFTER_ACL_COLLECTION_READ" />
	  <s:protect method="sample.dms.secured.SecureDocumentDao.getUsers" access="ROLE_USER" />
   </s:method-security-metadata-source>

</beans>
