SeamFramework.orgCommunity Documentation

Chapter 33. Security - External Authentication

33.1. Introduction
33.1.1. Configuration
33.2. OpenID
33.2.1. Overview
33.2.2. Enabling OpenID for your application
33.2.3. Choosing which OpenID provider to use
33.2.4. Managing the OpenID authentication process

The external authentication module is an optional add-on to the core Seam Security module, which provides a number of features that enable your application to authenticate against third party identity services, via a number of supported protocols.

Currently this module supports authentication via OpenID, and other protocols (such as SAML and OAuth) are currently under development for the next version of Seam.

OpenID allows the users of your application to authenticate without requiring them to create an account. When using OpenID, your user is temporarily redirected to the web site of their OpenID provider so that they can enter their password, after which they are redirected back to your application. The OpenID authentication process is safe - at no time is the user's password seen by any site besides their OpenID provider.

The external authentication module provides support for OpenID based on OpenID4Java, an open source OpenID library (licensed under the Apache v2 license) with both Relying Party and Identity Provider capabilities. This feature allows your application to authenticate its users against an external OpenID provider, such as Google or Yahoo, or to turn your application into an OpenID provider itself.

Note

To see the OpenID features in action, take a look at the openid-rp example included in the Seam Security distribution.

To use OpenID in your own application, you must configure Seam Security to use OpenIdAuthenticator, an Authenticator implementation that performs authentication against an OpenID provider. This authenticator is a named, session-scoped bean, with the following declaration:

public @Named("openIdAuthenticator") @SessionScoped class OpenIdAuthenticator

Seam provides built-in support for a number of well-known OpenID providers. The OpenIdAuthenticator bean may be configured to select which OpenID provider will be used to process an authentication request. Each concrete provider implements the following interface:

public interface OpenIdProvider {

   String getCode();
   String getName();
   String getUrl();
}

The following table lists the providers that come pre-packaged in Seam:

ProviderCodeNameURL
CustomOpenIdProvidercustomGoogle 
GoogleOpenIdProvidergoogleGooglehttps://www.google.com/accounts/o8/id
MyOpenIdProvidermyopenidMyOpenIDhttps://myopenid.com
YahooOpenIdProvideryahooYahoohttps://me.yahoo.com

To select one of the built-in providers to use for an authentication request, the providerCode property of the OpenIdAuthenticator bean should be set to one of the Code values from the above table. The OpenIdAuthenticator bean provides a convenience method called getProviders() that returns a list of all known providers. This may be used in conjunction with a radio group to allow the user to select which OpenID provider they wish to authenticate with - see the following JSF snippet for an example:


<h:selectOneRadio value="#{openIdAuthenticator.providerCode}">
  <f:selectItems value="#{openIdAuthenticator.providers}" var="p" itemValue="#{p.code}" itemLabel="#{p.name}"/>
</h:selectOneRadio>

Your application must provide an implementation of the OpenIdRelyingPartySpi interface to process OpenID callback events. This interface declares the following methods:

public interface OpenIdRelyingPartySpi {

   void loginSucceeded(OpenIdPrincipal principal, ResponseHolder responseHolder);
   void loginFailed(String message, ResponseHolder responseHolder);      
      

The implementation is responsible for processing the response of the OpenID authentication, and is typically used to redirect the user to an appropriate page depending on whether authentication was successful or not.

There are two API calls that must be made in the case of a successful authentication. The first one should notify the OpenIdAuthenticator that the authentication attempt was successful, and pass it the OpenIdPrincipal object:

openIdAuthenticator.success(principal);

Secondly, a DeferredAuthenticationEvent must be fired to signify that a deferred authentication attempt has been completed:

deferredAuthentication.fire(new DeferredAuthenticationEvent());

After making these two API calls, the implementation may perform whatever additional logic is required. The following code shows a complete example:

import java.io.IOException;


import javax.enterprise.event.Event;
import javax.inject.Inject;
import javax.servlet.ServletContext;
import org.jboss.seam.security.events.DeferredAuthenticationEvent;
import org.jboss.seam.security.external.api.ResponseHolder;
import org.jboss.seam.security.external.openid.OpenIdAuthenticator;
import org.jboss.seam.security.external.openid.api.OpenIdPrincipal;
import org.jboss.seam.security.external.spi.OpenIdRelyingPartySpi;
public class OpenIdRelyingPartySpiImpl implements OpenIdRelyingPartySpi {
   @Inject private ServletContext servletContext;
   @Inject OpenIdAuthenticator openIdAuthenticator;   
   @Inject Event<DeferredAuthenticationEvent> deferredAuthentication;
   public void loginSucceeded(OpenIdPrincipal principal, ResponseHolder responseHolder) {
      try {
         openIdAuthenticator.success(principal);
         deferredAuthentication.fire(new DeferredAuthenticationEvent());
         
         responseHolder.getResponse().sendRedirect(servletContext.getContextPath() + "/UserInfo.jsf");
      } catch (IOException e) {
         throw new RuntimeException(e);
      }
   }
   public void loginFailed(String message, ResponseHolder responseHolder) {
      try {
         responseHolder.getResponse().sendRedirect(servletContext.getContextPath() + "/AuthenticationFailed.jsf");
      } catch (IOException e) {
         throw new RuntimeException(e);
      }
   }
}