From seam-commits at lists.jboss.org Sun May 30 19:53:43 2010 Content-Type: multipart/mixed; boundary="===============2502031146515175342==" MIME-Version: 1.0 From: seam-commits at lists.jboss.org To: seam-commits at lists.jboss.org Subject: [seam-commits] Seam SVN: r12909 - modules/security/trunk/docs/en-US. Date: Sun, 30 May 2010 19:53:43 -0400 Message-ID: <201005302353.o4UNrht5025450@svn01.web.mwc.hst.phx2.redhat.com> --===============2502031146515175342== Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Author: shane.bryzak(a)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 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- 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 @@ + + + + + Security + + + Overview + = + + The Seam Security API provides a multitude of security-related featu= res for your Seam-based application, covering = + such areas as: + + = + + + + Authentication - an extensible, JAAS-based authentication layer = that allows users to authenticate + against any security provider. + + + + + Identity Management - an API for managing a Seam application's u= sers and roles at runtime. + + + + + Authorization - an extremely comprehensive authorization framewo= rk, supporting user roles, persistent and + rule-based permissions, and a pluggable permission resolver for = easily implementing customised security logic. + + + + + Permission Management - a set of built-in Seam components to all= ow easy management of an application's = + security policy. + = + + + + CAPTCHA support - to assist in the prevention of automated softw= are/scripts abusing your Seam-based site. + + + + + And much more + + + = + = + + This chapter will cover each of these features in detail. + = + + + + + Disabling Security + + + 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. Sim= ply call the static method + Identity.setSecurityEnabled(false) to disable the= security infrastructure. Of course, it's not + very convenient to have to call a static method when you want to con= figure the application, so as an alternative + you can control this setting in components.xml: + + + + + Entity Security + + + Hibernate Security Interceptor + + + Seam Security Interceptor + + + Page restrictions + + + Servlet API security integration + + + + + Assuming you are planning to take advantage of what Seam Security ha= s 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 co= nstraints (authorization). Let's begin with + the task of authentication since that's the foundation of any securi= ty model. + + + + = + + Authentication + + + 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 handlin= g user authentication. However, for less complex + authentication requirements Seam offers a much more simplified metho= d of authentication that hides the complexity of JAAS. + + = + + Configuring an Authenticator component + + + + 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). + + + + + The simplified authentication method provided by Seam uses a built= -in JAAS login module, SeamLoginModule, 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 p= rovided by your own application, or alternatively to = + authenticate with some other third party provider. Configuring th= is simplified form of authentication requires the = + identity component to be configured in components.xml: + + + + + + +]]> + + + The EL expression #{authenticator.authenticate}= is a method binding that indicates + the authenticate method of the authent= icator component will be used + to authenticate the user. + + + + + + Writing an authentication method + + + The authenticate-method property specified for = identity in + components.xml specifies which method will be u= sed by SeamLoginModule + to authenticate users. This method takes no parameters, and is ex= pected to return a boolean, which indicates + whether authentication is successful or not. The user's username = and password can be obtained from + Credentials.getUsername() and Credenti= als.getPassword(), + respectively (you can get a reference to the credentials<= /literal> component via + Identity.instance().getCredentials()). Any rol= es that the user is a member of = + should be assigned using Identity.addRole(). He= re's a complete example of an = + authentication method inside a POJO component: + + + + + + In the above example, both User and Us= erRole are application-specific + entity beans. The roles parameter is populated= with the roles that the user is a member + of, which should be added to the Set as literal= string values, e.g. "admin", "user". + In this case, if the user record is not found and a NoRes= ultException thrown, the + authentication method returns false to indicate= the authentication failed. + + = + + + When writing an authenticator method, it is important that it i= s kept minimal and free from + any side-effects. This is because there is no guarantee as to h= ow many times the authenticator + method will be called by the security API, and as such it may b= e invoked multiple times during + a single request. Because of this, any special code that shoul= d execute upon a successful or + failed authentication should be written by implementing an even= t observer. See the section on + Security Events further down in this chapter for more informati= on about which events are + raised by Seam Security. + + + + + Identity.addRole() + + + The Identity.addRole() method behaves differe= ntly depending on whether the current + session is authenticated or not. If the session is not authenti= cated, then addRole() + should only be called during the authentica= tion process. When called here, the + role name is placed into a temporary list of pre-authenticated r= oles. Once authentication is successful, + the pre-authenticated roles then become "real" roles, and callin= g Identity.hasRole() + for those roles will then return true. The following sequence d= iagram represents the list of pre-authenticated + roles as a first class object to show more clearly how it fits i= n to the authentication process. + + + + + + + + + + + + = + + If the current session is already authenticated, then calling Identity.addRole() will + have the expected effect of immediately granting the specified r= ole to the current user. + + + + + + Writing an event observer for security-related events</titl= e> + + <para> + Say for example, that upon a successful login that some user sta= tistics 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=3D"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 Authent= icator component itself. + You can find more information about security-related events late= r in this chapter. + </para> + </sect3> + + </sect2> + + <sect2> + <title>Writing a login form + + + The credentials component provides both username and password + 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 properti= es are set, calling = + identity.login() will authenticate the user usi= ng the provided credentials. + Here's an example of a simple login form: + + + + + + + +
+ + +
+ +
+ +
]]>
+ + + Similarly, logging out the user is done by calling #{iden= tity.logout}. Calling this + action will clear the security state of the currently authenticate= d user, and invalidate the user's session. + + +
+ + + Configuration Summary + + So to sum up, there are the three easy steps to configure authenti= cation: + + + + + + Configure an authentication method in components.xml<= /literal>. + + + + + Write an authentication method. + + + + + Write a login form so that the user can authenticate. + + + + + + = + + Remember Me + = + + Seam Security supports the same kind of "Remember Me" functionalit= y that is commonly encountered in many + online web-based applications. It is actually supported in two di= fferent "flavours", or modes - the first + mode allows the username to be stored in the user's browser as a c= ookie, and leaves the entering of the + password up to the browser (many modern browsers are capable of re= membering passwords). + + = + + 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 provid= e a password. + + = + + + Automatic client authentication with a persistent cookie stored = on the client machine is dangerous. = + While convenient for users, any cross-site scripting security ho= le in your website would have dramatically more = + serious effects than usual. Without the authentication cookie, t= he only cookie to steal for an attacker with XSS = + is the cookie of the current session of a user. This means the a= ttack only works when the user has an open session - = + which should be a short timespan. However, it is much more attra= ctive and dangerous if an attacker has the possibility = + to steal a persistent Remember Me cookie that allows him to logi= n without authentication, at any time. Note that this = + all depends on how well you protect your website against XSS att= acks - 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. = + + = + + 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 passwor= d for a particular website and domain, and fills out the = + login form automatically when you don't have an active session w= ith 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 da= ta 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. + + = + + To summarize: While everyone is doing it, persistent "Remember M= e" cookies with automatic authentication are a bad = + practice and should not be used. Cookies that "remember" only th= e users login name, and fill out the login form with = + that username as a convenience, are not an issue. = + + + = + + 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 rememberMe.enabled, like in the following + example: + + = + + + + + = +
+ + +
= + = +
+ + +
]]>
+ = + + Token-based Remember-me Authentication + = + + To use the automatic, token-based mode of the remember me featur= e, you must first configure a token store. The + most common scenario is to store these authentication tokens wit= hin a database (which Seam supports), however it = + is possible to implement your own token store by implementing th= e org.jboss.seam.security.TokenStore + interface. This section will assume you will be using the provi= ded JpaTokenStore implementation + to store authentication tokens inside a database table. + + = + + 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: + + = + + + + As you can see from this listing, a couple of special annotation= s, @TokenUsername and + @TokenValue are used to configure the usernam= e and token properties of the entity. These + annotations are required for the entity that will contain the au= thentication tokens. + + = + + The next step is to configure JpaTokenStore t= o use this entity bean to store and retrieve + authentication tokens. This is done in components.xml<= /literal> by specifying the token-class + attribute: + + = + = + ]]> + = + + Once this is done, the last thing to do is to configure the RememberMe component in + components.xml also. Its mode should be set to autoLogin: + + = + = + ]]> + = + + 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). + + = + + To ensure that users are automatically authenticated when return= ing to the site, the following section + should be placed in components.xml: + + + + + + + + + ]]> + = + + = +
+ + + Handling Security Exceptions + + + To prevent users from receiving the default error page in response= to a security error, it's recommended that + pages.xml is configured to redirect security er= rors to a more "pretty" page. The two + main types of exceptions thrown by the security API are: + + + + + + NotLoggedInException - This exception is th= rown if the user attempts to access a + restricted action or page when they are not logged in. + + + + + AuthorizationException - 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. + + + + + + In the case of a NotLoggedInException, it is re= commended that the user is redirected to + either a login or registration page so that they can log in. For = an AuthorizationException, + it may be useful to redirect the user to an error page. Here's an = example of a pages.xml + file that redirects both of these security exceptions: + + + + + ... + + + + You must be logged in to perform this action + + + + + + + You do not have the necessary security privileges to = perform this action. + + + +]]> + + + Most web applications require even more sophisticated handling of = login redirection, so + Seam includes some special functionality for handling this problem. + + + + + + Login Redirection + + + You can ask Seam to redirect the user to a login screen when an un= authenticated user tries + to access a particular view (or wildcarded view id) as follows: + + + + + + + ... + +]]> + + + + This is less of a blunt instrument than the exception handler s= hown above, but should + probably be used in conjunction with it. + + + + + After the user logs in, we want to automatically send them back wh= ere they came from, so + they can retry the action that required logging in. If you add the= following event listeners + to components.xml, attempts to access a restric= ted 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 ex= isted in the original + request. + + + + + + + + +]]> + + + Note that login redirection is implemented as a conversation-scope= d mechanism, so don't end + the conversation in your authenticate() method. + + + + + + HTTP Authentication + + + 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 authentication-filter component must be ena= bled in components.xml: + + + + ]]> + + + To enable the filter for basic authentication, set auth-t= ype to basic, + or for digest authentication, set it to digest.= If using digest authentication, the + key and realm must also be s= et: + + + + ]]> + + + The key can be any String value. The = realm is the name of the + authentication realm that is presented to the user when they authe= nticate. + + + + Writing a Digest Authenticator + + + If using digest authentication, your authenticator class should = extend the abstract class + org.jboss.seam.security.digest.DigestAuthenticator, and use the + validatePassword() method to validate the use= r's plain text password + against the digest request. Here is an example: + + + + + + + + + Advanced Authentication Features + + + This section explores some of the advanced features provided by th= e security API for addressing more complex + security requirements. + + + + Using your container's JAAS configuration + + + If you would rather not use the simplified JAAS configuration pr= ovided by the Seam Security API, you may + instead delegate to the default system JAAS configuration by pro= viding a jaas-config-name + property in components.xml. For example, if = you are using JBoss AS and wish to use + the other policy (which uses the Use= rsRolesLoginModule login module + provided by JBoss AS), then the entry in components.xml= would look like this: + + + ]]> + = + + 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 instr= ucts Seam Security to authenticate + itself using the configured JAAS security policy. + + + +
+ = + + Identity Management + = + + 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 identityManager 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 listi= ng users and roles. + + = + + Before it may be used, the identityManager must f= irst be configured with one or more + IdentityStores. These components do the actual w= ork of interacting with the backend + security provider, whether it be a database, LDAP server, or somethi= ng else. + + + + + + + + + + = + = + + Configuring IdentityManager + = + = + The identityManager component allows for separa= te 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 d= irectory, yet have their roles = + loaded from another identity store, such as a relational database. + + = + + Seam provides two IdentityStore implementations= out of the box; = + JpaIdentityStore uses a relational database to = store user and role information, = + and is the default identity store that is used if nothing is expli= citly configured in the + identityManager component. The other implement= ation that is provided is = + LdapIdentityStore, which uses an LDAP directory= to store users and roles. + + = + + There are two configurable properties for the identityMan= ager component - = + identityStore and roleIdentityStore. The value for these + properties must be an EL expression referring to a Seam component = implementing the + IdentityStore interface. As already mentioned, + if left unconfigured then JpaIdentityStore will= be assumed by default. If + only the identityStore property is configured, = then the same value will be used for + roleIdentityStore also. For example, the follo= wing entry in + components.xml will configure identity= Manager to use + an LdapIdentityStore for both user-related and = role-related operations: + + + + ]]> + = + + The following example configures identityManager to use an LdapIdentityStore + for user-related operations, and JpaIdentityStore for role-related operations: + + = + + ]]> + = + + The following sections explain both of these identity store implem= entations in greater detail. + + = + + = + + JpaIdentityStore + = + + 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 d= esign, allowing a great deal of = + flexibility in the underlying table structure. This is achieved t= hrough the use of a set of special + annotations, allowing entity beans to be configured to store user = and role records. = + + = + + Configuring JpaIdentityStore + = + + JpaIdentityStore requires that both the user-class and = + role-class properties are configured. These = properties should refer to the + entity classes that are to be used to store both user and role r= ecords, respectively. The following + example shows the configuration from components.xml in the SeamSpace example: + + = + + ]]> + = + + = + + Configuring the Entities + = + + As already mentioned, a set of special annotations are used to c= onfigure entity beans for storing + users and roles. The following table lists each of the annotati= ons, and their descriptions. + + = + + User Entity Annotations + = + + + + + = + + + + Annotation + + + Status + + + Description + + + + = + = + + + + @UserPrincipal + + + + Required + + + + This annotation marks the field or method containing t= he user's username. + + + = + = + + + + @UserPassword + + + + Required + + + + This annotation marks the field or method containing t= he user's password. It allows a hash + algorithm to be specified for password hashing. Possi= ble values for hash are + md5, sha and none. E.g: + + + + + + If an application requires a hash algorithm that isn't= supported natively by Seam, it + is possible to extend the PasswordHash component to implement other + hashing algorithms. + + + = + = + + + + @UserFirstName + + + + Optional + + + + This annotation marks the field or method containing t= he user's first name. + + + = + = + + + + @UserLastName + + + + Optional + + + + This annotation marks the field or method containing t= he user's last name. + + + = + = + + + + @UserEnabled + + + + Optional + + + + This annotation marks the field or method containing t= he enabled status of the user. This should be a boolean + property, and if not present then all user accounts ar= e assumed to be enabled. + + + = + = + + + + @UserRoles + + + + Required + + + + This annotation marks the field or method containing t= he roles of the user. This property will be described in = + more detail further down. + + + + + +
= + = + + Role Entity Annotations + = + + + + + = + + + + Annotation + + + Status + + + Description + + + + = + = + + + + @RoleName + + + + Required + + + + This annotation marks the field or method containing t= he name of the role. + + + = + = + + + + @RoleGroups + + + + Optional + + + + This annotation marks the field or method containing t= he group memberships of the role. + + + = + = + + + + @RoleConditional + + + + Optional + + + + This annotation marks the field or method indicating w= hether the role is conditional or not. + Conditional roles are explained later in this chapter. + + + = = + = + + +
= + = +
+ = + + Entity Bean Examples + = + + As mentioned previously, JpaIdentityStore is = designed to be as flexible as possible when + it comes to the database schema design of your user and role tab= les. This section looks at a number of + possible database schemas that can be used to store user and rol= e records. + + = + + Minimal schema example + = + + 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 = UserRoles. + + = + + + + + + + + = + = + roles; + = + @Id @GeneratedValue + public Integer getUserId() { return userId; } + public void setUserId(Integer userId) { this.userId =3D userId; } + = + @UserPrincipal + public String getUsername() { return username; } + public void setUsername(String username) { this.username =3D username; } + = + @UserPassword(hash =3D "md5") + public String getPasswordHash() { return passwordHash; } + public void setPasswordHash(String passwordHash) { this.passwordHash =3D= passwordHash; } + = + @UserRoles + @ManyToMany(targetEntity =3D Role.class) + @JoinTable(name =3D "UserRoles", = + joinColumns =3D @JoinColumn(name =3D "UserId"), + inverseJoinColumns =3D @JoinColumn(name =3D "RoleId")) + public Set getRoles() { return roles; } + public void setRoles(Set roles) { this.roles =3D roles; } +}]]> + + + + = + + Complex Schema Example + = + + This example builds on the above minimal example by including = all of the optional fields, and allowing + group memberships for roles. + + = + + + + + + + + = + = + roles; + private String firstname; + private String lastname; + private boolean enabled; + = + @Id @GeneratedValue + public Integer getUserId() { return userId; } + public void setUserId(Integer userId) { this.userId =3D userId; } + = + @UserPrincipal + public String getUsername() { return username; } + public void setUsername(String username) { this.username =3D username; } + = + @UserPassword(hash =3D "md5") + public String getPasswordHash() { return passwordHash; } + public void setPasswordHash(String passwordHash) { this.passwordHash =3D= passwordHash; } + = + @UserFirstName + public String getFirstname() { return firstname; } + public void setFirstname(String firstname) { this.firstname =3D firstnam= e; } + = + @UserLastName + public String getLastname() { return lastname; } + public void setLastname(String lastname) { this.lastname =3D lastname; } + = + @UserEnabled + public boolean isEnabled() { return enabled; } + public void setEnabled(boolean enabled) { this.enabled =3D enabled; } + = + @UserRoles + @ManyToMany(targetEntity =3D Role.class) + @JoinTable(name =3D "UserRoles", = + joinColumns =3D @JoinColumn(name =3D "UserId"), + inverseJoinColumns =3D @JoinColumn(name =3D "RoleId")) + public Set getRoles() { return roles; } + public void setRoles(Set roles) { this.roles =3D roles; } +}]]> + getGroups() { return groups; } + public void setGroups(Set groups) { this.groups =3D groups; } = + = +}]]> = + + = + + = + + JpaIdentityStore Events + = + + When using JpaIdentityStore as the identity s= tore implementation with IdentityManager, + a few events are raised as a result of invoking certain IdentityManager methods. + + = + + JpaIdentityStore.EVENT_PRE_PERSIST_USER + = + + This event is raised in response to calling IdentityM= anager.createUser(). 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 user-class configured for JpaIdentityStore. = + + = + + Writing an observer for this event may be useful for setting a= dditional field values on the entity, which aren't set + as part of the standard createUser() functi= onality. + + + = + + JpaIdentityStore.EVENT_USER_CREATED + = + + This event is also raised in response to calling Iden= tityManager.createUser(). However, it is = + raised after the user entity has already been persisted to the= database. Like the EVENT_PRE_PERSIST_USER + event, it also passes the entity instance as an event paramete= r. 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. + + + = + + JpaIdentityStore.EVENT_USER_AUTHENTICATED + = + + This event is raised when calling IdentityManager.aut= henticate(). It passes the user entity instance + as the event parameter, and is useful for reading additional p= roperties from the user entity that is being authenticated. + + + + = +
+ = + + LdapIdentityStore + = + + This identity store implementation is designed for working with us= er 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 stor= e, and provide some configuration examples. + + = + + Configuring LdapIdentityStore + = + + The following table describes the available properties that can = be configured in components.xml for + LdapIdentityStore. + + = + + LdapIdentityStore Configuration Properties + = + + + + + = + + + + Property + + + Default Value + + + Description + + + + = + = + + + + server-address + + + + localhost + + + + The address of the LDAP server. + + + + = + + + + server-port + + + + 389 + + + + The port number that the LDAP server is listening on. + + + + = + + + + user-context-DN + + + + ou=3DPerson,dc=3Dacme,dc=3Dcom<= /para> + + + + The Distinguished Name (DN) of the context containing = user records. + + + + = + + + + user-DN-prefix + + + + uid=3D + + + + This value is prefixed to the front of the username to= locate the user's record. + + + + = + + + + user-DN-suffix + + + + ,ou=3DPerson,dc=3Dacme,dc=3Dcom= + + + + This value is appended to the end of the username to l= ocate the user's record. + + + + = + + + + role-context-DN + + + + ou=3DRole,dc=3Dacme,dc=3Dcom + + + + The DN of the context containing role records. + + + + = + + + + role-DN-prefix + + + + cn=3D + + + + This value is prefixed to the front of the role name t= o form the DN for locating the = + role record. + + + + = + + + + role-DN-suffix + + + + ,ou=3DRoles,dc=3Dacme,dc=3Dcom<= /para> + + + + This value is appended to the role name to form the DN= for locating the role record. + + + + = + + + + bind-DN + + + + cn=3DManager,dc=3Dacme,dc=3Dcom= + + + + This is the context used to bind to the LDAP server. + + + + = + + + + bind-credentials + + + + secret + + + + These are the credentials (the password) used to bind = to the LDAP server. + + + + = + + + + user-role-attribute + + + + roles + + + + This is the name of the attribute of the user record t= hat contains the list of roles that the + user is a member of. + + + + = + + + + role-attribute-is-DN + + + + true + + + + This boolean property indicates whether the role attri= bute of the user record is itself a + distinguished name. + + + + = + + + + user-name-attribute + + + + uid + + + + Indicates which attribute of the user record contains = the username. + + + + = + + + + user-password-attribute + + + + userPassword + + + + Indicates which attribute of the user record contains = the user's password. + + + + = + + + + first-name-attribute + + + + null + + + + Indicates which attribute of the user record contains = the user's first name. + + + + = + + + + last-name-attribute + + + + sn + + + + Indicates which attribute of the user record contains = the user's last name. + + + + = + + + + full-name-attribute + + + + cn + + + + Indicates which attribute of the user record contains = the user's full (common) name. + + + + = + + + + enabled-attribute + + + + null + + + + Indicates which attribute of the user record determine= s whether the user is enabled. + + + + = + + + + role-name-attribute + + + + cn + + + + Indicates which attribute of the role record contains = the name of the role. + + + + = + + + + object-class-attribute + + + + objectClass + + + + Indicates which attribute determines the class of an o= bject in the directory. + + + + = + + + + role-object-classes + + + + organizationalRole + + + + An array of the object classes that new role records s= hould be created as. + + + + = + + + + user-object-classes + + + + person,uidObject + + + + An array of the object classes that new user records s= hould be created as. + + + + = + + +
= +
+ = + + LdapIdentityStore Configuration Example + = + + The following configuration example shows how LdapIdent= ityStore may be configured for + an LDAP directory running on fictional host directory.m= ycompany.com. The users are stored + within this directory under the context ou=3DPerson,dc= =3Dmycompany,dc=3Dcom, and are identified + using the uid attribute (which corresponds to= their username). Roles are stored in their + own context, ou=3DRoles,dc=3Dmycompany,dc=3Dcom and referenced from the user's entry via the = + roles attribute. Role entries are identified= by their common name (the cn attribute) + , which corresponds to the role name. In this example, users ma= y be disabled by setting the value of their = + enabled attribute to false. + + = + ]]> + = + + +
+ = + + Writing your own IdentityStore + = + + Writing your own identity store implementation allows you to authe= nticate 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 + org.jboss.seam.security.management.IdentityStore interface. + + = + + Please refer to the JavaDoc for IdentityStore f= or a description of the methods that + must be implemented. + + + = + = + + Authentication with Identity Management + = + + If you are using the Identity Management features in your Seam app= lication, then it is not required + to provide an authenticator component (see previous Authentication= section) to enable authentication. + Simply omit the authenticate-method from the identity configuration + in components.xml, and the SeamLoginMo= dule will by default + use IdentityManager to authenticate your applic= ation's users, without any special + configuration required. + + + = + + Using IdentityManager + = + + The IdentityManager can be accessed either by i= njecting it into your Seam + component as follows: + + + + + + or by accessing it through its static instance() method: + + + + + + The following table describes IdentityManager's= API methods: + + + + Identity Management API + + + + + + + + + Method + + + Returns + + + Description + + + + + + + + + + createUser(String name, String password) + + + + + boolean + + + + + Creates a new user account, with the specified name and = password. Returns true + if successful, or false if not. + + + = + + + + + deleteUser(String name) + + + + + boolean + + + + + Deletes the user account with the specified name. Retur= ns true + if successful, or false if not. + + + + = + + + + createRole(String role) + + + + + boolean + + + + + Creates a new role, with the specified name. Returns true + if successful, or false if not. + + + = + = + + + + deleteRole(String name) + + + + + boolean + + + + + Deletes the role with the specified name. Returns true + if successful, or false if not. + + + = + + + + + enableUser(String name) + + + + + boolean + + + + + Enables the user account with the specified name. Accou= nts that are not enabled are + not able to authenticate. Returns true if successful, or + false if not. + + + + + + + + disableUser(String name) + + + + + boolean + + + + + Disables the user account with the specified name. Retu= rns true if + successful, or false if not. + + + + + + + + changePassword(String name, String password) + + + + + boolean + + + + + Changes the password for the user account with the speci= fied name. Returns + true if successful, or false= if not. + + + + + + + + isUserEnabled(String name) + + + + + boolean + + + + + Returns true if the specified user ac= count is enabled, or + false if it isn't. + + + + + + + + grantRole(String name, String role) + + + + + boolean + + + + + Grants the specified role to the specified user or role.= The role must already exist for it to + be granted. Returns true if the role= is successfully granted, or + false if it is already granted to the= user. + + + + + + + + revokeRole(String name, String role) + + + + + boolean + + + + + Revokes the specified role from the specified user or ro= le. Returns true + if the specified user is a member of the role and it is = successfully revoked, or + false if the user is not a member of = the role. + + + + + + + + userExists(String name) + + + + + boolean + + + + + Returns true if the specified user ex= ists, or false + if it doesn't. + + + + + + + + listUsers() + + + + + List + + + + + Returns a list of all user names, sorted in alpha-numeri= c order. + + + + + + + + listUsers(String filter) + + + + + List + + + + + Returns a list of all user names filtered by the specifi= ed filter parameter, sorted in alpha-numeric order. + + + + + + + + listRoles() + + + + + List + + + + + Returns a list of all role names. + + + + + + + + getGrantedRoles(String name) + + + + + List + + + + + Returns a list of the names of all the roles explicitly = granted to the specified user name. + + + + + + + + getImpliedRoles(String name) + + + + + List + + + + + 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 dire= ctly granted to a user, rather they are + granted to the roles that the user is a member of. For = example, is the admin + role is a member of the user role, an= d a user is a member of the admin + role, then the implied roles for the user are both the <= literal>admin, and user + roles. + + + + + + + + authenticate(String name, String password) + + + + + boolean + + + + + Authenticates the specified username and password using = the configured Identity Store. Returns + true if successful or false<= /literal> if authentication failed. + Successful authentication implies nothing beyond the ret= urn value of the method. It does not + change the state of the Identity comp= onent - to perform a proper Seam login the + Identity.login() must be used instead. + + + + = + + + + addRoleToGroup(String role, String group) + + + + + boolean + + + + + Adds the specified role as a member of the specified gro= up. Returns true if the operation is successful. + + + = + = + + + + removeRoleFromGroup(String role, String group)<= /literal> + + + + + boolean + + + + + Removes the specified role from the specified group. Re= turns true if the operation is successful. + + + = + = + + + + listRoles() + + + + + List + + + + + Lists the names of all roles. + + + = + + + +
+ + + Using the Identity Management API requires that the calling user h= as the appropriate authorization to invoke + its methods. The following table describes the permission require= ments for each of the methods in + IdentityManager. The permission targets listed= below are literal String values. + + + + Identity Management Security Permissions + + + + + + + + + Method + + + Permission Target + + + Permission Action + + + + + + + + + createUser() + + + + + seam.user + + + + + create + + + + + + + + deleteUser() + + + + + seam.user + + + + + delete + + + + = + + + + createRole() + + + + + seam.role + + + + + create + + + = + = + + + + deleteRole() + + + + + seam.role + + + + + delete + + + = + + + + + enableUser() + + + + + seam.user + + + + + update + + + + + + + + disableUser() + + + + + seam.user + + + + + update + + + + + + + + changePassword() + + + + + seam.user + + + + + update + + + + + + + + isUserEnabled() + + + + + seam.user + + + + + read + + + + + + + + grantRole() + + + + + seam.user + + + + + update + + + + + + + + revokeRole() + + + + + seam.user + + + + + update + + + + + + + + userExists() + + + + + seam.user + + + + + read + + + = + + + + + listUsers() + + + + + seam.user + + + + + read + + + + + + + + listRoles() + + + + + seam.role + + + + + read + + + + = + + + + addRoleToGroup() + + + + + seam.role + + + + + update + + + = + = + + + + removeRoleFromGroup() + + + + + seam.role + + + + + update + + + = + + +
+ + + The following code listing provides an example set of security rul= es that grants access to all + Identity Management-related methods to members of the adm= in role: + + + + +
+ = +
+ + + Error Messages + + + The security API produces a number of default faces messages for var= ious security-related events. + The following table lists the message keys that can be used to overr= ide these messages by specifying + them in a message.properties resource file. To s= uppress the message, just put the + key with an empty value in the resource file. + + + + Security Message Keys + + + + + + + + + Message Key + + + Description + + + + + + + + + + org.jboss.seam.loginSuccessful + + + + + This message is produced when a user successfully logs in = via the security API. + + + + + + + org.jboss.seam.loginFailed + + + + + This message is produced when the login process fails, eit= her because the user provided an + incorrect username or password, or because authentication = failed in some other way. + + + + + + + org.jboss.seam.NotLoggedIn + + + + + This message is produced when a user attempts to perform a= n action or access a page that requires + a security check, and the user is not currently authentica= ted. + + + + + + + org.jboss.seam.AlreadyLoggedIn + + + + + This message is produced when a user that is already authe= nticated attempts to log in again. + + + = + + +
+
+ + + Authorization + + + 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 ea= ch of these. An important thing to + note is that if you wish to use any of the advanced features (such a= s rule-based permissions) then + your components.xml may need to be configured to = support this - see the Configuration section + above. + + + + Core concepts + + + Seam Security is built around the premise of users being granted r= oles 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. + + + + What is a role? + = + + A role is a group, or type, 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 c= an be granted either to users (or in some cases to other = + roles), and are used to create logical groups of users for the c= onvenient assignment of specific application privileges. + + + + + + + + + + = + + = + + What is a permission? + = + + 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 role= s offer a higher level of convenience when granting = + privileges to groups of users. They are slightly more complex i= n 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 sp= ecific recipient (or user). For example, the user "Bob" = + may have permission to delete customer objects. In this case, t= he permission target may be "customer", the permission = + action would be "delete" and the recipient would be "Bob". + + = + + + + + + + + + = + = + + Within this documentation, permissions are generally represented= in the form target:action = + (omitting the recipient, although in reality one is always requi= red). + = + + + + + + Securing components + + + Let's start by examining the simplest form of authorization, compo= nent security, starting with the + @Restrict annotation. + + = + + @Restrict vs Typesafe security annotations + = + + While using the @Restrict 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. + = + + + + The @Restrict annotation + + + Seam components may be secured either at the method or the class= level, using the @Restrict + annotation. If both a method and it's declaring class are annot= ated with @Restrict, + the method restriction will take precedence (and the class restr= iction will not apply). If a method + invocation fails a security check, then an exception will be thr= own as per the contract for + Identity.checkRestriction() (see Inline Restr= ictions). A @Restrict + on just the component class itself is equivalent to adding @Restrict to each of its + methods. + + + + An empty @Restrict implies a permission check= of componentName:methodName. + Take for example the following component method: + + + + + + In this example, the implied permission required to call the delete() method is + account:delete. The equivalent of this would= be to write + @Restrict("#{s:hasPermission('account','delete')}"). Now let's look at + another example: + + + + + + This time, the component class itself is annotated with @Restrict. This means that + any methods without an overriding @Restrict a= nnotation require an implicit permission check. + In the case of this example, the insert() met= hod requires a permission of + account:insert, while the delete() method requires that the user is a + member of the admin role. + + + + Before we go any further, let's address the #{s:hasRole= ()} expression seen in the above + example. Both s:hasRole and s:hasPe= rmission are EL functions, which + delegate to the correspondingly named methods of the Id= entity class. These + functions can be used within any EL expression throughout the en= tirety of the security API. + + + + Being an EL expression, the value of the @Restrict annotation may reference any objects that + exist within a Seam context. This is extremely useful when perf= orming permission checks for a specific + object instance. Look at this example: + + + + + + The interesting thing to note from this example is the reference= to selectedAccount + seen within the hasPermission() function call= . The value of this variable will be + looked up from within the Seam context, and passed to the hasPermission() method + in Identity, which in this case can then dete= rmine if the user has the required + permission for modifying the specified Account object. + + + + + Inline restrictions + + Sometimes it might be desirable to perform a security check in c= ode, without using the + @Restrict annotation. In this situation, sim= ply use + Identity.checkRestriction() to evaluate a sec= urity expression, like this: + + + + + + If the expression specified doesn't evaluate to true, either + + + + + + if the user is not logged in, a NotLoggedInEx= ception + exception is thrown or + + + + + if the user is logged in, an AuthorizationExc= eption + exception is thrown. + + + + + + It is also possible to call the hasRole() and= hasPermission() + methods directly from Java code: + + + + + + + + + Security in the user interface + + + 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 Secur= ity 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. + + + + Let's take a look at some examples of interface security. First o= f 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 + identity.isLoggedIn() property, we can write th= is: + + + ]]> + + + 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 a= ctions which should only be accessible + to users in the manager role. Here's one way t= hat these could be written: + + + + Manager Reports +]]> + + + This is also quite straight forward. If the user is not a member = of the manager + role, then the outputLink will not be rendered. The rende= red attribute can + generally be used on the control itself, or on a surrounding <s:div> or + <s:span> control. + + + + Now for something more complex. Let's say you have a h:d= ataTable control on a + page listing records for which you may or may not wish to render a= ction links depending on the + user's privileges. The s:hasPermission EL func= tion allows us to pass in an + object parameter which can be used to determine whether the user h= as the requested permission + for that object or not. Here's how a dataTable with secured links = might look: + + + + + Name + #{cl.name} + + + City + #{cl.city} + + + Action + + + +]]> + + + + + Securing pages + + Page security requires that the application is using a pa= ges.xml file, however is + extremely simple to configure. Simply include a <rest= rict/> element within + the page elements that you wish to secure. If = no explicit restriction is specified + by the restrict element, an implied permission = of /viewId.xhtml:render + will be checked when the page is accessed via a non-faces (GET) re= quest, and a permission of + /viewId.xhtml:restore will be required when any= JSF postback (form submission) originates + from the page. Otherwise, the specified restriction will be evalu= ated as a standard security expression. + Here's a couple of examples: + + + + +]]> + + + This page has an implied permission of /settings.xhtml:re= nder required for non-faces + requests and an implied permission of /settings.xhtml:res= tore for faces requests. + + + + #{s:hasRole('admin')} +]]> + + + Both faces and non-faces requests to this page require that the us= er is a member of the + admin role. + + + + + + Securing Entities + + + Seam security also makes it possible to apply security restriction= s to read, insert, update and + delete actions for entities. + + + + To secure all actions for an entity class, add a @Restric= t annotation on the class + itself: + + + + + + If no expression is specified in the @Restrict = annotation, the default security check + that is performed is a permission check of entity:action<= /literal>, where the permission target = + is the entity instance, and the action is eithe= r read, insert, = + update or delete. + + + + It is also possible to only restrict certain actions, by placing a= @Restrict annotation + on the relevent entity lifecycle method (annotated as follows): + + + + + + @PostLoad - Called after an entity instance= is loaded from the database. Use this + method to configure a read permission. + + + + + @PrePersist - Called before a new instance = of the entity is inserted. Use this method + to configure an insert permission. + + + + + @PreUpdate - Called before an entity is upd= ated. Use this method + to configure an update permission. + + + + + @PreRemove - Called before an entity is del= eted. Use this method + to configure a delete permission. + + + + + + Here's an example of how an entity would be configured to perform = a security check for any insert + operations. Please note that the method is not required to do any= thing, the only important thing in regard to + security is how it is annotated: + + + + + + Using <literal>/META-INF/orm.xml</literal> + = + + + You can also specify the call back method in /META-IN= F/orm.xml: + + + + + + + + + +]]> + + + Of course, you still need to annotate the prePersist(= ) + method on Customer with @Restrict<= /literal> + + + + + And here's an example of an entity permission rule that checks if = the authenticated user is allowed to insert + a new MemberBlog record (from the seamspace exa= mple). The entity for which the security + check is being made is automatically inserted into the working mem= ory (in this case MemberBlog): + + + (member.getUsername().equals(p= rincipal.getName()))) + check: PermissionCheck(target =3D=3D memberBlog, action =3D=3D "insert",= granted =3D=3D false) +then + check.grant(); +end;]]> + + + This rule will grant the permission memberBlog:insert if the currently authenticated + user (indicated by the Principal fact) has the= same name as the member for which the + blog entry is being created. The "principal: Principal(= )" structure that can be seen in the + example code is a variable binding - it binds the instance of the= Principal object from the + working memory (placed there during authentication) and assigns i= t to a variable called principal. + Variable bindings allow the value to be referred to in other plac= es, such as the following line which compares the = + member's username to the Principal name. For = more details, please refer to the JBoss Rules documentation. + + + + Finally, we need to install a listener class that integrates Seam= security with + your JPA provider. + + + + Entity security with JPA + + + Security checks for EJB3 entity beans are performed with an EntityListener. + You can install this listener by using the following ME= TA-INF/orm.xml file: + + + + + + + + + + + + + +]]> + + + + + Entity security with a Managed Hibernate Session + + + If you are using a Hibernate SessionFactory c= onfigured via Seam, + and are using annotations, or orm.xml, then y= ou don't + need to do anything special to use entity security. + + + + + + = + + Typesafe Permission Annotations + = + + Seam provides a number of annotations that may be used as an alter= native to @Restrict, which have + the added advantage of providing compile-time safety as they don't= support arbitrary EL expressions in the same way = + that @Restrict does. + + = + + Out of the box, Seam comes with annotations for standard CRUD-base= d permissions, however it is a simple matter to = + add your own. The following annotations are provided in the org.jboss.seam.annotations.security package: + + = + + + @Insert + + + @Read + + + @Update + + + @Delete + + + = + + To use these annotations, simply place them on the method or param= eter 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: + + = + + = + + In this example, a permission check will be performed for the user= to ensure that they have the rights to create + new Customer objects. The target of the permis= sion check will be Customer.class + (the actual java.lang.Class instance itself), a= nd the action is the lower case representation of the = + annotation name, which in this example is insert. + + = + + It is also possible to annotate the parameters of a component meth= od in the same way. If this is done, then it is + not required to specify a permission target (as the parameter valu= e itself will be the target of the permission check): + + = + + = + + To create your own security annotation, you simply need to annotat= e it with @PermissionCheck, for example: + + = + + + + 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 @PermissionC= heck annotation: + + = + + = + + = + + Typesafe Role Annotations = + = + + In addition to supporting typesafe permission annotation, Seam Sec= urity also provides typesafe role annotations that + allow you to restrict access to component methods based on the rol= e memberships of the currently authenticated user. + Seam provides one such annotation out of the box, org.jbo= ss.seam.annotations.security.Admin, used + to restrict access to a method to users that are a member of the <= literal>admin role (so long as your = + own application supports such a role). To create your own role an= notations, simply meta-annotate them with + org.jboss.seam.annotations.security.RoleCheck, = like in the following example: + + = + + + + Any methods subsequently annotated with the @User annotation as shown in the above example + will be automatically intercepted and the user checked for the mem= bership of the corresponding role name + (which is the lower case version of the annotation name, in this c= ase user). + + = + + = + + The Permission Authorization Model + = + + Seam Security provides an extensible framework for resolving appli= cation permissions. The following class diagram + shows an overview of the main components of the permission framewo= rk: + + + + + + + + + + = + = + + The relevant classes are explained in more detail in the following= sections. + + = + + PermissionResolver + = + + This is actually an interface, which provides methods for resolv= ing individual object permissions. Seam provides + the following built-in PermissionResolver imp= lementations, which are described in more detail later + in the chapter: + + = + + + RuleBasedPermissionResolver - This pe= rmission resolver uses Drools to resolve rule-based + permission checks. + + + PersistentPermissionResolver - This p= ermission resolver stores object permissions in a + persistent store, such as a relational database. + + + = + + Writing your own PermissionResolver + + + It is very simple to implement your own permission resolver. = The PermissionResolver + interface defines only two methods that must be implemented, a= s shown by the following table. By deploying + your own PermissionResolver implementation = in your Seam project, it will be automatically + scanned during deployment and registered with the default ResolverChain. + = + = + + PermissionResolver interface + = + + + + + + = + + + + Return type + + + Method + + + Description + + + + = + + = + + + + boolean + + + + + hasPermission(Object target, String action)= + + + + + This method must resolve whether the currently authe= nticated user (obtained via a call to + Identity.getPrincipal()) has the = permission specified by the target + and action parameters. It should= return true if the user has + the permission, or false if they = don't. + + + = + + + + + void + + + + + filterSetByAction(Set<Object> targets= , String action) + + + + + This method should remove any objects from the speci= fied set, that would = + return true if passed to the hasPermission() method with the = + same action parameter value. + + + = + = + + +
= + = + + + As they are cached in the user's session, any custom PermissionResolver = + implementations must adhere to a couple of restrictions. Fi= rstly, they may not contain any = + state that is finer-grained than session scope (and the scop= e 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 simu= ltaneously. In fact, for + performance reasons it is recommended that they are annotate= d with = + @BypassInterceptors to bypass Seam's inte= rceptor stack altogether. + + + = +
+
+ = + + ResolverChain + = + + A ResolverChain contains an ordered list of <= literal>PermissionResolvers, for the + purpose of resolving object permissions for a particular object = class or permission target. + + = + + The default ResolverChain consists of all per= mission resolvers discovered during + application deployment. The org.jboss.seam.security.de= faultResolverChainCreated + event is raised (and the ResolverChain instan= ce passed as an event parameter) = + when the default ResolverChain is created. T= his allows additional resolvers that + for some reason were not discovered during deployment to be adde= d, or for resolvers that are in the = + chain to be re-ordered or removed. + + = + + 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 s:hasPermis= sion EL function, or via an API + call to Identity.checkPermission: + + = + + + + + + + + = + = + + + + 1. A permission check is initiated somewhere (either in code= or via an EL + expression) resulting in a call to Identity.hasPerm= ission(). + = + + + + 1.1. Identity invokes = + PermissionMapper.resolvePermission(), pas= sing in the + permission to be resolved. + + + + + 1.1.1. PermissionMapper maintains a Map of = + ResolverChain instances, keyed by class. = It uses this map + to locate the correct ResolverChain for t= he permission's + target object. Once it has the correct ResolverCha= in, it + retrieves the list of PermissionResolvers= it contains via + a call to ResolverChain.getResolvers(). + + + + + 1.1.2. For each PermissionResolver in the= ResolverChain, + the PermissionMapper invokes its hasPermission() method, + passing in the permission instance to be checked. If any of= the PermissionResolvers + return true, then the permission check ha= s succeeded and the = + PermissionMapper also returns tr= ue to Identity. + If none of the PermissionResolvers return= true, then the permission check + has failed. + + = + + + = +
+ + + RuleBasedPermissionResolver + = + + One of the built-in permission resolvers provided by Seam, RuleBasedPermissionResolver = + 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 fo= r the business logic that is used to + evaluate user permissions, and 2) speed - Drools uses very efficie= nt algorithms for evaluating large = + numbers of complex rules involving multiple conditions. = + + = + + Requirements + = + + If using the rule-based permission features provided by Seam Sec= urity, the following jar files are required by Drools + to be distributed with your project: + + = + + + drools-api.jar + + + drools-compiler.jar + + + drools-core.jar + + + drools-decisiontables.jar + + + drools-templates.jar + + + janino.jar + + + antlr-runtime.jar + + + mvel2.jar + + + = + = + = + + Configuration + = + + The configuration for RuleBasedPermissionResolver requires that a Drools rule base is first + configured in components.xml. By default, it= expects that the rule base is named + securityRules, as per the following example: = = + + = + + = + + + /META-INF/security.drl + + + = + ]]> + = + + The default rule base name can be overridden by specifying the <= literal>security-rules = + property for RuleBasedPermissionResolver: + + = + ]]> + + + Once the RuleBase component is configured, it= 's time to write the security rules. + = + + = + + Writing Security Rules + = + + The first step to writing security rules is to create a new rule= file in the /META-INF + directory of your application's jar file. Usually this file wou= ld be named something like = + security.drl, however you can name it whateve= r you like as long as it is configured + correspondingly in components.xml. + + = + + So what should the security rules file contain? At this stage i= t might be a good idea to at least skim + through the Drools documentation, however to get started here's = an extremely simple example: + + = + + = + + Let's break this down step by step. The first thing we see is t= he package declaration. A package in Drools + is essentially a collection of rules. The package name can be a= nything you want - it doesn't relate + to anything else outside the scope of the rule base. + + = + + The next thing we can notice is a couple of import statements fo= r the PermissionCheck + and Role classes. These imports inform the ru= les engine that we'll be referencing + these classes within our rules. + + = + + Finally we have the code for the rule. Each rule within a packa= ge should be given a unique name (usually + describing the purpose of the rule). In this case our rule is c= alled CanUserDeleteCustomers + and will be used to check whether a user is allowed to delete a = customer record. + + = + + Looking at the body of the rule definition we can notice two dis= tinct 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 when 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 + then section. The end of the rule is denoted= by the end line. + + = + + If we look at the LHS of the rule, we see two conditions listed = there. Let's examine the first condition: + + = + + = + + In plain english, this condition is stating that there must exis= t a PermissionCheck object + with a target property equal to "customer", a= nd an action property equal + to "delete" within the working memory. + + = + + 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 informat= ion that is required by the rules engine to = + make a decision about a permission check. Each time the hasPermission() method is called, = + a temporary PermissionCheck object, or Fact, is inserted into the = + working memory. This PermissionCheck corresp= onds exactly to the permission that is being = + checked, so for example if you call hasPermission("acco= unt", "create") then a = + PermissionCheck object with a target= equal to "account" and = + action equal to "create" will be inserted int= o the working memory for the duration of the = + permission check. + + = + + Besides the PermissionCheck facts, there is a= lso a org.jboss.seam.security.Role + fact for each of the roles that the authenticated user is a memb= er of. These Role facts = + are synchronized with the user's authenticated roles at the begi= nning of every permission check. As a consequence, = + any Role object that is inserted into the wor= king memory during the course of a permission + check will be removed before the next permission check occurs, i= f the authenticated user is not actually a member of + that role. Besides the PermissionCheck and <= literal>Role facts, the working + memory also contains the java.security.Principal object that was created as a result of + the authentication process. = + + = + + It is also possible to insert additional long-lived facts into t= he working memory by calling = + RuleBasedPermissionResolver.instance().getSecurityConte= xt().insert(), + passing the object as a parameter. The exception to this is Role objects, which as + already discussed are synchronized at the start of each permissi= on check. + + = + + Getting back to our simple example, we can also notice that the = first line of our LHS is prefixed with + c:. This is a variable binding, and is used = to refer back to the object that is + matched by the condition (in this case, the PermissionC= heck). Moving on to the = + second line of our LHS, we see this: + + = + + = + + This condition simply states that there must be a Role<= /literal> object with a = + name of "admin" within the working memory. A= s already mentioned, user roles are inserted into = + the working memory at the beginning of each permission check. S= o, putting both conditions together, this = + rule is essentially saying "I will fire if you are checking for = the customer:delete = + permission and the user is a member of the admin role". + + = + + So what is the consequence of the rule firing? Let's take a loo= k at the RHS of the rule: + + = + + = + + The RHS consists of Java code, and in this case is invoking the = grant() + method of the c object, which as already ment= ioned is a variable binding + for the PermissionCheck object. Besides the = name and + action properties of the PermissionC= heck object, there + is also a granted property which is initially= set to false. + Calling grant() on a PermissionCheck= sets the + granted property to true, = which means that the permission + check was successful, allowing the user to carry out whatever ac= tion the permission check was + intended for. + + + = + + Non-String permission targets + = + + So far we have only seen permission checks for String-literal pe= rmission 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 comm= ents. The following rule demonstrates + how this may be expressed, by requiring the target of the permis= sion check to be an instance of + MemberBlog, and also requiring that the curre= ntly authenticated user is a member of the + user role: + + = + = + = + + + + Wildcard permission checks + + + It is possible to implement a wildcard permission check (which a= llows all actions for a given permission + target), by omitting the action constraint fo= r the PermissionCheck in + your rule, like this: + + + + + + This rule allows users with the admin role to= perform any action for + any customer permission check. + = + = + + = + + = + + PersistentPermissionResolver + = + + Another built-in permission resolver provided by Seam, Pe= rsistentPermissionResolver + 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, arb= itrarily-named permission targets (not = + necessarily object/class based) to be assigned in the same way. + + = + + Configuration + + + Before it can be used, PersistentPermissionResolver must be configured with a + valid PermissionStore in components.= xml. If not configured, + it will attempt to use the default permission store, Jp= aIdentityStore (see section + further down for details). To use a permission store other than= the default, configure the + permission-store property as follows: + = + = + ]]> + = + + = + + Permission Stores + = + + A permission store is required for PersistentPermission= Resolver to connect to the + backend storage where permissions are persisted. Seam provides = one PermissionStore + implementation out of the box, JpaPermissionStore, which is used to store + permissions inside a relational database. It is possible to wri= te your own permission store + by implementing the PermissionStore interface= , which defines the following + methods: + + = + + PermissionStore interface + = + + + + + = + + + + Return type + + + Method + + + Description + + + + = + + = + + + + List<Permission> + + + + + listPermissions(Object target) + + + + + This method should return a List of= Permission objects = + representing all the permissions granted for the speci= fied target object. + + + = + + + + + List<Permission> + + + + + listPermissions(Object target, String action)= + + + + + This method should return a List of= Permission objects = + representing all the permissions with the specified ac= tion, granted for the specified target object. + + + = + = + + + + List<Permission> + + + + + listPermissions(Set<Object> targets, St= ring action) + + + + + This method should return a List of= Permission objects = + representing all the permissions with the specified ac= tion, granted for the specified set of + target objects. + + + = + = + + + + boolean + + + + + grantPermission(Permission) + + + + + This method should persist the specified Perm= ission object to the backend + storage, returning true if successful. + + + = + = + + + + boolean + + + + + grantPermissions(List<Permission> permi= ssions) + + + + + This method should persist all of the Permiss= ion objects contained in the + specified List, returning true if s= uccessful. + + + = + = + + + + boolean + + + + + revokePermission(Permission permission) + + + + + This method should remove the specified Permi= ssion object from persistent storage. + + + = + = + + + + boolean + + + + + revokePermissions(List<Permission> perm= issions) + + + + + This method should remove all of the Permissi= on objects in the specified list + from persistent storage. + + + = + = + + + + List<String> + + + + + listAvailableActions(Object target) + + + + + 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 wi= th permission management to build the user + interface for granting specific class permissions (see= section further down). + + + = + + +
+ = +
+ = + + JpaPermissionStore + = + + This is the default PermissionStore implement= ation (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. + + = + + If you wish to use the same entity (i.e. a single database table= ) to store both user and role permissions, then + only the user-permission-class property is re= quired to be configured. If you wish to use + separate tables for storing user and role permissions, then in a= ddition to the user-permission-class + property you must also configure the role-permission-cl= ass property. + + = + For example, to configure a single entity class to store bot= h user and role permissions: + = + ]]> + = + To configure separate entity classes for storing user and ro= le permissions: + = + ]]> = + = + + Permission annotations + = + + As mentioned, the entity classes that contain the user and rol= e permissions must be configured with a + special set of annotations, contained within the org.= jboss.seam.annotations.security.permission package. + The following table lists each of these annotations along with= a description of how they are used: + + = + + Entity Permission annotations + = + + + + + = + + + + Annotation + + + Target + + + Description + + + + = + + = + + + + @PermissionTarget + + + + + FIELD,METHOD + + + + + This annotation identifies the property of the entit= y that will contain the permission target. The property + should be of type java.lang.String. + + + = + = + + + + @PermissionAction + + + + + FIELD,METHOD + + + + + This annotation identifies the property of the entit= y that will contain the permission action. The property + should be of type java.lang.String. + + + = + = + + + + @PermissionUser + + + + + FIELD,METHOD + + + + + This annotation identifies the property of the entit= y that will contain the recipient user for the permission. It should + be of type java.lang.String and c= ontain the user's username. + + + = + = + + + + @PermissionRole + + + + + FIELD,METHOD + + + + + This annotation identifies the property of the entit= y that will contain the recipient role for the permission. It should + be of type java.lang.String and c= ontain the role name. + + + = + = + + + + @PermissionDiscriminator + + + + + FIELD,METHOD + + + + + 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 discrimin= ate between user and role permissions. By default, if the column + value contains the string literal user, then the record will be treated as a user permission. If it + contains the string literal role,= then it will be treated as a role permission. It is also possible + to override these defaults by specifying the userValue and roleValue properties + within the annotation. For example, to use u and r instead of user + and role, the annotation would be= written like this: + + = + + + = + = + + +
= + = +
+ = + + Example Entity + = + + Here is an example of an entity class that is used to store bo= th user and role permissions. The following class can be found + inside the SeamSpace example: + + = + + = + + As can be seen in the above example, the getDiscrimin= ator() method has been annotated + with the @PermissionDiscriminator annotatio= n, to allow JpaPermissionStore to + determine which records represent user permissions and which r= epresent role permissions. In addition, it + can also be seen that the getRecipient() me= thod is annotated with both = + @PermissionUser and @PermissionRol= e annotations. This is perfectly valid, + and simply means that the recipient propert= y of the entity will either contain the name + of the user or the name of the role, depending on the value of= the discriminator property. + + = + + = + + Class-specific Permission Configuration + = + + A further set of class-specific annotations can be used to con= figure a specific set of allowable permissions + for a target class. These permissions can be found in the org.jboss.seam.annotation.security.permission + package: + + = + + Class Permission Annotations + = + + + + + = + + + + Annotation + + + Target + + + Description + + + + = + + = + + + + @Permissions + + + + + TYPE + + + + + A container annotation, this annotation may contain = an array of @Permission annotations. + + + = + = + + + + @Permission + + + + + TYPE + + + + + This annotation defines a single allowable permissio= n action for the target class. Its action + property must be specified, and an optional mask property may also be specified if permission + actions are to be persisted as bitmasked values (see= next section). + + + + = + + +
+ = + + Here's an example of the above annotations in action. The fol= lowing class can also be found in the SeamSpace example: + + = + + + + This example demonstrates how two allowable permission actions= , view and comment = + can be declared for the entity class MemberImage. + + = +
+ = + + Permission masks + = + + By default, multiple permissions for the same target object an= d recipient will be persisted as a single database record, + with the action property/column containing = a comma-separated list of the granted actions. To reduce + the amount of physical storage required to persist a large num= ber of permissions, it is possible to use a bitmasked + integer value (instead of a comma-separated list) to store the= list of permission actions. + + = + + For example, if recipient "Bob" is granted both the v= iew and comment permissions + for a particular MemberImage (an entity bea= n) instance, then by default the action property of the + permission entity will contain "view,comment", representing the two granted permission actions. = + Alternatively, if using bitmasked values for the permission ac= tions, as defined like so: + + = + = = + + + The action property will instead simply con= tain "3" (with both the 1 bit and 2 bit switched on). Obviously + for a large number of allowable actions for any particular tar= get class, the storage required for the permission records + is greatly reduced by using bitmasked actions. + + = + + Obviously, it is very important that the mask values specified are powers of 2. + + + = + + Identifier Policy + = + + When storing or looking up permissions, JpaPermission= Store must be able to uniquely identify specific + object instances to effectively operate on its permissions. T= o achieve this, an identifier strategy = + may be assigned to each target class for the generation of uni= que 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. + + = + + The IdentifierStrategy interface is very si= mple, declaring only two methods: + + = + + + + The first method, canIdentify() simply retu= rns true if the identifier strategy + is capable of generating a unique identifier for the specified= target class. The second method, = + getIdentifier() returns the unique identifi= er value for the specified target object. + + = + + Seam provides two IdentifierStrategy implem= entations, ClassIdentifierStrategy + and EntityIdentifierStrategy (see next sect= ions for details). + + = + + To explicitly configure a specific identifier strategy to use = for a particular class, it should be annotated with + org.jboss.seam.annotations.security.permission.Identi= fier, and the value should be set to + a concrete implementation of the IdentifierStrategy interface. An optional name + property can also be specified, the effect of which is depende= nt upon the actual IdentifierStrategy + implementation used. + + + = + + ClassIdentifierStrategy + = + + This identifier strategy is used to generate unique identifier= s for classes, and will use the value of the = + name (if specified) in the @Identi= fier annotation. If there is no + name property provided, then it will attemp= t to use the component name of the class + (if the class is a Seam component), or as a last resort it wil= l create an identifier based on the name + of the class (excluding the package name). For example, the i= dentifier for the following class will + be "customer": + + = + + = + + The identifier for the following class will be "custo= merAction": + + = + + = + + Finally, the identifier for the following class will be "Customer": + + = + + = + + = + + EntityIdentifierStrategy + = + + This identifier strategy is used to generate unique identifier= s for entity beans. It does so by + concatenating the entity name (or otherwise configured name) w= ith a string representation of the + primary key value of the entity. The rules for generating the= name section of the identifier are = + similar to ClassIdentifierStrategy. The pr= imary key value (i.e. the = + id of the entity) is obtained using the <= literal>PersistenceProvider + component, which is able to correctly determine the value rega= rdless of which persistence implementation + is used within the Seam application. For entities not annotat= ed with @Entity, it is + necessary to explicitly configure the identifier strategy on t= he entity class itself, for example: + + = + + = + + For an example of the type of identifier values generated, ass= ume we have the following entity class: + + = + + + + For a Customer instance with an id= value of 1, + the value of the identifier would be "Customer:1". If the entity class is annotated + with an explicit identifier name, like so: + + = + + + + Then a Customer with an id value of 123 + would have an identifier value of "cust:123= ". + + + = +
= + = +
+ +
+ = + + Permission Management + = + + In much the same way that Seam Security provides an Identity Managem= ent API for the management of users and roles, + it also provides a Permissions Management API for the management of = persistent user permissions, via the + PermissionManager component. + + = + + PermissionManager + = + + The PermissionManager component is an applicati= on-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 JpaPermissionStore if it is available). To explicitly configure a + custom permission store, specify the permission-store property in components.xml: + + = + = = + ]]> + = + + The following table describes each of the available methods provid= ed by PermissionManager: = + + = + + PermissionManager API methods + = + + + + + = + + + + Return type + + + Method + + + Description + + + + = + + = + + + + List<Permission> + + + + + listPermissions(Object target, String action) + + + + + Returns a list of Permission objects = representing all of the permissions that + have been granted for the specified target and action. + + + = + = + + + + List<Permission> + + + + + listPermissions(Object target) + + + + + Returns a list of Permission objects = representing all of the permissions that + have been granted for the specified target and action. + + + = + = + + + + boolean + + + + + grantPermission(Permission permission) + + + + + Persists (grants) the specified Permission to the backend permission store. = + Returns true if the operation was successful. + + + = + = + + + + boolean + + + + + grantPermissions(List<Permission> permiss= ions) + + + + + Persists (grants) the specified list of Permiss= ions to the backend permission store. = + Returns true if the operation was successful. + + + = + = + + + + boolean + + + + + revokePermission(Permission permission) + + + + + Removes (revokes) the specified Permission from the backend permission store. = + Returns true if the operation was successful. + + + = + = + + + + boolean + + + + + revokePermissions(List<Permission> permis= sions) + + + + + Removes (revokes) the specified list of Permiss= ions from the backend permission store. = + Returns true if the operation was successful. + + + = + = + + + + List<String> + + + + + listAvailableActions(Object target) + + + + + Returns a list of the available actions for the specifie= d target object. The actions that this + method returns are dependent on the @Permission= annotations configured on the = + target object's class. + + + + = + + +
+ = +
+ = + + Permission checks for PermissionManager operations + = + + Invoking the methods of PermissionManager requi= res that the currently-authenticated user + has the appropriate authorization to perform that management opera= tion. The following table lists the required + permissions that the current user must have. + + = + + Permission Management Security Permissions + + + + + + + + + Method + + + Permission Target + + + Permission Action + + + + + + + + + listPermissions() + + + + + The specified target + + + + + seam.read-permissions + + + + = + + + + grantPermission() + + + + + The target of the specified Permission, or each of the targets + for the specified list of Permissions= (depending on which method is + called). + + + + + seam.grant-permission + + + + = + + + + grantPermission() + + + + + The target of the specified Permission. + + + + + seam.grant-permission + + + + = + + + + grantPermissions() + + + + + Each of the targets of the specified list of Pe= rmissions. + + + + + seam.grant-permission + + + + = + + + + revokePermission() + + + + + The target of the specified Permission. + + + + + seam.revoke-permission + + + + = + + + + revokePermissions() + + + + + Each of the targets of the specified list of Pe= rmissions. + + + + + seam.revoke-permission + + + + = + + +
+
+ = +
+ + + SSL Security + + + Seam includes basic support for serving sensitive pages via the HTTP= S protocol. This is easily + configured by specifying a scheme for the page in= pages.xml. + The following example shows how the view /login.xhtml is configured to use + HTTPS: + + + ]]> + + + This configuration is automatically extended to both s:link= and + s:button JSF controls, which (when specifying the= view) + will also render the link using the correct protocol. Based on the = previous example, the following + link will use the HTTPS protocol because /login.xhtml is configured to use it: + + + ]]> + + + Browsing directly to a view when using the incorrect protocol will cause a + redirect to the same view using the correct pro= tocol. For example, browsing + to a page that has scheme=3D"https" using HTTP wi= ll cause a redirect to the same + page using HTTPS. + + + + It is also possible to configure a default scheme 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 acc= essed 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 scheme, add this line to pages.x= ml: + + + ]]> + + + Of course, if none of the pages in your applica= tion use HTTPS then it is not + required to specify a default scheme. + + + + You may configure Seam to automatically invalidate the current HTTP = session each time the scheme + changes. Just add this line to components.xml: + + + ]]> + + + This option helps make your system less vulnerable to sniffing of th= e session id or leakage of + sensitive data from pages using HTTPS to other pages using HTTP. + + = + + Overriding the default ports + = + + If you wish to configure the HTTP and HTTPS ports manually, they m= ay be configured in = + pages.xml by specifying the http-port<= /literal> and + https-port attributes on the pages element: + + = + = + ]]> + + + + + + CAPTCHA + + + Though strictly not part of the security API, Seam provides a built-= in CAPTCHA (Completely + Automated Public Turing test to tell + Computers and Humans Apart) algorithm to + prevent automated processes from interacting with your application. + + + + Configuring the CAPTCHA Servlet + + To get up and running, it is necessary to configure the Seam Resou= rce Servlet, which will provide the Captcha + challenge images to your pages. This requires the following entry= in web.xml: + + + + Seam Resource Servlet + org.jboss.seam.servlet.SeamResourceServlet + + + + Seam Resource Servlet + /seam/resource/* +]]> + + + + + Adding a CAPTCHA to a form + + + Adding a CAPTCHA challenge to a form is extremely easy. Here's an = example: + + + + + + +]]> + + + That's all there is to it. The graphicImage co= ntrol displays the CAPTCHA challenge, + and the inputText receives the user's response.= The response is automatically + validated against the CAPTCHA when the form is submitted. + + + + + + Customising the CAPTCHA algorithm + + + You may customize the CAPTCHA algorithm by overriding the built-in= component: + + + + + + + + + + Security Events + + + The following table describes a number of events (see ) raised by Seam Security + in response to certain security-related events. + + + + Security Events + + + + + + + + + Event Key + + + Description + + + + + + + + + + org.jboss.seam.security.loginSuccessful + + + + + Raised when a login attempt is successful. + + + + + + + org.jboss.seam.security.loginFailed + + + + + Raised when a login attempt fails. + + + + + + + org.jboss.seam.security.alreadyLoggedIn + + + + + Raised when a user that is already authenticated attempts = to log in again. + + + = + + + + org.jboss.seam.security.notLoggedIn + + + + + Raised when a security check fails when the user is not lo= gged in. + + + + + + + org.jboss.seam.security.notAuthorized + + + + + Raised when a security check fails when the user is logged= in however doesn't have sufficient privileges. + + + + + + + org.jboss.seam.security.preAuthenticate + + + + + Raised just prior to user authentication. + + + + + + + org.jboss.seam.security.postAuthenticate + + + + + Raised just after user authentication. + + + + + + + org.jboss.seam.security.loggedOut + + + + + Raised after the user has logged out. + + + + + + + org.jboss.seam.security.credentialsUpdated + + + + + Raised when the user's credentials have been changed. + + + + + + + org.jboss.seam.security.rememberMe + + + + + Raised when the Identity's rememberMe property is changed. + + + + + + +
+ +
+ = + + Run As + = + + Sometimes it may be necessary to perform certain operations with e= levated privileges, such + as creating a new user account as an unauthenticated user. Seam S= ecurity supports such a + mechanism via the RunAsOperation class. This c= lass allows either the + Principal or Subject, or the= user's roles to be + overridden for a single set of operations. + + = + + The following code example demonstrates how RunAsOperation<= /literal> is used, by + calling its addRole() method to provide a set of = roles to masquerade + as for the duration of the operation. The execute() method contains the + code that will be executed with the elevated privileges. + + = + + = + + In a similar way, the getPrincipal() or getSubject() + methods can also be overriden to specify the Principal and = + Subject instances to use for the duration of th= e operation. + Finally, the run() method is used to carry out = the = + RunAsOperation. + + + + + + Extending the Identity component + + + 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 Credentials component instead) = shows an extended Identity = + component with an additional companyCode field. = The install precendence of APPLICATION + ensures that this extended Identity gets installed in preference to = the built-in Identity. + + + + + + + Note that an Identity component must be marked = @Startup, so that it is + available immediately after the SESSION context= begins. Failing to do this may render + certain Seam functionality inoperable in your application. + + + + + + = + = + + OpenID + = + + OpenID is a community standard for external web-based authenti= cation. The basic + idea is that any web application can supplement (or replace) i= ts local handling of + authentication by delegating responsibility to an external Ope= nID server of the user's + chosing. This benefits the user, who no longer has to remembe= r a name and password for = + every web application he uses, and the developer, who is relie= ved of some of the burden of = + maintaining a complex authentication system. = + + = + 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 http://maximoburrito.myopenid.com however, + it's acceptable to leave off the http:// pa= rt of the identifier when logging into a site. The web application + (known as a relying party in OpenID-speak) determines which Op= enID 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. + + = + + It's important to realize at this + point that authentication does not imply authorization. The w= eb application still needs to make a determination of how to = + use that information. The web application could treat the use= r as instantly logged in and give full access to the system or + it could try and map the presented OpenID to a local user acco= unt, prompting the user to register if he hasn't already. + The choice of how to handle the OpenID is left as a design dec= ision for the local application. = + + + = + + Configuring OpenID + + Seam uses the openid4java package and requires four additi= onal JARs to make use of the Seam integration. These = + are: htmlparser.jar, openid4ja= va.jar, openxri-client.jar = + and openxri-syntax.jar. + + = + + OpenID processing requires the use of the OpenIdP= haseListener, which should be added to your = + faces-config.xml file. The phase liste= ner processes the callback from the OpenID provider, allowing + re-entry into the local application. + + = + <lifecycle> + <phase-listener>org.jboss.seam.security.openid.OpenIdPhaseListen= er</phase-listener> +</lifecycle> + + = + + With this configuration, OpenID support is available to yo= ur application. + The OpenID support component, org.jboss.seam.secu= rity.openid.openid, is installed automatically if the openid4java + classes are on the classpath. + + + = + + Presenting an OpenIdDLogin form + = + + To initiate an OpenID login, you can present a simply for= m to the user asking for the user's OpenID. The #{openid.id} = + value = + accepts the user's OpenID and the #{openid.login= } action initiates an authentication request. + + <h:form> + <h:inputText value=3D"#{openid.id}" /> + <h:commandButton action=3D"#{openid.login}" value=3D"= ;OpenID Login"/> +</h:form> = + = + + When the user submits the login form, he will be redirecte= d to his OpenID provider. The user will eventually = + return to your application through the Seam pseudo-view /openid.xhtml, which is + provided by the OpenIdPhaseListener. Yo= ur application can handle the OpenID response by means = + of a pages.xml navigation from that vie= w, just as if the user had never left your application. + + + = + + Logging in immediately + = + The simplest strategy is to simply login the user immediately. = The following navigation rule shows how to handle this using + the #{openid.loginImmediately()} action. + + = + <page view-id=3D"/openid.xhtm= l"> + <navigation evaluate=3D"#{openid.loginImmediately()}"> + <rule if-outcome=3D"true"> + <redirect view-id=3D"/main.xhtml"> + <message>OpenID login successful...</message> + </redirect> + </rule> + <rule if-outcome=3D"false"> + <redirect view-id=3D"/main.xhtml"> + <message>OpenID login rejected...</message> + </redirect> + </rule> + </navigation> +</page> = + = + Thie loginImmediately() 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 l= ogged in (i.e. #{identity.loggedIn} 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 #{openid.validatedId} and = + #{openid.valid} will be true. + + + + + = + + Deferring login + = + + You may not want the user to be immediately logged in to y= our application. In that case, your navigation + should check the #{openid.valid} proper= ty and redirect the user to a local registration or processing + page. Actions you might take would be asking for more inf= ormation and creating a local user account or presenting a captcha = + to avoid programmatic registrations. When you are done pr= ocessing, if you want to log the user in, you can call + the loginImmediately method, either thr= ough EL as shown previously or by directly interaction with the = + org.jboss.seam.security.openid.OpenId c= omponent. Of course, nothing prevents you from writing custom = + code to interact with the Seam identity component on your = own for even more customized behaviour. + + = + + = + = + + Logging out + = + + Logging out (forgetting an OpenID association) is done by = calling #{openid.logout}. If you + are not using Seam security, you can call this method dire= ctly. If you are using Seam security, you should + continue to use #{identity.logout} and = install an event handler to capture the logout event, calling = + the OpenID logout method. + = + + <event type=3D"org.jboss= .seam.security.loggedOut"> + <action execute=3D"#{openid.logout}" /> +</event> + = + It's important that you do not leave this out or the use= r will not be able to login again in the same session. + + + + = + = + + = + = +
Property changes on: modules/security/trunk/docs/en-US/security-general.xml ___________________________________________________________________ Name: svn:executable + * --===============2502031146515175342==--