Friday, November 1, 2013

Custom alfresco authentication by extending default authentication

Step 1 : Add following line in alfresco-global.properties file located at /alfresco/tomcat/shared/classes location.

authentication.chain=yamaha:yamaha

Step 2 : create new folder test at alfresco/tomcat/webapps/alfresco/WEB-INF/classes/alfresco/subsystems/Authentication location.

Step 3 : create new file test-authentication.properties in test folder created with following content.


external.authentication.defaultAdministratorUserNames=admin


Step 3 : Create new file test-authentication-context.xml in same test folder with following content.

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'>
<beans>
   <bean id="authenticationComponent" class="org.alfresco.repo.security.authentication.test.TestCustomAuthenticationImpl"
      parent="authenticationComponentBase">
      <property name="nodeService">
         <ref bean="nodeService" />
      </property>
      <property name="personService">
         <ref bean="personService" />
      </property>
      <property name="transactionService">
         <ref bean="transactionService" />
      </property>
      <property name="defaultAdministratorUserNameList">
         <value>${external.authentication.defaultAdministratorUserNames}</value>
      </property>
   </bean>

   <!-- Wrapped version to be used within subsystem -->
   <bean id="AuthenticationComponent" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
      <property name="proxyInterfaces">
         <list>
            <value>org.alfresco.repo.security.authentication.AuthenticationComponent</value>
         </list>
      </property>
      <property name="transactionManager">
         <ref bean="transactionManager" />
      </property>
      <property name="target">
         <ref bean="authenticationComponent" />
      </property>
      <property name="transactionAttributes">
         <props>
            <prop key="*">${server.transaction.mode.default}</prop>
         </props>
      </property>
   </bean>

   <!-- Authentication service for chaining -->
   <bean id="localAuthenticationService" class="org.alfresco.repo.security.authentication.AuthenticationServiceImpl">
      <property name="ticketComponent">
         <ref bean="ticketComponent" />
      </property>
      <property name="authenticationComponent">
         <ref bean="authenticationComponent" />
      </property>
      <property name="sysAdminParams">
         <ref bean="sysAdminParams" />
      </property>
   </bean>
</beans>


Step 4 : Create new file test-filter.properties in same test folder with following content.

external.authentication.proxyUserName=alfresco-system
external.authentication.proxyHeader=X-Alfresco-Remote-User
external.authentication.enabled=true
external.authentication.userIdPattern=


Step 5 : Create new file test-filter-context.xml in same test folder with following content.


<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'>
<beans>

   <!-- Enable control over mapping between request and user ID -->
   <bean id="remoteUserMapper" class="org.alfresco.web.app.servlet.DefaultRemoteUserMapper">
      <property name="proxyUserName">
         <value>${external.authentication.proxyUserName}</value>
      </property>
      <property name="proxyHeader">
         <value>${external.authentication.proxyHeader}</value>
      </property>
      <property name="active">
         <value>${external.authentication.enabled}</value>
      </property>
      <property name="userIdPattern">
         <value>${external.authentication.userIdPattern}</value>
      </property>
      <property name="personService">
         <ref bean="PersonService" />
      </property>
   </bean>

   <!-- Enable cookie-based handling of webscript logins. We must assume cookie based client authentication when external auth is in the chain. -->
   <bean id="webscriptAuthenticationFilter" class="org.alfresco.web.app.servlet.WebScriptSSOAuthenticationFilter">
      <property name="active">
         <value>true</value>
      </property>
      <property name="authenticationService">
         <ref bean="AuthenticationService" />
      </property>
      <property name="authenticationComponent">
         <ref bean="AuthenticationComponent" />
      </property>
      <property name="personService">
         <ref bean="personService" />
      </property>
      <property name="nodeService">
         <ref bean="NodeService" />
      </property>
      <property name="transactionService">
         <ref bean="TransactionService" />
      </property>
      <property name="container">
         <ref bean="webscripts.container" />
      </property>
   </bean>

</beans>


Step 5 : create new java project in eclipse with any name you want.

Step 6 : create package with name org.alfresco.repo.security.authentication.test in src folder.

Step 7 : Create java class TestCustomAuthenticationImpl.java with following content in same package created.


/**
 * Project Name : Alfresco Custom Authentication
 * ---------------------
 * @author      Sourabh Aggarwal
 * -----------------------------------------------------------------------------------
 * -----------------------------------------------------------------------------------
 */
package org.alfresco.repo.security.authentication.test;

import in.co.ymsli.sedocs.rest.client.ISeDocsRestClient;
import in.co.ymsli.sedocs.rest.client.dto.auth.ValidateTokenDTO;
import in.co.ymsli.sedocs.rest.client.impl.SeDocsRestClientImpl;
import net.sf.acegisecurity.Authentication;

import org.alfresco.repo.security.authentication.AbstractAuthenticationComponent;
import org.alfresco.repo.security.authentication.AuthenticationException;


/**
 * @author Sourabh Aggarwal
 *
 */
public class TestCustomAuthenticationImpl extends AbstractAuthenticationComponent
{


public void authenticateImpl(String userName, char[] password) throws AuthenticationException
{
System.out.println("userName = "+userName + " ::::::::::::::: password = "+String.valueOf(password));
             if(userName == "abc"){
setCurrentUser(oValidateTokenDTO.getUserName());
              }else{

System.out.println("Error calling login service");
throw new AuthenticationException("Unable to authentication");

                   }

}

/**
* The default is not to support Authentication token base authentication
*/
public Authentication authenticate(Authentication token) throws AuthenticationException
{

System.out.println("authenticating vi vi token");
//throw new AlfrescoRuntimeException("Authentication via token not supported");

return token;
}

@Override
protected boolean implementationAllowsGuestLogin() {
// TODO Auto-generated method stub
return false;
}
}


Step 8 : Import all library from alfresco/tomcat/webapps/alfresco/WEB-INF/lib folder.

Step 9 : create jar of java project and place it in alfresco/tomcat/webapps/alfresco/WEB-INF/lib folder.

Step 10: restart server.

Step 11 : its done.

Step 12 : only abc user with any password can login.





5 comments:

  1. i tried but it doesnt' work. in the global.properties file i write authentication.chain=test:test and i receive this error:
    .....tomcat\webapps\alfresco\WEB-INF\classes\alfresco\subsystems\Authentication\test\test-authentication-context.xml] is invalid; nested exception is org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 7; The processing instruction target matching "[xX][mM][lL]" is not allowed.
    at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:396)

    ReplyDelete
  2. Thanks for such a great help, it works with little effort i needed to provide authentication utilising remote server so my authenticateImpl which calls over service and gets back token. I dont know where to store this token to be able to get it back again later in the process.

    What about Authorization, athentication allows my users to log in, but obviously they are not authorized to do certain activities, what are the best possible options in your opinion.

    ReplyDelete
  3. Can you share the code please? is valid the example uin version alfresco community 4.2? thanks a lot for your help

    ReplyDelete
  4. I am testing this right now on 5.0.d.

    First to mention: the package of DefaultRemoteUserMapper has changed from org.alfresco.web.app.servlet.DefaultRemoteUserMapper to org.alfresco.repo.security.authentication.external.DefaultRemoteUserMapper.

    However I can't get it to work yet. I added the custom authentication as described, I can startup Alfresco & Share without any errors, but even upon login into Share (or Alfresco), I don't even see anything getting logged (packages all set to debug in log4j.properties). Just nothing happens...

    I do see one relevant line in the Share log though, which says:

    INFO [org.alfresco.web.site.servlet.SSOAuthenticationFilter] [localhost-startStop-1] SSOAuthenticationFilter initialised.
    but that's about it.

    and this in the repository log:
    2015-07-27 16:12:29,139 INFO [org.alfresco.repo.management.subsystems.ChildApplicationContextFactory] [localhost-startStop-1] Starting 'Authentication' subsystem, ID: [Authentication, managed, yamaha1]
    2015-07-27 16:12:29,179 INFO [org.alfresco.repo.management.subsystems.ChildApplicationContextFactory] [localhost-startStop-1] Startup of 'Authentication' subsystem, ID: [Authentication, managed, yamaha1] complete

    (Note - I have set it like this: authentication.chain=yamaha1:yamaha)

    ReplyDelete
  5. Update: ok, I got it working now :) I setup the custom authentication on a fresh system, cause the previous one I used was already configured to SSO with an AD/Kerberos. I guess there were some conflicts with the entire configuration, so I decided to give the external auth a try on a new system (5.0.d). Thanks for the blog post, was very helpful, since external authentication isn't well documented in the Alfresco Docs at all.

    ReplyDelete