[jboss-cvs] jboss-seam/doc/reference/en/modules ...

Shane Bryzak Shane_Bryzak at symantec.com
Tue Jan 30 08:14:10 EST 2007


  User: sbryzak2
  Date: 07/01/30 08:14:10

  Modified:    doc/reference/en/modules  security.xml
  Log:
  documented security rules
  
  Revision  Changes    Path
  1.11      +187 -155  jboss-seam/doc/reference/en/modules/security.xml
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: security.xml
  ===================================================================
  RCS file: /cvsroot/jboss/jboss-seam/doc/reference/en/modules/security.xml,v
  retrieving revision 1.10
  retrieving revision 1.11
  diff -u -b -r1.10 -r1.11
  --- security.xml	30 Jan 2007 07:30:13 -0000	1.10
  +++ security.xml	30 Jan 2007 13:14:10 -0000	1.11
  @@ -112,8 +112,9 @@
         <para>
           The <literal>Identity</literal> component provides both <literal>username</literal> and <literal>password</literal>
           properties, catering for the most common authentication scenario. These properties can be bound directly to the
  -        username and password fields on a login form.  Once these properties are set, the <literal>identity.login()</literal>
  -        method will authenticate the user using the provided credentials.  Here's an example of a simple login form:
  +        username and password fields on a login form.  Once these properties are set, calling the 
  +        <literal>identity.login()</literal> method will authenticate the user using the provided credentials.  
  +        Here's an example of a simple login form:
         </para>
   
         <programlisting>
  @@ -133,12 +134,18 @@
       </div>
           ]]>
         </programlisting>
  +      
  +      <para>
  +        Similarly, logging out the user is done by calling <literal>#{identity.logout}</literal>. Calling this
  +        action will clear the security state of the currently authenticated user.
  +      </para>
  +      
       </sect2>
   
       <sect2>
         <title>Summary</title>
         <para>
  -        So to sum up, here are the steps for configuring authentication:
  +        So to sum up, there are the three easy steps to configure authentication:
         </para>
   
         <itemizedlist>
  @@ -164,144 +171,6 @@
     </sect1>
   
     <sect1>
  -    <title>Identity</title>
  -
  -    <para>
  -      The <literal>Identity</literal> component is the core component of the Security API.  It is a session-scoped
  -      component that 1) contains the current state of the user's security, and 2) provides a number of useful
  -      security-related methods.  This section details the most useful features of the <literal>Identity</literal>
  -      component.  Please note that the alias <literal>identity</literal> can be used in EL expressions, including
  -      the body of a web page.
  -    </para>
  -
  -    <sect2>
  -      <title>Obtaining a reference</title>
  -
  -      <para>
  -        There are two ways of obtaining a reference to the <literal>Identity</literal> for the current user's session.
  -        The first, inline method is to simply call <literal>Identity.instance()</literal>.  Alternatively, you may inject
  -        the <literal>Identity</literal> directly into your own components:
  -      </para>
  -
  -      <programlisting>
  -        <![CDATA[
  -  @In Identity identity;
  -        ]]>
  -      </programlisting>
  -    </sect2>
  -
  -    <sect2>
  -      <title>isLoggedIn()</title>
  -      <para>
  -        The <literal>isLoggedIn()</literal> method returns a boolean value indicating whether the user has been
  -        successfully authenticated or not. It may be useful for controlling the rendering of certain sections of a page,
  -        depending if the user is logged in or not.  For example:
  -      </para>
  -
  -      <programlisting>
  -        <![CDATA[
  -    <h:outputLink value="login.seam" rendered="#{not identity.loggedIn}">Log in</h:outputLink>
  -        ]]>
  -      </programlisting>
  -    </sect2>
  -
  -    <sect2>
  -      <title>getSubject()</title>
  -      <para>
  -        The <literal>getSubject()</literal> method returns the <literal>javax.security.auth.Subject</literal> instance
  -        for the user's session.  The subject contains all of an authenticated user's principals.  If
  -        you are authenticating with your own <literal>LoginContext</literal>, it should be instantiated with the
  -        <literal>identity</literal>'s subject, for example:
  -      </para>
  -
  -      <programlisting>
  -        <![CDATA[
  -  LoginContext ctx = new LoginContext("custom", Identity.instance().getSubject());
  -        ]]>
  -      </programlisting>
  -    </sect2>
  -
  -    <sect2>
  -      <title>checkRestriction()</title>
  -      <para>
  -        The <literal>checkRestriction()</literal> method accepts a <literal>java.lang.String</literal> parameter
  -        specifying a security EL expression to evaluate.  If the expression evaluates to <literal>false</literal>,
  -        one of two things happen; 1) if the user is not logged in, a <literal>NotLoggedInException</literal> is
  -        thrown, or 2) if the user is logged in, an <literal>AuthorizationException</literal> is thrown.  EL security
  -        functions are discussed in the Authorization section of this chapter.
  -      </para>
  -
  -      <programlisting>
  -        <![CDATA[
  -  public void deleteCustomer() {
  -    Identity.instance().checkRestriction("#{s:hasPermission('customer', 'delete', customer)}");
  -    //...code
  -  }
  -        ]]>
  -      </programlisting>
  -    </sect2>
  -
  -    <sect2>
  -      <title>login()</title>
  -      <para>
  -        This method attempts to authenticate using the set values of the <literal>username</literal> and
  -        <literal>password</literal> properties.  An overloaded version of this method,
  -        <literal>login(LoginContext ctx)</literal> authenticates using an externally provided
  -        <literal>LoginContext</literal>.  This method throws a <literal>LoginException</literal>
  -        if authentication is not successful.
  -      </para>
  -    </sect2>
  -
  -    <sect2>
  -      <title>logout()</title>
  -      <para>
  -        This method clears the security state for the currently authenticated user.
  -      </para>
  -    </sect2>
  -
  -    <sect2>
  -      <title>hasRole()</title>
  -      <para>
  -        Returns <literal>true</literal> if the authenticated user is a member of the specified role.
  -      </para>
  -
  -      <programlisting>
  -        <![CDATA[
  -  if (!Identity.instance().hasRole("admin"))
  -    throw new AuthorizationException("Insufficient privileges");
  -        ]]>
  -      </programlisting>
  -    </sect2>
  -
  -    <sect2>
  -      <title>hasPermission()</title>
  -      <para>
  -        Returns <literal>true</literal> if the user (either authenticated or not) has the specified permission.
  -        This method accepts an object that can be used to determine if the permission should be granted or not.
  -        The object is temporarily asserted into the security context while the permission check is performed.
  -        If the object is a <literal>java.util.Collection</literal> then each object in the collection is asserted.
  -      </para>
  -
  -      <programlisting>
  -        <![CDATA[
  -  if (!Identity.instance().hasPermission("customer", "delete", customer))
  -    throw new AuthorizationException("Insufficient privileges");
  -        ]]>
  -      </programlisting>
  -    </sect2>
  -
  -    <sect2>
  -      <title>getSecurityContext()</title>
  -      <para>
  -        Returns the session-scoped <literal>org.drools.WorkingMemory</literal> used to evaluate security rules
  -        within the context of the current user.  Additional objects may be asserted into the working memory if
  -        required by the security rules.
  -      </para>
  -    </sect2>
  -
  -  </sect1>
  -
  -  <sect1>
       <title>Authorization</title>
   
       <para>
  @@ -329,7 +198,7 @@
       </sect2>
   
       <sect2>
  -      <title>Securing your components</title>
  +      <title>Securing components</title>
         <para>
           Let's start by examining the simplest form of authorization, component security, starting with the
           <literal>@Restrict</literal> annotation.
  @@ -429,7 +298,7 @@
           <para>
             Sometimes it might be desirable to perform a security check in code, without using the
             <literal>@Restrict</literal> annotation.  In this situation, simply use
  -          <literal>Identity.checkRestriction()</literal>, like this:
  +          <literal>Identity.checkRestriction()</literal> to evaluate a security expression, like this:
           </para>
   
           <programlisting>
  @@ -441,9 +310,11 @@
           </programlisting>
   
           <para>
  -          If the expression specified doesn't evaluate to <literal>true</literal>, an exception is thrown. It is
  -          also possible to call the <literal>hasRole</literal> and <literal>hasPermission</literal> methods
  -          directly:
  +          If the expression specified doesn't evaluate to <literal>true</literal>, either 1) a
  +          <literal>NotLoggedInException</literal> exception is thrown if the user is not logged in, or
  +          2) <literal>AuthorizationException</literal> is thrown if the user is logged in.
  +          It is also possible to call the <literal>hasRole</literal> and <literal>hasPermission</literal> 
  +          methods directly:
           </para>
   
           <programlisting>
  @@ -459,7 +330,7 @@
       </sect2>
       
       <sect2>
  -      <title>Securing your interface</title>
  +      <title>Securing the user interface</title>
         
         <para>
           One indication of a well designed user interface is that the user is not presented with options for 
  @@ -531,11 +402,11 @@
       </sect2>
       
       <sect2>
  -      <title>Securing your pages</title>      
  +      <title>Securing pages</title>      
         <para>
  -        Page security requires that your application is using a <literal>pages.xml</literal> file, however is
  +        Page security requires that the application is using a <literal>pages.xml</literal> file, however is
           extremely simple to configure.  Simply include a <literal>&lt;restrict/&gt;</literal> element within
  -        the <literal>page</literal> element.  By default, if a value is not provided for the
  +        the <literal>page</literal> elements that you wish to secure.  By default, if a value is not provided for the
           <literal>restrict</literal> element, an implied permission of <literal>{viewId}:view</literal> will
           be checked for whenever accessing that page.  Otherwise the value will be evaluated as a standard
           security expression.  Here's a couple of examples:
  @@ -564,11 +435,11 @@
     </sect1>
     
     <sect1>
  -    <title>Authoring Security Rules</title>
  +    <title>Writing Security Rules</title>
       
       <para>
         Up to this point there has been a lot of mention of permissions, but no information about how permissions
  -      are actually defined or granted.  This section completes the circle, by explaining how permission 
  +      are actually defined or granted.  This section completes the picture, by explaining how permission 
         checks are processed, and how to implement permission checks for a Seam application.
       </para>
       
  @@ -576,8 +447,169 @@
         <title>Permissions Overview</title>
         
         <para>
  -        Seam Security provides quite a novel method for determining user permissions. 
  +        So how does the security API know whether a user has the <literal>customer:modify</literal> permission 
  +        for a specific customer?  Seam Security provides quite a novel method for determining user permissions,
  +        based on JBoss Rules.  A couple of the advantages of using a rule engine are 1) a centralized location 
  +        for the business logic that is behind each user permission, and 2) speed - JBoss Rules uses very efficient 
  +        algorithms for evaluating large numbers of complex rules involving multiple conditions.
  +      </para>            
  +      
  +    </sect2>
  +    
  +    <sect2>
  +      <title>Configuring a rules file</title>
  +      
  +      <para>
  +        Seam Security expects to find a <literal>RuleBase</literal> component called <literal>securityRules</literal>
  +        which it uses to evaluate permission checks.  This is configured in <literal>pages.xml</literal> as follows:
  +      </para>
  +      
  +      <programlisting>
  +        <![CDATA[
  +    <component class="org.jboss.seam.drools.RuleBase" name="securityRules">
  +        <property name="ruleFiles">/META-INF/security-rules.drl</property>
  +    </component>        
  +        ]]>
  +      </programlisting>
  +      
  +      <para>
  +        Once the <literal>RuleBase</literal> component is configured, it's time to write the security rules.
  +      </para>
  +    </sect2>
  +    
  +    <sect2>
  +      <title>Creating a security rules file</title>
  +      <para>
  +        For this step you need to create a file called <literal>security-rules.drl</literal> in the 
  +        <literal>/META-INF</literal> of your application's jar file.  In actual fact this file can be called
  +        anything you want, and exist in any location as long as it is configured appropriately in
  +        <literal>pages.xml</literal>.
  +      </para>
  +      
  +      <para>
  +        So what should the security rules file contain?  At this stage it might be a good idea to at least skim 
  +        through the JBoss Rules documentation, however to get started here's an extremely simple example:
  +      </para>
  +      
  +      <programlisting>
  +        <![CDATA[
  +package MyApplicationPermissions;
  +
  +import org.jboss.seam.security.PermissionCheck;
  +import org.jboss.seam.security.Role;
  +
  +rule CanUserDeleteCustomers
  +when
  +  c: PermissionCheck(name == "customer", action == "delete")
  +  Role(name == "admin")
  +then
  +  c.grant()
  +end;        
  +        ]]>
  +      </programlisting>
  +      
  +      <para>
  +        Let's break this down.  The first thing we see is the package declaration.  A package in JBoss Rules
  +        is essentially a collection of rules.  The package name can be anything you want - it doesn't relate
  +        to anything else outside the scope of the rule base.
  +      </para>
  +      
  +      <para>
  +        The next thing we can notice is a couple of import statements for the <literal>PermissionCheck</literal>
  +        and <literal>Role</literal> classes. These imports inform the rules engine that we'll be referencing 
  +        these classes within our rules.
  +      </para>
  +      
  +      <para>
  +        Finally we have the code for the rule.  Each rule within a package should be given a unique name (usually 
  +        describing the purpose of the rule).  In this case our rule is called <literal>CanUserDeleteCustomers</literal> 
  +        and will be used to check whether a user is allowed to delete a customer record.
  +      </para>
  +      
  +      <para>
  +        Looking at the body of the rule definition we can notice two distinct sections.  Rules have what is known
  +        as a left hand side (LHS) and a right hand side (RHS).  The LHS consists of the conditional part of the 
  +        rule, i.e. a list of conditions which must be satisfied for the rule to fire.  The LHS is represented by 
  +        the <literal>when</literal> section.  The RHS is the consequence, or action section of the rule that will
  +        only be fired if all of the conditions in the LHS are met.  The RHS is represented by the
  +        <literal>then</literal> section.  The end of the rule is denoted by the <literal>end;</literal> line.
  +      </para>
  +      
  +      <para>
  +        If we look at the LHS of the rule, we see two conditions listed there.  Let's examine the first condition:
  +      </para>
  +      
  +      <programlisting>
  +        <![CDATA[
  +  c: PermissionCheck(name == "customer", action == "delete")        
  +        ]]>
  +      </programlisting>
  +      
  +      <para>
  +        In plain english, this condition is stating that there must exist a <literal>PermissionCheck</literal> object 
  +        with a <literal>name</literal> property equal to "customer", and an <literal>action</literal> property equal
  +        to "delete" within the working memory.  What is the working memory?  It is a session-scoped object that contains 
  +        the contextual information that is required by the rules engine to make a decision about a permission check.
  +        Each time the <literal>hasPermission()</literal> method is called, a temporary <literal>PermissionCheck</literal>
  +        object, or <emphasis>Fact</emphasis>, is asserted into the working memory.  This <literal>PermissionCheck</literal>
  +        corresponds exactly to the permission that is being checked, so for example if you call 
  +        <literal>hasPermission("account", "create", null)</literal> then a <literal>PermissionCheck</literal>
  +        object with a <literal>name</literal> equal to "account" and <literal>action</literal> equal to "create" will be
  +        asserted into the working memory for the duration of the permission check.
  +      </para>
  +      
  +      <para>
  +        So what else is in the working memory?  Besides the short-lived temporary facts asserted during a permission
  +        check, there are some longer-lived objects in the working memory that stay there for the entire duration of
  +        a user being authenticated.  These include any <literal>java.security.Principal</literal> objects that
  +        are created as part of the authentication process, plus a <literal>org.jboss.seam.security.Role</literal>
  +        object for each of the roles that the user is a member of.  It is also possible to assert additional 
  +        long-lived facts into the working memory by calling <literal>Identity.instance().getSecurityContext().assertObject()</literal>,
  +        passing the object as a parameter.
  +      </para>
  +      
  +      <para>
  +        Getting back to our simple example, we can also notice that the first line of our LHS is prefixed with
  +        <literal>c:</literal>.  This is a variable binding, and is used to refer back to the object that is
  +        matched by the condition.  Moving onto the second line of our LHS, we see this:
         </para>
  +      
  +      <programlisting>
  +        <![CDATA[
  +  Role(name == "admin")   
  +        ]]>
  +      </programlisting>      
  +      
  +      <para>
  +        This condition simply states that there must be a <literal>Role</literal> object with
  +        a <literal>name</literal> of "admin" within the working memory.  As mentioned, user roles are asserted 
  +        into the working memory as long-lived facts.  So, putting both conditions together, this rule is essentially 
  +        saying "I will fire if you are checking for the <literal>customer:delete</literal> permission and the user
  +        is a member of the <literal>admin</literal> role".
  +      </para>
  +      
  +      <para>
  +        So what is the consequence of the rule firing?  Let's take a look at the RHS of the rule:
  +      </para>
  +      
  +      <programlisting>
  +        <![CDATA[
  +  c.grant()        
  +        ]]>
  +      </programlisting>
  +      
  +      <para>
  +        The RHS consists of Java code, and in this case is invoking the <literal>grant()</literal> 
  +        method of the <literal>c</literal> object, which as already mentioned is a variable binding 
  +        for the <literal>PermissionCheck</literal> object.  Besides the <literal>name</literal> and
  +        <literal>action</literal> properties of the <literal>PermissionCheck</literal> object, there
  +        is also a <literal>granted</literal> property which is initially set to <literal>false</literal>.
  +        Calling <literal>grant()</literal> on a <literal>PermissionCheck</literal> sets the 
  +        <literal>granted</literal> property to <literal>true</literal>, which means that the permission
  +        check was successful, allowing the user to carry out whatever action the permission check was
  +        intended for.
  +      </para>
  +      
       </sect2>
     </sect1>
   
  
  
  



More information about the jboss-cvs-commits mailing list