SeamFramework.orgCommunity Documentation
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.
The features described in this chapter are a preview only. The APIs described may change in a subsequent version of Seam, and may not be backwards-compatible with previous versions.
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.
If your project is Maven-based, then add the following dependency to your project:
<dependency> <groupId>org.jboss.seam.security</groupId> <artifactId>seam-security-external</artifactId> </dependency>
If you are not using Maven, you must add the seam-security-external.jar
library to your project, which
can be found in the Seam Security downloadable distribution.
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.
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
If your application only uses OpenID to provide authentication services, then it is recommended
that OpenIdAuthenticator
is selected by configuring the authenticatorClass
property of the Identity
bean. The following code sample demonstrates how this might
be done by using Solder:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:s="urn:java:ee"
xmlns:security="urn:java:org.jboss.seam.security"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://jboss.org/schema/cdi/beans_1_0.xsd">
<security:Identity>
<s:modifies/>
<security:authenticatorClass>org.jboss.seam.security.external.openid.OpenIdAuthenticator</security:authenticatorClass>
</security:Identity>
If your application gives the user a choice of which authentication method to use, then it is not possible to
pre-configure which Authenticator
implementation is used to authenticate. In these circumstances,
it is recommended that you configure the authenticator by specifying a value for the authenticatorName
property of the Identity
bean. This can be done by binding a view-layer control such as a radio group
directly to this property, to allow the user to select the method of authentication they wish to use. See the
following JSF code as an example:
<h:outputLabel value="Authenticate using:"/>
<h:selectOneRadio id="authenticator" value="#{identity.authenticatorName}">
<f:selectItem itemLabel="OpenID" itemValue="openIdAuthenticator" />
<f:selectItem itemLabel="Custom" itemValue="customAuthenticator" />
</h:selectOneRadio>
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:
Provider | Code | Name | URL |
---|---|---|---|
CustomOpenIdProvider | custom | ||
GoogleOpenIdProvider | https://www.google.com/accounts/o8/id | ||
MyOpenIdProvider | myopenid | MyOpenID | https://myopenid.com |
YahooOpenIdProvider | yahoo | Yahoo | https://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>
If you would like to allow your users to specify an OpenID provider that is not supported out of the box by Seam, then
the CustomOpenIdProvider
may be used. As it is a @Named
bean, it can be accessed directly
from the view layer via EL. The following JSF code shows how you might allow the user to specify their own
OpenID provider:
<h:outputLabel value="If you have selected the Custom OpenID provider, please provide a URL:"/>
<h:inputText value="#{customOpenIdProvider.url}"/>
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:
If the following two API calls are omitted, unpredictable results may occur!
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);
}
}
}