Author: shane.bryzak(a)jboss.com
Date: 2008-06-20 00:08:36 -0400 (Fri, 20 Jun 2008)
New Revision: 8396
Modified:
trunk/doc/Seam_Reference_Guide/en-US/Security.xml
Log:
work in progress
Modified: trunk/doc/Seam_Reference_Guide/en-US/Security.xml
===================================================================
--- trunk/doc/Seam_Reference_Guide/en-US/Security.xml 2008-06-19 20:14:32 UTC (rev 8395)
+++ trunk/doc/Seam_Reference_Guide/en-US/Security.xml 2008-06-20 04:08:36 UTC (rev 8396)
@@ -3,82 +3,54 @@
<chapter id="security">
<title>Security</title>
- <para>
- The Seam Security API is an optional Seam feature that provides authentication and
authorization features
- for securing both domain and page resources within your Seam project.
- </para>
-
<sect1>
<title>Overview</title>
-
+
<para>
- Seam Security provides two different modes of operation:
+ The Seam Security API provides a multitude of security-related features for your
Seam-based application, covering
+ such areas as:
</para>
-
+
<itemizedlist>
<listitem>
<para>
- <emphasis>simplified mode</emphasis> - this mode supports
authentication services
- and simple role-based security checks.
+ Authentication - an extensible, JAAS-based authentication layer that allows
users to authenticate
+ against any security provider.
</para>
</listitem>
<listitem>
<para>
- <emphasis>advanced mode</emphasis> - this mode supports all the
same features as the simplified mode,
- plus it offers rule-based security checks using JBoss Rules.
+ Identity Management - an API for managing a Seam application's users and
roles at runtime.
</para>
</listitem>
- </itemizedlist>
-
- <sect2>
- <title>Which mode is right for my application?</title>
-
- <para>
- That all depends on the requirements of your application. If you have minimal
security requirements, for example
- if you only wish to restrict certain pages and actions to users who are logged
in, or who belong to a certain role,
- then the simplified mode will probably be sufficient. The advantages of this is
a more simplified configuration,
- significantly less libraries to include, and a smaller memory footprint.
- </para>
-
- <para>
- If on the other hand, your application requires security checks based on
contextual state or complex business rules,
- then you will require the features provided by the advanced mode.
- </para>
- </sect2>
- </sect1>
-
- <sect1>
- <title>Requirements</title>
-
- <para>
- If using the advanced mode features of Seam Security, the following jar files are
required to be configured as modules in
- <literal>application.xml</literal>. If you are using Seam Security in
simplified mode, these are <emphasis>not</emphasis>
- required:
- </para>
-
- <itemizedlist>
<listitem>
- <para>drools-compiler.jar</para>
+ <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>drools-core.jar</para>
+ <para>
+ Permission Management - a set of built-in Seam components to allow easy
management of an application's
+ security policy.
+ </para>
</listitem>
<listitem>
- <para>janino.jar</para>
+ <para>
+ CAPTCHA support - to assist in the prevention of automated software/scripts
abusing your Seam-based site.
+ </para>
</listitem>
<listitem>
- <para>antlr-runtime.jar</para>
+ <para>
+ And much more
+ </para>
</listitem>
- <listitem>
- <para>mvel14.jar</para>
- </listitem>
- </itemizedlist>
-
+ </itemizedlist>
+
<para>
- For web-based security, <literal>jboss-seam-ui.jar</literal> must also
be included in the application's war file.
- </para>
+ This chapter will cover each of these features in detail.
+ </para>
-
</sect1>
<sect1>
@@ -105,7 +77,7 @@
</listitem>
</itemizedlist>
</sect1>
-
+
<sect1>
<title>Authentication</title>
@@ -114,17 +86,22 @@
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>Configuration</title>
+ <title>Configuring an Authenticator component</title>
+ <note>
+ 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).
+ </note>
+
<para>
- The simplified authentication method uses a built-in JAAS login module,
<literal>SeamLoginModule</literal>, which
+ 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. Configuring this
- simplified form of authentication requires the
<literal>identity</literal> component to be configured in
- <literal>components.xml</literal>:
+ write an authentication method using the entity classes that are provided by your
own application, or alternatively to
+ authenticate against 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"
@@ -140,12 +117,6 @@
</components>]]></programlisting>
<para>
- If you wish to use the advanced security features such as rule-based permission
checks, all you need
- to do is include the Drools (JBoss Rules) jars in your classpath, and add some
additional configuration,
- described later.
- </para>
-
- <para>
The EL expression <literal>#{authenticator.authenticate}</literal> is
a method binding indicating that
the <literal>authenticate</literal> method of the
<literal>authenticator</literal> component will be used
to authenticate the user.
@@ -161,29 +132,31 @@
<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 indicating
whether authentication is successful or not. The user's username and
password can be obtained from
- <literal>Identity.instance().getUsername()</literal> and
<literal>Identity.instance().getPassword()</literal>,
+ <literal>Credentials.getUsername()</literal> and
<literal>Credentials.getPassword()</literal>,
respectively. Any roles that the user is a member of should be assigned using
- <literal>Identity.instance().addRole()</literal>. Here's a
complete example of an authentication method
- inside a JavaBean component:
+ <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", Identity.instance().getUsername())
- .setParameter("password", Identity.instance().getPassword())
+ .setParameter("username", credentials.getUsername())
+ .setParameter("password", credentials.getPassword())
.getSingleResult();
if (user.getRoles() != null)
{
for (UserRole mr : user.getRoles())
- Identity.instance().addRole(mr.getName());
+ identity.addRole(mr.getName());
}
return true;
@@ -204,6 +177,16 @@
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>
+
+ <note>
+ 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.
+ </note>
<sect3>
<title>Identity.addRole()</title>
@@ -227,24 +210,19 @@
<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 immediate granting the current user the specified
role.
+ </para>
</sect3>
<sect3>
- <title>Special Considerations</title>
+ <title>Writing an event observers for security-related
events</title>
<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>
-
- <para>
- To give an example, let's say that upon a successful login that some user
statistics must be
+ Let's say for example that upon a successful login that some user
statistics must be
updated. We would do this by writing an event observer for the
<literal>org.jboss.seam.security.loginSuccessful</literal> event,
like this:
</para>
@@ -257,6 +235,11 @@
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>
@@ -265,21 +248,21 @@
<title>Writing a login form</title>
<para>
- The <literal>Identity</literal> component provides both
<literal>username</literal> and <literal>password</literal>
+ 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 the
- <literal>identity.login()</literal> method will authenticate the user
using the provided credentials.
+ 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="#{identity.username}"/>
+ <h:inputText id="name" value="#{credentials.username}"/>
</div>
<div>
<h:outputLabel for="password" value="Password"/>
- <h:inputSecret id="password"
value="#{identity.password}"/>
+ <h:inputSecret id="password"
value="#{credentials.password}"/>
</div>
<div>
@@ -288,13 +271,13 @@
<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.
+ action will clear the security state of the currently authenticated user, and
invalidate the user's session.
</para>
</sect2>
<sect2>
- <title>Simplified Configuration - Summary</title>
+ <title>Configuration Summary</title>
<para>
So to sum up, there are the three easy steps to configure authentication:
</para>
@@ -509,9 +492,653 @@
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>
+
+ <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><![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><![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><![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> and
<literal>sha</literal>. E.g:
+
+ <programlisting><![CDATA[@UserPassword(hash =
"md5")
+public String getPasswordHash() {
+ return passwordHash;
+}]]></programlisting>
+
+ </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><![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><![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="3*" />
+
+ <thead>
+ <row>
+ <entry align="center">
+ <para>Property</para>
+ </entry>
+ <entry align="center">
+ <para>Description</para>
+ </entry>
+ </row>
+ </thead>
+
+ <tbody>
+ <row>
+ <entry>
+ <para>
+ <literal>server-address</literal>
+ </para>
+ </entry>
+ <entry>
+ <para>
+ The address of the LDAP server, defaults to
<literal>localhost</literal>.
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry>
+ <para>
+ <literal>server-port</literal>
+ </para>
+ </entry>
+ <entry>
+ <para>
+ The port number that the LDAP server is listening on, defaults to
389.
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry>
+ <para>
+ <literal>user-context-DN</literal>
+ </para>
+ </entry>
+ <entry>
+ <para>
+ The Distinguished Name (DN) of the context containing user records.
The default value is
+ "<literal>ou=Person,dc=acme,dc=com</literal>".
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry>
+ <para>
+ <literal>user-DN-prefix</literal>
+ </para>
+ </entry>
+ <entry>
+ <para>
+ This value is prefixed to the front of the username to locate the
user's record.
+ The default value is
"<literal>uid=</literal>".
+ </para>
+ </entry>
+ </row>
+
+ <row>
+ <entry>
+ <para>
+ <literal>user-DN-suffix</literal>
+ </para>
+ </entry>
+ <entry>
+ <para>
+ This value is appended to the end of the username to locate the
user's record. The default
+ value is
"<literal>,ou=Person,dc=acme,dc=com</literal>".
+ </para>
+ </entry>
+ </row>
+
+ </tbody>
+ </tgroup>
+ </table>
+ </sect3>
+ </sect2>
+
+ <sect2>
+ <title>Writing your own IdentityStore implementation</title>
+
+ <para>
+
+ </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>authenticator-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>
</sect1>
<sect1>
@@ -1028,7 +1655,46 @@
</sect3>
</sect2>
+
+ <sect2>
+ <title>Rule-based Permissions</title>
+
+ <sect3>
+ <title>Configuration</title>
+
+ </sect3>
+
+ <sect3>
+ <title>Requirements</title>
+
+ <para>
+ If using the rule-based permission features provided by Seam Security, the
following jar files are required to be
+ distributed with your project:
+ </para>
+
+ <itemizedlist>
+ <listitem>
+ <para>drools-compiler.jar</para>
+ </listitem>
+ <listitem>
+ <para>drools-core.jar</para>
+ </listitem>
+ <listitem>
+ <para>janino.jar</para>
+ </listitem>
+ <listitem>
+ <para>antlr-runtime.jar</para>
+ </listitem>
+ <listitem>
+ <para>mvel14.jar</para>
+ </listitem>
+ </itemizedlist>
+
+ </sect3>
+
+ </sect2>
+
</sect1>
<sect1>
@@ -1666,7 +2332,7 @@
<imagedata fileref="images/security-identitymanager.png"
align="center"/>
</imageobject>
<imageobject role="html">
- <imagedata fileref="../shared/images/security-identitymanager.png"
align="center"/>
+ <imagedata fileref="images/security-identitymanager.png"
align="center"/>
</imageobject>
</mediaobject>
@@ -1702,7 +2368,7 @@
<imagedata fileref="images/security-useraccount.png"
align="center"/>
</imageobject>
<imageobject role="html">
- <imagedata fileref="../shared/images/security-useraccount.png"
align="center"/>
+ <imagedata fileref="images/security-useraccount.png"
align="center"/>
</imageobject>
</mediaobject>
@@ -1715,7 +2381,7 @@
<imagedata fileref="images/security-useraccountschema.png"
align="center"/>
</imageobject>
<imageobject role="html">
- <imagedata
fileref="../shared/images/security-useraccountschema.png"
align="center"/>
+ <imagedata fileref="images/security-useraccountschema.png"
align="center"/>
</imageobject>
</mediaobject>
@@ -2515,7 +3181,7 @@
<imagedata fileref="images/security-usermanager1.png"
align="center"/>
</imageobject>
<imageobject role="html">
- <imagedata fileref="../shared/images/security-usermanager1.png"
align="center"/>
+ <imagedata fileref="images/security-usermanager1.png"
align="center"/>
</imageobject>
</mediaobject>
@@ -2528,7 +3194,7 @@
<imagedata fileref="images/security-usermanager2.png"
align="center"/>
</imageobject>
<imageobject role="html">
- <imagedata fileref="../shared/images/security-usermanager2.png"
align="center"/>
+ <imagedata fileref="images/security-usermanager2.png"
align="center"/>
</imageobject>
</mediaobject>