Skip to content

Commit 35345fa

Browse files
committed
Extract authorization subsections
Issue: gh-2567
1 parent 8cf5103 commit 35345fa

File tree

6 files changed

+734
-729
lines changed

6 files changed

+734
-729
lines changed

docs/manual/src/docs/asciidoc/_includes/authorization.adoc

-728
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
2+
[[authz-arch]]
3+
== Authorization Architecture
4+
5+
6+
[[authz-authorities]]
7+
=== Authorities
8+
As we saw in the <<tech-granted-authority,technical overview>>, all `Authentication` implementations store a list of `GrantedAuthority` objects.
9+
These represent the authorities that have been granted to the principal.
10+
the `GrantedAuthority` objects are inserted into the `Authentication` object by the `AuthenticationManager` and are later read by `AccessDecisionManager` s when making authorization decisions.
11+
12+
`GrantedAuthority` is an interface with only one method:
13+
14+
[source,java]
15+
----
16+
17+
String getAuthority();
18+
19+
----
20+
21+
This method allows
22+
`AccessDecisionManager` s to obtain a precise `String` representation of the `GrantedAuthority`.
23+
By returning a representation as a `String`, a `GrantedAuthority` can be easily "read" by most `AccessDecisionManager` s.
24+
If a `GrantedAuthority` cannot be precisely represented as a `String`, the `GrantedAuthority` is considered "complex" and `getAuthority()` must return `null`.
25+
26+
An example of a "complex" `GrantedAuthority` would be an implementation that stores a list of operations and authority thresholds that apply to different customer account numbers.
27+
Representing this complex `GrantedAuthority` as a `String` would be quite difficult, and as a result the `getAuthority()` method should return `null`.
28+
This will indicate to any `AccessDecisionManager` that it will need to specifically support the `GrantedAuthority` implementation in order to understand its contents.
29+
30+
Spring Security includes one concrete `GrantedAuthority` implementation, `SimpleGrantedAuthority`.
31+
This allows any user-specified `String` to be converted into a `GrantedAuthority`.
32+
All `AuthenticationProvider` s included with the security architecture use `SimpleGrantedAuthority` to populate the `Authentication` object.
33+
34+
35+
[[authz-pre-invocation]]
36+
=== Pre-Invocation Handling
37+
As we've also seen in the <<secure-objects,Technical Overview>> chapter, Spring Security provides interceptors which control access to secure objects such as method invocations or web requests.
38+
A pre-invocation decision on whether the invocation is allowed to proceed is made by the `AccessDecisionManager`.
39+
40+
41+
[[authz-access-decision-manager]]
42+
==== The AccessDecisionManager
43+
The `AccessDecisionManager` is called by the `AbstractSecurityInterceptor` and is responsible for making final access control decisions.
44+
the `AccessDecisionManager` interface contains three methods:
45+
46+
[source,java]
47+
----
48+
void decide(Authentication authentication, Object secureObject,
49+
Collection<ConfigAttribute> attrs) throws AccessDeniedException;
50+
51+
boolean supports(ConfigAttribute attribute);
52+
53+
boolean supports(Class clazz);
54+
----
55+
56+
The ``AccessDecisionManager``'s `decide` method is passed all the relevant information it needs in order to make an authorization decision.
57+
In particular, passing the secure `Object` enables those arguments contained in the actual secure object invocation to be inspected.
58+
For example, let's assume the secure object was a `MethodInvocation`.
59+
It would be easy to query the `MethodInvocation` for any `Customer` argument, and then implement some sort of security logic in the `AccessDecisionManager` to ensure the principal is permitted to operate on that customer.
60+
Implementations are expected to throw an `AccessDeniedException` if access is denied.
61+
62+
The `supports(ConfigAttribute)` method is called by the `AbstractSecurityInterceptor` at startup time to determine if the `AccessDecisionManager` can process the passed `ConfigAttribute`.
63+
The `supports(Class)` method is called by a security interceptor implementation to ensure the configured `AccessDecisionManager` supports the type of secure object that the security interceptor will present.
64+
65+
[[authz-voting-based]]
66+
==== Voting-Based AccessDecisionManager Implementations
67+
Whilst users can implement their own `AccessDecisionManager` to control all aspects of authorization, Spring Security includes several `AccessDecisionManager` implementations that are based on voting.
68+
<<authz-access-voting>> illustrates the relevant classes.
69+
70+
[[authz-access-voting]]
71+
.Voting Decision Manager
72+
image::images/access-decision-voting.png[]
73+
74+
75+
76+
Using this approach, a series of `AccessDecisionVoter` implementations are polled on an authorization decision.
77+
The `AccessDecisionManager` then decides whether or not to throw an `AccessDeniedException` based on its assessment of the votes.
78+
79+
The `AccessDecisionVoter` interface has three methods:
80+
81+
[source,java]
82+
----
83+
int vote(Authentication authentication, Object object, Collection<ConfigAttribute> attrs);
84+
85+
boolean supports(ConfigAttribute attribute);
86+
87+
boolean supports(Class clazz);
88+
----
89+
90+
Concrete implementations return an `int`, with possible values being reflected in the `AccessDecisionVoter` static fields `ACCESS_ABSTAIN`, `ACCESS_DENIED` and `ACCESS_GRANTED`.
91+
A voting implementation will return `ACCESS_ABSTAIN` if it has no opinion on an authorization decision.
92+
If it does have an opinion, it must return either `ACCESS_DENIED` or `ACCESS_GRANTED`.
93+
94+
There are three concrete `AccessDecisionManager` s provided with Spring Security that tally the votes.
95+
The `ConsensusBased` implementation will grant or deny access based on the consensus of non-abstain votes.
96+
Properties are provided to control behavior in the event of an equality of votes or if all votes are abstain.
97+
The `AffirmativeBased` implementation will grant access if one or more `ACCESS_GRANTED` votes were received (i.e. a deny vote will be ignored, provided there was at least one grant vote).
98+
Like the `ConsensusBased` implementation, there is a parameter that controls the behavior if all voters abstain.
99+
The `UnanimousBased` provider expects unanimous `ACCESS_GRANTED` votes in order to grant access, ignoring abstains.
100+
It will deny access if there is any `ACCESS_DENIED` vote.
101+
Like the other implementations, there is a parameter that controls the behaviour if all voters abstain.
102+
103+
It is possible to implement a custom `AccessDecisionManager` that tallies votes differently.
104+
For example, votes from a particular `AccessDecisionVoter` might receive additional weighting, whilst a deny vote from a particular voter may have a veto effect.
105+
106+
107+
[[authz-role-voter]]
108+
===== RoleVoter
109+
The most commonly used `AccessDecisionVoter` provided with Spring Security is the simple `RoleVoter`, which treats configuration attributes as simple role names and votes to grant access if the user has been assigned that role.
110+
111+
It will vote if any `ConfigAttribute` begins with the prefix `ROLE_`.
112+
It will vote to grant access if there is a `GrantedAuthority` which returns a `String` representation (via the `getAuthority()` method) exactly equal to one or more `ConfigAttributes` starting with the prefix `ROLE_`.
113+
If there is no exact match of any `ConfigAttribute` starting with `ROLE_`, the `RoleVoter` will vote to deny access.
114+
If no `ConfigAttribute` begins with `ROLE_`, the voter will abstain.
115+
116+
117+
[[authz-authenticated-voter]]
118+
===== AuthenticatedVoter
119+
Another voter which we've implicitly seen is the `AuthenticatedVoter`, which can be used to differentiate between anonymous, fully-authenticated and remember-me authenticated users.
120+
Many sites allow certain limited access under remember-me authentication, but require a user to confirm their identity by logging in for full access.
121+
122+
When we've used the attribute `IS_AUTHENTICATED_ANONYMOUSLY` to grant anonymous access, this attribute was being processed by the `AuthenticatedVoter`.
123+
See the Javadoc for this class for more information.
124+
125+
126+
[[authz-custom-voter]]
127+
===== Custom Voters
128+
Obviously, you can also implement a custom `AccessDecisionVoter` and you can put just about any access-control logic you want in it.
129+
It might be specific to your application (business-logic related) or it might implement some security administration logic.
130+
For example, you'll find a http://spring.io/blog/2009/01/03/spring-security-customization-part-2-adjusting-secured-session-in-real-time[blog article] on the Spring web site which describes how to use a voter to deny access in real-time to users whose accounts have been suspended.
131+
132+
133+
[[authz-after-invocation-handling]]
134+
=== After Invocation Handling
135+
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.
136+
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.
137+
138+
<<authz-after-invocation>> illustrates Spring Security's `AfterInvocationManager` and its concrete implementations.
139+
140+
[[authz-after-invocation]]
141+
.After Invocation Implementation
142+
image::images/after-invocation.png[]
143+
144+
Like many other parts of Spring Security, `AfterInvocationManager` has a single concrete implementation, `AfterInvocationProviderManager`, which polls a list of `AfterInvocationProvider` s.
145+
Each `AfterInvocationProvider` is allowed to modify the return object or throw an `AccessDeniedException`.
146+
Indeed multiple providers can modify the object, as the result of the previous provider is passed to the next in the list.
147+
148+
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.
149+
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.
150+
In turn, if the `AccessDecisionManager` property "`allowIfAllAbstainDecisions`" is `false`, an `AccessDeniedException` will be thrown.
151+
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.
152+
This latter (recommended) approach is usually achieved through a `ROLE_USER` or `ROLE_AUTHENTICATED` configuration attribute.
153+
154+
155+
[[authz-hierarchical-roles]]
156+
=== Hierarchical Roles
157+
It is a common requirement that a particular role in an application should automatically "include" other roles.
158+
For example, in an application which has the concept of an "admin" and a "user" role, you may want an admin to be able to do everything a normal user can.
159+
To achieve this, you can either make sure that all admin users are also assigned the "user" role.
160+
Alternatively, you can modify every access constraint which requires the "user" role to also include the "admin" role.
161+
This can get quite complicated if you have a lot of different roles in your application.
162+
163+
The use of a role-hierarchy allows you to configure which roles (or authorities) should include others.
164+
An extended version of Spring Security's <<authz-role-voter,RoleVoter>>, `RoleHierarchyVoter`, is configured with a `RoleHierarchy`, from which it obtains all the "reachable authorities" which the user is assigned.
165+
A typical configuration might look like this:
166+
167+
[source,xml]
168+
----
169+
170+
<bean id="roleVoter" class="org.springframework.security.access.vote.RoleHierarchyVoter">
171+
<constructor-arg ref="roleHierarchy" />
172+
</bean>
173+
<bean id="roleHierarchy"
174+
class="org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl">
175+
<property name="hierarchy">
176+
<value>
177+
ROLE_ADMIN > ROLE_STAFF
178+
ROLE_STAFF > ROLE_USER
179+
ROLE_USER > ROLE_GUEST
180+
</value>
181+
</property>
182+
</bean>
183+
----
184+
185+
Here we have four roles in a hierarchy `ROLE_ADMIN => ROLE_STAFF => ROLE_USER => ROLE_GUEST`.
186+
A user who is authenticated with `ROLE_ADMIN`, will behave as if they have all four roles when security constraints are evaluated against an `AccessDecisionManager` cconfigured with the above `RoleHierarchyVoter`.
187+
The `>` symbol can be thought of as meaning "includes".
188+
189+
Role hierarchies offer a convenient means of simplifying the access-control configuration data for your application and/or reducing the number of authorities which you need to assign to a user.
190+
For more complex requirements you may wish to define a logical mapping between the specific access-rights your application requires and the roles that are assigned to users, translating between the two when loading the user information.

0 commit comments

Comments
 (0)