Wednesday 23 October 2013

Authenticate user without password in alfresco

Hello everyone !

This one is really interesting.

You may come across a scenario where you do not want to use alfresco's username and password based authentication. Instead you are having some custom property set on user for example PIN number and want to do user's authentication against this PIN OR you do not want to use any authentication subsystem and want to do the user authentication against a database table. Authentication based on custom property is not available out-of-the-box in alfresco.

Here I am providing the details about the implementation approach in case you ever come across such scenario.

Okay ! here it goes !

Consider a scenario, wherein you want to do the authentication based on username and PIN (user's custom property) instead of password and retrive the ticket for further webscript calls.
This is not possible out-of-the-box in alfresco.

In out-of-the-box, you can use login webscript passing username and password to get the ticket.
Also, unless user is authenticated, you can not get user's metadata.

Following is the implementation detail to achieve user authentication without password.
1. Create a custom login webscript, which will take username and PIN as the input parameter.

2. Make sure you have set the <authentication>none</authentication> in the description file of this webcript.

3. Now, in your webscript controller (either java/javascript), first set the authentication to system user and search for the user with the given name. Once user is retrieved, get the PIN number of the user. Clear the system user authentication.

4. Match the retrived PIN with the webscript input parameter PIN. If both matches then here comes the main step. Using AuthenticationUtil.setRunAsUser(username), set the authentication for current user.

5. In order to retrieve the ticket, use following - authenticationService.getCurrentTicket() and populate the model object to return ticket as webscript response.

6. Then next step is to clear the security context using below - AuthenticationUtil.clearCurrentSecurityContext();

By implementing above, you should retrieve the ticket for the given user.

You can also validate the ticket by calling out-of-the-box loginticket webscript to determine that if the ticket belongs to the given user only or not.

Hope this one will be helpful to you.

Thanks,

8 comments:

  1. Hello,

    Very useful

    I applied it and I have a "Unable to retrieve user from repository" "Unable to create user - failed to retrieve user metadata"

    After I got the ticket I did in share:
    connector.getConnectorSession().setParameter(AlfrescoAuthenticator.CS_PARAM_ALF_TICKET, ticket);
    session.setAttribute(UserFactory.SESSION_ATTRIBUTE_KEY_USER_ID, userId);

    On the server webscript I have as you told:
    AuthenticationUtil.setRunAsUser(userName);
    String tempTicket = authenticationService.getCurrentTicket();
    result = "success";
    model.put("ticket", tempTicket);
    model.put("errormessage","");
    AuthenticationUtil.clearCurrentSecurityContext();

    Do I miss something?

    Thank you
    Jamil

    ReplyDelete
    Replies
    1. Thank you Jamil. Not sure if I have understood your question here. However, it looks like the following step is missed. In server webscript, first run with system user and search for the user. Once user is received then set run as user. It would be helpful if you could provide more details about the whole scenario and what exactly you are trying to do? Hope this helps.

      Delete
    2. Hi Ramesh,

      I did all what you mentioned and ticket received successfully
      Boolean userFound = AuthenticationUtil.runAs(new AuthenticationUtil.RunAsWork() {
      public Boolean doWork() throws Exception {
      Set peopleWithUserName = m_personService.getPeopleFilteredByProperty(ContentModel.PROP_USERNAME, userName, 10);
      if (peopleWithUserName.size() > 0) {
      return Boolean.TRUE;
      }
      return Boolean.FALSE;
      }
      }, authenticationComponent.getSystemUserName());

      if(userFound.booleanValue()){
      AuthenticationUtil.setRunAsUser(userName);
      String tempTicket = authenticationService.getCurrentTicket();
      result = "success";
      model.put("ticket", tempTicket);
      model.put("errormessage","");
      AuthenticationUtil.clearCurrentSecurityContext();
      }

      I want to login without using a password

      Jamil

      Delete
    3. It means your repo web script is working fine and you are facing issue while login with the retrieved ticket. Is that correct? Are you using Alfresco Share or a custom UI? If you are using Alfresco Share then you may have to customize its login process to point to your custom web script which provides the ticket and everything should work as it is. Hope this helps.

      Delete
  2. Hi Ramesh,

    Yes ticket is the good one and when I passed it as param in any repo service call I got the right response.

    I using Alfresco Share and customizing the login process. With the help of your blog "Behind the scenes of Alfresco Share Login page..." I override the method handleRequestInternal and inside it I am calling the webscript to get the ticket. My question is after I got the ticket what to do with it? to tell share it is successfully authenticated.
    I added the ticket to AlfrescoAuthenticator.CS_PARAM_ALF_TICKET parameter but still I every time I got "Unable to retrieve user from repository" from UserFactory exception

    Thank you
    Jamil

    ReplyDelete
    Replies
    1. It seems that you will probably have to debug it further to understand what exactly it does OOTB, once the ticket is retrieved with OOTB web script. In my opinion, once you invoke your custom login web script instead of OOTB one, there shouldn't be anything much you will need to change, as after all it is also returning you the ticket the way OOTB web script does. Kindly debug it further that will give you pointers. Hope this help.

      Delete
    2. OK, I found how to inject the ticket from handleRequestInternal() and it works.

      One final question please: what about the security of the webscript to get the ticket with the parameter authentication=none? is this a concern because it can be called without credentials and return the ticket? and if yes how do you think we can secure it?

      Jamil

      Delete
    3. For the custom login web script, if you are just using the username in order to retrieve the ticket then it could be a security concern. If you are fetching user details and along with it validating some unique metadata (for example PIN) then it will only return ticket if for the retrieved user the provided PIN and retrieved PIN matches. One alternate option could be you may want to send the username and PIN in some sort of encoded format and decode them in your custom web script. Hope this helps.

      Delete