|
@@ -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">
|
|
|
|
- <info><title>Common Authorization Concepts</title></info>
|
|
|
|
-
|
|
|
|
|
|
+<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="authorization-common"
|
|
|
|
+ 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>
|
|
|
|
-
|
|
|
|
- <para>As briefly mentioned in the Authentication section, all
|
|
|
|
- <interfacename>Authentication</interfacename> implementations are required to
|
|
|
|
- store an array of <interfacename>GrantedAuthority</interfacename> objects. These
|
|
|
|
- represent the authorities that have been granted to the principal. The
|
|
|
|
- <interfacename>GrantedAuthority</interfacename> objects are inserted into the
|
|
|
|
- <interfacename>Authentication</interfacename> object by the
|
|
|
|
- <interfacename>AuthenticationManager</interfacename> and are later read by
|
|
|
|
- <interfacename>AccessDecisionManager</interfacename>s when making authorization
|
|
|
|
- decisions.</para>
|
|
|
|
-
|
|
|
|
- <para><interfacename>GrantedAuthority</interfacename> is an interface with only
|
|
|
|
- one method:
|
|
|
|
|
|
+ <info>
|
|
|
|
+ <title>Authorities</title>
|
|
|
|
+ </info>
|
|
|
|
+ <para>As we saw in the <link xlink:href="#tech-granted-authority">technical overview</link>, all
|
|
|
|
+ <interfacename>Authentication</interfacename> implementations store a list of
|
|
|
|
+ <interfacename>GrantedAuthority</interfacename> objects. These represent the authorities
|
|
|
|
+ that have been granted to the principal. The <interfacename>GrantedAuthority</interfacename>
|
|
|
|
+ objects are inserted into the <interfacename>Authentication</interfacename> object by the
|
|
|
|
+ <interfacename>AuthenticationManager</interfacename> and are later read by
|
|
|
|
+ <interfacename>AccessDecisionManager</interfacename>s when making authorization
|
|
|
|
+ decisions.</para>
|
|
|
|
+ <para><interfacename>GrantedAuthority</interfacename> is an interface with only one method:
|
|
<programlisting>
|
|
<programlisting>
|
|
String getAuthority();
|
|
String getAuthority();
|
|
- </programlisting>
|
|
|
|
- This method allows <interfacename>AccessDecisionManager</interfacename>s to
|
|
|
|
- obtain a precise <literal>String</literal> representation of the
|
|
|
|
- <interfacename>GrantedAuthority</interfacename>. By returning a representation as
|
|
|
|
- a <literal>String</literal>, a <interfacename>GrantedAuthority</interfacename> can
|
|
|
|
- be easily "read" by most <interfacename>AccessDecisionManager</interfacename>s. If
|
|
|
|
- a <interfacename>GrantedAuthority</interfacename> cannot be precisely represented
|
|
|
|
- as a <literal>String</literal>, the
|
|
|
|
- <interfacename>GrantedAuthority</interfacename> is considered "complex" and
|
|
|
|
- <literal>getAuthority()</literal> must return
|
|
|
|
- <literal>null</literal>.</para>
|
|
|
|
-
|
|
|
|
- <para>An example of a "complex" <interfacename>GrantedAuthority</interfacename>
|
|
|
|
- would be an implementation that stores a list of operations and
|
|
|
|
- authority thresholds that apply to different customer account numbers.
|
|
|
|
- Representing this complex <interfacename>GrantedAuthority</interfacename> as a
|
|
|
|
- <literal>String</literal> would be quite complex, and as a result the
|
|
|
|
- <literal>getAuthority()</literal> method should return
|
|
|
|
- <literal>null</literal>. This will indicate to any
|
|
|
|
- <interfacename>AccessDecisionManager</interfacename> that it will need to
|
|
|
|
- specifically support the <interfacename>GrantedAuthority</interfacename>
|
|
|
|
- implementation in order to understand its contents.</para>
|
|
|
|
-
|
|
|
|
- <para>Spring Security includes one concrete
|
|
|
|
- <interfacename>GrantedAuthority</interfacename> implementation,
|
|
|
|
- <literal>GrantedAuthorityImpl</literal>. This allows any
|
|
|
|
- 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>
|
|
|
|
|
|
+ </programlisting> This method allows
|
|
|
|
+ <interfacename>AccessDecisionManager</interfacename>s to obtain a precise
|
|
|
|
+ <literal>String</literal> representation of the
|
|
|
|
+ <interfacename>GrantedAuthority</interfacename>. By returning a representation as a
|
|
|
|
+ <literal>String</literal>, a <interfacename>GrantedAuthority</interfacename> can be easily
|
|
|
|
+ <quote>read</quote> by most <interfacename>AccessDecisionManager</interfacename>s. If a
|
|
|
|
+ <interfacename>GrantedAuthority</interfacename> cannot be precisely represented as a
|
|
|
|
+ <literal>String</literal>, the <interfacename>GrantedAuthority</interfacename> is considered
|
|
|
|
+ <quote>complex</quote> and <literal>getAuthority()</literal> must return
|
|
|
|
+ <literal>null</literal>.</para>
|
|
|
|
+ <para>An example of a <quote>complex</quote>
|
|
|
|
+ <interfacename>GrantedAuthority</interfacename> would be an implementation that stores a list
|
|
|
|
+ of operations and authority thresholds that apply to different customer account numbers.
|
|
|
|
+ Representing this complex <interfacename>GrantedAuthority</interfacename> as a
|
|
|
|
+ <literal>String</literal> would be quite difficult, and as a result the
|
|
|
|
+ <literal>getAuthority()</literal> method should return <literal>null</literal>. This will
|
|
|
|
+ indicate to any <interfacename>AccessDecisionManager</interfacename> that it will need to
|
|
|
|
+ specifically support the <interfacename>GrantedAuthority</interfacename> implementation in
|
|
|
|
+ order to understand its contents.</para>
|
|
|
|
+ <para>Spring Security includes one concrete <interfacename>GrantedAuthority</interfacename>
|
|
|
|
+ implementation, <literal>GrantedAuthorityImpl</literal>. This allows any 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>
|
|
|
|
- As we'll see in the <link xlink:href="#secure-objects" >Technical Overview</link> chapter, Spring
|
|
|
|
- Security provides interceptors which control access to secure objects such as method invocations
|
|
|
|
- or web requests. A pre-invocation decision on whether the invocation is allowed to proceed is made by
|
|
|
|
- the <interfacename>AccessDecisionManager</interfacename>.
|
|
|
|
- </para>
|
|
|
|
-
|
|
|
|
|
|
+ <para> As we've also seen in the <link xlink:href="#secure-objects">Technical Overview</link>
|
|
|
|
+ chapter, Spring Security provides interceptors which control access to secure objects such as
|
|
|
|
+ method invocations or web requests. A pre-invocation decision on whether the invocation is
|
|
|
|
+ allowed to proceed is made by the <interfacename>AccessDecisionManager</interfacename>. </para>
|
|
<section>
|
|
<section>
|
|
<title>The AccessDecisionManager</title>
|
|
<title>The AccessDecisionManager</title>
|
|
- <para>The <interfacename>AccessDecisionManager</interfacename> is called by the
|
|
|
|
- <classname>AbstractSecurityInterceptor</classname> and is responsible for
|
|
|
|
- making final access control decisions. The
|
|
|
|
- <interfacename>AccessDecisionManager</interfacename> interface contains three
|
|
|
|
- methods:
|
|
|
|
- <programlisting>
|
|
|
|
|
|
+ <para>The <interfacename>AccessDecisionManager</interfacename> is called by the
|
|
|
|
+ <classname>AbstractSecurityInterceptor</classname> and is responsible for making final
|
|
|
|
+ access control decisions. The <interfacename>AccessDecisionManager</interfacename> interface
|
|
|
|
+ contains three methods:
|
|
|
|
+ <programlisting>
|
|
void decide(Authentication authentication, Object secureObject,
|
|
void decide(Authentication authentication, Object secureObject,
|
|
List<ConfigAttribute> config) throws AccessDeniedException;
|
|
List<ConfigAttribute> 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
|
|
|
|
- <interfacename>AccessDecisionManager</interfacename> is passed via method
|
|
|
|
- parameters all information that is likely to be of value in assessing
|
|
|
|
- an authorization decision. In particular, passing the secure
|
|
|
|
- <literal>Object</literal> enables those arguments contained in the
|
|
|
|
- actual secure object invocation to be inspected. For example, let's
|
|
|
|
- assume the secure object was a <classname>MethodInvocation</classname>. It
|
|
|
|
- would be easy to query the <classname>MethodInvocation</classname> for any
|
|
|
|
- <literal>Customer</literal> argument, and then implement some sort of
|
|
|
|
- security logic in the <interfacename>AccessDecisionManager</interfacename> to
|
|
|
|
- ensure the principal is permitted to operate on that customer.
|
|
|
|
- Implementations are expected to throw an
|
|
|
|
- <literal>AccessDeniedException</literal> if access is denied.</para>
|
|
|
|
-
|
|
|
|
- <para>The <literal>supports(ConfigAttribute)</literal> method is
|
|
|
|
- called by the <classname>AbstractSecurityInterceptor</classname> at
|
|
|
|
- startup time to determine if the
|
|
|
|
- <interfacename>AccessDecisionManager</interfacename> can process the passed
|
|
|
|
- <literal>ConfigAttribute</literal>. The
|
|
|
|
- <literal>supports(Class)</literal> method is called by a security
|
|
|
|
- interceptor implementation to ensure the configured
|
|
|
|
- <interfacename>AccessDecisionManager</interfacename> supports the type of secure
|
|
|
|
- object that the security interceptor will present.</para>
|
|
|
|
-
|
|
|
|
- <section>
|
|
|
|
- <title>Voting-Based AccessDecisionManager Implementations</title>
|
|
|
|
- <para>Whilst users can implement their own <interfacename>AccessDecisionManager</interfacename> to control all aspects of
|
|
|
|
- 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>
|
|
|
|
-<!--
|
|
|
|
|
|
+ The <interfacename>AccessDecisionManager</interfacename>'s <methodname>decide</methodname>
|
|
|
|
+ method is passed all the relevant information it needs in order to make an authorization
|
|
|
|
+ decision. In particular, passing the secure <literal>Object</literal> enables those
|
|
|
|
+ arguments contained in the actual secure object invocation to be inspected. For example,
|
|
|
|
+ let's assume the secure object was a <classname>MethodInvocation</classname>. It would be
|
|
|
|
+ easy to query the <classname>MethodInvocation</classname> for any
|
|
|
|
+ <literal>Customer</literal> argument, and then implement some sort of security logic in
|
|
|
|
+ the <interfacename>AccessDecisionManager</interfacename> to ensure the principal is
|
|
|
|
+ permitted to operate on that customer. Implementations are expected to throw an
|
|
|
|
+ <literal>AccessDeniedException</literal> if access is denied.</para>
|
|
|
|
+ <para>The <literal>supports(ConfigAttribute)</literal> method is called by the
|
|
|
|
+ <classname>AbstractSecurityInterceptor</classname> at startup time to determine if the
|
|
|
|
+ <interfacename>AccessDecisionManager</interfacename> can process the passed
|
|
|
|
+ <literal>ConfigAttribute</literal>. The <literal>supports(Class)</literal> method is
|
|
|
|
+ called by a security interceptor implementation to ensure the configured
|
|
|
|
+ <interfacename>AccessDecisionManager</interfacename> supports the type of secure object
|
|
|
|
+ that the security interceptor will present.</para>
|
|
|
|
+ <section>
|
|
|
|
+ <title>Voting-Based AccessDecisionManager Implementations</title>
|
|
|
|
+ <para>Whilst users can implement their own
|
|
|
|
+ <interfacename>AccessDecisionManager</interfacename> to control all aspects of
|
|
|
|
+ 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>
|
|
|
|
- <imagedata align="center" scalefit="1" fileref="images/AccessDecisionVoting.gif" format="GIF"/>
|
|
|
|
- </imageobject>
|
|
|
|
- </mediaobject>
|
|
|
|
- </figure>
|
|
|
|
- <para>Using this approach, a series of
|
|
|
|
- <interfacename>AccessDecisionVoter</interfacename> implementations are polled on
|
|
|
|
- an authorization decision. The
|
|
|
|
- <interfacename>AccessDecisionManager</interfacename> then decides whether or not
|
|
|
|
- to throw an <literal>AccessDeniedException</literal> based on its
|
|
|
|
- assessment of the votes.</para>
|
|
|
|
-
|
|
|
|
- <para>The <interfacename>AccessDecisionVoter</interfacename> interface has three
|
|
|
|
- methods:
|
|
|
|
-<programlisting>
|
|
|
|
|
|
+-->
|
|
|
|
+ <imageobject>
|
|
|
|
+ <imagedata align="center" scalefit="1" fileref="images/AccessDecisionVoting.gif"
|
|
|
|
+ format="GIF"/>
|
|
|
|
+ </imageobject>
|
|
|
|
+ </mediaobject>
|
|
|
|
+ </figure>
|
|
|
|
+ <para>Using this approach, a series of <interfacename>AccessDecisionVoter</interfacename>
|
|
|
|
+ implementations are polled on an authorization decision. The
|
|
|
|
+ <interfacename>AccessDecisionManager</interfacename> then decides whether or not to
|
|
|
|
+ throw an <literal>AccessDeniedException</literal> based on its assessment of the
|
|
|
|
+ votes.</para>
|
|
|
|
+ <para>The <interfacename>AccessDecisionVoter</interfacename> interface has three methods:
|
|
|
|
+ <programlisting>
|
|
int vote(Authentication authentication, Object object, List<ConfigAttribute> config);
|
|
int vote(Authentication authentication, Object object, List<ConfigAttribute> 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
|
|
|
|
- possible values being reflected in the
|
|
|
|
- <interfacename>AccessDecisionVoter</interfacename> static fields
|
|
|
|
- <literal>ACCESS_ABSTAIN</literal>, <literal>ACCESS_DENIED</literal>
|
|
|
|
- and <literal>ACCESS_GRANTED</literal>. A voting implementation will
|
|
|
|
- return <literal>ACCESS_ABSTAIN</literal> if it has no opinion on an
|
|
|
|
- authorization decision. If it does have an opinion, it must return
|
|
|
|
- either <literal>ACCESS_DENIED</literal> or
|
|
|
|
- <literal>ACCESS_GRANTED</literal>.</para>
|
|
|
|
-
|
|
|
|
- <para>There are three concrete
|
|
|
|
- <interfacename>AccessDecisionManager</interfacename>s 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. Properties are provided to control behavior in the
|
|
|
|
- event of an equality of votes or if all votes are abstain. The
|
|
|
|
- <literal>AffirmativeBased</literal> implementation will grant access
|
|
|
|
- if one or more <literal>ACCESS_GRANTED</literal> votes were received
|
|
|
|
- (i.e. a deny vote will be ignored, provided there was at least one grant
|
|
|
|
- vote). Like the <literal>ConsensusBased</literal> implementation,
|
|
|
|
- there is a parameter that controls the behavior if all voters abstain.
|
|
|
|
- The <literal>UnanimousBased</literal> provider expects unanimous
|
|
|
|
- <literal>ACCESS_GRANTED</literal> votes in order to grant access,
|
|
|
|
- ignoring abstains. It will deny access if there is any
|
|
|
|
- <literal>ACCESS_DENIED</literal> vote. Like the other implementations,
|
|
|
|
- there is a parameter that controls the behaviour if all voters
|
|
|
|
- abstain.</para>
|
|
|
|
-
|
|
|
|
- <para>It is possible to implement a custom
|
|
|
|
- <interfacename>AccessDecisionManager</interfacename> that tallies votes
|
|
|
|
- differently. For example, votes from a particular
|
|
|
|
- <interfacename>AccessDecisionVoter</interfacename> might receive additional
|
|
|
|
- weighting, whilst a deny vote from a particular voter may have a veto
|
|
|
|
- effect.</para>
|
|
|
|
-
|
|
|
|
- <section>
|
|
|
|
- <title><classname>RoleVoter</classname></title>
|
|
|
|
- <para>
|
|
|
|
- The most commonly used <interfacename>AccessDecisionVoter</interfacename>
|
|
|
|
- provided with Spring Security is the simple <classname>RoleVoter</classname>, which treats
|
|
|
|
- configuration attributes as simple role names and votes to grant access if the user has been assigned
|
|
|
|
- that role.</para>
|
|
|
|
- <para>It will vote if any ConfigAttribute begins with the prefix <literal>ROLE_</literal>.
|
|
|
|
- It will vote to grant access if there is a <interfacename>GrantedAuthority</interfacename> which returns a
|
|
|
|
- <literal>String</literal> representation (via the
|
|
|
|
- <literal>getAuthority()</literal> method) exactly equal to one or more
|
|
|
|
- <literal>ConfigAttributes</literal> starting with
|
|
|
|
- <literal>ROLE_</literal>. If there is no exact match of any
|
|
|
|
- <literal>ConfigAttribute</literal> starting with
|
|
|
|
- <literal>ROLE_</literal>, the <literal>RoleVoter</literal> will vote
|
|
|
|
- to deny access. If no <literal>ConfigAttribute</literal> begins with
|
|
|
|
- <literal>ROLE_</literal>, the voter will abstain.
|
|
|
|
- <literal>RoleVoter</literal> is case sensitive on comparisons as well
|
|
|
|
- as the <literal>ROLE_</literal> prefix.</para>
|
|
|
|
- </section>
|
|
|
|
-
|
|
|
|
- <section>
|
|
|
|
- <title>Custom Voters</title>
|
|
|
|
- <para>It is also possible to implement a custom
|
|
|
|
- <interfacename>AccessDecisionVoter</interfacename>. Several examples are provided
|
|
|
|
- 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>
|
|
|
|
|
|
+ Concrete implementations return an <literal>int</literal>, with possible values being
|
|
|
|
+ reflected in the <interfacename>AccessDecisionVoter</interfacename> static fields
|
|
|
|
+ <literal>ACCESS_ABSTAIN</literal>, <literal>ACCESS_DENIED</literal> and
|
|
|
|
+ <literal>ACCESS_GRANTED</literal>. A voting implementation will return
|
|
|
|
+ <literal>ACCESS_ABSTAIN</literal> if it has no opinion on an authorization decision. If
|
|
|
|
+ it does have an opinion, it must return either <literal>ACCESS_DENIED</literal> or
|
|
|
|
+ <literal>ACCESS_GRANTED</literal>.</para>
|
|
|
|
+ <para>There are three concrete <interfacename>AccessDecisionManager</interfacename>s
|
|
|
|
+ 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.
|
|
|
|
+ Properties are provided to control behavior in the event of an equality of votes or if all
|
|
|
|
+ votes are abstain. The <literal>AffirmativeBased</literal> implementation will grant
|
|
|
|
+ access if one or more <literal>ACCESS_GRANTED</literal> votes were received (i.e. a deny
|
|
|
|
+ vote will be ignored, provided there was at least one grant vote). Like the
|
|
|
|
+ <literal>ConsensusBased</literal> implementation, there is a parameter that controls the
|
|
|
|
+ behavior if all voters abstain. The <literal>UnanimousBased</literal> provider expects
|
|
|
|
+ unanimous <literal>ACCESS_GRANTED</literal> votes in order to grant access, ignoring
|
|
|
|
+ abstains. It will deny access if there is any <literal>ACCESS_DENIED</literal> vote. Like
|
|
|
|
+ the other implementations, there is a parameter that controls the behaviour if all voters
|
|
|
|
+ abstain.</para>
|
|
|
|
+ <para>It is possible to implement a custom
|
|
|
|
+ <interfacename>AccessDecisionManager</interfacename> that tallies votes differently. For
|
|
|
|
+ example, votes from a particular <interfacename>AccessDecisionVoter</interfacename> might
|
|
|
|
+ receive additional weighting, whilst a deny vote from a particular voter may have a veto
|
|
|
|
+ effect.</para>
|
|
|
|
+ <section>
|
|
|
|
+ <title><classname>RoleVoter</classname></title>
|
|
|
|
+ <para> The most commonly used <interfacename>AccessDecisionVoter</interfacename> provided
|
|
|
|
+ with Spring Security is the simple <classname>RoleVoter</classname>, which treats
|
|
|
|
+ configuration attributes as simple role names and votes to grant access if the user has
|
|
|
|
+ been assigned that role.</para>
|
|
|
|
+ <para>It will vote if any ConfigAttribute begins with the prefix <literal>ROLE_</literal>.
|
|
|
|
+ It will vote to grant access if there is a
|
|
|
|
+ <interfacename>GrantedAuthority</interfacename> which returns a
|
|
|
|
+ <literal>String</literal> representation (via the <literal>getAuthority()</literal>
|
|
|
|
+ method) exactly equal to one or more <literal>ConfigAttributes</literal> starting with
|
|
|
|
+ <literal>ROLE_</literal>. If there is no exact match of any
|
|
|
|
+ <literal>ConfigAttribute</literal> starting with <literal>ROLE_</literal>, the
|
|
|
|
+ <literal>RoleVoter</literal> will vote to deny access. If no
|
|
|
|
+ <literal>ConfigAttribute</literal> begins with <literal>ROLE_</literal>, the voter
|
|
|
|
+ will abstain. <literal>RoleVoter</literal> is case sensitive on comparisons as well as
|
|
|
|
+ the <literal>ROLE_</literal> prefix.</para>
|
|
|
|
+ </section>
|
|
|
|
+ <section>
|
|
|
|
+ <title>Custom Voters</title>
|
|
|
|
+ <para>It is also possible to implement a custom
|
|
|
|
+ <interfacename>AccessDecisionVoter</interfacename>. Several examples are provided 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>
|
|
|
|
- <para>Whilst the <interfacename>AccessDecisionManager</interfacename> is called by
|
|
|
|
- the <classname>AbstractSecurityInterceptor</classname> before proceeding
|
|
|
|
- with the secure object invocation, some applications need a way of
|
|
|
|
- modifying the object actually returned by the secure object
|
|
|
|
- invocation. Whilst you could easily implement your own AOP concern to
|
|
|
|
- achieve this, Spring Security provides a convenient hook that has
|
|
|
|
- several concrete implementations that integrate with its ACL
|
|
|
|
- capabilities.</para>
|
|
|
|
-
|
|
|
|
|
|
+ <info>
|
|
|
|
+ <title>After Invocation Handling</title>
|
|
|
|
+ </info>
|
|
|
|
+ <para>Whilst the <interfacename>AccessDecisionManager</interfacename> is called by the
|
|
|
|
+ <classname>AbstractSecurityInterceptor</classname> before proceeding with the secure object
|
|
|
|
+ invocation, some applications need a way of modifying the object actually returned by the
|
|
|
|
+ secure object invocation. Whilst you could easily implement your own AOP concern to achieve
|
|
|
|
+ this, Spring Security provides a convenient hook that has several concrete implementations
|
|
|
|
+ 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
|
|
|
|
- implementations.
|
|
|
|
-
|
|
|
|
- <figure xml:id="authz-after-invocation">
|
|
|
|
- <title>After Invocation Implementation</title>
|
|
|
|
- <mediaobject>
|
|
|
|
- <imageobject>
|
|
|
|
- <imagedata align="center" scalefit="1" fileref="images/AfterInvocation.gif" format="GIF"/>
|
|
|
|
- </imageobject>
|
|
|
|
- </mediaobject>
|
|
|
|
-
|
|
|
|
- </figure>
|
|
|
|
- </para>
|
|
|
|
-
|
|
|
|
- <para>Like many other parts of Spring Security,
|
|
|
|
- <literal>AfterInvocationManager</literal> has a single concrete
|
|
|
|
- implementation, <literal>AfterInvocationProviderManager</literal>,
|
|
|
|
- which polls a list of <literal>AfterInvocationProvider</literal>s.
|
|
|
|
- Each <literal>AfterInvocationProvider</literal> is allowed to modify
|
|
|
|
- the return object or throw an
|
|
|
|
- <literal>AccessDeniedException</literal>. Indeed multiple providers
|
|
|
|
- can modify the object, as the result of the previous provider is
|
|
|
|
- passed to the next in the list. Let's now consider our ACL-aware
|
|
|
|
- implementations of <literal>AfterInvocationProvider</literal>.</para>
|
|
|
|
-
|
|
|
|
- <para>Please be aware that if you're using
|
|
|
|
- <literal>AfterInvocationManager</literal>, you will still need
|
|
|
|
- configuration attributes that allow the
|
|
|
|
- <classname>MethodSecurityInterceptor</classname>'s
|
|
|
|
- <interfacename>AccessDecisionManager</interfacename> to allow an operation. If
|
|
|
|
- you're using the typical Spring Security included
|
|
|
|
- <interfacename>AccessDecisionManager</interfacename> implementations, having no
|
|
|
|
- configuration attributes defined for a particular secure method
|
|
|
|
- invocation will cause each <interfacename>AccessDecisionVoter</interfacename> to
|
|
|
|
- abstain from voting. In turn, if the
|
|
|
|
- <interfacename>AccessDecisionManager</interfacename> property
|
|
|
|
- "<literal>allowIfAllAbstainDecisions</literal>" is
|
|
|
|
- <literal>false</literal>, an <literal>AccessDeniedException</literal>
|
|
|
|
- will be thrown. You may avoid this potential issue by either (i)
|
|
|
|
- setting "<literal>allowIfAllAbstainDecisions</literal>" to
|
|
|
|
- <literal>true</literal> (although this is generally not recommended)
|
|
|
|
- or (ii) simply ensure that there is at least one configuration
|
|
|
|
- attribute that an <interfacename>AccessDecisionVoter</interfacename> will vote to
|
|
|
|
- grant access for. This latter (recommended) approach is usually
|
|
|
|
- achieved through a <literal>ROLE_USER</literal> or
|
|
|
|
- <literal>ROLE_AUTHENTICATED</literal> configuration attribute</para>
|
|
|
|
-
|
|
|
|
- <section xml:id="after-invocation-acl-aware"><info><title>ACL-Aware AfterInvocationProviders</title></info>
|
|
|
|
-<!-- TODO: Move to ACL section and add reference here -->
|
|
|
|
- <para>A common services layer method we've all written at one stage
|
|
|
|
- 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[
|
|
|
|
|
|
+ <literal>AfterInvocationManager</literal> and its concrete implementations. <figure
|
|
|
|
+ xml:id="authz-after-invocation">
|
|
|
|
+ <title>After Invocation Implementation</title>
|
|
|
|
+ <mediaobject>
|
|
|
|
+ <imageobject>
|
|
|
|
+ <imagedata align="center" scalefit="1" fileref="images/AfterInvocation.gif" format="GIF"
|
|
|
|
+ />
|
|
|
|
+ </imageobject>
|
|
|
|
+ </mediaobject>
|
|
|
|
+ </figure></para>
|
|
|
|
+ <para>Like many other parts of Spring Security, <literal>AfterInvocationManager</literal> has a
|
|
|
|
+ single concrete implementation, <literal>AfterInvocationProviderManager</literal>, which polls
|
|
|
|
+ a list of <literal>AfterInvocationProvider</literal>s. Each
|
|
|
|
+ <literal>AfterInvocationProvider</literal> is allowed to modify the return object or throw
|
|
|
|
+ an <literal>AccessDeniedException</literal>. Indeed multiple providers can modify the object,
|
|
|
|
+ as the result of the previous provider is passed to the next in the list. Let's now consider
|
|
|
|
+ our ACL-aware implementations of <literal>AfterInvocationProvider</literal>.</para>
|
|
|
|
+ <para>Please be aware that if you're using <literal>AfterInvocationManager</literal>, you will
|
|
|
|
+ still need configuration attributes that allow the
|
|
|
|
+ <classname>MethodSecurityInterceptor</classname>'s
|
|
|
|
+ <interfacename>AccessDecisionManager</interfacename> to allow an operation. If you're using
|
|
|
|
+ the typical Spring Security included <interfacename>AccessDecisionManager</interfacename>
|
|
|
|
+ implementations, having no configuration attributes defined for a particular secure method
|
|
|
|
+ invocation will cause each <interfacename>AccessDecisionVoter</interfacename> to abstain from
|
|
|
|
+ voting. In turn, if the <interfacename>AccessDecisionManager</interfacename> property
|
|
|
|
+ "<literal>allowIfAllAbstainDecisions</literal>" is <literal>false</literal>, an
|
|
|
|
+ <literal>AccessDeniedException</literal> will be thrown. You may avoid this potential issue
|
|
|
|
+ by either (i) setting "<literal>allowIfAllAbstainDecisions</literal>" to
|
|
|
|
+ <literal>true</literal> (although this is generally not recommended) or (ii) simply ensure
|
|
|
|
+ that there is at least one configuration attribute that an
|
|
|
|
+ <interfacename>AccessDecisionVoter</interfacename> will vote to grant access for. This
|
|
|
|
+ latter (recommended) approach is usually achieved through a <literal>ROLE_USER</literal> or
|
|
|
|
+ <literal>ROLE_AUTHENTICATED</literal> configuration attribute</para>
|
|
|
|
+ <section xml:id="after-invocation-acl-aware">
|
|
|
|
+ <info>
|
|
|
|
+ <title>ACL-Aware AfterInvocationProviders</title>
|
|
|
|
+ </info>
|
|
|
|
+ <!-- TODO: Move to ACL section and add reference here -->
|
|
|
|
+ <para>A common services layer method we've all written at one stage 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>
|
|
|
|
- In the above example, the <literal>Contact</literal> will be
|
|
|
|
- retrieved and passed to the
|
|
|
|
- <classname>AclEntryAfterInvocationProvider</classname>. The provider
|
|
|
|
- will thrown an <classname>AccessDeniedException</classname> if one of
|
|
|
|
- the listed <literal>requirePermission</literal>s is not held by the
|
|
|
|
- <interfacename>Authentication</interfacename>. The
|
|
|
|
- <classname>AclEntryAfterInvocationProvider</classname> queries the
|
|
|
|
- acl service to determine the ACL that applies for
|
|
|
|
- this domain object to this <interfacename>Authentication</interfacename>.</para>
|
|
|
|
-
|
|
|
|
- <para>Similar to the
|
|
|
|
- <classname>AclEntryAfterInvocationProvider</classname> is
|
|
|
|
- <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[
|
|
|
|
|
|
+]]></programlisting> In the above example, the <literal>Contact</literal> will be retrieved and
|
|
|
|
+ passed to the <classname>AclEntryAfterInvocationProvider</classname>. The provider will
|
|
|
|
+ thrown an <classname>AccessDeniedException</classname> if one of the listed
|
|
|
|
+ <literal>requirePermission</literal>s is not held by the
|
|
|
|
+ <interfacename>Authentication</interfacename>. The
|
|
|
|
+ <classname>AclEntryAfterInvocationProvider</classname> queries the acl service to
|
|
|
|
+ determine the ACL that applies for this domain object to this
|
|
|
|
+ <interfacename>Authentication</interfacename>.</para>
|
|
|
|
+ <para>Similar to the <classname>AclEntryAfterInvocationProvider</classname> is
|
|
|
|
+ <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>
|
|
|
|
- As you can imagine, the returned <literal>Object</literal>
|
|
|
|
- must be a <literal>Collection</literal> or array for this provider
|
|
|
|
- to operate. It will remove any element if the
|
|
|
|
- <literal>AclManager</literal> indicates the
|
|
|
|
- <interfacename>Authentication</interfacename> does not hold one of the listed
|
|
|
|
- <literal>requirePermission</literal>s.</para>
|
|
|
|
-
|
|
|
|
|
|
+]]> </programlisting> As you can imagine, the returned <literal>Object</literal> must be a
|
|
|
|
+ <literal>Collection</literal> or array for this provider to operate. It will remove any
|
|
|
|
+ element if the <literal>AclManager</literal> indicates the
|
|
|
|
+ <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>
|
|
|
|
-
|
|
|
|
- <para><literal>AuthorizeTag</literal> is used to include content if
|
|
|
|
- the current principal holds certain
|
|
|
|
- <interfacename>GrantedAuthority</interfacename>s.</para>
|
|
|
|
-
|
|
|
|
|
|
+ <info>
|
|
|
|
+ <title>Authorization Tag Libraries</title>
|
|
|
|
+ </info>
|
|
|
|
+ <para><literal>AuthorizeTag</literal> is used to include content if the current principal holds
|
|
|
|
+ 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>
|
|
|
|
-
|
|
|
|
- <para><programlisting>
|
|
|
|
|
|
+ <literal>AuthorizeTag</literal>:</para>
|
|
|
|
+ <para>
|
|
|
|
+ <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>
|
|
|
|
-
|
|
|
|
- <para>This tag would cause the tag's body to be output if the
|
|
|
|
- principal has been granted ROLE_SUPERVISOR.</para>
|
|
|
|
-
|
|
|
|
- <para>The <literal>security:authorize</literal> tag declares the
|
|
|
|
- following attributes:</para>
|
|
|
|
-
|
|
|
|
- <para><itemizedlist spacing="compact">
|
|
|
|
|
|
+]]></programlisting>
|
|
|
|
+ </para>
|
|
|
|
+ <para>This tag would cause the tag's body to be output if the principal has been granted
|
|
|
|
+ ROLE_SUPERVISOR.</para>
|
|
|
|
+ <para>The <literal>security:authorize</literal> tag declares the following attributes:</para>
|
|
|
|
+ <para>
|
|
|
|
+ <itemizedlist spacing="compact">
|
|
<listitem>
|
|
<listitem>
|
|
- <para><literal>ifAllGranted</literal>: All the listed roles must
|
|
|
|
- be granted for the tag to output its body.</para>
|
|
|
|
|
|
+ <para><literal>ifAllGranted</literal>: All the listed roles must be granted for the tag to
|
|
|
|
+ output its body.</para>
|
|
</listitem>
|
|
</listitem>
|
|
-
|
|
|
|
<listitem>
|
|
<listitem>
|
|
- <para><literal>ifAnyGranted</literal>: Any of the listed roles
|
|
|
|
- must be granted for the tag to output its body.</para>
|
|
|
|
|
|
+ <para><literal>ifAnyGranted</literal>: Any of the listed roles must be granted for the tag
|
|
|
|
+ to output its body.</para>
|
|
</listitem>
|
|
</listitem>
|
|
-
|
|
|
|
<listitem>
|
|
<listitem>
|
|
- <para><literal>ifNotGranted</literal>: None of the listed roles
|
|
|
|
- must be granted for the tag to output its body.</para>
|
|
|
|
|
|
+ <para><literal>ifNotGranted</literal>: None of the listed roles must be granted for the
|
|
|
|
+ tag to output its body.</para>
|
|
</listitem>
|
|
</listitem>
|
|
- </itemizedlist></para>
|
|
|
|
-
|
|
|
|
- <para>You'll note that in each attribute you can list multiple roles.
|
|
|
|
- Simply separate the roles using a comma. The
|
|
|
|
- <literal>authorize</literal> tag ignores whitespace in
|
|
|
|
- attributes.</para>
|
|
|
|
-
|
|
|
|
- <para>The tag library logically ANDs all of it's parameters together.
|
|
|
|
- This means that if you 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
|
|
|
|
- <literal>ifNotGranted="ROLE_SUPERVISOR"</literal>, or you'll be
|
|
|
|
- surprised to never see the tag's body.</para>
|
|
|
|
-
|
|
|
|
- <para>By requiring all attributes to return true, the authorize tag
|
|
|
|
- allows you to create more complex authorization scenarios. For
|
|
|
|
- example, you could declare an
|
|
|
|
- <literal>ifAllGranted="ROLE_SUPERVISOR"</literal> and an
|
|
|
|
- <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
|
|
|
|
- <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>
|
|
|
|
-
|
|
|
|
|
|
+ </itemizedlist>
|
|
|
|
+ </para>
|
|
|
|
+ <para>You'll note that in each attribute you can list multiple roles. Simply separate the roles
|
|
|
|
+ using a comma. The <literal>authorize</literal> tag ignores whitespace in attributes.</para>
|
|
|
|
+ <para>The tag library logically ANDs all of it's parameters together. This means that if you
|
|
|
|
+ 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
|
|
|
|
+ <literal>ifNotGranted="ROLE_SUPERVISOR"</literal>, or you'll be surprised to never see the
|
|
|
|
+ tag's body.</para>
|
|
|
|
+ <para>By requiring all attributes to return true, the authorize tag allows you to create more
|
|
|
|
+ complex authorization scenarios. For example, you could declare an
|
|
|
|
+ <literal>ifAllGranted="ROLE_SUPERVISOR"</literal> and an
|
|
|
|
+ <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
|
|
|
|
+ <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>:
|
|
|
|
-<programlisting><![CDATA[
|
|
|
|
|
|
+ <literal>AccessControlListTag</literal>: <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>
|
|
|
|
- This tag would cause the tag's body to be output if the
|
|
|
|
- principal holds either permission 16 or permission 1 for the "contact"
|
|
|
|
- domain object. The numbers are actually integers that are used with
|
|
|
|
- <literal>BasePermission</literal> bit masking. Please refer to the ACL
|
|
|
|
- section of this reference guide to understand more about the ACL
|
|
|
|
- capabilities of Spring Security.</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>
|
|
|
|
|
|
+]]></programlisting> This tag would cause the tag's body to be output if the principal holds either
|
|
|
|
+ permission 16 or permission 1 for the "contact" domain object. The numbers are actually
|
|
|
|
+ integers that are used with <literal>BasePermission</literal> bit masking. Please refer to the
|
|
|
|
+ ACL section of this reference guide to understand more about the ACL capabilities of Spring
|
|
|
|
+ Security.</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>
|