Whilst the AccessDecisionManager
is called by
the AbstractSecurityInterceptor
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.
Figure 22.2, “After Invocation Implementation” illustrates Spring Security's
AfterInvocationManager
and its concrete
implementations.
Like many other parts of Spring Security,
AfterInvocationManager
has a single concrete
implementation, AfterInvocationProviderManager
,
which polls a list of AfterInvocationProvider
s.
Each AfterInvocationProvider
is allowed to modify
the return object or throw an
AccessDeniedException
. 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 AfterInvocationProvider
.
Please be aware that if you're using
AfterInvocationManager
, you will still need
configuration attributes that allow the
MethodSecurityInterceptor
's
AccessDecisionManager
to allow an operation. If
you're using the typical Spring Security included
AccessDecisionManager
implementations, having no
configuration attributes defined for a particular secure method
invocation will cause each AccessDecisionVoter
to
abstain from voting. In turn, if the
AccessDecisionManager
property
"allowIfAllAbstainDecisions
" is
false
, an AccessDeniedException
will be thrown. You may avoid this potential issue by either (i)
setting "allowIfAllAbstainDecisions
" to
true
(although this is generally not recommended)
or (ii) simply ensure that there is at least one configuration
attribute that an AccessDecisionVoter
will vote to
grant access for. This latter (recommended) approach is usually
achieved through a ROLE_USER
or
ROLE_AUTHENTICATED
configuration attribute
PLEASE NOTE: Acegi Security 1.0.3 contains a preview of a new
ACL module. The new ACL module is a significant rewrite of the
existing ACL module. The new module can be found under the
org.springframework.security.acls
package, with
the old ACL module under
org.springframework.security.acl
. We encourage
users to consider testing with the new ACL module and build
applications with it. The old ACL module should be considered
deprecated and may be removed from a future release. The following
information relates to the new ACL package, and is thus
recommended.
A common services layer method we've all written at one stage or another looks like this:
public Contact getById(Integer id);
Quite often, only principals with permission to read the
Contact
should be allowed to obtain it. In this
situation the AccessDecisionManager
approach
provided by the AbstractSecurityInterceptor
will
not suffice. This is because the identity of the
Contact
is all that is available before the
secure object is invoked. The
AclAfterInvocationProvider
delivers a solution,
and is configured as follows:
<bean id="afterAclRead" class="org.springframework.security.afterinvocation.AclEntryAfterInvocationProvider"> <constructor-arg ref="aclService"/> <constructor-arg> <list> <ref local="org.springframework.security.acls.domain.BasePermission.ADMINISTRATION"/> <ref local="org.springframework.security.acls.domain.BasePermission.READ"/> </list> </constructor-arg> </bean>
In the above example, the Contact
will be
retrieved and passed to the
AclEntryAfterInvocationProvider
. The provider
will thrown an AccessDeniedException
if one of
the listed requirePermission
s is not held by the
Authentication
. The
AclEntryAfterInvocationProvider
queries the
Acl
Service to determine the ACL that applies for
this domain object to this Authentication
.
Similar to the
AclEntryAfterInvocationProvider
is
AclEntryAfterInvocationCollectionFilteringProvider
.
It is designed to remove Collection
or array
elements for which a principal does not have access. It never thrown
an AccessDeniedException
- simply silently
removes the offending elements. The provider is configured as
follows:
<bean id="afterAclCollectionRead" class="org.springframework.security.afterinvocation.AclEntryAfterInvocationCollectionFilteringProvider"> <constructor-arg ref="aclService"/> <constructor-arg> <list> <ref local="org.springframework.security.acls.domain.BasePermission.ADMINISTRATION"/> <ref local="org.springframework.security.acls.domain.BasePermission.READ"/> </list> </constructor-arg> </bean>
As you can imagine, the returned Object
must be a Collection
or array for this provider
to operate. It will remove any element if the
AclManager
indicates the
Authentication
does not hold one of the listed
requirePermission
s.
The Contacts sample application demonstrates these two
AfterInvocationProvider
s.
PLEASE NOTE: Acegi Security 1.0.3 contains a preview of a new
ACL module. The new ACL module is a significant rewrite of the
existing ACL module. The new module can be found under the
org.springframework.security.acls
package, with
the old ACL module under
org.springframework.security.acl
. We encourage
users to consider testing with the new ACL module and build
applications with it. The old ACL module should be considered
deprecated and may be removed from a future release.
A common services layer method we've all written at one stage or another looks like this:
public Contact getById(Integer id);
Quite often, only principals with permission to read the
Contact
should be allowed to obtain it. In this
situation the AccessDecisionManager
approach
provided by the AbstractSecurityInterceptor
will
not suffice. This is because the identity of the
Contact
is all that is available before the
secure object is invoked. The
BasicAclAfterInvocationProvider
delivers a
solution, and is configured as follows:
<bean id="afterAclRead" class="org.springframework.security.afterinvocation.BasicAclEntryAfterInvocationProvider"> <property name="aclManager" ref="aclManager"/> <property name="requirePermission"> <list> <ref local="org.springframework.security.acl.basic.SimpleAclEntry.ADMINISTRATION"/> <ref local="org.springframework.security.acl.basic.SimpleAclEntry.READ"/> </list> </property> </bean>
In the above example, the Contact
will be
retrieved and passed to the
BasicAclEntryAfterInvocationProvider
. The
provider will thrown an AccessDeniedException
if
one of the listed requirePermission
s is not held
by the Authentication
. The
BasicAclEntryAfterInvocationProvider
queries the
AclManager
to determine the ACL that applies for
this domain object to this Authentication
.
Similar to the
BasicAclEntryAfterInvocationProvider
is
BasicAclEntryAfterInvocationCollectionFilteringProvider
.
It is designed to remove Collection
or array
elements for which a principal does not have access. It never thrown
an AccessDeniedException
- simply silently
removes the offending elements. The provider is configured as
follows:
<bean id="afterAclCollectionRead" class="org.springframework.security.afterinvocation.BasicAclEntryAfterInvocationCollectionFilteringProvider"> <property name="aclManager" ref="aclManager"/> <property name="requirePermission"> <list> <ref local="org.springframework.security.acl.basic.SimpleAclEntry.ADMINISTRATION"/> <ref local="org.springframework.security.acl.basic.SimpleAclEntry.READ"/> </list> </property> </bean>
As you can imagine, the returned Object
must be a Collection
or array for this provider
to operate. It will remove any element if the
AclManager
indicates the
Authentication
does not hold one of the listed
requirePermission
s.
The Contacts sample application demonstrates these two
AfterInvocationProvider
s.