Implementing single sign on in Weblogic

Jan Vermeir

In this post I will describe the proof of concept I've done for one of our customers in the Netherlands. The assignment was to implement Single Sign On using Weblogic Platform 10.2 infrastructure. I will explain the options available to pass security information around and describe the solution we've implemented.

Our customer is setting up a platform to host services in a SOA. Most of these services need the identity of the user to determine access rights. The idea is that a user will authenticate with a proxy server to access a page in Weblogic Portal. The portal page uses services developed in ALSB, which in turn delegate to services deployed in WLI. A service in WLI may call other services in ALSB or WLI to fulfill the request and return results to the user. An important requirement was that a solution should be as non-invasive as possible. This means infrastructure is preferred over code whenever possible.
An important aspect of the infrastructure is that Portal, ALSB and WLI run in separate domains. This means security information, most notably session data, cannot be easily shared.

The sequence diagram below shows a typical flow of a request through the infrastructure.

Flow of requests through the intrastructure

A user request arrives at a proxy. The proxy checks the users credentials (username/password, digital tokens, ...) in a Novell eDirectory instance and forwards the request to Portal.
The target platform was Weblogic Platform 10.2 (including Portal 10.2, WLI 10.2 and Server 10.0) and ALSB 3.0. The '2' in '10.2' may not seem like a terribly important detail, but unfortunately there is quite a difference in the standards supported by Platform 10.2 and Platform 10.3. Most importantly, the former doesn't support SAML2.0 while the latter does.

After discussing the problem with my customer we concluded that SAML would give us the cleanest implementation. SAML2.0 uses a security token that can be added to a request. Services can check the authenticity of the token and derive access rights from its contents. Unfortunately, using SAML2.0 would require additions to Weblogic's server classpath (i.e. the classpath used to start the JVM running Weblogic). One of the additions would be a new implementation of the XML parsing libraries. This would cause us to lose Oracle support, which would be unacceptable. Migrating to Weblogic Platform 10.3 would involve a lot of re-testing of applications so we thought that would be too much work for now.

The second best solution we came up with was SAML1.1, so I tried implementing that in the architecture sketched above. The problem now was that SAML1.1 seems intended to be used by web browsers: once a user is authenticated with SiteA and visits SiteB, SiteA and SiteB can transfer security tokens using browser redirects. The picture in sstc-saml-tech-overview-1.1-cd.pdf (see page 12) shows what is supposed to happen. In my case there is a session between browser and Portal, but not between browser and ALSB or browser and WLI. There is no redirection going on. We tried to get SAML1.1 to work in our architecture but had to give up in the end.

On to the next solution: passing username and password in WS-Security headers. I found there is a lot of confusion about WS-Security. It wasn't clear to me at first that it is no more than a transport for security information. You can use WS-Security to add security tokens to the header of a web service call. The token could be a SAML2.0 token or it could be username and password.
In my customers infrastructure, the portal is accessed through a proxy that authenticates the user. This means that username and password (or any other form of security token) are checked by the proxy and are not available to Portal at all. To set up a session in this architecture, the proxy has to log in to the portal. The easiest way to achieve that in our architecture was to protect Portal resources using basic authentication.

One of the jobs of the proxy component is to centralize access rights: a user has access only if there is a valid account in a directory, which is checked by the proxy. Applications behind the proxy manage role membership for users. The proxy has a separate account for each application. This allowed us to create a username/password combination exclusively for Portal, ALSB and WLI use. The password used can be different from the password as the user knows it. The user could even have a client certificate or a one time password generated by a token generator. This 'external identity' is translated to an 'internal identity' by the proxy.

In our architecture the proxy sets up a session with Portal. Portal then calls web services, passing in username and password in WS-Security headers. In order to do that Portal needs the username and password. Unfortunately the password is not available to an application deployed on Portal, though the username is (using request.getUserPrincipal()). We solved this problem by having the proxy add username and password as header parameters to the request.
So, Portal receives a request, say 'index.jsp', with basic authentication data and an extra set of username and password data passed in as header parameters. Portal checks username and password with the directory and starts a session for the user. The username and password data are retrieved from the request and stored in the users server side session:

       String username = (String) request.getHeader('X-USERNAME'); 
       String password = (String) request.getHeader('X-PASSWORD'); 

(Btw. Firefox has a plugin available to add headers to a request. This simplifies development because now I could test without having the proxy server installed. The plugin is named 'Modify Headers' and can be found here).

Using the username and password, Portal constructs a web service call. The code below adds username and password to the WS-Security header

          List credProviders = new ArrayList(); 
          CredentialProvider cp = new ClientUNTCredentialProvider(username.getBytes(), password.getBytes()); 
          credProviders.add(cp); 
          Stub stub = (Stub) port; 
          stub._setProperty(WSSecurityContext.CREDENTIAL_PROVIDER_LIST, credProviders); 

The easiest way to configure ALSB services is to have an existing WLI service deployed. So I adapted the HelloWorld service installed with Weblogic Platform and deployed it on WLI. The WLI service uses Weblogic's web service library, so security is added using tags in the Java source file:

@Policies({ 
    @Policy(uri='policy:Auth.xml', direction=Policy.Direction.inbound) 
}) 
public class SecureHelloWorldImpl { 
  @WebMethod() 
  public String sayHello(String s) { 
    // Implementation goes here
  }
}

The code above produces a web service that accepts a string and is accessible only if the WS-Security header in the request contains some form of authentication. It is easy to test the service using the client code provided by the Weblogic samples. I also found Soap UI helpful to construct a request based on the WSDL for the service.

In ALSB I created a business service using the WSDL produced by the service in WLI. For security our ALSB services rely on services in WLI. This means you can call the ALSB service, but the call may fail because the user has insufficient access rights for the WLI service. The business service is called by a ALSB proxy service which defines the routing for the request. It may also change the request, so I used the string replace functions to add a label that allowed me to trace the request on its way through the infrastructure.
In order to get this to work with the secured WLI service, you have to add a so-called service account to the ALSB project and configure it in 'pass through' mode. Now the security information in the WS-Security header is passed on to WLI. ALSB doesn't itself check the security, but in our case WLI performs all authorization necessary.

The enabler for all this is the central LDAP directory. We had to configure each Weblogic domain to check access rights in the same Novell directory. Because Weblogic offers a authentication provider for Novell, this part was easy enough.

To summarize: a request from a users browser is enhanced with username and password data by a proxy server. The proxy server delegates to a Portal application protected using basic authentication. The portal page constructs a request to WLI which passes through ALSB. The Weblogic webservices framework uses the security information in the WS-Security header to base its access right decisions on.
The net effect is that services in WLI can be called with the end users identity without adding security checking to business code.

Comments (4)

  1. Pankaj - Reply

    November 26, 2009 at 3:12 pm

    Hi,
    I alo want to implement a logic for single sign on for my application deployed on Sun app server. Justwanted to know how by using proxy we can add headers to the request and forward that request thar request to our application.

    Thanks,
    Pankaj

  2. Jan Vermeir - Reply

    November 27, 2009 at 8:54 am

    Hi Pankaj, my customer was using Novell e-directory and some custom code to check user credentials. One of the features of their solution is that it allows them to extend and modify a request from a browser before forwarding to app servers. I guess that should be possible with proxies in general. I don't know the full software stack you're using, but if there's Apache in there somewhere you can probably find a module that allows you to modify the request.
    We also found a way to get to the user credentials without explicitly adding them to headers. Weblogic allows you to add an authenticator to a chain of authenticators. A request is routed to the first authenticator in the chain. This code tries to validate credentials. If it fails control is passed to the next authenticator in the chain.
    What we did is develop a custom authenticator that reads the username and password from the basic authentication headers and places them in a new set of header parameters. Then it reports failure and control is passed to an LDAP authenticator. This authenticator validates username and password from the BA headers, reports success and removes the password from the header. In our JSP we then accessed the password from the headers added by our custom authenticator.
    This solution relies on a feature of Weblogic, but I'm sure Sun's app server will offer something similar.

  3. pankaj - Reply

    November 30, 2009 at 1:51 pm

    Thanks Jan. I will have to find out how can we implement the same in Sun App server. Actually the problem is that I cannot modify the code deployed on Application server. I cannot add some filters in say web.xml which will modify the request.
    I want to develop a application similiar to Site Minder application.

  4. Jan Vermeir - Reply

    November 30, 2009 at 5:50 pm

    Hi Pankaj, my solution does not require you to update any web.xml files. I thought I had to adapt all applications, like I did for the Portal part, but that turned out to be unnecessary because in Weblogic you can change the request before it is processed by an application. In my case there is some sort of paradigm-switch going on: a html/http request is transformed into a xml/http request by Portal. So without being able to change the portal app, it's going to be difficult.
    You may consider doing a redirect using a component before your web app is accessed? like some sort of server-wide login filter?

Add a Comment