![]() ![]() ![]() ![]() ![]() ![]() |
Some portlets need to connect to back-end systems or remote applications with a username and password. If a remote application uses the same credentials as those used by the portal, the portlets can re-use the credentials. However, in most cases, the credentials required by remote systems are not same as user credentials used for logging into the portal. For optimal user experience, a single sign-on is needed. The Credential Vault provides a safe storage mechanism to securely set and retrieve credentials for portlets accessing remote applications.
In previous releases of WebLogic Portal, you could implement functionality similar to the Credential Vault by storing credentials in user profiles. However, user profile properties are not encrypted and not a safe place for storing credentials. Although it is possible to encrypt properties using WebLogic Server encryption methods, they are complex, limited, and required custom programming. Additionally, JCA cannot be used because JCA adapters do not fit into the portlet scope.
The Credential Vault provides APIs that allow portlets to store and access user credentials and use those credentials to log into remote applications on behalf of the user. With these APIs, a developer can build secure repositories that store usernames and passwords, plus optional metadata required by the resource, such as a URL. The username and password are encrypted, while the metadata (name value pairs of String
type) are stored in plain text. The Credential Vault does not provide the mechanism to pass the credentials to the remote system.
In addition to the APIs, the Credential Vault provides a GUI in the WebLogic Portal Administration Console, where a portal administrator can create a system credential vault. The three types of credential vaults are as follows:
A user credential vault securely stores a user’s credentials for a remote system for individual portlets based only on the username. In other words, a credential entry is accessible to all the resource instances of a logged-in user. In the WebLogic Portal
Javadoc, this entry is called USER_TYPE
.
Using the Credential Vault APIs in a typical implementation, a portlet is created that allows a user to provide their login information to a remote system. After that, whenever the user logs into the portal, the portlet code automatically reads the login information and passes it to the remote application without the user having to re-enter their credentials. The following figure shows an example of this type of credential vault, where two portlets on the same portal page connect to two different remote systems.
Use this type of credential vault when a portal contains two or more portlets that connect to the same remote system for users who require different credentials. For example, one portlet might connect the user to the remote system as a generic user and the other portlet might connect the user as an administrator. In a User + Resource Credential Vault, credential entry is only accessible to a particular resource instance of the logged-in user. In the WebLogic Portal
Javadoc, this entry is called RESOURCE_TYPE
.
An administrator can create a system credential vault that stores a global username and password so that credential entry is accessible to all resource instances of all logged-in users. In the WebLogic Portal
Javadoc, this entry is called SYSTEM_TYPE
.
This type of credential vault allows multiple users to share the same password (and username) to access a remote resource. It is best suited for use as a demonstration account, where a user has read-only access to a resource before getting an account. You can use either the Credential Vault APIs or the WebLogic Portal Administration Console to create a system credential vault. For more information, see Using the Credential Vault APIs and Creating or Viewing System Credentials in the Administration Console.
You can specify the scope of the three types of credential vaults entry across web applications, enterprise applications, and within a domain:
Scoping allows you to shadow the names of the credential vaults within the Java EE application. Within the same scope, the names must be unique. In different scopes you can shadow the name. From an outer scope, all the names are visible to any of its containing scope. For example, if both an EAR scope and WAR scope have a credential vault named foo, the credential vault in WAR scope is used because foo in WAR scope shadows the foo within the EAR scope.
The following figure shows an example.
When accessing the credential vault, the code associated with a portlet traverses the credential vaults until it finds an entry for the user. If no credentials are found, you can use the APIs to present a login to the user. The following example provides more details:
Suppose an employee logs into a Human Resources portal page with their WebLogic authenticated username and password. This page contains portlets to services such as payroll, stock options, and career development. The employee wants to change their payroll deduction and the payroll system exists on a remote SAP application. When the employee clicks the Payroll portlet, the system looks for the login credentials in the payroll credential vault (Web App). If it finds the employee’s credentials, the portlet logs in the user to the SAP payroll application.
If the employee’s credentials do not exist in that credential vault, the portlet looks for them in the enterprise credential vault (EAR). If the enterprise credential vault contains the employee’s credentials, the portlet logs the employee into the SAP payroll application. If not, the system looks for the credentials in the global credential vault (domain). If the portlet finds the employee’s credentials, the employee is logged on to the remote SAP application. If not, the portlet presents a login to the SAP application.
Once the user successfully logs onto the SAP application, the credentials are stored in one of the credential vaults; which credential vault is determined by the system design.
The package com.bea.p13n.security.management.credentials
, documented in
Javadoc, lets you create entries and access the three types of credential vaults. The Javadoc provides the detailed information that you need for implementing credential vaults. The following sections provide the framework for using creating and accessing credential vaults.
Note: | Some of the following sections use RESOURCE_TYPE (User + Resource) as an example of the credential vault type. To change type, simply change RESOURCE_TYPE to either USER_TYPE or SYSTEM_TYPE . |
The entry point to the credential vault API is through the Credential Vault Service interface:
CredentailVaultService cvs = com.bea.wlp.services.Services.getService(com.bea.p13n.security.management.credentials.CredentailVaultService.class)
The resource key contains the scope and Resource ID of the credential service. You must specify the scope because the portlet instance is a web-scoped resource.
ResourceKey rc = new ResourceKey(Scope.getWebApplicationScope(request), portletInstanceId);
Tip: | Although the resource ID is not required for User or System credential vaults, it is a best practice to use the actual Resource ID. This will allow you to easily convert the credential vault to a different type in the future. |
When you create an entry you set the resource key and entry type for the credential vault. The entry type is one of the following: USER_TYPE
(User), RESOURCE_TYPE
(User + Resource), or SYSTEM_TYPE
(System).
return cvs.createCredentialEntry(entryName, EntryType.RESOURCE_TYPE, null, rc);
You can also provide a description for the entry. If you do not want a description, use null
.
When you access an entry, you supply the resource key and entry type for the credential vault. The entry type is one of the following: USER_TYPE
(User), RESOURCE_TYPE
(User + Resource), or SYSTEM_TYPE
(System).
return cvs.fetchCredentialEntry(entryName, EntryType.RESOURCE_TYPE, rc);
Note: | If more than one entry exists with same name but a different scope, the one with closest scope to requesting resource is retrieved. |
To add or change the username and password, use UserPasswordCredential
.
entry.setCredential(new UserPasswordCredential(username, password.getBytes("UTF-8")));
To remove a credential entry, use removeCredentialEntry
.
cvs.removeCredentialEntry(entryName, EntryType.RESOURCE_TYPE, rc);
Sample code showing CRUD operations for each type of credential vault may be available on Dev2dev. On Dev2Dev, search for Credential Vault.
The following examples show the CRUD operations for a user (USER_TYPE
) credential vault. For User + Resource and System Credential Vaults, you only need to change the type to RESOURCE_TYPE
or SYSTEM_TYPE
respectively.
CredentialVaultHelper
—demonstrates the code you need for using the Credential Vault API.EmailAccountBacking
file—shows the portlet logic needed get and update an entry in a User Credential Vault.index.jsp
—displays the email account credential entry.config.jsp
—updates the email account credential entry.
The CredentialVaultHelper
class demonstrates all of the code you need for using the Credential Vault API.
package examples.credential;
import javax.servlet.http.HttpServletRequest;
import com.bea.p13n.security.management.credentials.AlreadyExistsException;
import com.bea.p13n.security.management.credentials.CredentialVaultService;
import com.bea.p13n.security.management.credentials.ResourceKey;
import com.bea.p13n.security.management.credentials.Scope;
import com.bea.p13n.security.management.credentials.CredentialEntry;
import com.bea.p13n.security.management.credentials.CredentialEntry.EntryType;
public class CredentialHelper
{
private static CredentialVaultService cvs = com.bea.wlp.services.Services.getService(CredentialVaultService.class);
public static CredentialEntry createCredentialEntryForPortletInstance(String entryName, HttpServletRequest request)
throws AlreadyExistsException
{
String portletInstanceId = com.bea.netuix.util.PortalFrameworkUtils.getUniquePortletDesktopString(request);
// need webapp scope since portlet instance is web scoped resource.
ResourceKey rc = new ResourceKey(Scope.getWebApplicationScope(request), portletInstanceId);
return cvs.createCredentialEntry(entryName, EntryType.RESOURCE_TYPE, null, rc);
}
public static CredentialEntry getCredentialEntryForPortletInstance(String entryName, HttpServletRequest request)
{
String portletInstanceId = com.bea.netuix.util.PortalFrameworkUtils.getUniquePortletDesktopString(request);
// need webapp scope since portlet instance is web scoped resource.
ResourceKey rc = new ResourceKey(Scope.getWebApplicationScope(request), portletInstanceId);
return cvs.fetchCredentialEntry(entryName, EntryType.RESOURCE_TYPE, rc);
}
public static void removeCredentialEntryForPortletInstance(String entryName, HttpServletRequest request)
{
String portletInstanceId = com.bea.netuix.util.PortalFrameworkUtils.getUniquePortletDesktopString(request);
// need webapp scope since portlet instance is web scoped resource.
ResourceKey rc = new ResourceKey(Scope.getWebApplicationScope(request), portletInstanceId);
cvs.removeCredentialEntry(entryName, EntryType.RESOURCE_TYPE, rc);
}
public static CredentialEntry createUserCredentialEntry(String entryName, HttpServletRequest request)
throws AlreadyExistsException
{
// resourceId is not important in user type credential, you can use anything you like
String dummyResourceId = com.bea.netuix.util.PortalFrameworkUtils.getUniquePortletDesktopString(request);
// this case use enterprise scope, so all portal web can see this entry, but not another enterpise app target to external users.
ResourceKey rc = new ResourceKey(Scope.getApplicationScope(), dummyResourceId);
return cvs.createCredentialEntry(entryName, EntryType.USER_TYPE, null, rc);
}
public static CredentialEntry getUserCredentialEntry(String entryName, HttpServletRequest request)
{
// resourceId is not important in user type credential, you can use anything you like
String dummyResourceId = com.bea.netuix.util.PortalFrameworkUtils.getUniquePortletDesktopString(request);
// this case use enterprise scope, so all portal web can see this entry, but not another enterpise app target to external users.
ResourceKey rc = new ResourceKey(Scope.getApplicationScope(), dummyResourceId);
return cvs.fetchCredentialEntry(entryName, EntryType.USER_TYPE, rc);
}
public static void removeUserCredentialEntry(String entryName, HttpServletRequest request)
{
// resourceId is not important in user type credential, you can use anything you like
String dummyResourceId = com.bea.netuix.util.PortalFrameworkUtils.getUniquePortletDesktopString(request);
// this case use enterprise scope, so all portal web can see this entry, but not another enterpise app target to external users.
ResourceKey rc = new ResourceKey(Scope.getApplicationScope(), dummyResourceId);
cvs.removeCredentialEntry(entryName, EntryType.USER_TYPE, rc);
}
// only portal administrator have the privilige to create system type credential
public static CredentialEntry createCommonCredentialEntry(String entryName, HttpServletRequest request)
throws AlreadyExistsException
{
// resourceId is not important in system type credential, you can use anything you like
String dummyResourceId = com.bea.netuix.util.PortalFrameworkUtils.getUniquePortletDesktopString(request);
// this case use enterprise scope, so all portal web can see this entry, but not another enterpise app target to external users.
ResourceKey rc = new ResourceKey(Scope.getApplicationScope(), dummyResourceId);
return cvs.createCredentialEntry(entryName, EntryType.SYSTEM_TYPE, null, rc);
}
public static CredentialEntry getCommonCredentialEntry(String entryName, HttpServletRequest request)
{
// resourceId is not important in system type credential, you can use anything you like
String dummyResourceId = com.bea.netuix.util.PortalFrameworkUtils.getUniquePortletDesktopString(request);
// this case use enterprise scope, so all portal web can see this entry, but not another enterpise app target to external users.
ResourceKey rc = new ResourceKey(Scope.getApplicationScope(), dummyResourceId);
return cvs.fetchCredentialEntry(entryName, EntryType.SYSTEM_TYPE, rc);
}
// only portal administrator have the privilige to create system type credential
public static void removeCommonCredentialEntry(String entryName, HttpServletRequest request)
{
// resourceId is not important in system type credential, you can use anything you like
String dummyResourceId = com.bea.netuix.util.PortalFrameworkUtils.getUniquePortletDesktopString(request);
// this case use enterprise scope, so all portal web can see this entry, but not another enterpise app target to external users.
ResourceKey rc = new ResourceKey(Scope.getApplicationScope(), dummyResourceId);
cvs.removeCredentialEntry(entryName, EntryType.SYSTEM_TYPE, rc);
}
}
The EmailAccountBacking
file shows an example of the portlet logic needed get and update an entry in a User (USER_TYPE
) Credential Vault. For more information about backing files, see
Backing Files in the Portlet Development Guide.
package examples.credential;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.bea.netuix.servlets.controls.content.backing.AbstractJspBacking;
import com.bea.netuix.servlets.controls.portlet.backing.PortletBackingContext;
import com.bea.netuix.servlets.controls.window.WindowCapabilities;
import com.bea.p13n.security.management.credentials.AlreadyExistsException;
import com.bea.p13n.security.management.credentials.CredentialEntry;
import com.bea.p13n.security.management.credentials.UserPasswordCredential;
public class EmailAccountBacking extends AbstractJspBacking {
private static final long serialVersionUID = -4933113295375846721L;
private CredentialEntry entry;
@Override
public boolean handlePostbackData(HttpServletRequest request, HttpServletResponse response)
{
// retrieve credential entry from vault
entry = CredentialHelper.getCredentialEntryForPortletInstance("emailAccount", request);
if ( isRequestTargeted(request) )
{
// get submitted parameters if transit from config page
String server = request.getParameter("server");
String protocol = request.getParameter("protocol");
String username = request.getParameter("username");
String password = request.getParameter("password");
if ( username != null && password != null)
{
if ( entry == null )
{
// create a new credential entry if not already exists
try
{
entry = CredentialHelper.createCredentialEntryForPortletInstance("emailAccount", request);
}
catch (AlreadyExistsException e)
{
e.printStackTrace();
}
}
// reset or update credential and/or properties
try
{
entry.setCredential(new UserPasswordCredential(username, password.getBytes("UTF-8")));
entry.setAttribute("server", server);
entry.setAttribute("protocol", protocol);
}
catch (Exception e)
{
e.printStackTrace();
}
}
else if (request.getParameter("delete") != null)
{
// delete the credential and move back to config page
CredentialHelper.removeCredentialEntryForPortletInstance("emailAccount", request);
PortletBackingContext.getPortletBackingContext(request).setupModeChangeEvent(WindowCapabilities.EDIT.getName());
return true;
}
return false;
}
if ( entry == null )
{
// no credential has been set, switch to config page
PortletBackingContext.getPortletBackingContext(request).setupModeChangeEvent(WindowCapabilities.EDIT.getName());
return true;
}
else if ( ! WindowCapabilities.VIEW.equals(PortletBackingContext.getPortletBackingContext(request).getWindowMode()) )
{
PortletBackingContext.getPortletBackingContext(request).setupModeChangeEvent(WindowCapabilities.VIEW.getName());
return true;
}
return false;
}
@Override
public boolean preRender(HttpServletRequest request, HttpServletResponse response)
{
// show this portlet for only login user
if ( request.getUserPrincipal() == null )
return false;
return true;
}
}
The index.jsp
displays the email account credential entry.
<%@ page language="java" contentType="text/html;charset=UTF-8"%>
<%@ taglib uri="http://www.bea.com/servers/portal/tags/netuix/render" prefix="render" %>
<%@page import="com.bea.p13n.security.management.credentials.UserPasswordCredential" %>
<%@page import="com.bea.p13n.security.management.credentials.CredentialEntry" %>
<%@page import="examples.credential.CredentialHelper" %>
<%
CredentialEntry entry = CredentialHelper.getCredentialEntryForPortletInstance("emailAccount", request);
if (entry == null)
{
out.println("Credential not exists. Click edit button on right of portlet title bar to config credential");
}
else
{
UserPasswordCredential credential = (UserPasswordCredential)entry.getCredential();
%>
Email account for this portlet instance is:
<form method="post" action="<render:windowUrl/>">
<table>
<tr>
<td>mail server: </td>
<td><%=entry.getAttribute("server")%>
</tr>
<tr>
<td>protocol: </td>
<td><%=entry.getAttribute("protocol")%>
</tr>
<tr>
<td>username: </td>
<td><%=credential.getPrincipalName()%>
</tr>
<tr>
<td>password: </td>
<td><%=new String(credential.getPrincipalPassword(), "UTF-8")%>
</tr>
<tr>
<td colspan="2" align="center">
<input type="hidden" name="delete" value="1">
<input type="submit" value="delete"/>
</td>
</tr>
</table>
</form>
<%
}
%>
The config.jsp
updates the email account credential entry.
<%@ page language="java" contentType="text/html;charset=UTF-8"%>
<%@ taglib uri="http://www.bea.com/servers/portal/tags/netuix/render" prefix="render" %>
<%@ page import="com.bea.netuix.servlets.controls.window.WindowCapabilities" %>
<form method="post" action="<render:windowUrl windowMode='<%=WindowCapabilities.VIEW.getName()%>'/>">
Note: do not leave field empty, this simple demo does not validate input.<br/>
Otherwise, a NPE exception may appear.
<table>
<tr>
<td>mail server: </td>
<td><input type="text" name="server"/>
</tr>
<tr>
<td>protocol: </td>
<td><input type="text" name="protocol" />
</tr>
<tr>
<td>username: </td>
<td><input type="text" name="username" />
</tr>
<tr>
<td>password: </td>
<td><input type="password" name="password" />
</tr>
<tr>
<td colspan="2" align="center"><input type="submit" value="save"/></td>
</tr>
</table>
</form>
The WebLogic Portal Administration Console provides an administrator with the ability to create a system credential vault. A system credential vault is a vault for a global username and password, as described in System Credential Vault.
Note: | When creating a system credential vault using the Portal Administration console, you are creating an enterprise application-scoped credential vault whose entries are not visible to a different enterprise application in the same domain. |
![]() ![]() ![]() |