OAuth authentication with Social Networks

Version 9

    OAuth is authorization and authentication protocol, which provides possibility that 3rd party application(client) gains access to resources of user on behalf of another application (authorization server).

    Main purpose of OAuth is authorization, but in many web pages, OAuth is also used for authentication/registration of users. And this is also the case in GateIn Portal.

    Since version 3.6, GateIn has supported oauth-integration with Facebook, Google+ and Twitter (see more at GateIn docs)

     

    The following are improvements and changes that we would like to do in GateIn 3.7 scope in term of OAuth integration.

     

    LinkedIn integration

    To provide built-in LinkedIn integration in GateIn like Facebook, Google+ and Twitter

    Some class/interface and configuration will be added to gatein for implementing LinkedIn integration (like Facebook, Twitter and Google+ implementations):

    • 4 new class/interface: LinkedInFilter, LinkedinAccessTokenContext, LinkedinProcessor and LinkedinProcessorImpl
    • Adding new configuration for linkedIn
      ## LinkedIn
      gatein.oauth.linkedin.enabled=false
      gatein.oauth.linkedin.apiKey=to be replaced
      gatein.oauth.linkedin.apiSecret=to be replaced
      gatein.oauth.linkedin.redirectURL=${gatein.oauth.portal.url}/@@portal.container.name@@/linkedinAuth
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    • Service configuration will be added to oauth-configuration.xml like configuration of Facebook, Twitter and Google+

     

    Remember me feature

    "Remember Me" feature should work consistently whether we sign in with username/password or through Oauth. For this feature working with oauth, we have to change some in gatein codebase:

    • Client-side: We need add some javascript to prcess "Remember me" checkbox when user click on "Sign in with..."
    • Server-side: we will process like "remember me" feature when user login via username/password:
      • In OAuthProviderFilter#doFilter(): we must store current oauth-login need "remember me" or not
      • In LoginServlet: we must process "remember me" for oauth after user login successfully
      • RememberMeFilter: we must check "remember me" of oauth authentication and process it if yes.

     

    Enable customize user generation strategy by extension

    Usecase:

    When i register new account with LinkedIn, i see a registration form with random-string username prefilled

    It's because LinkedIn does not provide username as unique attribute for each user, so we have to get userid instead of username, and this is a random-string by LinkedIn

    linkedin-register.png

    Solutions:

    We can improve method OAuthUtils#convertOAuthPrincipalToGateInUser() and customize the way to convert oauth-principal to gatein user for LinkedIn.

    But when someone provide other oauth integration via extension, he can not customize OAuthUtils#convertOAuthPrincipalToGateInUser() method to generate gatein user by the way that oauth provider should do.

    And when someone want to use other way to generate gatein-user from oauth infomation (for example: use email for username) and he can not customise OAuthUtils#convertOAuthPrincipalToGateInUser() too.

     

    So we should enable developer change the way to generate gatein user for each oauth provider via extension.

     

    Implementation:

    • We introduce OAuthPrincipalProcessor interface which provides a method #convertToGateInUser(OAuthPrincipal principal). The implementation of this interface can be registered as a parameter principalProcessorClass of OauthProviderTypeRegistryPlugin. For instance, we provided a specific LinkedInPrincipalProcessor implementation for LinkedIn provider and configure the parameter like following:


      <external-component-plugins>
        <target-component>org.gatein.security.oauth.spi.OAuthProviderTypeRegistry</target-component>
        <component-plugin>
          <name>LinkedInOauthProvider</name>
          <set-method>addPlugin</set-method>
          <type>org.gatein.security.oauth.registry.OauthProviderTypeRegistryPlugin</type>
          <init-params>
            <value-param>
              <name>key</name>
              <value>LINKEDIN</value>
            </value-param>
            <value-param>
              <name>enabled</name>
              <value>${gatein.oauth.linkedin.enabled}</value>
            </value-param>
            <value-param>
              <name>userNameAttributeName</name>
              <value>user.social-info.linkedin.userName</value>
            </value-param>
            <value-param>
              <name>oauthProviderProcessorClass</name>
              <value>org.gatein.security.oauth.linkedin.LinkedinProcessor</value>
            </value-param>
            <value-param>
              <name>principalProcessorClass</name>
              <value>org.gatein.security.oauth.linkedin.LinkedInPrincipalProcessor</value>
            </value-param>
            <value-param>
              <name>initOAuthURL</name>
              <value>/linkedinAuth</value>
            </value-param>
            <value-param>
              <name>friendlyName</name>
              <value>LinkedIn</value>
            </value-param>
          </init-params>
        </component-plugin>
      </external-component-plugins>
    


    • This oauth principal processor configuration is optional. If it is omitted, the DefaultPrincipalProcessor will be used which behaves as before. In the case you want to use your own oauth principal processor implementation as default processor. You could extend DefaultPrincipalProcessor and configure it as a normal component service, like following:
      <component>
        <key>org.gatein.security.oauth.principal.DefaultPrincipalProcessor</key>
        <type>org.gatein.security.oauth.principal.YourDefaultPrincipalProcessor</type>
      </component>