Minor doc updates

This commit is contained in:
Luke Taylor 2009-07-22 17:24:05 +00:00
parent 0a37aed4b9
commit 40efe6db57
3 changed files with 286 additions and 382 deletions

View File

@ -1,293 +1,244 @@
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="authorization-common" xmlns:xlink="http://www.w3.org/1999/xlink"> <chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="authorization-common"
<info><title>Common Authorization Concepts</title></info> xmlns:xlink="http://www.w3.org/1999/xlink">
<info>
<title>Common Authorization Concepts</title>
</info>
<section xml:id="authorities"> <section xml:id="authorities">
<info><title>Authorities</title></info> <info>
<title>Authorities</title>
<para>As briefly mentioned in the Authentication section, all </info>
<interfacename>Authentication</interfacename> implementations are required to <para>As we saw in the <link xlink:href="#tech-granted-authority">technical overview</link>, all
store an array of <interfacename>GrantedAuthority</interfacename> objects. These <interfacename>Authentication</interfacename> implementations store a list of
represent the authorities that have been granted to the principal. The <interfacename>GrantedAuthority</interfacename> objects. These represent the authorities
<interfacename>GrantedAuthority</interfacename> objects are inserted into the that have been granted to the principal. The <interfacename>GrantedAuthority</interfacename>
<interfacename>Authentication</interfacename> object by the objects are inserted into the <interfacename>Authentication</interfacename> object by the
<interfacename>AuthenticationManager</interfacename> and are later read by <interfacename>AuthenticationManager</interfacename> and are later read by
<interfacename>AccessDecisionManager</interfacename>s when making authorization <interfacename>AccessDecisionManager</interfacename>s when making authorization
decisions.</para> decisions.</para>
<para><interfacename>GrantedAuthority</interfacename> is an interface with only one method:
<para><interfacename>GrantedAuthority</interfacename> is an interface with only
one method:
<programlisting> <programlisting>
String getAuthority(); String getAuthority();
</programlisting> </programlisting> This method allows
This method allows <interfacename>AccessDecisionManager</interfacename>s to <interfacename>AccessDecisionManager</interfacename>s to obtain a precise
obtain a precise <literal>String</literal> representation of the <literal>String</literal> representation of the
<interfacename>GrantedAuthority</interfacename>. By returning a representation as <interfacename>GrantedAuthority</interfacename>. By returning a representation as a
a <literal>String</literal>, a <interfacename>GrantedAuthority</interfacename> can <literal>String</literal>, a <interfacename>GrantedAuthority</interfacename> can be easily
be easily "read" by most <interfacename>AccessDecisionManager</interfacename>s. If <quote>read</quote> by most <interfacename>AccessDecisionManager</interfacename>s. If a
a <interfacename>GrantedAuthority</interfacename> cannot be precisely represented <interfacename>GrantedAuthority</interfacename> cannot be precisely represented as a
as a <literal>String</literal>, the <literal>String</literal>, the <interfacename>GrantedAuthority</interfacename> is considered
<interfacename>GrantedAuthority</interfacename> is considered "complex" and <quote>complex</quote> and <literal>getAuthority()</literal> must return
<literal>getAuthority()</literal> must return <literal>null</literal>.</para>
<literal>null</literal>.</para> <para>An example of a <quote>complex</quote>
<interfacename>GrantedAuthority</interfacename> would be an implementation that stores a list
<para>An example of a "complex" <interfacename>GrantedAuthority</interfacename> of operations and authority thresholds that apply to different customer account numbers.
would be an implementation that stores a list of operations and Representing this complex <interfacename>GrantedAuthority</interfacename> as a
authority thresholds that apply to different customer account numbers. <literal>String</literal> would be quite difficult, and as a result the
Representing this complex <interfacename>GrantedAuthority</interfacename> as a <literal>getAuthority()</literal> method should return <literal>null</literal>. This will
<literal>String</literal> would be quite complex, and as a result the indicate to any <interfacename>AccessDecisionManager</interfacename> that it will need to
<literal>getAuthority()</literal> method should return specifically support the <interfacename>GrantedAuthority</interfacename> implementation in
<literal>null</literal>. This will indicate to any order to understand its contents.</para>
<interfacename>AccessDecisionManager</interfacename> that it will need to <para>Spring Security includes one concrete <interfacename>GrantedAuthority</interfacename>
specifically support the <interfacename>GrantedAuthority</interfacename> implementation, <literal>GrantedAuthorityImpl</literal>. This allows any user-specified
implementation in order to understand its contents.</para> <literal>String</literal> to be converted into a
<interfacename>GrantedAuthority</interfacename>. All
<para>Spring Security includes one concrete <classname>AuthenticationProvider</classname>s included with the security architecture use
<interfacename>GrantedAuthority</interfacename> implementation, <literal>GrantedAuthorityImpl</literal> to populate the
<literal>GrantedAuthorityImpl</literal>. This allows any <interfacename>Authentication</interfacename> object.</para>
user-specified <literal>String</literal> to be converted into a
<interfacename>GrantedAuthority</interfacename>. All
<classname>AuthenticationProvider</classname>s included with the security
architecture use <literal>GrantedAuthorityImpl</literal> to populate
the <interfacename>Authentication</interfacename> object.</para>
</section> </section>
<section xml:id="pre-invocation"> <section xml:id="pre-invocation">
<info> <info>
<title>Pre-Invocation Handling</title> <title>Pre-Invocation Handling</title>
</info> </info>
<para> <para> As we've also seen in the <link xlink:href="#secure-objects">Technical Overview</link>
As we'll see in the <link xlink:href="#secure-objects" >Technical Overview</link> chapter, Spring chapter, Spring Security provides interceptors which control access to secure objects such as
Security provides interceptors which control access to secure objects such as method invocations method invocations or web requests. A pre-invocation decision on whether the invocation is
or web requests. A pre-invocation decision on whether the invocation is allowed to proceed is made by allowed to proceed is made by the <interfacename>AccessDecisionManager</interfacename>. </para>
the <interfacename>AccessDecisionManager</interfacename>.
</para>
<section> <section>
<title>The AccessDecisionManager</title> <title>The AccessDecisionManager</title>
<para>The <interfacename>AccessDecisionManager</interfacename> is called by the <para>The <interfacename>AccessDecisionManager</interfacename> is called by the
<classname>AbstractSecurityInterceptor</classname> and is responsible for <classname>AbstractSecurityInterceptor</classname> and is responsible for making final
making final access control decisions. The access control decisions. The <interfacename>AccessDecisionManager</interfacename> interface
<interfacename>AccessDecisionManager</interfacename> interface contains three contains three methods:
methods: <programlisting>
<programlisting>
void decide(Authentication authentication, Object secureObject, void decide(Authentication authentication, Object secureObject,
List&lt;ConfigAttribute&gt; config) throws AccessDeniedException; List&lt;ConfigAttribute&gt; config) throws AccessDeniedException;
boolean supports(ConfigAttribute attribute); boolean supports(ConfigAttribute attribute);
boolean supports(Class clazz); boolean supports(Class clazz);
</programlisting> </programlisting>
As can be seen from the first method, the The <interfacename>AccessDecisionManager</interfacename>'s <methodname>decide</methodname>
<interfacename>AccessDecisionManager</interfacename> is passed via method method is passed all the relevant information it needs in order to make an authorization
parameters all information that is likely to be of value in assessing decision. In particular, passing the secure <literal>Object</literal> enables those
an authorization decision. In particular, passing the secure arguments contained in the actual secure object invocation to be inspected. For example,
<literal>Object</literal> enables those arguments contained in the let's assume the secure object was a <classname>MethodInvocation</classname>. It would be
actual secure object invocation to be inspected. For example, let's easy to query the <classname>MethodInvocation</classname> for any
assume the secure object was a <classname>MethodInvocation</classname>. It <literal>Customer</literal> argument, and then implement some sort of security logic in
would be easy to query the <classname>MethodInvocation</classname> for any the <interfacename>AccessDecisionManager</interfacename> to ensure the principal is
<literal>Customer</literal> argument, and then implement some sort of permitted to operate on that customer. Implementations are expected to throw an
security logic in the <interfacename>AccessDecisionManager</interfacename> to <literal>AccessDeniedException</literal> if access is denied.</para>
ensure the principal is permitted to operate on that customer. <para>The <literal>supports(ConfigAttribute)</literal> method is called by the
Implementations are expected to throw an <classname>AbstractSecurityInterceptor</classname> at startup time to determine if the
<literal>AccessDeniedException</literal> if access is denied.</para> <interfacename>AccessDecisionManager</interfacename> can process the passed
<literal>ConfigAttribute</literal>. The <literal>supports(Class)</literal> method is
<para>The <literal>supports(ConfigAttribute)</literal> method is called by a security interceptor implementation to ensure the configured
called by the <classname>AbstractSecurityInterceptor</classname> at <interfacename>AccessDecisionManager</interfacename> supports the type of secure object
startup time to determine if the that the security interceptor will present.</para>
<interfacename>AccessDecisionManager</interfacename> can process the passed <section>
<literal>ConfigAttribute</literal>. The <title>Voting-Based AccessDecisionManager Implementations</title>
<literal>supports(Class)</literal> method is called by a security <para>Whilst users can implement their own
interceptor implementation to ensure the configured <interfacename>AccessDecisionManager</interfacename> to control all aspects of
<interfacename>AccessDecisionManager</interfacename> supports the type of secure authorization, Spring Security includes several
object that the security interceptor will present.</para> <interfacename>AccessDecisionManager</interfacename> implementations that are based on
voting. <xref linkend="authz-access-voting"/> illustrates the relevant classes.</para>
<section> <figure xml:id="authz-access-voting">
<title>Voting-Based AccessDecisionManager Implementations</title> <title>Voting Decision Manager</title>
<para>Whilst users can implement their own <interfacename>AccessDecisionManager</interfacename> to control all aspects of <mediaobject>
authorization, Spring Security includes several <interfacename>AccessDecisionManager</interfacename> implementations that are <!--
based on voting. <xref linkend="authz-access-voting"/> illustrates the relevant classes.</para>
<figure xml:id="authz-access-voting">
<title>Voting Decision Manager</title>
<mediaobject>
<!--
<imageobject role="fo"> <imageobject role="fo">
<imagedata align="center" fileref="resources/images/AccessDecisionVoting.gif" format="GIF"/> <imagedata align="center" fileref="resources/images/AccessDecisionVoting.gif" format="GIF"/>
</imageobject> </imageobject>
--> -->
<imageobject> <imageobject>
<imagedata align="center" scalefit="1" fileref="images/AccessDecisionVoting.gif" format="GIF"/> <imagedata align="center" scalefit="1" fileref="images/AccessDecisionVoting.gif"
</imageobject> format="GIF"/>
</mediaobject> </imageobject>
</figure> </mediaobject>
<para>Using this approach, a series of </figure>
<interfacename>AccessDecisionVoter</interfacename> implementations are polled on <para>Using this approach, a series of <interfacename>AccessDecisionVoter</interfacename>
an authorization decision. The implementations are polled on an authorization decision. The
<interfacename>AccessDecisionManager</interfacename> then decides whether or not <interfacename>AccessDecisionManager</interfacename> then decides whether or not to
to throw an <literal>AccessDeniedException</literal> based on its throw an <literal>AccessDeniedException</literal> based on its assessment of the
assessment of the votes.</para> votes.</para>
<para>The <interfacename>AccessDecisionVoter</interfacename> interface has three methods:
<para>The <interfacename>AccessDecisionVoter</interfacename> interface has three <programlisting>
methods:
<programlisting>
int vote(Authentication authentication, Object object, List&lt;ConfigAttribute&gt; config); int vote(Authentication authentication, Object object, List&lt;ConfigAttribute&gt; config);
boolean supports(ConfigAttribute attribute); boolean supports(ConfigAttribute attribute);
boolean supports(Class clazz); boolean supports(Class clazz);
</programlisting> </programlisting>
Concrete implementations return an <literal>int</literal>, with Concrete implementations return an <literal>int</literal>, with possible values being
possible values being reflected in the reflected in the <interfacename>AccessDecisionVoter</interfacename> static fields
<interfacename>AccessDecisionVoter</interfacename> static fields <literal>ACCESS_ABSTAIN</literal>, <literal>ACCESS_DENIED</literal> and
<literal>ACCESS_ABSTAIN</literal>, <literal>ACCESS_DENIED</literal> <literal>ACCESS_GRANTED</literal>. A voting implementation will return
and <literal>ACCESS_GRANTED</literal>. A voting implementation will <literal>ACCESS_ABSTAIN</literal> if it has no opinion on an authorization decision. If
return <literal>ACCESS_ABSTAIN</literal> if it has no opinion on an it does have an opinion, it must return either <literal>ACCESS_DENIED</literal> or
authorization decision. If it does have an opinion, it must return <literal>ACCESS_GRANTED</literal>.</para>
either <literal>ACCESS_DENIED</literal> or <para>There are three concrete <interfacename>AccessDecisionManager</interfacename>s
<literal>ACCESS_GRANTED</literal>.</para> provided with Spring Security that tally the votes. The <literal>ConsensusBased</literal>
implementation will grant or deny access based on the consensus of non-abstain votes.
<para>There are three concrete Properties are provided to control behavior in the event of an equality of votes or if all
<interfacename>AccessDecisionManager</interfacename>s provided with Spring votes are abstain. The <literal>AffirmativeBased</literal> implementation will grant
Security that tally the votes. The <literal>ConsensusBased</literal> access if one or more <literal>ACCESS_GRANTED</literal> votes were received (i.e. a deny
implementation will grant or deny access based on the consensus of vote will be ignored, provided there was at least one grant vote). Like the
non-abstain votes. Properties are provided to control behavior in the <literal>ConsensusBased</literal> implementation, there is a parameter that controls the
event of an equality of votes or if all votes are abstain. The behavior if all voters abstain. The <literal>UnanimousBased</literal> provider expects
<literal>AffirmativeBased</literal> implementation will grant access unanimous <literal>ACCESS_GRANTED</literal> votes in order to grant access, ignoring
if one or more <literal>ACCESS_GRANTED</literal> votes were received abstains. It will deny access if there is any <literal>ACCESS_DENIED</literal> vote. Like
(i.e. a deny vote will be ignored, provided there was at least one grant the other implementations, there is a parameter that controls the behaviour if all voters
vote). Like the <literal>ConsensusBased</literal> implementation, abstain.</para>
there is a parameter that controls the behavior if all voters abstain. <para>It is possible to implement a custom
The <literal>UnanimousBased</literal> provider expects unanimous <interfacename>AccessDecisionManager</interfacename> that tallies votes differently. For
<literal>ACCESS_GRANTED</literal> votes in order to grant access, example, votes from a particular <interfacename>AccessDecisionVoter</interfacename> might
ignoring abstains. It will deny access if there is any receive additional weighting, whilst a deny vote from a particular voter may have a veto
<literal>ACCESS_DENIED</literal> vote. Like the other implementations, effect.</para>
there is a parameter that controls the behaviour if all voters <section>
abstain.</para> <title><classname>RoleVoter</classname></title>
<para> The most commonly used <interfacename>AccessDecisionVoter</interfacename> provided
<para>It is possible to implement a custom with Spring Security is the simple <classname>RoleVoter</classname>, which treats
<interfacename>AccessDecisionManager</interfacename> that tallies votes configuration attributes as simple role names and votes to grant access if the user has
differently. For example, votes from a particular been assigned that role.</para>
<interfacename>AccessDecisionVoter</interfacename> might receive additional <para>It will vote if any ConfigAttribute begins with the prefix <literal>ROLE_</literal>.
weighting, whilst a deny vote from a particular voter may have a veto It will vote to grant access if there is a
effect.</para> <interfacename>GrantedAuthority</interfacename> which returns a
<literal>String</literal> representation (via the <literal>getAuthority()</literal>
<section> method) exactly equal to one or more <literal>ConfigAttributes</literal> starting with
<title><classname>RoleVoter</classname></title> <literal>ROLE_</literal>. If there is no exact match of any
<para> <literal>ConfigAttribute</literal> starting with <literal>ROLE_</literal>, the
The most commonly used <interfacename>AccessDecisionVoter</interfacename> <literal>RoleVoter</literal> will vote to deny access. If no
provided with Spring Security is the simple <classname>RoleVoter</classname>, which treats <literal>ConfigAttribute</literal> begins with <literal>ROLE_</literal>, the voter
configuration attributes as simple role names and votes to grant access if the user has been assigned will abstain. <literal>RoleVoter</literal> is case sensitive on comparisons as well as
that role.</para> the <literal>ROLE_</literal> prefix.</para>
<para>It will vote if any ConfigAttribute begins with the prefix <literal>ROLE_</literal>. </section>
It will vote to grant access if there is a <interfacename>GrantedAuthority</interfacename> which returns a <section>
<literal>String</literal> representation (via the <title>Custom Voters</title>
<literal>getAuthority()</literal> method) exactly equal to one or more <para>It is also possible to implement a custom
<literal>ConfigAttributes</literal> starting with <interfacename>AccessDecisionVoter</interfacename>. Several examples are provided in
<literal>ROLE_</literal>. If there is no exact match of any Spring Security unit tests, including <literal>ContactSecurityVoter</literal> and
<literal>ConfigAttribute</literal> starting with <literal>DenyVoter</literal>. The <literal>ContactSecurityVoter</literal> abstains
<literal>ROLE_</literal>, the <literal>RoleVoter</literal> will vote from voting decisions where a <literal>CONTACT_OWNED_BY_CURRENT_USER</literal>
to deny access. If no <literal>ConfigAttribute</literal> begins with <literal>ConfigAttribute</literal> is not found. If voting, it queries the
<literal>ROLE_</literal>, the voter will abstain. <classname>MethodInvocation</classname> to extract the owner of the
<literal>RoleVoter</literal> is case sensitive on comparisons as well <literal>Contact</literal> object that is subject of the method call. It votes to
as the <literal>ROLE_</literal> prefix.</para> grant access if the <literal>Contact</literal> owner matches the principal presented in
</section> the <interfacename>Authentication</interfacename> object. It could have just as easily
compared the <literal>Contact</literal> owner with some
<section> <interfacename>GrantedAuthority</interfacename> the
<title>Custom Voters</title> <interfacename>Authentication</interfacename> object presented. All of this is
<para>It is also possible to implement a custom achieved with relatively few lines of code and demonstrates the flexibility of the
<interfacename>AccessDecisionVoter</interfacename>. Several examples are provided authorization model.</para>
in Spring Security unit tests, including
<literal>ContactSecurityVoter</literal> and
<literal>DenyVoter</literal>. The
<literal>ContactSecurityVoter</literal> abstains from voting decisions
where a <literal>CONTACT_OWNED_BY_CURRENT_USER</literal>
<literal>ConfigAttribute</literal> is not found. If voting, it queries
the <classname>MethodInvocation</classname> to extract the owner of the
<literal>Contact</literal> object that is subject of the method call.
It votes to grant access if the <literal>Contact</literal> owner
matches the principal presented in the
<interfacename>Authentication</interfacename> object. It could have just as easily
compared the <literal>Contact</literal> owner with some
<interfacename>GrantedAuthority</interfacename> the
<interfacename>Authentication</interfacename> object presented. All of this is
achieved with relatively few lines of code and demonstrates the
flexibility of the authorization model.</para>
</section> </section>
</section>
</section> </section>
</section>
</section> </section>
<section xml:id="after-invocation"> <section xml:id="after-invocation">
<info><title>After Invocation Handling</title></info> <info>
<para>Whilst the <interfacename>AccessDecisionManager</interfacename> is called by <title>After Invocation Handling</title>
the <classname>AbstractSecurityInterceptor</classname> before proceeding </info>
with the secure object invocation, some applications need a way of <para>Whilst the <interfacename>AccessDecisionManager</interfacename> is called by the
modifying the object actually returned by the secure object <classname>AbstractSecurityInterceptor</classname> before proceeding with the secure object
invocation. Whilst you could easily implement your own AOP concern to invocation, some applications need a way of modifying the object actually returned by the
achieve this, Spring Security provides a convenient hook that has secure object invocation. Whilst you could easily implement your own AOP concern to achieve
several concrete implementations that integrate with its ACL this, Spring Security provides a convenient hook that has several concrete implementations
capabilities.</para> that integrate with its ACL capabilities.</para>
<para><xref linkend="authz-after-invocation"/> illustrates Spring Security's <para><xref linkend="authz-after-invocation"/> illustrates Spring Security's
<literal>AfterInvocationManager</literal> and its concrete <literal>AfterInvocationManager</literal> and its concrete implementations. <figure
implementations. xml:id="authz-after-invocation">
<title>After Invocation Implementation</title>
<figure xml:id="authz-after-invocation"> <mediaobject>
<title>After Invocation Implementation</title> <imageobject>
<mediaobject> <imagedata align="center" scalefit="1" fileref="images/AfterInvocation.gif" format="GIF"
<imageobject> />
<imagedata align="center" scalefit="1" fileref="images/AfterInvocation.gif" format="GIF"/> </imageobject>
</imageobject> </mediaobject>
</mediaobject> </figure></para>
<para>Like many other parts of Spring Security, <literal>AfterInvocationManager</literal> has a
</figure> single concrete implementation, <literal>AfterInvocationProviderManager</literal>, which polls
</para> a list of <literal>AfterInvocationProvider</literal>s. Each
<literal>AfterInvocationProvider</literal> is allowed to modify the return object or throw
<para>Like many other parts of Spring Security, an <literal>AccessDeniedException</literal>. Indeed multiple providers can modify the object,
<literal>AfterInvocationManager</literal> has a single concrete as the result of the previous provider is passed to the next in the list. Let's now consider
implementation, <literal>AfterInvocationProviderManager</literal>, our ACL-aware implementations of <literal>AfterInvocationProvider</literal>.</para>
which polls a list of <literal>AfterInvocationProvider</literal>s. <para>Please be aware that if you're using <literal>AfterInvocationManager</literal>, you will
Each <literal>AfterInvocationProvider</literal> is allowed to modify still need configuration attributes that allow the
the return object or throw an <classname>MethodSecurityInterceptor</classname>'s
<literal>AccessDeniedException</literal>. Indeed multiple providers <interfacename>AccessDecisionManager</interfacename> to allow an operation. If you're using
can modify the object, as the result of the previous provider is the typical Spring Security included <interfacename>AccessDecisionManager</interfacename>
passed to the next in the list. Let's now consider our ACL-aware implementations, having no configuration attributes defined for a particular secure method
implementations of <literal>AfterInvocationProvider</literal>.</para> invocation will cause each <interfacename>AccessDecisionVoter</interfacename> to abstain from
voting. In turn, if the <interfacename>AccessDecisionManager</interfacename> property
<para>Please be aware that if you're using "<literal>allowIfAllAbstainDecisions</literal>" is <literal>false</literal>, an
<literal>AfterInvocationManager</literal>, you will still need <literal>AccessDeniedException</literal> will be thrown. You may avoid this potential issue
configuration attributes that allow the by either (i) setting "<literal>allowIfAllAbstainDecisions</literal>" to
<classname>MethodSecurityInterceptor</classname>'s <literal>true</literal> (although this is generally not recommended) or (ii) simply ensure
<interfacename>AccessDecisionManager</interfacename> to allow an operation. If that there is at least one configuration attribute that an
you're using the typical Spring Security included <interfacename>AccessDecisionVoter</interfacename> will vote to grant access for. This
<interfacename>AccessDecisionManager</interfacename> implementations, having no latter (recommended) approach is usually achieved through a <literal>ROLE_USER</literal> or
configuration attributes defined for a particular secure method <literal>ROLE_AUTHENTICATED</literal> configuration attribute</para>
invocation will cause each <interfacename>AccessDecisionVoter</interfacename> to <section xml:id="after-invocation-acl-aware">
abstain from voting. In turn, if the <info>
<interfacename>AccessDecisionManager</interfacename> property <title>ACL-Aware AfterInvocationProviders</title>
"<literal>allowIfAllAbstainDecisions</literal>" is </info>
<literal>false</literal>, an <literal>AccessDeniedException</literal> <!-- TODO: Move to ACL section and add reference here -->
will be thrown. You may avoid this potential issue by either (i) <para>A common services layer method we've all written at one stage or another looks like
setting "<literal>allowIfAllAbstainDecisions</literal>" to this:</para>
<literal>true</literal> (although this is generally not recommended) <para>
or (ii) simply ensure that there is at least one configuration <programlisting>public Contact getById(Integer id);</programlisting>
attribute that an <interfacename>AccessDecisionVoter</interfacename> will vote to </para>
grant access for. This latter (recommended) approach is usually <para>Quite often, only principals with permission to read the <literal>Contact</literal>
achieved through a <literal>ROLE_USER</literal> or should be allowed to obtain it. In this situation the
<literal>ROLE_AUTHENTICATED</literal> configuration attribute</para> <interfacename>AccessDecisionManager</interfacename> approach provided by the
<classname>AbstractSecurityInterceptor</classname> will not suffice. This is because the
<section xml:id="after-invocation-acl-aware"><info><title>ACL-Aware AfterInvocationProviders</title></info> identity of the <literal>Contact</literal> is all that is available before the secure object
<!-- TODO: Move to ACL section and add reference here --> is invoked. The <classname>AclEntryAfterInvocationProvider</classname> delivers a solution,
<para>A common services layer method we've all written at one stage and is configured as follows: <programlisting><![CDATA[
or another looks like this:</para>
<para><programlisting>public Contact getById(Integer id);</programlisting></para>
<para>Quite often, only principals with permission to read the
<literal>Contact</literal> should be allowed to obtain it. In this
situation the <interfacename>AccessDecisionManager</interfacename> approach
provided by the <classname>AbstractSecurityInterceptor</classname> will
not suffice. This is because the identity of the
<literal>Contact</literal> is all that is available before the
secure object is invoked. The
<classname>AclEntryAfterInvocationProvider</classname> delivers a solution,
and is configured as follows:
<programlisting><![CDATA[
<bean id="afterAclRead" <bean id="afterAclRead"
class="org.springframework.security.acls.afterinvocation.AclEntryAfterInvocationProvider"> class="org.springframework.security.acls.afterinvocation.AclEntryAfterInvocationProvider">
<constructor-arg ref="aclService"/> <constructor-arg ref="aclService"/>
@ -298,26 +249,19 @@ boolean supports(Class clazz);
</list> </list>
</constructor-arg> </constructor-arg>
</bean> </bean>
]]></programlisting> ]]></programlisting> In the above example, the <literal>Contact</literal> will be retrieved and
In the above example, the <literal>Contact</literal> will be passed to the <classname>AclEntryAfterInvocationProvider</classname>. The provider will
retrieved and passed to the thrown an <classname>AccessDeniedException</classname> if one of the listed
<classname>AclEntryAfterInvocationProvider</classname>. The provider <literal>requirePermission</literal>s is not held by the
will thrown an <classname>AccessDeniedException</classname> if one of <interfacename>Authentication</interfacename>. The
the listed <literal>requirePermission</literal>s is not held by the <classname>AclEntryAfterInvocationProvider</classname> queries the acl service to
<interfacename>Authentication</interfacename>. The determine the ACL that applies for this domain object to this
<classname>AclEntryAfterInvocationProvider</classname> queries the <interfacename>Authentication</interfacename>.</para>
acl service to determine the ACL that applies for <para>Similar to the <classname>AclEntryAfterInvocationProvider</classname> is
this domain object to this <interfacename>Authentication</interfacename>.</para> <classname>AclEntryAfterInvocationCollectionFilteringProvider</classname>. It is designed
to remove <literal>Collection</literal> or array elements for which a principal does not
<para>Similar to the have access. It never thrown an <classname>AccessDeniedException</classname> - simply
<classname>AclEntryAfterInvocationProvider</classname> is silently removes the offending elements. The provider is configured as follows: <programlisting><![CDATA[
<classname>AclEntryAfterInvocationCollectionFilteringProvider</classname>.
It is designed to remove <literal>Collection</literal> or array
elements for which a principal does not have access. It never thrown
an <classname>AccessDeniedException</classname> - simply silently
removes the offending elements. The provider is configured as
follows:
<programlisting><![CDATA[
<bean id="afterAclCollectionRead" <bean id="afterAclCollectionRead"
class="org.springframework.security.acls.afterinvocation.AclEntryAfterInvocationCollectionFilteringProvider"> class="org.springframework.security.acls.afterinvocation.AclEntryAfterInvocationCollectionFilteringProvider">
<constructor-arg ref="aclService"/> <constructor-arg ref="aclService"/>
@ -328,109 +272,83 @@ boolean supports(Class clazz);
</list> </list>
</constructor-arg> </constructor-arg>
</bean> </bean>
]]> </programlisting> ]]> </programlisting> As you can imagine, the returned <literal>Object</literal> must be a
As you can imagine, the returned <literal>Object</literal> <literal>Collection</literal> or array for this provider to operate. It will remove any
must be a <literal>Collection</literal> or array for this provider element if the <literal>AclManager</literal> indicates the
to operate. It will remove any element if the <interfacename>Authentication</interfacename> does not hold one of the listed
<literal>AclManager</literal> indicates the <literal>requirePermission</literal>s.</para>
<interfacename>Authentication</interfacename> does not hold one of the listed
<literal>requirePermission</literal>s.</para>
<para>The Contacts sample application demonstrates these two <para>The Contacts sample application demonstrates these two
<literal>AfterInvocationProvider</literal>s.</para> <literal>AfterInvocationProvider</literal>s.</para>
</section> </section>
</section> </section>
<section xml:id="authorization-taglibs"> <section xml:id="authorization-taglibs">
<info><title>Authorization Tag Libraries</title></info> <info>
<title>Authorization Tag Libraries</title>
<para><literal>AuthorizeTag</literal> is used to include content if </info>
the current principal holds certain <para><literal>AuthorizeTag</literal> is used to include content if the current principal holds
<interfacename>GrantedAuthority</interfacename>s.</para> certain <interfacename>GrantedAuthority</interfacename>s.</para>
<para>The following JSP fragment illustrates how to use the <para>The following JSP fragment illustrates how to use the
<literal>AuthorizeTag</literal>:</para> <literal>AuthorizeTag</literal>:</para>
<para>
<para><programlisting> <programlisting>
<![CDATA[ <![CDATA[
<security:authorize ifAllGranted="ROLE_SUPERVISOR"> <security:authorize ifAllGranted="ROLE_SUPERVISOR">
<td> <td>
<a href="del.htm?id=<c:out value="${contact.id}"/>">Del</a> <a href="del.htm?id=<c:out value="${contact.id}"/>">Del</a>
</td> </td>
</security:authorize> </security:authorize>
]]></programlisting></para> ]]></programlisting>
</para>
<para>This tag would cause the tag's body to be output if the <para>This tag would cause the tag's body to be output if the principal has been granted
principal has been granted ROLE_SUPERVISOR.</para> ROLE_SUPERVISOR.</para>
<para>The <literal>security:authorize</literal> tag declares the following attributes:</para>
<para>The <literal>security:authorize</literal> tag declares the <para>
following attributes:</para> <itemizedlist spacing="compact">
<para><itemizedlist spacing="compact">
<listitem> <listitem>
<para><literal>ifAllGranted</literal>: All the listed roles must <para><literal>ifAllGranted</literal>: All the listed roles must be granted for the tag to
be granted for the tag to output its body.</para> output its body.</para>
</listitem> </listitem>
<listitem> <listitem>
<para><literal>ifAnyGranted</literal>: Any of the listed roles <para><literal>ifAnyGranted</literal>: Any of the listed roles must be granted for the tag
must be granted for the tag to output its body.</para> to output its body.</para>
</listitem> </listitem>
<listitem> <listitem>
<para><literal>ifNotGranted</literal>: None of the listed roles <para><literal>ifNotGranted</literal>: None of the listed roles must be granted for the
must be granted for the tag to output its body.</para> tag to output its body.</para>
</listitem> </listitem>
</itemizedlist></para> </itemizedlist>
</para>
<para>You'll note that in each attribute you can list multiple roles. <para>You'll note that in each attribute you can list multiple roles. Simply separate the roles
Simply separate the roles using a comma. The using a comma. The <literal>authorize</literal> tag ignores whitespace in attributes.</para>
<literal>authorize</literal> tag ignores whitespace in <para>The tag library logically ANDs all of it's parameters together. This means that if you
attributes.</para> combine two or more attributes, all attributes must be true for the tag to output it's body.
Don't add an <literal>ifAllGranted="ROLE_SUPERVISOR"</literal>, followed by an
<para>The tag library logically ANDs all of it's parameters together. <literal>ifNotGranted="ROLE_SUPERVISOR"</literal>, or you'll be surprised to never see the
This means that if you combine two or more attributes, all attributes tag's body.</para>
must be true for the tag to output it's body. Don't add an <para>By requiring all attributes to return true, the authorize tag allows you to create more
<literal>ifAllGranted="ROLE_SUPERVISOR"</literal>, followed by an complex authorization scenarios. For example, you could declare an
<literal>ifNotGranted="ROLE_SUPERVISOR"</literal>, or you'll be <literal>ifAllGranted="ROLE_SUPERVISOR"</literal> and an
surprised to never see the tag's body.</para> <literal>ifNotGranted="ROLE_NEWBIE_SUPERVISOR"</literal> in the same tag, in order to
prevent new supervisors from seeing the tag body. However it would no doubt be simpler to use
<para>By requiring all attributes to return true, the authorize tag <literal>ifAllGranted="ROLE_EXPERIENCED_SUPERVISOR"</literal> rather than inserting NOT
allows you to create more complex authorization scenarios. For conditions into your design.</para>
example, you could declare an <para>One last item: the tag verifies the authorizations in a specific order: first
<literal>ifAllGranted="ROLE_SUPERVISOR"</literal> and an <literal>ifNotGranted</literal>, then <literal>ifAllGranted</literal>, and finally,
<literal>ifNotGranted="ROLE_NEWBIE_SUPERVISOR"</literal> in the same <literal>if AnyGranted</literal>.</para>
tag, in order to prevent new supervisors from seeing the tag body. <para><literal>AccessControlListTag</literal> is used to include content if the current
However it would no doubt be simpler to use principal has an ACL to the indicated domain object.</para>
<literal>ifAllGranted="ROLE_EXPERIENCED_SUPERVISOR"</literal> rather
than inserting NOT conditions into your design.</para>
<para>One last item: the tag verifies the authorizations in a specific
order: first <literal>ifNotGranted</literal>, then
<literal>ifAllGranted</literal>, and finally, <literal>if
AnyGranted</literal>.</para>
<para><literal>AccessControlListTag</literal> is used to include
content if the current principal has an ACL to the indicated domain
object.</para>
<para>The following JSP fragment illustrates how to use the <para>The following JSP fragment illustrates how to use the
<literal>AccessControlListTag</literal>: <literal>AccessControlListTag</literal>: <programlisting><![CDATA[
<programlisting><![CDATA[
<security:accesscontrollist domainObject="${contact}" hasPermission="8,16"> <security:accesscontrollist domainObject="${contact}" hasPermission="8,16">
<td><a href="<c:url value="del.htm"><c:param name="contactId" value="${contact.id}"/></c:url>">Del</a></td> <td><a href="<c:url value="del.htm"><c:param name="contactId" value="${contact.id}"/></c:url>">Del</a></td>
</security:accesscontrollist> </security:accesscontrollist>
]]></programlisting> ]]></programlisting> This tag would cause the tag's body to be output if the principal holds either
This tag would cause the tag's body to be output if the permission 16 or permission 1 for the "contact" domain object. The numbers are actually
principal holds either permission 16 or permission 1 for the "contact" integers that are used with <literal>BasePermission</literal> bit masking. Please refer to the
domain object. The numbers are actually integers that are used with ACL section of this reference guide to understand more about the ACL capabilities of Spring
<literal>BasePermission</literal> bit masking. Please refer to the ACL Security.</para>
section of this reference guide to understand more about the ACL <para><literal>AclTag</literal> is part of the old ACL module and should be considered
capabilities of Spring Security.</para> deprecated. For the sake of historical reference, works exactly the samae as
<literal>AccessControlListTag</literal>.</para>
<para><literal>AclTag</literal> is part of the old ACL module and
should be considered deprecated. For the sake of historical reference,
works exactly the samae as
<literal>AccessControlListTag</literal>.</para>
</section> </section>
</chapter> </chapter>

View File

@ -637,20 +637,6 @@
in the list of pointcuts, as the first matching expression will be used. </para> in the list of pointcuts, as the first matching expression will be used. </para>
</section> </section>
</section> </section>
<section xml:id="ns-intercept-methods">
<title>The <literal>intercept-methods</literal> Bean Decorator</title>
<para> This alternative syntax allows you to specify security for a specific bean by adding
this element within the bean itself. <programlisting language="xml"><![CDATA[
<bean:bean id="target" class="com.mycompany.myapp.MyBean">
<intercept-methods>
<protect method="set*" access="ROLE_ADMIN" />
<protect method="get*" access="ROLE_ADMIN,ROLE_USER" />
<protect method="doSomething" access="ROLE_USER" />
</intercept-methods>
</bean:bean>
]]></programlisting> This allows you to configure security attributes for individual methods on the
bean or simple wildcarded patterns. </para>
</section>
</section> </section>
<section xml:id="ns-access-manager"> <section xml:id="ns-access-manager">
<title>The Default AccessDecisionManager</title> <title>The Default AccessDecisionManager</title>

View File

@ -76,7 +76,7 @@ if (principal instanceof UserDetails) {
}</programlisting> }</programlisting>
<para>The object returned by the call to <methodname>getContext()</methodname> is an <para>The object returned by the call to <methodname>getContext()</methodname> is an
instance of the <interfacename>SecurityContext</interfacename> interface. This is the instance of the <interfacename>SecurityContext</interfacename> interface. This is the
object that is kept in thread-local storage. As we'll see below, Most authentication object that is kept in thread-local storage. As we'll see below, Most authentication
mechanisms withing Spring Security return an instance of mechanisms withing Spring Security return an instance of
<interfacename>UserDetails</interfacename> as the principal. </para> <interfacename>UserDetails</interfacename> as the principal. </para>
</section> </section>
@ -127,7 +127,7 @@ if (principal instanceof UserDetails) {
<interfacename>Authentication</interfacename> is <literal>getAuthorities(</literal>). This <interfacename>Authentication</interfacename> is <literal>getAuthorities(</literal>). This
method provides an array of <interfacename>GrantedAuthority</interfacename> objects. A method provides an array of <interfacename>GrantedAuthority</interfacename> objects. A
<interfacename>GrantedAuthority</interfacename> is, not surprisingly, an authority that is <interfacename>GrantedAuthority</interfacename> is, not surprisingly, an authority that is
granted to the principal. Such authorities are usually "roles", such as granted to the principal. Such authorities are usually <quote>roles</quote>, such as
<literal>ROLE_ADMINISTRATOR</literal> or <literal>ROLE_HR_SUPERVISOR</literal>. These <literal>ROLE_ADMINISTRATOR</literal> or <literal>ROLE_HR_SUPERVISOR</literal>. These
roles are later on configured for web authorization, method authorization and domain object roles are later on configured for web authorization, method authorization and domain object
authorization. Other parts of Spring Security are capable of interpreting these authorities, authorization. Other parts of Spring Security are capable of interpreting these authorities,