3 * Copyright (C) 2012 EDIT
4 * European Distributed Institute of Taxonomy
5 * http://www.e-taxonomy.eu
7 * The contents of this file are subject to the Mozilla Public License Version 1.1
8 * See LICENSE.TXT at the top of this package for the full license terms.
10 package eu
.etaxonomy
.cdm
.persistence
.hibernate
.permission
.voter
;
12 import java
.util
.Collection
;
14 import org
.apache
.log4j
.Logger
;
15 import org
.springframework
.security
.access
.AccessDecisionVoter
;
16 import org
.springframework
.security
.access
.ConfigAttribute
;
17 import org
.springframework
.security
.core
.Authentication
;
18 import org
.springframework
.security
.core
.GrantedAuthority
;
20 import sun
.security
.provider
.PolicyParser
.ParsingException
;
22 import eu
.etaxonomy
.cdm
.model
.common
.CdmBase
;
23 import eu
.etaxonomy
.cdm
.persistence
.hibernate
.permission
.CdmAuthority
;
24 import eu
.etaxonomy
.cdm
.persistence
.hibernate
.permission
.Operation
;
25 import eu
.etaxonomy
.cdm
.persistence
.hibernate
.permission
.CdmPermissionClass
;
28 * The <code>CdmPermissionVoter</code> provides access control votes for {@link CdmBase} objects.
30 * @author andreas kohlbecker
34 public abstract class CdmPermissionVoter
implements AccessDecisionVoter
{
36 public static final Logger logger
= Logger
.getLogger(CdmPermissionVoter
.class);
39 * @see org.springframework.security.access.AccessDecisionVoter#supports(org.springframework.security.access.ConfigAttribute)
41 public boolean supports(ConfigAttribute attribute
) {
42 // all CdmPermissionVoter support CdmAuthority
43 return attribute
instanceof CdmAuthority
;
47 * @see org.springframework.security.access.AccessDecisionVoter#supports(java.lang.Class)
49 public boolean supports(Class
<?
> clazz
) {
51 * Do not change this, all CdmPermissionVoters must support CdmBase.class
53 return clazz
.isInstance(CdmBase
.class);
57 * Sets the Cdm type, or super type this Voter is responsible for.
59 abstract public Class
<?
extends CdmBase
> getResponsibilityClass();
62 protected boolean isResponsibleFor(Object securedObject
) {
63 return getResponsibilityClass().isAssignableFrom(securedObject
.getClass());
66 protected boolean isResponsibleFor(CdmPermissionClass permissionClass
) {
67 return getResponsibility().equals(permissionClass
);
71 * Get the according CdmPermissionClass matching {@link #getResponsibilityClass()} the cdm class this voter is responsible for.
74 protected CdmPermissionClass
getResponsibility() {
75 return CdmPermissionClass
.getValueOf(getResponsibilityClass());
79 * @see org.springframework.security.access.AccessDecisionVoter#vote(org.springframework.security.core.Authentication, java.lang.Object, java.util.Collection)
81 public int vote(Authentication authentication
, Object object
, Collection
<ConfigAttribute
> attributes
) {
83 if(!isResponsibleFor(object
)){
84 logger
.debug("class missmatch => ACCESS_ABSTAIN");
85 return ACCESS_ABSTAIN
;
88 if (logger
.isDebugEnabled()){
89 logger
.debug("authentication: " + authentication
.getName() + ", object : " + object
.toString() + ", attribute[0]:" + ((CdmAuthority
)attributes
.iterator().next()).getAttribute());
92 int fallThroughVote
= ACCESS_DENIED
;
94 // loop over all attributes = permissions of which at least one must match
95 // usually there is only one element in the collection!
96 for(ConfigAttribute attribute
: attributes
){
97 if(!(attribute
instanceof CdmAuthority
)){
98 throw new RuntimeException("attributes must contain only CdmAuthority");
100 CdmAuthority evalPermission
= (CdmAuthority
)attribute
;
102 for (GrantedAuthority authority
: authentication
.getAuthorities()){
106 auth
= CdmAuthority
.fromGrantedAuthority(authority
);
107 } catch (ParsingException e
) {
108 logger
.debug("skipping " + authority
.getAuthority() + " due to ParsingException");
112 // check if the voter is responsible for the permission to be evaluated
113 if( ! isResponsibleFor(evalPermission
.getPermissionClass())){
114 logger
.debug(getResponsibility() + " not responsible for " + evalPermission
.getPermissionClass() + " -> skipping");
118 ValidationResult vr
= new ValidationResult();
120 boolean isALL
= auth
.getPermissionClass().equals(CdmPermissionClass
.ALL
);
122 vr
.isClassMatch
= isALL
|| auth
.getPermissionClass().equals(evalPermission
.getPermissionClass());
123 vr
.isPermissionMatch
= auth
.getOperation().containsAll(evalPermission
.getOperation());
124 vr
.isUuidMatch
= auth
.hasTargetUuid() && auth
.getTargetUUID().equals(((CdmBase
)object
).getUuid());
127 // only vote if no property is defined.
128 // Authorities with properties must be voted by type specific voters.
130 if(!auth
.hasProperty()){
131 if ( !auth
.hasTargetUuid() && vr
.isClassMatch
&& vr
.isPermissionMatch
){
132 logger
.debug("no tragetUuid, class & permission match => ACCESS_GRANTED");
133 return ACCESS_GRANTED
;
135 if ( vr
.isUuidMatch
&& vr
.isClassMatch
&& vr
.isPermissionMatch
){
136 logger
.debug("permission, class and uuid are matching => ACCESS_GRANTED");
137 return ACCESS_GRANTED
;
141 // If the authority contains a property AND the voter is responsible for this class
142 // we must change the fallThroughVote
143 // to ABSTAIN, since no decision can be made in this case at this point
146 fallThroughVote
= ACCESS_ABSTAIN
;
151 // ask subclasses for further voting decisions
152 // subclasses will cast votes for specific Cdm Types
154 Integer furtherVotingResult
= furtherVotingDescisions(auth
, object
, attributes
, vr
);
155 if(furtherVotingResult
!= null && furtherVotingResult
!= ACCESS_ABSTAIN
){
156 logger
.debug("furtherVotingResult => " + furtherVotingResult
);
157 return furtherVotingResult
;
160 } // END Authorities loop
161 } // END attributes loop
163 // the value of fallThroughVote depends on whether the authority had an property or not, see above
164 logger
.debug("fallThroughVote => " + fallThroughVote
);
165 return fallThroughVote
;
169 * Override this method to implement specific decisions.
170 * Implementations of this method will be executed in {@link #vote(Authentication, Object, Collection)}.
172 * @param CdmAuthority
175 * @param validationResult
176 * @return A return value of ACCESS_ABSTAIN or null will be ignored in {@link #vote(Authentication, Object, Collection)}
178 protected Integer
furtherVotingDescisions(CdmAuthority CdmAuthority
, Object object
, Collection
<ConfigAttribute
> attributes
,
179 ValidationResult validationResult
) {
184 * Holds various flags with validation results.
185 * Is used to pass this information from
186 * {@link CdmPermissionVoter#vote(Authentication, Object, Collection)}
187 * to {@link CdmPermissionVoter#furtherVotingDescisions(CdmAuthority, Object, Collection, ValidationResult)}
189 * @author andreas kohlbecker
193 protected class ValidationResult
{
194 boolean isPermissionMatch
= false;
195 boolean isPropertyMatch
= false;
196 boolean isUuidMatch
= false;
197 boolean isClassMatch
= false;