Consider a situation where you have an existing Web application, deployed on IBM® WebSphere® Application Server, which enables employees to submit requests for scheduling vacations. The corporate directory is used to secure the application. Suppose you want to deploy a portal or workplace environment that pulls together various types of content of interest to employees, including the ability to make vacation requests. Rather than redeploying the human resources (HR) application that handles vacation requests, you can write portlets which make use of the application remotely. Figure 1 illustrates a simple view of integrating this employee portal with the existing HR application.
Figure 1. Adding a portal to the architecture

In order to integrate an existing Web application, which has been set up with security, into a portal, you have to determine how your portlets will connect to the Web application and handle user authentication. By writing a portlet service to connect to the Web application you hide the details of this integration from the individual portlets. You also allow yourself to change the way that you use the Web application in the future without updating the code in all of the portlets.
This article illustrates how a portlet service can be used to connect to the session beans of a remote Web application in a secure environment. It will then describe how to update the portlet service to connect to servlets instead, without requiring any changes to the portlets that use the portlet service.
To get the most out of this article, you should be familiar with enterprise application security concepts, portlet development, and portlet service development.
For the example in this article a number of assumptions are made about the remote Web application:
- It is on IBM WebSphere Application Server V5.1.
- Security is enabled.
- The Web application and portal both use the same LDAP directory and LTPA mechanism for authentication.
- The business logic of the application is in or behind a layer of session beans; for example, the Web application makes use of the Session Facade pattern.
- Access to the session beans is restricted. Individual portal users do not have access, but a single LDAP user id can be used to access all the session beans.
A PortletService interface is provided with WebSphere Portal which you can extend and implement to add your own portlet service to the portal. The CredentialVaultService is an example of a portlet service that is provided by WebSphere Portal. Refer to the product documentation for details on portlet services.
The portlet service provides the business methods that your portlets need to call in order to use the business functionality provided by the remote Web application. These connect to the session beans of your remote Web application. The implementation of these methods depends on the requirements of your application.
Because the portal users do not have access to the remote Web application, the portlet service needs to authenticate with a different user id. This user id and password are obtained from the WebSphere Portal credential vault, shown in Figure 2. For the portlet service to get these from the credential vault, it needs the PortletRequest and PortletConfig objects from the portlet. Therefore, you add methods to the portlet service which the portlets set prior to calling any of the business methods.
Figure 2. Setting up the shared credential vault slot

Within the business methods you need to programmatically login with the user id that has access to the session beans, and then call the methods on the session beans within the context of the authenticated Subject. The session beans only see the user that you just authenticated--not the user that is logged into the portal.
For the example of submitting a vacation request, create a portlet service named HRPortletService. The VacationRequest portlet and HRPortletService perform the task of submitting the request roughly as follows:
VacationRequestgets an instance ofHRPortletService.VacationRequestsupplies HRPortletServicewith the currentPortletConfigandPortletRequestobjects using setter methods. These are needed later by the portlet service to successfully retrieve the shared credential.VacationRequestcalls the HRPortletServicemethod for submitting a vacation request,submitRequest, passing in the value object expected by the remote HR application. WithinsubmitRequest, the following occurs:HRPortletServicegets the loginSubjectusing thePortletConfigandPortletRequestobjects it was given earlier.HRPortletServicelooks up the HR application session bean using the login SubjectHRPortletServicecalls thesubmitRequestbusiness method of the session bean within theSubject's security context.
Before looking at the HRPortletService.submitRequest method, let's look at the methods that it needs to call. The two methods shown below are used together to get the login Subject. The first logs into the Web application and returns the Subject object, which is used later to make calls to the session bean. The second method is called by the first method to obtain the credential from the credential vault that is used to login to the remote Web application hosted on the fictional mywebapp.ibm.com server. The code that follows was tested in WebSphere Portal 5.0.2, and it is also supported in WebSphere Portal V5.1.
Listing 1. Logging in to the remote Web application
private javax.security.auth.Subject getLoginSubject(PortletConfig pc,
PortletRequest portletRequest) throws HRPortletServiceException
{
StringBuffer userId = new StringBuffer("");
StringBuffer password = new StringBuffer("");
UserPasswordPassiveCredential credential = getCredential(pc,portletRequest);
if( credential != null) {
userId.append(credential.getUserId());
password.append(String.valueOf(credential.getPassword()));
}
LoginContext lc;
javax.security.auth.Subject s=null;
try
{
System.out.println("Login as user: " + userId);
lc = new LoginContext("ClientContainer",
new WSCallbackHandlerImpl(userId.toString(),"mywebapp.ibm.com",
password.toString()));
lc.login();
s = lc.getSubject();
}
catch (LoginException le1)
{
System.err.println("Cannot create LoginContext: "+le1.getMessage());
System.err.println("Throwing HRPortletServiceException");
throw new HRPortletServiceException();
}
return s;
}
private UserPasswordPassiveCredential getCredential(PortletConfig pc,
PortletRequest portletRequest)
{
CredentialVaultService vaultService = null;
try
{
vaultService = (CredentialVaultService)
pc.getContext().getService(CredentialVaultService.class);
}
catch (PortletServiceNotFoundException e)
{
System.err.println("credential vault service not found");
}
catch (PortletServiceUnavailableException unavail)
{
System.err.println("credential vault service unavailable: "+unavail);
}
UserPasswordPassiveCredential credential = null;
try
{
if( vaultSlot != null ) {
credential = (UserPasswordPassiveCredential)vaultService.getCredential(vaultSlot,
"UserPasswordPassive",new HashMap(),portletRequest);
}
}
catch (CredentialSecretNotSetException e)
{
System.err.println("no credential secret: "+e);
}
catch (PortletServiceException e2)
{
System.err.println("error with portletservice: "+e2);
}
return credential;
}
|
After logging in, submitRequest needs to look up the remote home for the session bean. The method below performs this task. It makes use of the Subject object obtained from the getLoginSubject method above. This Subject object represents the authenticated user that has access to the session bean. The remote session bean is returned to be used to call the bean's business methods.
Listing 2. Looking up the remote session bean
private HRRequestSessionRemote getSessionEJB(javax.security.auth.Subject s)
{
Object sessionObj = null;
sessionObj = com.ibm.websphere.security.auth.WSSubject.doAs(s,
new java.security.PrivilegedAction()
{
public Object run() {
HRRequestSessionRemote session = null;
try
{
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY,
"com.ibm.websphere.naming.WsnInitialContextFactory");
env.put(Context.PROVIDER_URL, "corbaloc:iiop:mywebapp.ibm.com:2809");
Context initialContext = null;
initialContext = new InitialContext(env);
Object o = initialContext.lookup(serverJNDIName);
HRRequestSessionRemoteHome home=null;
home =(HRRequestSessionRemoteHome) PortableRemoteObject.narrow(o,
HRRequestSessionRemoteHome.class);
session = home.create();
}
catch (Exception sessionExc)
{
System.err.println("Error getting session: " + sessionExc);
}
return session;
}
}
); //end doAs
return (HRRequestSessionRemote) sessionObj;
}
|
You can use the above methods in all your portlet service business methods to make calls to the remote Web application. This call is illustrated below in the implementation of the submitRequest method, which submits an HRRequest object to the Web application for processing:
Listing 3. Submitting the request to the Web application
public void submitRequest(HRRequest newRequest) throws HRPortletServiceException
{
if (newRequest != null)
{
final HRRequest newReq = newRequest;
javax.security.auth.Subject s = getLoginSubject(pc,request);
final HRRequestSessionRemote session = getSessionEJB(s);
if (session != null)
{
//doAs programmatic login userid
com.ibm.websphere.security.auth.WSSubject.doAs(s,
new java.security.PrivilegedAction()
{
public Object run() {
Vector reqs=null;
try
{
session.submitRequest(newReq);
}
catch (RemoteException runExc)
{
System.out.println("Submit request run failed:" + runExc);
}
return null;
}
}
); //end doAs
}
else
{
System.err.println("Error obtaining session bean to submit request for: "+
newReq.getRequestorShortName());
throw new HRPortletServiceException();
}
}
}
|
The code uses a PrivilegedAction in the getSessionEJB method to look up the session bean's home, and again in the submitRequest method for calling the session bean's submitRequest method. All interaction with the session bean must be within the context of the Subject object. The bean lookup and submitRequest method call were not combined so that the session bean lookup code would not need to be duplicated each time you need to call a different method on the session bean.
As outlined, to make use of this portlet service you first need to get an instance of the service. Then, you pass the PortletConfig and PortletRequest objects to the service, which needs them for getting the credential out of the credential vault. Finally, you call the business method on the portlet service. An example code fragment from the VacationRequest portlet which makes use of the submitRequest method is included here:
Listing 4. Calling the portlet service from a portlet
if (portletConfig!=null) {
if (portletConfig instanceof PortletConfig) {
PortletContext portletContext= portletConfig.getContext();
if (portletContext!=null) {
hrService = (HRPortletService) portletContext.getService(HRPortletService.class);
}
}
}
hrService.setPortletConfig(portletConfig);
hrService.setPortletRequest(portletRequest);
hrService.submitRequest(hrRequest);
|
Changing the portlet service to use servlets
In the previous section, you used a portlet service to connect to the session beans of a remote Web application. This section describes the changes necessary to the portlet service to call servlets instead. Because all the code for accessing the remote Web application was placed in a portlet service, only the portlet service needs to be updated. The portlets are unaffected.
Changes to the assumptions for the Web application
For this section, the following assumptions are made about the Web application, replacing numbers four and five in Web application configuration.
- The business logic of the application is in, or behind, a layer of servlets.
- Access to the servlets is restricted to authenticated users. The individual authenticated portal users have access to the servlets.
Changes to the portlet service
The getLoginSubject and getSessionEJB methods implemented above are no longer necessary. Use an HttpURLConnection to call the remote Web application's servlets. For the objects that you need to pass to and from the Web application, serialize them to the connection's input and output streams. To gain access to the Web application, retrieve the LTPA token from the PortletRequest object and add it to the HttpURLConnection to the Web application. Here's the code for retrieving the token:
Listing 5. Retrieving the LTPA token to access the Web application
private String getLtpaToken() {
Cookie[] cookies = portletRequest.getCookies();
String LtpaToken = null;
if (cookies != null && cookies.length > 0) {
for (int i = 0; i < cookies.length; i++) {
if (cookies[i].getName().equalsIgnoreCase("LtpaToken")){
LtpaToken = cookies[i].getValue();
}
}
}
return LtpaToken;
}
|
Here is the submitRequest method that you saw earlier, updated to connect to a servlet:
Listing 6. Connecting to a remote servlet
public void submitRequest(HRRequest newRequest)
throws HRPortletServiceException {
URL url=null;
HttpURLConnection con=null;
OutputStream os =null;
OutputStreamWriter osw = null;
ObjectOutputStream oos = null;
ObjectInputStream results = null;
try
{
url = new URL(submitRequestsURL);
con = (HttpURLConnection)url.openConnection();
con.setRequestProperty("Cookie","LtpaToken="+getLtpaToken());
con.setDoInput(true);
con.setDoOutput(true);
con.setAllowUserInteraction(true);
os = con.getOutputStream();
osw = new OutputStreamWriter(os);
oos = new ObjectOutputStream(os);
oos.writeObject(newRequest);
osw.flush();
results = new ObjectInputStream(con.getInputStream());
}
catch(Exception e)
{
e.printStackTrace();
}
finally
{
try
{
if(os!=null)
os.close();
if(osw!=null)
osw.close();
if(oos!=null)
oos.close();
if(results!=null)
results.close();
}
catch(Exception e)
{
e.printStackTrace();
}
}
}
|
In this article you've seen how a portlet service can be used to encapsulate the integration of your portal with a remote Web application. Within this portlet service, you have used two different implementations for connecting to a remote Web application in a secure environment.
- For a tour of Java authorization mechanisms, see Java authorization internals
- For details on the Session Facade pattern, see Rules and Patterns for Session Facades
- WebSphere Portal zone provides an ever-growing collection of technical resources related to WebSphere Portal.
- WebSphere Portal product documentation provides access to all the latest product documentation for all versions and editions of WebSphere Portal.
- For an overview of the credential vault, see Using Credential Vault to Provide Single Sign-on for Portlets
- For another example which uses a portlet service, see Improving the performance of WebSphere Portal applications using the expirable properties portlet service.





