SSO between BEA WebLogic Server and SAP Enterprise Portal (Web Dynpro) using Web services

You’re looking for a way to consume Web services in SAP NetWeaver 2004s (and SAP Composition Environment aka NetWeaver 7.1) from BEA WebLogic Server 8.1 (and newer versions) using Single Sign On (SSO)?

You may have figured out already that SAML is not an option here because the SAP side is just a SAML consumer and not a provider (as of today). The only way left is to use the proprietary SAP Logon Tickets. Proprietary authentication mechanisms always require some extra work. In this blog article I’ll fill you in on what you need to SSO-connect those two J2EE platforms.

Here’s what you need for BEA WebLogic Server:

  • Develop your own identity asserter which is able to read the MYSAPSSO2 ticket string from the cookie in your HTTP header.
  • Verify the ticket using the SAPSSOEXT and SAPSECU libraries (see my earlier post for some hints) within your new identity asserter. You can download verify.pse from the keystore in your SAP Enterprise Portal.
  • The user provided in the ticket has to be authenticatable in your LDAP or whatever directory mechanism you use in WebLogic Server to authenticate users.
  • Your Web service has to use perimeter authentication or your new identity asserter won’t be triggered for an in coming request.

Here’s what you need on the Enterprise Portal side:

  • Every SSO Web service you want to call from a SAP Web Dynpro has to be defined as a Dynamic Web Service Proxy in Visual Admin.
  • When generating the Webservice model from the WSDL you have to provide the name of the Dynamic Web Service Proxy.

Web service configuration

To use perimeter authentication you have to change your web.xml so it looks similar to this:

Sample web.xml

<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>

	<servlet>
		<servlet-name>XFireServlet</servlet-name>
		<display-name>XFire Servlet</display-name>
		<servlet-class>
			org.codehaus.xfire.transport.http.XFireConfigurableServlet
		</servlet-class>
	</servlet>

	<servlet-mapping>
		<servlet-name>XFireServlet</servlet-name>
		<url-pattern>/services/*</url-pattern>
	</servlet-mapping>

<security-constraint>
		<web-resource-collection>
			<web-resource-name>Success</web-resource-name>
			<url-pattern>/*</url-pattern>			
			<http-method>POST</http-method>
		</web-resource-collection>
		<auth-constraint>
			<role-name>SomeRole</role-name> 
		</auth-constraint>
	</security-constraint>
	
	<login-config>
		<auth-method>CLIENT-CERT</auth-method>
		<realm-name>myrealm</realm-name>
	</login-config>

	<security-role>
		<role-name>SomeRole</role-name>
	</security-role>

</web-app>

Sample weblogic.xml (nothing fancy in here)

<!DOCTYPE weblogic-web-app PUBLIC "-//BEA Systems, Inc.//DTD Web Application 8.1//EN" "http://www.bea.com/servers/wls810/dtd/weblogic810-web-jar.dtd">

<weblogic-web-app>

	<security-role-assignment>
		<role-name>SomeRole</role-name>
		<externally-defined />
	</security-role-assignment>

</weblogic-web-app>

CLIENT-CERT enables perimeter authentication in WebLogic Server. If you don’t use XFire then most other lines may not be of interest to you.

Important: You don’t have to use SSL to be able to use perimeter authentication tokens in WebLogic (but of course you can if you want to).

Weblogic configuration, perimeter authentication

Develop a custom Identity Assertion Provider that extracts the MYSAPSSO2 cookie and validates it using the SAPSSOEXT and SAPSECU libraries. See BEA’s documentation about how to develop custom identity asserters.

Sample BEA WebLogic Identity Asserter MBean XML:

.
.
.
 <!-- You must set the value of the SupportedTypes attribute
      (inherited from the 
       weblogic.management.security.authentication.IdentityAsserter mbean)
      to the list of token types that your identity asserter supports.

      Whoever is initiating the identity assertion (eg. a client sending
      a perimeter authentication token via an HTTP request header), must
      use the same token type.
 -->
 <MBeanAttribute  
  Name 		= "SupportedTypes"
  Type 		= "java.lang.String[]"
  Writeable 	= "false"
  Default 	= "new String[] { "MYSAPSSO2" }"
 />
 <!-- The ActiveTypes attribute (a settable attribute inherited from the
      weblogic.management.security.authentication.IdentityAsserter mbean)
      contains the subset of your mbean's SupportedTypes that are active
      in the realm.
 -->
 <MBeanAttribute  
  Name 		= "ActiveTypes"
  Type 		= "java.lang.String[]"
  Default 	= "new String[] { "MYSAPSSO2" }"
 />
.
.
. 

Sample BEA Idendity Asserter Class:

package com.trick77.identityassertion;

import javax.naming.Context;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.login.AppConfigurationEntry;

import com.mysap.sso.SSO2Ticket;

import weblogic.jndi.Environment;
import weblogic.management.MBeanHome;
import weblogic.management.security.ProviderMBean;
import weblogic.security.spi.AuthenticationProvider;
import weblogic.security.spi.IdentityAsserter;
import weblogic.security.spi.IdentityAssertionException;
import weblogic.security.spi.PrincipalValidator;
import weblogic.security.spi.SecurityProvider;
import weblogic.security.spi.SecurityServices;
import weblogic.utils.StringUtils;
import weblogic.logging.NonCatalogLogger;

public final class SapSSO2TicketIdentityAsserterProviderImpl implements AuthenticationProvider, IdentityAsserter {

	final static private String TOKEN_TYPE = "MYSAPSSO2"; // the kind of token's we handle

  .
  .
  .
  
	public CallbackHandler assertIdentity(String aType, Object aToken) throws IdentityAssertionException {
		debug("SapSSO2TicketIdentityAsserterProviderImpl.assertIdentity");
		debug("assertIdentity: type=" + aType + "token=" + aToken);
	
		// check the token type
		if (!(TOKEN_TYPE.equals(aType))) {
			String _error = "SapSSO2TicketIdentityAsserter received unknown token type \"" + aType + "\".";
			error(_error);
			throw new IdentityAssertionException(_error);
		}

		// make sure the token is a byte array
		if (!(aToken instanceof byte[])) {
			String _error = "SapVisumIdentityAsserter received unknown token class \"" + aToken.getClass() + "\"." + " Expected a byte[].";
			error(_error);
			throw new IdentityAssertionException(_error);
		}

		debug("MYSAPSSO2_Asserter.assertIdentity: Class of aToken: [" + aToken.getClass() + "]");
		String _strToken = new String((byte[]) aToken);
		debug("MYSAPSSO2_Asserter.assertIdentity: String _token: [" + _strToken + "]");
		
		.
		.
		.
		read verify.pse path
		validate _strToken using SSO2Ticket
		.
		.
		.
		// Use the embedded username from the decrypted Sap Logon Ticket in your own javax.security.auth.callback.CallbackHandler.
		return new MySapCallbackHandlerImpl(_sapTicket.getUser());
	}
	
	.
	.
	.

}

Once the custom identity asserter is available to your WebLogic instance you can configure it here (screenshots for WebLogic 8.1 console)WebLogic authenticator configuration

The TOKEN_TYPE in our case is MYSAPSSO2 because that’s the name of the key in the cookie when your Web Dynpro calls into the Web service in BEA WebLogic.WebLogic token configuration

Make sure Base64 decoding isn’t checked because the native SAP ticket validation libraries need an encoded ticket. The received ticket is already Base64 encoded.WebLogic Base64 decoding

SAP NetWeaver NWDS/J2EE server configuration

Click the screenshot below for a Dynamic Web Service Proxy configuration sample in Visual Admin. I’m using the XFire Web service implementation with dynamic Aegis binding in BEA Weblogic so my WSDL is always accessible with the ?wsdl Parameter.

Dynamic webservice proxy configuration in Visual Admin

The next step is to import the WSDL and to generate your Web dynpro Web service model. Enter the name of your Dynamic Web Service Proxy in the default destination fields like this:
Proxy destinations configuration

Make sure your WSDL is accessible without any authentication.

The certificate (verify.pse) to validate the incoming SAP Logon Tickets can be downloaded in SAP Enterprise Portal:
Where to download the verify.pse certificate