Guide to Integrate LinkedIn 2.0 Connect with the eXo Platform Sign-In Mechanism

eXo Platform Blog
LinkedIn 2.0

ON May 1, 2019, LinkedIn deprecated the use of its v1 APIs, therefore, Applications requesting it  started experiencing issues as this API version services began to be removed. For eXo Platform as well, the migration to the 2.0 Version of our APIs and from OAuth 1.0 to OAuth 2.0 was already set to be processed.

A few days ago, a community member asked us how to make the LinkedIn 2.0 sign-in mechanism work for his own project running eXo Platform 6. Then, after sharing the full process with him, we thought it would be valuable to make everyone profit from this knowledge. So, this article will focus on using LinkedIn 2.0 authentication to sign in to Platform 6, yet, the same process should be usable to allow authentication via Facebook or Twitter as well.

I. Objective

  1. Users can sign into your eXo Platform 6 website using their LinkedIn accounts.
  2. The LinkedIn user profile can be imported into the eXo Platform user profile.

II. Steps

The steps below summarise the whole process:

  1. Obtain LinkedIn API 2.0 key and secret key via the LinkedIn developer website.
  2. Develop a LinkedIn OAuth 2.0 component (.jar) in your own java project.
  3. Deploy your component into eXo Platform.
  4. Develop a login module (.jar) in your java project.
  5. Deploy and configure JAAS Realm to enable your login module.

1. Obtain LinkedIn API 2.0 key and secret code.

  1. Go to https://www.linkedin.com/developer/apps/.
  2. Register your application by selecting Create Application.
  3. Fill values for Name, Description, Application Logo URL, Application User, Business Email and Business Phone. For Website URL, enter http://server.local.network.com:8080.
  4. Click Submit.
  5. In the Authentication part, tick two checkboxes: r_basicprofile and r_emailaddress,
  6. Add the following URL http://server.local.network.com:8080/portal/linkedinAuth as the Authorized Redirect URLs
  7. Click Update.
  8. – Once the registration is done, you can retrieve your API key and secret key.

    Note that keys can be regenerated later, if needed.

    2. Develop a LinkedIn OAuth 2.0 component (.jar).

    – Start your Maven project.

    – Edit your pom.xml to add scribe dependency:

    <dependency>  
    	<groupId>com.github.scribejava</groupId>  
    	<artifactId>scribejava-apis</artifactId>  
    	<version>6.9.0</version>        
    </dependency>
    <dependency>  
    	<groupId>com.github.scribejava</groupId>  
    	<artifactId>scribejava-core</artifactId>  
    	<version>6.9.0</version>        
    </dependency>
    

    The scrib library can be used this way:

     
    import com.github.scribejava.apis.LinkedInApi20;
    import com.github.scribejava.core.builder.ServiceBuilder;
    import com.github.scribejava.core.model.OAuth2AccessToken;
    import com.github.scribejava.core.oauth.OAuth20Service;
    import com.github.scribejava.core.model.OAuthRequest;
    import com.github.scribejava.core.model.Response;
    import com.github.scribejava.core.model.Verb;
    
    

    – Write a java class that carries out the interconnection between eXo Platform and LinkedIn using Scribe API 2.0 .

    The interconnection is explained here:

    Authenticating with OAuth 2.0 Overview

    If you need to read more about Scribe API:

    Articles from LinkedIn

    Scribejava

    – Write another class (called “filter” in this tutorial) that:

    • Redirects users to the LinkedIn login page using the login url
    • Redirects users to the login page on our website once the needed information has been retrieved

    Sample code for the filter:

    public class OAuthLinkedinFilter implements org.exoplatform.web.filter.Filter{
     
    	public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException {
    		
    	HttpServletRequest req = (HttpServletRequest)request;
        HttpServletResponse res = (HttpServletResponse)response;
        HttpSession session = req.getSession(true);
        LinkedinAuthHelper helper = new LinkedinAuthHelper();
        String code = request.getParameter("code");
        String stateRes = request.getParameter("state");
        String stateReq = (String)session.getAttribute("state");
        if(code == null ||  stateReq == null || stateRes == null || "".equals(code) || "".equals(stateReq) || "".equals(stateRes) || !stateRes.equals(stateReq)){
    			session.setAttribute("state", helper.getStateToken());
    			String loginUrl = helper.getLoginUrl();
    			res.sendRedirect(loginUrl);
    			return;              
    		}else if(code != null  && stateRes != null && stateReq != null && stateRes.equals(stateReq)){
          session.removeAttribute("state");    
          String username = helper.getUsernameFromTokenCode(code);
          if(username != null){
              SecureRandom random = new SecureRandom();
              String password = new BigInteger(130, random).toString(32);
              session.setAttribute("oauth_username",username);
              session.setAttribute("oauth_password",password);
              res.sendRedirect("/portal/login?username="+username+"&password="+password);
              return; 	
          }        
        }
    }
    

    Note: This sample saves the username and password in a browser session.

    3. Deploy your LinkedIn Auth 2.0  component

    – After building your project, install the jar to tomcat/lib.

    – Declare the filter via an eXo Platform Extension. The filter will be declared in WEB-INF/conf/portal/configuration.xml, as in the following sample. (Note that the class name is org.exoplatform.community.oauth.linkedin.OAuthLinkedinFilter and the url is /linkedinAuth.)

     
    <?xml version="1.0" encoding="ISO-8859-1"?>
    <configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               	xsi:schemaLocation="http://www.exoplaform.org/xml/ns/kernel_1_2.xsd http://www.exoplaform.org/xml/ns/kernel_1_2.xsd"
               	xmlns="http://www.exoplaform.org/xml/ns/kernel_1_2.xsd">
      <external-component-plugins>
          <!-- The full qualified name of the ExtensibleFilter -->
        <target-component>org.exoplatform.web.filter.ExtensibleFilter</target-component>
        <component-plugin>
          <!-- The name of the plugin -->
          <name>Sample Filter Definition Plugin</name>
          <!-- The name of the method to call on the ExtensibleFilter in order to register the FilterDefinitions -->
          <set-method>addFilterDefinitions</set-method>
          <!-- The full qualified name of the FilterDefinitionPlugin -->
          <type>org.exoplatform.web.filter.FilterDefinitionPlugin</type>
          <init-params>
            <object-param>
              <name>Sample Filter Definition</name>
              <object type="org.exoplatform.web.filter.FilterDefinition">
                <!-- The filter instance -->
                <field name="filter">
                  <object type="org.exoplatform.community.oauth.linkedin.OAuthLinkedinFilter"/>
                </field>
                <!-- The mapping to use -->
                <!-- WARNING: the mapping is expressed with regular expressions -->
                <field name="patterns">
                  <collection type="java.util.ArrayList" item-type="java.lang.String">
                    <value>
                      <string>/linkedinAuth</string>
                    </value>
                  </collection>
                </field>
              </object>
            </object-param>
          </init-params>
        </component-plugin>      
      </external-component-plugins>
    </configuration>
    
    

    4. Develop your login module.

    – Write a login module that extends AbstractLoginModule.

    See the code sample below:

     
    package org.exoplatform.community.service.sso;
    public class ORGLoginModule extends AbstractLoginModule {
     
    	public boolean login() throws LoginException {  
        
        try {  
    			HttpServletRequest request = getCurrentHttpServletRequest();    
    			ExoContainer container = getContainer();  
    			HttpSession session = request.getSession(true);  
    			String username = null;  
    			String password = null;  
    			if(session != null) {    
    				if(session.getAttribute("oauth_username") != null) {  
    					 username = (String) session.getAttribute("oauth_username");  
    					 session.removeAttribute("oauth_username");  
    				}  
    				if(session.getAttribute("oauth_password") != null) {  
    					 password = (String) session.getAttribute("oauth_password");  
    					 session.removeAttribute("oauth_password");  
    				}  
          }  
    			if(username != null){  
    				establishSecurityContext(container, username);  
    				if (log.isTraceEnabled()) {  
    					log.trace("Successfully established security context for user " + username);  
    				}
    				return true;  
    			}  
    			return false;  
        }catch (Exception e) {  
    		if (log.isTraceEnabled()) {  
    			log.trace("Exception in login module", e);  
        }  
        return false;  
    }  
     
    	protected void establishSecurityContext(ExoContainer container, String username) throws Exception {
            
    		Authenticator authenticator = (Authenticator) container.getComponentInstanceOfType(Authenticator.class);
      	if (authenticator == null) {
    			throw new LoginException("No Authenticator component found, check your configuration");
        }
        Identity identity = authenticator.createIdentity(username);
        sharedState.put("exo.security.identity", identity);
        sharedState.put("javax.security.auth.login.name", username);
        UsernameCredential usernameCredential = new UsernameCredential(username);
        subject.getPublicCredentials().add(usernameCredential);
        }
    	}
    
    

    5. Deploy and configure JAAS to enable your login module.

    – After building your login module jar, install it to tomcat/lib.

    – Configure to enable the module in tomcat/conf/jaas.conf. Your login module should be placed before other modules. In the following example, it is ORGLoginModule:

     
    gatein-domain {
    	org.exoplatform.community.service.sso.ORGLoginModule required;
    	org.gatein.sso.integration.SSODelegateLoginModule required
    	enabled="#{gatein.sso.login.module.enabled}"
    	delegateClassName="#{gatein.sso.login.module.class}"
    	portalContainerName=portal
    	realmName=gatein-domain
    	password-stacking=useFirstPass;
    	org.exoplatform.services.security.j2ee.TomcatLoginModule required
    	portalContainerName=portal
    	realmName=gatein-domain;
    };
    
    

    6. Test

    – To check if the filter works, go to {your website}/portal/linkedInAuth

    If the module is working, it will redirect you to a LinkedIn login page like this one:

    Once you are identified on LinkedIn you have to allow the access, then you will be redirected back to the website with the user data provided by LinkedIn.

    These data are formatted under json format in the following manner:

    {“id”:”QuUeufSui4″,”lastName”:”Bengayed”,”emailAddress”:”lotfi.bengayed@gmail.com”,”firstName”:”Lotfi”}

    Now, you can do whatever you want with these data.

Related Posts

Being a developer, engineer at eXo Platform, I am mainly responsible for implementing new features and maintenance in our product. Also, I've been part of many customer's project.

Comments
Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>