Writing a Liberty Service Provider in Java

Author: Nicolas Clapiès
Contact: nclapies@entrouvert.com
Date: 2006-10-27
Revision: 1.1
Copyright: Copyright © 2006 Entr'ouvert

1   Lasso Java Binding Settings

Java binding of Lasso is implemented by the Java package lasso.jar. In order to compile Java sources importing this package, you need to set environment variable CLASSPATH:

export CLASSPATH=$CLASSPATH:/path/to/lasso/jar/lasso.jar

Lasso Java package is linked to C Lasso library thanks to JNI interface library. Under UNIXes like Linux, the library is named linjlasso.so. Under Mac OS X, library is named libjlasso.dynlib. Windows systems need jlasso.dll. You need to add library directory path to system library loader.

For UNIXes system with bash, command is like:

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/path/to/lasso/jni/interface/

where /path/to/lasso/jni/interface/ is the Lasso JNI interface hosting directory.

2   Liberty and Lasso profiles

Lasso provides the necessary functions to implement Liberty Alliance profiles, as defined in the Liberty ID-FF Bindings and Profiles Specification :

  • Single Sign-On and Federation
  • Single Logout
  • Federation Termination Notification

3   Lasso settings

Java applications first need to import Lasso package:

import com.entrouvert.lasso.*;

4   Service Provider keys and metadata files

4.1   Liberty key files

Service Provider needs private and public keys to sign sent messages. It also needs Identity Provider public key to verify received messages. Private and public keys are loaded from PEM files by Lasso.

4.2   Liberty Metadata files

Service Provider need to get Identity Provider metadata to know where to send requests and how to process received requests from Identity Provider. Metadata are xml document describing provider identifier, deployed urls where to send requests and initiate profile and methods describing how to send or process requests.

Service provider typically describe metadata like this:

<?xml version="1.0"?>
<EntityDescriptor
  providerID="http://sp.example.com/liberty/metadata"
  xmlns="urn:liberty:metadata:2003-08">
  <SPDescriptor protocolSupportEnumeration="urn:liberty:iff:2003-08">
      <SoapEndpoint>http://sp.example.com/liberty/soap-endpoint</SoapEndpoint>
      <SingleLogoutServiceURL>sp.example.com/liberty/single-logout</SingleLogoutServiceURL>
      <AssertionConsumerServiceURL id="AssertionConsumerService1"isDefault="true">http://sp.example.com/liberty/assertion-consumer-service</AssertionConsumerServiceURL>
      <FederationTerminationNotificationProtocolProfile>http://projectliberty.org/profiles/fedterm-idp-soap</FederationTerminationNotificationProtocolProfile>
      <FederationTerminationNotificationProtocolProfile>http://projectliberty.org/profiles/fedterm-idp-http</FederationTerminationNotificationProtocolProfile>
      <SingleLogoutProtocolProfile>http://projectliberty.org/profiles/slo-idp-soap</SingleLogoutProtocolProfile>
      <SingleLogoutProtocolProfile>http://projectliberty.org/profiles/slo-idp-http</SingleLogoutProtocolProfile>
      <SingleLogoutProtocolProfile>http://projectliberty.org/profiles/slo-sp-soap</SingleLogoutProtocolProfile>
      <AuthnRequestsSigned>true</AuthnRequestsSigned>
  </SPDescriptor>
  <Organization>
      <OrganizationName>Example Organization</OrganizationName>
  </Organization>
</EntityDescriptor>

Where sp.example.com is the domain name of Service Provider.

http://sp.example.com/liberty/metadata is the Service Provider Liberty identifier.

http://sp.example.com/liberty/soap-endpoint is the Service Provider SOAP endpoint where Identity Provider send SOAP single logout or defederation requests.

http://sp.example.com/liberty/assertion-consumer-service is the Service Provider assertion consumer url where Identity Provider must return single sign on authentication response.

http://sp.example.com/liberty/single-logout is the Service Provider single logout url. Service Provider can initiate single logout from this url or process HTTP single logout request from Identity Provider. `

5   Lasso Server and remote providers settings

5.1   LassoServer

Every time needing to initiate a Liberty Profile or process a Liberty request, Lasso needs to set a Lasso Profile object with a Lasso Server to set Service Provider informations (private key and metadata) and identity Provider informations (public key, certificate and metadata).

The Server object may be created as follows:

Server lassoServer = new Server("sp-metadata.xml",
                "sp-privatekey.pem", null, null);
lassoServer.addProvider(lasso.PROVIDER_ROLE_IDP,
                "idp-metadata.xml", "idp-publickey.pem", null);
  • sp-metadata.xml is the Liberty metadata file of the service provider
  • idp-metadata.xml is the Liberty metadata file for the identity provider
  • sp-privatekey.pem is the service provider private key; used to sign documents
  • idp-publickey.pem is the identity provider public key; used to verify signature in documents sent by the identity provider

5.2   Serialisation

It can be useful to dumps Server object and save it for next use. LassoServer objects can be serialised into a XML formatted string:

String lassoServerDump = lassoServer->dump();`

It is then really easy to get back properly constructed objects:

Server lassoServer = Server.newFromDump(lassoServerDump);

6   Single Sign On

Initiating Single Sign On:

Login lassoLogin = new Login(lassoServer);
lassoLogin.initAuthnRequest(lassoServer.getProviderIds().getItem(0),
                lasso.HTTP_METHOD_REDIRECT);
LibAuthnRequest authnRequest = (LibAuthnRequest) login.getRequest();
authnRequest.setNameIdPolicy(lasso.LIB_NAMEID_POLICY_TYPE_FEDERATED);
authnRequest.setProtocolProfile(lasso.LIB_PROTOCOL_PROFILE_BRWS_ARTIFACT);
lassoLogin.buildAuthnRequestMsg();
String msgUrl = lassoLogin.getMsgUrl();

Processing Single Sign On Identity Provider Artifact response from AssertionConsumerServiceURL metadata URL:

lassoLogin.initRequest(queryString, lasso.HTTP_METHOD_REDIRECT);
lassoLogin.buildRequestMsg();
String soapEndpoint = lassoLogin.getMsgUrl();
String soapRequestMsg = lassoLogin.getMsgBody();
// If a lassoSessionDump or a lassoIdentityDump was saved, restore them.
lassoLogin.setSessionFromDump(lassoSessionDump);
lassoLogin.setIdentityFromDump(lassoIdentityDump);
try {
  lassoLogin.acceptSso();
} catch (RuntimeException e) {
}
String lassoSessionDump = lassoLogin.getSession().dump();
String lassoIdentityDump = lassoLogin.getIdentity().dump();
String nameIdentifier = lassoLogin.getNameIdentifier().getContent();

7   Single Logout

7.1   Initiate SOAP Single Logout from Service Provider

Initiating single logout from SingleLogoutServiceURL metadata url:

Logout lassoLogout = new Logout(sp.server);
lassoLogout.setSessionFromDump(lassoSessionDump);
lassoLogout.setIdentityFromDump(lassoIdentityDump);
lassoLogout.initRequest(sp.server.getProviderIds().getItem(0),
              lasso.HTTP_METHOD_SOAP);
lassoLogout.buildRequestMsg();
String soapEndpoint = lassoLogout.getMsgUrl();
String soapRequestMsg = lassoLogout.getMsgBody();
// Send SOAP request and get SOAP response ...
try {
  lassoLogout.processResponseMsg(soapResponseMsg);
} catch (RuntimeException e) {
  // an error occured
  return;
}
// Everything is ok, remove lasso session dump from application storage

7.2   Process Single Logout HTTP request from Identity Provider

Process single logout from SoapEndpoint metadata url:

Logout lassoLogout = new Logout(lassoServer);
lassoLogout.processRequestMsg(logoutRequestMsg);
lassoLogout.setIdentityFromDump(lassoIdentityDump);
lassoLogout.setSessionFromDump(lassoSessionDump);
try {
   lassoLogout.validateRequest();
} catch (RuntimeException e) {
}
lassoLogout.buildResponseMsg();
String soapResponseMsg = lassoLogout.getMsgBody();

8   Defederation

Processing SOAP defederation from SoapEndpoint metadata url:

if (lasso.getRequestTypeFromSoapMsg(soapRequestMsg) == lasso.REQUEST_TYPE_DEFEDERATION) {
  Defederation lassoDefederation = new Defederation(lassoServer);
  lassoDefederation.processNotificationMsg(soapRequestMsg);
  lassoDefederation.setIdentityFromDump(lassoIdentityDump);
  try {
      lassoDefederation.validateNotification();
  } catch () {
    // an error occured
  }
  // return 204 HTTP status code
}

9   Database Considerations

Lasso has been designed to let the service provider keep on using existing databases. Typically there is already a table describing users; just add an identity dump column to the existing table:

User Id existing data (name, address...) Identity dump
1 ... <Identity> ...
2 ... <Identity> ...

Mapping between existing users and name identifiers sent by the identity provider can be done with a simple table.

Name Identifier User Id
AQWWRRS... 1
CGFASDE... 2
YYSSSDS... 1

Note

A separate table is needed because one user Id could map to several name identifiers; in case there are several identity providers.

Sessions are also commonly stored in databases; just add a session dump column to the existing session table:

Session Id misc session data Session dump
6744066 ... <Session> ...
3338824 ... <Session> ...

Likewise sessions should be mapped to name identifiers.

Name Identifier Session Id
AQWWRRS... 3338824