+

Search Tips   |   Advanced Search

Portlet authentication using Credential Vault


Overview

Portal uses CORBA credentials and an encrypted LTPA cookie to authenticate users. For backend systems that require their own authentication, portlets need to provide some form of authentication to access these remote applications.

To provide a single sign-on user experience, portlets must be able to store and retrieve user credentials for their particular associated application. Then, they use those credentials to log in on behalf of the user. HCL WebSphere Portal supports the use of a credential vault where users and administrators can safely store credentials for authentication. Portlets written to extract the user's credentials from the vault can hide the login challenge from the user.

Portlets interact with the credential vault portlet service (CredentialVaultService).


Credential vault organization

The portal administrator can partition the vault into vault segments. A vault segment contains one or more vault slots. Each slot holds one credential. Vault implementations include the default database vault and Security Access Management Family lock box. Resources include Lotus Notes, personnel records, and bank accounts.


Vault segments

Portlets, on behalf of a portal user, can...

  • Set and retrieve credentials in vault slots for administrator and user managed vault segments.
  • Create vault slots only in user-managed vault segments.

There is only one user-managed vault segment: The default vault provided by HCL WebSphere Portal.


Vault slots

  • Vault slots in administrator-managed vault segments:

    • System slot

      Secret is shared among users and portlets. Created using Credential Vault portlet, by adding a slot in an administrator-managed vault segment, and marking it as shared.

    • Administrative slot

      Secret is not shared among users and portlets. Allows each user to store a secret for example, to Lotus Notes. Created using Credential Vault portlet, by adding a slot in an administrator-managed vault segment, and marking it as not shared shared.

  • Vault slots in user-managed vault segments:

    • Shared user slot

      Stores user credentials shared among the user's portlets. Use the Credential Vault portlet to create the shared slot. Set shared slot to true.

    • Portlet private slot

      Store user credentials not shared among portlets. Use Credential Vault portlet to create the shared slot. Set shared slot to false.

Vault Slot Type Segment type Shared Creation through Secret Sharing
System Slot administrator-managed true Credential Vault portlet One secret per system
Shared among all users and portlets
Administrative Slot administrator-managed false Credential Vault portlet One secret per user
Shared among all of user's portlets
Shared User Slot user-managed true Credential Vault service One secret per user
Shared among all of user's portlets
Portlet Private Slot user-managed false Credential Vault portlet service One secret per user and portlet entity
Not shared among portlets


Credential objects

The credential vault portlet service returns credentials in form of credential objects. The following are the base interface classes for all credential objects:

    Standard portlet API

      com.ibm.portal.portlet.service.credentialvault.credentials.Credential

    IBM Portlet API

      com.ibm.wps.portletservice.credentialvault.credentials.Credential

Passive credential objects are containers for the credential's secret. Portlets using passive credentials extract the secret from the credential, and do all the authentication communication with the backend itself.

    Object userSecret = credential.getUserSecret();
       < portlet connects to backend system authenticates using the user's secret >
       < portlet can use the connection to communicate with the backend application >
       < portlet takes care of logging at the backend >

The PassiveCredential interface inherits from the Credential base interface...

    Passive Credential Objects:

      SimplePassive
      Store secrets in the form of serializable Java objects. As the vault service does currently not support binary large object (BLOB) secrets, it is intended for future use only.

      UserPasswordPassive
      Store secrets in the form of userid/password pairs.

      JaasSubjectPassive
      Store secrets in form of javax.security.auth.Subject objects. This kind of secret cannot currently be stored by the vault service. Used as a transient credential that is not persisted, but taken from the user's session.

      BinaryPassiveCredential
      Store secrets in the form of a byte array.

    Store credential objects in the PortletSession

    Credential objects do not implement java.io.Serializable - they cannot be stored in the PortletSession for security reasons. The credential classes store the credential secret as one of their private attributes.

    We can store a credential object in PortletSession if you ensure sure that it is not serialized in a clustered environment. One way is to define a credential container class that stores the credential object as a transient member. This container object can then be stored in the PortletSession without any problems. Check whether the credential object got lost during serialization and in this case retrieve it from the vault again.

      import com.ibm.portal.portlet.service.credentialvault.credentials.Credential;
       public class CredentialSessionContainer implements java.io.Serializable
      {
         private transient Credential credential = null;
          public void setCredential(Credential cred) {this.credential = cred;}
          public Credential getCredential() {return credential;}
          public boolean hasCredential() {return credential != null;}
      }


Credential vault usage scenarios

Portlets that need a credential to complete their service have two options:

  1. Use an existing slot defined by the portal administrator in an administrator-managed vault segment.

  2. Create a slot in the user-managed vault segment.

The option chosen depends on how the portlet used. Generally, the best solution hides the technical details of the credential vault from users. The following are some example scenarios for the use of slots.

    Intranet Lotus Notes mail portlet

    • A company has an intranet employee portal. Each portal user has a Lotus Notes mail server account and a Lotus Notes mail portlet is deployed and pre-configured on one of the employee's default portal pages.

    • Design solution.

    • The Notes mail portlet needs to store the user's Notes password. As most users use this portlet, the administrator creates a "Lotus Notes Credential Slot" for it using the Credential Vault portlet's configure mode. The administrator sets the vault slot ID for all portlet entries. The portlet allows users to set their personal Notes password in edit mode. The portlet can store each user's password in the credential vault.

    • If the company uses a Domino server within the same single sign-on domain as portal, it is possible to use an LTPAToken Credential based on the user's JAAS Subject. This credential offers access to the domino server through an authenticated connection that reuses the user's LTPA token.

    Stock of inventory portlet

    A company's buying department runs a portal that integrates different legacy applications. One of these applications is a mainframe-ordering application that directly connects to the systems of the suppliers. Several employees use the ordering portlet. However, the mainframe application is secured by a single system ID; it does not support several user accounts.

    Design solution: The ordering portlet needs to access the ordering application under the system ID. The administrator configures the vault slot ID during portlet deployment. The portal administrator therefore creates a vault slot in an administrator-managed vault segment and marks it as a system credential. The administrator uses the Credential vault portlet to store the ordering system ID and password in this slot. The buying department's employees do not have to be concerned with credentials at all.

    Internet Mail federating POP3 portlet

    An Internet community portal offers, among other features, a mail-federating portlet that can be used by a portal user to collect mail from a number of POP3 mail accounts.

    Design solution: The mail federating portlet is just another feature of the community portal and thus is likely to be used only by some of the portal users. Furthermore, it is not clear how many mail accounts a user wants to federate. Therefore, it does not make sense for the portal administrator to create a vault slot for this portlet. Instead, the portlet provides users with a comfortable configuration in edit mode. Users can add as many POP3 mailboxes as necessary. The portlet creates a vault slot for each of the user's mailboxes in the user-managed vault segment.

    Theoretically, a user might configure two instances of the portlet on a page, one for business accounts and one for private mail accounts. Therefore, and because it most likely does not make sense to share the user's mail credentials with other portlets, the portlet created vault slots are better marked as portlet private.


Credential vault samples

This section contains sample code for using the credential vault service. See the Portlet API Javadoc documentation for information about the CredentialVaultService methods.

    Standard portlet example from Rational Application Developer

    When we use the portlet wizard in Rational Application Developer to create portlets using the credential vault portlet service, the wizard generates a SecretManager class for you that handles common tasks. The session bean generated by the wizard includes getters and setters for the secret type and vault slot name. The following examples show code that might be generated for you, depending on your selections, when creating a JSR 168 portlet project.

    This code is only a demonstration of how use the credential vault. Any code generated must be further customized for the specific application requirements.

    1. Retrieve the credential vault portlet service.

      This code is placed in the init() method of the SecretManager and is called from the init() of the main portlet class. See Access portlet services for general information about how portlet services are retrieved with JNDI.

        public static void init(PortletConfig config) throws PortletException 
        {
          try {
            if( vaultService == null ) 
        {
              Context ctx = new InitialContext();
              PortletServiceHome cvsHome = (PortletServiceHome)ctx.lookup("portletservice/com.ibm.portal.portlet.service.credentialvault.CredentialVaultService");        
              if (cvsHome != null) 
              {
                vaultService = (CredentialVaultService)cvsHome.getPortletService (CredentialVaultService.class);
              }
            }
          } catch (Exception e) 
            {
               throw(new PortletException("Error on init()", e));    
            }
        }
        

    2. Set the credential.

      The portlet's processAction() method gets the USERID and PASSWORD parameters on the action request from the edit JSP. If both parameters are not null, then they are used to set the credential.

        if( request.getParameter(USER_SUBMIT) != null ) 
        {
           // Set userId/password text in the credential vault        
           PortletSessionBean sessionBean = getSessionBean(request);
           if( sessionBean!=null ) 
           {
              String userID   = request.getParameter(USERID);
              String password = request.getParameter(PASSWORD);
              // save only if both parameters are set              
              if(userID!=null && password!=null && !userID.trim().equals("") &&!password.trim().equals("")) 
              {
                 try 
                 {
                    SecretManager.setCredential(request,sessionBean,userID,password);
                 }
                 catch (Exception e) 
                 {
                    //Exception Handling
                 }
              }
           }
        }
        

      The setCredential() method in the SecretManager class determines whether the portlet can write to the slot and if the slot ID has content. If so, it uses the setCredentialSecretUserPassword() method of the credential vault service to set the credential to the slot.

        public static boolean setCredential(PortletRequest portletRequest, PortletSessionBean sessionBean, String userID, String password) throws PortletException  
        {
            try 
            {
               if( isWritable(sessionBean) )     
               {
                   String slotId = getSlotId(portletRequest,sessionBean,true);        
                   // create slot if necessary              
                   if( slotId != null )        
                   {
         vaultService.setCredentialSecretUserPassword(slotId,userID,password.toCharArray(),portletRequest);
         return true;
                   }
               }
            }
            catch( CredentialVaultException e) 
            {
              //Exception Handling
            }
            return false;
        }
        

    3. Get a slot for storing the user's credentials.

      The setCredential() method calls this method to either create a new slot or use an existing, accessible slot.

      • The slot name is set as a portlet preference so that it can be changed by the administrator to any slots created with the portal administration interface.

      • For a portlet private slot, this method creates a new slot if the slot name from the portlet preferences is null. The createNewSlot() method is another custom method of SecretManager that uses to createCredentialSlot() method of the credential vault service. This method can create non-system slots and returns a CredentialSlotConfig object. The slotID of the new slot is stored in the portlet preferences and is used to update, and retrieve the portlet private credentials.

      • For a shared slot, this method searches for a shared resource name from accessible slots. If a shared slot is not available, it creates a new slot.

        private static String getSlotId(PortletRequest portletRequest, PortletSessionBean sessionBean, boolean bCreate)  throws PortletException 
        {
           String slotId = null;
           String slotName = sessionBean.getVaultSlotName();
        
           switch( sessionBean.getSecretType() ) 
           {
              case SECRET_PORTLET_PRIVATE_SLOT:
                 PortletPreferences prefs = portletRequest.getPreferences();
                 String prefsKey = ".slot."+portletRequest.getRemoteUser()+".  "+slotName;
                 slotId = prefs.getValue(prefsKey,null);
                 if( slotId==null && bCreate ) 
                 {
                    slotId = createNewSlot(portletRequest,slotName, true);  
                    // create private slot             
                    if( slotId != null ) 
                    {
         try 
         {
            prefs.setValue(prefsKey,slotId);
            prefs.store();
         }
         catch( Exception e ) 
         {
            throw(new PortletException("Error on PortletPreferences.
              store()", e));
         }
                    }
                 }
                 break;
              case SECRET_SHARED_SLOT:
                 try 
                 {
                    Iterator it = vaultService.getAccessibleSlots(portletRequest);
                    while( it.hasNext() )              
                    {
         CredentialSlotConfig config = (CredentialSlotConfig)it.next() ;
         //searches for shared resource name    
         if( config.getResourceName().startsWith(slotName ) ) {
            slotId = config.getSlotId();
            break;
         }
                    }
                    if( slotId==null && bCreate )
          slotId = createNewSlot(portletRequest,slotName,false);       
                    // create shared slot          
                 }
                 catch( CredentialVaultException e) 
                 {
                     // exception handling goes here          
                 }
                 break;
              default:
                 slotId = slotName;
                 break;
           }
           return slotId;
        }
        

    4. Retrieve the credential

      Both the doView() and doEdit method call getCredential() from the SecretManager. For the case of passive credentials, this portlet sets the USERID and PASSWORD returned from this method as attributes on the request.

        StringBuffer userId = new StringBuffer("");
        StringBuffer password = new StringBuffer("");
        try 
        {
           SecretManager.getCredential(request,sessionBean,userId, password);
        }
        catch( Exception e ) 
        {
           getPortletContext().log("Exception on SecretManager.getCredential(): "+e.getMessage());
        }
        request.setAttribute(USERID,userId.toString());
        request.setAttribute(PASSWORD,password.toString());
        

      The getCredential() method of SecretManager handles UserPasswordPassiveCredential types. The type of credential is set as an Integer in the portlet preferences. The getCredential() method of the credential vault service is used to obtain the credentials stored in the slot.

        public static void getCredential(PortletRequest portletRequest, 
                                         PortletSessionBean sessionBean, 
                                         StringBuffer userid, 
                                         StringBuffer password) 
                                         throws PortletException  
        {
           try     
           {
              String slotId = getSlotId(portletRequest,sessionBean,false);
                 if( slotId != null ) 
                 {
                    UserPasswordPassiveCredential credential = (UserPasswordPassiveCredential)vaultService.getCredential 
                                                               (slotId,CredentialTypes.USER_PASSWORD_PASSIVE,new HashMap(),portletRequest);
                    if( credential != null) 
                    {
                         userid.append(credential.getUserId());
                         password.append(String.valueOf(credential.getPassword()));
                    }
                 }
           }
           catch( CredentialVaultException e) 
           {
              // exception handling goes here    
           }
        }
        

    IBM example that reads a credential from the vault

    The following is an example of an IBM portlet that uses a user ID and password credential to log in to a web application. The web application is secured with an HTTP form-based login page. The example shows how the CredentialVaultService is used to read a credential from the vault and how to use this credential. Does not show how in the portlet's edit mode the portlet queries the user for the secret and stores it in the vault. This example is incomplete; do not paste into working code.

      import org.apache.jetspeed.portlet.service.PortletServiceException;
      import com.ibm.portal.portlet.service.credentialvault.CredentialVaultService;
      import com.ibm.portal.portlet.service.credentialvault.CredentialSecretNotSetException;
      import com.ibm.portal.portlet.service.credentialvault.credentials.HttpFormBasedAuthCredential;
      
      ...
      
      public void doView (PortletRequest request, PortletResponse response) throws PortletException, IOException 
      {
         // get output stream and write out the results      
         PrintWriter writer = response.getWriter();
      
         // get the CredentialVault PortletService
         PortletContext context = this.getPortletConfig().getContext();
         CredentialVaultService service = (CredentialVaultService) context.getService(CredentialVaultService.class);
      
         // retrieve slotId from persistent portlet data      
         String slotId = (String) request.getData().getAttribute("VaultTestSlotID");
      
         if (slotId == null) 
         {
           writer.println("<h2>Credential not found. Please set it in the edit mode! </h2>");
           return;
         }
         // bundle the credential config data mostly based on the backend application's login form   
         HashMap config = new HashMap();
         config.put( HttpFormBasedAuthCredential.KEY_USERID_ATTRIBUTE_NAME,   "j_userid");
         config.put( HttpFormBasedAuthCredential.KEY_PASSWORD_ATTRIBUTE_NAME, "j_password");
         config.put( HttpFormBasedAuthCredential.KEY_LOGIN_URL, "EAI.myco.com/myapp/j_security_check");
         config.put( HttpFormBasedAuthCredential.KEY_LOGOUT_URL,"EAI.myco.com/myapp/quit.jsp");
         config.put( HttpFormBasedAuthCredential.KEY_USE_AUTH_COOKIES, Boolean.TRUE);
         List formData= new ArrayList();
         formData.add("action=Login");
      
         // add the POST data the form's login button will generate (name=value)
         config.put( HttpFormBasedAuthCredential.KEY_FORM_DATA, formData);
      
         // get the actual credential from the credential vault      
         HttpFormBasedAuthCredential credential;
         try 
         {
           credential = (HttpFormBasedAuthCredential)
               service.getCredential(slotId, "HttpFormBasedAuth", config, request);
         } catch (PortletServiceException serviceExc) {
           writer.println("<h2>Credential vault error, please contact the admin! </h2>");
           return;
         } catch (CredentialSecretNotSetException userExc) {
           writer.println("<h2>Credential not set. Please set it in the edit mode! </h2>");
           return;
         }
          try 
          {
          // use credential object to log in at the backend server          
          credential.login();
          // get an authenticated connection to the backend server and send the actual request          
          connection = credential.getAuthenticatedConnection("EAI.myco.com/request.jsp");
      
          // Work with the connection: send an HTTP GET or POST and evaluate the response          
          [...]       
          // the business code          
          // use credential object to log out at the backend server          
          credential.logout();
          } 
          catch (IOException exc) 
          {
              writer.println("<h2>Single-sign-on error, login at backend failed! </h2>");
              return;
          }
          // get output stream and write out the results      
          PrintWriter writer = response.getWriter();
      }
      


Change the credential vault encryption

HCL WebSphere Portal supports plugging in different vault adapters for the storage and retrieval of credentials. The default vault adapter that includes with HCL WebSphere Portal stores user credentials in the portal configuration database. By default, the passwords are only obfuscated, but not encrypted.


Parent Portlet creation basics