AnsweredAssumed Answered

Alfresco integration with CAS with Acegi

Question asked by escaglia on Sep 7, 2006
Latest reply on Dec 18, 2006 by andrepra
Hello everybody,
we'd like to submit you the way we integrated Alfresco with our CAS, asking you for help on (at least) a couple of doubts we have.
The relevant part of web.xml we used is:


<filter>
          <filter-name>Acegi CAS Processing Filter</filter-name>
          <filter-class>net.sf.acegisecurity.util.FilterToBeanProxy</filter-class>
          <init-param>
            <param-name>targetClass</param-name>
           <param-value>net.sf.acegisecurity.util.FilterChainProxy</param-value>
          </init-param>
</filter>
       <filter-mapping>
          <filter-name>Acegi CAS Processing Filter</filter-name>
          <url-pattern>/*</url-pattern>
</filter-mapping>

The file authentication-services-context.xml we used is:


<beans>
    <!–                                                                    –>
    <!– The Acegi authentication manager.                                  –>
    <!–                                                                    –>
    <!– Provders are asked to authenticate in order.                       –>
    <!– First, is a provider that checks if an acegi authentication object –>
    <!– is already bound to the executing thread. If it is, and it is set  –>
    <!– as authenticated then no further authentication is required. If    –>
    <!– this is absent, Acegi validates the password for every method      –>
    <!– invocation, which is too CPU expensive. If we set an               –>
    <!– authentication based on a ticket etc …. or we want to set the    –>
    <!– the system user as the current user … we do not have the         –>
    <!– password. So if we have set an authentication and set it as        –>
    <!– authenticated that is sufficient to validate the user.             –>
    <!–                                                                    –>
    <!– If the authentication bound to the current thread is not set as    –>
    <!– authenticated the standard Acegi DAO Authentication provider       –>
    <!– is used to authenticate.                                           –>
    <!–                                                                    –>

   <bean id="filterChainProxy" class="net.sf.acegisecurity.util.FilterChainProxy">
      <property name="filterInvocationDefinitionSource">
         <value>
          CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
          PATTERN_TYPE_APACHE_ANT
            /faces/**=Cas2AlfrescoContextIntegrationFilter,securityEnforcementFilter
            /j_acegi_cas_security_check**=Cas2AlfrescoContextIntegrationFilter,casProcessingFilter
         </value>
      </property>
    </bean>

    <bean id="Cas2AlfrescoContextIntegrationFilter" class="org.alfresco.web.app.servlet.Cas2AlfrescoContextIntegrationFilter">
       <property name="context"><value>net.sf.acegisecurity.context.security.SecureContextImpl</value></property>
    </bean>








    <bean id="authenticationManager" class="net.sf.acegisecurity.providers.ProviderManager">
        <property name="providers">
            <list>
                <ref bean="authenticatedAuthenticationPassthroughProvider" />
                <ref bean="casAuthenticationProvider" />
            </list>
        </property>
    </bean>

   <bean id="serviceProperties" class="net.sf.acegisecurity.ui.cas.ServiceProperties">
     <property name="service"><value>http://pc29029.csi.it:8080/alfresco/j_acegi_cas_security_check</value></property>
     <property name="sendRenew"><value>false</value></property>
   </bean>
   <bean id="casProcessingFilter" class="net.sf.acegisecurity.ui.cas.CasProcessingFilter">
     <property name="authenticationManager"><ref bean="authenticationManager"/></property>
     <property name="authenticationFailureUrl"><value>/casfailed.jsp</value></property>
     <property name="defaultTargetUrl"><value>/</value></property>
     <property name="filterProcessesUrl"><value>/j_acegi_cas_security_check</value></property>
   </bean>
   <bean id="securityEnforcementFilter" class="net.sf.acegisecurity.intercept.web.SecurityEnforcementFilter">
        <property name="authenticationEntryPoint"><ref bean="casProcessingFilterEntryPoint"/></property>
      <property name="filterSecurityInterceptor" ref="filterInvocationInterceptor"/>
    </bean>

   <bean id="filterInvocationInterceptor" class="net.sf.acegisecurity.intercept.web.FilterSecurityInterceptor">
        <property name="authenticationManager"><ref bean="authenticationManager"/></property>
        <property name="accessDecisionManager"><ref bean="httpRequestAccessDecisionManager"/></property><!–<ref bean="accessDecisionManager"/></property–>
        <property name="objectDefinitionSource">
            <value>
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/**=ROLE_AUTHENTICATED
            </value>
        </property>
    </bean>
   <bean id="httpRequestAccessDecisionManager" class="net.sf.acegisecurity.vote.AffirmativeBased">
      <property name="allowIfAllAbstainDecisions"><value>false</value></property>
      <property name="decisionVoters">
         <list><ref bean="roleVoter"/></list>
      </property>
   </bean>
    <!– ~~~~~~~~~~~~~~~~~~~~ AUTHORIZATION DEFINITIONS ~~~~~~~~~~~~~~~~~~~ –>
    <!– An access decision voter that reads ROLE_* configuaration settings –>
    <!– <bean id="roleVoter" class="net.sf.acegisecurity.vote.RoleVoter"/> –>
    <!– <bean id="ACLEntryVoter" class="org.alfresco.repo.security.permissions.impl.acegi.ACLEntryVoter"/> –>
    <!– An access decision manager used by the business objects –>
   
   <bean id="casProcessingFilterEntryPoint" class="net.sf.acegisecurity.ui.cas.CasProcessingFilterEntryPoint">
     <property name="loginUrl"><value>https://cstvip01.csi.it/ssobart/login</value></property>
     <property name="serviceProperties"><ref bean="serviceProperties"/></property>
   </bean>

   <bean id="casAuthenticationProvider" class="net.sf.acegisecurity.providers.cas.CasAuthenticationProvider">
     <property name="casAuthoritiesPopulator"><ref bean="casAuthoritiesPopulator"/></property>
     <property name="casProxyDecider"><ref bean="casProxyDecider"/></property>
     <property name="ticketValidator"><ref bean="casProxyTicketValidator"/></property>
     <property name="statelessTicketCache"><ref bean="statelessTicketCache"/></property>
     <property name="key"><value>my_password_for_this_auth_provider_only</value></property>
   </bean>
   
   <bean id="casProxyTicketValidator" class="net.sf.acegisecurity.providers.cas.ticketvalidator.CasProxyTicketValidator">
     <property name="casValidate"><value>http://alessandria.cst-alessandria.csi.it/ssobart/serviceValidate</value></property>
     <property name="proxyCallbackUrl"><value>https://localhost:8443/contacts-cas/casProxy/receptor</value></property>
     <property name="serviceProperties"><ref bean="serviceProperties"/></property>
     <!– <property name="trustStore"><value>/some/path/to/your/lib/security/cacerts</value></property> –>
   </bean>
   
   <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
     <property name="configLocation">
       <value>classpath:/ehcache-failsafe.xml</value>
     </property>
   </bean>
      
   <bean id="ticketCacheBackend" class="org.springframework.cache.ehcache.EhCacheFactoryBean">
     <property name="cacheManager">
       <ref local="cacheManager"/>
     </property>
     <property name="cacheName">
       <value>ticketCache</value>
     </property>
   </bean>
     
   <bean id="statelessTicketCache" class="net.sf.acegisecurity.providers.cas.cache.EhCacheBasedTicketCache">
     <property name="cache"><ref local="ticketCacheBackend"/></property>
   </bean>
   
   <bean id="casAuthoritiesPopulator" class="net.sf.acegisecurity.providers.cas.populator.DaoCasAuthoritiesPopulator">
     <property name="authenticationDao"><ref bean="alfDaoImpl"/></property>
   </bean>
   
   <bean id="casProxyDecider" class="net.sf.acegisecurity.providers.cas.proxy.RejectProxyTickets"/>

    <bean id="inMemoryDaoImpl" class="org.alfresco.repo.security.authentication.InMemoryDaoImpl">
        <property name="userMap">
            <value>
               AAAAAA00B77B000F=***,ROLE_ADMIN
                admin=***,ROLE_ADMIN
                    gcs=***,ROLE_ADMIN
                mc=***,ROLE_ADMIN,ROLE_TELLER,ROLE_SUPERVISOR
                    peter=***,disabled,ROLE_TELLER
            </value>
        </property>
    </bean>

    <!– We provide a DAO to plug into the Acegi DaoAuthenticationProvider  –>

    <bean id="daoAuthenticationProvider" class="net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider">
        <property name="authenticationDao">
            <ref bean="authenticationDao" />
        </property>
        <property name="saltSource">
            <ref bean="saltSource" />
        </property>
        <property name="passwordEncoder">
            <ref bean="passwordEncoder" />
        </property>
    </bean>

    <!– An authentication Provider that just believes authentications      –>
    <!– bound to the local thread are valid if they are set as             –>
    <!– authenticated.                                                     –>

    <bean id="authenticatedAuthenticationPassthroughProvider" class="org.alfresco.repo.security.authentication.AuthenticatedAuthenticationPassthroughProvider" />

    <!– The authroity DAO implements an interface extended from the Acegi  –>
    <!– DAO that supports CRUD.                                            –>

    <bean id="alfDaoImpl" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
        <property name="proxyInterfaces">
            <value>org.alfresco.repo.security.authentication.MutableAuthenticationDao</value>
        </property>
        <property name="transactionManager">
            <ref bean="transactionManager" />
        </property>
        <property name="target">
            <ref bean="authenticationDao"/>
        </property>
        <property name="transactionAttributes">
            <props>
                <prop key="*">${server.transaction.mode.default}</prop>
            </props>
        </property>
    </bean>
   
    <bean id="authenticationDao" class="org.alfresco.repo.security.authentication.RepositoryAuthenticationDao">
       <property name="nodeService">
           <ref bean="nodeService" />
       </property>
       <property name="dictionaryService">
           <ref bean="dictionaryService" />
       </property>
       <property name="namespaceService">
           <ref bean="namespaceService" />
       </property>
       <property name="searchService">
           <ref bean="searchService" />
       </property>
       <property name="userNamesAreCaseSensitive">
          <value>${user.name.caseSensitive}</value>
       </property>
       <property name="passwordEncoder">
           <ref bean="passwordEncoder" />
       </property>
    </bean>

    <!– The DAO also acts as a salt provider.                              –>
   
    <alias alias="saltSource" name="alfDaoImpl"/>

    <!– Passwords are encoded using MD4                                    –>
    <!– This is not ideal and only done to be compatible with NTLM         –>
    <!– authentication against the default authentication mechanism.       –>

    <bean id="passwordEncoder" class="org.alfresco.repo.security.authentication.MD4PasswordEncoderImpl"></bean>


    <!– A transactional wrapper around the implementation.                 –>
    <!– TODO: This should be removed.                                      –>             

    <bean id="authenticationService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
        <property name="proxyInterfaces">
            <value>org.alfresco.service.cmr.security.AuthenticationService</value>
        </property>
        <property name="transactionManager">
            <ref bean="transactionManager" />
        </property>
        <property name="target">
            <ref bean="authenticationServiceImpl" />
        </property>
        <property name="transactionAttributes">
            <props>
                <prop key="*">${server.transaction.mode.default}</prop>
            </props>
        </property>
    </bean>

    <!– The Authentication Service implementation.                         –>
    <!–                                                                    –>
    <!– This delegates its work to two services:                           –>
    <!– an AuthenticationComponent and a MutableAuthenticationDAO.         –>
    <!–                                                                    –>
    <!– The permissions service is required so that permissions can be     –>
    <!– cleaned up when a user is deleted.                                 –>
   
    <bean id="authenticationServiceImpl" class="org.alfresco.repo.security.authentication.AuthenticationServiceImpl">
        <property name="authenticationDao">
            <ref bean="authenticationDao" />
        </property>
        <property name="ticketComponent">
            <ref bean="ticketComponent" />
        </property>
        <property name="authenticationComponent">
            <ref bean="authenticationComponentImpl" />
        </property>
    </bean>

    <!– A transactional wrapper that should be removed.                    –>

    <bean id="authenticationComponent" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
        <property name="proxyInterfaces">
            <value>org.alfresco.repo.security.authentication.AuthenticationComponent</value>
        </property>
        <property name="transactionManager">
            <ref bean="transactionManager" />
        </property>
        <property name="target">
            <ref bean="authenticationComponentImpl" />
        </property>
        <property name="transactionAttributes">
            <props>
                <prop key="*">${server.transaction.mode.default}</prop>
            </props>
        </property>
    </bean>

    <!– The authentication component.                                      –>

    <bean id="authenticationComponentImpl" class="org.alfresco.repo.security.authentication.AuthenticationComponentImpl">
        <property name="authenticationDao">
            <ref bean="authenticationDao" />
        </property>
        <property name="authenticationManager">
            <ref bean="authenticationManager" />
        </property>
        <property name="allowGuestLogin">
            <value>true</value>
        </property>
    </bean>

   
    <!– Simple Authentication component that rejects all authentication requests –>
    <!– Use this defintion for Novell IChain integration.                        –>
    <!– It should never go to the login screen  so this is not required          –>
    <!– (Enterprise version only)                                                –>
   
    <!–
    <bean id="authenticationComponentImpl" class="org.alfresco.repo.security.authentication.SimpleAcceptOrRejectAllAuthenticationComponentImpl">
    </bean>
    –>



    <!– The person service.                                                –>

    <bean id="personService" class="org.alfresco.repo.security.person.PersonServiceImpl">
      <property name="nodeService">
          <ref bean="nodeService" />
      </property>
      <property name="searchService">
          <ref bean="searchService" />
      </property>
      <property name="permissionServiceSPI">
         <ref bean="permissionServiceImpl" />
      </property>
        <property name="authorityService">
           <ref bean="authorityService" />
        </property>
      <property name="namespacePrefixResolver">
         <ref bean="namespaceService" />
      </property>
        <!– Configurable properties.                                 –>
        <!–                                                          –>
        <!– TODO:                                                    –>
        <!– Add support for creating real home spaces adn setting    –>
        <!– permissions on the hame space and people created.        –>
        <!–                                                          –>
        <!– The store in which people are persisted.                 –>
        <property name="storeUrl">
           <value>${spaces.store}</value>
        </property>
        <!– The path to the company home space, used to set the      –>
        <!– default home space for users that are created if         –>
        <!– missing.                                                 –>
        <property name="companyHomePath">
           <value>/${spaces.company_home.childname}</value>
        </property>
        <!– Some authentication mechanisms may need to create people –>
        <!– in the repository on demand. This enables that feature.  –>
        <!– If dsiabled an error will be generated for missing       –>
        <!– people. If enabled then a person will be created and     –>
        <!– persisted.                                               –>
        <!–                                                          –>
        <!– This value should be false or only true if the           –>
        <!– repository is mutable; set from the property             –>
        <!– ${server.transaction.allow-writes}                       –>
        <property name="createMissingPeople">
           <value>${server.transaction.allow-writes}</value>
        </property>
        <!– Set is user names are case sensitive - taken from the    –>
        <!– repository wide setting - you are advised not to change  –>
        <!– this setting.                                            –>
        <!– This value should be ${user.name.caseSensitive}          –>
        <property name="userNamesAreCaseSensitive">
           <value>${user.name.caseSensitive}</value>
        </property>
    </bean>

    <!– The ticket component.                                              –>
    <!– Used for reauthentication                                          –>
    <bean id="ticketComponent" class="org.alfresco.repo.security.authentication.InMemoryTicketComponentImpl">
        <!– The period for which tickets are valid in XML duration format. –>
        <!– The default is P1H for one hour.                               –>
        <property name="validDuration">
            <value>P1H</value>
        </property>
        <!– Do tickets expire or live for ever?                            –>
        <property name="ticketsExpire">
            <value>false</value>
        </property>
        <!– Are tickets only valid for a single use?                       –>
        <property name="oneOff">
            <value>false</value>
        </property>
    </bean>
   
</beans>


We used the class FilterToBeanProxy to make spring load the class FilterChainProxy which can apply a filter chain.

We used the filter Cas2AlfrescoContextIntegrationFilter which extends from net.sf.acegisecurity.context.HttpSessionContextIntegrationFilter to put into session the object ACEGI_SECURITY_CONTEXT and the ticket _alfAuthTicket.
ACEGI_SECURITY_CONTEXT is a SecureContextImpl containing as a property CasAuthenticationToken, result of the Cas authentication process. _alfAuthTicket instead contains org.alfresco.web.bean.repository.User, object required by Alfresco after authentication.

We didn't use InMemoryDaoImpl but we used Alfresco alfDaoImpl bean as the Alfresco user store. This means that a user, beside existing in the Cas repository, must be priorly created by an admin user in Alfresco.
First question: is there a way to force user creation at first login?

Here is the code of our class:
Cas2AlfrescoContextIntegrationFilter

package org.alfresco.web.app.servlet;



import net.sf.acegisecurity.context.Context;

import net.sf.acegisecurity.context.ContextHolder;

import net.sf.acegisecurity.context.security.SecureContextImpl;



import org.alfresco.model.ContentModel;

import org.alfresco.service.ServiceRegistry;

import org.alfresco.service.cmr.repository.NodeRef;

import org.alfresco.service.cmr.repository.NodeService;

import org.alfresco.service.cmr.security.AuthenticationService;

import org.alfresco.service.cmr.security.PersonService;

import org.alfresco.service.transaction.TransactionService;

import org.alfresco.web.bean.repository.User;

import org.apache.commons.logging.Log;

import org.apache.commons.logging.LogFactory;

import org.springframework.web.context.WebApplicationContext;

import org.springframework.web.context.support.WebApplicationContextUtils;



import java.io.IOException;



import javax.servlet.FilterChain;

import javax.servlet.ServletException;

import javax.servlet.ServletRequest;

import javax.servlet.ServletResponse;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpSession;

import javax.transaction.UserTransaction;





public class Cas2AlfrescoContextIntegrationFilter extends net.sf.acegisecurity.context.HttpSessionContextIntegrationFilter {

    //~ Static fields/initializers =============================================



    protected static final Log logger = LogFactory.getLog(Cas2AlfrescoContextIntegrationFilter.class);

    private static final String FILTER_APPLIED = "__acegi_session_integration_filter_applied";

    public static final String ACEGI_SECURITY_CONTEXT_KEY = "ACEGI_SECURITY_CONTEXT";

    public static final String ALF_SECURITY_CONTEXT_KEY = "_alfAuthTicket";



    //~ Instance fields ========================================================



    private Object contextObject;



    /**

     * Indicates if this filter can create a HttpSession if needed

     * (sessions are always created sparingly, but setting this value to false

     * will prohibit sessions from ever being created). Defaults to true.

     */

    private boolean allowSessionCreation = true;



    //~ Methods ================================================================



    public void doFilter(ServletRequest request, ServletResponse response,

        FilterChain chain) throws IOException, ServletException {

        if ((request != null) && (request.getAttribute(FILTER_APPLIED) != null)) {

            // ensure that filter is only applied once per request

            chain.doFilter(request, response);

        } else {

            if (request != null) {

                request.setAttribute(FILTER_APPLIED, Boolean.TRUE);

            }



            if (ContextHolder.getContext() != null) {

                if (logger.isWarnEnabled()) {

                    logger.warn(

                        "ContextHolder should have been null but contained: '"

                        + ContextHolder.getContext() + "'; setting to null now");

                }



                ContextHolder.setContext(null);

            }



            HttpSession httpSession = null;

            boolean httpSessionExistedAtStartOfRequest = false;



            try {

                httpSession = ((HttpServletRequest) request).getSession(false);

            } catch (IllegalStateException ignored) {}



            if (httpSession != null) {

                httpSessionExistedAtStartOfRequest = true;



                Object contextObject = httpSession.getAttribute(ACEGI_SECURITY_CONTEXT_KEY);



                if (contextObject != null) {

                    if (contextObject instanceof Context) {

                        if (logger.isDebugEnabled()) {

                            logger.debug(

                                "Obtained from ACEGI_SECURITY_CONTEXT a valid Context and set to ContextHolder: '"

                                + contextObject + "'");

                        }



                        ContextHolder.setContext((Context) contextObject);

                    } else {

                        if (logger.isWarnEnabled()) {

                            logger.warn(

                                "ACEGI_SECURITY_CONTEXT did not contain a Context but contained: '"

                                + contextObject

                                + "'; are you improperly modifying the HttpSession directly (you should always use ContextHolder) or using the HttpSession attribute reserved for this class?");

                        }

                    }

                } else {

                    if (logger.isDebugEnabled()) {

                        logger.debug(

                            "HttpSession returned null object for ACEGI_SECURITY_CONTEXT");

                    }

                }

            } else {

                if (logger.isDebugEnabled()) {

                    logger.debug("No HttpSession currently exists");

                }

            }



            if (ContextHolder.getContext() == null) {

                ContextHolder.setContext(generateNewContext());



                if (logger.isDebugEnabled()) {

                    logger.debug(

                        "As ContextHolder null, setup ContextHolder with a fresh new instance: '"

                        + ContextHolder.getContext() + "'");

                }

            }



            // Make the HttpSession null, as we want to ensure we don't keep

            // a reference to the HttpSession laying around in case the

            // chain.doFilter() invalidates it.

            httpSession = null;



            // Proceed with chain

            chain.doFilter(request, response);



            // Store context back to HttpSession

            try {

                httpSession = ((HttpServletRequest) request).getSession(false);

            } catch (IllegalStateException ignored) {}



            if ((httpSession == null) && httpSessionExistedAtStartOfRequest) {

                if (logger.isDebugEnabled()) {

                    logger.debug(

                        "HttpSession is now null, but was not null at start of request; session was invalidated, so do not create a new session");

                }

            }



            // Generate a HttpSession only if we need to

            if ((httpSession == null) && !httpSessionExistedAtStartOfRequest) {

                if (!allowSessionCreation) {

                    if (logger.isDebugEnabled()) {

                        logger.debug(

                            "Whilst ContextHolder contents have changed, the HttpSessionContextIntegrationFilter is prohibited from creating a HttpSession by the allowSessionCreation property being false");

                    }

                } else if (!contextObject.equals(ContextHolder.getContext())) {

                    if (logger.isDebugEnabled()) {

                        logger.debug(

                            "HttpSession being created as ContextHolder contents are non-default");

                    }



                    try {

                        httpSession = ((HttpServletRequest) request).getSession(true);

                    } catch (IllegalStateException ignored) {}

                } else {

                    if (logger.isDebugEnabled()) {

                        logger.debug(

                            "HttpSession still null, but ContextHolder has not changed from default: ' "

                            + ContextHolder.getContext()

                            + "'; not creating HttpSession or storing ContextHolder contents");

                    }

                }

            }



            // If HttpSession exists, store current ContextHolder contents

            if (httpSession != null) {

                httpSession.setAttribute(ACEGI_SECURITY_CONTEXT_KEY,

                    ContextHolder.getContext());



                if (logger.isDebugEnabled()) {

                    logger.debug("Context stored to HttpSession: '"

                        + ContextHolder.getContext() + "'");

                }

                SecureContextImpl sec_context = (SecureContextImpl)ContextHolder.getContext();

                if (sec_context != null && (sec_context.getAuthentication() != null)) {

                    //String username = ((UserDetails)sec_context.getAuthentication().getDetails()).getUsername().substring(0,16);

                    String username = (String)sec_context.getAuthentication().getPrincipal();

                    User alfuser = null;

                    WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(httpSession.getServletContext());

                    ServiceRegistry serviceRegistry = (ServiceRegistry) ctx.getBean(ServiceRegistry.SERVICE_REGISTRY);

                    AuthenticationService authService = (AuthenticationService) ctx.getBean("authenticationService");

                    TransactionService transactionService = serviceRegistry.getTransactionService();

                    UserTransaction tx = transactionService.getUserTransaction();

                    PersonService personService = (PersonService)ctx.getBean("personService");

               

                    try {

                  tx.begin();

                  //personService.setCreateMissingPeople(true);

                  String currentTicket = authService.getCurrentTicket();

                        alfuser =  new User(username,currentTicket,personService.getPerson(username));

                        NodeService nodeService = serviceRegistry.getNodeService();

                        //personService.setCreateMissingPeople(false);

                        NodeRef homeSpaceRef = (NodeRef) nodeService.getProperty(personService.getPerson(username),

                                ContentModel.PROP_HOMEFOLDER);

                        alfuser.setHomeSpaceId(homeSpaceRef.getId());

                        tx.commit();

               } catch (Throwable ex) {

                  logger.error(ex);



                  try {

                     tx.rollback();

                  } catch (Exception ex2) {

                     logger.error(

                           "Failed to rollback transaction",

                           ex2);

                  }



                  if (ex instanceof RuntimeException) {

                     throw (RuntimeException) ex;

                  } else {

                     throw new RuntimeException(

                           "Failed to set authenticated user",

                           ex);

                  }

               }

                    httpSession.setAttribute(ALF_SECURITY_CONTEXT_KEY,alfuser);

                }


            }



            // Remove ContextHolder contents

            ContextHolder.setContext(null);



            if (logger.isDebugEnabled()) {

                logger.debug(

                    "ContextHolder set to null as request processing completed");

            }

        }

    }

}

Second question: we had to change the class org.alfresco.repo.security.permissions.impl.PermissionServiceImpl.java at line 444 in method getAuthorizations to avoid a classCastExceptionError:

java.lang.ClassCastException: java.lang.String
        at org.alfresco.repo.security.permissions.impl.PermissionServiceImpl.getAuthorisations(PermissionServiceImpl.java:444)
        at org.alfresco.repo.security.permissions.impl.PermissionServiceImpl.hasPermission(PermissionServiceImpl.java:363)
        at org.alfresco.repo.security.permissions.impl.PermissionServiceImpl.hasPermission(PermissionServiceImpl.java:582)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:585)
        at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:335)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:181)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:148)
        at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:170)
        at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:176)
        at $Proxy64.hasPermission(Unknown Source)
        at org.alfresco.repo.security.permissions.impl.acegi.ACLEntryVoter.vote(ACLEntryVoter.java:316)
        at net.sf.acegisecurity.vote.AffirmativeBased.decide(AffirmativeBased.java:69)
        at net.sf.acegisecurity.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:394)
        at net.sf.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor.invoke(MethodSecurityInterceptor.java:77)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:170)
        at org.alfresco.repo.security.permissions.impl.ExceptionTranslatorMethodInterceptor.invoke(ExceptionTranslatorMethodInterceptor.java:40)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:170)
        at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:170)
        at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:176)
        at $Proxy66.getProperty(Unknown Source)
at org.alfresco.web.app.servlet.Cas2AlfrescoContextIntegrationFilter.doFilter(Cas2AlfrescoContextIntegrationFilter.java:275)
  …

This is due, for what we can understand, to a mismatch between line 201 of casAuthenticationProvider, which state

return new CasAuthenticationToken(this.key, response.getUser(),

            authentication.getCredentials(), userDetails.getAuthorities(),

            userDetails, response.getProxyList(),

            response.getProxyGrantingTicketIou());
(note the second parameter response.getUser which returns a String)
and line 444 of org.alfresco.repo.security.permissions.impl.PermissionServiceImpl.java where auth is of type CasAuthenticationToken and so auth.getPrincipal() returns a String and cannot be casted to User (see code inside constructor of CasAuthenticationToken.
To solve this problem we changed method getAuthorisations in PermissionServiceImpl.java this way:

    private Set<String> getAuthorisations(Authentication auth, NodeRef nodeRef)

    {

        HashSet<String> auths = new HashSet<String>();

        // No authenticated user then no permissions

        if (auth == null)

        {

            return auths;

        }

        // TODO: Refactor and use the authentication service for this.

        //User user = (User) auth.getPrincipal();

       

        //auths.add(user.getUsername());

        auths.add((String)auth.getPrincipal());

        for (GrantedAuthority authority : auth.getAuthorities())

        {

            auths.add(authority.getAuthority());

        }

        if (dynamicAuthorities != null)

        {

            for (DynamicAuthority da : dynamicAuthorities)

            {

//               if (da.hasAuthority(nodeRef, user.getUsername()))

               if (da.hasAuthority(nodeRef,(String)auth.getPrincipal()))

                {

                    auths.add(da.getAuthority());

                }

            }

        }

        auths.addAll(authorityService.getAuthorities());

        return auths;

    }

Does it seem meaningful or we missed the all thing?javascript:emoticon(':D')
Thank you in advance for your help?

Davide & Emanuele

Outcomes