Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

Version 1 Next »

Overview

The library was envisioned as a utility that makes the use of delegated SAML authentication easy for portlet developers. SAML designers realized that the authentication, attribute release, and federation of authentication services is very complex. That's why they have promoted the use of authentication and attribute release as "layers" removed from the Web application developers and administered by dedicated security experts.

The goal of this library is to make delegated SAML authentication, where the portal acts as a proxy on behalf of the user, just as easy for the portlet developers.

The reader of this document should be familiar with concepts outside the scope of this library. Unfortunately, this means a lot of concepts, including:

  • Public key cryptography
  • Digital certificates
  • Digital signatures
  • TLS/SSL
  • Web services
  • All standards behind portals
    • Enterprise Java
    • Web filters
    • Portlets

The reader does not have to be an expert in any of these but should understand the concepts. The writer is not an expert in most of these, either.

Design

Background

There are myriad of ways that developers can write portlets. From the low-level servlet-like programming to rich Model-View-Controller (MVC) frameworks, portal developers can choose complexity vs. efficiency or performance vs. size to sample just a few of the choices available to portlet developers.

The overriding design principle of this project is to avoid restricting these choices in any way. For example, the library supports logging, but at the same time allows developer to choose a logging framework to use.

While the library is designed for use with portlets, it should be usable from non-portlet code, provided that a method of obtaining a SAML assertion and optional IdP public key is devised. The only method that works with this library is for portlets running in uPortal.

At the same time, it is important to recognize the value of existing open source frameworks and avoid "reinventing the wheel." For functionality not available with standard Java distributions and portal servers, the designers of this library have turned to existing projects, like Apache Commons HTTP Client or OpenSAML for Java.

Recognizing that portlet developers may use this library to access a Web service, from RESTful, through SOAP to simple HTML, the design of the library concentrated on performing authentication and then relaying on the underlying transport to maintain a secure session with the Web Service Provider (WSP). Apache Commons HTTP Client supports "stateful" Web sessions much like browsers do, and the library makes such a session available to the portlet and steps out of the way.

XML Processing

SAML messages are complex XML documents using a multitude of namespaces. The library discussed here is mostly a proxy passing these messages to work within the SAML 2 Enhanced Client or Proxy (ECP) profile. To keep the XML processing efficient and keeping in mind the need to preserve the SAML assertions' integrity, the XML processing in the library relies on DOM and XPath. SAML assertions are digitally signed and even the most innocuous changes would break the assertions' digital signatures.

Generally speaking, the library processes an XML message like so:

  1. breaks it down into a DOM tree
  2. examines it for validity, if applicable
  3. retrieves and removes information targeted at the ECP
  4. adds information that the recipient may require from the ECP
  5. serializes the message for transmission

The DOM tree of each processed message is not kept. The only exception is the SAML assertion DOM because it is needed in several places.

Delegated SAML Authentication

To accomplish delegated SAML authentication, there are several interactions that all the involved players (user, IdP, portal, portal's SP, portlet, WSP) must perform. These interactions are best illustrated in this diagram from the Shibboleth Web site.

What the above footnotes do not distinguish is which component is responsible for which of these interactions.

Steps 1-4 are initiated by the user, and partly automated by the portal's SP and the IdP via HTTP redirection. The user has to provide credentials to the IdP, unless a valid Single Sign-On (SSO) session was previously established.

Steps 5-8 are performed by the portal and portlet container. A uPortal-compatible library, documented elsewhere, handles these interactions. When step 8 is done, the portlet is ready to request SAML-protected resources from WSP.

Steps 9-14 are initiated by the portlet, but most of the work is performed on portlet's behalf in the library documented here.

Security

The security of the SAML assertion is protected by all involved parties. Its integrity is protected with digital signatures, and the IdP signs the assertion using its private key. The portal's SP and the WSP examine the digital signature when receiving the assertion. The library retrieves elements from the SAML assertion, but it cannot modify anything within the assertion, as that would invalidate the assertion's digital signature. The portlet should treat the assertion the same way. It may be authorized to examine the contents of the assertion, but it may not modify it in any way.

The library's responsibility to protect SAML assertion consists of various levels of assurance that the servers it deals with, IdP and the WSP, are trusted. The library supports various methods of authenticating the servers it communicates with using private/public keys and X.509 certificates.

Both communications with the IdP and with the WSP can use client TLS certificates to authenticate the client, in this case the library/portlet, to the server. When authenticating this way to the IdP the portlet must use the certificate and private key belonging to the portal's SP because, as far as the IdP is concerned, they are one and the same. The library supports PEM-encoded private key and certificate (commonly used with OpenSSL) or a Java standard KeyStore. Those files must me accessible to the process running the portal and the portlet.

The library also supports server authentication. Either the IdP or the WSP can be authenticated using a TrustStore, which is basically a standard Java KeyStore containing server certificates to trust. Obviously, different TrustStores can be used for IdP and WSP authentication. The portal's SP may also convey the IdP public key to the portal and the portlet. This public key may be used to authenticate the IdP, and in this case the library does not examine the IdP's certificate(s) but only the public keys within the IdP's X.509 certificate(s).

Installation

Overview

This library uses Maven for building and installation. A portlet developer in a need to retrieve resources from a SAML-protected Web Service will need to perform two steps to take advantage of this library:

  1. Build the library from sources to make it available as a local Maven resource
  2. Add the library to the developer's portlet project, presumably a Maven project itself

Building the Library

The library is built using Maven. In the future the library may be published to a public Maven repository, and this step will not be necessary. As of this writing, however, this is not available.

To build the library, a developer needs to run the following Maven command:

mvn install

This command compiles the code, assembles the binaries into a jar file, and installs it in a local Maven repository.

Since this library has a programming API, it may be desirable to generate Javadoc documentation. This is accomplished with the following command:

mvn javadoc:javadoc

Adding the Library to a Portlet Project

To add this library to a Maven portlet project, a developer must add the following dependency to the portlet's pom.xml file:

<dependency>
  <groupId>org.jasig.service</groupId>
  <artifactId>delegated-saml-authentication</artifactId>
  <version>1.0</version>
</dependency> 

The names used in this dependency element match the names used in the library's own pom.xml and this matching is what allows Maven to locate the library in the local Maven repository.

Usage

Introduction

The reason this library exists is to facilitate delegated SAML authentication for portlets that act on behalf of the logged on user. It is not the library's responsibility, nor was it its requirement, to retrieve any resources from the SAML-protected WSP. The library uses Apache HttpClient component. The only difference from using HttpClient directly is that instead of creating an instance of HttpClient, a developer obtains it from the library. The initial testing of this library was performed with only HTTP GET as the initial request to retrieve a protected resource. This is because that was the only method that would handle SAML authentication "as-needed." Support to preserve HTTP POST form post elements was recently added to the Shibboleth SP, but this will need to be tested in the future.

There are some things to keep in mind about this:

  • This resource in the initial HTTP GET can exist only for the purpose of completing authentication, and it could be ignored by the portlet.
  • Upon successful authentication, the portlet may use the Apache Commons HTTP Client API and will not be limited to HTTP GET.

Simple Example

With SAML assertion and resource URL available, the portlet is ready to start a delegated SAML authentication session. It first creates a new copy of the SAMLSession class and passes the SAML assertion as the constructor parameter. From the instance of SAMLSession, the portlet obtains an instance of HttpClient and uses the API of the Apache HttpClient from then on.

The delegated SAML authentication business logic is encapsulated in a class called SAMLDelegatedAuthenticationService. There is no need to make an explicit instance of this class, as it is created internally to the library. Here is an illustration of the steps required to retrieve a protected resource using HTTP GET:

String samlAssertion = getAssertion();   // Example only.  Portlet obtains a String containing SAML assertion
samlSession = new SAMLSession(samlAssertion);
Resource resource = new Resource ();  // Simple example class representing a protected resource
resource.setResourceUrl(url);   // The url variable here is a String initialized elsewhere
getResource(samlSession, resource);  // Portlet's local method detailed below

The following is an example of a getResource method that a portlet may use:

private void getResource(SAMLSession samlSession, Resource resource) {
  HttpClient client = samlSession.getHttpClient();  // This is how to obtain an instance of "authenticated" HttpClient
  HttpGet method = new HttpGet(resource.getResourceUrl());
  
  // There is no need to check the HTTP response status because the HTTP
  // client will handle normal HTTP protocol flow, including redirects
  // In case of error, HTTP client will throw an exception
  ResponseHandler<String> responseHandler = new BasicResponseHandler();
  String response;
  try {
    response = client.execute(method, responseHandler);
    resource.setResource(response);
  }
  catch (Exception ex) {  // ClientProtocolException or IOException
    log.error("Exception while trying to retrieve the resource.", ex);
  }
}

In this simplest of examples, assuming that SAML protects a RESTful Web Service, at the end of this sequence the portlet may call resource.getResource(), which will return a String representation of what came back from the WSP. Since the data encapsulating classes are stateful, SAMLSession and Resource should not be considered thread-safe.

IdP Resolution

While the example above shows how the WSP is identified with the resource URL, it would be a valid question to ask how the library locates the IdP. After all, only an IdP may issue an assertion that is suitable for the WSP. While it would be possible to require that the portlet identify the IdP, it should not be necessary. Not in all cases, anyway.

The SAML assertion issued to the portal, the same assertion that the portlet uses as a constructor parameter when creating an instance of the SAMLSession class, contains an Issuer element. This identifies the IdP that issued the assertion. The IdP is identified by what's referred to as entityID. This may sometimes look like a URL, but it does not have to be. A fully-qualified URL is required by the library to obtain a delegated SAML assertion from the IdP and present to the WSP. In order to make this flexible, the library uses a "pluggable" resolver. The resolver wirks with SAMLSession and an instance of the DelegatedSAMLAuthenticationState class, which is populated with the IdP's entityID. The IdP resolver will resolve the specific URL, or "endpoint." On successful resolution, the resolver places the IdP endpoint into the DelegatedSAMLAuthenticationState class. The resolver needs to implement a simple interface IdPEPRResolver:

public interface IdPEPRResolver {
  /**
   * This method will take the samlSession's idp entity ID and resolve it to
   * an endpoint.  The endpoint is a URL that the ECP will use to ask the IdP
   * for a delegated authentication assertion.  The endpoint will be placed into
   * authnState for later use.  This method is invoked immediately prior
   * to making a connection to the IdP.  The implementation of this method should
   * retrieve the IdP entityID, or name, by calling {@link SAMLSession#getIdp()}
   * and store the resolved endpoint by calling {@link DelegatedSAMLAuthenticationState#setIdpEndpoint(String) SAMLSession.setIdpEndpoint}.
   * 
   * @param samlSession SAMLSession instance
   */
  public void resolve(SAMLSession samlSession, DelegatedSAMLAuthenticationState authnState);
}

"EPR" in IdPEPRResolver stands for End Point Reference. The implementation of this interface delivered with this library assumes that Shibboleth IdP was used to issue the SAML assertion, and Shibboleth IdP includes an EPR in the assertions it issues. When working with other SAML IdP, portlet developers should write their own implementation of the above interface and set it with a authnState.setIdpResolver method call. SAMLSession defaults to using the included implementation, so at installations using Shibboleth IdP there is no need to instantiate or sent the IdP resolver in the SAMLSession object.

Reusing SAMLSession

SAMLSession encapsulates a great deal of properties. Most of them may not even be useful to portlet developers, but many are. One of the properties is the HttpClient instance that can be reused for "stateful" communications with the WSP. HttpClient from Apache Commons has the default behavior like that of a browser. This means that once a client is set up, it will continue operating in a "stateful" way, including sending cookies that were previously set by the server. These cookies may represent the SAML session and some sort of WSP-specific session. Maintaining these sessions is critical to efficiently communicating with the WSP and not performing authentications unnecessarily.

To reuse the stateful HttpClient, a portlet developer needs to make sure to use the samlSession.getHttpClient method.

Authenticating the IdP

While the library does not enforce it, communicating with the IdP should always be performed over a secure connection, most commonly utilizing TLS. In addition to encrypting all of the information between the IdP and its client, TLS also supports methods of authenticating the server. This can go a long way to assuring that there client, in this case the delegated SAML authentication library, is not a victim of a man-in-the-middle attack. The library supports two different methods of authenticating the IdP:

  • By only trusting an IdP that presents an X.509 certificate that's in a specified Java TrustStore
  • By only trusting an IdP whose certificate contains a specific public key.

By default, Java will trust any server whose certificate was signed by a recognized Certificate Authority (CA). This is also the default trust model employed by Web browsers. However, with the IdP it may be desirable to disable the default behavior and restrict which X.509 certificates are to be trusted. A clever adversary could, for example, obtain an X.509 server certificate that's signed by one of the CAs that Java is set up to trust. For that reason, the portlet developer has an option to override the default Java TrustStore. To do that, the developer can make the following call prior to the initial samlSession.getHttpClient() call:

samlSession.setIdPClientTrustStore(keyStore, keyStorePass);

The keyStore argument is a String containing the file name of the Java KeyStore, and keyStorePass is a String containing the KeyStore password. This will replace the default Java behavior of using $JAVA_HOME/jre/lib/security/cacerts as the default TrustStore. It is up to the developer to create the Java KeyStore to be used here.

Another method to authenticate the IdP is to only connect to an IdP that presents an X.509 certificate containing a specific public key. With Shibboleth SP, the IdP public key can be supplied at runtime, so there is no need to create and maintain a Java KeyStore. Portlet developers using uPortal can configure uPortal to supply the IdP public key to the portlet as a Base64-encoded String. With that String, the developer tells the library to only communicate with an IdP if it presents a trusted public key with this call:

samlSession.setIdPServerPublicKeys(encodedKey);

At this time the library only supports a single public key to trust. Internally, the library decodes the key, retrieves all the X.509 certificates presented by the IdP, and looks for a matching public key in one of those certificates. A secure connection to the IdP will only be allowed if a matching public key is found.

Authenticating to the IdP

Just as the IdP client needs to authenticate the IdP it is about to communicate with, the IdP may want to restrict the clients authorized to obtain delegated SAML authentication. This is supported by the library, and it also uses TLS as the means of IdP client authentication. The IdP authenticates its clients by examining the client X.509 certificate. By presenting to the TLS/SSL layer a certificate and private key, the client's certificate with the public key is presented to the IdP. Since, as far as the IdP is concerned, the library/portlet/portal are synonymous with their corresponding SP, the library must use the SP's certificate and private key. There are two methods by which a portlet developer may convey the private key and certificate to the TLS layer:

  • With a Java KeyStore containing the certificate and private key
  • With a PEM-encoded private key file and PEM-encoded certificate file

The first method requires a KeyStore password. The portlet developer may convey the KeyStore information to the library with the following call:

samlSession.setIdPClientKeystore(keyStore, keyStorePass);

where keyStore is the file name of the Java KeyStore and keyStorePass is the KeyStore password. Since the SP is probably going to use PEM-encoded certificate and private key, the KeyStore used in this example must be created. One advantage of using this method is that Apache HTTP Client uses KeyStore "natively," so this method may be slightly more efficient. Another potential advantage is that, since the KeyStore holding the private key must have a password, this KeyStore has that additional level of security.

The second method of conveying the private key and certificate to the library to authenticate itself to the IdP is to provide PEM-encoded files containing both. These should be the same files installed on the portal's SP, which is the same SP that received the original SAML assertion and made it available to the portal. Since these files are not password-protected, care needs to be taken when dealing with them. Some administrators may be reluctant to copy these files, but if the portal's application server resides on the same server as its SP, the administrator may simply give a permission to read these files to the application server process. Obviously, these issues are installation-specific.

Portlet developer may convey the locations of the PEM-encoded private key and certificate files like this:

samlSession.setIdPClientPrivateKeyAndCert(pkFile, certFile);

where pkFile is the file name of the PEM-encoded private key and certFile is the file name of the PEM-encoded certificate file, and they both must be readable by the portal's application server process.

The library will use the keys and/or certificates in its communications with the IdP.

Authenticating the WSP

Just as with the IdP, communications with the WSP may need to be secured using TLS. The WSP will present its certificate to the client, and the client must trust the certificate to allow the connection to proceed. The default behavior is to trust servers whose X.509 certificates have been signed by a recognized CA. Institutions wishing to issue their own certificates, either signed by their own CA or even self-signed certificates, may override the default behavior of Java and Apache HTTP Client. This can be done by providing an alternate TrustStore for communications with the WSP. The following call specifies the TrustStore to use:

resource.setWSPClientTrustStore (trustStore, trustStorePass);

where trustStore is a file name of a Java KeyStore containing certificates to trust and trustStorePass is the password that was used to secure the KeyStore. The TrustStore may contain certificates of CA, if the WSP has a CA-signed certificate or a certificate of the WSP, if the WSP uses a self-signed certificate. Please note that with this authentication the use of the Resource class becomes a requirement. The Resource class encapsulates the state specific to the WSP, while SAMLSession's state is IdP-specific.

Authenticating to the WSP

As with the IdP, the WSP may require a client TLS certificate to authenticate and trust its clients. The library supports that with TLS client certificates. This is virtually identical to the TLS client certificates that can be presented to the IdP, so rather than repeat that section verbosely, here are the two different method calls to convey the client certificate location to the library:

resource.setWSPClientPrivateKeyAndCert (pkFile, certFile);

resource.setWSPClientKeystore (keyStore, keyStorePass);

where the first method has the file names of the PEM-encoded private key and certificate as arguments and the second has the Java KeyStore location and KeyStore password as arguments.

Because the library "steps out of the way" allowing the portlet to communicate directly with the WSP, to activate the WSP authentication a portlet developer must perform an additional step prior to communicating with the WSP. This step sets up the TSL layer. This is accomplished with the following sequence:

resource = new Resource();
resource.setResourceUrl(url);  //obtained elsewhere
resource.setWSPClientPrivateKeyAndCert (pkFile, certFile);  //one of the methods to authenticate the client to the WSP
resource.setupWSPClientConnection(samlSession);  // This looks for "https" in the Resource URL and the optional port number to use
HttpClient client = samlSession.getHttpClient();
  • No labels