2

I need to login the user in Liferay by authenticating against an external system. However, I still need to have a valid Liferay session. So, I need to login to Liferay by

  1. Asking the username/password from the user
  2. Use them to authenticate against the external system.
  3. Use just the username (not the password) to authenticate against the Liferay login.
  4. Log the user in , if the external system login is successful.

I did few things:

  1. Auto login
  2. Hooks to UserLocalService.authenticateByScreenName override
  3. auth.pipeline pre and check = false
  4. LoginFilter .

These did not work. Here is an explanation of these approaches. The idea is to include //Call external system to authenticate will be included if these methods work. Please correct where I m making the mistake and if some approach is better compared to other.

1. Autologin:

a. Set portal-ext.properties

 auto.login.hooks=com.poc.AutoLoginFil

b. Create a class

public class AutoLoginFilter implements AutoLogin {

    public AutoLoginFilter() {
        super();
    }

    @Override
    public String[] login(HttpServletRequest req, HttpServletResponse arg1) throws AutoLoginException {

//Call external system to authenticate 
        User user =  UserLocalServiceUtil.getUserByScreenName(company.getCompanyId(), login);
         credentials[0] = String.valueOf(user.getUserId());

        credentials[1] = "undefined";
        credentials[2] = Boolean.TRUE.toString();

            return credentials;
    }
}

c. Deploy the plugin project, restart the server and go to http: //localhost:8080/web/guest/home . This should log in as joebloggs

This did not work

2. Hooks to UserLocalService.authenticateByScreenName override

a. In liferay-hook.xml

<service>
        <service-type>
            com.liferay.portal.service.UserLocalService
        </service-type>
        <service-impl>
            com.test.UserService
        </service-impl>
    </service>

b. Extend UserLocalServiceWrapper and use the custom class.

public class UserService  extends  UserLocalServiceWrapper
{

@Override
    public int authenticateByScreenName(long companyId, String screenName, String password, Map headerMap, Map parameterMap, Map resultsMap)
    {
//Call external system to authenticate 
        String name = "";
        log.info(screenName);
        return SUCCESS;
    }

}

When I login, it should work with any password. It does not.

3. auth.pipeline pre and check = false

a. In portal-ext.properties

auth.pipeline.enable.liferay.check=false
auth.pipeline.pre=com.test.AutoLoginCustom

b. Then, in

public class AutoLoginCustom implements AutoLogin
{

@Override
public String[] login(HttpServletRequest arg0, HttpServletResponse arg1)
            throws AutoLoginException {

@Override
    public String[] login(HttpServletRequest arg0, HttpServletResponse arg1)
{
//Call external system to authenticate 
  credentials[0] = "joebloggs";

        credentials[1] = "undefined";
        credentials[2] = Boolean.TRUE.toString();

            return credentials;
}

c. Deploy the project and restart the server. Go to http://localhost:8080/web/guest/home. Login using username and different password. It does not login. It does not even hit the debug point in the AutoLoginCustom java.

4. LoginFilter In the liferay-hook.xml,

<servlet-filter>
        <servlet-filter-name>Login</servlet-filter-name>
        <servlet-filter-impl>com.test.AutoLoginFilter</servlet-filter-impl>
    </servlet-filter>

In AutoLoginFilter

public class AutoLoginFil implements Filter
{

    @Override
    public void doFilter(ServletRequest arg0, ServletResponse arg1,
            FilterChain arg2) throws IOException, ServletException {

//Call external system to authenticate 
        log.debug("doFilter");

    }
}

The debug filter is not called.

Is there mistakes in any of these approaches and if yes, what is it and is there a different approach to do this? I had already looked at the following references.

How do I use autologin in liferay?

Liferay - AutoLogin + Authenticator - Get Credentials From Request Header

Community
  • 1
  • 1
user1592521
  • 61
  • 1
  • 9

1 Answers1

2

I did some more playing around and i was able to figure out way to solve this.

The answer for
2. Hooks to UserLocalService.authenticateByScreenName override

Step 1:

<service>
        <service-type>
            com.liferay.portal.service.UserLocalService
        </service-type>
        <service-impl>
            com.test.UserService
        </service-impl>
    </service>

Step 2:

Extend UserLocalServiceWrapper and use the custom class.

public class UserService  extends  UserLocalServiceWrapper
{

@Override
    public int authenticateByScreenName(long companyId, String screenName, String password, Map headerMap, Map parameterMap, Map resultsMap)
    {
//Call external system to authenticate 

        if(externalAuthenticationSuccess)
        {
          return Authenticator.SUCCESS;
       }
       else
       {
         return Authenticator.FAILURE; 
       } 

}

This works, when deployed.

This was not working when I posted the question because:

  1. I had Tomcat in the Servers. I deployed the project before making this change.
  2. Once I made the update, I used the Liferay Plugin and deployed using Right Click Project -> Liferay-> deploy.
  3. I was using the breakpoint in the code to see if it will catch it during login.
  4. This was not caught because the Eclipse IDE I was using needs the project deployed through ReDeploy under Server and not the Liferay Plugin command.

When I deployed using the Eclipse Tomcat Server as well, it caught the breakpoint.

The answer to

  1. auth.pipeline pre and check = false

    In portal-ext.properties

    auth.pipeline.enable.liferay.check=false auth.pipeline.pre=com.test.CustomAuthenticator

    public class CustomAuthenticator implements Authenticator
    {
        @Override
        public int authenticateByScreenName(long companyId, String screenName, String password,
                Map<String, String[]> headerMap, Map<String, String[]> parameterMap) throws AuthException {
    
    
    
        //Call external system to authenticate 
        if(externalAuthenticationSuccess)
        {
            return Authenticator.SUCCESS;
        }
        else
        {
            return Authenticator.FAILURE; 
        } 
    
    
        }
    }
    

This works too, but it worked only in JBoss, not in Tomcat. I deployed the portal-ext.properties in

TOMCAT_HOME\webapps\ROOT\WEB-INF\classes

In JBoss EAP, it is under Liferay_Home. It might not have picked up the property in Tomcat, but did in JBoss.

The other possible solutions posted in the question might work too, but I did not explore everything to find the mistakes in the configuration.

If there is any comment or question about these solutions, please post and I ll be happy to provide further step. Thank you.

user1592521
  • 61
  • 1
  • 9
  • Hi, I am looking a similar project to authenticate to an external system. Did you also need autologin customization? It would be great if you could post your external system call with sensitive details cleaned up here as well. Thanks a lot! – VC1 Feb 22 '16 at 18:06
  • 1
    The external system call can by anything (Db, LDAP, etc) . this example below shows the ldap call Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); env.put(Context.PROVIDER_URL, "ldap://host:port"); env.put(Context.SECURITY_AUTHENTICATION, "simple"); env.put(Context.SECURITY_PRINCIPAL, screenName); //might need domain env.put(Context.SECURITY_CREDENTIALS, password); DirContext ctx = new InitialDirContext(env); externalAuthenticationSuccess = (ctx != null); – user1592521 Feb 23 '16 at 19:52
  • 1
    sorry about formatting. i dont know how to make the comments as code, even after i indented space. – user1592521 Feb 23 '16 at 19:53
  • Thanks for the sample. Did you also need autologin customization? If you add the code sample to your answer, you may be able to format it better. – VC1 Feb 23 '16 at 20:29
  • 1
    I could not get 1 and 4 working. I did not need the autologin customization for points 2 and 3 to work. Sorry I could not provide those steps. – user1592521 Feb 25 '16 at 13:39
  • We need only one of these approaches to work, right? Not all or a combination? – VC1 Mar 16 '16 at 16:01
  • You just need only of these approaches to work. Not all or combination. – user1592521 Mar 18 '16 at 17:05
  • Are you able to establish a LR session after login with just one of the approaches? I was able to override the UserLocalServiceWrapper in the hook, however, unless I call the super.authenticateByScreenName in my method, I am not able to login. I am trying to debug to understand the code better but the debug mode is failing for me. If you have any insight on what liferay needs for this to work, it would be great. – VC1 Mar 21 '16 at 20:28
  • 1
    I apologize for late reply. Yes, I had to call user = UserLocalServiceUtil.getUserByScreenName( themeDisplay.getCompanyId(), username); The user still exists in the User_ in Liferay. Just not authenticated using that. – user1592521 Apr 04 '16 at 13:55
  • Thanks, so how and where do you import the user its a new user? Did you account for this user case? – VC1 Apr 05 '16 at 13:29
  • 1
    You mean when a new user is added ? When they register, we call the regular Liferay registration steps, except we set the autopassword argument to true. This will let Liferay choose a password and it does not matter what it is. The user will not be using that. If you are talking about importing a new user from the external system, yes, we are using a registration script which does the Liferay registration without the user involving in that. – user1592521 Apr 07 '16 at 13:00
  • Yes, thanks. Maybe a dumb question but why is the password not used when using this approach? Also, where and how do you run the registration script to import the user from the external system? Is it a shell script with java liferay API code to create users or another mechanism? – VC1 Apr 08 '16 at 18:06
  • 1
    I think the User_ table in Liferay database needs the password. If we were pointing to an external LDAP by configuring through Liferay, we might not need the password to be stored in Liferay ( I dont know this for sure), but we are using the external web service to authenticate and bypassing Liferay authentication (not authenticating through Liferay). So, Liferay password is in the table, but not used. The password typed by the user is stored in an external repository. As for registration, we are still writing that, but thinking about script which runs in Liferay context using Java Liferay API – user1592521 Apr 12 '16 at 13:40
  • i have mix authentication mode, client my use sso may use liferay login flow, now from you code i could authenticate sso user, but what if user login through direct login page, then can i continue existing process of authentication for non sso user ? – bharatpatel Jul 02 '18 at 13:33
  • Sorry for late reply. Yes, if you are eventually logging in via Liferay, you should be able to login the users that are using the direct login page. Based on how you are implementing it, you might have to override using the hooks code! But, the question is if you are single signing on the users , what are the parameters used to authenticate? do you get the username and password from the calling system? is your Liferay acting as the SP (Service Provider) or IDP ( Identity Provider) in this case? – user1592521 Jul 05 '18 at 02:39