Credential Vault
Overview
For resources protected by the portal, WebSphere Portal uses CORBA credentials and an encrypted LTPA cookie to authenticate users. For backend systems that require their own authentication WebSphere Portal uses a credential vault. Portlets can extract user credentials, hiding any login challenges.
Portlets can use it through the Credential Vault PortletService.
Credential vault organization
The portal server's credential vault is organized as follows:
- The portal administrator can partition the vault into several vault segments. Vault segments can be created and configured only by portal administrators.
- A vault segment contains one or more vault slots. Vault slots are the "drawers" where portlets store and retrieve a user's credentials. Each slot holds one credential.
- A vault slot is linked to a resource in a vault implementation.
- A vault implementation is the place where users credentials are actually stored. Examples of vault implementations include the WebSphere Portal's default database vault or the Tivoli Access Manager lock box.
- The resource within the vault implementation corresponds to an application or backend system that requires its own authentication. Examples of resources include Lotus Notes, personnel records, or a bank account.
Vault segments
A vault segment is flagged to be either administrator-managed or user-managed. While portlets (on behalf of a portal user) can set and retrieve credentials in both types of segments, they are permitted to create vault slots only in user-managed vault segments. The following figure shows how administrator-managed vault segments can be distributed among different vault implementations. There is only one user-managed vault segment, and it resides in the vault provided by WebSphere Portal.
Vault implementations Vault Service WebSphere Portal vault
User-managed segment (U)Slot Ua Slot Ub Slot Uc
Administrator-managed
segment (A1)Slot A1a Slot A1b Slot A1c Administrator-managed
segment (A2)Other vault implementation Slot A2a Slot A2b Slot A2c
Vault slots
The credential vault provided by WebSphere Portal distinguishes between four different types of vault slots:
Slot Description system Stores system credentials where the actual secret is shared among all users and portlets. administrative Allows each user to store a secret for an administrator-defined resource (for example, Lotus Notes) shared Stores user credentials that are shared among the user's portlets. portlet Private slot that stores user credentials that are not shared among portlets.
Credential objects
The CredentialVault PortletService returns credentials in form of credential objects:
com.ibm.wps.portletservice.credentialvault.credentials.CredentialWebSphere Portal differentiates between passive and active credential objects:
- Passive credential objects are containers for the credential's secret. Portlets that use passive credentials need to 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 >- Active credential objects hide the credential's secret from the portlet; there is no way of extracting it out of the credential. In return, active credential objects offer business methods that take care of all the authentication.
// log into the backend system credential.login() // get an authenticated connection to work with URLConnection = credential.getAuthenticatedConnection(); // log out at the back end credential.logout();
The second case allows portlets to trigger authentication to remote servers using standard mechanisms such as basic authentication, HTTP form-based authentication, or POP3 authentication, without even knowing the credential secrets. They can ask the portal to authenticate on their behalf and then use already authenticated connections. From a security point of view the portlets never get in touch with the credential secrets and thus there is no risk a portlet could violate any security rules like, for example, storing the secret on the portlet session. While there might not always be an appropriate active credential class available, it is the preferred type of credential object to use.
All credential types that are available within the portal are registered in a credential type registry. WebSphere Portal provides a small set of credential types, but additional credential objects can easily be registered in this registry.
The credential classes that are shipped with the current release are:
Passive Credential Objects:
- SimplePassive
- Stores secrets in form of serializable Java objects. As the vault service does currently not support binary large object (BLOB) secrets, this is intended for future use only.
- UserPasswordPassive
- Credential object that stores secrets in the form of userid/password pairs.
- JaasSubjectPassive
- Credential object that stores secrets in form of javax.security.auth.Subject objects. Again, this kind of secret cannot currently be stored by the vault service.
Active Credential Objects:
- HttpBasicAuth
- Stores userid/password secrets and supports HTTP Basic Authentication.
- HttpFormBasedAuth
- Stores userid/password secrets and supports HTTP Form-Based Authentication.
- JavaMail
- Stores userid/password pairs and leverages the authentication functionality of the javax.mail API.
- LtpaToken
- Authenticates with a backend system that is within the same WAS single sign-on domain as the portal.
- SiteMinderToken
- Authenticates with a backend system that is within the same SiteMinder single sign-on domain as the portal. Used when SiteMinder is used as an authentication proxy for the portal.
- WebSealToken
- Authenticates with a backend system that is within the same WebSEAL single sign-on domain as the portal. Used when a WebSEAL authentication proxy is used by the portal.
Storing credential objects in the PortletSession
Credential objects do not implement java.io.Serializable - they cannot simply be stored in the PortletSession. This is for security reasons. Because the credential classes store the actual credential secret as one of their private attributes, the secret could be found by anyone who has access to the application server session database.
However, you can store a credential object in the PortletSession as long as you ensure sure that it is not serialized in a cluster setup. One way of doing this would be to define a credential container class that stores the actual credential object as a transient member. This container object can then be stored in the PortletSession without any problems, you only have to make sure to check whether the credential object got lost during serialization and in this case retrieve it from the vault again.
import com.ibm.wps.portletservice.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:
- Use an existing slot that has been defined by the portal administrator in an administrator-managed vault segment.
- Create a slot in the user-managed vault segment.
The option you choose depends on how the portlet will be 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 will be 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 will actually use this portlet, the administrator needs to create a "Lotus Notes Credential Slot" for it. Using the portlet's configure mode, the administrator sets the vault slot ID for all concrete portlet instances. 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.
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 doesn't 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 from the outset 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 could 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 doesn't 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 for further information about the methods of the CredentialVaultService .
Credential vault implementation code
The file...
wp_root/dev/CredentialVault/CredentialVaultImplementation.zip...contains sections of code that can be integrated into a portlet to use the credential vault service.
This section provides instructions for using this code in your own portlets. Keep in mind that this is only one model for using the credential vault. A developer can implement the vault using the com.ibm.wps.portletservice.credentialvault and
com.ibm.wps.portletservice.credentialvault.credentials
packages.The code described here is intended to allow developers to implement the credential vault and take advantage of single sign-on services without possessing an intimate knowledge of how the services work. You can also use this code in test portlets to explore how the credential vault service works before writing your own code.
Storing the user ID and password
- Copy the files CredentialVaultBean.java and SecretManager.java into the directory that contains all of your other source files. Change the packages in these files to match the rest of the packages of your portlet.
- Copy and paste the code from the files actionPerformedCode.txt, doViewCode.txt, and doEditCode.txt into the respective methods of the portlet. Change the name of the PortletRequest object as necessary. Add the following import statement to the class that contains your doView() and doEdit() methods.
import com.ibm.wps.portletservice.credentialvault.*;- Copy the contents of the file portletXMLcode.txt into the concrete portlet definition of your portlet.xml .
- Copy the file SecretManager.properties into the /WEB-INF/classes/nls directory of your WAR file.
- Copy the file SecretManager.jsp into the directory that contains the rest of your JSP pages. Change the first package on the import line in this file to import your portlet's package. Change the class attribute of the <jsp:useBean> tag to match the location of the CredentialVaultBean.java class in your portlet package.
- In your portlet JSP for edit mode, add the line:
<jsp:include page="SecretManager.jsp" flush="true" />Place this line wherever the user ID and password fields should appear on the page. Make sure it is not inside a <form> tag.
Note: If your portlet performs maintenance on the PortletData, make sure that it does not remove the VAULT_SLOT and VAULT_SLOTdescrip attributes from the PortletData.
Extracting the secret
Now the portlet must be modified to extract the user's secret and use it instead of prompting for a user ID and password. The code in this sample uses only userID/password passive credentials (for information on other types of credentials, see Credential objects). The UserPasswordPassiveCredential object serves as a container for the user ID and password. You must extract the user ID and password from this container using the getUserID() and getPassword() methods. These methods will return null if a secret has not been set or if some other exception occurs. For example:
String adminUserId; String adminPassword; try{ adminUserId = SecretManager.getUserID(portletRequest); adminPassword = SecretManager.getPassword(portletRequest); } catch(Exception e){ adminPassword = ""; adminUserId = null; }
Documenting the portlet
Once a portal administrator has installed a portlet that uses this code to access the credential vault, the following steps are required using Portal Administration.
- Create a vault slot
- Go to...
Security | Credential Vault...and add a vault slot for the portlet to the default admin segment. This name is case sensitive.
- Shared vault slot
- For protected resources that are shared by users check the Vault slot is shared option.
- Configure the portlet to access the vault slot
- Go to...
Portlets | Manage Portlets | portlet | Modify parameters...and set the VAULT_SLOT parameter to the name of the vault slot that was created.
Reading a credential from the vault
The following is an example of a portlet that uses a userid/password credential to log into a Web application that 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. It does not show how in the portlet's edit mode the portlet queries the user for his/her secret and stores it in the vault. This example is incomplete and should not be pasted into working code.
import org.apache.jetspeed.portlet.service.PortletServiceException; import com.ibm.wps.portletservice.credentialvault.CredentialVaultService; import com.ibm.wps.portletservice.credentialvault.CredentialSecretNotSetException; import com.ibm.wps.portletservice.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.yourco.com/myapp/j_security_check"); config.put( HttpFormBasedAuthCredential.KEY_LOGOUT_URL,"EAI.yourco.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 that 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 your 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.yourco.com/request.jsp"); // Work with the connection: send an HTTP GET or POST and evaluate the response [...] // your 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(); }
See also