[seam-commits] Seam SVN: r12909 - modules/security/trunk/docs/en-US.

seam-commits at lists.jboss.org seam-commits at lists.jboss.org
Sun May 30 19:53:43 EDT 2010


Author: shane.bryzak at jboss.com
Date: 2010-05-30 19:53:42 -0400 (Sun, 30 May 2010)
New Revision: 12909

Added:
   modules/security/trunk/docs/en-US/images/
   modules/security/trunk/docs/en-US/security-general.xml
Log:
re-add old documentation


Added: modules/security/trunk/docs/en-US/security-general.xml
===================================================================
--- modules/security/trunk/docs/en-US/security-general.xml	                        (rev 0)
+++ modules/security/trunk/docs/en-US/security-general.xml	2010-05-30 23:53:42 UTC (rev 12909)
@@ -0,0 +1,5202 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN" "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd">
+
+<chapter id="security">
+  <title>Security</title>
+
+  <sect1>
+    <title>Overview</title>
+    
+    <para>
+      The Seam Security API provides a multitude of security-related features for your Seam-based application, covering 
+      such areas as:
+    </para>
+    
+    <itemizedlist>
+      <listitem>
+        <para>
+          Authentication - an extensible, JAAS-based authentication layer that allows users to authenticate
+          against any security provider.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
+          Identity Management - an API for managing a Seam application's users and roles at runtime.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
+          Authorization - an extremely comprehensive authorization framework, supporting user roles, persistent and
+          rule-based permissions, and a pluggable permission resolver for easily implementing customised security logic.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
+          Permission Management - a set of built-in Seam components to allow easy management of an application's 
+          security policy.
+        </para>   
+      </listitem>
+      <listitem>
+        <para>
+          CAPTCHA support - to assist in the prevention of automated software/scripts abusing your Seam-based site.
+        </para>
+      </listitem>
+      <listitem>
+        <para>
+          And much more
+        </para>
+      </listitem>
+    </itemizedlist>                  
+    
+    <para>
+      This chapter will cover each of these features in detail.
+    </para>    
+
+  </sect1>
+
+  <sect1>
+    <title>Disabling Security</title>
+
+    <para>
+      In some situations it may be necessary to disable Seam Security, for instances during unit tests or because you
+      are using a different approach to security, such as native JAAS. Simply call the static method
+      <literal>Identity.setSecurityEnabled(false)</literal> to disable the security infrastructure. Of course, it's not
+      very convenient to have to call a static method when you want to configure the application, so as an alternative
+      you can control this setting in components.xml:
+    </para>
+
+    <itemizedlist>
+      <listitem>
+        <para>Entity Security</para>
+      </listitem>
+      <listitem>
+        <para>Hibernate Security Interceptor</para>
+      </listitem>
+      <listitem>
+        <para>Seam Security Interceptor</para>
+      </listitem>
+      <listitem>
+        <para>Page restrictions</para>
+      </listitem>
+      <listitem>
+        <para>Servlet API security integration</para>
+      </listitem>
+    </itemizedlist>
+
+    <para>
+      Assuming you are planning to take advantage of what Seam Security has to offer, the rest of this chapter documents
+      the plethora of options you have for giving your user an identity in the eyes of the security model
+      (authentication) and locking down the application by establishing constraints (authorization). Let's begin with
+      the task of authentication since that's the foundation of any security model.
+    </para>
+
+  </sect1>
+  
+  <sect1>
+    <title>Authentication</title>
+
+    <para>
+      The authentication features provided by Seam Security are built upon JAAS (Java Authentication and Authorization Service),
+      and as such provide a robust and highly configurable API for handling user authentication.  However, for less complex
+      authentication requirements Seam offers a much more simplified method of authentication that hides the complexity of JAAS.
+    </para>
+    
+    <sect2>
+      <title>Configuring an Authenticator component</title>
+
+      <note>
+        <para>
+          If you use Seam's Identity Management features (discussed later in this chapter) then it is not necessary to create
+          an authenticator component (and you can skip this section).
+        </para>
+      </note>
+
+      <para>
+        The simplified authentication method provided by Seam uses a built-in JAAS login module, <literal>SeamLoginModule</literal>, which
+        delegates authentication to one of your own Seam components.  This login module is already configured inside Seam as
+        part of a default application policy and as such does not require any additional configuration files.  It allows you to
+        write an authentication method using the entity classes that are provided by your own application, or alternatively to 
+        authenticate with some other third party provider.  Configuring this simplified form of authentication requires the 
+        <literal>identity</literal> component to be configured in <literal>components.xml</literal>:
+      </para>
+
+      <programlisting role="XML"><![CDATA[<components xmlns="http://jboss.com/products/seam/components"
+            xmlns:core="http://jboss.com/products/seam/core"
+            xmlns:security="http://jboss.com/products/seam/security"
+            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+            xsi:schemaLocation=
+                "http://jboss.com/products/seam/components http://jboss.com/products/seam/components-2.2.xsd
+                 http://jboss.com/products/seam/security http://jboss.com/products/seam/security-2.2.xsd">
+
+    <security:identity authenticate-method="#{authenticator.authenticate}"/>
+
+</components>]]></programlisting>
+
+      <para>
+        The EL expression <literal>#{authenticator.authenticate}</literal> is a method binding that indicates
+        the <literal>authenticate</literal> method of the <literal>authenticator</literal> component will be used
+        to authenticate the user.
+      </para>
+
+    </sect2>
+
+    <sect2>
+      <title>Writing an authentication method</title>
+
+      <para>
+        The <literal>authenticate-method</literal> property specified for <literal>identity</literal> in
+        <literal>components.xml</literal> specifies which method will be used by <literal>SeamLoginModule</literal>
+        to authenticate users.  This method takes no parameters, and is expected to return a boolean, which indicates
+        whether authentication is successful or not.  The user's username and password can be obtained from
+        <literal>Credentials.getUsername()</literal> and <literal>Credentials.getPassword()</literal>,
+        respectively (you can get a reference to the <literal>credentials</literal> component via
+        <literal>Identity.instance().getCredentials()</literal>).  Any roles that the user is a member of 
+        should be assigned using <literal>Identity.addRole()</literal>. Here's a complete example of an 
+        authentication method inside a POJO component:
+      </para>
+
+      <programlisting role="JAVA"><![CDATA[@Name("authenticator")
+public class Authenticator {
+   @In EntityManager entityManager;
+   @In Credentials credentials;
+   @In Identity identity;
+
+   public boolean authenticate() {
+      try {
+         User user = (User) entityManager.createQuery(
+            "from User where username = :username and password = :password")
+            .setParameter("username", credentials.getUsername())
+            .setParameter("password", credentials.getPassword())
+            .getSingleResult();
+
+         if (user.getRoles() != null) {
+            for (UserRole mr : user.getRoles())
+               identity.addRole(mr.getName());
+         }
+
+         return true;
+      }
+      catch (NoResultException ex) {
+         return false;
+      }
+
+   }
+
+}]]></programlisting>
+
+      <para>
+        In the above example, both <literal>User</literal> and <literal>UserRole</literal> are application-specific
+        entity beans.  The <literal>roles</literal> parameter is populated with the roles that the user is a member
+        of, which should be added to the <literal>Set</literal> as literal string values, e.g. "admin", "user".
+        In this case, if the user record is not found and a <literal>NoResultException</literal> thrown, the
+        authentication method returns <literal>false</literal> to indicate the authentication failed.
+      </para>
+      
+      <tip>
+         <para>
+           When writing an authenticator method, it is important that it is kept minimal and free from
+           any side-effects. This is because there is no guarantee as to how many times the authenticator
+           method will be called by the security API, and as such it may be invoked multiple times during
+           a single request.  Because of this, any special code that should execute upon a successful or
+           failed authentication should be written by implementing an event observer.  See the section on
+           Security Events further down in this chapter for more information about which events are
+           raised by Seam Security.
+        </para>
+      </tip>
+
+      <sect3>
+        <title>Identity.addRole()</title>
+
+        <para>
+          The <literal>Identity.addRole()</literal> method behaves differently depending on whether the current
+          session is authenticated or not.  If the session is not authenticated, then <literal>addRole()</literal>
+          should <emphasis>only</emphasis> be called during the authentication process.  When called here, the
+          role name is placed into a temporary list of pre-authenticated roles.  Once authentication is successful,
+          the pre-authenticated roles then become "real" roles, and calling <literal>Identity.hasRole()</literal>
+          for those roles will then return true.  The following sequence diagram represents the list of pre-authenticated
+          roles as a first class object to show more clearly how it fits in to the authentication process.
+
+        </para>
+
+        <mediaobject>
+          <imageobject role="fo">
+            <imagedata fileref="images/security-addrole.png" align="center" scalefit="1"/>
+          </imageobject>
+          <imageobject role="html">
+            <imagedata fileref="images/security-addrole.png" align="center"/>
+          </imageobject>
+        </mediaobject>
+        
+        <para>
+          If the current session is already authenticated, then calling <literal>Identity.addRole()</literal> will
+          have the expected effect of immediately granting the specified role to the current user.
+        </para>
+
+      </sect3>
+
+      <sect3>
+        <title>Writing an event observer for security-related events</title>
+
+        <para>
+          Say for example, that upon a successful login that some user statistics must be
+          updated.  This would be done by writing an event observer for the
+          <literal>org.jboss.seam.security.loginSuccessful</literal> event, like this:
+        </para>
+
+        <programlisting role="JAVA"><![CDATA[   @In UserStats userStats;
+
+   @Observer("org.jboss.seam.security.loginSuccessful")
+   public void updateUserStats()
+   {
+      userStats.setLastLoginDate(new Date());
+      userStats.incrementLoginCount();
+   }]]></programlisting>
+   
+        <para>
+          This observer method can be placed anywhere, even in the Authenticator component itself.
+          You can find more information about security-related events later in this chapter.
+        </para>
+      </sect3>
+
+    </sect2>
+
+    <sect2>
+      <title>Writing a login form</title>
+
+      <para>
+        The <literal>credentials</literal> component provides both <literal>username</literal> and <literal>password</literal>
+        properties, catering for the most common authentication scenario. These properties can be bound directly to the
+        username and password fields on a login form.  Once these properties are set, calling 
+        <literal>identity.login()</literal> will authenticate the user using the provided credentials.
+        Here's an example of a simple login form:
+      </para>
+
+      <programlisting role="XHTML"><![CDATA[<div>
+    <h:outputLabel for="name" value="Username"/>
+    <h:inputText id="name" value="#{credentials.username}"/>
+</div>
+
+<div>
+    <h:outputLabel for="password" value="Password"/>
+    <h:inputSecret id="password" value="#{credentials.password}"/>
+</div>
+
+<div>
+    <h:commandButton value="Login" action="#{identity.login}"/>
+</div>]]></programlisting>
+
+      <para>
+        Similarly, logging out the user is done by calling <literal>#{identity.logout}</literal>. Calling this
+        action will clear the security state of the currently authenticated user, and invalidate the user's session.
+      </para>
+
+    </sect2>
+
+    <sect2>
+      <title>Configuration Summary</title>
+      <para>
+        So to sum up, there are the three easy steps to configure authentication:
+      </para>
+
+      <itemizedlist>
+        <listitem>
+          <para>
+            Configure an authentication method in <literal>components.xml</literal>.
+          </para>
+        </listitem>
+        <listitem>
+          <para>
+            Write an authentication method.
+          </para>
+        </listitem>
+        <listitem>
+          <para>
+            Write a login form so that the user can authenticate.
+          </para>
+        </listitem>
+      </itemizedlist>
+
+    </sect2>
+    
+    <sect2>
+      <title>Remember Me</title>
+      
+      <para>
+        Seam Security supports the same kind of "Remember Me" functionality that is commonly encountered in many
+        online web-based applications.  It is actually supported in two different "flavours", or modes - the first
+        mode allows the username to be stored in the user's browser as a cookie, and leaves the entering of the
+        password up to the browser (many modern browsers are capable of remembering passwords).
+      </para>
+      
+      <para>
+        The second mode supports the storing of a unique token in a cookie, and allows a user to authenticate
+        automatically upon returning to the site, without having to provide a password.
+      </para>
+      
+      <warning>
+        <para>
+          Automatic client authentication with a persistent cookie stored on the client machine is dangerous.  
+          While convenient for users, any cross-site scripting security hole in your website would have dramatically more 
+          serious effects than usual. Without the authentication cookie, the only cookie to steal for an attacker with XSS 
+          is the cookie of the current session of a user. This means the attack only works when the user has an open session - 
+          which should be a short timespan. However, it is much more attractive and dangerous if an attacker has the possibility 
+          to steal a persistent Remember Me cookie that allows him to login without authentication, at any time. Note that this 
+          all depends on how well you protect your website against XSS attacks - it's up to you to make sure that your website 
+          is 100% XSS safe - a non-trival achievement for any website that allows user input to be rendered on a page.          
+        </para>
+        
+        <para>
+          Browser vendors recognized this issue and introduced a "Remember Passwords" feature - today almost all browsers support 
+          this. Here, the browser remembers the login username and password for a particular website and domain, and fills out the 
+          login form automatically when you don't have an active session with the website. If you as a website designer then offer 
+          a convenient login keyboard shortcut, this approach is almost as convenient as a "Remember Me" cookie and much safer. 
+          Some browsers (e.g. Safari on OS X) even store the login form data in the encrypted global operation system keychain. 
+          Or, in a networked environment, the keychain can be transported with the user (between laptop and desktop for example), 
+          while browser cookies are usually not synchronized.
+        </para>
+        
+        <para>
+          To summarize: While everyone is doing it, persistent "Remember Me" cookies with automatic authentication are a bad 
+          practice and should not be used. Cookies that "remember" only the users login name, and fill out the login form with 
+          that username as a convenience, are not an issue. 
+        </para>
+      </warning>
+      
+      <para>
+        To enable the remember me feature for the default (safe, username only) mode, no special configuration is required.
+        In your login form, simply bind the remember me checkbox to <literal>rememberMe.enabled</literal>, like in the following
+        example:
+      </para>
+      
+      <programlisting role="XHTML"><![CDATA[  <div>
+    <h:outputLabel for="name" value="User name"/>
+    <h:inputText id="name" value="#{credentials.username}"/>
+  </div>
+  
+  <div>
+    <h:outputLabel for="password" value="Password"/>
+    <h:inputSecret id="password" value="#{credentials.password}" redisplay="true"/>
+  </div>      
+  
+  <div class="loginRow">
+    <h:outputLabel for="rememberMe" value="Remember me"/>
+    <h:selectBooleanCheckbox id="rememberMe" value="#{rememberMe.enabled}"/>
+  </div>]]></programlisting>
+  
+      <sect3>
+        <title>Token-based Remember-me Authentication</title>
+        
+        <para>
+          To use the automatic, token-based mode of the remember me feature, you must first configure a token store.  The
+          most common scenario is to store these authentication tokens within a database (which Seam supports), however it 
+          is possible to implement your own token store by implementing the <literal>org.jboss.seam.security.TokenStore</literal>
+          interface.  This section will assume you will be using the provided <literal>JpaTokenStore</literal> implementation
+          to store authentication tokens inside a database table.
+        </para>
+        
+        <para>
+          The first step is to create a new Entity which will contain the tokens.  The following example shows a possible
+          structure that you may use:
+        </para>
+        
+        <programlisting role="JAVA"><![CDATA[@Entity
+public class AuthenticationToken implements Serializable {  
+   private Integer tokenId;
+   private String username;
+   private String value;
+   
+   @Id @GeneratedValue
+   public Integer getTokenId() {
+      return tokenId;
+   }
+   
+   public void setTokenId(Integer tokenId) {
+      this.tokenId = tokenId;
+   }
+   
+   @TokenUsername
+   public String getUsername() {
+      return username;
+   }
+   
+   public void setUsername(String username) {
+      this.username = username;
+   }
+   
+   @TokenValue
+   public String getValue() {
+      return value;
+   }
+   
+   public void setValue(String value) {
+      this.value = value;
+   }
+}]]></programlisting>
+
+        <para>
+          As you can see from this listing, a couple of special annotations, <literal>@TokenUsername</literal> and
+          <literal>@TokenValue</literal> are used to configure the username and token properties of the entity.  These
+          annotations are required for the entity that will contain the authentication tokens.
+        </para>
+        
+        <para>
+          The next step is to configure <literal>JpaTokenStore</literal> to use this entity bean to store and retrieve
+          authentication tokens.  This is done in <literal>components.xml</literal> by specifying the <literal>token-class</literal>
+          attribute:
+        </para>
+        
+        <programlisting role="XML"><![CDATA[
+  <security:jpa-token-store token-class="org.jboss.seam.example.seamspace.AuthenticationToken"/>        
+        ]]></programlisting>
+        
+        <para>
+          Once this is done, the last thing to do is to configure the <literal>RememberMe</literal> component in
+          <literal>components.xml</literal> also.  Its <literal>mode</literal> should be set to <literal>autoLogin</literal>:
+        </para>
+        
+        <programlisting role="XML"><![CDATA[  <security:remember-me mode="autoLogin"/>        
+        ]]></programlisting>
+        
+        <para>
+          That is all that is required - automatic authentication will now occur for users revisiting your site (as long as they
+          check the "remember me" checkbox).
+        </para>
+        
+        <para>
+          To ensure that users are automatically authenticated when returning to the site, the following section
+          should be placed in components.xml:
+        </para>
+
+        <programlisting role="XML"><![CDATA[  <event type="org.jboss.seam.security.notLoggedIn">
+    <action execute="#{redirect.captureCurrentView}"/>
+    <action execute="#{identity.tryLogin()}"/>
+  </event>
+  <event type="org.jboss.seam.security.loginSuccessful">
+    <action execute="#{redirect.returnToCapturedView}"/>
+  </event>]]></programlisting>
+      
+      </sect3>
+      
+    </sect2>
+
+    <sect2>
+      <title>Handling Security Exceptions</title>
+
+      <para>
+        To prevent users from receiving the default error page in response to a security error, it's recommended that
+        <literal>pages.xml</literal> is configured to redirect security errors to a more "pretty" page.  The two
+        main types of exceptions thrown by the security API are:
+      </para>
+
+      <itemizedlist>
+        <listitem>
+          <para>
+            <literal>NotLoggedInException</literal> - This exception is thrown if the user attempts to access a
+            restricted action or page when they are not logged in.
+          </para>
+        </listitem>
+        <listitem>
+          <para>
+            <literal>AuthorizationException</literal> - This exception is only thrown if the user is already logged in,
+            and they have attempted to access a restricted action or page for which they do not have the necessary
+            privileges.
+          </para>
+        </listitem>
+      </itemizedlist>
+
+      <para>
+        In the case of a <literal>NotLoggedInException</literal>, it is recommended that the user is redirected to
+        either a login or registration page so that they can log in.  For an <literal>AuthorizationException</literal>,
+        it may be useful to redirect the user to an error page. Here's an example of a <literal>pages.xml</literal>
+        file that redirects both of these security exceptions:
+      </para>
+
+      <programlisting role="XML"><![CDATA[<pages>
+
+    ...
+
+    <exception class="org.jboss.seam.security.NotLoggedInException">
+        <redirect view-id="/login.xhtml">
+            <message>You must be logged in to perform this action</message>
+        </redirect>
+    </exception>
+
+    <exception class="org.jboss.seam.security.AuthorizationException">
+        <end-conversation/>
+        <redirect view-id="/security_error.xhtml">
+            <message>You do not have the necessary security privileges to perform this action.</message>
+        </redirect>
+    </exception>
+
+</pages>]]></programlisting>
+
+      <para>
+        Most web applications require even more sophisticated handling of login redirection, so
+        Seam includes some special functionality for handling this problem.
+      </para>
+
+    </sect2>
+
+    <sect2>
+      <title>Login Redirection</title>
+
+      <para>
+        You can ask Seam to redirect the user to a login screen when an unauthenticated user tries
+        to access a particular view (or wildcarded view id) as follows:
+      </para>
+
+      <programlisting role="XML"><![CDATA[<pages login-view-id="/login.xhtml">
+
+    <page view-id="/members/*" login-required="true"/>
+
+    ...
+
+</pages>]]></programlisting>
+
+      <tip>
+         <para>
+           This is less of a blunt instrument than the exception handler shown above, but should
+           probably be used in conjunction with it.
+         </para>
+      </tip>
+
+      <para>
+        After the user logs in, we want to automatically send them back where they came from, so
+        they can retry the action that required logging in. If you add the following event listeners
+        to <literal>components.xml</literal>, attempts to access a restricted view while not logged
+        in will be remembered, so that upon the user successfully logging in they will be redirected
+        to the originally requested view, with any page parameters that existed in the original
+        request.
+      </para>
+
+      <programlisting role="XML"><![CDATA[<event type="org.jboss.seam.security.notLoggedIn">
+    <action execute="#{redirect.captureCurrentView}"/>
+</event>
+
+<event type="org.jboss.seam.security.postAuthenticate">
+    <action execute="#{redirect.returnToCapturedView}"/>
+</event>]]></programlisting>
+
+      <para>
+        Note that login redirection is implemented as a conversation-scoped mechanism, so don't end
+        the conversation in your <literal>authenticate()</literal> method.
+      </para>
+
+    </sect2>
+
+    <sect2>
+      <title>HTTP Authentication</title>
+
+      <para>
+        Although not recommended for use unless absolutely necessary, Seam provides means for authenticating
+        using either HTTP Basic or HTTP Digest (RFC 2617) methods.  To use either form of authentication,
+        the <literal>authentication-filter</literal> component must be enabled in components.xml:
+      </para>
+
+      <programlisting role="XML"><![CDATA[
+  <web:authentication-filter url-pattern="*.seam" auth-type="basic"/>
+      ]]></programlisting>
+
+      <para>
+        To enable the filter for basic authentication, set <literal>auth-type</literal> to <literal>basic</literal>,
+        or for digest authentication, set it to <literal>digest</literal>.  If using digest authentication, the
+        <literal>key</literal> and <literal>realm</literal> must also be set:
+      </para>
+
+      <programlisting role="XML"><![CDATA[
+  <web:authentication-filter url-pattern="*.seam" auth-type="digest" key="AA3JK34aSDlkj" realm="My App"/>
+      ]]></programlisting>
+
+      <para>
+        The <literal>key</literal> can be any String value.  The <literal>realm</literal> is the name of the
+        authentication realm that is presented to the user when they authenticate.
+      </para>
+
+      <sect3>
+        <title>Writing a Digest Authenticator</title>
+
+        <para>
+          If using digest authentication, your authenticator class should extend the abstract class
+          <literal>org.jboss.seam.security.digest.DigestAuthenticator</literal>, and use the
+          <literal>validatePassword()</literal> method to validate the user's plain text password
+          against the digest request.  Here is an example:
+        </para>
+
+        <programlisting role="JAVA"><![CDATA[
+   public boolean authenticate()
+   {
+      try
+      {
+         User user = (User) entityManager.createQuery(
+            "from User where username = :username")
+            .setParameter("username", identity.getUsername())
+            .getSingleResult();
+
+         return validatePassword(user.getPassword());
+      }
+      catch (NoResultException ex)
+      {
+         return false;
+      }
+   }
+        ]]></programlisting>
+      </sect3>
+
+    </sect2>
+
+    <sect2>
+      <title>Advanced Authentication Features</title>
+
+      <para>
+        This section explores some of the advanced features provided by the security API for addressing more complex
+        security requirements.
+      </para>
+
+      <sect3>
+        <title>Using your container's JAAS configuration</title>
+
+        <para>
+          If you would rather not use the simplified JAAS configuration provided by the Seam Security API, you may
+          instead delegate to the default system JAAS configuration by providing a <literal>jaas-config-name</literal>
+          property in <literal>components.xml</literal>.  For example, if you are using JBoss AS and wish to use
+          the <literal>other</literal> policy (which uses the <literal>UsersRolesLoginModule</literal> login module
+          provided by JBoss AS), then the entry in <literal>components.xml</literal> would look like this:
+        </para>
+
+        <programlisting role="XML"><![CDATA[<security:identity jaas-config-name="other"/>]]></programlisting>
+                      
+        <para>
+          Please keep in mind that doing this does not mean that your user will be authenticated in whichever
+          container your Seam application is deployed in.  It merely instructs Seam Security to authenticate
+          itself using the configured JAAS security policy.
+        </para>
+      </sect3>
+    </sect2>
+  </sect1>
+  
+  <sect1>
+    <title>Identity Management</title>
+    
+    <para>
+      Identity Management provides a standard API for the management of a Seam application's users and roles,
+      regardless of which identity store (database, LDAP, etc) is used on the backend.  At the center
+      of the Identity Management API is the <literal>identityManager</literal> component, which provides 
+      all the methods for creating, modifying and deleting users, granting and revoking roles, changing passwords,
+      enabling and disabling user accounts, authenticating users and listing users and roles.
+    </para>
+    
+    <para>
+      Before it may be used, the <literal>identityManager</literal> must first be configured with one or more
+      <literal>IdentityStore</literal>s.  These components do the actual work of interacting with the backend
+      security provider, whether it be a database, LDAP server, or something else.
+    </para>
+
+    <mediaobject>
+      <imageobject role="fo">
+        <imagedata fileref="images/security-identitymanager.png" align="center"/>
+      </imageobject>
+      <imageobject role="html">
+        <imagedata fileref="images/security-identitymanager.png" align="center"/>
+      </imageobject>
+    </mediaobject>    
+    
+    <sect2>
+      <title>Configuring IdentityManager</title>
+      
+      <para>    
+        The <literal>identityManager</literal> component allows for separate identity stores to be configured 
+        for authentication and authorization operations.  This means that it is possible for users to
+        be authenticated against one identity store, for example an LDAP directory, yet have their roles 
+        loaded from another identity store, such as a relational database.
+      </para>
+      
+      <para>
+        Seam provides two <literal>IdentityStore</literal> implementations out of the box; 
+        <literal>JpaIdentityStore</literal> uses a relational database to store user and role information, 
+        and is the default identity store that is used if nothing is explicitly configured in the
+        <literal>identityManager</literal> component.  The other implementation that is provided is 
+        <literal>LdapIdentityStore</literal>, which uses an LDAP directory to store users and roles.
+      </para>
+      
+      <para>
+        There are two configurable properties for the <literal>identityManager</literal> component - 
+        <literal>identityStore</literal> and <literal>roleIdentityStore</literal>.  The value for these
+        properties must be an EL expression referring to a Seam component implementing the
+        <literal>IdentityStore</literal> interface.  As already mentioned,
+        if left unconfigured then <literal>JpaIdentityStore</literal> will be assumed by default.  If
+        only the <literal>identityStore</literal> property is configured, then the same value will be used for
+        <literal>roleIdentityStore</literal> also.  For example, the following entry in
+        <literal>components.xml</literal> will configure <literal>identityManager</literal> to use
+        an <literal>LdapIdentityStore</literal> for both user-related and role-related operations:
+      </para>
+
+      <programlisting role="XML"><![CDATA[      
+  <security:identity-manager identity-store="#{ldapIdentityStore}"/>
+      ]]></programlisting>
+      
+      <para>
+        The following example configures <literal>identityManager</literal> to use an <literal>LdapIdentityStore</literal>
+        for user-related operations, and <literal>JpaIdentityStore</literal> for role-related operations:
+      </para>
+      
+      <programlisting role="XML"><![CDATA[      
+  <security:identity-manager 
+    identity-store="#{ldapIdentityStore}" 
+    role-identity-store="#{jpaIdentityStore}"/>
+      ]]></programlisting>
+      
+      <para>
+        The following sections explain both of these identity store implementations in greater detail.
+      </para>
+      
+    </sect2>
+    
+    <sect2>
+      <title>JpaIdentityStore</title>
+      
+      <para>
+        This identity store allows for users and roles to be stored inside a relational database.  It is designed 
+        to be as unrestrictive as possible in regards to database schema design, allowing a great deal of 
+        flexibility in the underlying table structure.  This is achieved through the use of a set of special
+        annotations, allowing entity beans to be configured to store user and role records.  
+      </para>
+      
+      <sect3>
+        <title>Configuring JpaIdentityStore</title>
+        
+        <para>
+          <literal>JpaIdentityStore</literal> requires that both the <literal>user-class</literal> and 
+          <literal>role-class</literal> properties are configured.  These properties should refer to the
+          entity classes that are to be used to store both user and role records, respectively.  The following
+          example shows the configuration from <literal>components.xml</literal> in the SeamSpace example:
+        </para>
+        
+        <programlisting role="XML"><![CDATA[
+  <security:jpa-identity-store 
+    user-class="org.jboss.seam.example.seamspace.MemberAccount"
+    role-class="org.jboss.seam.example.seamspace.MemberRole"/>
+        ]]></programlisting>
+        
+      </sect3>
+      
+      <sect3>
+        <title>Configuring the Entities</title>
+        
+        <para>
+          As already mentioned, a set of special annotations are used to configure entity beans for storing
+          users and roles.  The following table lists each of the annotations, and their descriptions.
+        </para>
+        
+        <table>
+          <title>User Entity Annotations</title>
+    
+          <tgroup cols="2">
+            <colspec colnum="1" colwidth="2*" />
+            <colspec colnum="2" colwidth="1*" />
+            <colspec colnum="3" colwidth="3*" />
+    
+            <thead>
+              <row>
+                <entry align="center">
+                  <para>Annotation</para>
+                </entry>
+                <entry align="center">
+                  <para>Status</para>
+                </entry>
+                <entry align="center">
+                  <para>Description</para>
+                </entry>
+              </row>
+            </thead>
+    
+            <tbody>    
+              <row>
+                <entry>
+                  <para>
+                    <literal>@UserPrincipal</literal>
+                  </para>
+                </entry>
+                <entry>
+                  <para>Required</para>
+                </entry>
+                <entry>
+                  <para>
+                    This annotation marks the field or method containing the user's username.
+                  </para>
+                </entry>
+              </row> 
+              
+              <row>
+                <entry>
+                  <para>
+                    <literal>@UserPassword</literal>
+                  </para>
+                </entry>
+                <entry>
+                  <para>Required</para>
+                </entry>
+                <entry>
+                  <para>
+                    This annotation marks the field or method containing the user's password.  It allows a <literal>hash</literal>
+                    algorithm to be specified for password hashing.  Possible values for <literal>hash</literal> are
+                    <literal>md5</literal>, <literal>sha</literal> and <literal>none</literal>.  E.g:
+                  </para>
+
+                  <programlisting role="JAVA"><![CDATA[@UserPassword(hash = "md5")
+public String getPasswordHash() { 
+  return passwordHash; 
+}]]></programlisting>
+
+                  <para>
+                    If an application requires a hash algorithm that isn't supported natively by Seam, it
+                    is possible to extend the <literal>PasswordHash</literal> component to implement other
+                    hashing algorithms.
+                  </para>
+                </entry>
+              </row>     
+              
+              <row>
+                <entry>
+                  <para>
+                    <literal>@UserFirstName</literal>
+                  </para>
+                </entry>
+                <entry>
+                  <para>Optional</para>
+                </entry>
+                <entry>
+                  <para>
+                    This annotation marks the field or method containing the user's first name.
+                  </para>
+                </entry>
+              </row> 
+              
+              <row>
+                <entry>
+                  <para>
+                    <literal>@UserLastName</literal>
+                  </para>
+                </entry>
+                <entry>
+                  <para>Optional</para>
+                </entry>
+                <entry>
+                  <para>
+                    This annotation marks the field or method containing the user's last name.
+                  </para>
+                </entry>
+              </row>   
+              
+              <row>
+                <entry>
+                  <para>
+                    <literal>@UserEnabled</literal>
+                  </para>
+                </entry>
+                <entry>
+                  <para>Optional</para>
+                </entry>
+                <entry>
+                  <para>
+                    This annotation marks the field or method containing the enabled status of the user.  This should be a boolean
+                    property, and if not present then all user accounts are assumed to be enabled.
+                  </para>
+                </entry>
+              </row>    
+              
+              <row>
+                <entry>
+                  <para>
+                    <literal>@UserRoles</literal>
+                  </para>
+                </entry>
+                <entry>
+                  <para>Required</para>
+                </entry>
+                <entry>
+                  <para>
+                    This annotation marks the field or method containing the roles of the user.  This property will be described in 
+                    more detail further down.
+                  </para>
+                </entry>
+              </row>
+            </tbody>
+          </tgroup>
+        </table>               
+              
+        <table>
+          <title>Role Entity Annotations</title>
+    
+          <tgroup cols="2">
+            <colspec colnum="1" colwidth="2*" />
+            <colspec colnum="2" colwidth="1*" />
+            <colspec colnum="3" colwidth="3*" />
+    
+            <thead>
+              <row>
+                <entry align="center">
+                  <para>Annotation</para>
+                </entry>
+                <entry align="center">
+                  <para>Status</para>
+                </entry>
+                <entry align="center">
+                  <para>Description</para>
+                </entry>
+              </row>
+            </thead>
+    
+            <tbody>               
+              <row>
+                <entry>
+                  <para>
+                    <literal>@RoleName</literal>
+                  </para>
+                </entry>
+                <entry>
+                  <para>Required</para>
+                </entry>
+                <entry>
+                  <para>
+                    This annotation marks the field or method containing the name of the role.
+                  </para>
+                </entry>
+              </row>  
+              
+              <row>
+                <entry>
+                  <para>
+                    <literal>@RoleGroups</literal>
+                  </para>
+                </entry>
+                <entry>
+                  <para>Optional</para>
+                </entry>
+                <entry>
+                  <para>
+                    This annotation marks the field or method containing the group memberships of the role.
+                  </para>
+                </entry>
+              </row>    
+              
+              <row>
+                <entry>
+                  <para>
+                    <literal>@RoleConditional</literal>
+                  </para>
+                </entry>
+                <entry>
+                  <para>Optional</para>
+                </entry>
+                <entry>
+                  <para>
+                    This annotation marks the field or method indicating whether the role is conditional or not.
+                    Conditional roles are explained later in this chapter.
+                  </para>
+                </entry>
+              </row>                                                                                       
+              
+            </tbody>
+          </tgroup>
+        </table>     
+        
+      </sect3>
+      
+      <sect3>
+        <title>Entity Bean Examples</title>
+        
+        <para>
+          As mentioned previously, <literal>JpaIdentityStore</literal> is designed to be as flexible as possible when
+          it comes to the database schema design of your user and role tables.  This section looks at a number of
+          possible database schemas that can be used to store user and role records.
+        </para>
+        
+        <sect4>
+          <title>Minimal schema example</title>
+          
+          <para>
+            In this bare minimal example, a simple user and role table are linked via a
+            many-to-many relationship using a cross-reference table named <literal>UserRoles</literal>.
+          </para>
+          
+          <mediaobject>
+            <imageobject role="fo">
+              <imagedata fileref="images/security-entities-1.png" align="center" scalefit="1"/>
+            </imageobject>
+            <imageobject role="html">
+              <imagedata fileref="images/security-entities-1.png" align="center"/>
+            </imageobject>
+          </mediaobject>          
+          
+          <programlisting role="JAVA"><![CDATA[@Entity
+public class User {
+  private Integer userId;
+  private String username;
+  private String passwordHash;
+  private Set<Role> roles;
+  
+  @Id @GeneratedValue
+  public Integer getUserId() { return userId; }
+  public void setUserId(Integer userId) { this.userId = userId; }
+  
+  @UserPrincipal
+  public String getUsername() { return username; }
+  public void setUsername(String username) { this.username = username; }
+  
+  @UserPassword(hash = "md5")
+  public String getPasswordHash() { return passwordHash; }
+  public void setPasswordHash(String passwordHash) { this.passwordHash = passwordHash; }
+  
+  @UserRoles
+  @ManyToMany(targetEntity = Role.class)
+  @JoinTable(name = "UserRoles", 
+    joinColumns = @JoinColumn(name = "UserId"),
+    inverseJoinColumns = @JoinColumn(name = "RoleId"))
+  public Set<Role> getRoles() { return roles; }
+  public void setRoles(Set<Role> roles) { this.roles = roles; }
+}]]></programlisting>
+<programlisting><![CDATA[@Entity
+public class Role {
+  private Integer roleId;
+  private String rolename;
+  
+  @Id @Generated
+  public Integer getRoleId() { return roleId; }
+  public void setRoleId(Integer roleId) { this.roleId = roleId; }
+  
+  @RoleName
+  public String getRolename() { return rolename; }
+  public void setRolename(String rolename) { this.rolename = rolename; }
+}]]></programlisting>
+
+        </sect4>
+        
+        <sect4>
+          <title>Complex Schema Example</title>
+          
+          <para>
+            This example builds on the above minimal example by including all of the optional fields, and allowing
+            group memberships for roles.
+          </para>
+          
+          <mediaobject>
+            <imageobject role="fo">
+              <imagedata fileref="images/security-entities-2.png" align="center" scalefit="1"/>
+            </imageobject>
+            <imageobject role="html">
+              <imagedata fileref="images/security-entities-2.png" align="center"/>
+            </imageobject>
+          </mediaobject>         
+          
+          <programlisting role="JAVA"><![CDATA[@Entity
+public class User {
+  private Integer userId;
+  private String username;
+  private String passwordHash;
+  private Set<Role> roles;
+  private String firstname;
+  private String lastname;
+  private boolean enabled;
+  
+  @Id @GeneratedValue
+  public Integer getUserId() { return userId; }
+  public void setUserId(Integer userId) { this.userId = userId; }
+  
+  @UserPrincipal
+  public String getUsername() { return username; }
+  public void setUsername(String username) { this.username = username; }
+  
+  @UserPassword(hash = "md5")
+  public String getPasswordHash() { return passwordHash; }
+  public void setPasswordHash(String passwordHash) { this.passwordHash = passwordHash; }
+  
+  @UserFirstName
+  public String getFirstname() { return firstname; }
+  public void setFirstname(String firstname) { this.firstname = firstname; }
+  
+  @UserLastName
+  public String getLastname() { return lastname; }
+  public void setLastname(String lastname) { this.lastname = lastname; }
+  
+  @UserEnabled
+  public boolean isEnabled() { return enabled; }
+  public void setEnabled(boolean enabled) { this.enabled = enabled; }
+  
+  @UserRoles
+  @ManyToMany(targetEntity = Role.class)
+  @JoinTable(name = "UserRoles", 
+    joinColumns = @JoinColumn(name = "UserId"),
+    inverseJoinColumns = @JoinColumn(name = "RoleId"))
+  public Set<Role> getRoles() { return roles; }
+  public void setRoles(Set<Role> roles) { this.roles = roles; }
+}]]></programlisting>
+<programlisting><![CDATA[@Entity
+public class Role {
+  private Integer roleId;
+  private String rolename;
+  private boolean conditional;
+  
+  @Id @Generated
+  public Integer getRoleId() { return roleId; }
+  public void setRoleId(Integer roleId) { this.roleId = roleId; }
+  
+  @RoleName
+  public String getRolename() { return rolename; }
+  public void setRolename(String rolename) { this.rolename = rolename; }
+  
+  @RoleConditional
+  public boolean isConditional() { return conditional; }
+  public void setConditional(boolean conditional) { this.conditional = conditional; }
+  
+  @RoleGroups
+  @ManyToMany(targetEntity = Role.class)
+  @JoinTable(name = "RoleGroups", 
+    joinColumns = @JoinColumn(name = "RoleId"),
+    inverseJoinColumns = @JoinColumn(name = "GroupId"))
+  public Set<Role> getGroups() { return groups; }
+  public void setGroups(Set<Role> groups) { this.groups = groups; }  
+  
+}]]></programlisting>           
+        </sect4>
+      
+      </sect3>
+      
+      <sect3>
+        <title>JpaIdentityStore Events</title>
+        
+        <para>
+          When using <literal>JpaIdentityStore</literal> as the identity store implementation with <literal>IdentityManager</literal>,
+          a few events are raised as a result of invoking certain <literal>IdentityManager</literal> methods.
+        </para>
+        
+        <sect4>
+          <title>JpaIdentityStore.EVENT_PRE_PERSIST_USER</title>
+          
+          <para>
+            This event is raised in response to calling <literal>IdentityManager.createUser()</literal>.  Just before the user
+            entity is persisted to the database, this event will be raised passing the entity instance as an event parameter.  
+            The entity will be an instance of the <literal>user-class</literal> configured for <literal>JpaIdentityStore</literal>.            
+          </para>
+          
+          <para>
+            Writing an observer for this event may be useful for setting additional field values on the entity, which aren't set
+            as part of the standard <literal>createUser()</literal> functionality.
+          </para>
+        </sect4>
+        
+        <sect4>
+          <title>JpaIdentityStore.EVENT_USER_CREATED</title>
+          
+          <para>
+            This event is also raised in response to calling <literal>IdentityManager.createUser()</literal>.  However, it is 
+            raised after the user entity has already been persisted to the database.  Like the <literal>EVENT_PRE_PERSIST_USER</literal>
+            event, it also passes the entity instance as an event parameter.  It may be useful to observe this event if you also
+            need to persist other entities that reference the user entity, for example contact detail records or other user-specific
+            data.
+          </para>
+        </sect4>
+        
+        <sect4>
+          <title>JpaIdentityStore.EVENT_USER_AUTHENTICATED</title>
+          
+          <para>
+            This event is raised when calling <literal>IdentityManager.authenticate()</literal>.  It passes the user entity instance
+            as the event parameter, and is useful for reading additional properties from the user entity that is being authenticated.
+          </para>
+        </sect4>
+      </sect3>
+      
+    </sect2>
+    
+    <sect2>
+      <title>LdapIdentityStore</title>
+      
+      <para>
+        This identity store implementation is designed for working with user records stored in an LDAP directory.  It is very
+        highly configurable, allowing great flexibility in how both users and roles are stored in the directory.  The following
+        sections describe the configuration options for this identity store, and provide some configuration examples.
+      </para>
+      
+      <sect3>
+        <title>Configuring LdapIdentityStore</title>
+        
+        <para>
+          The following table describes the available properties that can be configured in <literal>components.xml</literal> for
+          <literal>LdapIdentityStore</literal>.
+        </para>
+        
+        <table>
+          <title>LdapIdentityStore Configuration Properties</title>
+    
+          <tgroup cols="2">
+            <colspec colnum="1" colwidth="2*" />
+            <colspec colnum="2" colwidth="1*" />
+            <colspec colnum="3" colwidth="3*" />
+    
+            <thead>
+              <row>
+                <entry align="center">
+                  <para>Property</para>
+                </entry>
+                <entry align="center">
+                  <para>Default Value</para>
+                </entry>
+                <entry align="center">
+                  <para>Description</para>
+                </entry>
+              </row>
+            </thead>
+    
+            <tbody>               
+              <row>
+                <entry>
+                  <para>
+                    <literal>server-address</literal>
+                  </para>
+                </entry>
+                <entry>
+                  <para><literal>localhost</literal></para>
+                </entry>
+                <entry>
+                  <para>
+                    The address of the LDAP server.
+                  </para>
+                </entry>
+              </row>
+              
+              <row>
+                <entry>
+                  <para>
+                    <literal>server-port</literal>
+                  </para>
+                </entry>
+                <entry>
+                  <para><literal>389</literal></para>
+                </entry>
+                <entry>
+                  <para>
+                    The port number that the LDAP server is listening on.
+                  </para>
+                </entry>
+              </row>
+              
+              <row>
+                <entry>
+                  <para>
+                    <literal>user-context-DN</literal>
+                  </para>
+                </entry>
+                <entry>
+                  <para><literal>ou=Person,dc=acme,dc=com</literal></para>
+                </entry>
+                <entry>
+                  <para>
+                    The Distinguished Name (DN) of the context containing user records.
+                  </para>
+                </entry>
+              </row>
+              
+              <row>
+                <entry>
+                  <para>
+                    <literal>user-DN-prefix</literal>
+                  </para>
+                </entry>
+                <entry>
+                  <para><literal>uid=</literal></para>
+                </entry>
+                <entry>
+                  <para>
+                    This value is prefixed to the front of the username to locate the user's record.
+                  </para>
+                </entry>
+              </row>
+              
+              <row>
+                <entry>
+                  <para>
+                    <literal>user-DN-suffix</literal>
+                  </para>
+                </entry>
+                <entry>
+                  <para><literal>,ou=Person,dc=acme,dc=com</literal></para>
+                </entry>
+                <entry>
+                  <para>
+                    This value is appended to the end of the username to locate the user's record.
+                  </para>
+                </entry>
+              </row>
+              
+              <row>
+                <entry>
+                  <para>
+                    <literal>role-context-DN</literal>
+                  </para>
+                </entry>
+                <entry>
+                  <para><literal>ou=Role,dc=acme,dc=com</literal></para>
+                </entry>
+                <entry>
+                  <para>
+                    The DN of the context containing role records.
+                  </para>
+                </entry>
+              </row>
+              
+              <row>
+                <entry>
+                  <para>
+                    <literal>role-DN-prefix</literal>
+                  </para>
+                </entry>
+                <entry>
+                  <para><literal>cn=</literal></para>
+                </entry>
+                <entry>
+                  <para>
+                    This value is prefixed to the front of the role name to form the DN for locating the 
+                    role record.
+                  </para>
+                </entry>
+              </row>
+              
+              <row>
+                <entry>
+                  <para>
+                    <literal>role-DN-suffix</literal>
+                  </para>
+                </entry>
+                <entry>
+                  <para><literal>,ou=Roles,dc=acme,dc=com</literal></para>
+                </entry>
+                <entry>
+                  <para>
+                    This value is appended to the role name to form the DN for locating the role record.
+                  </para>
+                </entry>
+              </row>
+              
+              <row>
+                <entry>
+                  <para>
+                    <literal>bind-DN</literal>
+                  </para>
+                </entry>
+                <entry>
+                  <para><literal>cn=Manager,dc=acme,dc=com</literal></para>
+                </entry>
+                <entry>
+                  <para>
+                    This is the context used to bind to the LDAP server.
+                  </para>
+                </entry>
+              </row>
+              
+              <row>
+                <entry>
+                  <para>
+                    <literal>bind-credentials</literal>
+                  </para>
+                </entry>
+                <entry>
+                  <para><literal>secret</literal></para>
+                </entry>
+                <entry>
+                  <para>
+                    These are the credentials (the password) used to bind to the LDAP server.
+                  </para>
+                </entry>
+              </row>
+              
+              <row>
+                <entry>
+                  <para>
+                    <literal>user-role-attribute</literal>
+                  </para>
+                </entry>
+                <entry>
+                  <para><literal>roles</literal></para>
+                </entry>
+                <entry>
+                  <para>
+                    This is the name of the attribute of the user record that contains the list of roles that the
+                    user is a member of.
+                  </para>
+                </entry>
+              </row>
+              
+              <row>
+                <entry>
+                  <para>
+                    <literal>role-attribute-is-DN</literal>
+                  </para>
+                </entry>
+                <entry>
+                  <para><literal>true</literal></para>
+                </entry>
+                <entry>
+                  <para>
+                    This boolean property indicates whether the role attribute of the user record is itself a
+                    distinguished name.
+                  </para>
+                </entry>
+              </row>
+              
+              <row>
+                <entry>
+                  <para>
+                    <literal>user-name-attribute</literal>
+                  </para>
+                </entry>
+                <entry>
+                  <para><literal>uid</literal></para>
+                </entry>
+                <entry>
+                  <para>
+                    Indicates which attribute of the user record contains the username.
+                  </para>
+                </entry>
+              </row>
+              
+              <row>
+                <entry>
+                  <para>
+                    <literal>user-password-attribute</literal>
+                  </para>
+                </entry>
+                <entry>
+                  <para><literal>userPassword</literal></para>
+                </entry>
+                <entry>
+                  <para>
+                    Indicates which attribute of the user record contains the user's password.
+                  </para>
+                </entry>
+              </row>
+              
+              <row>
+                <entry>
+                  <para>
+                    <literal>first-name-attribute</literal>
+                  </para>
+                </entry>
+                <entry>
+                  <para><literal>null</literal></para>
+                </entry>
+                <entry>
+                  <para>
+                    Indicates which attribute of the user record contains the user's first name.
+                  </para>
+                </entry>
+              </row>
+              
+              <row>
+                <entry>
+                  <para>
+                    <literal>last-name-attribute</literal>
+                  </para>
+                </entry>
+                <entry>
+                  <para><literal>sn</literal></para>
+                </entry>
+                <entry>
+                  <para>
+                    Indicates which attribute of the user record contains the user's last name.
+                  </para>
+                </entry>
+              </row>
+              
+              <row>
+                <entry>
+                  <para>
+                    <literal>full-name-attribute</literal>
+                  </para>
+                </entry>
+                <entry>
+                  <para><literal>cn</literal></para>
+                </entry>
+                <entry>
+                  <para>
+                    Indicates which attribute of the user record contains the user's full (common) name.
+                  </para>
+                </entry>
+              </row>
+              
+              <row>
+                <entry>
+                  <para>
+                    <literal>enabled-attribute</literal>
+                  </para>
+                </entry>
+                <entry>
+                  <para><literal>null</literal></para>
+                </entry>
+                <entry>
+                  <para>
+                    Indicates which attribute of the user record determines whether the user is enabled.
+                  </para>
+                </entry>
+              </row>
+              
+              <row>
+                <entry>
+                  <para>
+                    <literal>role-name-attribute</literal>
+                  </para>
+                </entry>
+                <entry>
+                  <para><literal>cn</literal></para>
+                </entry>
+                <entry>
+                  <para>
+                    Indicates which attribute of the role record contains the name of the role.
+                  </para>
+                </entry>
+              </row>
+              
+              <row>
+                <entry>
+                  <para>
+                    <literal>object-class-attribute</literal>
+                  </para>
+                </entry>
+                <entry>
+                  <para><literal>objectClass</literal></para>
+                </entry>
+                <entry>
+                  <para>
+                    Indicates which attribute determines the class of an object in the directory.
+                  </para>
+                </entry>
+              </row>
+              
+              <row>
+                <entry>
+                  <para>
+                    <literal>role-object-classes</literal>
+                  </para>
+                </entry>
+                <entry>
+                  <para><literal>organizationalRole</literal></para>
+                </entry>
+                <entry>
+                  <para>
+                    An array of the object classes that new role records should be created as.
+                  </para>
+                </entry>
+              </row>
+              
+              <row>
+                <entry>
+                  <para>
+                    <literal>user-object-classes</literal>
+                  </para>
+                </entry>
+                <entry>
+                  <para><literal>person,uidObject</literal></para>
+                </entry>
+                <entry>
+                  <para>
+                    An array of the object classes that new user records should be created as.
+                  </para>
+                </entry>
+              </row>
+               
+            </tbody>
+          </tgroup>
+        </table>     
+      </sect3>
+      
+      <sect3>
+        <title>LdapIdentityStore Configuration Example</title>
+        
+        <para>
+          The following configuration example shows how <literal>LdapIdentityStore</literal> may be configured for
+          an LDAP directory running on fictional host <literal>directory.mycompany.com</literal>.  The users are stored
+          within this directory under the context <literal>ou=Person,dc=mycompany,dc=com</literal>, and are identified
+          using the <literal>uid</literal> attribute (which corresponds to their username).  Roles are stored in their
+          own context, <literal>ou=Roles,dc=mycompany,dc=com</literal> and referenced from the user's entry via the 
+          <literal>roles</literal> attribute.  Role entries are identified by their common name (the <literal>cn</literal> attribute)
+          , which corresponds to the role name.  In this example, users may be disabled by setting the value of their 
+          <literal>enabled</literal> attribute to false.
+        </para>
+        
+        <programlisting role="XML"><![CDATA[
+  <security:ldap-identity-store
+    server-address="directory.mycompany.com"
+    bind-DN="cn=Manager,dc=mycompany,dc=com"
+    bind-credentials="secret"
+    user-DN-prefix="uid="
+    user-DN-suffix=",ou=Person,dc=mycompany,dc=com"
+    role-DN-prefix="cn="
+    role-DN-suffix=",ou=Roles,dc=mycompany,dc=com"
+    user-context-DN="ou=Person,dc=mycompany,dc=com"
+    role-context-DN="ou=Roles,dc=mycompany,dc=com"
+    user-role-attribute="roles"
+    role-name-attribute="cn"
+    user-object-classes="person,uidObject"
+    enabled-attribute="enabled"
+    />]]></programlisting>
+        
+      </sect3>
+
+    </sect2>
+    
+    <sect2>
+      <title>Writing your own IdentityStore</title>
+      
+      <para>
+        Writing your own identity store implementation allows you to authenticate and perform identity management
+        operations against security providers that aren't supported out of the box by Seam.  Only a single class is 
+        required to achieve this, and it must implement the
+        <literal>org.jboss.seam.security.management.IdentityStore</literal> interface.
+      </para>
+      
+      <para>
+        Please refer to the JavaDoc for <literal>IdentityStore</literal> for a description of the methods that
+        must be implemented.
+      </para>
+    </sect2>
+    
+    
+    <sect2>
+      <title>Authentication with Identity Management</title>
+      
+      <para>
+        If you are using the Identity Management features in your Seam application, then it is not required
+        to provide an authenticator component (see previous Authentication section) to enable authentication.
+        Simply omit the <literal>authenticate-method</literal> from the <literal>identity</literal> configuration
+        in <literal>components.xml</literal>, and the <literal>SeamLoginModule</literal> will by default
+        use <literal>IdentityManager</literal> to authenticate your application's users, without any special
+        configuration required.
+      </para>
+    </sect2>
+    
+    <sect2>
+      <title>Using IdentityManager</title>
+            
+      <para>
+        The <literal>IdentityManager</literal> can be accessed either by injecting it into your Seam
+        component as follows:
+      </para>
+
+      <programlisting role="JAVA"><![CDATA[  @In IdentityManager identityManager;]]></programlisting>
+
+      <para>
+        or by accessing it through its static <literal>instance()</literal> method:
+      </para>
+
+      <programlisting role="JAVA"><![CDATA[  IdentityManager identityManager = IdentityManager.instance();]]></programlisting>
+
+      <para>
+        The following table describes <literal>IdentityManager</literal>'s API methods:
+      </para>
+
+      <table>
+        <title>Identity Management API</title>
+
+        <tgroup cols="2">
+          <colspec colnum="1" colwidth="1*" />
+          <colspec colnum="2" colwidth="3*" />
+
+          <thead>
+            <row>
+              <entry align="center">
+                <para>Method</para>
+              </entry>
+              <entry align="center">
+                <para>Returns</para>
+              </entry>
+              <entry align="center">
+                <para>Description</para>
+              </entry>
+            </row>
+          </thead>
+
+          <tbody>
+
+            <row>
+              <entry>
+                <para>
+                  <literal>createUser(String name, String password)</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>boolean</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  Creates a new user account, with the specified name and password.  Returns <literal>true</literal>
+                  if successful, or <literal>false</literal> if not.
+                </para>
+              </entry>
+            </row>       
+
+            <row>
+              <entry>
+                <para>
+                  <literal>deleteUser(String name)</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>boolean</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  Deletes the user account with the specified name.  Returns <literal>true</literal>
+                  if successful, or <literal>false</literal> if not.
+                </para>
+              </entry>
+            </row>
+                        
+            <row>
+              <entry>
+                <para>
+                  <literal>createRole(String role)</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>boolean</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  Creates a new role, with the specified name.  Returns <literal>true</literal>
+                  if successful, or <literal>false</literal> if not.
+                </para>
+              </entry>
+            </row>                
+            
+            <row>
+              <entry>
+                <para>
+                  <literal>deleteRole(String name)</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>boolean</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  Deletes the role with the specified name.  Returns <literal>true</literal>
+                  if successful, or <literal>false</literal> if not.
+                </para>
+              </entry>
+            </row>            
+
+            <row>
+              <entry>
+                <para>
+                  <literal>enableUser(String name)</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>boolean</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  Enables the user account with the specified name.  Accounts that are not enabled are
+                  not able to authenticate.  Returns <literal>true</literal> if successful, or
+                  <literal>false</literal> if not.
+                </para>
+              </entry>
+            </row>
+
+            <row>
+              <entry>
+                <para>
+                  <literal>disableUser(String name)</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>boolean</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  Disables the user account with the specified name.  Returns <literal>true</literal> if
+                  successful, or <literal>false</literal> if not.
+                </para>
+              </entry>
+            </row>
+
+            <row>
+              <entry>
+                <para>
+                  <literal>changePassword(String name, String password)</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>boolean</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  Changes the password for the user account with the specified name.  Returns
+                  <literal>true</literal> if successful, or <literal>false</literal> if not.
+                </para>
+              </entry>
+            </row>
+
+            <row>
+              <entry>
+                <para>
+                  <literal>isUserEnabled(String name)</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>boolean</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  Returns <literal>true</literal> if the specified user account is enabled, or
+                  <literal>false</literal> if it isn't.
+                </para>
+              </entry>
+            </row>
+
+            <row>
+              <entry>
+                <para>
+                  <literal>grantRole(String name, String role)</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>boolean</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  Grants the specified role to the specified user or role.  The role must already exist for it to
+                  be granted.  Returns <literal>true</literal> if the role is successfully granted, or
+                  <literal>false</literal> if it is already granted to the user.
+                </para>
+              </entry>
+            </row>
+
+            <row>
+              <entry>
+                <para>
+                  <literal>revokeRole(String name, String role)</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>boolean</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  Revokes the specified role from the specified user or role.  Returns <literal>true</literal>
+                  if the specified user is a member of the role and it is successfully revoked, or
+                  <literal>false</literal> if the user is not a member of the role.
+                </para>
+              </entry>
+            </row>
+
+            <row>
+              <entry>
+                <para>
+                  <literal>userExists(String name)</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>boolean</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  Returns <literal>true</literal> if the specified user exists, or <literal>false</literal>
+                  if it doesn't.
+                </para>
+              </entry>
+            </row>
+
+            <row>
+              <entry>
+                <para>
+                  <literal>listUsers()</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>List</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  Returns a list of all user names, sorted in alpha-numeric order.
+                </para>
+              </entry>
+            </row>
+
+            <row>
+              <entry>
+                <para>
+                  <literal>listUsers(String filter)</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>List</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  Returns a list of all user names filtered by the specified filter parameter, sorted in alpha-numeric order.
+                </para>
+              </entry>
+            </row>
+
+            <row>
+              <entry>
+                <para>
+                  <literal>listRoles()</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>List</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  Returns a list of all role names.
+                </para>
+              </entry>
+            </row>
+
+            <row>
+              <entry>
+                <para>
+                  <literal>getGrantedRoles(String name)</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>List</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  Returns a list of the names of all the roles explicitly granted to the specified user name.
+                </para>
+              </entry>
+            </row>
+
+            <row>
+              <entry>
+                <para>
+                  <literal>getImpliedRoles(String name)</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>List</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  Returns a list of the names of all the roles implicitly granted to the specified user name.
+                  Implicitly granted roles include those that are not directly granted to a user, rather they are
+                  granted to the roles that the user is a member of.  For example, is the <literal>admin</literal>
+                  role is a member of the <literal>user</literal> role, and a user is a member of the <literal>admin</literal>
+                  role, then the implied roles for the user are both the <literal>admin</literal>, and <literal>user</literal>
+                  roles.
+                </para>
+              </entry>
+            </row>
+
+            <row>
+              <entry>
+                <para>
+                  <literal>authenticate(String name, String password)</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>boolean</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  Authenticates the specified username and password using the configured Identity Store.  Returns
+                  <literal>true</literal> if successful or <literal>false</literal> if authentication failed.
+                  Successful authentication implies nothing beyond the return value of the method.  It does not
+                  change the state of the <literal>Identity</literal> component - to perform a proper Seam login the
+                  <literal>Identity.login()</literal> must be used instead.
+                </para>
+              </entry>
+            </row>
+            
+            <row>
+              <entry>
+                <para>
+                  <literal>addRoleToGroup(String role, String group)</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>boolean</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  Adds the specified role as a member of the specified group.  Returns true if the operation is successful.
+                </para>
+              </entry>
+            </row>     
+            
+            <row>
+              <entry>
+                <para>
+                  <literal>removeRoleFromGroup(String role, String group)</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>boolean</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  Removes the specified role from the specified group.  Returns true if the operation is successful.
+                </para>
+              </entry>
+            </row>    
+            
+            <row>
+              <entry>
+                <para>
+                  <literal>listRoles()</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>List</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  Lists the names of all roles.
+                </para>
+              </entry>
+            </row>       
+
+          </tbody>
+        </tgroup>
+      </table>
+
+      <para>
+        Using the Identity Management API requires that the calling user has the appropriate authorization to invoke
+        its methods.  The following table describes the permission requirements for each of the methods in
+        <literal>IdentityManager</literal>.  The permission targets listed below are literal String values.
+      </para>
+
+      <table>
+        <title>Identity Management Security Permissions</title>
+
+        <tgroup cols="2">
+          <colspec colnum="1" colwidth="1*" />
+          <colspec colnum="2" colwidth="3*" />
+
+          <thead>
+            <row>
+              <entry align="center">
+                <para>Method</para>
+              </entry>
+              <entry align="center">
+                <para>Permission Target</para>
+              </entry>
+              <entry align="center">
+                <para>Permission Action</para>
+              </entry>
+            </row>
+          </thead>
+
+          <tbody>
+            <row>
+              <entry>
+                <para>
+                  <literal>createUser()</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>seam.user</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>create</literal>
+                </para>
+              </entry>
+            </row>
+
+            <row>
+              <entry>
+                <para>
+                  <literal>deleteUser()</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>seam.user</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>delete</literal>
+                </para>
+              </entry>
+            </row>
+            
+            <row>
+              <entry>
+                <para>
+                  <literal>createRole()</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>seam.role</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>create</literal>
+                </para>
+              </entry>
+            </row>            
+            
+            <row>
+              <entry>
+                <para>
+                  <literal>deleteRole()</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>seam.role</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>delete</literal>
+                </para>
+              </entry>
+            </row>            
+
+            <row>
+              <entry>
+                <para>
+                  <literal>enableUser()</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>seam.user</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>update</literal>
+                </para>
+              </entry>
+            </row>
+
+            <row>
+              <entry>
+                <para>
+                  <literal>disableUser()</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>seam.user</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>update</literal>
+                </para>
+              </entry>
+            </row>
+
+            <row>
+              <entry>
+                <para>
+                  <literal>changePassword()</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>seam.user</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>update</literal>
+                </para>
+              </entry>
+            </row>
+
+            <row>
+              <entry>
+                <para>
+                  <literal>isUserEnabled()</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>seam.user</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>read</literal>
+                </para>
+              </entry>
+            </row>
+
+            <row>
+              <entry>
+                <para>
+                  <literal>grantRole()</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>seam.user</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>update</literal>
+                </para>
+              </entry>
+            </row>
+
+            <row>
+              <entry>
+                <para>
+                  <literal>revokeRole()</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>seam.user</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>update</literal>
+                </para>
+              </entry>
+            </row>
+
+            <row>
+              <entry>
+                <para>
+                  <literal>userExists()</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>seam.user</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>read</literal>
+                </para>
+              </entry>
+            </row>        
+
+            <row>
+              <entry>
+                <para>
+                  <literal>listUsers()</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>seam.user</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>read</literal>
+                </para>
+              </entry>
+            </row>
+
+            <row>
+              <entry>
+                <para>
+                  <literal>listRoles()</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>seam.role</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>read</literal>
+                </para>
+              </entry>
+            </row>
+            
+            <row>
+              <entry>
+                <para>
+                  <literal>addRoleToGroup()</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>seam.role</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>update</literal>
+                </para>
+              </entry>
+            </row>       
+            
+            <row>
+              <entry>
+                <para>
+                  <literal>removeRoleFromGroup()</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>seam.role</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>update</literal>
+                </para>
+              </entry>
+            </row>                 
+          </tbody>
+        </tgroup>
+      </table>
+
+      <para>
+        The following code listing provides an example set of security rules that grants access to all
+        Identity Management-related methods to members of the <literal>admin</literal> role:
+      </para>
+
+      <programlisting><![CDATA[rule ManageUsers
+  no-loop
+  activation-group "permissions"
+when
+  check: PermissionCheck(name == "seam.user", granted == false)
+  Role(name == "admin")
+then
+  check.grant();
+end
+
+rule ManageRoles
+  no-loop
+  activation-group "permissions"
+when
+  check: PermissionCheck(name == "seam.role", granted == false)
+  Role(name == "admin")
+then
+  check.grant();
+end
+]]></programlisting>
+
+    </sect2>
+        
+  </sect1>
+
+  <sect1>
+    <title>Error Messages</title>
+
+    <para>
+      The security API produces a number of default faces messages for various security-related events.
+      The following table lists the message keys that can be used to override these messages by specifying
+      them in a <literal>message.properties</literal> resource file.  To suppress the message, just put the
+      key with an empty value in the resource file.
+    </para>
+
+    <table>
+      <title>Security Message Keys</title>
+
+      <tgroup cols="2">
+        <colspec colnum="1" colwidth="2*" />
+        <colspec colnum="2" colwidth="3*" />
+
+        <thead>
+          <row>
+            <entry align="center">
+              <para>Message Key</para>
+            </entry>
+            <entry align="center">
+              <para>Description</para>
+            </entry>
+          </row>
+        </thead>
+
+        <tbody>
+
+          <row>
+            <entry>
+              <para>
+                <literal>org.jboss.seam.loginSuccessful</literal>
+              </para>
+            </entry>
+            <entry>
+              <para>
+                This message is produced when a user successfully logs in via the security API.
+              </para>
+            </entry>
+          </row>
+          <row>
+            <entry>
+              <para>
+                <literal>org.jboss.seam.loginFailed</literal>
+              </para>
+            </entry>
+            <entry>
+              <para>
+                This message is produced when the login process fails, either because the user provided an
+                incorrect username or password, or because authentication failed in some other way.
+              </para>
+            </entry>
+          </row>
+          <row>
+            <entry>
+              <para>
+                <literal>org.jboss.seam.NotLoggedIn</literal>
+              </para>
+            </entry>
+            <entry>
+              <para>
+                This message is produced when a user attempts to perform an action or access a page that requires
+                a security check, and the user is not currently authenticated.
+              </para>
+            </entry>
+          </row>
+          <row>
+            <entry>
+              <para>
+                <literal>org.jboss.seam.AlreadyLoggedIn</literal>
+              </para>
+            </entry>
+            <entry>
+              <para>
+                This message is produced when a user that is already authenticated attempts to log in again.
+              </para>
+            </entry>
+          </row>          
+        </tbody>
+      </tgroup>
+    </table>
+  </sect1>
+
+  <sect1>
+    <title>Authorization</title>
+
+    <para>
+      There are a number of authorization mechanisms provided by the Seam Security API for securing access to
+      components, component methods, and pages.  This section describes each of these.  An important thing to
+      note is that if you wish to use any of the advanced features (such as rule-based permissions) then
+      your <literal>components.xml</literal> may need to be configured to support this - see the Configuration section
+      above.
+    </para>
+
+    <sect2>
+      <title>Core concepts</title>
+
+      <para>
+        Seam Security is built around the premise of users being granted roles and/or permissions, allowing them to
+        perform operations that may not otherwise be permissible for users without the necessary security privileges.
+        Each of the authorization mechanisms provided by the Seam Security API are built upon this core concept of roles and
+        permissions, with an extensible framework providing multiple ways to secure application resources.
+      </para>
+
+      <sect3>
+        <title>What is a role?</title>
+        
+        <para>
+          A role is a <emphasis>group</emphasis>, or <emphasis>type</emphasis>, of user that may have been granted certain 
+          privileges for performing one or more specific actions within an application.  They are simple constructs, consisting 
+          of just a name such as "admin", "user", "customer", etc.  They can be granted either to users (or in some cases to other 
+          roles), and are used to create logical groups of users for the convenient assignment of specific application privileges.
+        </para>
+
+        <mediaobject>
+          <imageobject role="fo">
+            <imagedata fileref="images/security-roleclass.png" align="center"/>
+          </imageobject>
+          <imageobject role="html">
+            <imagedata fileref="images/security-roleclass.png" align="center"/>
+          </imageobject>
+        </mediaobject>        
+      </sect3>
+      
+      <sect3>
+        <title>What is a permission?</title>
+        
+        <para>
+          A permission is a privilege (sometimes once-off) for performing a single, specific action.  It is entirely possible to 
+          build an application using nothing but permissions, however roles offer a higher level of convenience when granting 
+          privileges to groups of users.  They are slightly more complex in structure than roles, essentially consisting of three 
+          "aspects"; a target, an action, and a recipient.  The target of a permission is the object (or an arbitrary name or class) 
+          for which a particular action is allowed to be performed by a specific recipient (or user).  For example, the user "Bob" 
+          may have permission to delete customer objects.  In this case, the permission target may be "customer", the permission 
+          action would be "delete" and the recipient would be "Bob".
+        </para>
+        
+
+        <mediaobject>
+          <imageobject role="fo">
+            <imagedata fileref="images/security-permissionclass.png" align="center"/>
+          </imageobject>
+          <imageobject role="html">
+            <imagedata fileref="images/security-permissionclass.png" align="center"/>
+          </imageobject>
+        </mediaobject>        
+      
+        <para>
+          Within this documentation, permissions are generally represented in the form <literal>target:action</literal> 
+          (omitting the recipient, although in reality one is always required).
+        </para>  
+      </sect3>
+
+    </sect2>
+
+    <sect2>
+      <title>Securing components</title>
+
+      <para>
+        Let's start by examining the simplest form of authorization, component security, starting with the
+        <literal>@Restrict</literal> annotation.
+      </para>
+      
+      <note>
+        <title>@Restrict vs Typesafe security annotations</title>
+        
+        <para>
+          While using the <literal>@Restrict</literal> annotation provides a powerful and flexible method for security component methods
+          due to its ability to support EL expressions, it is recommended that the typesafe equivalent (described later) be
+          used, at least for the compile-time safety it provides.
+        </para>      
+      </note>
+
+      <sect3>
+        <title>The @Restrict annotation</title>
+
+        <para>
+          Seam components may be secured either at the method or the class level, using the <literal>@Restrict</literal>
+          annotation.  If both a method and it's declaring class are annotated with <literal>@Restrict</literal>,
+          the method restriction will take precedence (and the class restriction will not apply).  If a method
+          invocation fails a security check, then an exception will be thrown as per the contract for
+          <literal>Identity.checkRestriction()</literal> (see Inline Restrictions).  A <literal>@Restrict</literal>
+          on just the component class itself is equivalent to adding <literal>@Restrict</literal> to each of its
+          methods.
+        </para>
+
+        <para>
+          An empty <literal>@Restrict</literal> implies a permission check of <literal>componentName:methodName</literal>.
+          Take for example the following component method:
+        </para>
+
+        <programlisting role="JAVA"><![CDATA[@Name("account")
+public class AccountAction {
+    @Restrict public void delete() {
+      ...
+    }
+}]]></programlisting>
+
+        <para>
+          In this example, the implied permission required to call the <literal>delete()</literal> method is
+          <literal>account:delete</literal>.  The equivalent of this would be to write
+          <literal>@Restrict("#{s:hasPermission('account','delete')}")</literal>.  Now let's look at
+          another example:
+        </para>
+
+        <programlisting role="JAVA"><![CDATA[@Restrict @Name("account")
+public class AccountAction {
+    public void insert() {
+      ...
+    }
+    @Restrict("#{s:hasRole('admin')}")
+    public void delete() {
+      ...
+    }
+}]]></programlisting>
+
+        <para>
+          This time, the component class itself is annotated with <literal>@Restrict</literal>.  This means that
+          any methods without an overriding <literal>@Restrict</literal> annotation require an implicit permission check.
+          In the case of this example, the <literal>insert()</literal> method requires a permission of
+          <literal>account:insert</literal>, while the <literal>delete()</literal> method requires that the user is a
+          member of the <literal>admin</literal> role.
+        </para>
+
+        <para>
+          Before we go any further, let's address the <literal>#{s:hasRole()}</literal> expression seen in the above
+          example.  Both <literal>s:hasRole</literal> and <literal>s:hasPermission</literal> are EL functions, which
+          delegate to the correspondingly named methods of the <literal>Identity</literal> class. These
+          functions can be used within any EL expression throughout the entirety of the security API.
+        </para>
+
+        <para>
+          Being an EL expression, the value of the <literal>@Restrict</literal> annotation may reference any objects that
+          exist within a Seam context.  This is extremely useful when performing permission checks for a specific
+          object instance.  Look at this example:
+        </para>
+
+        <programlisting role="JAVA"><![CDATA[@Name("account")
+public class AccountAction {
+    @In Account selectedAccount;
+    @Restrict("#{s:hasPermission(selectedAccount,'modify')}")
+    public void modify() {
+        selectedAccount.modify();
+    }
+}]]></programlisting>
+
+        <para>
+          The interesting thing to note from this example is the reference to <literal>selectedAccount</literal>
+          seen within the <literal>hasPermission()</literal> function call.  The value of this variable will be
+          looked up from within the Seam context, and passed to the <literal>hasPermission()</literal> method
+          in <literal>Identity</literal>, which in this case can then determine if the user has the required
+          permission for modifying the specified <literal>Account</literal> object.
+        </para>
+      </sect3>
+
+      <sect3>
+        <title>Inline restrictions</title>
+        <para>
+          Sometimes it might be desirable to perform a security check in code, without using the
+          <literal>@Restrict</literal> annotation.  In this situation, simply use
+          <literal>Identity.checkRestriction()</literal> to evaluate a security expression, like this:
+        </para>
+
+        <programlisting role="JAVA"><![CDATA[public void deleteCustomer() {
+    Identity.instance().checkRestriction("#{s:hasPermission(selectedCustomer,'delete')}");
+}]]></programlisting>
+
+        <para>
+          If the expression specified doesn't evaluate to <literal>true</literal>, either
+        </para>
+
+        <itemizedlist>
+            <listitem>
+                <para>
+                    if the user is not logged in, a <literal>NotLoggedInException</literal>
+                    exception is thrown or
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    if the user is logged in, an <literal>AuthorizationException</literal>
+                    exception is thrown.
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+          It is also possible to call the <literal>hasRole()</literal> and <literal>hasPermission()</literal>
+          methods directly from Java code:
+        </para>
+
+        <programlisting role="JAVA"><![CDATA[if (!Identity.instance().hasRole("admin"))
+     throw new AuthorizationException("Must be admin to perform this action");
+
+if (!Identity.instance().hasPermission("customer", "create"))
+     throw new AuthorizationException("You may not create new customers");]]></programlisting>
+
+      </sect3>
+    </sect2>
+
+    <sect2>
+      <title>Security in the user interface</title>
+
+      <para>
+        One indication of a well designed user interface is that the user is not presented with options for
+        which they don't have the necessary privileges to use.  Seam Security allows conditional rendering of
+        either 1) sections of a page or 2) individual controls, based upon the privileges of the user, using
+        the very same EL expressions that are used for component security.
+      </para>
+
+      <para>
+        Let's take a look at some examples of interface security.  First of all, let's pretend that we have a
+        login form that should only be rendered if the user is not already logged in.  Using the
+        <literal>identity.isLoggedIn()</literal> property, we can write this:
+      </para>
+
+      <programlisting role="XHTML"><![CDATA[<h:form class="loginForm" rendered="#{not identity.loggedIn}">]]></programlisting>
+
+      <para>
+        If the user isn't logged in, then the login form will be rendered - very straight forward so far.
+        Now let's pretend there is a menu on the page that contains some actions which should only be accessible
+        to users in the <literal>manager</literal> role.  Here's one way that these could be written:
+      </para>
+
+      <programlisting role="XHTML"><![CDATA[<h:outputLink action="#{reports.listManagerReports}" rendered="#{s:hasRole('manager')}">
+    Manager Reports
+</h:outputLink>]]></programlisting>
+
+      <para>
+        This is also quite straight forward.  If the user is not a member of the <literal>manager</literal>
+        role, then the outputLink will not be rendered. The <literal>rendered</literal> attribute can
+        generally be used on the control itself, or on a surrounding <literal>&lt;s:div&gt;</literal> or
+        <literal>&lt;s:span&gt;</literal> control.
+      </para>
+
+      <para>
+        Now for something more complex.  Let's say you have a <literal>h:dataTable</literal> control on a
+        page listing records for which you may or may not wish to render action links depending on the
+        user's privileges.  The <literal>s:hasPermission</literal> EL function allows us to pass in an
+        object parameter which can be used to determine whether the user has the requested permission
+        for that object or not. Here's how a dataTable with secured links might look:
+      </para>
+
+      <programlisting role="XHTML"><![CDATA[<h:dataTable value="#{clients}" var="cl">
+    <h:column>
+        <f:facet name="header">Name</f:facet>
+        #{cl.name}
+    </h:column>
+    <h:column>
+        <f:facet name="header">City</f:facet>
+        #{cl.city}
+    </h:column>
+    <h:column>
+        <f:facet name="header">Action</f:facet>
+        <s:link value="Modify Client" action="#{clientAction.modify}"
+                rendered="#{s:hasPermission(cl,'modify')}"/>
+        <s:link value="Delete Client" action="#{clientAction.delete}"
+                rendered="#{s:hasPermission(cl,'delete')}"/>
+    </h:column>
+</h:dataTable>]]></programlisting>
+
+    </sect2>
+
+    <sect2>
+      <title>Securing pages</title>
+      <para>
+        Page security requires that the application is using a <literal>pages.xml</literal> file, however is
+        extremely simple to configure.  Simply include a <literal>&lt;restrict/&gt;</literal> element within
+        the <literal>page</literal> elements that you wish to secure.  If no explicit restriction is specified
+        by the <literal>restrict</literal> element, an implied permission of <literal>/viewId.xhtml:render</literal>
+        will be checked when the page is accessed via a non-faces (GET) request, and a permission of
+        <literal>/viewId.xhtml:restore</literal> will be required when any JSF postback (form submission) originates
+        from the page.  Otherwise, the specified restriction will be evaluated as a standard security expression.
+        Here's a couple of examples:
+      </para>
+
+      <programlisting role="XML"><![CDATA[<page view-id="/settings.xhtml">
+    <restrict/>
+</page>]]></programlisting>
+
+      <para>
+        This page has an implied permission of <literal>/settings.xhtml:render</literal> required for non-faces
+        requests and an implied permission of <literal>/settings.xhtml:restore</literal> for faces requests.
+      </para>
+
+      <programlisting role="XML"><![CDATA[<page view-id="/reports.xhtml">
+    <restrict>#{s:hasRole('admin')}</restrict>
+</page>]]></programlisting>
+
+      <para>
+        Both faces and non-faces requests to this page require that the user is a member of the
+        <literal>admin</literal> role.
+      </para>
+
+    </sect2>
+
+    <sect2>
+      <title>Securing Entities</title>
+
+      <para>
+        Seam security also makes it possible to apply security restrictions to read, insert, update and
+        delete actions for entities.
+      </para>
+
+      <para>
+        To secure all actions for an entity class, add a <literal>@Restrict</literal> annotation on the class
+        itself:
+      </para>
+
+      <programlisting role="JAVA"><![CDATA[@Entity
+ at Name("customer")
+ at Restrict
+public class Customer {
+  ...
+}]]></programlisting>
+
+      <para>
+        If no expression is specified in the <literal>@Restrict</literal> annotation, the default security check
+        that is performed is a permission check of <literal>entity:action</literal>, where the permission target 
+        is the entity instance, and the <literal>action</literal> is either <literal>read</literal>, <literal>insert</literal>, 
+        <literal>update</literal> or <literal>delete</literal>.
+      </para>
+
+      <para>
+        It is also possible to only restrict certain actions, by placing a <literal>@Restrict</literal> annotation
+        on the relevent entity lifecycle method (annotated as follows):
+      </para>
+
+      <itemizedlist>
+        <listitem>
+          <para>
+            <literal>@PostLoad</literal> - Called after an entity instance is loaded from the database. Use this
+            method to configure a <literal>read</literal> permission.
+          </para>
+        </listitem>
+        <listitem>
+          <para>
+            <literal>@PrePersist</literal> - Called before a new instance of the entity is inserted. Use this method
+            to configure an <literal>insert</literal> permission.
+          </para>
+        </listitem>
+        <listitem>
+          <para>
+            <literal>@PreUpdate</literal> - Called before an entity is updated. Use this method
+            to configure an <literal>update</literal> permission.
+          </para>
+        </listitem>
+        <listitem>
+          <para>
+            <literal>@PreRemove</literal> - Called before an entity is deleted. Use this method
+            to configure a <literal>delete</literal> permission.
+          </para>
+        </listitem>
+      </itemizedlist>
+
+      <para>
+        Here's an example of how an entity would be configured to perform a security check for any <literal>insert</literal>
+        operations.  Please note that the method is not required to do anything, the only important thing in regard to
+        security is how it is annotated:
+      </para>
+
+      <programlisting role="JAVA"><![CDATA[
+  @PrePersist @Restrict
+  public void prePersist() {}
+   ]]></programlisting>
+
+      <note>
+         <title>Using <literal>/META-INF/orm.xml</literal></title>
+         
+
+         <para>
+            You can also specify the call back method in <literal>/META-INF/orm.xml</literal>:
+         </para>
+
+         <programlisting role="XML"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
+<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
+                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+                 xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_1_0.xsd"
+                 version="1.0">
+
+   <entity class="Customer">
+      <pre-persist method-name="prePersist" />
+   </entity>
+
+</entity-mappings>]]></programlisting>
+
+         <para>
+            Of course, you still need to annotate the <literal>prePersist()</literal>
+            method on <literal>Customer</literal> with <literal>@Restrict</literal>
+         </para>
+      </note>
+
+      <para>
+        And here's an example of an entity permission rule that checks if the authenticated user is allowed to insert
+        a new <literal>MemberBlog</literal> record (from the seamspace example).  The entity for which the security
+        check is being made is automatically inserted into the working memory (in this case <literal>MemberBlog</literal>):
+      </para>
+
+      <programlisting><![CDATA[rule InsertMemberBlog
+  no-loop
+  activation-group "permissions"
+when
+  principal: Principal()
+  memberBlog: MemberBlog(member : member -> (member.getUsername().equals(principal.getName())))
+  check: PermissionCheck(target == memberBlog, action == "insert", granted == false)
+then
+  check.grant();
+end;]]></programlisting>
+
+       <para>
+         This rule will grant the permission <literal>memberBlog:insert</literal> if the currently authenticated
+         user (indicated by the <literal>Principal</literal> fact) has the same name as the member for which the
+         blog entry is being created.  The "<literal>principal: Principal()</literal>" structure that can be seen in the
+         example code is a variable binding - it binds the instance of the <literal>Principal</literal> object from the
+         working memory (placed there during authentication) and assigns it to a variable called <literal>principal</literal>.
+         Variable bindings allow the value to be referred to in other places, such as the following line which compares the 
+         member's username to the <literal>Principal</literal> name.  For more details, please refer to the JBoss Rules documentation.
+       </para>
+
+       <para>
+         Finally, we need to install a listener class that integrates Seam security with
+         your JPA provider.
+       </para>
+
+      <sect3>
+        <title>Entity security with JPA</title>
+
+        <para>
+          Security checks for EJB3 entity beans are performed with an <literal>EntityListener</literal>.
+          You can install this listener by using the following <literal>META-INF/orm.xml</literal> file:
+        </para>
+
+        <programlisting role="XML"><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
+<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
+                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+                 xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_1_0.xsd"
+                 version="1.0">
+
+    <persistence-unit-metadata>
+        <persistence-unit-defaults>
+            <entity-listeners>
+                <entity-listener class="org.jboss.seam.security.EntitySecurityListener"/>
+            </entity-listeners>
+        </persistence-unit-defaults>
+    </persistence-unit-metadata>
+
+</entity-mappings>]]></programlisting>
+
+      </sect3>
+
+      <sect3>
+        <title>Entity security with a Managed Hibernate Session</title>
+
+        <para>
+          If you are using a Hibernate <literal>SessionFactory</literal> configured via Seam,
+          and are using annotations, or <literal>orm.xml</literal>, then you don't
+          need to do anything special to use entity security.
+        </para>
+
+      </sect3>
+
+    </sect2>
+    
+    <sect2>
+      <title>Typesafe Permission Annotations</title>
+      
+      <para>
+        Seam provides a number of annotations that may be used as an alternative to <literal>@Restrict</literal>, which have
+        the added advantage of providing compile-time safety as they don't support arbitrary EL expressions in the same way 
+        that <literal>@Restrict</literal> does.
+      </para>
+      
+      <para>
+        Out of the box, Seam comes with annotations for standard CRUD-based permissions, however it is a simple matter to 
+        add your own.  The following annotations are provided in the <literal>org.jboss.seam.annotations.security</literal> package:
+      </para>
+      
+      <itemizedlist>
+        <listitem>
+          <para>@Insert</para>
+        </listitem>
+        <listitem>
+          <para>@Read</para>
+        </listitem>
+        <listitem>
+          <para>@Update</para>
+        </listitem>
+        <listitem>
+          <para>@Delete</para>
+        </listitem>
+      </itemizedlist>
+      
+      <para>
+        To use these annotations, simply place them on the method or parameter for which you wish to perform a security check.
+        If placed on a method, then they should specify a target class for which the permission will be checked.  Take the
+        following example:
+      </para>
+      
+      <programlisting><![CDATA[  @Insert(Customer.class)
+  public void createCustomer() {
+    ...
+  }]]></programlisting>
+  
+      <para>
+        In this example, a permission check will be performed for the user to ensure that they have the rights to create
+        new <literal>Customer</literal> objects.  The target of the permission check will be <literal>Customer.class</literal>
+        (the actual <literal>java.lang.Class</literal> instance itself), and the action is the lower case representation of the 
+        annotation name, which in this example is <literal>insert</literal>.
+      </para>
+      
+      <para>
+        It is also possible to annotate the parameters of a component method in the same way.  If this is done, then it is
+        not required to specify a permission target (as the parameter value itself will be the target of the permission check):
+      </para>
+      
+      <programlisting><![CDATA[  public void updateCustomer(@Update Customer customer) {
+    ...
+  }]]></programlisting>
+  
+      <para>
+        To create your own security annotation, you simply need to annotate it with <literal>@PermissionCheck</literal>, for example:
+      </para>
+      
+      <programlisting role="JAVA"><![CDATA[@Target({METHOD, PARAMETER})
+ at Documented
+ at Retention(RUNTIME)
+ at Inherited
+ at PermissionCheck
+public @interface Promote {
+   Class value() default void.class;
+}]]></programlisting>
+
+      <para>
+        If you wish to override the default permisison action name (which is the lower case version of the annotation name) with
+        another value, you can specify it within the <literal>@PermissionCheck</literal> annotation:
+      </para>
+      
+      <programlisting><![CDATA[@PermissionCheck("upgrade")]]></programlisting>
+      
+    </sect2>
+    
+    <sect2>
+      <title>Typesafe Role Annotations</title>    
+      
+      <para>
+        In addition to supporting typesafe permission annotation, Seam Security also provides typesafe role annotations that
+        allow you to restrict access to component methods based on the role memberships of the currently authenticated user.
+        Seam provides one such annotation out of the box, <literal>org.jboss.seam.annotations.security.Admin</literal>, used
+        to restrict access to a method to users that are a member of the <literal>admin</literal> role (so long as your 
+        own application supports such a role).  To create your own role annotations, simply meta-annotate them with
+        <literal>org.jboss.seam.annotations.security.RoleCheck</literal>, like in the following example:
+      </para>
+      
+      <programlisting><![CDATA[@Target({METHOD})
+ at Documented
+ at Retention(RUNTIME)
+ at Inherited
+ at RoleCheck
+public @interface User { 
+}]]></programlisting>
+
+      <para>
+        Any methods subsequently annotated with the <literal>@User</literal> annotation as shown in the above example
+        will be automatically intercepted and the user checked for the membership of the corresponding role name
+        (which is the lower case version of the annotation name, in this case <literal>user</literal>).
+      </para>
+      
+    </sect2>
+    
+    <sect2>
+      <title>The Permission Authorization Model</title>
+    
+      <para>
+        Seam Security provides an extensible framework for resolving application permissions.  The following class diagram
+        shows an overview of the main components of the permission framework:
+      </para>
+
+      <mediaobject>
+        <imageobject role="fo">
+          <imagedata fileref="images/security-permission-classdiagram.png" align="center"/>
+        </imageobject>
+        <imageobject role="html">
+          <imagedata fileref="images/security-permission-classdiagram.png" align="center"/>
+        </imageobject>
+      </mediaobject>     
+      
+      <para>
+        The relevant classes are explained in more detail in the following sections.
+      </para>
+      
+      <sect3>
+        <title>PermissionResolver</title>
+        
+        <para>
+          This is actually an interface, which provides methods for resolving individual object permissions.  Seam provides
+          the following built-in <literal>PermissionResolver</literal> implementations, which are described in more detail later
+          in the chapter:
+        </para>
+        
+        <itemizedlist>
+          <listitem>
+            <para><literal>RuleBasedPermissionResolver</literal> - This permission resolver uses Drools to resolve rule-based
+            permission checks.</para>
+          </listitem>
+          <listitem>
+            <para><literal>PersistentPermissionResolver</literal> - This permission resolver stores object permissions in a
+            persistent store, such as a relational database.</para>
+          </listitem>
+        </itemizedlist>
+        
+        <sect4>
+          <title>Writing your own PermissionResolver</title>
+
+          <para>
+            It is very simple to implement your own permission resolver.  The <literal>PermissionResolver</literal>
+            interface defines only two methods that must be implemented, as shown by the following table.  By deploying
+            your own <literal>PermissionResolver</literal> implementation in your Seam project, it will be automatically
+            scanned during deployment and registered with the default <literal>ResolverChain</literal>.
+          </para>          
+          
+          <table>
+            <title>PermissionResolver interface</title>
+      
+            <tgroup cols="2">
+              <colspec colnum="1" colwidth="2*" />
+              <colspec colnum="2" colwidth="3*" />
+              <colspec colnum="3" colwidth="3*" />
+              <colspec colnum="4" colwidth="4*" />
+      
+              <thead>
+                <row>
+                  <entry align="center">
+                    <para>Return type</para>
+                  </entry>
+                  <entry align="center">
+                    <para>Method</para>
+                  </entry>
+                  <entry align="center">
+                    <para>Description</para>
+                  </entry>
+                </row>
+              </thead>
+      
+              <tbody>
+      
+                <row>
+                  <entry>
+                    <para>
+                      <literal>boolean</literal>
+                    </para>
+                  </entry>
+                  <entry>
+                    <para>
+                      <literal>hasPermission(Object target, String action)</literal>
+                    </para>
+                  </entry>
+                  <entry>
+                    <para>
+                      This method must resolve whether the currently authenticated user (obtained via a call to
+                      <literal>Identity.getPrincipal()</literal>) has the permission specified by the <literal>target</literal>
+                      and <literal>action</literal> parameters.  It should return <literal>true</literal> if the user has
+                      the permission, or <literal>false</literal> if they don't.
+                    </para>
+                  </entry>
+                </row>   
+
+                <row>
+                  <entry>
+                    <para>
+                      <literal>void</literal>
+                    </para>
+                  </entry>
+                  <entry>
+                    <para>
+                      <literal>filterSetByAction(Set&lt;Object&gt; targets, String action)</literal>
+                    </para>
+                  </entry>
+                  <entry>
+                    <para>
+                      This method should remove any objects from the specified set, that would 
+                      return <literal>true</literal> if passed to the <literal>hasPermission()</literal> method with the 
+                      same <literal>action</literal> parameter value.
+                    </para>
+                  </entry>
+                </row>                 
+                
+              </tbody>
+            </tgroup>
+          </table>       
+          
+          <note>
+            <para>
+              As they are cached in the user's session, any custom <literal>PermissionResolver</literal> 
+              implementations must adhere to a couple of restrictions.  Firstly, they may not contain any 
+              state that is finer-grained than session scope (and the scope of the component itself should
+              either be application or session).  Secondly, they must not use dependency 
+              injection as they may be accessed from multiple threads simultaneously.  In fact, for
+              performance reasons it is recommended that they are annotated with 
+              <literal>@BypassInterceptors</literal> to bypass Seam's interceptor stack altogether.
+            </para>
+          </note>
+          
+        </sect4>
+      </sect3>
+      
+      <sect3>
+        <title>ResolverChain</title>
+        
+        <para>
+          A <literal>ResolverChain</literal> contains an ordered list of <literal>PermissionResolver</literal>s, for the
+          purpose of resolving object permissions for a particular object class or permission target.
+        </para>
+        
+        <para>
+          The default <literal>ResolverChain</literal> consists of all permission resolvers discovered during
+          application deployment.  The <literal>org.jboss.seam.security.defaultResolverChainCreated</literal>
+          event is raised (and the <literal>ResolverChain</literal> instance passed as an event parameter) 
+          when the default <literal>ResolverChain</literal> is created.  This allows additional resolvers that
+          for some reason were not discovered during deployment to be added, or for resolvers that are in the 
+          chain to be re-ordered or removed.
+        </para>
+      
+        <para>
+          The following sequence diagram shows the interaction between the components of the permission framework during a
+          permission check (explanation follows).  A permission check can originate from a number of possible sources,
+          for example - the security interceptor, the <literal>s:hasPermission</literal> EL function, or via an API
+          call to <literal>Identity.checkPermission</literal>:
+        </para>
+        
+        <mediaobject>
+          <imageobject role="fo">
+            <imagedata fileref="images/security-permission-sequence.png" align="center"/>
+          </imageobject>
+          <imageobject role="html">
+            <imagedata fileref="images/security-permission-sequence.png" align="center"/>
+          </imageobject>
+        </mediaobject>         
+      
+        <itemizedlist>
+          <listitem>
+            <para>
+              1. A permission check is initiated somewhere (either in code or via an EL
+              expression) resulting in a call to <literal>Identity.hasPermission()</literal>.
+            </para>          
+          </listitem>
+          <listitem>
+            <para>
+              1.1. <literal>Identity</literal> invokes 
+              <literal>PermissionMapper.resolvePermission()</literal>, passing in the
+              permission to be resolved.
+            </para>
+          </listitem>
+          <listitem>
+            <para>
+              1.1.1. <literal>PermissionMapper</literal> maintains a <literal>Map</literal> of 
+              <literal>ResolverChain</literal> instances, keyed by class.  It uses this map
+              to locate the correct <literal>ResolverChain</literal> for the permission's
+              target object.  Once it has the correct <literal>ResolverChain</literal>, it
+              retrieves the list of <literal>PermissionResolver</literal>s it contains via
+              a call to <literal>ResolverChain.getResolvers()</literal>.
+            </para>
+          </listitem>
+          <listitem>
+            <para>
+              1.1.2. For each <literal>PermissionResolver</literal> in the <literal>ResolverChain</literal>,
+              the <literal>PermissionMapper</literal> invokes its <literal>hasPermission()</literal> method,
+              passing in the permission instance to be checked.  If any of the <literal>PermissionResolver</literal>s
+              return <literal>true</literal>, then the permission check has succeeded and the 
+              <literal>PermissionMapper</literal> also returns <literal>true</literal> to <literal>Identity</literal>.
+              If none of the <literal>PermissionResolver</literal>s return true, then the permission check
+              has failed.
+            </para>
+          </listitem>      
+        </itemizedlist>
+      </sect3>
+      
+    </sect2>
+
+    <sect2>
+      <title>RuleBasedPermissionResolver</title>
+      
+      <para>
+        One of the built-in permission resolvers provided by Seam, <literal>RuleBasedPermissionResolver</literal> 
+        allows permissions to be evaluated based on a set of Drools (JBoss Rules) security rules.  A couple of the 
+        advantages of using a rule engine are 1) a centralized location for the business logic that is used to
+        evaluate user permissions, and 2) speed - Drools uses very efficient algorithms for evaluating large 
+        numbers of complex rules involving multiple conditions.        
+      </para>
+      
+      <sect3>
+        <title>Requirements</title>
+    
+        <para>
+          If using the rule-based permission features provided by Seam Security, the following jar files are required by Drools
+          to be distributed with your project:
+        </para>
+    
+        <itemizedlist>
+          <listitem>
+            <para>drools-api.jar</para>
+          </listitem>
+          <listitem>
+            <para>drools-compiler.jar</para>
+          </listitem>
+          <listitem>
+            <para>drools-core.jar</para>
+          </listitem>
+          <listitem>
+            <para>drools-decisiontables.jar</para>
+          </listitem>
+          <listitem>
+            <para>drools-templates.jar</para>
+          </listitem>
+          <listitem>
+            <para>janino.jar</para>
+          </listitem>
+          <listitem>
+            <para>antlr-runtime.jar</para>
+          </listitem>
+          <listitem>
+            <para>mvel2.jar</para>
+          </listitem>
+        </itemizedlist>
+    
+      </sect3>       
+      
+      <sect3>
+        <title>Configuration</title>
+        
+        <para>
+          The configuration for <literal>RuleBasedPermissionResolver</literal> requires that a Drools rule base is first
+          configured in <literal>components.xml</literal>.  By default, it expects that the rule base is named
+          <literal>securityRules</literal>, as per the following example:       
+        </para>
+        
+        <programlisting role="XML"><![CDATA[<components xmlns="http://jboss.com/products/seam/components"
+              xmlns:core="http://jboss.com/products/seam/core"
+              xmlns:security="http://jboss.com/products/seam/security"
+              xmlns:drools="http://jboss.com/products/seam/drools"
+              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+              xsi:schemaLocation=
+                  "http://jboss.com/products/seam/core http://jboss.com/products/seam/core-2.2.xsd
+                   http://jboss.com/products/seam/components http://jboss.com/products/seam/components-2.2.xsd
+                   http://jboss.com/products/seam/drools http://jboss.com/products/seam/drools-2.2.xsd
+                   http://jboss.com/products/seam/security http://jboss.com/products/seam/security-2.2.xsd">
+  
+     <drools:rule-base name="securityRules">
+         <drools:rule-files>
+             <value>/META-INF/security.drl</value>
+         </drools:rule-files>
+     </drools:rule-base>
+  
+  </components>]]></programlisting>
+  
+        <para>
+          The default rule base name can be overridden by specifying the <literal>security-rules</literal> 
+          property for <literal>RuleBasedPermissionResolver</literal>:
+        </para>
+        
+        <programlisting><![CDATA[
+  <security:rule-based-permission-resolver security-rules="#{prodSecurityRules}"/>]]></programlisting>
+
+        <para>
+          Once the <literal>RuleBase</literal> component is configured, it's time to write the security rules.
+        </para>                
+      </sect3>
+      
+      <sect3>
+        <title>Writing Security Rules</title>
+        
+        <para>
+          The first step to writing security rules is to create a new rule file in the <literal>/META-INF</literal>
+          directory of your application's jar file.  Usually this file would be named something like 
+          <literal>security.drl</literal>, however you can name it whatever you like as long as it is configured
+          correspondingly in <literal>components.xml</literal>.
+        </para>
+        
+        <para>
+          So what should the security rules file contain?  At this stage it might be a good idea to at least skim
+          through the Drools documentation, however to get started here's an extremely simple example:
+        </para>
+  
+        <programlisting><![CDATA[package MyApplicationPermissions;
+  
+  import org.jboss.seam.security.permission.PermissionCheck;
+  import org.jboss.seam.security.Role;
+  
+  rule CanUserDeleteCustomers
+  when
+    c: PermissionCheck(target == "customer", action == "delete")
+    Role(name == "admin")
+  then
+    c.grant();
+  end]]></programlisting>
+  
+        <para>
+          Let's break this down step by step.  The first thing we see is the package declaration.  A package in Drools
+          is essentially a collection of rules.  The package name can be anything you want - it doesn't relate
+          to anything else outside the scope of the rule base.
+        </para>
+  
+        <para>
+          The next thing we can notice is a couple of import statements for the <literal>PermissionCheck</literal>
+          and <literal>Role</literal> classes. These imports inform the rules engine that we'll be referencing
+          these classes within our rules.
+        </para>
+  
+        <para>
+          Finally we have the code for the rule.  Each rule within a package should be given a unique name (usually
+          describing the purpose of the rule).  In this case our rule is called <literal>CanUserDeleteCustomers</literal>
+          and will be used to check whether a user is allowed to delete a customer record.
+        </para>
+  
+        <para>
+          Looking at the body of the rule definition we can notice two distinct sections.  Rules have what is known
+          as a left hand side (LHS) and a right hand side (RHS).  The LHS consists of the conditional part of the
+          rule, i.e. a list of conditions which must be satisfied for the rule to fire.  The LHS is represented by
+          the <literal>when</literal> section.  The RHS is the consequence, or action section of the rule that will
+          only be fired if all of the conditions in the LHS are met.  The RHS is represented by the
+          <literal>then</literal> section.  The end of the rule is denoted by the <literal>end</literal> line.
+        </para>
+  
+        <para>
+          If we look at the LHS of the rule, we see two conditions listed there.  Let's examine the first condition:
+        </para>
+  
+        <programlisting><![CDATA[c: PermissionCheck(target == "customer", action == "delete")]]></programlisting>
+  
+        <para>
+          In plain english, this condition is stating that there must exist a <literal>PermissionCheck</literal> object
+          with a <literal>target</literal> property equal to "customer", and an <literal>action</literal> property equal
+          to "delete" within the working memory.
+        </para>
+               
+        <para>
+          So what is the working memory? Also known as a "stateful session" in Drools terminology, the working memory 
+          is a session-scoped object that contains the contextual information that is required by the rules engine to 
+          make a decision about a permission check. Each time the <literal>hasPermission()</literal> method is called, 
+          a temporary <literal>PermissionCheck</literal> object, or <emphasis>Fact</emphasis>, is inserted into the 
+          working memory.  This <literal>PermissionCheck</literal> corresponds exactly to the permission that is being 
+          checked, so for example if you call <literal>hasPermission("account", "create")</literal> then a 
+          <literal>PermissionCheck</literal> object with a <literal>target</literal> equal to "account" and 
+          <literal>action</literal> equal to "create" will be inserted into the working memory for the duration of the 
+          permission check.
+        </para>
+        
+        <para>
+          Besides the <literal>PermissionCheck</literal> facts, there is also a <literal>org.jboss.seam.security.Role</literal>
+          fact for each of the roles that the authenticated user is a member of.  These <literal>Role</literal> facts 
+          are synchronized with the user's authenticated roles at the beginning of every permission check.  As a consequence, 
+          any <literal>Role</literal> object that is inserted into the working memory during the course of a permission
+          check will be removed before the next permission check occurs, if the authenticated user is not actually a member of
+          that role.  Besides the <literal>PermissionCheck</literal> and <literal>Role</literal> facts, the working
+          memory also contains the <literal>java.security.Principal</literal> object that was created as a result of
+          the authentication process.  
+        </para>
+        
+        <para>
+          It is also possible to insert additional long-lived facts into the working  memory by calling 
+          <literal>RuleBasedPermissionResolver.instance().getSecurityContext().insert()</literal>,
+          passing the object as a parameter.  The exception to this is <literal>Role</literal> objects, which as
+          already discussed are synchronized at the start of each permission check.
+        </para>
+  
+        <para>
+          Getting back to our simple example, we can also notice that the first line of our LHS is prefixed with
+          <literal>c:</literal>.  This is a variable binding, and is used to refer back to the object that is
+          matched by the condition (in this case, the <literal>PermissionCheck</literal>).  Moving on to the 
+          second line of our LHS, we see this:
+        </para>
+  
+        <programlisting><![CDATA[Role(name == "admin")]]></programlisting>
+  
+        <para>
+          This condition simply states that there must be a <literal>Role</literal> object with a 
+          <literal>name</literal> of "admin" within the working memory.  As already mentioned, user roles are inserted into 
+          the working memory at the beginning of each permission check.  So, putting both conditions together, this 
+          rule is essentially saying "I will fire if you are checking for the <literal>customer:delete</literal> 
+          permission and the user is a member of the <literal>admin</literal> role".
+        </para>
+  
+        <para>
+          So what is the consequence of the rule firing?  Let's take a look at the RHS of the rule:
+        </para>
+  
+        <programlisting><![CDATA[c.grant()]]></programlisting>
+  
+        <para>
+          The RHS consists of Java code, and in this case is invoking the <literal>grant()</literal>
+          method of the <literal>c</literal> object, which as already mentioned is a variable binding
+          for the <literal>PermissionCheck</literal> object.  Besides the <literal>name</literal> and
+          <literal>action</literal> properties of the <literal>PermissionCheck</literal> object, there
+          is also a <literal>granted</literal> property which is initially set to <literal>false</literal>.
+          Calling <literal>grant()</literal> on a <literal>PermissionCheck</literal> sets the
+          <literal>granted</literal> property to <literal>true</literal>, which means that the permission
+          check was successful, allowing the user to carry out whatever action the permission check was
+          intended for.
+        </para>
+      </sect3>
+      
+      <sect3>
+        <title>Non-String permission targets</title>
+        
+        <para>
+          So far we have only seen permission checks for String-literal permission targets.  It is of course also
+          possible to write security rules for permission targets of more complex types.  For example, let's say that you wish
+          to write a security rule to allow your users to create blog comments.  The following rule demonstrates
+          how this may be expressed, by requiring the target of the permission check to be an instance of
+          <literal>MemberBlog</literal>, and also requiring that the currently authenticated user is a member of the
+          <literal>user</literal> role:
+        </para>
+        
+        <programlisting><![CDATA[rule CanCreateBlogComment
+  no-loop
+  activation-group "permissions"
+when
+  blog: MemberBlog()
+  check: PermissionCheck(target == blog, action == "create", granted == false)
+  Role(name == "user")
+then
+  check.grant();
+end
+]]></programlisting>        
+      
+      </sect3>
+
+      <sect3>
+        <title>Wildcard permission checks</title>
+
+        <para>
+          It is possible to implement a wildcard permission check (which allows all actions for a given permission
+          target), by omitting the <literal>action</literal> constraint for the <literal>PermissionCheck</literal> in
+          your rule, like this:
+        </para>
+
+        <programlisting><![CDATA[rule CanDoAnythingToCustomersIfYouAreAnAdmin
+when
+  c: PermissionCheck(target == "customer")
+  Role(name == "admin")
+then
+  c.grant();
+end;
+        ]]></programlisting>
+
+        <para>
+          This rule allows users with the <literal>admin</literal> role to perform <emphasis>any</emphasis> action for
+          any <literal>customer</literal> permission check.
+        </para>        
+        
+      </sect3>
+      
+    </sect2>
+    
+    <sect2>
+      <title>PersistentPermissionResolver</title>
+      
+      <para>
+        Another built-in permission resolver provided by Seam, <literal>PersistentPermissionResolver</literal>
+        allows permissions to be loaded from persistent storage, such as a relational database.  This permission 
+        resolver provides ACL style instance-based security, allowing for specific object permissions to be assigned
+        to individual users and roles.  It also allows for persistent, arbitrarily-named permission targets (not 
+        necessarily object/class based) to be assigned in the same way.
+      </para>
+      
+      <sect3>
+        <title>Configuration</title>
+
+        <para>
+          Before it can be used, <literal>PersistentPermissionResolver</literal> must be configured with a
+          valid <literal>PermissionStore</literal> in <literal>components.xml</literal>.  If not configured,
+          it will attempt to use the default permission store, <literal>JpaIdentityStore</literal> (see section
+          further down for details).  To use a permission store other than the default, configure the
+          <literal>permission-store</literal> property as follows:
+        </para>        
+        
+        <programlisting><![CDATA[  <security:persistent-permission-resolver permission-store="#{myCustomPermissionStore}"/>]]></programlisting>
+        
+      </sect3>
+      
+      <sect3>
+        <title>Permission Stores</title>
+        
+        <para>
+          A permission store is required for <literal>PersistentPermissionResolver</literal> to connect to the
+          backend storage where permissions are persisted.  Seam provides one <literal>PermissionStore</literal>
+          implementation out of the box, <literal>JpaPermissionStore</literal>, which is used to store
+          permissions inside a relational database.  It is possible to write your own permission store
+          by implementing the <literal>PermissionStore</literal> interface, which defines the following
+          methods:
+        </para>
+        
+        <table>
+          <title>PermissionStore interface</title>
+    
+          <tgroup cols="2">
+            <colspec colnum="1" colwidth="2*" />
+            <colspec colnum="2" colwidth="3*" />
+            <colspec colnum="3" colwidth="3*" />
+    
+            <thead>
+              <row>
+                <entry align="center">
+                  <para>Return type</para>
+                </entry>
+                <entry align="center">
+                  <para>Method</para>
+                </entry>
+                <entry align="center">
+                  <para>Description</para>
+                </entry>
+              </row>
+            </thead>
+    
+            <tbody>
+    
+              <row>
+                <entry>
+                  <para>
+                    <literal>List&lt;Permission&gt;</literal>
+                  </para>
+                </entry>
+                <entry>
+                  <para>
+                    <literal>listPermissions(Object target)</literal>
+                  </para>
+                </entry>
+                <entry>
+                  <para>
+                    This method should return a <literal>List</literal> of <literal>Permission</literal> objects 
+                    representing all the permissions granted for the specified target object.
+                  </para>
+                </entry>
+              </row>         
+
+              <row>
+                <entry>
+                  <para>
+                    <literal>List&lt;Permission&gt;</literal>
+                  </para>
+                </entry>
+                <entry>
+                  <para>
+                    <literal>listPermissions(Object target, String action)</literal>
+                  </para>
+                </entry>
+                <entry>
+                  <para>
+                    This method should return a <literal>List</literal> of <literal>Permission</literal> objects 
+                    representing all the permissions with the specified action, granted for the specified target object.
+                  </para>
+                </entry>
+              </row>         
+              
+              <row>
+                <entry>
+                  <para>
+                    <literal>List&lt;Permission&gt;</literal>
+                  </para>
+                </entry>
+                <entry>
+                  <para>
+                    <literal>listPermissions(Set&lt;Object&gt; targets, String action)</literal>
+                  </para>
+                </entry>
+                <entry>
+                  <para>
+                    This method should return a <literal>List</literal> of <literal>Permission</literal> objects 
+                    representing all the permissions with the specified action, granted for the specified set of
+                    target objects.
+                  </para>
+                </entry>
+              </row>         
+        
+              <row>
+                <entry>
+                  <para>
+                    <literal>boolean</literal>
+                  </para>
+                </entry>
+                <entry>
+                  <para>
+                    <literal>grantPermission(Permission)</literal>
+                  </para>
+                </entry>
+                <entry>
+                  <para>
+                    This method should persist the specified <literal>Permission</literal> object to the backend
+                    storage, returning true if successful.
+                  </para>
+                </entry>
+              </row>  
+              
+              <row>
+                <entry>
+                  <para>
+                    <literal>boolean</literal>
+                  </para>
+                </entry>
+                <entry>
+                  <para>
+                    <literal>grantPermissions(List&lt;Permission&gt; permissions)</literal>
+                  </para>
+                </entry>
+                <entry>
+                  <para>
+                    This method should persist all of the <literal>Permission</literal> objects contained in the
+                    specified <literal>List</literal>, returning true if successful.
+                  </para>
+                </entry>
+              </row>  
+              
+              <row>
+                <entry>
+                  <para>
+                    <literal>boolean</literal>
+                  </para>
+                </entry>
+                <entry>
+                  <para>
+                    <literal>revokePermission(Permission permission)</literal>
+                  </para>
+                </entry>
+                <entry>
+                  <para>
+                    This method should remove the specified <literal>Permission</literal> object from persistent storage.
+                  </para>
+                </entry>
+              </row>  
+              
+              <row>
+                <entry>
+                  <para>
+                    <literal>boolean</literal>
+                  </para>
+                </entry>
+                <entry>
+                  <para>
+                    <literal>revokePermissions(List&lt;Permission&gt; permissions)</literal>
+                  </para>
+                </entry>
+                <entry>
+                  <para>
+                    This method should remove all of the <literal>Permission</literal> objects in the specified list
+                    from persistent storage.
+                  </para>
+                </entry>
+              </row> 
+              
+              <row>
+                <entry>
+                  <para>
+                    <literal>List&lt;String&gt;</literal>
+                  </para>
+                </entry>
+                <entry>
+                  <para>
+                    <literal>listAvailableActions(Object target)</literal>
+                  </para>
+                </entry>
+                <entry>
+                  <para>
+                    This method should return a list of all the available actions (as Strings) for the class of the 
+                    specified target object.  It is used in conjunction with permission management to build the user
+                    interface for granting specific class permissions (see section further down).
+                  </para>
+                </entry>
+              </row> 
+            </tbody>
+          </tgroup>
+        </table>
+      
+      </sect3>
+           
+      <sect3>
+        <title>JpaPermissionStore</title>
+        
+        <para>
+          This is the default <literal>PermissionStore</literal> implementation (and the only one provided by Seam), which 
+          uses a relational database to store permissions.  Before it can be used it must be configured with either one or 
+          two entity classes for storing user and role permissions.  These entity classes must be annotated with a special 
+          set of security annotations to configure which properties of the entity correspond to various aspects of the 
+          permissions being stored.
+        </para>
+        
+        <para>
+          If you wish to use the same entity (i.e. a single database table) to store both user and role permissions, then
+          only the <literal>user-permission-class</literal> property is required to be configured.  If you wish to use
+          separate tables for storing user and role permissions, then in addition to the <literal>user-permission-class</literal>
+          property you must also configure the <literal>role-permission-class</literal> property.
+        </para>
+        
+        <para>For example, to configure a single entity class to store both user and role permissions:</para>
+        
+        <programlisting role="XML"><![CDATA[<security:jpa-permission-store user-permission-class="com.acme.model.AccountPermission"/>]]></programlisting>
+        
+        <para>To configure separate entity classes for storing user and role permissions:</para>
+        
+        <programlisting role="XML"><![CDATA[<security:jpa-permission-store user-permission-class="com.acme.model.UserPermission"
+    role-permission-class="com.acme.model.RolePermission"/>]]></programlisting>        
+        
+        <sect4>
+          <title>Permission annotations</title>
+          
+          <para>
+            As mentioned, the entity classes that contain the user and role permissions must be configured with a
+            special set of annotations, contained within the <literal>org.jboss.seam.annotations.security.permission</literal> package.
+            The following table lists each of these annotations along with a description of how they are used:
+          </para>
+          
+          <table>
+            <title>Entity Permission annotations</title>
+      
+            <tgroup cols="2">
+              <colspec colnum="1" colwidth="2*" />
+              <colspec colnum="2" colwidth="3*" />
+              <colspec colnum="3" colwidth="3*" />
+      
+              <thead>
+                <row>
+                  <entry align="center">
+                    <para>Annotation</para>
+                  </entry>
+                  <entry align="center">
+                    <para>Target</para>
+                  </entry>
+                  <entry align="center">
+                    <para>Description</para>
+                  </entry>
+                </row>
+              </thead>
+      
+              <tbody>
+      
+                <row>
+                  <entry>
+                    <para>
+                      <literal>@PermissionTarget</literal>
+                    </para>
+                  </entry>
+                  <entry>
+                    <para>
+                      <literal>FIELD,METHOD</literal>
+                    </para>
+                  </entry>
+                  <entry>
+                    <para>
+                      This annotation identifies the property of the entity that will contain the permission target.  The property
+                      should be of type <literal>java.lang.String</literal>.
+                    </para>
+                  </entry>
+                </row>   
+                
+                <row>
+                  <entry>
+                    <para>
+                      <literal>@PermissionAction</literal>
+                    </para>
+                  </entry>
+                  <entry>
+                    <para>
+                      <literal>FIELD,METHOD</literal>
+                    </para>
+                  </entry>
+                  <entry>
+                    <para>
+                      This annotation identifies the property of the entity that will contain the permission action.  The property
+                      should be of type <literal>java.lang.String</literal>.
+                    </para>
+                  </entry>
+                </row>           
+                
+                <row>
+                  <entry>
+                    <para>
+                      <literal>@PermissionUser</literal>
+                    </para>
+                  </entry>
+                  <entry>
+                    <para>
+                      <literal>FIELD,METHOD</literal>
+                    </para>
+                  </entry>
+                  <entry>
+                    <para>
+                      This annotation identifies the property of the entity that will contain the recipient user for the permission. It should
+                      be of type <literal>java.lang.String</literal> and contain the user's username.
+                    </para>
+                  </entry>
+                </row>  
+                
+                <row>
+                  <entry>
+                    <para>
+                      <literal>@PermissionRole</literal>
+                    </para>
+                  </entry>
+                  <entry>
+                    <para>
+                      <literal>FIELD,METHOD</literal>
+                    </para>
+                  </entry>
+                  <entry>
+                    <para>
+                      This annotation identifies the property of the entity that will contain the recipient role for the permission. It should
+                      be of type <literal>java.lang.String</literal> and contain the role name.
+                    </para>
+                  </entry>
+                </row>  
+                
+                <row>
+                  <entry>
+                    <para>
+                      <literal>@PermissionDiscriminator</literal>
+                    </para>
+                  </entry>
+                  <entry>
+                    <para>
+                      <literal>FIELD,METHOD</literal>
+                    </para>
+                  </entry>
+                  <entry>
+                    <para>
+                      This annotation should be used when the same entity/table is used to store both user and role permissions.  It identifies
+                      the property of the entity that is used to discriminate between user and role permissions.  By default, if the column
+                      value contains the string literal <literal>user</literal>, then the record will be treated as a user permission.  If it
+                      contains the string literal <literal>role</literal>, then it will be treated as a role permission.  It is also possible
+                      to override these defaults by specifying the <literal>userValue</literal> and <literal>roleValue</literal> properties
+                      within the annotation.  For example, to use <literal>u</literal> and <literal>r</literal> instead of <literal>user</literal>
+                      and <literal>role</literal>, the annotation would be written like this:
+                    </para>
+                    
+                    <programlisting role="JAVA"><![CDATA[@PermissionDiscriminator(userValue = "u", roleValue = "r")]]></programlisting>
+                  </entry>
+                </row>                
+                
+              </tbody>
+            </tgroup>
+          </table>          
+          
+        </sect4>
+        
+        <sect4>
+          <title>Example Entity</title>
+          
+          <para>
+            Here is an example of an entity class that is used to store both user and role permissions.  The following class can be found
+            inside the SeamSpace example:
+          </para>
+          
+          <programlisting role="JAVA"><![CDATA[
+ at Entity
+public class AccountPermission implements Serializable {  
+   private Integer permissionId;
+   private String recipient;
+   private String target;
+   private String action;
+   private String discriminator;
+   
+   @Id @GeneratedValue
+   public Integer getPermissionId() {
+      return permissionId;
+   }
+   
+   public void setPermissionId(Integer permissionId) {
+      this.permissionId = permissionId;
+   }
+   
+   @PermissionUser @PermissionRole
+   public String getRecipient() {
+      return recipient;
+   }
+   
+   public void setRecipient(String recipient) {
+      this.recipient = recipient;
+   }
+   
+   @PermissionTarget
+   public String getTarget() {
+      return target;
+   }
+   
+   public void setTarget(String target) {
+      this.target = target;
+   }
+   
+   @PermissionAction
+   public String getAction() {
+      return action;
+   }
+   
+   public void setAction(String action) {
+      this.action = action;
+   }
+   
+   @PermissionDiscriminator
+   public String getDiscriminator() {
+      return discriminator;
+   }
+   
+   public void setDiscriminator(String discriminator) {
+      this.discriminator = discriminator;
+   }
+}          
+          ]]></programlisting>
+          
+          <para>
+            As can be seen in the above example, the <literal>getDiscriminator()</literal> method has been annotated
+            with the <literal>@PermissionDiscriminator</literal> annotation, to allow <literal>JpaPermissionStore</literal> to
+            determine which records represent user permissions and which represent role permissions.  In addition, it
+            can also be seen that the <literal>getRecipient()</literal> method is annotated with both 
+            <literal>@PermissionUser</literal> and <literal>@PermissionRole</literal> annotations.  This is perfectly valid,
+            and simply means that the <literal>recipient</literal> property of the entity will either contain the name
+            of the user or the name of the role, depending on the value of the <literal>discriminator</literal> property.
+          </para>
+          
+        </sect4>
+        
+        <sect4>
+          <title>Class-specific Permission Configuration</title>
+        
+          <para>
+            A further set of class-specific annotations can be used to configure a specific set of allowable permissions
+            for a target class.  These permissions can be found in the <literal>org.jboss.seam.annotation.security.permission</literal>
+            package:
+          </para>
+          
+          <table>
+            <title>Class Permission Annotations</title>
+      
+            <tgroup cols="2">
+              <colspec colnum="1" colwidth="2*" />
+              <colspec colnum="2" colwidth="3*" />
+              <colspec colnum="3" colwidth="3*" />
+      
+              <thead>
+                <row>
+                  <entry align="center">
+                    <para>Annotation</para>
+                  </entry>
+                  <entry align="center">
+                    <para>Target</para>
+                  </entry>
+                  <entry align="center">
+                    <para>Description</para>
+                  </entry>
+                </row>
+              </thead>
+      
+              <tbody>
+      
+                <row>
+                  <entry>
+                    <para>
+                      <literal>@Permissions</literal>
+                    </para>
+                  </entry>
+                  <entry>
+                    <para>
+                      <literal>TYPE</literal>
+                    </para>
+                  </entry>
+                  <entry>
+                    <para>
+                      A container annotation, this annotation may contain an array of <literal>@Permission</literal> annotations.
+                    </para>
+                  </entry>
+                </row>        
+                
+                <row>
+                  <entry>
+                    <para>
+                      <literal>@Permission</literal>
+                    </para>
+                  </entry>
+                  <entry>
+                    <para>
+                      <literal>TYPE</literal>
+                    </para>
+                  </entry>
+                  <entry>
+                    <para>
+                      This annotation defines a single allowable permission action for the target class.  Its <literal>action</literal>
+                      property must be specified, and an optional <literal>mask</literal> property may also be specified if permission
+                      actions are to be persisted as bitmasked values (see next section).
+                    </para>
+                  </entry>
+                </row>
+                
+              </tbody>
+            </tgroup>
+          </table>
+          
+          <para>
+            Here's an example of the above annotations in action.  The following class can also be found in the SeamSpace example:
+          </para>
+          
+          <programlisting role="JAVA"><![CDATA[@Permissions({
+   @Permission(action = "view"),
+   @Permission(action = "comment")
+})
+ at Entity
+public class MemberImage implements Serializable {]]></programlisting>
+
+          <para>
+            This example demonstrates how two allowable permission actions, <literal>view</literal> and <literal>comment</literal> 
+            can be declared for the entity class <literal>MemberImage</literal>.
+          </para>
+          
+        </sect4>
+        
+        <sect4>
+          <title>Permission masks</title>
+          
+          <para>
+            By default, multiple permissions for the same target object and recipient will be persisted as a single database record,
+            with the <literal>action</literal> property/column containing a comma-separated list of the granted actions.  To reduce
+            the amount of physical storage required to persist a large number of permissions, it is possible to use a bitmasked
+            integer value (instead of a comma-separated list) to store the list of permission actions.
+          </para>
+          
+          <para>
+            For example, if recipient "Bob" is granted both the <literal>view</literal> and <literal>comment</literal> permissions
+            for a particular <literal>MemberImage</literal> (an entity bean) instance, then by default the <literal>action</literal> property of the
+            permission entity will contain "<literal>view,comment</literal>", representing the two granted permission actions.  
+            Alternatively, if using bitmasked values for the permission actions, as defined like so:
+          </para>
+          
+          <programlisting role="JAVA"><![CDATA[@Permissions({
+   @Permission(action = "view", mask = 1),
+   @Permission(action = "comment", mask = 2)
+})
+ at Entity
+public class MemberImage implements Serializable {]]></programlisting>          
+
+          <para>
+            The <literal>action</literal> property will instead simply contain "3" (with both the 1 bit and 2 bit switched on).  Obviously
+            for a large number of allowable actions for any particular target class, the storage required for the permission records
+            is greatly reduced by using bitmasked actions.
+          </para>
+          
+          <para>
+            Obviously, it is very important that the <literal>mask</literal> values specified are powers of 2.
+          </para>
+        </sect4>
+        
+        <sect4>
+          <title>Identifier Policy</title>
+          
+          <para>
+            When storing or looking up permissions, <literal>JpaPermissionStore</literal> must be able to uniquely identify specific
+            object instances to effectively operate on its permissions.  To achieve this, an <emphasis>identifier strategy</emphasis> 
+            may be assigned to each target class for the generation of unique identifier values.  Each identifier strategy
+            implementation knows how to generate unique identifiers for a particular type of class, and it is a simple matter to 
+            create new identifier strategies.
+          </para>
+          
+          <para>
+            The <literal>IdentifierStrategy</literal> interface is very simple, declaring only two methods:
+          </para>
+          
+          <programlisting role="JAVA"><![CDATA[public interface IdentifierStrategy {
+   boolean canIdentify(Class targetClass);
+   String getIdentifier(Object target);
+}]]></programlisting>
+
+          <para>
+            The first method, <literal>canIdentify()</literal> simply returns <literal>true</literal> if the identifier strategy
+            is capable of generating a unique identifier for the specified target class.  The second method, 
+            <literal>getIdentifier()</literal> returns the unique identifier value for the specified target object.
+          </para>
+          
+          <para>
+            Seam provides two <literal>IdentifierStrategy</literal> implementations, <literal>ClassIdentifierStrategy</literal>
+            and <literal>EntityIdentifierStrategy</literal> (see next sections for details).
+          </para>
+          
+          <para>
+            To explicitly configure a specific identifier strategy to use for a particular class, it should be annotated with
+            <literal>org.jboss.seam.annotations.security.permission.Identifier</literal>, and the value should be set to
+            a concrete implementation of the <literal>IdentifierStrategy</literal> interface.  An optional <literal>name</literal>
+            property can also be specified, the effect of which is dependent upon the actual <literal>IdentifierStrategy</literal>
+            implementation used.
+          </para>
+        </sect4>
+        
+        <sect4>
+          <title>ClassIdentifierStrategy</title>
+          
+          <para>
+            This identifier strategy is used to generate unique identifiers for classes, and will use the value of the 
+            <literal>name</literal> (if specified) in the <literal>@Identifier</literal> annotation.  If there is no
+            <literal>name</literal> property provided, then it will attempt to use the component name of the class
+            (if the class is a Seam component), or as a last resort it will create an identifier based on the name
+            of the class (excluding the package name).  For example, the identifier for the following class will
+            be "<literal>customer</literal>":
+          </para>
+          
+          <programlisting role="JAVA"><![CDATA[@Identifier(name = "customer")
+public class Customer {]]></programlisting>
+          
+          <para>
+            The identifier for the following class will be "<literal>customerAction</literal>":
+          </para>
+          
+          <programlisting role="JAVA"><![CDATA[@Name("customerAction")
+public class CustomerAction { ]]></programlisting>
+          
+          <para>
+            Finally, the identifier for the following class will be "<literal>Customer</literal>":
+          </para>
+          
+          <programlisting><![CDATA[public class Customer { ]]></programlisting>
+          
+        </sect4>
+        
+        <sect4>
+          <title>EntityIdentifierStrategy</title>
+          
+          <para>
+            This identifier strategy is used to generate unique identifiers for entity beans.  It does so by
+            concatenating the entity name (or otherwise configured name) with a string representation of the
+            primary key value of the entity.  The rules for generating the name section of the identifier are 
+            similar to <literal>ClassIdentifierStrategy</literal>.  The primary key value (i.e. the 
+            <emphasis>id</emphasis> of the entity) is obtained using the <literal>PersistenceProvider</literal>
+            component, which is able to correctly determine the value regardless of which persistence implementation
+            is used within the Seam application.  For entities not annotated with <literal>@Entity</literal>, it is
+            necessary to explicitly configure the identifier strategy on the entity class itself, for example:
+          </para>
+          
+          <programlisting role="JAVA"><![CDATA[@Identifier(value = EntityIdentifierStrategy.class)
+public class Customer { ]]></programlisting>
+          
+          <para>
+            For an example of the type of identifier values generated, assume we have the following entity class:
+          </para>
+          
+          <programlisting role="JAVA"><![CDATA[@Entity
+public class Customer {
+  private Integer id;
+  private String firstName;
+  private String lastName;
+  
+  @Id 
+  public Integer getId() { return id; }
+  public void setId(Integer id) { this.id = id; }
+  
+  public String getFirstName() { return firstName; }
+  public void setFirstName(String firstName) { this.firstName = firstName; }
+  
+  public String getLastName() { return lastName; }
+  public void setLastName(String lastName) { this.lastName = lastName; }
+}]]></programlisting>
+
+          <para>
+            For a <literal>Customer</literal> instance with an <literal>id</literal> value of <literal>1</literal>,
+            the value of the identifier would be "<literal>Customer:1</literal>".  If the entity class is annotated
+            with an explicit identifier name, like so:
+          </para>
+          
+          <programlisting role="JAVA"><![CDATA[@Entity
+ at Identifier(name = "cust")
+public class Customer { ]]></programlisting>
+
+          <para>
+            Then a <literal>Customer</literal> with an <literal>id</literal> value of <literal>123</literal>
+            would have an identifier value of "<literal>cust:123</literal>".
+          </para>
+        </sect4>
+                
+      </sect3>     
+    
+    </sect2>
+
+  </sect1>
+  
+  <sect1>
+    <title>Permission Management</title>
+    
+    <para>
+      In much the same way that Seam Security provides an Identity Management API for the management of users and roles,
+      it also provides a Permissions Management API for the management of persistent user permissions, via the
+      <literal>PermissionManager</literal> component.
+    </para>
+    
+    <sect2>
+      <title>PermissionManager</title>
+      
+      <para>
+        The <literal>PermissionManager</literal> component is an application-scoped Seam component that provides a number of 
+        methods for managing permissions.  Before it can be used, it must be configured with a permission store (although by
+        default it will attempt to use <literal>JpaPermissionStore</literal> if it is available).  To explicitly configure a
+        custom permission store, specify the <literal>permission-store</literal> property in components.xml:
+      </para>
+      
+      <programlisting role="XML"><![CDATA[
+<security:permission-manager permission-store="#{ldapPermissionStore}"/>      
+      ]]></programlisting>
+      
+      <para>
+        The following table describes each of the available methods provided by <literal>PermissionManager</literal>: 
+      </para>
+      
+      <table>
+        <title>PermissionManager API methods</title>
+  
+        <tgroup cols="2">
+          <colspec colnum="1" colwidth="2*" />
+          <colspec colnum="2" colwidth="3*" />
+          <colspec colnum="3" colwidth="3*" />
+  
+          <thead>
+            <row>
+              <entry align="center">
+                <para>Return type</para>
+              </entry>
+              <entry align="center">
+                <para>Method</para>
+              </entry>
+              <entry align="center">
+                <para>Description</para>
+              </entry>
+            </row>
+          </thead>
+  
+          <tbody>
+  
+            <row>
+              <entry>
+                <para>
+                  <literal>List&lt;Permission&gt;</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>listPermissions(Object target, String action)</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  Returns a list of <literal>Permission</literal> objects representing all of the permissions that
+                  have been granted for the specified target and action.
+                </para>
+              </entry>
+            </row>        
+            
+            <row>
+              <entry>
+                <para>
+                  <literal>List&lt;Permission&gt;</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>listPermissions(Object target)</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  Returns a list of <literal>Permission</literal> objects representing all of the permissions that
+                  have been granted for the specified target and action.
+                </para>
+              </entry>
+            </row> 
+            
+            <row>
+              <entry>
+                <para>
+                  <literal>boolean</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>grantPermission(Permission permission)</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  Persists (grants) the specified <literal>Permission</literal> to the backend permission store.  
+                  Returns true if the operation was successful.
+                </para>
+              </entry>
+            </row> 
+            
+            <row>
+              <entry>
+                <para>
+                  <literal>boolean</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>grantPermissions(List&lt;Permission&gt; permissions)</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  Persists (grants) the specified list of <literal>Permission</literal>s to the backend permission store.  
+                  Returns true if the operation was successful.
+                </para>
+              </entry>
+            </row> 
+            
+            <row>
+              <entry>
+                <para>
+                  <literal>boolean</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>revokePermission(Permission permission)</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  Removes (revokes) the specified <literal>Permission</literal> from the backend permission store.  
+                  Returns true if the operation was successful.
+                </para>
+              </entry>
+            </row> 
+            
+            <row>
+              <entry>
+                <para>
+                  <literal>boolean</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>revokePermissions(List&lt;Permission&gt; permissions)</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  Removes (revokes) the specified list of <literal>Permission</literal>s from the backend permission store.  
+                  Returns true if the operation was successful.
+                </para>
+              </entry>
+            </row> 
+            
+            <row>
+              <entry>
+                <para>
+                  <literal>List&lt;String&gt;</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>listAvailableActions(Object target)</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  Returns a list of the available actions for the specified target object.  The actions that this
+                  method returns are dependent on the <literal>@Permission</literal> annotations configured on the 
+                  target object's class.
+                </para>
+              </entry>
+            </row>
+            
+          </tbody>
+        </tgroup>
+      </table>
+      
+    </sect2>
+    
+    <sect2>
+      <title>Permission checks for PermissionManager operations</title>
+      
+      <para>
+        Invoking the methods of <literal>PermissionManager</literal> requires that the currently-authenticated user
+        has the appropriate authorization to perform that management operation.  The following table lists the required
+        permissions that the current user must have.
+      </para>
+      
+      <table>
+        <title>Permission Management Security Permissions</title>
+
+        <tgroup cols="2">
+          <colspec colnum="1" colwidth="1*" />
+          <colspec colnum="2" colwidth="3*" />
+
+          <thead>
+            <row>
+              <entry align="center">
+                <para>Method</para>
+              </entry>
+              <entry align="center">
+                <para>Permission Target</para>
+              </entry>
+              <entry align="center">
+                <para>Permission Action</para>
+              </entry>
+            </row>
+          </thead>
+
+          <tbody>
+            <row>
+              <entry>
+                <para>
+                  <literal>listPermissions()</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  The specified <literal>target</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>seam.read-permissions</literal>
+                </para>
+              </entry>
+            </row>
+            
+            <row>
+              <entry>
+                <para>
+                  <literal>grantPermission()</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  The target of the specified <literal>Permission</literal>, or each of the targets
+                  for the specified list of <literal>Permission</literal>s (depending on which method is
+                  called).
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>seam.grant-permission</literal>
+                </para>
+              </entry>
+            </row>
+            
+            <row>
+              <entry>
+                <para>
+                  <literal>grantPermission()</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  The target of the specified <literal>Permission</literal>.
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>seam.grant-permission</literal>
+                </para>
+              </entry>
+            </row>
+            
+            <row>
+              <entry>
+                <para>
+                  <literal>grantPermissions()</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  Each of the targets of the specified list of <literal>Permission</literal>s.
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>seam.grant-permission</literal>
+                </para>
+              </entry>
+            </row>
+            
+            <row>
+              <entry>
+                <para>
+                  <literal>revokePermission()</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  The target of the specified <literal>Permission</literal>.
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>seam.revoke-permission</literal>
+                </para>
+              </entry>
+            </row>
+            
+            <row>
+              <entry>
+                <para>
+                  <literal>revokePermissions()</literal>
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  Each of the targets of the specified list of <literal>Permission</literal>s.
+                </para>
+              </entry>
+              <entry>
+                <para>
+                  <literal>seam.revoke-permission</literal>
+                </para>
+              </entry>
+            </row>
+            
+          </tbody>
+        </tgroup>
+      </table>
+    </sect2>
+  
+  </sect1>
+
+  <sect1>
+    <title>SSL Security</title>
+
+    <para>
+      Seam includes basic support for serving sensitive pages via the HTTPS protocol.  This is easily
+      configured by specifying a <literal>scheme</literal> for the page in <literal>pages.xml</literal>.
+      The following example shows how the view <literal>/login.xhtml</literal> is configured to use
+      HTTPS:
+    </para>
+
+    <programlisting role="XML"><![CDATA[<page view-id="/login.xhtml" scheme="https"/>]]></programlisting>
+
+    <para>
+      This configuration is automatically extended to both <literal>s:link</literal> and
+      <literal>s:button</literal> JSF controls, which (when specifying the <literal>view</literal>)
+      will also render the link using the correct protocol.  Based on the previous example, the following
+      link will use the HTTPS protocol because <literal>/login.xhtml</literal> is configured to use it:
+    </para>
+
+    <programlisting role="XHTML"><![CDATA[<s:link view="/login.xhtml" value="Login"/>]]></programlisting>
+
+    <para>
+      Browsing directly to a view when using the <emphasis>incorrect</emphasis> protocol will cause a
+      redirect to the same view using the <emphasis>correct</emphasis> protocol.  For example, browsing
+      to a page that has <literal>scheme="https"</literal> using HTTP will cause a redirect to the same
+      page using HTTPS.
+    </para>
+
+    <para>
+      It is also possible to configure a <emphasis>default scheme</emphasis> for all pages. This is useful
+      if you wish to use HTTPS for a only few pages. If no default scheme is specified then the normal
+      behavior is to continue use the current scheme. So once the user accessed a page that required
+      HTTPS, then HTTPS would continue to be used after the user navigated away to other non-HTTPS pages.
+      (While this is good for security, it is not so great for performance!). To define HTTP as the
+      default <literal>scheme</literal>, add this line to <literal>pages.xml</literal>:
+    </para>
+
+    <programlisting role="XML"><![CDATA[<page view-id="*" scheme="http" />]]></programlisting>
+
+    <para>
+      Of course, if <emphasis>none</emphasis> of the pages in your application use HTTPS then it is not
+      required to specify a default scheme.
+    </para>
+
+    <para>
+      You may configure Seam to automatically invalidate the current HTTP session each time the scheme
+      changes. Just add this line to <literal>components.xml</literal>:
+    </para>
+
+    <programlisting role="XML"><![CDATA[<web:session invalidate-on-scheme-change="true"/>]]></programlisting>
+
+    <para>
+      This option helps make your system less vulnerable to sniffing of the session id or leakage of
+      sensitive data from pages using HTTPS to other pages using HTTP.
+    </para>
+    
+    <sect2>
+      <title>Overriding the default ports</title>
+      
+      <para>
+        If you wish to configure the HTTP and HTTPS ports manually, they may be configured in 
+        <literal>pages.xml</literal> by specifying the <literal>http-port</literal> and
+        <literal>https-port</literal> attributes on the <literal>pages</literal> element:
+      </para>
+      
+      <programlisting role="XML"><![CDATA[
+<pages xmlns="http://jboss.com/products/seam/pages"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://jboss.com/products/seam/pages http://jboss.com/products/seam/pages-2.2.xsd"
+       no-conversation-view-id="/home.xhtml"
+       login-view-id="/login.xhtml"
+       http-port="8080"
+       https-port="8443">      
+      ]]></programlisting>
+    </sect2>
+
+  </sect1>
+
+  <sect1>
+    <title>CAPTCHA</title>
+
+    <para>
+      Though strictly not part of the security API, Seam provides a built-in CAPTCHA (<emphasis>C</emphasis>ompletely
+      <emphasis>A</emphasis>utomated <emphasis>P</emphasis>ublic <emphasis>T</emphasis>uring test to tell
+      <emphasis>C</emphasis>omputers and <emphasis>H</emphasis>umans <emphasis>A</emphasis>part) algorithm to
+      prevent automated processes from interacting with your application.
+    </para>
+
+    <sect2>
+      <title>Configuring the CAPTCHA Servlet</title>
+      <para>
+        To get up and running, it is necessary to configure the Seam Resource Servlet, which will provide the Captcha
+        challenge images to your pages.  This requires the following entry in <literal>web.xml</literal>:
+      </para>
+
+      <programlisting role="XML"><![CDATA[<servlet>
+    <servlet-name>Seam Resource Servlet</servlet-name>
+    <servlet-class>org.jboss.seam.servlet.SeamResourceServlet</servlet-class>
+</servlet>
+
+<servlet-mapping>
+    <servlet-name>Seam Resource Servlet</servlet-name>
+    <url-pattern>/seam/resource/*</url-pattern>
+</servlet-mapping>]]></programlisting>
+
+    </sect2>
+
+    <sect2>
+      <title>Adding a CAPTCHA to a form</title>
+
+      <para>
+        Adding a CAPTCHA challenge to a form is extremely easy. Here's an example:
+      </para>
+
+      <programlisting role="XHTML"><![CDATA[<h:graphicImage value="/seam/resource/captcha"/>
+<h:inputText id="verifyCaptcha" value="#{captcha.response}" required="true">
+   <s:validate />
+</h:inputText>
+<h:message for="verifyCaptcha"/>]]></programlisting>
+
+      <para>
+        That's all there is to it.  The <literal>graphicImage</literal> control displays the CAPTCHA challenge,
+        and the <literal>inputText</literal> receives the user's response. The response is automatically
+        validated against the CAPTCHA when the form is submitted.
+      </para>
+
+    </sect2>
+
+    <sect2>
+      <title>Customising the CAPTCHA algorithm</title>
+
+      <para>
+        You may customize the CAPTCHA algorithm by overriding the built-in component:
+      </para>
+
+      <programlisting role="JAVA"><![CDATA[@Name("org.jboss.seam.captcha.captcha")
+ at Scope(SESSION)
+public class HitchhikersCaptcha extends Captcha
+{
+   @Override @Create
+   public void init()
+   {
+      setChallenge("What is the answer to life, the universe and everything?");
+      setCorrectResponse("42");
+   }
+
+   @Override
+   public BufferedImage renderChallenge()
+   {
+       BufferedImage img = super.renderChallenge();
+       img.getGraphics().drawOval(5, 3, 60, 14); //add an obscuring decoration
+       return img;
+   }
+}]]></programlisting>
+
+    </sect2>
+
+  </sect1>
+
+  <sect1>
+    <title>Security Events</title>
+
+    <para>
+      The following table describes a number of events (see <xref linkend="events"/>) raised by Seam Security
+      in response to certain security-related events.
+    </para>
+
+    <table>
+      <title>Security Events</title>
+
+      <tgroup cols="2">
+        <colspec colnum="1" colwidth="3*" />
+        <colspec colnum="2" colwidth="2*" />
+
+        <thead>
+          <row>
+            <entry align="center">
+              <para>Event Key</para>
+            </entry>
+            <entry align="center">
+              <para>Description</para>
+            </entry>
+          </row>
+        </thead>
+
+        <tbody>
+
+          <row>
+            <entry>
+              <para>
+                <literal>org.jboss.seam.security.loginSuccessful</literal>
+              </para>
+            </entry>
+            <entry>
+              <para>
+                Raised when a login attempt is successful.
+              </para>
+            </entry>
+          </row>
+          <row>
+            <entry>
+              <para>
+                <literal>org.jboss.seam.security.loginFailed</literal>
+              </para>
+            </entry>
+            <entry>
+              <para>
+                Raised when a login attempt fails.
+              </para>
+            </entry>
+          </row>
+          <row>
+            <entry>
+              <para>
+                <literal>org.jboss.seam.security.alreadyLoggedIn</literal>
+              </para>
+            </entry>
+            <entry>
+              <para>
+                Raised when a user that is already authenticated attempts to log in again.
+              </para>
+            </entry>
+          </row>          
+          <row>
+            <entry>
+              <para>
+                <literal>org.jboss.seam.security.notLoggedIn</literal>
+              </para>
+            </entry>
+            <entry>
+              <para>
+                Raised when a security check fails when the user is not logged in.
+              </para>
+            </entry>
+          </row>
+          <row>
+            <entry>
+              <para>
+                <literal>org.jboss.seam.security.notAuthorized</literal>
+              </para>
+            </entry>
+            <entry>
+              <para>
+                Raised when a security check fails when the user is logged in however doesn't have sufficient privileges.
+              </para>
+            </entry>
+          </row>
+          <row>
+            <entry>
+              <para>
+                <literal>org.jboss.seam.security.preAuthenticate</literal>
+              </para>
+            </entry>
+            <entry>
+              <para>
+                Raised just prior to user authentication.
+              </para>
+            </entry>
+          </row>
+          <row>
+            <entry>
+              <para>
+                <literal>org.jboss.seam.security.postAuthenticate</literal>
+              </para>
+            </entry>
+            <entry>
+              <para>
+                Raised just after user authentication.
+              </para>
+            </entry>
+          </row>
+          <row>
+            <entry>
+              <para>
+                <literal>org.jboss.seam.security.loggedOut</literal>
+              </para>
+            </entry>
+            <entry>
+              <para>
+                Raised after the user has logged out.
+              </para>
+            </entry>
+          </row>
+          <row>
+            <entry>
+              <para>
+                <literal>org.jboss.seam.security.credentialsUpdated</literal>
+              </para>
+            </entry>
+            <entry>
+              <para>
+                Raised when the user's credentials have been changed.
+              </para>
+            </entry>
+          </row>
+          <row>
+            <entry>
+              <para>
+                <literal>org.jboss.seam.security.rememberMe</literal>
+              </para>
+            </entry>
+            <entry>
+              <para>
+                Raised when the Identity's rememberMe property is changed.
+              </para>
+            </entry>
+          </row>
+
+        </tbody>
+      </tgroup>
+    </table>
+
+  </sect1>
+  
+  <sect1>
+    <title>Run As</title>
+    
+    <para>
+        Sometimes it may be necessary to perform certain operations with elevated privileges, such
+        as creating a new user account as an unauthenticated user.  Seam Security supports such a
+        mechanism via the <literal>RunAsOperation</literal> class.  This class allows either the
+        <literal>Principal</literal> or <literal>Subject</literal>, or the user's roles to be
+        overridden for a single set of operations.
+    </para>
+    
+    <para>
+      The following code example demonstrates how <literal>RunAsOperation</literal> is used, by
+      calling its <literal>addRole()</literal> method to provide a set of roles to masquerade
+      as for the duration of the operation.  The <literal>execute()</literal> method contains the
+      code that will be executed with the elevated privileges.
+    </para>
+    
+    <programlisting role="JAVA"><![CDATA[    new RunAsOperation() {       
+       public void execute() {
+          executePrivilegedOperation();
+       }         
+    }.addRole("admin")
+     .run();]]></programlisting>
+    
+    <para>
+        In a similar way, the <literal>getPrincipal()</literal> or <literal>getSubject()</literal>
+        methods can also be overriden to specify the <literal>Principal</literal> and 
+        <literal>Subject</literal> instances to use for the duration of the operation.
+        Finally, the <literal>run()</literal> method is used to carry out the 
+        <literal>RunAsOperation</literal>.
+    </para>
+
+  </sect1>
+
+  <sect1>
+    <title>Extending the Identity component</title>
+
+    <para>
+      Sometimes it might be necessary to extend the Identity component if your application has
+      special security requirements.  The following example (contrived, as credentials would normally
+      be handled by the <literal>Credentials</literal> component instead) shows an extended Identity 
+      component with an additional <literal>companyCode</literal> field.  The install precendence of <literal>APPLICATION</literal>
+      ensures that this extended Identity gets installed in preference to the built-in Identity.
+    </para>
+
+    <programlisting role="JAVA"><![CDATA[@Name("org.jboss.seam.security.identity")
+ at Scope(SESSION)
+ at Install(precedence = APPLICATION)
+ at BypassInterceptors
+ at Startup
+public class CustomIdentity extends Identity
+{
+   private static final LogProvider log = Logging.getLogProvider(CustomIdentity.class);
+
+   private String companyCode;
+
+   public String getCompanyCode()
+   {
+      return companyCode;
+   }
+
+   public void setCompanyCode(String companyCode)
+   {
+      this.companyCode = companyCode;
+   }
+
+   @Override
+   public String login()
+   {
+      log.info("###### CUSTOM LOGIN CALLED ######");
+      return super.login();
+   }
+}]]></programlisting>
+
+    <warning>
+      <para>
+        Note that an <literal>Identity</literal> component must be marked <literal>@Startup</literal>, so that it is
+        available immediately after the <literal>SESSION</literal> context begins.  Failing to do this may render
+        certain Seam functionality inoperable in your application.
+      </para>
+    </warning>
+
+
+  </sect1>
+    
+    
+    <sect1>
+        <title>OpenID</title>
+        
+        <para>
+            OpenID is a community standard for external web-based authentication. The basic
+            idea is that any web application can supplement (or replace) its local handling of
+            authentication by delegating responsibility to an external OpenID server of the user's
+            chosing.  This benefits the user, who no longer has to remember a name and password for 
+            every web application he uses, and the developer, who is relieved of some of the burden of 
+            maintaining a complex authentication system.  
+        </para>
+        
+        <para>When using OpenID, the user selects an OpenID provider, and the provider assigns the user
+            an OpenID.  The id will take the form of a URL, for example <literal>http://maximoburrito.myopenid.com</literal> however,
+            it's acceptable to leave off the <literal>http://</literal> part of the identifier when logging into a site.  The web application
+            (known as a relying party in OpenID-speak) determines which OpenID server to contact and redirects the user to the remote
+            site for authentication.   Upon successful authentication the user is given
+            the (cryptographically secure) token proving his identity and is redirected back to the original web application.The 
+            local web application can then be sure the user accessing the application controls the OpenID he presented.
+        </para>
+        
+        <para>
+            It's important to realize at this
+            point that authentication does not imply authorization.  The web application still needs to make a determination of how to 
+            use that information.  The web application could treat the user as instantly logged in and give full access to the system or
+            it could try and map the presented OpenID to a local user account, prompting the user to register if he hasn't already.
+            The choice of how to handle the OpenID is left as a design decision for the local application.  
+        </para>
+
+    
+        <sect2>
+            <title>Configuring OpenID</title>
+            <para>
+                Seam uses the openid4java package and requires four additional JARs to make use of the Seam integration.  These 
+                are: <literal>htmlparser.jar</literal>, <literal>openid4java.jar</literal>, <literal>openxri-client.jar</literal> 
+                and <literal>openxri-syntax.jar</literal>.
+            </para>
+            
+            <para>
+                OpenID processing requires the use of the <literal>OpenIdPhaseListener</literal>, which should be added to your 
+                <literal>faces-config.xml</literal> file.  The phase listener processes the callback from the OpenID provider, allowing
+                re-entry into the local application.
+            </para>
+            
+            <programlisting role="XML">&lt;lifecycle&gt;
+    &lt;phase-listener&gt;org.jboss.seam.security.openid.OpenIdPhaseListener&lt;/phase-listener&gt;
+&lt;/lifecycle&gt;</programlisting>
+
+        
+            <para>
+                With this configuration, OpenID support is available to your application.
+                The OpenID support component, <literal>org.jboss.seam.security.openid.openid</literal>, is installed automatically if the openid4java
+                classes are on the classpath.
+            </para>
+        </sect2>
+        
+        <sect2>
+            <title>Presenting an OpenIdDLogin form</title>
+            
+            <para>
+                 To initiate an OpenID login, you can present a simply form to the user asking for the user's OpenID.  The <literal>#{openid.id}</literal> 
+                  value 
+                 accepts the user's OpenID and the <literal>#{openid.login}</literal> action initiates an authentication request.
+            </para>
+ <programlisting role="XML">&lt;h:form&gt;
+    &lt;h:inputText value=&quot;#{openid.id}&quot; /&gt;
+    &lt;h:commandButton action=&quot;#{openid.login}&quot; value=&quot;OpenID Login&quot;/&gt;
+&lt;/h:form&gt;</programlisting>          
+            
+            <para>
+                When the user submits the login form, he will be redirected to his OpenID provider. The user will eventually 
+                return to your application through the Seam pseudo-view <literal>/openid.xhtml</literal>, which is
+                provided by the <literal>OpenIdPhaseListener</literal>. Your application can handle the OpenID response by means 
+                of a <literal>pages.xml</literal> navigation from that view, just as if the user had never left your application.
+            </para>
+        </sect2>
+            
+            <sect2>
+                <title>Logging in immediately</title>
+    
+    <para> The simplest strategy is to simply login the user immediately.  The following navigation rule shows how to handle this using
+        the <literal>#{openid.loginImmediately()}</literal> action.
+    </para>
+        
+        <programlisting role="XML">&lt;page view-id=&quot;/openid.xhtml&quot;&gt;
+    &lt;navigation evaluate=&quot;#{openid.loginImmediately()}&quot;&gt;
+        &lt;rule if-outcome=&quot;true&quot;&gt;
+            &lt;redirect view-id=&quot;/main.xhtml&quot;&gt;
+                &lt;message&gt;OpenID login successful...&lt;/message&gt;
+            &lt;/redirect&gt;
+        &lt;/rule&gt;
+        &lt;rule if-outcome=&quot;false&quot;&gt;
+            &lt;redirect view-id=&quot;/main.xhtml&quot;&gt;
+                &lt;message&gt;OpenID login rejected...&lt;/message&gt;
+            &lt;/redirect&gt;
+        &lt;/rule&gt;
+    &lt;/navigation&gt;
+&lt;/page&gt;</programlisting>            
+    
+        <para>Thie <literal>loginImmediately()</literal> action checks to see if the OpenID is valid.  If it is valid, it adds an
+            OpenIDPrincipal to the identity component, marks the user as logged in (i.e. <literal>#{identity.loggedIn}</literal> will be true)
+            and returns true.  If the OpenID was not validated, the method returns false, and the user re-enters the application un-authenticated.
+            If the user's OpenID is valid, it will be accessible using the expression <literal>#{openid.validatedId}</literal> and 
+            <literal>#{openid.valid}</literal> will be true.
+        </para>
+
+
+        </sect2>
+   
+        <sect2>
+            <title>Deferring login</title>
+            
+            <para>
+                You may not want the user to be immediately logged in to your application.  In that case, your navigation
+                should check the <literal>#{openid.valid}</literal> property and redirect the user to a local registration or processing
+                page.  Actions you might take would be asking for more information and creating a local user account or presenting a captcha 
+                to avoid programmatic registrations.  When you are done processing, if you want to log the user in, you can call
+                the <literal>loginImmediately</literal> method, either through EL as shown previously or by directly interaction with the 
+                <literal>org.jboss.seam.security.openid.OpenId</literal> component.  Of course, nothing prevents you from writing custom 
+                code to interact with the Seam identity component on your own for even more customized behaviour.
+            </para>
+            
+        </sect2>
+        
+        
+        <sect2>
+            <title>Logging out</title>
+            
+            <para>
+                Logging out (forgetting an OpenID association) is done by calling <literal>#{openid.logout}</literal>.  If you
+                are not using Seam security, you can call this method directly.  If you are using Seam security, you should
+                continue to use <literal>#{identity.logout}</literal> and install an event handler to capture the logout event, calling 
+                the OpenID logout method.
+                
+            </para>
+             <programlisting role="XML">&lt;event type=&quot;org.jboss.seam.security.loggedOut&quot;&gt;
+    &lt;action execute=&quot;#{openid.logout}&quot; /&gt;
+&lt;/event&gt; </programlisting>
+            
+            <para>It's important that you do not leave this out or the user will not be able to login again in the same session.</para>
+        </sect2>
+
+
+        
+        
+    </sect1>
+    
+    
+</chapter>


Property changes on: modules/security/trunk/docs/en-US/security-general.xml
___________________________________________________________________
Name: svn:executable
   + *



More information about the seam-commits mailing list