Reformat code using spring-javaformat
Run `./gradlew format` to reformat all java files. Issue gh-8945
This commit is contained in:
@@ -27,25 +27,23 @@ import org.springframework.security.core.Authentication;
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public interface AccessDecisionManager {
|
||||
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
/**
|
||||
* Resolves an access control decision for the passed parameters.
|
||||
*
|
||||
* @param authentication the caller invoking the method (not null)
|
||||
* @param object the secured object being called
|
||||
* @param configAttributes the configuration attributes associated with the secured
|
||||
* object being invoked
|
||||
*
|
||||
* @throws AccessDeniedException if access is denied as the authentication does not
|
||||
* hold a required authority or ACL privilege
|
||||
* @throws InsufficientAuthenticationException if access is denied as the
|
||||
* authentication does not provide a sufficient level of trust
|
||||
*/
|
||||
void decide(Authentication authentication, Object object,
|
||||
Collection<ConfigAttribute> configAttributes) throws AccessDeniedException,
|
||||
InsufficientAuthenticationException;
|
||||
void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes)
|
||||
throws AccessDeniedException, InsufficientAuthenticationException;
|
||||
|
||||
/**
|
||||
* Indicates whether this <code>AccessDecisionManager</code> is able to process
|
||||
@@ -56,10 +54,8 @@ public interface AccessDecisionManager {
|
||||
* <code>AccessDecisionManager</code> and/or <code>RunAsManager</code> and/or
|
||||
* <code>AfterInvocationManager</code>.
|
||||
* </p>
|
||||
*
|
||||
* @param attribute a configuration attribute that has been configured against the
|
||||
* <code>AbstractSecurityInterceptor</code>
|
||||
*
|
||||
* @return true if this <code>AccessDecisionManager</code> can support the passed
|
||||
* configuration attribute
|
||||
*/
|
||||
@@ -68,10 +64,9 @@ public interface AccessDecisionManager {
|
||||
/**
|
||||
* Indicates whether the <code>AccessDecisionManager</code> implementation is able to
|
||||
* provide access control decisions for the indicated secured object type.
|
||||
*
|
||||
* @param clazz the class that is being queried
|
||||
*
|
||||
* @return <code>true</code> if the implementation can process the indicated class
|
||||
*/
|
||||
boolean supports(Class<?> clazz);
|
||||
|
||||
}
|
||||
|
||||
@@ -30,11 +30,14 @@ import org.springframework.security.core.Authentication;
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public interface AccessDecisionVoter<S> {
|
||||
|
||||
// ~ Static fields/initializers
|
||||
// =====================================================================================
|
||||
|
||||
int ACCESS_GRANTED = 1;
|
||||
|
||||
int ACCESS_ABSTAIN = 0;
|
||||
|
||||
int ACCESS_DENIED = -1;
|
||||
|
||||
// ~ Methods
|
||||
@@ -47,10 +50,8 @@ public interface AccessDecisionVoter<S> {
|
||||
* This allows the {@code AbstractSecurityInterceptor} to check every configuration
|
||||
* attribute can be consumed by the configured {@code AccessDecisionManager} and/or
|
||||
* {@code RunAsManager} and/or {@code AfterInvocationManager}.
|
||||
*
|
||||
* @param attribute a configuration attribute that has been configured against the
|
||||
* {@code AbstractSecurityInterceptor}
|
||||
*
|
||||
* @return true if this {@code AccessDecisionVoter} can support the passed
|
||||
* configuration attribute
|
||||
*/
|
||||
@@ -59,9 +60,7 @@ public interface AccessDecisionVoter<S> {
|
||||
/**
|
||||
* Indicates whether the {@code AccessDecisionVoter} implementation is able to provide
|
||||
* access control votes for the indicated secured object type.
|
||||
*
|
||||
* @param clazz the class that is being queried
|
||||
*
|
||||
* @return true if the implementation can process the indicated class
|
||||
*/
|
||||
boolean supports(Class<?> clazz);
|
||||
@@ -87,14 +86,12 @@ public interface AccessDecisionVoter<S> {
|
||||
* parameter to maximise flexibility in making access control decisions, implementing
|
||||
* classes should not modify it or cause the represented invocation to take place (for
|
||||
* example, by calling {@code MethodInvocation.proceed()}).
|
||||
*
|
||||
* @param authentication the caller making the invocation
|
||||
* @param object the secured object being invoked
|
||||
* @param attributes the configuration attributes associated with the secured object
|
||||
*
|
||||
* @return either {@link #ACCESS_GRANTED}, {@link #ACCESS_ABSTAIN} or
|
||||
* {@link #ACCESS_DENIED}
|
||||
*/
|
||||
int vote(Authentication authentication, S object,
|
||||
Collection<ConfigAttribute> attributes);
|
||||
int vote(Authentication authentication, S object, Collection<ConfigAttribute> attributes);
|
||||
|
||||
}
|
||||
|
||||
@@ -23,12 +23,12 @@ package org.springframework.security.access;
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public class AccessDeniedException extends RuntimeException {
|
||||
|
||||
// ~ Constructors
|
||||
// ===================================================================================================
|
||||
|
||||
/**
|
||||
* Constructs an <code>AccessDeniedException</code> with the specified message.
|
||||
*
|
||||
* @param msg the detail message
|
||||
*/
|
||||
public AccessDeniedException(String msg) {
|
||||
@@ -38,11 +38,11 @@ public class AccessDeniedException extends RuntimeException {
|
||||
/**
|
||||
* Constructs an <code>AccessDeniedException</code> with the specified message and
|
||||
* root cause.
|
||||
*
|
||||
* @param msg the detail message
|
||||
* @param t root cause
|
||||
*/
|
||||
public AccessDeniedException(String msg, Throwable t) {
|
||||
super(msg, t);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -28,12 +28,12 @@ import org.springframework.security.core.Authentication;
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public interface AfterInvocationProvider {
|
||||
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
Object decide(Authentication authentication, Object object,
|
||||
Collection<ConfigAttribute> attributes, Object returnedObject)
|
||||
throws AccessDeniedException;
|
||||
Object decide(Authentication authentication, Object object, Collection<ConfigAttribute> attributes,
|
||||
Object returnedObject) throws AccessDeniedException;
|
||||
|
||||
/**
|
||||
* Indicates whether this <code>AfterInvocationProvider</code> is able to participate
|
||||
@@ -44,10 +44,8 @@ public interface AfterInvocationProvider {
|
||||
* <code>AccessDecisionManager</code> and/or <code>RunAsManager</code> and/or
|
||||
* <code>AccessDecisionManager</code>.
|
||||
* </p>
|
||||
*
|
||||
* @param attribute a configuration attribute that has been configured against the
|
||||
* <code>AbstractSecurityInterceptor</code>
|
||||
*
|
||||
* @return true if this <code>AfterInvocationProvider</code> can support the passed
|
||||
* configuration attribute
|
||||
*/
|
||||
@@ -56,10 +54,9 @@ public interface AfterInvocationProvider {
|
||||
/**
|
||||
* Indicates whether the <code>AfterInvocationProvider</code> is able to provide
|
||||
* "after invocation" processing for the indicated secured object type.
|
||||
*
|
||||
* @param clazz the class of secure object that is being queried
|
||||
*
|
||||
* @return true if the implementation can process the indicated class
|
||||
*/
|
||||
boolean supports(Class<?> clazz);
|
||||
|
||||
}
|
||||
|
||||
+2
-2
@@ -25,13 +25,13 @@ package org.springframework.security.access;
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public class AuthorizationServiceException extends AccessDeniedException {
|
||||
|
||||
// ~ Constructors
|
||||
// ===================================================================================================
|
||||
|
||||
/**
|
||||
* Constructs an <code>AuthorizationServiceException</code> with the specified
|
||||
* message.
|
||||
*
|
||||
* @param msg the detail message
|
||||
*/
|
||||
public AuthorizationServiceException(String msg) {
|
||||
@@ -41,11 +41,11 @@ public class AuthorizationServiceException extends AccessDeniedException {
|
||||
/**
|
||||
* Constructs an <code>AuthorizationServiceException</code> with the specified message
|
||||
* and root cause.
|
||||
*
|
||||
* @param msg the detail message
|
||||
* @param t root cause
|
||||
*/
|
||||
public AuthorizationServiceException(String msg, Throwable t) {
|
||||
super(msg, t);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ import org.springframework.security.access.intercept.RunAsManager;
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public interface ConfigAttribute extends Serializable {
|
||||
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
@@ -52,10 +53,10 @@ public interface ConfigAttribute extends Serializable {
|
||||
* <code>null</code> will require any relying classes to specifically support the
|
||||
* <code>ConfigAttribute</code> implementation, so returning <code>null</code> should
|
||||
* be avoided unless actually required.
|
||||
*
|
||||
* @return a representation of the configuration attribute (or <code>null</code> if
|
||||
* the configuration attribute cannot be expressed as a <code>String</code> with
|
||||
* sufficient precision).
|
||||
*/
|
||||
String getAttribute();
|
||||
|
||||
}
|
||||
|
||||
+2
-1
@@ -27,14 +27,15 @@ import org.springframework.security.core.Authentication;
|
||||
* @since 3.1
|
||||
*/
|
||||
public interface PermissionCacheOptimizer extends AopInfrastructureBean {
|
||||
|
||||
/**
|
||||
* Optimises the permission cache for anticipated operation on the supplied collection
|
||||
* of objects. Usually this will entail batch loading of permissions for the objects
|
||||
* in the collection.
|
||||
*
|
||||
* @param a the user for whom permissions should be obtained.
|
||||
* @param objects the (non-null) collection of domain objects for which permissions
|
||||
* should be retrieved.
|
||||
*/
|
||||
void cachePermissionsFor(Authentication a, Collection<?> objects);
|
||||
|
||||
}
|
||||
|
||||
@@ -24,13 +24,12 @@ import org.springframework.security.core.Authentication;
|
||||
* Strategy used in expression evaluation to determine whether a user has a permission or
|
||||
* permissions for a given domain object.
|
||||
*
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @since 3.0
|
||||
*/
|
||||
public interface PermissionEvaluator extends AopInfrastructureBean {
|
||||
|
||||
/**
|
||||
*
|
||||
* @param authentication represents the user in question. Should not be null.
|
||||
* @param targetDomainObject the domain object for which permissions should be
|
||||
* checked. May be null in which case implementations should return false, as the null
|
||||
@@ -39,13 +38,11 @@ public interface PermissionEvaluator extends AopInfrastructureBean {
|
||||
* expression system. Not null.
|
||||
* @return true if the permission is granted, false otherwise
|
||||
*/
|
||||
boolean hasPermission(Authentication authentication, Object targetDomainObject,
|
||||
Object permission);
|
||||
boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission);
|
||||
|
||||
/**
|
||||
* Alternative method for evaluating a permission where only the identifier of the
|
||||
* target object is available, rather than the target instance itself.
|
||||
*
|
||||
* @param authentication represents the user in question. Should not be null.
|
||||
* @param targetId the identifier for the object instance (usually a Long)
|
||||
* @param targetType a String representing the target's type (usually a Java
|
||||
@@ -54,6 +51,6 @@ public interface PermissionEvaluator extends AopInfrastructureBean {
|
||||
* expression system. Not null.
|
||||
* @return true if the permission is granted, false otherwise
|
||||
*/
|
||||
boolean hasPermission(Authentication authentication, Serializable targetId,
|
||||
String targetType, Object permission);
|
||||
boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission);
|
||||
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import org.springframework.util.StringUtils;
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public class SecurityConfig implements ConfigAttribute {
|
||||
|
||||
// ~ Instance fields
|
||||
// ================================================================================================
|
||||
|
||||
@@ -76,8 +77,7 @@ public class SecurityConfig implements ConfigAttribute {
|
||||
|
||||
public static List<ConfigAttribute> createList(String... attributeNames) {
|
||||
Assert.notNull(attributeNames, "You must supply an array of attribute names");
|
||||
List<ConfigAttribute> attributes = new ArrayList<>(
|
||||
attributeNames.length);
|
||||
List<ConfigAttribute> attributes = new ArrayList<>(attributeNames.length);
|
||||
|
||||
for (String attribute : attributeNames) {
|
||||
attributes.add(new SecurityConfig(attribute.trim()));
|
||||
@@ -85,4 +85,5 @@ public class SecurityConfig implements ConfigAttribute {
|
||||
|
||||
return attributes;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -28,22 +28,19 @@ import org.springframework.security.access.intercept.AbstractSecurityInterceptor
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public interface SecurityMetadataSource extends AopInfrastructureBean {
|
||||
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
/**
|
||||
* Accesses the {@code ConfigAttribute}s that apply to a given secure object.
|
||||
*
|
||||
* @param object the object being secured
|
||||
*
|
||||
* @return the attributes that apply to the passed in secured object. Should return an
|
||||
* empty collection if there are no applicable attributes.
|
||||
*
|
||||
* @throws IllegalArgumentException if the passed object is not of a type supported by
|
||||
* the <code>SecurityMetadataSource</code> implementation
|
||||
*/
|
||||
Collection<ConfigAttribute> getAttributes(Object object)
|
||||
throws IllegalArgumentException;
|
||||
Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* If available, returns all of the {@code ConfigAttribute}s defined by the
|
||||
@@ -51,7 +48,6 @@ public interface SecurityMetadataSource extends AopInfrastructureBean {
|
||||
* <p>
|
||||
* This is used by the {@link AbstractSecurityInterceptor} to perform startup time
|
||||
* validation of each {@code ConfigAttribute} configured against it.
|
||||
*
|
||||
* @return the {@code ConfigAttribute}s or {@code null} if unsupported
|
||||
*/
|
||||
Collection<ConfigAttribute> getAllConfigAttributes();
|
||||
@@ -59,10 +55,9 @@ public interface SecurityMetadataSource extends AopInfrastructureBean {
|
||||
/**
|
||||
* Indicates whether the {@code SecurityMetadataSource} implementation is able to
|
||||
* provide {@code ConfigAttribute}s for the indicated secure object type.
|
||||
*
|
||||
* @param clazz the class that is being queried
|
||||
*
|
||||
* @return true if the implementation can process the indicated class
|
||||
*/
|
||||
boolean supports(Class<?> clazz);
|
||||
|
||||
}
|
||||
|
||||
+1
@@ -31,4 +31,5 @@ import java.util.*;
|
||||
public interface AnnotationMetadataExtractor<A extends Annotation> {
|
||||
|
||||
Collection<? extends ConfigAttribute> extractAttributes(A securityAnnotation);
|
||||
|
||||
}
|
||||
|
||||
+3
-5
@@ -36,8 +36,7 @@ import org.springframework.security.access.method.AbstractFallbackMethodSecurity
|
||||
* @author Ben Alex
|
||||
* @since 2.0
|
||||
*/
|
||||
public class Jsr250MethodSecurityMetadataSource extends
|
||||
AbstractFallbackMethodSecurityMetadataSource {
|
||||
public class Jsr250MethodSecurityMetadataSource extends AbstractFallbackMethodSecurityMetadataSource {
|
||||
|
||||
private String defaultRolePrefix = "ROLE_";
|
||||
|
||||
@@ -51,7 +50,6 @@ public class Jsr250MethodSecurityMetadataSource extends
|
||||
* <p>
|
||||
* If null or empty, then no default role prefix is used.
|
||||
* </p>
|
||||
*
|
||||
* @param defaultRolePrefix the default prefix to add to roles. Default "ROLE_".
|
||||
*/
|
||||
public void setDefaultRolePrefix(String defaultRolePrefix) {
|
||||
@@ -62,8 +60,7 @@ public class Jsr250MethodSecurityMetadataSource extends
|
||||
return processAnnotations(clazz.getAnnotations());
|
||||
}
|
||||
|
||||
protected Collection<ConfigAttribute> findAttributes(Method method,
|
||||
Class<?> targetClass) {
|
||||
protected Collection<ConfigAttribute> findAttributes(Method method, Class<?> targetClass) {
|
||||
return processAnnotations(AnnotationUtils.getAnnotations(method));
|
||||
}
|
||||
|
||||
@@ -111,4 +108,5 @@ public class Jsr250MethodSecurityMetadataSource extends
|
||||
}
|
||||
return defaultRolePrefix + role;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+4
-4
@@ -27,10 +27,10 @@ import javax.annotation.security.DenyAll;
|
||||
* @since 2.0
|
||||
*/
|
||||
public class Jsr250SecurityConfig extends SecurityConfig {
|
||||
public static final Jsr250SecurityConfig PERMIT_ALL_ATTRIBUTE = new Jsr250SecurityConfig(
|
||||
PermitAll.class.getName());
|
||||
public static final Jsr250SecurityConfig DENY_ALL_ATTRIBUTE = new Jsr250SecurityConfig(
|
||||
DenyAll.class.getName());
|
||||
|
||||
public static final Jsr250SecurityConfig PERMIT_ALL_ATTRIBUTE = new Jsr250SecurityConfig(PermitAll.class.getName());
|
||||
|
||||
public static final Jsr250SecurityConfig DENY_ALL_ATTRIBUTE = new Jsr250SecurityConfig(DenyAll.class.getName());
|
||||
|
||||
public Jsr250SecurityConfig(String role) {
|
||||
super(role);
|
||||
|
||||
@@ -33,7 +33,6 @@ public class Jsr250Voter implements AccessDecisionVoter<Object> {
|
||||
/**
|
||||
* The specified config attribute is supported if its an instance of a
|
||||
* {@link Jsr250SecurityConfig}.
|
||||
*
|
||||
* @param configAttribute The config attribute.
|
||||
* @return whether the config attribute is supported.
|
||||
*/
|
||||
@@ -43,7 +42,6 @@ public class Jsr250Voter implements AccessDecisionVoter<Object> {
|
||||
|
||||
/**
|
||||
* All classes are supported.
|
||||
*
|
||||
* @param clazz the class.
|
||||
* @return true
|
||||
*/
|
||||
@@ -56,14 +54,12 @@ public class Jsr250Voter implements AccessDecisionVoter<Object> {
|
||||
* <p>
|
||||
* If no JSR-250 attributes are found, it will abstain, otherwise it will grant or
|
||||
* deny access based on the attributes that are found.
|
||||
*
|
||||
* @param authentication The authentication object.
|
||||
* @param object The access object.
|
||||
* @param definition The configuration definition.
|
||||
* @return The vote.
|
||||
*/
|
||||
public int vote(Authentication authentication, Object object,
|
||||
Collection<ConfigAttribute> definition) {
|
||||
public int vote(Authentication authentication, Object object, Collection<ConfigAttribute> definition) {
|
||||
boolean jsr250AttributeFound = false;
|
||||
|
||||
for (ConfigAttribute attribute : definition) {
|
||||
@@ -88,4 +84,5 @@ public class Jsr250Voter implements AccessDecisionVoter<Object> {
|
||||
|
||||
return jsr250AttributeFound ? ACCESS_DENIED : ACCESS_ABSTAIN;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -50,10 +50,12 @@ import java.lang.annotation.Target;
|
||||
@Inherited
|
||||
@Documented
|
||||
public @interface Secured {
|
||||
|
||||
/**
|
||||
* Returns the list of security configuration attributes (e.g. ROLE_USER, ROLE_ADMIN).
|
||||
*
|
||||
* Returns the list of security configuration attributes (e.g. ROLE_USER,
|
||||
* ROLE_ADMIN).
|
||||
* @return String[] The secure method attributes
|
||||
*/
|
||||
String[] value();
|
||||
|
||||
}
|
||||
|
||||
+9
-10
@@ -38,22 +38,21 @@ import org.springframework.util.Assert;
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
public class SecuredAnnotationSecurityMetadataSource extends
|
||||
AbstractFallbackMethodSecurityMetadataSource {
|
||||
public class SecuredAnnotationSecurityMetadataSource extends AbstractFallbackMethodSecurityMetadataSource {
|
||||
|
||||
private AnnotationMetadataExtractor annotationExtractor;
|
||||
|
||||
private Class<? extends Annotation> annotationType;
|
||||
|
||||
public SecuredAnnotationSecurityMetadataSource() {
|
||||
this(new SecuredAnnotationMetadataExtractor());
|
||||
}
|
||||
|
||||
public SecuredAnnotationSecurityMetadataSource(
|
||||
AnnotationMetadataExtractor annotationMetadataExtractor) {
|
||||
public SecuredAnnotationSecurityMetadataSource(AnnotationMetadataExtractor annotationMetadataExtractor) {
|
||||
Assert.notNull(annotationMetadataExtractor, "annotationMetadataExtractor cannot be null");
|
||||
annotationExtractor = annotationMetadataExtractor;
|
||||
annotationType = (Class<? extends Annotation>) GenericTypeResolver
|
||||
.resolveTypeArgument(annotationExtractor.getClass(),
|
||||
AnnotationMetadataExtractor.class);
|
||||
.resolveTypeArgument(annotationExtractor.getClass(), AnnotationMetadataExtractor.class);
|
||||
Assert.notNull(annotationType, () -> annotationExtractor.getClass().getName()
|
||||
+ " must supply a generic parameter for AnnotationMetadataExtractor");
|
||||
}
|
||||
@@ -62,8 +61,7 @@ public class SecuredAnnotationSecurityMetadataSource extends
|
||||
return processAnnotation(AnnotationUtils.findAnnotation(clazz, annotationType));
|
||||
}
|
||||
|
||||
protected Collection<ConfigAttribute> findAttributes(Method method,
|
||||
Class<?> targetClass) {
|
||||
protected Collection<ConfigAttribute> findAttributes(Method method, Class<?> targetClass) {
|
||||
return processAnnotation(AnnotationUtils.findAnnotation(method, annotationType));
|
||||
}
|
||||
|
||||
@@ -78,14 +76,14 @@ public class SecuredAnnotationSecurityMetadataSource extends
|
||||
|
||||
return annotationExtractor.extractAttributes(a);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class SecuredAnnotationMetadataExtractor implements AnnotationMetadataExtractor<Secured> {
|
||||
|
||||
public Collection<ConfigAttribute> extractAttributes(Secured secured) {
|
||||
String[] attributeTokens = secured.value();
|
||||
List<ConfigAttribute> attributes = new ArrayList<>(
|
||||
attributeTokens.length);
|
||||
List<ConfigAttribute> attributes = new ArrayList<>(attributeTokens.length);
|
||||
|
||||
for (String token : attributeTokens) {
|
||||
attributes.add(new SecurityConfig(token));
|
||||
@@ -93,4 +91,5 @@ class SecuredAnnotationMetadataExtractor implements AnnotationMetadataExtractor<
|
||||
|
||||
return attributes;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-1
@@ -24,15 +24,16 @@ import org.springframework.context.ApplicationEvent;
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public abstract class AbstractAuthorizationEvent extends ApplicationEvent {
|
||||
|
||||
// ~ Constructors
|
||||
// ===================================================================================================
|
||||
|
||||
/**
|
||||
* Construct the event, passing in the secure object being intercepted.
|
||||
*
|
||||
* @param secureObject the secure object
|
||||
*/
|
||||
public AbstractAuthorizationEvent(Object secureObject) {
|
||||
super(secureObject);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+5
-5
@@ -28,10 +28,12 @@ import org.springframework.security.authentication.AuthenticationCredentialsNotF
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public class AuthenticationCredentialsNotFoundEvent extends AbstractAuthorizationEvent {
|
||||
|
||||
// ~ Instance fields
|
||||
// ================================================================================================
|
||||
|
||||
private AuthenticationCredentialsNotFoundException credentialsNotFoundException;
|
||||
|
||||
private Collection<ConfigAttribute> configAttribs;
|
||||
|
||||
// ~ Constructors
|
||||
@@ -39,21 +41,18 @@ public class AuthenticationCredentialsNotFoundEvent extends AbstractAuthorizatio
|
||||
|
||||
/**
|
||||
* Construct the event.
|
||||
*
|
||||
* @param secureObject the secure object
|
||||
* @param attributes that apply to the secure object
|
||||
* @param credentialsNotFoundException exception returned to the caller (contains
|
||||
* reason)
|
||||
*
|
||||
*/
|
||||
public AuthenticationCredentialsNotFoundEvent(Object secureObject,
|
||||
Collection<ConfigAttribute> attributes,
|
||||
public AuthenticationCredentialsNotFoundEvent(Object secureObject, Collection<ConfigAttribute> attributes,
|
||||
AuthenticationCredentialsNotFoundException credentialsNotFoundException) {
|
||||
super(secureObject);
|
||||
|
||||
if ((attributes == null) || (credentialsNotFoundException == null)) {
|
||||
throw new IllegalArgumentException(
|
||||
"All parameters are required and cannot be null");
|
||||
throw new IllegalArgumentException("All parameters are required and cannot be null");
|
||||
}
|
||||
|
||||
this.configAttribs = attributes;
|
||||
@@ -70,4 +69,5 @@ public class AuthenticationCredentialsNotFoundEvent extends AbstractAuthorizatio
|
||||
public AuthenticationCredentialsNotFoundException getCredentialsNotFoundException() {
|
||||
return credentialsNotFoundException;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+8
-9
@@ -35,11 +35,14 @@ import org.springframework.security.core.Authentication;
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public class AuthorizationFailureEvent extends AbstractAuthorizationEvent {
|
||||
|
||||
// ~ Instance fields
|
||||
// ================================================================================================
|
||||
|
||||
private AccessDeniedException accessDeniedException;
|
||||
|
||||
private Authentication authentication;
|
||||
|
||||
private Collection<ConfigAttribute> configAttributes;
|
||||
|
||||
// ~ Constructors
|
||||
@@ -47,24 +50,19 @@ public class AuthorizationFailureEvent extends AbstractAuthorizationEvent {
|
||||
|
||||
/**
|
||||
* Construct the event.
|
||||
*
|
||||
* @param secureObject the secure object
|
||||
* @param attributes that apply to the secure object
|
||||
* @param authentication that was found in the <code>SecurityContextHolder</code>
|
||||
* @param accessDeniedException that was returned by the
|
||||
* <code>AccessDecisionManager</code>
|
||||
*
|
||||
* @throws IllegalArgumentException if any null arguments are presented.
|
||||
*/
|
||||
public AuthorizationFailureEvent(Object secureObject,
|
||||
Collection<ConfigAttribute> attributes, Authentication authentication,
|
||||
AccessDeniedException accessDeniedException) {
|
||||
public AuthorizationFailureEvent(Object secureObject, Collection<ConfigAttribute> attributes,
|
||||
Authentication authentication, AccessDeniedException accessDeniedException) {
|
||||
super(secureObject);
|
||||
|
||||
if ((attributes == null) || (authentication == null)
|
||||
|| (accessDeniedException == null)) {
|
||||
throw new IllegalArgumentException(
|
||||
"All parameters are required and cannot be null");
|
||||
if ((attributes == null) || (authentication == null) || (accessDeniedException == null)) {
|
||||
throw new IllegalArgumentException("All parameters are required and cannot be null");
|
||||
}
|
||||
|
||||
this.configAttributes = attributes;
|
||||
@@ -86,4 +84,5 @@ public class AuthorizationFailureEvent extends AbstractAuthorizationEvent {
|
||||
public Collection<ConfigAttribute> getConfigAttributes() {
|
||||
return configAttributes;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -30,10 +30,12 @@ import org.springframework.security.core.Authentication;
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public class AuthorizedEvent extends AbstractAuthorizationEvent {
|
||||
|
||||
// ~ Instance fields
|
||||
// ================================================================================================
|
||||
|
||||
private Authentication authentication;
|
||||
|
||||
private Collection<ConfigAttribute> configAttributes;
|
||||
|
||||
// ~ Constructors
|
||||
@@ -41,19 +43,16 @@ public class AuthorizedEvent extends AbstractAuthorizationEvent {
|
||||
|
||||
/**
|
||||
* Construct the event.
|
||||
*
|
||||
* @param secureObject the secure object
|
||||
* @param attributes that apply to the secure object
|
||||
* @param authentication that successfully called the secure object
|
||||
*
|
||||
*/
|
||||
public AuthorizedEvent(Object secureObject, Collection<ConfigAttribute> attributes,
|
||||
Authentication authentication) {
|
||||
public AuthorizedEvent(Object secureObject, Collection<ConfigAttribute> attributes, Authentication authentication) {
|
||||
super(secureObject);
|
||||
|
||||
if ((attributes == null) || (authentication == null)) {
|
||||
throw new IllegalArgumentException(
|
||||
"All parameters are required and cannot be null");
|
||||
throw new IllegalArgumentException("All parameters are required and cannot be null");
|
||||
}
|
||||
|
||||
this.configAttributes = attributes;
|
||||
@@ -70,4 +69,5 @@ public class AuthorizedEvent extends AbstractAuthorizationEvent {
|
||||
public Collection<ConfigAttribute> getConfigAttributes() {
|
||||
return configAttributes;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ import org.springframework.context.ApplicationListener;
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public class LoggerListener implements ApplicationListener<AbstractAuthorizationEvent> {
|
||||
|
||||
// ~ Static fields/initializers
|
||||
// =====================================================================================
|
||||
|
||||
@@ -43,10 +44,8 @@ public class LoggerListener implements ApplicationListener<AbstractAuthorization
|
||||
AuthenticationCredentialsNotFoundEvent authEvent = (AuthenticationCredentialsNotFoundEvent) event;
|
||||
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("Security interception failed due to: "
|
||||
+ authEvent.getCredentialsNotFoundException()
|
||||
+ "; secure object: " + authEvent.getSource()
|
||||
+ "; configuration attributes: "
|
||||
logger.warn("Security interception failed due to: " + authEvent.getCredentialsNotFoundException()
|
||||
+ "; secure object: " + authEvent.getSource() + "; configuration attributes: "
|
||||
+ authEvent.getConfigAttributes());
|
||||
}
|
||||
}
|
||||
@@ -55,12 +54,9 @@ public class LoggerListener implements ApplicationListener<AbstractAuthorization
|
||||
AuthorizationFailureEvent authEvent = (AuthorizationFailureEvent) event;
|
||||
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("Security authorization failed due to: "
|
||||
+ authEvent.getAccessDeniedException()
|
||||
+ "; authenticated principal: " + authEvent.getAuthentication()
|
||||
+ "; secure object: " + authEvent.getSource()
|
||||
+ "; configuration attributes: "
|
||||
+ authEvent.getConfigAttributes());
|
||||
logger.warn("Security authorization failed due to: " + authEvent.getAccessDeniedException()
|
||||
+ "; authenticated principal: " + authEvent.getAuthentication() + "; secure object: "
|
||||
+ authEvent.getSource() + "; configuration attributes: " + authEvent.getConfigAttributes());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,9 +64,8 @@ public class LoggerListener implements ApplicationListener<AbstractAuthorization
|
||||
AuthorizedEvent authEvent = (AuthorizedEvent) event;
|
||||
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Security authorized for authenticated principal: "
|
||||
+ authEvent.getAuthentication() + "; secure object: "
|
||||
+ authEvent.getSource() + "; configuration attributes: "
|
||||
logger.info("Security authorized for authenticated principal: " + authEvent.getAuthentication()
|
||||
+ "; secure object: " + authEvent.getSource() + "; configuration attributes: "
|
||||
+ authEvent.getConfigAttributes());
|
||||
}
|
||||
}
|
||||
@@ -79,9 +74,9 @@ public class LoggerListener implements ApplicationListener<AbstractAuthorization
|
||||
PublicInvocationEvent authEvent = (PublicInvocationEvent) event;
|
||||
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Security interception not required for public secure object: "
|
||||
+ authEvent.getSource());
|
||||
logger.info("Security interception not required for public secure object: " + authEvent.getSource());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-1
@@ -30,15 +30,16 @@ package org.springframework.security.access.event;
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public class PublicInvocationEvent extends AbstractAuthorizationEvent {
|
||||
|
||||
// ~ Constructors
|
||||
// ===================================================================================================
|
||||
|
||||
/**
|
||||
* Construct the event, passing in the public secure object.
|
||||
*
|
||||
* @param secureObject the public secure object
|
||||
*/
|
||||
public PublicInvocationEvent(Object secureObject) {
|
||||
super(secureObject);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,4 +17,3 @@
|
||||
* Authorization event and listener classes.
|
||||
*/
|
||||
package org.springframework.security.access.event;
|
||||
|
||||
|
||||
+13
-15
@@ -36,11 +36,15 @@ import org.springframework.util.Assert;
|
||||
* @author Luke Taylor
|
||||
* @since 3.1
|
||||
*/
|
||||
public abstract class AbstractSecurityExpressionHandler<T> implements
|
||||
SecurityExpressionHandler<T>, ApplicationContextAware {
|
||||
public abstract class AbstractSecurityExpressionHandler<T>
|
||||
implements SecurityExpressionHandler<T>, ApplicationContextAware {
|
||||
|
||||
private ExpressionParser expressionParser = new SpelExpressionParser();
|
||||
|
||||
private BeanResolver br;
|
||||
|
||||
private RoleHierarchy roleHierarchy;
|
||||
|
||||
private PermissionEvaluator permissionEvaluator = new DenyAllPermissionEvaluator();
|
||||
|
||||
public final ExpressionParser getExpressionParser() {
|
||||
@@ -55,18 +59,14 @@ public abstract class AbstractSecurityExpressionHandler<T> implements
|
||||
/**
|
||||
* Invokes the internal template methods to create {@code StandardEvaluationContext}
|
||||
* and {@code SecurityExpressionRoot} objects.
|
||||
*
|
||||
* @param authentication the current authentication object
|
||||
* @param invocation the invocation (filter, method, channel)
|
||||
* @return the context object for use in evaluating the expression, populated with a
|
||||
* suitable root object.
|
||||
*/
|
||||
public final EvaluationContext createEvaluationContext(Authentication authentication,
|
||||
T invocation) {
|
||||
SecurityExpressionOperations root = createSecurityExpressionRoot(authentication,
|
||||
invocation);
|
||||
StandardEvaluationContext ctx = createEvaluationContextInternal(authentication,
|
||||
invocation);
|
||||
public final EvaluationContext createEvaluationContext(Authentication authentication, T invocation) {
|
||||
SecurityExpressionOperations root = createSecurityExpressionRoot(authentication, invocation);
|
||||
StandardEvaluationContext ctx = createEvaluationContextInternal(authentication, invocation);
|
||||
ctx.setBeanResolver(br);
|
||||
ctx.setRootObject(root);
|
||||
|
||||
@@ -79,27 +79,24 @@ public abstract class AbstractSecurityExpressionHandler<T> implements
|
||||
* The returned object will have a {@code SecurityExpressionRootPropertyAccessor}
|
||||
* added, allowing beans in the {@code ApplicationContext} to be accessed via
|
||||
* expression properties.
|
||||
*
|
||||
* @param authentication the current authentication object
|
||||
* @param invocation the invocation (filter, method, channel)
|
||||
* @return A {@code StandardEvaluationContext} or potentially a custom subclass if
|
||||
* overridden.
|
||||
*/
|
||||
protected StandardEvaluationContext createEvaluationContextInternal(
|
||||
Authentication authentication, T invocation) {
|
||||
protected StandardEvaluationContext createEvaluationContextInternal(Authentication authentication, T invocation) {
|
||||
return new StandardEvaluationContext();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implement in order to create a root object of the correct type for the supported
|
||||
* invocation type.
|
||||
*
|
||||
* @param authentication the current authentication object
|
||||
* @param invocation the invocation (filter, method, channel)
|
||||
* @return the object wh
|
||||
*/
|
||||
protected abstract SecurityExpressionOperations createSecurityExpressionRoot(
|
||||
Authentication authentication, T invocation);
|
||||
protected abstract SecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication,
|
||||
T invocation);
|
||||
|
||||
protected RoleHierarchy getRoleHierarchy() {
|
||||
return roleHierarchy;
|
||||
@@ -120,4 +117,5 @@ public abstract class AbstractSecurityExpressionHandler<T> implements
|
||||
public void setApplicationContext(ApplicationContext applicationContext) {
|
||||
br = new BeanFactoryResolver(applicationContext);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+7
-8
@@ -36,20 +36,19 @@ public class DenyAllPermissionEvaluator implements PermissionEvaluator {
|
||||
/**
|
||||
* @return false always
|
||||
*/
|
||||
public boolean hasPermission(Authentication authentication, Object target,
|
||||
Object permission) {
|
||||
logger.warn("Denying user " + authentication.getName() + " permission '"
|
||||
+ permission + "' on object " + target);
|
||||
public boolean hasPermission(Authentication authentication, Object target, Object permission) {
|
||||
logger.warn(
|
||||
"Denying user " + authentication.getName() + " permission '" + permission + "' on object " + target);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return false always
|
||||
*/
|
||||
public boolean hasPermission(Authentication authentication, Serializable targetId,
|
||||
String targetType, Object permission) {
|
||||
logger.warn("Denying user " + authentication.getName() + " permission '"
|
||||
+ permission + "' on object with Id '" + targetId);
|
||||
public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType,
|
||||
Object permission) {
|
||||
logger.warn("Denying user " + authentication.getName() + " permission '" + permission + "' on object with Id '"
|
||||
+ targetId);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -26,8 +26,8 @@ public final class ExpressionUtils {
|
||||
return expr.getValue(ctx, Boolean.class);
|
||||
}
|
||||
catch (EvaluationException e) {
|
||||
throw new IllegalArgumentException("Failed to evaluate expression '"
|
||||
+ expr.getExpressionString() + "'", e);
|
||||
throw new IllegalArgumentException("Failed to evaluate expression '" + expr.getExpressionString() + "'", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
@@ -28,6 +28,7 @@ import org.springframework.security.core.Authentication;
|
||||
* @since 3.1
|
||||
*/
|
||||
public interface SecurityExpressionHandler<T> extends AopInfrastructureBean {
|
||||
|
||||
/**
|
||||
* @return an expression parser for the expressions used by the implementation.
|
||||
*/
|
||||
@@ -38,4 +39,5 @@ public interface SecurityExpressionHandler<T> extends AopInfrastructureBean {
|
||||
* invocation type.
|
||||
*/
|
||||
EvaluationContext createEvaluationContext(Authentication authentication, T invocation);
|
||||
|
||||
}
|
||||
|
||||
+4
-6
@@ -59,7 +59,6 @@ public interface SecurityExpressionOperations {
|
||||
* implementation may convert it to use "ROLE_USER" instead. The way in which the role
|
||||
* is converted may depend on the implementation settings.
|
||||
* </p>
|
||||
*
|
||||
* @param role the authority to test (i.e. "USER")
|
||||
* @return true if the authority is found, else false
|
||||
*/
|
||||
@@ -71,12 +70,11 @@ public interface SecurityExpressionOperations {
|
||||
* within {@link Authentication#getAuthorities()}.
|
||||
* </p>
|
||||
* <p>
|
||||
* This is a similar to hasAnyAuthority except that this method implies
|
||||
* that the String passed in is a role. For example, if "USER" is passed in the
|
||||
* implementation may convert it to use "ROLE_USER" instead. The way in which the role
|
||||
* is converted may depend on the implementation settings.
|
||||
* This is a similar to hasAnyAuthority except that this method implies that the
|
||||
* String passed in is a role. For example, if "USER" is passed in the implementation
|
||||
* may convert it to use "ROLE_USER" instead. The way in which the role is converted
|
||||
* may depend on the implementation settings.
|
||||
* </p>
|
||||
*
|
||||
* @param roles the authorities to test (i.e. "USER", "ADMIN")
|
||||
* @return true if any of the authorities is found, else false
|
||||
*/
|
||||
|
||||
+16
-10
@@ -33,10 +33,15 @@ import org.springframework.security.core.authority.AuthorityUtils;
|
||||
* @since 3.0
|
||||
*/
|
||||
public abstract class SecurityExpressionRoot implements SecurityExpressionOperations {
|
||||
|
||||
protected final Authentication authentication;
|
||||
|
||||
private AuthenticationTrustResolver trustResolver;
|
||||
|
||||
private RoleHierarchy roleHierarchy;
|
||||
|
||||
private Set<String> roles;
|
||||
|
||||
private String defaultRolePrefix = "ROLE_";
|
||||
|
||||
/** Allows "permitAll" expression */
|
||||
@@ -44,11 +49,17 @@ public abstract class SecurityExpressionRoot implements SecurityExpressionOperat
|
||||
|
||||
/** Allows "denyAll" expression */
|
||||
public final boolean denyAll = false;
|
||||
|
||||
private PermissionEvaluator permissionEvaluator;
|
||||
|
||||
public final String read = "read";
|
||||
|
||||
public final String write = "write";
|
||||
|
||||
public final String create = "create";
|
||||
|
||||
public final String delete = "delete";
|
||||
|
||||
public final String admin = "administration";
|
||||
|
||||
/**
|
||||
@@ -116,8 +127,7 @@ public abstract class SecurityExpressionRoot implements SecurityExpressionOperat
|
||||
}
|
||||
|
||||
public final boolean isFullyAuthenticated() {
|
||||
return !trustResolver.isAnonymous(authentication)
|
||||
&& !trustResolver.isRememberMe(authentication);
|
||||
return !trustResolver.isAnonymous(authentication) && !trustResolver.isRememberMe(authentication);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -148,7 +158,6 @@ public abstract class SecurityExpressionRoot implements SecurityExpressionOperat
|
||||
* <p>
|
||||
* If null or empty, then no default role prefix is used.
|
||||
* </p>
|
||||
*
|
||||
* @param defaultRolePrefix the default prefix to add to roles. Default "ROLE_".
|
||||
*/
|
||||
public void setDefaultRolePrefix(String defaultRolePrefix) {
|
||||
@@ -157,12 +166,10 @@ public abstract class SecurityExpressionRoot implements SecurityExpressionOperat
|
||||
|
||||
private Set<String> getAuthoritySet() {
|
||||
if (roles == null) {
|
||||
Collection<? extends GrantedAuthority> userAuthorities = authentication
|
||||
.getAuthorities();
|
||||
Collection<? extends GrantedAuthority> userAuthorities = authentication.getAuthorities();
|
||||
|
||||
if (roleHierarchy != null) {
|
||||
userAuthorities = roleHierarchy
|
||||
.getReachableGrantedAuthorities(userAuthorities);
|
||||
userAuthorities = roleHierarchy.getReachableGrantedAuthorities(userAuthorities);
|
||||
}
|
||||
|
||||
roles = AuthorityUtils.authorityListToSet(userAuthorities);
|
||||
@@ -176,8 +183,7 @@ public abstract class SecurityExpressionRoot implements SecurityExpressionOperat
|
||||
}
|
||||
|
||||
public boolean hasPermission(Object targetId, String targetType, Object permission) {
|
||||
return permissionEvaluator.hasPermission(authentication, (Serializable) targetId,
|
||||
targetType, permission);
|
||||
return permissionEvaluator.hasPermission(authentication, (Serializable) targetId, targetType, permission);
|
||||
}
|
||||
|
||||
public void setPermissionEvaluator(PermissionEvaluator permissionEvaluator) {
|
||||
@@ -187,7 +193,6 @@ public abstract class SecurityExpressionRoot implements SecurityExpressionOperat
|
||||
/**
|
||||
* Prefixes role with defaultRolePrefix if defaultRolePrefix is non-null and if role
|
||||
* does not already start with defaultRolePrefix.
|
||||
*
|
||||
* @param defaultRolePrefix
|
||||
* @param role
|
||||
* @return
|
||||
@@ -204,4 +209,5 @@ public abstract class SecurityExpressionRoot implements SecurityExpressionOperat
|
||||
}
|
||||
return defaultRolePrefix + role;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+10
-10
@@ -33,30 +33,29 @@ import org.springframework.util.Assert;
|
||||
* @since 3.0
|
||||
*/
|
||||
abstract class AbstractExpressionBasedMethodConfigAttribute implements ConfigAttribute {
|
||||
|
||||
private final Expression filterExpression;
|
||||
|
||||
private final Expression authorizeExpression;
|
||||
|
||||
/**
|
||||
* Parses the supplied expressions as Spring-EL.
|
||||
*/
|
||||
AbstractExpressionBasedMethodConfigAttribute(String filterExpression,
|
||||
String authorizeExpression) throws ParseException {
|
||||
AbstractExpressionBasedMethodConfigAttribute(String filterExpression, String authorizeExpression)
|
||||
throws ParseException {
|
||||
Assert.isTrue(filterExpression != null || authorizeExpression != null,
|
||||
"Filter and authorization Expressions cannot both be null");
|
||||
SpelExpressionParser parser = new SpelExpressionParser();
|
||||
this.filterExpression = filterExpression == null ? null : parser
|
||||
.parseExpression(filterExpression);
|
||||
this.authorizeExpression = authorizeExpression == null ? null : parser
|
||||
.parseExpression(authorizeExpression);
|
||||
this.filterExpression = filterExpression == null ? null : parser.parseExpression(filterExpression);
|
||||
this.authorizeExpression = authorizeExpression == null ? null : parser.parseExpression(authorizeExpression);
|
||||
}
|
||||
|
||||
AbstractExpressionBasedMethodConfigAttribute(Expression filterExpression,
|
||||
Expression authorizeExpression) throws ParseException {
|
||||
AbstractExpressionBasedMethodConfigAttribute(Expression filterExpression, Expression authorizeExpression)
|
||||
throws ParseException {
|
||||
Assert.isTrue(filterExpression != null || authorizeExpression != null,
|
||||
"Filter and authorization Expressions cannot both be null");
|
||||
this.filterExpression = filterExpression == null ? null : filterExpression;
|
||||
this.authorizeExpression = authorizeExpression == null ? null
|
||||
: authorizeExpression;
|
||||
this.authorizeExpression = authorizeExpression == null ? null : authorizeExpression;
|
||||
}
|
||||
|
||||
Expression getFilterExpression() {
|
||||
@@ -70,4 +69,5 @@ abstract class AbstractExpressionBasedMethodConfigAttribute implements ConfigAtt
|
||||
public String getAttribute() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+37
-45
@@ -49,15 +49,17 @@ import org.springframework.util.Assert;
|
||||
* @author Luke Taylor
|
||||
* @since 3.0
|
||||
*/
|
||||
public class DefaultMethodSecurityExpressionHandler extends
|
||||
AbstractSecurityExpressionHandler<MethodInvocation> implements
|
||||
MethodSecurityExpressionHandler {
|
||||
public class DefaultMethodSecurityExpressionHandler extends AbstractSecurityExpressionHandler<MethodInvocation>
|
||||
implements MethodSecurityExpressionHandler {
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
|
||||
|
||||
private ParameterNameDiscoverer parameterNameDiscoverer = new DefaultSecurityParameterNameDiscoverer();
|
||||
|
||||
private PermissionCacheOptimizer permissionCacheOptimizer = null;
|
||||
|
||||
private String defaultRolePrefix = "ROLE_";
|
||||
|
||||
public DefaultMethodSecurityExpressionHandler() {
|
||||
@@ -67,18 +69,16 @@ public class DefaultMethodSecurityExpressionHandler extends
|
||||
* Uses a {@link MethodSecurityEvaluationContext} as the <tt>EvaluationContext</tt>
|
||||
* implementation.
|
||||
*/
|
||||
public StandardEvaluationContext createEvaluationContextInternal(Authentication auth,
|
||||
MethodInvocation mi) {
|
||||
public StandardEvaluationContext createEvaluationContextInternal(Authentication auth, MethodInvocation mi) {
|
||||
return new MethodSecurityEvaluationContext(auth, mi, getParameterNameDiscoverer());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the root object for expression evaluation.
|
||||
*/
|
||||
protected MethodSecurityExpressionOperations createSecurityExpressionRoot(
|
||||
Authentication authentication, MethodInvocation invocation) {
|
||||
MethodSecurityExpressionRoot root = new MethodSecurityExpressionRoot(
|
||||
authentication);
|
||||
protected MethodSecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication,
|
||||
MethodInvocation invocation) {
|
||||
MethodSecurityExpressionRoot root = new MethodSecurityExpressionRoot(authentication);
|
||||
root.setThis(invocation.getThis());
|
||||
root.setPermissionEvaluator(getPermissionEvaluator());
|
||||
root.setTrustResolver(getTrustResolver());
|
||||
@@ -89,24 +89,22 @@ public class DefaultMethodSecurityExpressionHandler extends
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the {@code filterTarget} object (which must be either a collection, array, map
|
||||
* or stream), by evaluating the supplied expression.
|
||||
* Filters the {@code filterTarget} object (which must be either a collection, array,
|
||||
* map or stream), by evaluating the supplied expression.
|
||||
* <p>
|
||||
* If a {@code Collection} or {@code Map} is used, the original instance will be modified to contain
|
||||
* the elements for which the permission expression evaluates to {@code true}. For an
|
||||
* array, a new array instance will be returned.
|
||||
* If a {@code Collection} or {@code Map} is used, the original instance will be
|
||||
* modified to contain the elements for which the permission expression evaluates to
|
||||
* {@code true}. For an array, a new array instance will be returned.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public Object filter(Object filterTarget, Expression filterExpression,
|
||||
EvaluationContext ctx) {
|
||||
MethodSecurityExpressionOperations rootObject = (MethodSecurityExpressionOperations) ctx
|
||||
.getRootObject().getValue();
|
||||
public Object filter(Object filterTarget, Expression filterExpression, EvaluationContext ctx) {
|
||||
MethodSecurityExpressionOperations rootObject = (MethodSecurityExpressionOperations) ctx.getRootObject()
|
||||
.getValue();
|
||||
final boolean debug = logger.isDebugEnabled();
|
||||
List retainList;
|
||||
|
||||
if (debug) {
|
||||
logger.debug("Filtering with expression: "
|
||||
+ filterExpression.getExpressionString());
|
||||
logger.debug("Filtering with expression: " + filterExpression.getExpressionString());
|
||||
}
|
||||
|
||||
if (filterTarget instanceof Collection) {
|
||||
@@ -114,13 +112,11 @@ public class DefaultMethodSecurityExpressionHandler extends
|
||||
retainList = new ArrayList(collection.size());
|
||||
|
||||
if (debug) {
|
||||
logger.debug("Filtering collection with " + collection.size()
|
||||
+ " elements");
|
||||
logger.debug("Filtering collection with " + collection.size() + " elements");
|
||||
}
|
||||
|
||||
if (permissionCacheOptimizer != null) {
|
||||
permissionCacheOptimizer.cachePermissionsFor(
|
||||
rootObject.getAuthentication(), collection);
|
||||
permissionCacheOptimizer.cachePermissionsFor(rootObject.getAuthentication(), collection);
|
||||
}
|
||||
|
||||
for (Object filterObject : (Collection) filterTarget) {
|
||||
@@ -150,8 +146,7 @@ public class DefaultMethodSecurityExpressionHandler extends
|
||||
}
|
||||
|
||||
if (permissionCacheOptimizer != null) {
|
||||
permissionCacheOptimizer.cachePermissionsFor(
|
||||
rootObject.getAuthentication(), Arrays.asList(array));
|
||||
permissionCacheOptimizer.cachePermissionsFor(rootObject.getAuthentication(), Arrays.asList(array));
|
||||
}
|
||||
|
||||
for (Object o : array) {
|
||||
@@ -166,8 +161,8 @@ public class DefaultMethodSecurityExpressionHandler extends
|
||||
logger.debug("Retaining elements: " + retainList);
|
||||
}
|
||||
|
||||
Object[] filtered = (Object[]) Array.newInstance(filterTarget.getClass()
|
||||
.getComponentType(), retainList.size());
|
||||
Object[] filtered = (Object[]) Array.newInstance(filterTarget.getClass().getComponentType(),
|
||||
retainList.size());
|
||||
for (int i = 0; i < retainList.size(); i++) {
|
||||
filtered[i] = retainList.get(i);
|
||||
}
|
||||
@@ -207,19 +202,16 @@ public class DefaultMethodSecurityExpressionHandler extends
|
||||
return original.filter(filterObject -> {
|
||||
rootObject.setFilterObject(filterObject);
|
||||
return ExpressionUtils.evaluateAsBoolean(filterExpression, ctx);
|
||||
})
|
||||
.onClose(original::close);
|
||||
}).onClose(original::close);
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException(
|
||||
"Filter target must be a collection, array, map or stream type, but was "
|
||||
+ filterTarget);
|
||||
"Filter target must be a collection, array, map or stream type, but was " + filterTarget);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link AuthenticationTrustResolver} to be used. The default is
|
||||
* {@link AuthenticationTrustResolverImpl}.
|
||||
*
|
||||
* @param trustResolver the {@link AuthenticationTrustResolver} to use. Cannot be
|
||||
* null.
|
||||
*/
|
||||
@@ -230,7 +222,7 @@ public class DefaultMethodSecurityExpressionHandler extends
|
||||
|
||||
/**
|
||||
* @return The current {@link AuthenticationTrustResolver}
|
||||
*/
|
||||
*/
|
||||
protected AuthenticationTrustResolver getTrustResolver() {
|
||||
return trustResolver;
|
||||
}
|
||||
@@ -246,33 +238,32 @@ public class DefaultMethodSecurityExpressionHandler extends
|
||||
|
||||
/**
|
||||
* @return The current {@link ParameterNameDiscoverer}
|
||||
*/
|
||||
*/
|
||||
protected ParameterNameDiscoverer getParameterNameDiscoverer() {
|
||||
return parameterNameDiscoverer;
|
||||
}
|
||||
|
||||
public void setPermissionCacheOptimizer(
|
||||
PermissionCacheOptimizer permissionCacheOptimizer) {
|
||||
public void setPermissionCacheOptimizer(PermissionCacheOptimizer permissionCacheOptimizer) {
|
||||
this.permissionCacheOptimizer = permissionCacheOptimizer;
|
||||
}
|
||||
|
||||
public void setReturnObject(Object returnObject, EvaluationContext ctx) {
|
||||
((MethodSecurityExpressionOperations) ctx.getRootObject().getValue())
|
||||
.setReturnObject(returnObject);
|
||||
((MethodSecurityExpressionOperations) ctx.getRootObject().getValue()).setReturnObject(returnObject);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Sets the default prefix to be added to {@link org.springframework.security.access.expression.SecurityExpressionRoot#hasAnyRole(String...)} or
|
||||
* {@link org.springframework.security.access.expression.SecurityExpressionRoot#hasRole(String)}. For example, if hasRole("ADMIN") or hasRole("ROLE_ADMIN")
|
||||
* is passed in, then the role ROLE_ADMIN will be used when the defaultRolePrefix is
|
||||
* "ROLE_" (default).
|
||||
* Sets the default prefix to be added to
|
||||
* {@link org.springframework.security.access.expression.SecurityExpressionRoot#hasAnyRole(String...)}
|
||||
* or
|
||||
* {@link org.springframework.security.access.expression.SecurityExpressionRoot#hasRole(String)}.
|
||||
* For example, if hasRole("ADMIN") or hasRole("ROLE_ADMIN") is passed in, then the
|
||||
* role ROLE_ADMIN will be used when the defaultRolePrefix is "ROLE_" (default).
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* If null or empty, then no default role prefix is used.
|
||||
* </p>
|
||||
*
|
||||
* @param defaultRolePrefix the default prefix to add to roles. Default "ROLE_".
|
||||
*/
|
||||
public void setDefaultRolePrefix(String defaultRolePrefix) {
|
||||
@@ -281,8 +272,9 @@ public class DefaultMethodSecurityExpressionHandler extends
|
||||
|
||||
/**
|
||||
* @return The default role prefix
|
||||
*/
|
||||
*/
|
||||
protected String getDefaultRolePrefix() {
|
||||
return defaultRolePrefix;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+20
-24
@@ -30,53 +30,49 @@ import org.springframework.security.access.prepost.PrePostInvocationAttributeFac
|
||||
* @author Rob Winch
|
||||
* @since 3.0
|
||||
*/
|
||||
public class ExpressionBasedAnnotationAttributeFactory implements
|
||||
PrePostInvocationAttributeFactory {
|
||||
public class ExpressionBasedAnnotationAttributeFactory implements PrePostInvocationAttributeFactory {
|
||||
|
||||
private final Object parserLock = new Object();
|
||||
|
||||
private ExpressionParser parser;
|
||||
|
||||
private MethodSecurityExpressionHandler handler;
|
||||
|
||||
public ExpressionBasedAnnotationAttributeFactory(
|
||||
MethodSecurityExpressionHandler handler) {
|
||||
public ExpressionBasedAnnotationAttributeFactory(MethodSecurityExpressionHandler handler) {
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
public PreInvocationAttribute createPreInvocationAttribute(String preFilterAttribute,
|
||||
String filterObject, String preAuthorizeAttribute) {
|
||||
public PreInvocationAttribute createPreInvocationAttribute(String preFilterAttribute, String filterObject,
|
||||
String preAuthorizeAttribute) {
|
||||
try {
|
||||
// TODO: Optimization of permitAll
|
||||
ExpressionParser parser = getParser();
|
||||
Expression preAuthorizeExpression = preAuthorizeAttribute == null ? parser
|
||||
.parseExpression("permitAll") : parser
|
||||
.parseExpression(preAuthorizeAttribute);
|
||||
Expression preFilterExpression = preFilterAttribute == null ? null : parser
|
||||
.parseExpression(preFilterAttribute);
|
||||
return new PreInvocationExpressionAttribute(preFilterExpression,
|
||||
filterObject, preAuthorizeExpression);
|
||||
Expression preAuthorizeExpression = preAuthorizeAttribute == null ? parser.parseExpression("permitAll")
|
||||
: parser.parseExpression(preAuthorizeAttribute);
|
||||
Expression preFilterExpression = preFilterAttribute == null ? null
|
||||
: parser.parseExpression(preFilterAttribute);
|
||||
return new PreInvocationExpressionAttribute(preFilterExpression, filterObject, preAuthorizeExpression);
|
||||
}
|
||||
catch (ParseException e) {
|
||||
throw new IllegalArgumentException("Failed to parse expression '"
|
||||
+ e.getExpressionString() + "'", e);
|
||||
throw new IllegalArgumentException("Failed to parse expression '" + e.getExpressionString() + "'", e);
|
||||
}
|
||||
}
|
||||
|
||||
public PostInvocationAttribute createPostInvocationAttribute(
|
||||
String postFilterAttribute, String postAuthorizeAttribute) {
|
||||
public PostInvocationAttribute createPostInvocationAttribute(String postFilterAttribute,
|
||||
String postAuthorizeAttribute) {
|
||||
try {
|
||||
ExpressionParser parser = getParser();
|
||||
Expression postAuthorizeExpression = postAuthorizeAttribute == null ? null
|
||||
: parser.parseExpression(postAuthorizeAttribute);
|
||||
Expression postFilterExpression = postFilterAttribute == null ? null : parser
|
||||
.parseExpression(postFilterAttribute);
|
||||
Expression postFilterExpression = postFilterAttribute == null ? null
|
||||
: parser.parseExpression(postFilterAttribute);
|
||||
|
||||
if (postFilterExpression != null || postAuthorizeExpression != null) {
|
||||
return new PostInvocationExpressionAttribute(postFilterExpression,
|
||||
postAuthorizeExpression);
|
||||
return new PostInvocationExpressionAttribute(postFilterExpression, postAuthorizeExpression);
|
||||
}
|
||||
}
|
||||
catch (ParseException e) {
|
||||
throw new IllegalArgumentException("Failed to parse expression '"
|
||||
+ e.getExpressionString() + "'", e);
|
||||
throw new IllegalArgumentException("Failed to parse expression '" + e.getExpressionString() + "'", e);
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -84,7 +80,6 @@ public class ExpressionBasedAnnotationAttributeFactory implements
|
||||
|
||||
/**
|
||||
* Delay the lookup of the {@link ExpressionParser} to prevent SEC-2136
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private ExpressionParser getParser() {
|
||||
@@ -97,4 +92,5 @@ public class ExpressionBasedAnnotationAttributeFactory implements
|
||||
}
|
||||
return this.parser;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+9
-14
@@ -27,27 +27,23 @@ import org.springframework.security.access.prepost.PostInvocationAuthorizationAd
|
||||
import org.springframework.security.core.Authentication;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @since 3.0
|
||||
*/
|
||||
public class ExpressionBasedPostInvocationAdvice implements
|
||||
PostInvocationAuthorizationAdvice {
|
||||
public class ExpressionBasedPostInvocationAdvice implements PostInvocationAuthorizationAdvice {
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private final MethodSecurityExpressionHandler expressionHandler;
|
||||
|
||||
public ExpressionBasedPostInvocationAdvice(
|
||||
MethodSecurityExpressionHandler expressionHandler) {
|
||||
public ExpressionBasedPostInvocationAdvice(MethodSecurityExpressionHandler expressionHandler) {
|
||||
this.expressionHandler = expressionHandler;
|
||||
}
|
||||
|
||||
public Object after(Authentication authentication, MethodInvocation mi,
|
||||
PostInvocationAttribute postAttr, Object returnedObject)
|
||||
throws AccessDeniedException {
|
||||
public Object after(Authentication authentication, MethodInvocation mi, PostInvocationAttribute postAttr,
|
||||
Object returnedObject) throws AccessDeniedException {
|
||||
PostInvocationExpressionAttribute pia = (PostInvocationExpressionAttribute) postAttr;
|
||||
EvaluationContext ctx = expressionHandler.createEvaluationContext(authentication,
|
||||
mi);
|
||||
EvaluationContext ctx = expressionHandler.createEvaluationContext(authentication, mi);
|
||||
Expression postFilter = pia.getFilterExpression();
|
||||
Expression postAuthorize = pia.getAuthorizeExpression();
|
||||
|
||||
@@ -57,8 +53,7 @@ public class ExpressionBasedPostInvocationAdvice implements
|
||||
}
|
||||
|
||||
if (returnedObject != null) {
|
||||
returnedObject = expressionHandler
|
||||
.filter(returnedObject, postFilter, ctx);
|
||||
returnedObject = expressionHandler.filter(returnedObject, postFilter, ctx);
|
||||
}
|
||||
else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
@@ -69,8 +64,7 @@ public class ExpressionBasedPostInvocationAdvice implements
|
||||
|
||||
expressionHandler.setReturnObject(returnedObject, ctx);
|
||||
|
||||
if (postAuthorize != null
|
||||
&& !ExpressionUtils.evaluateAsBoolean(postAuthorize, ctx)) {
|
||||
if (postAuthorize != null && !ExpressionUtils.evaluateAsBoolean(postAuthorize, ctx)) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("PostAuthorize expression rejected access");
|
||||
}
|
||||
@@ -79,4 +73,5 @@ public class ExpressionBasedPostInvocationAdvice implements
|
||||
|
||||
return returnedObject;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+12
-16
@@ -34,15 +34,13 @@ import org.springframework.security.core.Authentication;
|
||||
* @author Luke Taylor
|
||||
* @since 3.0
|
||||
*/
|
||||
public class ExpressionBasedPreInvocationAdvice implements
|
||||
PreInvocationAuthorizationAdvice {
|
||||
public class ExpressionBasedPreInvocationAdvice implements PreInvocationAuthorizationAdvice {
|
||||
|
||||
private MethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
|
||||
|
||||
public boolean before(Authentication authentication, MethodInvocation mi,
|
||||
PreInvocationAttribute attr) {
|
||||
public boolean before(Authentication authentication, MethodInvocation mi, PreInvocationAttribute attr) {
|
||||
PreInvocationExpressionAttribute preAttr = (PreInvocationExpressionAttribute) attr;
|
||||
EvaluationContext ctx = expressionHandler.createEvaluationContext(authentication,
|
||||
mi);
|
||||
EvaluationContext ctx = expressionHandler.createEvaluationContext(authentication, mi);
|
||||
Expression preFilter = preAttr.getFilterExpression();
|
||||
Expression preAuthorize = preAttr.getAuthorizeExpression();
|
||||
|
||||
@@ -59,16 +57,14 @@ public class ExpressionBasedPreInvocationAdvice implements
|
||||
return ExpressionUtils.evaluateAsBoolean(preAuthorize, ctx);
|
||||
}
|
||||
|
||||
private Object findFilterTarget(String filterTargetName, EvaluationContext ctx,
|
||||
MethodInvocation mi) {
|
||||
private Object findFilterTarget(String filterTargetName, EvaluationContext ctx, MethodInvocation mi) {
|
||||
Object filterTarget = null;
|
||||
|
||||
if (filterTargetName.length() > 0) {
|
||||
filterTarget = ctx.lookupVariable(filterTargetName);
|
||||
if (filterTarget == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Filter target was null, or no argument with name "
|
||||
+ filterTargetName + " found in method");
|
||||
"Filter target was null, or no argument with name " + filterTargetName + " found in method");
|
||||
}
|
||||
}
|
||||
else if (mi.getArguments().length == 1) {
|
||||
@@ -77,19 +73,18 @@ public class ExpressionBasedPreInvocationAdvice implements
|
||||
filterTarget = arg;
|
||||
}
|
||||
if (filterTarget == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"A PreFilter expression was set but the method argument type"
|
||||
+ arg.getClass() + " is not filterable");
|
||||
throw new IllegalArgumentException("A PreFilter expression was set but the method argument type"
|
||||
+ arg.getClass() + " is not filterable");
|
||||
}
|
||||
} else if (mi.getArguments().length > 1) {
|
||||
}
|
||||
else if (mi.getArguments().length > 1) {
|
||||
throw new IllegalArgumentException(
|
||||
"Unable to determine the method argument for filtering. Specify the filter target.");
|
||||
}
|
||||
|
||||
if (filterTarget.getClass().isArray()) {
|
||||
throw new IllegalArgumentException(
|
||||
"Pre-filtering on array types is not supported. "
|
||||
+ "Using a Collection will solve this problem");
|
||||
"Pre-filtering on array types is not supported. " + "Using a Collection will solve this problem");
|
||||
}
|
||||
|
||||
return filterTarget;
|
||||
@@ -98,4 +93,5 @@ public class ExpressionBasedPreInvocationAdvice implements
|
||||
public void setExpressionHandler(MethodSecurityExpressionHandler expressionHandler) {
|
||||
this.expressionHandler = expressionHandler;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+3
-2
@@ -37,8 +37,8 @@ import org.springframework.security.core.parameters.DefaultSecurityParameterName
|
||||
* @since 3.0
|
||||
*/
|
||||
class MethodSecurityEvaluationContext extends MethodBasedEvaluationContext {
|
||||
private static final Log logger = LogFactory
|
||||
.getLog(MethodSecurityEvaluationContext.class);
|
||||
|
||||
private static final Log logger = LogFactory.getLog(MethodSecurityEvaluationContext.class);
|
||||
|
||||
/**
|
||||
* Intended for testing. Don't use in practice as it creates a new parameter resolver
|
||||
@@ -57,4 +57,5 @@ class MethodSecurityEvaluationContext extends MethodBasedEvaluationContext {
|
||||
private static Method getSpecificMethod(MethodInvocation mi) {
|
||||
return AopUtils.getMostSpecificMethod(mi.getMethod(), AopProxyUtils.ultimateTargetClass(mi.getThis()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-4
@@ -27,11 +27,10 @@ import org.springframework.security.access.expression.SecurityExpressionHandler;
|
||||
* @author Luke Taylor
|
||||
* @since 3.0
|
||||
*/
|
||||
public interface MethodSecurityExpressionHandler extends
|
||||
SecurityExpressionHandler<MethodInvocation> {
|
||||
public interface MethodSecurityExpressionHandler extends SecurityExpressionHandler<MethodInvocation> {
|
||||
|
||||
/**
|
||||
* Filters a target collection or array. Only applies to method invocations.
|
||||
*
|
||||
* @param filterTarget the array or collection to be filtered.
|
||||
* @param filterExpression the expression which should be used as the filter
|
||||
* condition. If it returns false on evaluation, the object will be removed from the
|
||||
@@ -45,7 +44,6 @@ public interface MethodSecurityExpressionHandler extends
|
||||
/**
|
||||
* Used to inform the expression system of the return object for the given evaluation
|
||||
* context. Only applies to method invocations.
|
||||
*
|
||||
* @param returnObject the return object value
|
||||
* @param ctx the context within which the object should be set (as created through a
|
||||
* call to
|
||||
|
||||
+2
@@ -25,6 +25,7 @@ import org.springframework.security.access.expression.SecurityExpressionOperatio
|
||||
* @since 3.1.1
|
||||
*/
|
||||
public interface MethodSecurityExpressionOperations extends SecurityExpressionOperations {
|
||||
|
||||
void setFilterObject(Object filterObject);
|
||||
|
||||
Object getFilterObject();
|
||||
@@ -34,4 +35,5 @@ public interface MethodSecurityExpressionOperations extends SecurityExpressionOp
|
||||
Object getReturnObject();
|
||||
|
||||
Object getThis();
|
||||
|
||||
}
|
||||
|
||||
+5
-3
@@ -24,10 +24,12 @@ import org.springframework.security.core.Authentication;
|
||||
* @author Luke Taylor
|
||||
* @since 3.0
|
||||
*/
|
||||
class MethodSecurityExpressionRoot extends SecurityExpressionRoot implements
|
||||
MethodSecurityExpressionOperations {
|
||||
class MethodSecurityExpressionRoot extends SecurityExpressionRoot implements MethodSecurityExpressionOperations {
|
||||
|
||||
private Object filterObject;
|
||||
|
||||
private Object returnObject;
|
||||
|
||||
private Object target;
|
||||
|
||||
MethodSecurityExpressionRoot(Authentication a) {
|
||||
@@ -54,7 +56,6 @@ class MethodSecurityExpressionRoot extends SecurityExpressionRoot implements
|
||||
* Sets the "this" property for use in expressions. Typically this will be the "this"
|
||||
* property of the {@code JoinPoint} representing the method invocation which is being
|
||||
* protected.
|
||||
*
|
||||
* @param target the target object on which the method in is being invoked.
|
||||
*/
|
||||
void setThis(Object target) {
|
||||
@@ -64,4 +65,5 @@ class MethodSecurityExpressionRoot extends SecurityExpressionRoot implements
|
||||
public Object getThis() {
|
||||
return target;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+8
-12
@@ -20,20 +20,18 @@ import org.springframework.expression.ParseException;
|
||||
import org.springframework.security.access.prepost.PostInvocationAttribute;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @since 3.0
|
||||
*/
|
||||
class PostInvocationExpressionAttribute extends
|
||||
AbstractExpressionBasedMethodConfigAttribute implements PostInvocationAttribute {
|
||||
class PostInvocationExpressionAttribute extends AbstractExpressionBasedMethodConfigAttribute
|
||||
implements PostInvocationAttribute {
|
||||
|
||||
PostInvocationExpressionAttribute(String filterExpression, String authorizeExpression)
|
||||
throws ParseException {
|
||||
PostInvocationExpressionAttribute(String filterExpression, String authorizeExpression) throws ParseException {
|
||||
super(filterExpression, authorizeExpression);
|
||||
}
|
||||
|
||||
PostInvocationExpressionAttribute(Expression filterExpression,
|
||||
Expression authorizeExpression) throws ParseException {
|
||||
PostInvocationExpressionAttribute(Expression filterExpression, Expression authorizeExpression)
|
||||
throws ParseException {
|
||||
super(filterExpression, authorizeExpression);
|
||||
}
|
||||
|
||||
@@ -42,11 +40,9 @@ class PostInvocationExpressionAttribute extends
|
||||
StringBuilder sb = new StringBuilder();
|
||||
Expression authorize = getAuthorizeExpression();
|
||||
Expression filter = getFilterExpression();
|
||||
sb.append("[authorize: '").append(
|
||||
authorize == null ? "null" : authorize.getExpressionString());
|
||||
sb.append("', filter: '")
|
||||
.append(filter == null ? "null" : filter.getExpressionString())
|
||||
.append("']");
|
||||
sb.append("[authorize: '").append(authorize == null ? "null" : authorize.getExpressionString());
|
||||
sb.append("', filter: '").append(filter == null ? "null" : filter.getExpressionString()).append("']");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+9
-12
@@ -20,24 +20,23 @@ import org.springframework.expression.ParseException;
|
||||
import org.springframework.security.access.prepost.PreInvocationAttribute;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @since 3.0
|
||||
*/
|
||||
class PreInvocationExpressionAttribute extends
|
||||
AbstractExpressionBasedMethodConfigAttribute implements PreInvocationAttribute {
|
||||
class PreInvocationExpressionAttribute extends AbstractExpressionBasedMethodConfigAttribute
|
||||
implements PreInvocationAttribute {
|
||||
|
||||
private final String filterTarget;
|
||||
|
||||
PreInvocationExpressionAttribute(String filterExpression, String filterTarget,
|
||||
String authorizeExpression) throws ParseException {
|
||||
PreInvocationExpressionAttribute(String filterExpression, String filterTarget, String authorizeExpression)
|
||||
throws ParseException {
|
||||
super(filterExpression, authorizeExpression);
|
||||
|
||||
this.filterTarget = filterTarget;
|
||||
}
|
||||
|
||||
PreInvocationExpressionAttribute(Expression filterExpression, String filterTarget,
|
||||
Expression authorizeExpression) throws ParseException {
|
||||
PreInvocationExpressionAttribute(Expression filterExpression, String filterTarget, Expression authorizeExpression)
|
||||
throws ParseException {
|
||||
super(filterExpression, authorizeExpression);
|
||||
|
||||
this.filterTarget = filterTarget;
|
||||
@@ -46,7 +45,6 @@ class PreInvocationExpressionAttribute extends
|
||||
/**
|
||||
* The parameter name of the target argument (must be a Collection) to which filtering
|
||||
* will be applied.
|
||||
*
|
||||
* @return the method parameter name
|
||||
*/
|
||||
String getFilterTarget() {
|
||||
@@ -58,11 +56,10 @@ class PreInvocationExpressionAttribute extends
|
||||
StringBuilder sb = new StringBuilder();
|
||||
Expression authorize = getAuthorizeExpression();
|
||||
Expression filter = getFilterExpression();
|
||||
sb.append("[authorize: '").append(
|
||||
authorize == null ? "null" : authorize.getExpressionString());
|
||||
sb.append("', filter: '").append(
|
||||
filter == null ? "null" : filter.getExpressionString());
|
||||
sb.append("[authorize: '").append(authorize == null ? "null" : authorize.getExpressionString());
|
||||
sb.append("', filter: '").append(filter == null ? "null" : filter.getExpressionString());
|
||||
sb.append("', filterTarget: '").append(filterTarget).append("']");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
-1
@@ -19,4 +19,3 @@
|
||||
* @since 3.0
|
||||
*/
|
||||
package org.springframework.security.access.expression.method;
|
||||
|
||||
|
||||
@@ -14,10 +14,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
/**
|
||||
* Expression handling code to support the use of Spring-EL based expressions in {@code @PreAuthorize}, {@code @PreFilter},
|
||||
* {@code @PostAuthorize} and {@code @PostFilter} annotations. Mainly for internal framework use and liable to change.
|
||||
* Expression handling code to support the use of Spring-EL based expressions in
|
||||
* {@code @PreAuthorize}, {@code @PreFilter}, {@code @PostAuthorize} and
|
||||
* {@code @PostFilter} annotations. Mainly for internal framework use and liable to
|
||||
* change.
|
||||
*
|
||||
* @since 3.0
|
||||
*/
|
||||
package org.springframework.security.access.expression;
|
||||
|
||||
|
||||
-1
@@ -20,7 +20,6 @@ import java.util.Collection;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @since 3.0
|
||||
*/
|
||||
|
||||
-1
@@ -36,7 +36,6 @@ public interface RoleHierarchy {
|
||||
* Role hierarchy: ROLE_A > ROLE_B > ROLE_C.<br>
|
||||
* Directly assigned authority: ROLE_A.<br>
|
||||
* Reachable authorities: ROLE_A, ROLE_B, ROLE_C.
|
||||
*
|
||||
* @param authorities - List of the directly assigned authorities.
|
||||
* @return List of all reachable authorities given the assigned authorities.
|
||||
*/
|
||||
|
||||
+3
-2
@@ -24,14 +24,15 @@ import java.util.*;
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public class RoleHierarchyAuthoritiesMapper implements GrantedAuthoritiesMapper {
|
||||
|
||||
private final RoleHierarchy roleHierarchy;
|
||||
|
||||
public RoleHierarchyAuthoritiesMapper(RoleHierarchy roleHierarchy) {
|
||||
this.roleHierarchy = roleHierarchy;
|
||||
}
|
||||
|
||||
public Collection<? extends GrantedAuthority> mapAuthorities(
|
||||
Collection<? extends GrantedAuthority> authorities) {
|
||||
public Collection<? extends GrantedAuthority> mapAuthorities(Collection<? extends GrantedAuthority> authorities) {
|
||||
return roleHierarchy.getReachableGrantedAuthorities(authorities);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+30
-28
@@ -34,7 +34,8 @@ import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
* This class defines a role hierarchy for use with various access checking components.
|
||||
*
|
||||
* <p>
|
||||
* Here is an example configuration of a role hierarchy (hint: read the ">" sign as "includes"):
|
||||
* Here is an example configuration of a role hierarchy (hint: read the ">" sign as
|
||||
* "includes"):
|
||||
*
|
||||
* <pre>
|
||||
* <property name="hierarchy">
|
||||
@@ -49,25 +50,26 @@ import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
* <p>
|
||||
* Explanation of the above:
|
||||
* <ul>
|
||||
* <li>In effect every user with ROLE_A also has ROLE_B, ROLE_AUTHENTICATED and ROLE_UNAUTHENTICATED;</li>
|
||||
* <li>In effect every user with ROLE_A also has ROLE_B, ROLE_AUTHENTICATED and
|
||||
* ROLE_UNAUTHENTICATED;</li>
|
||||
* <li>every user with ROLE_B also has ROLE_AUTHENTICATED and ROLE_UNAUTHENTICATED;</li>
|
||||
* <li>every user with ROLE_AUTHENTICATED also has ROLE_UNAUTHENTICATED.</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>
|
||||
* Hierarchical Roles will dramatically shorten your access rules (and also make the access rules
|
||||
* much more elegant).
|
||||
* Hierarchical Roles will dramatically shorten your access rules (and also make the
|
||||
* access rules much more elegant).
|
||||
*
|
||||
* <p>
|
||||
* Consider this access rule for Spring Security's RoleVoter (background: every user that is
|
||||
* authenticated should be able to log out):
|
||||
* Consider this access rule for Spring Security's RoleVoter (background: every user that
|
||||
* is authenticated should be able to log out):
|
||||
* <pre>/logout.html=ROLE_A,ROLE_B,ROLE_AUTHENTICATED</pre>
|
||||
*
|
||||
* With hierarchical roles this can now be shortened to:
|
||||
* <pre>/logout.html=ROLE_AUTHENTICATED</pre>
|
||||
*
|
||||
* In addition to shorter rules this will also make your access rules more readable and your
|
||||
* intentions clearer.
|
||||
* In addition to shorter rules this will also make your access rules more readable and
|
||||
* your intentions clearer.
|
||||
*
|
||||
* @author Michael Mayr
|
||||
*/
|
||||
@@ -76,20 +78,21 @@ public class RoleHierarchyImpl implements RoleHierarchy {
|
||||
private static final Log logger = LogFactory.getLog(RoleHierarchyImpl.class);
|
||||
|
||||
/**
|
||||
* Raw hierarchy configuration where each line represents single or multiple level role chain.
|
||||
* Raw hierarchy configuration where each line represents single or multiple level
|
||||
* role chain.
|
||||
*/
|
||||
private String roleHierarchyStringRepresentation = null;
|
||||
|
||||
/**
|
||||
* {@code rolesReachableInOneStepMap} is a Map that under the key of a specific role name
|
||||
* contains a set of all roles reachable from this role in 1 step
|
||||
* (i.e. parsed {@link #roleHierarchyStringRepresentation} grouped by the higher role)
|
||||
* {@code rolesReachableInOneStepMap} is a Map that under the key of a specific role
|
||||
* name contains a set of all roles reachable from this role in 1 step (i.e. parsed
|
||||
* {@link #roleHierarchyStringRepresentation} grouped by the higher role)
|
||||
*/
|
||||
private Map<String, Set<GrantedAuthority>> rolesReachableInOneStepMap = null;
|
||||
|
||||
/**
|
||||
* {@code rolesReachableInOneOrMoreStepsMap} is a Map that under the key of a specific role
|
||||
* name contains a set of all roles reachable from this role in 1 or more steps
|
||||
* {@code rolesReachableInOneOrMoreStepsMap} is a Map that under the key of a specific
|
||||
* role name contains a set of all roles reachable from this role in 1 or more steps
|
||||
* (i.e. fully resolved hierarchy from {@link #rolesReachableInOneStepMap})
|
||||
*/
|
||||
private Map<String, Set<GrantedAuthority>> rolesReachableInOneOrMoreStepsMap = null;
|
||||
@@ -100,15 +103,13 @@ public class RoleHierarchyImpl implements RoleHierarchy {
|
||||
* is done for performance reasons (reachable roles can then be calculated in O(1)
|
||||
* time). During pre-calculation, cycles in role hierarchy are detected and will cause
|
||||
* a <tt>CycleInRoleHierarchyException</tt> to be thrown.
|
||||
*
|
||||
* @param roleHierarchyStringRepresentation - String definition of the role hierarchy.
|
||||
*/
|
||||
public void setHierarchy(String roleHierarchyStringRepresentation) {
|
||||
this.roleHierarchyStringRepresentation = roleHierarchyStringRepresentation;
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("setHierarchy() - The following role hierarchy was set: "
|
||||
+ roleHierarchyStringRepresentation);
|
||||
logger.debug("setHierarchy() - The following role hierarchy was set: " + roleHierarchyStringRepresentation);
|
||||
}
|
||||
|
||||
buildRolesReachableInOneStepMap();
|
||||
@@ -150,9 +151,8 @@ public class RoleHierarchyImpl implements RoleHierarchy {
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("getReachableGrantedAuthorities() - From the roles "
|
||||
+ authorities + " one can reach " + reachableRoles
|
||||
+ " in zero or more steps.");
|
||||
logger.debug("getReachableGrantedAuthorities() - From the roles " + authorities + " one can reach "
|
||||
+ reachableRoles + " in zero or more steps.");
|
||||
}
|
||||
|
||||
List<GrantedAuthority> reachableRoleList = new ArrayList<>(reachableRoles.size());
|
||||
@@ -179,14 +179,15 @@ public class RoleHierarchyImpl implements RoleHierarchy {
|
||||
if (!this.rolesReachableInOneStepMap.containsKey(higherRole)) {
|
||||
rolesReachableInOneStepSet = new HashSet<>();
|
||||
this.rolesReachableInOneStepMap.put(higherRole, rolesReachableInOneStepSet);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
rolesReachableInOneStepSet = this.rolesReachableInOneStepMap.get(higherRole);
|
||||
}
|
||||
rolesReachableInOneStepSet.add(lowerRole);
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("buildRolesReachableInOneStepMap() - From role " + higherRole
|
||||
+ " one can reach role " + lowerRole + " in one step.");
|
||||
logger.debug("buildRolesReachableInOneStepMap() - From role " + higherRole + " one can reach role "
|
||||
+ lowerRole + " in one step.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -209,18 +210,19 @@ public class RoleHierarchyImpl implements RoleHierarchy {
|
||||
// take a role from the rolesToVisit set
|
||||
GrantedAuthority lowerRole = rolesToVisitSet.iterator().next();
|
||||
rolesToVisitSet.remove(lowerRole);
|
||||
if (!visitedRolesSet.add(lowerRole) ||
|
||||
!this.rolesReachableInOneStepMap.containsKey(lowerRole.getAuthority())) {
|
||||
if (!visitedRolesSet.add(lowerRole)
|
||||
|| !this.rolesReachableInOneStepMap.containsKey(lowerRole.getAuthority())) {
|
||||
continue; // Already visited role or role with missing hierarchy
|
||||
} else if (roleName.equals(lowerRole.getAuthority())) {
|
||||
}
|
||||
else if (roleName.equals(lowerRole.getAuthority())) {
|
||||
throw new CycleInRoleHierarchyException();
|
||||
}
|
||||
rolesToVisitSet.addAll(this.rolesReachableInOneStepMap.get(lowerRole.getAuthority()));
|
||||
}
|
||||
this.rolesReachableInOneOrMoreStepsMap.put(roleName, visitedRolesSet);
|
||||
|
||||
logger.debug("buildRolesReachableInOneOrMoreStepsMap() - From role " + roleName
|
||||
+ " one can reach " + visitedRolesSet + " in one or more steps.");
|
||||
logger.debug("buildRolesReachableInOneOrMoreStepsMap() - From role " + roleName + " one can reach "
|
||||
+ visitedRolesSet + " in one or more steps.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+5
-5
@@ -35,13 +35,13 @@ public final class RoleHierarchyUtils {
|
||||
|
||||
/**
|
||||
* Converts the supplied {@link Map} of role name to implied role name(s) to a string
|
||||
* representation understood by {@link RoleHierarchyImpl#setHierarchy(String)}.
|
||||
* The map key is the role name and the map value is a {@link List} of implied role name(s).
|
||||
*
|
||||
* representation understood by {@link RoleHierarchyImpl#setHierarchy(String)}. The
|
||||
* map key is the role name and the map value is a {@link List} of implied role
|
||||
* name(s).
|
||||
* @param roleHierarchyMap the mapping(s) of role name to implied role name(s)
|
||||
* @return a string representation of a role hierarchy
|
||||
* @throws IllegalArgumentException if roleHierarchyMap is null or empty or if a role name is null or
|
||||
* empty or if an implied role name(s) is null or empty
|
||||
* @throws IllegalArgumentException if roleHierarchyMap is null or empty or if a role
|
||||
* name is null or empty or if an implied role name(s) is null or empty
|
||||
*
|
||||
*/
|
||||
public static String roleHierarchyFromMap(Map<String, List<String>> roleHierarchyMap) {
|
||||
|
||||
-1
@@ -17,4 +17,3 @@
|
||||
* Role hierarchy implementation.
|
||||
*/
|
||||
package org.springframework.security.access.hierarchicalroles;
|
||||
|
||||
|
||||
+52
-79
@@ -54,7 +54,8 @@ import org.springframework.util.Assert;
|
||||
* configuration of the security interceptor. It will also implement the proper handling
|
||||
* of secure object invocations, namely:
|
||||
* <ol>
|
||||
* <li>Obtain the {@link Authentication} object from the {@link SecurityContextHolder}.</li>
|
||||
* <li>Obtain the {@link Authentication} object from the
|
||||
* {@link SecurityContextHolder}.</li>
|
||||
* <li>Determine if the request relates to a secured or public invocation by looking up
|
||||
* the secure object request against the {@link SecurityMetadataSource}.</li>
|
||||
* <li>For an invocation that is secured (there is a list of <code>ConfigAttribute</code>s
|
||||
@@ -100,8 +101,9 @@ import org.springframework.util.Assert;
|
||||
* @author Ben Alex
|
||||
* @author Rob Winch
|
||||
*/
|
||||
public abstract class AbstractSecurityInterceptor implements InitializingBean,
|
||||
ApplicationEventPublisherAware, MessageSourceAware {
|
||||
public abstract class AbstractSecurityInterceptor
|
||||
implements InitializingBean, ApplicationEventPublisherAware, MessageSourceAware {
|
||||
|
||||
// ~ Static fields/initializers
|
||||
// =====================================================================================
|
||||
|
||||
@@ -111,49 +113,49 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean,
|
||||
// ================================================================================================
|
||||
|
||||
protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
|
||||
|
||||
private ApplicationEventPublisher eventPublisher;
|
||||
|
||||
private AccessDecisionManager accessDecisionManager;
|
||||
|
||||
private AfterInvocationManager afterInvocationManager;
|
||||
|
||||
private AuthenticationManager authenticationManager = new NoOpAuthenticationManager();
|
||||
|
||||
private RunAsManager runAsManager = new NullRunAsManager();
|
||||
|
||||
private boolean alwaysReauthenticate = false;
|
||||
|
||||
private boolean rejectPublicInvocations = false;
|
||||
|
||||
private boolean validateConfigAttributes = true;
|
||||
|
||||
private boolean publishAuthorizationSuccess = false;
|
||||
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
public void afterPropertiesSet() {
|
||||
Assert.notNull(getSecureObjectClass(),
|
||||
"Subclass must provide a non-null response to getSecureObjectClass()");
|
||||
Assert.notNull(getSecureObjectClass(), "Subclass must provide a non-null response to getSecureObjectClass()");
|
||||
Assert.notNull(this.messages, "A message source must be set");
|
||||
Assert.notNull(this.authenticationManager, "An AuthenticationManager is required");
|
||||
Assert.notNull(this.accessDecisionManager, "An AccessDecisionManager is required");
|
||||
Assert.notNull(this.runAsManager, "A RunAsManager is required");
|
||||
Assert.notNull(this.obtainSecurityMetadataSource(),
|
||||
"An SecurityMetadataSource is required");
|
||||
Assert.isTrue(this.obtainSecurityMetadataSource()
|
||||
.supports(getSecureObjectClass()),
|
||||
() -> "SecurityMetadataSource does not support secure object class: "
|
||||
+ getSecureObjectClass());
|
||||
Assert.notNull(this.obtainSecurityMetadataSource(), "An SecurityMetadataSource is required");
|
||||
Assert.isTrue(this.obtainSecurityMetadataSource().supports(getSecureObjectClass()),
|
||||
() -> "SecurityMetadataSource does not support secure object class: " + getSecureObjectClass());
|
||||
Assert.isTrue(this.runAsManager.supports(getSecureObjectClass()),
|
||||
() -> "RunAsManager does not support secure object class: "
|
||||
+ getSecureObjectClass());
|
||||
() -> "RunAsManager does not support secure object class: " + getSecureObjectClass());
|
||||
Assert.isTrue(this.accessDecisionManager.supports(getSecureObjectClass()),
|
||||
() -> "AccessDecisionManager does not support secure object class: "
|
||||
+ getSecureObjectClass());
|
||||
() -> "AccessDecisionManager does not support secure object class: " + getSecureObjectClass());
|
||||
|
||||
if (this.afterInvocationManager != null) {
|
||||
Assert.isTrue(this.afterInvocationManager.supports(getSecureObjectClass()),
|
||||
() -> "AfterInvocationManager does not support secure object class: "
|
||||
+ getSecureObjectClass());
|
||||
() -> "AfterInvocationManager does not support secure object class: " + getSecureObjectClass());
|
||||
}
|
||||
|
||||
if (this.validateConfigAttributes) {
|
||||
Collection<ConfigAttribute> attributeDefs = this
|
||||
.obtainSecurityMetadataSource().getAllConfigAttributes();
|
||||
Collection<ConfigAttribute> attributeDefs = this.obtainSecurityMetadataSource().getAllConfigAttributes();
|
||||
|
||||
if (attributeDefs == null) {
|
||||
logger.warn("Could not validate configuration attributes as the SecurityMetadataSource did not return "
|
||||
@@ -164,17 +166,14 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean,
|
||||
Set<ConfigAttribute> unsupportedAttrs = new HashSet<>();
|
||||
|
||||
for (ConfigAttribute attr : attributeDefs) {
|
||||
if (!this.runAsManager.supports(attr)
|
||||
&& !this.accessDecisionManager.supports(attr)
|
||||
&& ((this.afterInvocationManager == null) || !this.afterInvocationManager
|
||||
.supports(attr))) {
|
||||
if (!this.runAsManager.supports(attr) && !this.accessDecisionManager.supports(attr)
|
||||
&& ((this.afterInvocationManager == null) || !this.afterInvocationManager.supports(attr))) {
|
||||
unsupportedAttrs.add(attr);
|
||||
}
|
||||
}
|
||||
|
||||
if (unsupportedAttrs.size() != 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"Unsupported configuration attributes: " + unsupportedAttrs);
|
||||
throw new IllegalArgumentException("Unsupported configuration attributes: " + unsupportedAttrs);
|
||||
}
|
||||
|
||||
logger.debug("Validated configuration attributes");
|
||||
@@ -186,24 +185,19 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean,
|
||||
final boolean debug = logger.isDebugEnabled();
|
||||
|
||||
if (!getSecureObjectClass().isAssignableFrom(object.getClass())) {
|
||||
throw new IllegalArgumentException(
|
||||
"Security invocation attempted for object "
|
||||
+ object.getClass().getName()
|
||||
+ " but AbstractSecurityInterceptor only configured to support secure objects of type: "
|
||||
+ getSecureObjectClass());
|
||||
throw new IllegalArgumentException("Security invocation attempted for object " + object.getClass().getName()
|
||||
+ " but AbstractSecurityInterceptor only configured to support secure objects of type: "
|
||||
+ getSecureObjectClass());
|
||||
}
|
||||
|
||||
Collection<ConfigAttribute> attributes = this.obtainSecurityMetadataSource()
|
||||
.getAttributes(object);
|
||||
Collection<ConfigAttribute> attributes = this.obtainSecurityMetadataSource().getAttributes(object);
|
||||
|
||||
if (attributes == null || attributes.isEmpty()) {
|
||||
if (rejectPublicInvocations) {
|
||||
throw new IllegalArgumentException(
|
||||
"Secure object invocation "
|
||||
+ object
|
||||
+ " was denied as public invocations are not allowed via this interceptor. "
|
||||
+ "This indicates a configuration error because the "
|
||||
+ "rejectPublicInvocations property is set to 'true'");
|
||||
throw new IllegalArgumentException("Secure object invocation " + object
|
||||
+ " was denied as public invocations are not allowed via this interceptor. "
|
||||
+ "This indicates a configuration error because the "
|
||||
+ "rejectPublicInvocations property is set to 'true'");
|
||||
}
|
||||
|
||||
if (debug) {
|
||||
@@ -220,10 +214,8 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean,
|
||||
}
|
||||
|
||||
if (SecurityContextHolder.getContext().getAuthentication() == null) {
|
||||
credentialsNotFound(messages.getMessage(
|
||||
"AbstractSecurityInterceptor.authenticationNotFound",
|
||||
"An Authentication object was not found in the SecurityContext"),
|
||||
object, attributes);
|
||||
credentialsNotFound(messages.getMessage("AbstractSecurityInterceptor.authenticationNotFound",
|
||||
"An Authentication object was not found in the SecurityContext"), object, attributes);
|
||||
}
|
||||
|
||||
Authentication authenticated = authenticateIfRequired();
|
||||
@@ -233,8 +225,7 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean,
|
||||
this.accessDecisionManager.decide(authenticated, object, attributes);
|
||||
}
|
||||
catch (AccessDeniedException accessDeniedException) {
|
||||
publishEvent(new AuthorizationFailureEvent(object, attributes, authenticated,
|
||||
accessDeniedException));
|
||||
publishEvent(new AuthorizationFailureEvent(object, attributes, authenticated, accessDeniedException));
|
||||
|
||||
throw accessDeniedException;
|
||||
}
|
||||
@@ -248,8 +239,7 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean,
|
||||
}
|
||||
|
||||
// Attempt to run as a different user
|
||||
Authentication runAs = this.runAsManager.buildRunAs(authenticated, object,
|
||||
attributes);
|
||||
Authentication runAs = this.runAsManager.buildRunAs(authenticated, object, attributes);
|
||||
|
||||
if (runAs == null) {
|
||||
if (debug) {
|
||||
@@ -257,8 +247,7 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean,
|
||||
}
|
||||
|
||||
// no further work post-invocation
|
||||
return new InterceptorStatusToken(SecurityContextHolder.getContext(), false,
|
||||
attributes, object);
|
||||
return new InterceptorStatusToken(SecurityContextHolder.getContext(), false, attributes, object);
|
||||
}
|
||||
else {
|
||||
if (debug) {
|
||||
@@ -279,14 +268,12 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean,
|
||||
* object invocation has been completed. This method should be invoked after the
|
||||
* secure object invocation and before afterInvocation regardless of the secure object
|
||||
* invocation returning successfully (i.e. it should be done in a finally block).
|
||||
*
|
||||
* @param token as returned by the {@link #beforeInvocation(Object)} method
|
||||
*/
|
||||
protected void finallyInvocation(InterceptorStatusToken token) {
|
||||
if (token != null && token.isContextHolderRefreshRequired()) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Reverting to original Authentication: "
|
||||
+ token.getSecurityContext().getAuthentication());
|
||||
logger.debug("Reverting to original Authentication: " + token.getSecurityContext().getAuthentication());
|
||||
}
|
||||
|
||||
SecurityContextHolder.setContext(token.getSecurityContext());
|
||||
@@ -296,7 +283,6 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean,
|
||||
/**
|
||||
* Completes the work of the <tt>AbstractSecurityInterceptor</tt> after the secure
|
||||
* object invocation has been completed.
|
||||
*
|
||||
* @param token as returned by the {@link #beforeInvocation(Object)} method
|
||||
* @param returnedObject any object returned from the secure object invocation (may be
|
||||
* <tt>null</tt>)
|
||||
@@ -314,15 +300,12 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean,
|
||||
if (afterInvocationManager != null) {
|
||||
// Attempt after invocation handling
|
||||
try {
|
||||
returnedObject = afterInvocationManager.decide(token.getSecurityContext()
|
||||
.getAuthentication(), token.getSecureObject(), token
|
||||
.getAttributes(), returnedObject);
|
||||
returnedObject = afterInvocationManager.decide(token.getSecurityContext().getAuthentication(),
|
||||
token.getSecureObject(), token.getAttributes(), returnedObject);
|
||||
}
|
||||
catch (AccessDeniedException accessDeniedException) {
|
||||
AuthorizationFailureEvent event = new AuthorizationFailureEvent(
|
||||
token.getSecureObject(), token.getAttributes(), token
|
||||
.getSecurityContext().getAuthentication(),
|
||||
accessDeniedException);
|
||||
AuthorizationFailureEvent event = new AuthorizationFailureEvent(token.getSecureObject(),
|
||||
token.getAttributes(), token.getSecurityContext().getAuthentication(), accessDeniedException);
|
||||
publishEvent(event);
|
||||
|
||||
throw accessDeniedException;
|
||||
@@ -336,12 +319,10 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean,
|
||||
* Checks the current authentication token and passes it to the AuthenticationManager
|
||||
* if {@link org.springframework.security.core.Authentication#isAuthenticated()}
|
||||
* returns false or the property <tt>alwaysReauthenticate</tt> has been set to true.
|
||||
*
|
||||
* @return an authenticated <tt>Authentication</tt> object.
|
||||
*/
|
||||
private Authentication authenticateIfRequired() {
|
||||
Authentication authentication = SecurityContextHolder.getContext()
|
||||
.getAuthentication();
|
||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
|
||||
if (authentication.isAuthenticated() && !alwaysReauthenticate) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
@@ -369,18 +350,15 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean,
|
||||
* publishes an event to the application context.
|
||||
* <p>
|
||||
* Always throws an exception.
|
||||
*
|
||||
* @param reason to be provided in the exception detail
|
||||
* @param secureObject that was being called
|
||||
* @param configAttribs that were defined for the secureObject
|
||||
*/
|
||||
private void credentialsNotFound(String reason, Object secureObject,
|
||||
Collection<ConfigAttribute> configAttribs) {
|
||||
AuthenticationCredentialsNotFoundException exception = new AuthenticationCredentialsNotFoundException(
|
||||
reason);
|
||||
private void credentialsNotFound(String reason, Object secureObject, Collection<ConfigAttribute> configAttribs) {
|
||||
AuthenticationCredentialsNotFoundException exception = new AuthenticationCredentialsNotFoundException(reason);
|
||||
|
||||
AuthenticationCredentialsNotFoundEvent event = new AuthenticationCredentialsNotFoundEvent(
|
||||
secureObject, configAttribs, exception);
|
||||
AuthenticationCredentialsNotFoundEvent event = new AuthenticationCredentialsNotFoundEvent(secureObject,
|
||||
configAttribs, exception);
|
||||
publishEvent(event);
|
||||
|
||||
throw exception;
|
||||
@@ -406,7 +384,6 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean,
|
||||
* Indicates the type of secure objects the subclass will be presenting to the
|
||||
* abstract parent for processing. This is used to ensure collaborators wired to the
|
||||
* {@code AbstractSecurityInterceptor} all support the indicated secure object class.
|
||||
*
|
||||
* @return the type of secure object the subclass provides services for
|
||||
*/
|
||||
public abstract Class<?> getSecureObjectClass();
|
||||
@@ -439,7 +416,6 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean,
|
||||
* meaning by default the <code>Authentication.isAuthenticated()</code> property is
|
||||
* trusted and re-authentication will not occur if the principal has already been
|
||||
* authenticated.
|
||||
*
|
||||
* @param alwaysReauthenticate <code>true</code> to force
|
||||
* <code>AbstractSecurityInterceptor</code> to disregard the value of
|
||||
* <code>Authentication.isAuthenticated()</code> and always re-authenticate the
|
||||
@@ -449,8 +425,7 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean,
|
||||
this.alwaysReauthenticate = alwaysReauthenticate;
|
||||
}
|
||||
|
||||
public void setApplicationEventPublisher(
|
||||
ApplicationEventPublisher applicationEventPublisher) {
|
||||
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
|
||||
this.eventPublisher = applicationEventPublisher;
|
||||
}
|
||||
|
||||
@@ -465,7 +440,6 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean,
|
||||
/**
|
||||
* Only {@code AuthorizationFailureEvent} will be published. If you set this property
|
||||
* to {@code true}, {@code AuthorizedEvent}s will also be published.
|
||||
*
|
||||
* @param publishAuthorizationSuccess default value is {@code false}
|
||||
*/
|
||||
public void setPublishAuthorizationSuccess(boolean publishAuthorizationSuccess) {
|
||||
@@ -481,7 +455,6 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean,
|
||||
* <tt>IllegalArgumentException</tt> will be thrown by the
|
||||
* <tt>AbstractSecurityInterceptor</tt> if you set this property to <tt>true</tt> and
|
||||
* an attempt is made to invoke a secure object that has no configuration attributes.
|
||||
*
|
||||
* @param rejectPublicInvocations set to <code>true</code> to reject invocations of
|
||||
* secure objects that have no configuration attributes (by default it is
|
||||
* <code>false</code> which treats undeclared secure objects as "public" or
|
||||
@@ -507,10 +480,10 @@ public abstract class AbstractSecurityInterceptor implements InitializingBean,
|
||||
|
||||
private static class NoOpAuthenticationManager implements AuthenticationManager {
|
||||
|
||||
public Authentication authenticate(Authentication authentication)
|
||||
throws AuthenticationException {
|
||||
throw new AuthenticationServiceException("Cannot authenticate "
|
||||
+ authentication);
|
||||
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
||||
throw new AuthenticationServiceException("Cannot authenticate " + authentication);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+4
-10
@@ -43,6 +43,7 @@ import org.springframework.security.core.Authentication;
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public interface AfterInvocationManager {
|
||||
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
@@ -50,24 +51,20 @@ public interface AfterInvocationManager {
|
||||
* Given the details of a secure object invocation including its returned
|
||||
* <code>Object</code>, make an access control decision or optionally modify the
|
||||
* returned <code>Object</code>.
|
||||
*
|
||||
* @param authentication the caller that invoked the method
|
||||
* @param object the secured object that was called
|
||||
* @param attributes the configuration attributes associated with the secured object
|
||||
* that was invoked
|
||||
* @param returnedObject the <code>Object</code> that was returned from the secure
|
||||
* object invocation
|
||||
*
|
||||
* @return the <code>Object</code> that will ultimately be returned to the caller (if
|
||||
* an implementation does not wish to modify the object to be returned to the caller,
|
||||
* the implementation should simply return the same object it was passed by the
|
||||
* <code>returnedObject</code> method argument)
|
||||
*
|
||||
* @throws AccessDeniedException if access is denied
|
||||
*/
|
||||
Object decide(Authentication authentication, Object object,
|
||||
Collection<ConfigAttribute> attributes, Object returnedObject)
|
||||
throws AccessDeniedException;
|
||||
Object decide(Authentication authentication, Object object, Collection<ConfigAttribute> attributes,
|
||||
Object returnedObject) throws AccessDeniedException;
|
||||
|
||||
/**
|
||||
* Indicates whether this <code>AfterInvocationManager</code> is able to process
|
||||
@@ -78,10 +75,8 @@ public interface AfterInvocationManager {
|
||||
* <code>AccessDecisionManager</code> and/or <code>RunAsManager</code> and/or
|
||||
* <code>AfterInvocationManager</code>.
|
||||
* </p>
|
||||
*
|
||||
* @param attribute a configuration attribute that has been configured against the
|
||||
* <code>AbstractSecurityInterceptor</code>
|
||||
*
|
||||
* @return true if this <code>AfterInvocationManager</code> can support the passed
|
||||
* configuration attribute
|
||||
*/
|
||||
@@ -90,10 +85,9 @@ public interface AfterInvocationManager {
|
||||
/**
|
||||
* Indicates whether the <code>AfterInvocationManager</code> implementation is able to
|
||||
* provide access control decisions for the indicated secured object type.
|
||||
*
|
||||
* @param clazz the class that is being queried
|
||||
*
|
||||
* @return <code>true</code> if the implementation can process the indicated class
|
||||
*/
|
||||
boolean supports(Class<?> clazz);
|
||||
|
||||
}
|
||||
|
||||
+9
-14
@@ -45,13 +45,12 @@ import org.springframework.util.Assert;
|
||||
*
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public class AfterInvocationProviderManager implements AfterInvocationManager,
|
||||
InitializingBean {
|
||||
public class AfterInvocationProviderManager implements AfterInvocationManager, InitializingBean {
|
||||
|
||||
// ~ Static fields/initializers
|
||||
// =====================================================================================
|
||||
|
||||
protected static final Log logger = LogFactory
|
||||
.getLog(AfterInvocationProviderManager.class);
|
||||
protected static final Log logger = LogFactory.getLog(AfterInvocationProviderManager.class);
|
||||
|
||||
// ~ Instance fields
|
||||
// ================================================================================================
|
||||
@@ -67,14 +66,12 @@ public class AfterInvocationProviderManager implements AfterInvocationManager,
|
||||
|
||||
private void checkIfValidList(List<?> listToCheck) {
|
||||
if ((listToCheck == null) || (listToCheck.size() == 0)) {
|
||||
throw new IllegalArgumentException(
|
||||
"A list of AfterInvocationProviders is required");
|
||||
throw new IllegalArgumentException("A list of AfterInvocationProviders is required");
|
||||
}
|
||||
}
|
||||
|
||||
public Object decide(Authentication authentication, Object object,
|
||||
Collection<ConfigAttribute> config, Object returnedObject)
|
||||
throws AccessDeniedException {
|
||||
public Object decide(Authentication authentication, Object object, Collection<ConfigAttribute> config,
|
||||
Object returnedObject) throws AccessDeniedException {
|
||||
|
||||
Object result = returnedObject;
|
||||
|
||||
@@ -94,9 +91,8 @@ public class AfterInvocationProviderManager implements AfterInvocationManager,
|
||||
providers = new ArrayList<>(newList.size());
|
||||
|
||||
for (Object currentObject : newList) {
|
||||
Assert.isInstanceOf(AfterInvocationProvider.class, currentObject,
|
||||
() -> "AfterInvocationProvider " + currentObject.getClass().getName()
|
||||
+ " must implement AfterInvocationProvider");
|
||||
Assert.isInstanceOf(AfterInvocationProvider.class, currentObject, () -> "AfterInvocationProvider "
|
||||
+ currentObject.getClass().getName() + " must implement AfterInvocationProvider");
|
||||
providers.add((AfterInvocationProvider) currentObject);
|
||||
}
|
||||
}
|
||||
@@ -121,9 +117,7 @@ public class AfterInvocationProviderManager implements AfterInvocationManager,
|
||||
* <p>
|
||||
* If one or more providers cannot support the presented class, <code>false</code> is
|
||||
* returned.
|
||||
*
|
||||
* @param clazz the secure object class being queries
|
||||
*
|
||||
* @return if the <code>AfterInvocationProviderManager</code> can support the secure
|
||||
* object class, which requires every one of its <code>AfterInvocationProvider</code>s
|
||||
* to support the secure object class
|
||||
@@ -137,4 +131,5 @@ public class AfterInvocationProviderManager implements AfterInvocationManager,
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+7
-3
@@ -31,20 +31,23 @@ import org.springframework.security.core.context.SecurityContext;
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public class InterceptorStatusToken {
|
||||
|
||||
// ~ Instance fields
|
||||
// ================================================================================================
|
||||
|
||||
private SecurityContext securityContext;
|
||||
|
||||
private Collection<ConfigAttribute> attr;
|
||||
|
||||
private Object secureObject;
|
||||
|
||||
private boolean contextHolderRefreshRequired;
|
||||
|
||||
// ~ Constructors
|
||||
// ===================================================================================================
|
||||
|
||||
public InterceptorStatusToken(SecurityContext securityContext,
|
||||
boolean contextHolderRefreshRequired, Collection<ConfigAttribute> attributes,
|
||||
Object secureObject) {
|
||||
public InterceptorStatusToken(SecurityContext securityContext, boolean contextHolderRefreshRequired,
|
||||
Collection<ConfigAttribute> attributes, Object secureObject) {
|
||||
this.securityContext = securityContext;
|
||||
this.contextHolderRefreshRequired = contextHolderRefreshRequired;
|
||||
this.attr = attributes;
|
||||
@@ -69,4 +72,5 @@ public class InterceptorStatusToken {
|
||||
public boolean isContextHolderRefreshRequired() {
|
||||
return contextHolderRefreshRequired;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+8
-12
@@ -43,11 +43,11 @@ import org.springframework.util.Assert;
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public class MethodInvocationPrivilegeEvaluator implements InitializingBean {
|
||||
|
||||
// ~ Static fields/initializers
|
||||
// =====================================================================================
|
||||
|
||||
protected static final Log logger = LogFactory
|
||||
.getLog(MethodInvocationPrivilegeEvaluator.class);
|
||||
protected static final Log logger = LogFactory.getLog(MethodInvocationPrivilegeEvaluator.class);
|
||||
|
||||
// ~ Instance fields
|
||||
// ================================================================================================
|
||||
@@ -63,11 +63,9 @@ public class MethodInvocationPrivilegeEvaluator implements InitializingBean {
|
||||
|
||||
public boolean isAllowed(MethodInvocation mi, Authentication authentication) {
|
||||
Assert.notNull(mi, "MethodInvocation required");
|
||||
Assert.notNull(mi.getMethod(),
|
||||
"MethodInvocation must provide a non-null getMethod()");
|
||||
Assert.notNull(mi.getMethod(), "MethodInvocation must provide a non-null getMethod()");
|
||||
|
||||
Collection<ConfigAttribute> attrs = securityInterceptor
|
||||
.obtainSecurityMetadataSource().getAttributes(mi);
|
||||
Collection<ConfigAttribute> attrs = securityInterceptor.obtainSecurityMetadataSource().getAttributes(mi);
|
||||
|
||||
if (attrs == null) {
|
||||
if (securityInterceptor.isRejectPublicInvocations()) {
|
||||
@@ -82,13 +80,11 @@ public class MethodInvocationPrivilegeEvaluator implements InitializingBean {
|
||||
}
|
||||
|
||||
try {
|
||||
securityInterceptor.getAccessDecisionManager().decide(authentication, mi,
|
||||
attrs);
|
||||
securityInterceptor.getAccessDecisionManager().decide(authentication, mi, attrs);
|
||||
}
|
||||
catch (AccessDeniedException unauthorized) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(mi.toString() + " denied for " + authentication.toString(),
|
||||
unauthorized);
|
||||
logger.debug(mi.toString() + " denied for " + authentication.toString(), unauthorized);
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -99,11 +95,11 @@ public class MethodInvocationPrivilegeEvaluator implements InitializingBean {
|
||||
|
||||
public void setSecurityInterceptor(AbstractSecurityInterceptor securityInterceptor) {
|
||||
Assert.notNull(securityInterceptor, "AbstractSecurityInterceptor cannot be null");
|
||||
Assert.isTrue(
|
||||
MethodInvocation.class.equals(securityInterceptor.getSecureObjectClass()),
|
||||
Assert.isTrue(MethodInvocation.class.equals(securityInterceptor.getSecureObjectClass()),
|
||||
"AbstractSecurityInterceptor does not support MethodInvocations");
|
||||
Assert.notNull(securityInterceptor.getAccessDecisionManager(),
|
||||
"AbstractSecurityInterceptor must provide a non-null AccessDecisionManager");
|
||||
this.securityInterceptor = securityInterceptor;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+3
-2
@@ -30,11 +30,11 @@ import org.springframework.security.core.Authentication;
|
||||
* @author Ben Alex
|
||||
*/
|
||||
final class NullRunAsManager implements RunAsManager {
|
||||
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
public Authentication buildRunAs(Authentication authentication, Object object,
|
||||
Collection<ConfigAttribute> config) {
|
||||
public Authentication buildRunAs(Authentication authentication, Object object, Collection<ConfigAttribute> config) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -45,4 +45,5 @@ final class NullRunAsManager implements RunAsManager {
|
||||
public boolean supports(Class<?> clazz) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+7
-8
@@ -43,32 +43,30 @@ import org.springframework.util.Assert;
|
||||
* If the key does not match, a <code>BadCredentialsException</code> is thrown.
|
||||
* </p>
|
||||
*/
|
||||
public class RunAsImplAuthenticationProvider implements InitializingBean,
|
||||
AuthenticationProvider, MessageSourceAware {
|
||||
public class RunAsImplAuthenticationProvider implements InitializingBean, AuthenticationProvider, MessageSourceAware {
|
||||
|
||||
// ~ Instance fields
|
||||
// ================================================================================================
|
||||
|
||||
protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
|
||||
|
||||
private String key;
|
||||
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
public void afterPropertiesSet() {
|
||||
Assert.notNull(key,
|
||||
"A Key is required and should match that configured for the RunAsManagerImpl");
|
||||
Assert.notNull(key, "A Key is required and should match that configured for the RunAsManagerImpl");
|
||||
}
|
||||
|
||||
public Authentication authenticate(Authentication authentication)
|
||||
throws AuthenticationException {
|
||||
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
||||
RunAsUserToken token = (RunAsUserToken) authentication;
|
||||
|
||||
if (token.getKeyHash() == key.hashCode()) {
|
||||
return authentication;
|
||||
}
|
||||
else {
|
||||
throw new BadCredentialsException(messages.getMessage(
|
||||
"RunAsImplAuthenticationProvider.incorrectKey",
|
||||
throw new BadCredentialsException(messages.getMessage("RunAsImplAuthenticationProvider.incorrectKey",
|
||||
"The presented RunAsUserToken does not contain the expected key"));
|
||||
}
|
||||
}
|
||||
@@ -88,4 +86,5 @@ public class RunAsImplAuthenticationProvider implements InitializingBean,
|
||||
public boolean supports(Class<?> authentication) {
|
||||
return RunAsUserToken.class.isAssignableFrom(authentication);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -59,24 +59,22 @@ import org.springframework.security.core.Authentication;
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public interface RunAsManager {
|
||||
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
/**
|
||||
* Returns a replacement <code>Authentication</code> object for the current secure
|
||||
* object invocation, or <code>null</code> if replacement not required.
|
||||
*
|
||||
* @param authentication the caller invoking the secure object
|
||||
* @param object the secured object being called
|
||||
* @param attributes the configuration attributes associated with the secure object
|
||||
* being invoked
|
||||
*
|
||||
* @return a replacement object to be used for duration of the secure object
|
||||
* invocation, or <code>null</code> if the <code>Authentication</code> should be left
|
||||
* as is
|
||||
*/
|
||||
Authentication buildRunAs(Authentication authentication, Object object,
|
||||
Collection<ConfigAttribute> attributes);
|
||||
Authentication buildRunAs(Authentication authentication, Object object, Collection<ConfigAttribute> attributes);
|
||||
|
||||
/**
|
||||
* Indicates whether this <code>RunAsManager</code> is able to process the passed
|
||||
@@ -87,10 +85,8 @@ public interface RunAsManager {
|
||||
* <code>AccessDecisionManager</code> and/or <code>RunAsManager</code> and/or
|
||||
* <code>AfterInvocationManager</code>.
|
||||
* </p>
|
||||
*
|
||||
* @param attribute a configuration attribute that has been configured against the
|
||||
* <code>AbstractSecurityInterceptor</code>
|
||||
*
|
||||
* @return <code>true</code> if this <code>RunAsManager</code> can support the passed
|
||||
* configuration attribute
|
||||
*/
|
||||
@@ -99,10 +95,9 @@ public interface RunAsManager {
|
||||
/**
|
||||
* Indicates whether the <code>RunAsManager</code> implementation is able to provide
|
||||
* run-as replacement for the indicated secure object type.
|
||||
*
|
||||
* @param clazz the class that is being queried
|
||||
*
|
||||
* @return true if the implementation can process the indicated class
|
||||
*/
|
||||
boolean supports(Class<?> clazz);
|
||||
|
||||
}
|
||||
|
||||
+7
-10
@@ -54,18 +54,19 @@ import org.springframework.util.Assert;
|
||||
* @author colin sampaleanu
|
||||
*/
|
||||
public class RunAsManagerImpl implements RunAsManager, InitializingBean {
|
||||
|
||||
// ~ Instance fields
|
||||
// ================================================================================================
|
||||
|
||||
private String key;
|
||||
|
||||
private String rolePrefix = "ROLE_";
|
||||
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
public void afterPropertiesSet() {
|
||||
Assert.notNull(
|
||||
key,
|
||||
Assert.notNull(key,
|
||||
"A Key is required and should match that configured for the RunAsImplAuthenticationProvider");
|
||||
}
|
||||
|
||||
@@ -88,9 +89,8 @@ public class RunAsManagerImpl implements RunAsManager, InitializingBean {
|
||||
// Add existing authorities
|
||||
newAuthorities.addAll(authentication.getAuthorities());
|
||||
|
||||
return new RunAsUserToken(this.key, authentication.getPrincipal(),
|
||||
authentication.getCredentials(), newAuthorities,
|
||||
authentication.getClass());
|
||||
return new RunAsUserToken(this.key, authentication.getPrincipal(), authentication.getCredentials(),
|
||||
newAuthorities, authentication.getClass());
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
@@ -108,7 +108,6 @@ public class RunAsManagerImpl implements RunAsManager, InitializingBean {
|
||||
/**
|
||||
* Allows the default role prefix of <code>ROLE_</code> to be overridden. May be set
|
||||
* to an empty value, although this is usually not desirable.
|
||||
*
|
||||
* @param rolePrefix the new prefix
|
||||
*/
|
||||
public void setRolePrefix(String rolePrefix) {
|
||||
@@ -116,19 +115,17 @@ public class RunAsManagerImpl implements RunAsManager, InitializingBean {
|
||||
}
|
||||
|
||||
public boolean supports(ConfigAttribute attribute) {
|
||||
return attribute.getAttribute() != null
|
||||
&& attribute.getAttribute().startsWith("RUN_AS_");
|
||||
return attribute.getAttribute() != null && attribute.getAttribute().startsWith("RUN_AS_");
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation supports any type of class, because it does not query the
|
||||
* presented secure object.
|
||||
*
|
||||
* @param clazz the secure object
|
||||
*
|
||||
* @return always <code>true</code>
|
||||
*/
|
||||
public boolean supports(Class<?> clazz) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+5
-2
@@ -37,8 +37,11 @@ public class RunAsUserToken extends AbstractAuthenticationToken {
|
||||
// ================================================================================================
|
||||
|
||||
private final Class<? extends Authentication> originalAuthentication;
|
||||
|
||||
private final Object credentials;
|
||||
|
||||
private final Object principal;
|
||||
|
||||
private final int keyHash;
|
||||
|
||||
// ~ Constructors
|
||||
@@ -79,10 +82,10 @@ public class RunAsUserToken extends AbstractAuthenticationToken {
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder(super.toString());
|
||||
String className = this.originalAuthentication == null ? null
|
||||
: this.originalAuthentication.getName();
|
||||
String className = this.originalAuthentication == null ? null : this.originalAuthentication.getName();
|
||||
sb.append("; Original Class: ").append(className);
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+3
-5
@@ -37,8 +37,8 @@ import org.aopalliance.intercept.MethodInvocation;
|
||||
* @author Ben Alex
|
||||
* @author Rob Winch
|
||||
*/
|
||||
public class MethodSecurityInterceptor extends AbstractSecurityInterceptor implements
|
||||
MethodInterceptor {
|
||||
public class MethodSecurityInterceptor extends AbstractSecurityInterceptor implements MethodInterceptor {
|
||||
|
||||
// ~ Instance fields
|
||||
// ================================================================================================
|
||||
|
||||
@@ -53,12 +53,9 @@ public class MethodSecurityInterceptor extends AbstractSecurityInterceptor imple
|
||||
|
||||
/**
|
||||
* This method should be used to enforce security on a <code>MethodInvocation</code>.
|
||||
*
|
||||
* @param mi The method being invoked which requires a security decision
|
||||
*
|
||||
* @return The returned value from the method invocation (possibly modified by the
|
||||
* {@code AfterInvocationManager}).
|
||||
*
|
||||
* @throws Throwable if any error occurs
|
||||
*/
|
||||
public Object invoke(MethodInvocation mi) throws Throwable {
|
||||
@@ -85,4 +82,5 @@ public class MethodSecurityInterceptor extends AbstractSecurityInterceptor imple
|
||||
public void setSecurityMetadataSource(MethodSecurityMetadataSource newSource) {
|
||||
this.securityMetadataSource = newSource;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+22
-21
@@ -38,8 +38,8 @@ import org.springframework.util.Assert;
|
||||
* {@link MethodInterceptor} from public (non-secure) methods.
|
||||
* <p>
|
||||
* Because the AOP framework caches advice calculations, this is normally faster than just
|
||||
* letting the <code>MethodInterceptor</code> run and find out itself that it has
|
||||
* no work to do.
|
||||
* letting the <code>MethodInterceptor</code> run and find out itself that it has no work
|
||||
* to do.
|
||||
* <p>
|
||||
* This class also allows the use of Spring's {@code DefaultAdvisorAutoProxyCreator},
|
||||
* which makes configuration easier than setup a <code>ProxyFactoryBean</code> for each
|
||||
@@ -51,17 +51,23 @@ import org.springframework.util.Assert;
|
||||
* @author Ben Alex
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public class MethodSecurityMetadataSourceAdvisor extends AbstractPointcutAdvisor
|
||||
implements BeanFactoryAware {
|
||||
public class MethodSecurityMetadataSourceAdvisor extends AbstractPointcutAdvisor implements BeanFactoryAware {
|
||||
|
||||
// ~ Instance fields
|
||||
// ================================================================================================
|
||||
|
||||
private transient MethodSecurityMetadataSource attributeSource;
|
||||
|
||||
private transient MethodInterceptor interceptor;
|
||||
|
||||
private final Pointcut pointcut = new MethodSecurityMetadataSourcePointcut();
|
||||
|
||||
private BeanFactory beanFactory;
|
||||
|
||||
private final String adviceBeanName;
|
||||
|
||||
private final String metadataSourceBeanName;
|
||||
|
||||
private transient volatile Object adviceMonitor = new Object();
|
||||
|
||||
// ~ Constructors
|
||||
@@ -73,19 +79,17 @@ public class MethodSecurityMetadataSourceAdvisor extends AbstractPointcutAdvisor
|
||||
* instantiation of the interceptor (and hence the AuthenticationManager). See
|
||||
* SEC-773, for example. The metadataSourceBeanName is used rather than a direct
|
||||
* reference to support serialization via a bean factory lookup.
|
||||
*
|
||||
* @param adviceBeanName name of the MethodSecurityInterceptor bean
|
||||
* @param attributeSource the SecurityMetadataSource (should be the same as the one
|
||||
* used on the interceptor)
|
||||
* @param attributeSourceBeanName the bean name of the attributeSource (required for
|
||||
* serialization)
|
||||
*/
|
||||
public MethodSecurityMetadataSourceAdvisor(String adviceBeanName,
|
||||
MethodSecurityMetadataSource attributeSource, String attributeSourceBeanName) {
|
||||
public MethodSecurityMetadataSourceAdvisor(String adviceBeanName, MethodSecurityMetadataSource attributeSource,
|
||||
String attributeSourceBeanName) {
|
||||
Assert.notNull(adviceBeanName, "The adviceBeanName cannot be null");
|
||||
Assert.notNull(attributeSource, "The attributeSource cannot be null");
|
||||
Assert.notNull(attributeSourceBeanName,
|
||||
"The attributeSourceBeanName cannot be null");
|
||||
Assert.notNull(attributeSourceBeanName, "The attributeSourceBeanName cannot be null");
|
||||
|
||||
this.adviceBeanName = adviceBeanName;
|
||||
this.attributeSource = attributeSource;
|
||||
@@ -102,12 +106,9 @@ public class MethodSecurityMetadataSourceAdvisor extends AbstractPointcutAdvisor
|
||||
public Advice getAdvice() {
|
||||
synchronized (this.adviceMonitor) {
|
||||
if (interceptor == null) {
|
||||
Assert.notNull(adviceBeanName,
|
||||
"'adviceBeanName' must be set for use with bean factory lookup.");
|
||||
Assert.state(beanFactory != null,
|
||||
"BeanFactory must be set to resolve 'adviceBeanName'");
|
||||
interceptor = beanFactory.getBean(this.adviceBeanName,
|
||||
MethodInterceptor.class);
|
||||
Assert.notNull(adviceBeanName, "'adviceBeanName' must be set for use with bean factory lookup.");
|
||||
Assert.state(beanFactory != null, "BeanFactory must be set to resolve 'adviceBeanName'");
|
||||
interceptor = beanFactory.getBean(this.adviceBeanName, MethodInterceptor.class);
|
||||
}
|
||||
return interceptor;
|
||||
}
|
||||
@@ -117,23 +118,23 @@ public class MethodSecurityMetadataSourceAdvisor extends AbstractPointcutAdvisor
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream ois) throws IOException,
|
||||
ClassNotFoundException {
|
||||
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
|
||||
ois.defaultReadObject();
|
||||
adviceMonitor = new Object();
|
||||
attributeSource = beanFactory.getBean(metadataSourceBeanName,
|
||||
MethodSecurityMetadataSource.class);
|
||||
attributeSource = beanFactory.getBean(metadataSourceBeanName, MethodSecurityMetadataSource.class);
|
||||
}
|
||||
|
||||
// ~ Inner Classes
|
||||
// ==================================================================================================
|
||||
|
||||
class MethodSecurityMetadataSourcePointcut extends StaticMethodMatcherPointcut
|
||||
implements Serializable {
|
||||
class MethodSecurityMetadataSourcePointcut extends StaticMethodMatcherPointcut implements Serializable {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public boolean matches(Method m, Class targetClass) {
|
||||
Collection attributes = attributeSource.getAttributes(m, targetClass);
|
||||
return attributes != null && !attributes.isEmpty();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-2
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
/**
|
||||
* Enforces security for AOP Alliance <code>MethodInvocation</code>s, such as via Spring AOP.
|
||||
* Enforces security for AOP Alliance <code>MethodInvocation</code>s, such as via Spring
|
||||
* AOP.
|
||||
*/
|
||||
package org.springframework.security.access.intercept.aopalliance;
|
||||
|
||||
|
||||
+2
@@ -24,8 +24,10 @@ package org.springframework.security.access.intercept.aspectj;
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public interface AspectJCallback {
|
||||
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
Object proceedWithObject();
|
||||
|
||||
}
|
||||
|
||||
+2
-5
@@ -36,7 +36,6 @@ public final class AspectJMethodSecurityInterceptor extends MethodSecurityInterc
|
||||
|
||||
/**
|
||||
* Method that is suitable for user with @Aspect notation.
|
||||
*
|
||||
* @param jp The AspectJ joint point being invoked which requires a security decision
|
||||
* @return The returned value from the method invocation
|
||||
* @throws Throwable if the invocation throws one
|
||||
@@ -47,16 +46,13 @@ public final class AspectJMethodSecurityInterceptor extends MethodSecurityInterc
|
||||
|
||||
/**
|
||||
* Method that is suitable for user with traditional AspectJ-code aspects.
|
||||
*
|
||||
* @param jp The AspectJ joint point being invoked which requires a security decision
|
||||
* @param advisorProceed the advice-defined anonymous class that implements
|
||||
* {@code AspectJCallback} containing a simple {@code return proceed();} statement
|
||||
*
|
||||
* @return The returned value from the method invocation
|
||||
*/
|
||||
public Object invoke(JoinPoint jp, AspectJCallback advisorProceed) {
|
||||
InterceptorStatusToken token = super
|
||||
.beforeInvocation(new MethodInvocationAdapter(jp));
|
||||
InterceptorStatusToken token = super.beforeInvocation(new MethodInvocationAdapter(jp));
|
||||
|
||||
Object result;
|
||||
try {
|
||||
@@ -68,4 +64,5 @@ public final class AspectJMethodSecurityInterceptor extends MethodSecurityInterc
|
||||
|
||||
return super.afterInvocation(token, result);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+6
-4
@@ -31,8 +31,11 @@ import org.aspectj.lang.reflect.CodeSignature;
|
||||
* @since 3.0.3
|
||||
*/
|
||||
public final class MethodInvocationAdapter implements MethodInvocation {
|
||||
|
||||
private final ProceedingJoinPoint jp;
|
||||
|
||||
private final Method method;
|
||||
|
||||
private final Object target;
|
||||
|
||||
MethodInvocationAdapter(JoinPoint jp) {
|
||||
@@ -45,15 +48,13 @@ public final class MethodInvocationAdapter implements MethodInvocation {
|
||||
target = jp.getSignature().getDeclaringType();
|
||||
}
|
||||
String targetMethodName = jp.getStaticPart().getSignature().getName();
|
||||
Class<?>[] types = ((CodeSignature) jp.getStaticPart().getSignature())
|
||||
.getParameterTypes();
|
||||
Class<?>[] types = ((CodeSignature) jp.getStaticPart().getSignature()).getParameterTypes();
|
||||
Class<?> declaringType = jp.getStaticPart().getSignature().getDeclaringType();
|
||||
|
||||
method = findMethod(targetMethodName, declaringType, types);
|
||||
|
||||
if (method == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Could not obtain target method from JoinPoint: '" + jp + "'");
|
||||
throw new IllegalArgumentException("Could not obtain target method from JoinPoint: '" + jp + "'");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,4 +97,5 @@ public final class MethodInvocationAdapter implements MethodInvocation {
|
||||
public Object proceed() throws Throwable {
|
||||
return jp.proceed();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-2
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
/**
|
||||
* Enforces security for AspectJ <code>JointPoint</code>s, delegating secure object callbacks to the calling aspect.
|
||||
* Enforces security for AspectJ <code>JointPoint</code>s, delegating secure object
|
||||
* callbacks to the calling aspect.
|
||||
*/
|
||||
package org.springframework.security.access.intercept.aspectj;
|
||||
|
||||
|
||||
+14
-16
@@ -17,21 +17,19 @@
|
||||
* Abstract level security interception classes which are responsible for enforcing the
|
||||
* configured security constraints for a secure object.
|
||||
* <p>
|
||||
* A <i>secure object</i> is a term frequently used throughout the security
|
||||
* system. It does <b>not</b> refer to a business object that is being
|
||||
* secured, but instead refers to some infrastructure object that can have
|
||||
* security facilities provided for it by Spring Security.
|
||||
* For example, one secure object would be <code>MethodInvocation</code>,
|
||||
* whilst another would be HTTP
|
||||
* {@code org.springframework.security.web.FilterInvocation}. Note these are
|
||||
* infrastructure objects and their design allows them to represent a large
|
||||
* variety of actual resources that might need to be secured, such as business
|
||||
* objects or HTTP request URLs.
|
||||
* <p>Each secure object typically has its own interceptor package.
|
||||
* Each package usually includes a concrete security interceptor (which subclasses
|
||||
* {@link org.springframework.security.access.intercept.AbstractSecurityInterceptor}) and an
|
||||
* appropriate {@link org.springframework.security.access.SecurityMetadataSource}
|
||||
* for the type of resources the secure object represents.
|
||||
* A <i>secure object</i> is a term frequently used throughout the security system. It
|
||||
* does <b>not</b> refer to a business object that is being secured, but instead refers to
|
||||
* some infrastructure object that can have security facilities provided for it by Spring
|
||||
* Security. For example, one secure object would be <code>MethodInvocation</code>, whilst
|
||||
* another would be HTTP {@code org.springframework.security.web.FilterInvocation}. Note
|
||||
* these are infrastructure objects and their design allows them to represent a large
|
||||
* variety of actual resources that might need to be secured, such as business objects or
|
||||
* HTTP request URLs.
|
||||
* <p>
|
||||
* Each secure object typically has its own interceptor package. Each package usually
|
||||
* includes a concrete security interceptor (which subclasses
|
||||
* {@link org.springframework.security.access.intercept.AbstractSecurityInterceptor}) and
|
||||
* an appropriate {@link org.springframework.security.access.SecurityMetadataSource} for
|
||||
* the type of resources the secure object represents.
|
||||
*/
|
||||
package org.springframework.security.access.intercept;
|
||||
|
||||
|
||||
+2
-6
@@ -42,8 +42,7 @@ import org.springframework.security.access.ConfigAttribute;
|
||||
* @author Luke taylor
|
||||
* @since 2.0
|
||||
*/
|
||||
public abstract class AbstractFallbackMethodSecurityMetadataSource extends
|
||||
AbstractMethodSecurityMetadataSource {
|
||||
public abstract class AbstractFallbackMethodSecurityMetadataSource extends AbstractMethodSecurityMetadataSource {
|
||||
|
||||
public Collection<ConfigAttribute> getAttributes(Method method, Class<?> targetClass) {
|
||||
// The method may be on an interface, but we need attributes from the target
|
||||
@@ -83,13 +82,11 @@ public abstract class AbstractFallbackMethodSecurityMetadataSource extends
|
||||
* may wish to provide advanced capabilities related to method metadata being
|
||||
* "registered" against a method even if the target class does not declare the method
|
||||
* (i.e. the subclass may only inherit the method).
|
||||
*
|
||||
* @param method the method for the current invocation (never <code>null</code>)
|
||||
* @param targetClass the target class for the invocation (may be <code>null</code>)
|
||||
* @return the security metadata (or null if no metadata applies)
|
||||
*/
|
||||
protected abstract Collection<ConfigAttribute> findAttributes(Method method,
|
||||
Class<?> targetClass);
|
||||
protected abstract Collection<ConfigAttribute> findAttributes(Method method, Class<?> targetClass);
|
||||
|
||||
/**
|
||||
* Obtains the security metadata registered against the specified class.
|
||||
@@ -99,7 +96,6 @@ public abstract class AbstractFallbackMethodSecurityMetadataSource extends
|
||||
* should NOT aggregate metadata for each method registered against a class, as the
|
||||
* abstract superclass will separate invoke {@link #findAttributes(Method, Class)} for
|
||||
* individual methods as appropriate.
|
||||
*
|
||||
* @param clazz the target class for the invocation (never <code>null</code>)
|
||||
* @return the security metadata (or null if no metadata applies)
|
||||
*/
|
||||
|
||||
+2
-2
@@ -31,8 +31,7 @@ import org.springframework.security.access.ConfigAttribute;
|
||||
* @author Ben Alex
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public abstract class AbstractMethodSecurityMetadataSource implements
|
||||
MethodSecurityMetadataSource {
|
||||
public abstract class AbstractMethodSecurityMetadataSource implements MethodSecurityMetadataSource {
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
@@ -65,4 +64,5 @@ public abstract class AbstractMethodSecurityMetadataSource implements
|
||||
public final boolean supports(Class<?> clazz) {
|
||||
return (MethodInvocation.class.isAssignableFrom(clazz));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+15
-16
@@ -36,21 +36,19 @@ import org.springframework.util.ObjectUtils;
|
||||
* @author Ben Alex
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public final class DelegatingMethodSecurityMetadataSource extends
|
||||
AbstractMethodSecurityMetadataSource {
|
||||
private final static List<ConfigAttribute> NULL_CONFIG_ATTRIBUTE = Collections
|
||||
.emptyList();
|
||||
public final class DelegatingMethodSecurityMetadataSource extends AbstractMethodSecurityMetadataSource {
|
||||
|
||||
private final static List<ConfigAttribute> NULL_CONFIG_ATTRIBUTE = Collections.emptyList();
|
||||
|
||||
private final List<MethodSecurityMetadataSource> methodSecurityMetadataSources;
|
||||
|
||||
private final Map<DefaultCacheKey, Collection<ConfigAttribute>> attributeCache = new HashMap<>();
|
||||
|
||||
// ~ Constructor
|
||||
// ====================================================================================================
|
||||
|
||||
public DelegatingMethodSecurityMetadataSource(
|
||||
List<MethodSecurityMetadataSource> methodSecurityMetadataSources) {
|
||||
Assert.notNull(methodSecurityMetadataSources,
|
||||
"MethodSecurityMetadataSources cannot be null");
|
||||
public DelegatingMethodSecurityMetadataSource(List<MethodSecurityMetadataSource> methodSecurityMetadataSources) {
|
||||
Assert.notNull(methodSecurityMetadataSources, "MethodSecurityMetadataSources cannot be null");
|
||||
this.methodSecurityMetadataSources = methodSecurityMetadataSources;
|
||||
}
|
||||
|
||||
@@ -83,8 +81,7 @@ public final class DelegatingMethodSecurityMetadataSource extends
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Caching method [" + cacheKey + "] with attributes "
|
||||
+ attributes);
|
||||
logger.debug("Caching method [" + cacheKey + "] with attributes " + attributes);
|
||||
}
|
||||
|
||||
this.attributeCache.put(cacheKey, attributes);
|
||||
@@ -113,7 +110,9 @@ public final class DelegatingMethodSecurityMetadataSource extends
|
||||
// ==================================================================================================
|
||||
|
||||
private static class DefaultCacheKey {
|
||||
|
||||
private final Method method;
|
||||
|
||||
private final Class<?> targetClass;
|
||||
|
||||
DefaultCacheKey(Method method, Class<?> targetClass) {
|
||||
@@ -124,20 +123,20 @@ public final class DelegatingMethodSecurityMetadataSource extends
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
DefaultCacheKey otherKey = (DefaultCacheKey) other;
|
||||
return (this.method.equals(otherKey.method) && ObjectUtils.nullSafeEquals(
|
||||
this.targetClass, otherKey.targetClass));
|
||||
return (this.method.equals(otherKey.method)
|
||||
&& ObjectUtils.nullSafeEquals(this.targetClass, otherKey.targetClass));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.method.hashCode() * 21
|
||||
+ (this.targetClass != null ? this.targetClass.hashCode() : 0);
|
||||
return this.method.hashCode() * 21 + (this.targetClass != null ? this.targetClass.hashCode() : 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CacheKey[" + (targetClass == null ? "-" : targetClass.getName())
|
||||
+ "; " + method + "]";
|
||||
return "CacheKey[" + (targetClass == null ? "-" : targetClass.getName()) + "; " + method + "]";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+24
-46
@@ -42,8 +42,8 @@ import org.springframework.util.ClassUtils;
|
||||
* @author Ben Alex
|
||||
* @since 2.0
|
||||
*/
|
||||
public class MapBasedMethodSecurityMetadataSource extends
|
||||
AbstractFallbackMethodSecurityMetadataSource implements BeanClassLoaderAware {
|
||||
public class MapBasedMethodSecurityMetadataSource extends AbstractFallbackMethodSecurityMetadataSource
|
||||
implements BeanClassLoaderAware {
|
||||
|
||||
// ~ Instance fields
|
||||
// ================================================================================================
|
||||
@@ -65,8 +65,7 @@ public class MapBasedMethodSecurityMetadataSource extends
|
||||
* Creates the <tt>MapBasedMethodSecurityMetadataSource</tt> from a
|
||||
* @param methodMap map of method names to <tt>ConfigAttribute</tt>s.
|
||||
*/
|
||||
public MapBasedMethodSecurityMetadataSource(
|
||||
Map<String, List<ConfigAttribute>> methodMap) {
|
||||
public MapBasedMethodSecurityMetadataSource(Map<String, List<ConfigAttribute>> methodMap) {
|
||||
for (Map.Entry<String, List<ConfigAttribute>> entry : methodMap.entrySet()) {
|
||||
addSecureMethod(entry.getKey(), entry.getValue());
|
||||
}
|
||||
@@ -85,8 +84,7 @@ public class MapBasedMethodSecurityMetadataSource extends
|
||||
* applicable.
|
||||
*/
|
||||
@Override
|
||||
protected Collection<ConfigAttribute> findAttributes(Method method,
|
||||
Class<?> targetClass) {
|
||||
protected Collection<ConfigAttribute> findAttributes(Method method, Class<?> targetClass) {
|
||||
if (targetClass == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -94,8 +92,7 @@ public class MapBasedMethodSecurityMetadataSource extends
|
||||
return findAttributesSpecifiedAgainst(method, targetClass);
|
||||
}
|
||||
|
||||
private List<ConfigAttribute> findAttributesSpecifiedAgainst(Method method,
|
||||
Class<?> clazz) {
|
||||
private List<ConfigAttribute> findAttributesSpecifiedAgainst(Method method, Class<?> clazz) {
|
||||
RegisteredMethod registeredMethod = new RegisteredMethod(method, clazz);
|
||||
if (methodMap.containsKey(registeredMethod)) {
|
||||
return methodMap.get(registeredMethod);
|
||||
@@ -110,7 +107,6 @@ public class MapBasedMethodSecurityMetadataSource extends
|
||||
/**
|
||||
* Add configuration attributes for a secure method. Method names can end or start
|
||||
* with <code>*</code> for matching multiple methods.
|
||||
*
|
||||
* @param name type and method name, separated by a dot
|
||||
* @param attr the security attributes associated with the method
|
||||
*/
|
||||
@@ -118,8 +114,7 @@ public class MapBasedMethodSecurityMetadataSource extends
|
||||
int lastDotIndex = name.lastIndexOf(".");
|
||||
|
||||
if (lastDotIndex == -1) {
|
||||
throw new IllegalArgumentException("'" + name
|
||||
+ "' is not a valid method name: format is FQN.methodName");
|
||||
throw new IllegalArgumentException("'" + name + "' is not a valid method name: format is FQN.methodName");
|
||||
}
|
||||
|
||||
String methodName = name.substring(lastDotIndex + 1);
|
||||
@@ -134,19 +129,16 @@ public class MapBasedMethodSecurityMetadataSource extends
|
||||
/**
|
||||
* Add configuration attributes for a secure method. Mapped method names can end or
|
||||
* start with <code>*</code> for matching multiple methods.
|
||||
*
|
||||
* @param javaType target interface or class the security configuration attribute
|
||||
* applies to
|
||||
* @param mappedName mapped method name, which the javaType has declared or inherited
|
||||
* @param attr required authorities associated with the method
|
||||
*/
|
||||
public void addSecureMethod(Class<?> javaType, String mappedName,
|
||||
List<ConfigAttribute> attr) {
|
||||
public void addSecureMethod(Class<?> javaType, String mappedName, List<ConfigAttribute> attr) {
|
||||
String name = javaType.getName() + '.' + mappedName;
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Request to add secure method [" + name + "] with attributes ["
|
||||
+ attr + "]");
|
||||
logger.debug("Request to add secure method [" + name + "] with attributes [" + attr + "]");
|
||||
}
|
||||
|
||||
Method[] methods = javaType.getMethods();
|
||||
@@ -159,8 +151,7 @@ public class MapBasedMethodSecurityMetadataSource extends
|
||||
}
|
||||
|
||||
if (matchingMethods.isEmpty()) {
|
||||
throw new IllegalArgumentException("Couldn't find method '" + mappedName
|
||||
+ "' on '" + javaType + "'");
|
||||
throw new IllegalArgumentException("Couldn't find method '" + mappedName + "' on '" + javaType + "'");
|
||||
}
|
||||
|
||||
// register all matching methods
|
||||
@@ -168,24 +159,20 @@ public class MapBasedMethodSecurityMetadataSource extends
|
||||
RegisteredMethod registeredMethod = new RegisteredMethod(method, javaType);
|
||||
String regMethodName = this.nameMap.get(registeredMethod);
|
||||
|
||||
if ((regMethodName == null)
|
||||
|| (!regMethodName.equals(name) && (regMethodName.length() <= name
|
||||
.length()))) {
|
||||
if ((regMethodName == null) || (!regMethodName.equals(name) && (regMethodName.length() <= name.length()))) {
|
||||
// no already registered method name, or more specific
|
||||
// method name specification now -> (re-)register method
|
||||
if (regMethodName != null) {
|
||||
logger.debug("Replacing attributes for secure method [" + method
|
||||
+ "]: current name [" + name + "] is more specific than ["
|
||||
+ regMethodName + "]");
|
||||
logger.debug("Replacing attributes for secure method [" + method + "]: current name [" + name
|
||||
+ "] is more specific than [" + regMethodName + "]");
|
||||
}
|
||||
|
||||
this.nameMap.put(registeredMethod, name);
|
||||
addSecureMethod(registeredMethod, attr);
|
||||
}
|
||||
else {
|
||||
logger.debug("Keeping attributes for secure method [" + method
|
||||
+ "]: current name [" + name + "] is not more specific than ["
|
||||
+ regMethodName + "]");
|
||||
logger.debug("Keeping attributes for secure method [" + method + "]: current name [" + name
|
||||
+ "] is not more specific than [" + regMethodName + "]");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -199,14 +186,11 @@ public class MapBasedMethodSecurityMetadataSource extends
|
||||
* <p>
|
||||
* This method should only be called during initialization of the {@code BeanFactory}.
|
||||
*/
|
||||
public void addSecureMethod(Class<?> javaType, Method method,
|
||||
List<ConfigAttribute> attr) {
|
||||
public void addSecureMethod(Class<?> javaType, Method method, List<ConfigAttribute> attr) {
|
||||
RegisteredMethod key = new RegisteredMethod(method, javaType);
|
||||
|
||||
if (methodMap.containsKey(key)) {
|
||||
logger.debug("Method [" + method
|
||||
+ "] is already registered with attributes [" + methodMap.get(key)
|
||||
+ "]");
|
||||
logger.debug("Method [" + method + "] is already registered with attributes [" + methodMap.get(key) + "]");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -215,7 +199,6 @@ public class MapBasedMethodSecurityMetadataSource extends
|
||||
|
||||
/**
|
||||
* Add configuration attributes for a secure method.
|
||||
*
|
||||
* @param method the method to be secured
|
||||
* @param attr required authorities associated with the method
|
||||
*/
|
||||
@@ -223,15 +206,13 @@ public class MapBasedMethodSecurityMetadataSource extends
|
||||
Assert.notNull(method, "RegisteredMethod required");
|
||||
Assert.notNull(attr, "Configuration attribute required");
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Adding secure method [" + method + "] with attributes [" + attr
|
||||
+ "]");
|
||||
logger.info("Adding secure method [" + method + "] with attributes [" + attr + "]");
|
||||
}
|
||||
this.methodMap.put(method, attr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains the configuration attributes explicitly defined against this bean.
|
||||
*
|
||||
* @return the attributes explicitly defined against this bean
|
||||
*/
|
||||
@Override
|
||||
@@ -248,17 +229,13 @@ public class MapBasedMethodSecurityMetadataSource extends
|
||||
/**
|
||||
* Return if the given method name matches the mapped name. The default implementation
|
||||
* checks for "xxx" and "xxx" matches.
|
||||
*
|
||||
* @param methodName the method name of the class
|
||||
* @param mappedName the name in the descriptor
|
||||
*
|
||||
* @return if the names match
|
||||
*/
|
||||
private boolean isMatch(String methodName, String mappedName) {
|
||||
return (mappedName.endsWith("*") && methodName.startsWith(mappedName.substring(0,
|
||||
mappedName.length() - 1)))
|
||||
|| (mappedName.startsWith("*") && methodName.endsWith(mappedName
|
||||
.substring(1, mappedName.length())));
|
||||
return (mappedName.endsWith("*") && methodName.startsWith(mappedName.substring(0, mappedName.length() - 1)))
|
||||
|| (mappedName.startsWith("*") && methodName.endsWith(mappedName.substring(1, mappedName.length())));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -284,7 +261,9 @@ public class MapBasedMethodSecurityMetadataSource extends
|
||||
* we're invoking against and the Method will provide details of the declared class.
|
||||
*/
|
||||
private static class RegisteredMethod {
|
||||
|
||||
private final Method method;
|
||||
|
||||
private final Class<?> registeredJavaType;
|
||||
|
||||
RegisteredMethod(Method method, Class<?> registeredJavaType) {
|
||||
@@ -301,8 +280,7 @@ public class MapBasedMethodSecurityMetadataSource extends
|
||||
}
|
||||
if (obj != null && obj instanceof RegisteredMethod) {
|
||||
RegisteredMethod rhs = (RegisteredMethod) obj;
|
||||
return method.equals(rhs.method)
|
||||
&& registeredJavaType.equals(rhs.registeredJavaType);
|
||||
return method.equals(rhs.method) && registeredJavaType.equals(rhs.registeredJavaType);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -314,9 +292,9 @@ public class MapBasedMethodSecurityMetadataSource extends
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RegisteredMethod[" + registeredJavaType.getName() + "; " + method
|
||||
+ "]";
|
||||
return "RegisteredMethod[" + registeredJavaType.getName() + "; " + method + "]";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
@@ -29,5 +29,7 @@ import org.springframework.security.access.SecurityMetadataSource;
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public interface MethodSecurityMetadataSource extends SecurityMetadataSource {
|
||||
|
||||
Collection<ConfigAttribute> getAttributes(Method method, Class<?> targetClass);
|
||||
|
||||
}
|
||||
|
||||
@@ -45,4 +45,5 @@ public @interface P {
|
||||
* @return
|
||||
*/
|
||||
String value();
|
||||
|
||||
}
|
||||
@@ -14,8 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
/**
|
||||
* Provides {@code SecurityMetadataSource} implementations for securing Java method invocations via different
|
||||
* AOP libraries.
|
||||
* Provides {@code SecurityMetadataSource} implementations for securing Java method
|
||||
* invocations via different AOP libraries.
|
||||
*/
|
||||
package org.springframework.security.access.method;
|
||||
|
||||
|
||||
@@ -14,9 +14,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
/**
|
||||
* Core access-control related code, including security metadata related classes, interception code, access control
|
||||
* annotations, EL support and voter-based implementations of the central
|
||||
* {@link org.springframework.security.access.AccessDecisionManager AccessDecisionManager} interface.
|
||||
* Core access-control related code, including security metadata related classes,
|
||||
* interception code, access control annotations, EL support and voter-based
|
||||
* implementations of the central
|
||||
* {@link org.springframework.security.access.AccessDecisionManager AccessDecisionManager}
|
||||
* interface.
|
||||
*/
|
||||
package org.springframework.security.access;
|
||||
|
||||
|
||||
@@ -34,9 +34,11 @@ import java.lang.annotation.Target;
|
||||
@Inherited
|
||||
@Documented
|
||||
public @interface PostAuthorize {
|
||||
|
||||
/**
|
||||
* @return the Spring-EL expression to be evaluated after invoking the protected
|
||||
* method
|
||||
*/
|
||||
String value();
|
||||
|
||||
}
|
||||
|
||||
@@ -34,9 +34,11 @@ import java.lang.annotation.Target;
|
||||
@Inherited
|
||||
@Documented
|
||||
public @interface PostFilter {
|
||||
|
||||
/**
|
||||
* @return the Spring-EL expression to be evaluated after invoking the protected
|
||||
* method
|
||||
*/
|
||||
String value();
|
||||
|
||||
}
|
||||
|
||||
+6
-7
@@ -35,6 +35,7 @@ import org.springframework.security.core.Authentication;
|
||||
* @since 3.0
|
||||
*/
|
||||
public class PostInvocationAdviceProvider implements AfterInvocationProvider {
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private final PostInvocationAuthorizationAdvice postAdvice;
|
||||
@@ -43,9 +44,8 @@ public class PostInvocationAdviceProvider implements AfterInvocationProvider {
|
||||
this.postAdvice = postAdvice;
|
||||
}
|
||||
|
||||
public Object decide(Authentication authentication, Object object,
|
||||
Collection<ConfigAttribute> config, Object returnedObject)
|
||||
throws AccessDeniedException {
|
||||
public Object decide(Authentication authentication, Object object, Collection<ConfigAttribute> config,
|
||||
Object returnedObject) throws AccessDeniedException {
|
||||
|
||||
PostInvocationAttribute pia = findPostInvocationAttribute(config);
|
||||
|
||||
@@ -53,12 +53,10 @@ public class PostInvocationAdviceProvider implements AfterInvocationProvider {
|
||||
return returnedObject;
|
||||
}
|
||||
|
||||
return postAdvice.after(authentication, (MethodInvocation) object, pia,
|
||||
returnedObject);
|
||||
return postAdvice.after(authentication, (MethodInvocation) object, pia, returnedObject);
|
||||
}
|
||||
|
||||
private PostInvocationAttribute findPostInvocationAttribute(
|
||||
Collection<ConfigAttribute> config) {
|
||||
private PostInvocationAttribute findPostInvocationAttribute(Collection<ConfigAttribute> config) {
|
||||
for (ConfigAttribute attribute : config) {
|
||||
if (attribute instanceof PostInvocationAttribute) {
|
||||
return (PostInvocationAttribute) attribute;
|
||||
@@ -75,4 +73,5 @@ public class PostInvocationAdviceProvider implements AfterInvocationProvider {
|
||||
public boolean supports(Class<?> clazz) {
|
||||
return clazz.isAssignableFrom(MethodInvocation.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-2
@@ -18,8 +18,8 @@ package org.springframework.security.access.prepost;
|
||||
import org.springframework.security.access.ConfigAttribute;
|
||||
|
||||
/**
|
||||
* Marker interface for attributes which are created from combined @PostFilter and @PostAuthorize
|
||||
* annotations.
|
||||
* Marker interface for attributes which are created from combined @PostFilter
|
||||
* and @PostAuthorize annotations.
|
||||
* <p>
|
||||
* Consumed by a {@link PostInvocationAuthorizationAdvice}.
|
||||
*
|
||||
|
||||
+2
-2
@@ -28,7 +28,7 @@ import org.springframework.security.core.Authentication;
|
||||
*/
|
||||
public interface PostInvocationAuthorizationAdvice extends AopInfrastructureBean {
|
||||
|
||||
Object after(Authentication authentication, MethodInvocation mi,
|
||||
PostInvocationAttribute pia, Object returnedObject)
|
||||
Object after(Authentication authentication, MethodInvocation mi, PostInvocationAttribute pia, Object returnedObject)
|
||||
throws AccessDeniedException;
|
||||
|
||||
}
|
||||
|
||||
@@ -34,9 +34,11 @@ import java.lang.annotation.Target;
|
||||
@Inherited
|
||||
@Documented
|
||||
public @interface PreAuthorize {
|
||||
|
||||
/**
|
||||
* @return the Spring-EL expression to be evaluated before invoking the protected
|
||||
* method
|
||||
*/
|
||||
String value();
|
||||
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ import java.lang.annotation.Target;
|
||||
@Inherited
|
||||
@Documented
|
||||
public @interface PreFilter {
|
||||
|
||||
/**
|
||||
* @return the Spring-EL expression to be evaluated before invoking the protected
|
||||
* method
|
||||
@@ -58,4 +59,5 @@ public @interface PreFilter {
|
||||
* attribute can be omitted.
|
||||
*/
|
||||
String filterTarget() default "";
|
||||
|
||||
}
|
||||
|
||||
+2
-2
@@ -18,8 +18,8 @@ package org.springframework.security.access.prepost;
|
||||
import org.springframework.security.access.ConfigAttribute;
|
||||
|
||||
/**
|
||||
* Marker interface for attributes which are created from combined @PreFilter and @PreAuthorize
|
||||
* annotations.
|
||||
* Marker interface for attributes which are created from combined @PreFilter
|
||||
* and @PreAuthorize annotations.
|
||||
* <p>
|
||||
* Consumed by a {@link PreInvocationAuthorizationAdvice}.
|
||||
*
|
||||
|
||||
+4
-5
@@ -30,14 +30,13 @@ public interface PreInvocationAuthorizationAdvice extends AopInfrastructureBean
|
||||
/**
|
||||
* The "before" advice which should be executed to perform any filtering necessary and
|
||||
* to decide whether the method call is authorised.
|
||||
*
|
||||
* @param authentication the information on the principal on whose account the
|
||||
* decision should be made
|
||||
* @param mi the method invocation being attempted
|
||||
* @param preInvocationAttribute the attribute built from the @PreFilter and @PostFilter
|
||||
* annotations.
|
||||
* @param preInvocationAttribute the attribute built from the @PreFilter
|
||||
* and @PostFilter annotations.
|
||||
* @return true if authorised, false otherwise
|
||||
*/
|
||||
boolean before(Authentication authentication, MethodInvocation mi,
|
||||
PreInvocationAttribute preInvocationAttribute);
|
||||
boolean before(Authentication authentication, MethodInvocation mi, PreInvocationAttribute preInvocationAttribute);
|
||||
|
||||
}
|
||||
|
||||
+5
-6
@@ -37,8 +37,8 @@ import org.springframework.security.core.Authentication;
|
||||
* @author Luke Taylor
|
||||
* @since 3.0
|
||||
*/
|
||||
public class PreInvocationAuthorizationAdviceVoter implements
|
||||
AccessDecisionVoter<MethodInvocation> {
|
||||
public class PreInvocationAuthorizationAdviceVoter implements AccessDecisionVoter<MethodInvocation> {
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private final PreInvocationAuthorizationAdvice preAdvice;
|
||||
@@ -55,8 +55,7 @@ public class PreInvocationAuthorizationAdviceVoter implements
|
||||
return MethodInvocation.class.isAssignableFrom(clazz);
|
||||
}
|
||||
|
||||
public int vote(Authentication authentication, MethodInvocation method,
|
||||
Collection<ConfigAttribute> attributes) {
|
||||
public int vote(Authentication authentication, MethodInvocation method, Collection<ConfigAttribute> attributes) {
|
||||
|
||||
// Find prefilter and preauth (or combined) attributes
|
||||
// if both null, abstain
|
||||
@@ -74,8 +73,7 @@ public class PreInvocationAuthorizationAdviceVoter implements
|
||||
return allowed ? ACCESS_GRANTED : ACCESS_DENIED;
|
||||
}
|
||||
|
||||
private PreInvocationAttribute findPreInvocationAttribute(
|
||||
Collection<ConfigAttribute> config) {
|
||||
private PreInvocationAttribute findPreInvocationAttribute(Collection<ConfigAttribute> config) {
|
||||
for (ConfigAttribute attribute : config) {
|
||||
if (attribute instanceof PreInvocationAttribute) {
|
||||
return (PreInvocationAttribute) attribute;
|
||||
@@ -84,4 +82,5 @@ public class PreInvocationAuthorizationAdviceVoter implements
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+24
-29
@@ -36,15 +36,16 @@ import java.lang.reflect.Method;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* A {@link MethodInterceptor} that supports {@link PreAuthorize} and {@link PostAuthorize} for methods that return
|
||||
* {@link Mono} or {@link Flux}
|
||||
* A {@link MethodInterceptor} that supports {@link PreAuthorize} and
|
||||
* {@link PostAuthorize} for methods that return {@link Mono} or {@link Flux}
|
||||
*
|
||||
* @author Rob Winch
|
||||
* @since 5.0
|
||||
*/
|
||||
public class PrePostAdviceReactiveMethodInterceptor implements MethodInterceptor {
|
||||
|
||||
private Authentication anonymous = new AnonymousAuthenticationToken("key", "anonymous",
|
||||
AuthorityUtils.createAuthorityList("ROLE_ANONYMOUS"));
|
||||
AuthorityUtils.createAuthorityList("ROLE_ANONYMOUS"));
|
||||
|
||||
private final MethodSecurityMetadataSource attributeSource;
|
||||
|
||||
@@ -58,7 +59,9 @@ public class PrePostAdviceReactiveMethodInterceptor implements MethodInterceptor
|
||||
* @param preInvocationAdvice the {@link PreInvocationAuthorizationAdvice} to use
|
||||
* @param postInvocationAdvice the {@link PostInvocationAuthorizationAdvice} to use
|
||||
*/
|
||||
public PrePostAdviceReactiveMethodInterceptor(MethodSecurityMetadataSource attributeSource, PreInvocationAuthorizationAdvice preInvocationAdvice, PostInvocationAuthorizationAdvice postInvocationAdvice) {
|
||||
public PrePostAdviceReactiveMethodInterceptor(MethodSecurityMetadataSource attributeSource,
|
||||
PreInvocationAuthorizationAdvice preInvocationAdvice,
|
||||
PostInvocationAuthorizationAdvice postInvocationAdvice) {
|
||||
Assert.notNull(attributeSource, "attributeSource cannot be null");
|
||||
Assert.notNull(preInvocationAdvice, "preInvocationAdvice cannot be null");
|
||||
Assert.notNull(postInvocationAdvice, "postInvocationAdvice cannot be null");
|
||||
@@ -73,52 +76,44 @@ public class PrePostAdviceReactiveMethodInterceptor implements MethodInterceptor
|
||||
Method method = invocation.getMethod();
|
||||
Class<?> returnType = method.getReturnType();
|
||||
if (!Publisher.class.isAssignableFrom(returnType)) {
|
||||
throw new IllegalStateException("The returnType " + returnType + " on " + method + " must return an instance of org.reactivestreams.Publisher (i.e. Mono / Flux) in order to support Reactor Context");
|
||||
throw new IllegalStateException("The returnType " + returnType + " on " + method
|
||||
+ " must return an instance of org.reactivestreams.Publisher (i.e. Mono / Flux) in order to support Reactor Context");
|
||||
}
|
||||
Class<?> targetClass = invocation.getThis().getClass();
|
||||
Collection<ConfigAttribute> attributes = this.attributeSource
|
||||
.getAttributes(method, targetClass);
|
||||
Collection<ConfigAttribute> attributes = this.attributeSource.getAttributes(method, targetClass);
|
||||
|
||||
PreInvocationAttribute preAttr = findPreInvocationAttribute(attributes);
|
||||
Mono<Authentication> toInvoke = ReactiveSecurityContextHolder.getContext()
|
||||
.map(SecurityContext::getAuthentication)
|
||||
.defaultIfEmpty(this.anonymous)
|
||||
.filter( auth -> this.preInvocationAdvice.before(auth, invocation, preAttr))
|
||||
.switchIfEmpty(Mono.defer(() -> Mono.error(new AccessDeniedException("Denied"))));
|
||||
|
||||
.map(SecurityContext::getAuthentication).defaultIfEmpty(this.anonymous)
|
||||
.filter(auth -> this.preInvocationAdvice.before(auth, invocation, preAttr))
|
||||
.switchIfEmpty(Mono.defer(() -> Mono.error(new AccessDeniedException("Denied"))));
|
||||
|
||||
PostInvocationAttribute attr = findPostInvocationAttribute(attributes);
|
||||
|
||||
if (Mono.class.isAssignableFrom(returnType)) {
|
||||
return toInvoke
|
||||
.flatMap( auth -> this.<Mono<?>>proceed(invocation)
|
||||
.map( r -> attr == null ? r : this.postAdvice.after(auth, invocation, attr, r))
|
||||
);
|
||||
return toInvoke.flatMap(auth -> this.<Mono<?>>proceed(invocation)
|
||||
.map(r -> attr == null ? r : this.postAdvice.after(auth, invocation, attr, r)));
|
||||
}
|
||||
|
||||
if (Flux.class.isAssignableFrom(returnType)) {
|
||||
return toInvoke
|
||||
.flatMapMany( auth -> this.<Flux<?>>proceed(invocation)
|
||||
.map( r -> attr == null ? r : this.postAdvice.after(auth, invocation, attr, r))
|
||||
);
|
||||
return toInvoke.flatMapMany(auth -> this.<Flux<?>>proceed(invocation)
|
||||
.map(r -> attr == null ? r : this.postAdvice.after(auth, invocation, attr, r)));
|
||||
}
|
||||
|
||||
return toInvoke
|
||||
.flatMapMany( auth -> Flux.from(this.<Publisher<?>>proceed(invocation))
|
||||
.map( r -> attr == null ? r : this.postAdvice.after(auth, invocation, attr, r))
|
||||
);
|
||||
return toInvoke.flatMapMany(auth -> Flux.from(this.<Publisher<?>>proceed(invocation))
|
||||
.map(r -> attr == null ? r : this.postAdvice.after(auth, invocation, attr, r)));
|
||||
}
|
||||
|
||||
private static <T extends Publisher<?>> T proceed(final MethodInvocation invocation) {
|
||||
try {
|
||||
return (T) invocation.proceed();
|
||||
} catch(Throwable throwable) {
|
||||
}
|
||||
catch (Throwable throwable) {
|
||||
throw Exceptions.propagate(throwable);
|
||||
}
|
||||
}
|
||||
|
||||
private static PostInvocationAttribute findPostInvocationAttribute(
|
||||
Collection<ConfigAttribute> config) {
|
||||
private static PostInvocationAttribute findPostInvocationAttribute(Collection<ConfigAttribute> config) {
|
||||
for (ConfigAttribute attribute : config) {
|
||||
if (attribute instanceof PostInvocationAttribute) {
|
||||
return (PostInvocationAttribute) attribute;
|
||||
@@ -128,8 +123,7 @@ public class PrePostAdviceReactiveMethodInterceptor implements MethodInterceptor
|
||||
return null;
|
||||
}
|
||||
|
||||
private static PreInvocationAttribute findPreInvocationAttribute(
|
||||
Collection<ConfigAttribute> config) {
|
||||
private static PreInvocationAttribute findPreInvocationAttribute(Collection<ConfigAttribute> config) {
|
||||
for (ConfigAttribute attribute : config) {
|
||||
if (attribute instanceof PreInvocationAttribute) {
|
||||
return (PreInvocationAttribute) attribute;
|
||||
@@ -138,4 +132,5 @@ public class PrePostAdviceReactiveMethodInterceptor implements MethodInterceptor
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+21
-30
@@ -25,11 +25,12 @@ import org.springframework.security.access.method.AbstractMethodSecurityMetadata
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* <tt>MethodSecurityMetadataSource</tt> which extracts metadata from the @PreFilter and @PreAuthorize
|
||||
* annotations placed on a method. This class is merely responsible for locating the
|
||||
* relevant annotations (if any). It delegates the actual <tt>ConfigAttribute</tt>
|
||||
* creation to its {@link PrePostInvocationAttributeFactory}, thus decoupling itself from
|
||||
* the mechanism which will enforce the annotations' behaviour.
|
||||
* <tt>MethodSecurityMetadataSource</tt> which extracts metadata from the @PreFilter
|
||||
* and @PreAuthorize annotations placed on a method. This class is merely responsible for
|
||||
* locating the relevant annotations (if any). It delegates the actual
|
||||
* <tt>ConfigAttribute</tt> creation to its {@link PrePostInvocationAttributeFactory},
|
||||
* thus decoupling itself from the mechanism which will enforce the annotations'
|
||||
* behaviour.
|
||||
* <p>
|
||||
* Annotations may be specified on classes or methods, and method-specific annotations
|
||||
* will take precedence. If you use any annotation and do not specify a pre-authorization
|
||||
@@ -41,17 +42,14 @@ import org.springframework.util.ClassUtils;
|
||||
* defined on the method itself, or at interface or class level.
|
||||
*
|
||||
* @see PreInvocationAuthorizationAdviceVoter
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @since 3.0
|
||||
*/
|
||||
public class PrePostAnnotationSecurityMetadataSource extends
|
||||
AbstractMethodSecurityMetadataSource {
|
||||
public class PrePostAnnotationSecurityMetadataSource extends AbstractMethodSecurityMetadataSource {
|
||||
|
||||
private final PrePostInvocationAttributeFactory attributeFactory;
|
||||
|
||||
public PrePostAnnotationSecurityMetadataSource(
|
||||
PrePostInvocationAttributeFactory attributeFactory) {
|
||||
public PrePostAnnotationSecurityMetadataSource(PrePostInvocationAttributeFactory attributeFactory) {
|
||||
this.attributeFactory = attributeFactory;
|
||||
}
|
||||
|
||||
@@ -60,18 +58,15 @@ public class PrePostAnnotationSecurityMetadataSource extends
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
logger.trace("Looking for Pre/Post annotations for method '" + method.getName()
|
||||
+ "' on target class '" + targetClass + "'");
|
||||
logger.trace("Looking for Pre/Post annotations for method '" + method.getName() + "' on target class '"
|
||||
+ targetClass + "'");
|
||||
PreFilter preFilter = findAnnotation(method, targetClass, PreFilter.class);
|
||||
PreAuthorize preAuthorize = findAnnotation(method, targetClass,
|
||||
PreAuthorize.class);
|
||||
PreAuthorize preAuthorize = findAnnotation(method, targetClass, PreAuthorize.class);
|
||||
PostFilter postFilter = findAnnotation(method, targetClass, PostFilter.class);
|
||||
// TODO: Can we check for void methods and throw an exception here?
|
||||
PostAuthorize postAuthorize = findAnnotation(method, targetClass,
|
||||
PostAuthorize.class);
|
||||
PostAuthorize postAuthorize = findAnnotation(method, targetClass, PostAuthorize.class);
|
||||
|
||||
if (preFilter == null && preAuthorize == null && postFilter == null
|
||||
&& postAuthorize == null) {
|
||||
if (preFilter == null && preAuthorize == null && postFilter == null && postAuthorize == null) {
|
||||
// There is no meta-data so return
|
||||
logger.trace("No expression annotations found");
|
||||
return Collections.emptyList();
|
||||
@@ -81,20 +76,19 @@ public class PrePostAnnotationSecurityMetadataSource extends
|
||||
String filterObject = preFilter == null ? null : preFilter.filterTarget();
|
||||
String preAuthorizeAttribute = preAuthorize == null ? null : preAuthorize.value();
|
||||
String postFilterAttribute = postFilter == null ? null : postFilter.value();
|
||||
String postAuthorizeAttribute = postAuthorize == null ? null : postAuthorize
|
||||
.value();
|
||||
String postAuthorizeAttribute = postAuthorize == null ? null : postAuthorize.value();
|
||||
|
||||
ArrayList<ConfigAttribute> attrs = new ArrayList<>(2);
|
||||
|
||||
PreInvocationAttribute pre = attributeFactory.createPreInvocationAttribute(
|
||||
preFilterAttribute, filterObject, preAuthorizeAttribute);
|
||||
PreInvocationAttribute pre = attributeFactory.createPreInvocationAttribute(preFilterAttribute, filterObject,
|
||||
preAuthorizeAttribute);
|
||||
|
||||
if (pre != null) {
|
||||
attrs.add(pre);
|
||||
}
|
||||
|
||||
PostInvocationAttribute post = attributeFactory.createPostInvocationAttribute(
|
||||
postFilterAttribute, postAuthorizeAttribute);
|
||||
PostInvocationAttribute post = attributeFactory.createPostInvocationAttribute(postFilterAttribute,
|
||||
postAuthorizeAttribute);
|
||||
|
||||
if (post != null) {
|
||||
attrs.add(post);
|
||||
@@ -115,8 +109,7 @@ public class PrePostAnnotationSecurityMetadataSource extends
|
||||
* for the logic of this method. The ordering here is slightly different in that we
|
||||
* consider method-specific annotations on an interface before class-level ones.
|
||||
*/
|
||||
private <A extends Annotation> A findAnnotation(Method method, Class<?> targetClass,
|
||||
Class<A> annotationClass) {
|
||||
private <A extends Annotation> A findAnnotation(Method method, Class<?> targetClass, Class<A> annotationClass) {
|
||||
// The method may be on an interface, but we need attributes from the target
|
||||
// class.
|
||||
// If the target class is null, the method will be unchanged.
|
||||
@@ -140,12 +133,10 @@ public class PrePostAnnotationSecurityMetadataSource extends
|
||||
|
||||
// Check the class-level (note declaringClass, not targetClass, which may not
|
||||
// actually implement the method)
|
||||
annotation = AnnotationUtils.findAnnotation(specificMethod.getDeclaringClass(),
|
||||
annotationClass);
|
||||
annotation = AnnotationUtils.findAnnotation(specificMethod.getDeclaringClass(), annotationClass);
|
||||
|
||||
if (annotation != null) {
|
||||
logger.debug(annotation + " found on: "
|
||||
+ specificMethod.getDeclaringClass().getName());
|
||||
logger.debug(annotation + " found on: " + specificMethod.getDeclaringClass().getName());
|
||||
return annotation;
|
||||
}
|
||||
|
||||
|
||||
+4
-5
@@ -18,15 +18,14 @@ package org.springframework.security.access.prepost;
|
||||
import org.springframework.aop.framework.AopInfrastructureBean;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @since 3.0
|
||||
*/
|
||||
public interface PrePostInvocationAttributeFactory extends AopInfrastructureBean {
|
||||
|
||||
PreInvocationAttribute createPreInvocationAttribute(String preFilterAttribute,
|
||||
String filterObject, String preAuthorizeAttribute);
|
||||
PreInvocationAttribute createPreInvocationAttribute(String preFilterAttribute, String filterObject,
|
||||
String preAuthorizeAttribute);
|
||||
|
||||
PostInvocationAttribute createPostInvocationAttribute(String postFilterAttribute, String postAuthorizeAttribute);
|
||||
|
||||
PostInvocationAttribute createPostInvocationAttribute(String postFilterAttribute,
|
||||
String postAuthorizeAttribute);
|
||||
}
|
||||
|
||||
@@ -14,11 +14,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
/**
|
||||
* Contains the infrastructure classes for handling the {@code @PreAuthorize}, {@code @PreFilter}, {@code @PostAuthorize}
|
||||
* and {@code @PostFilter} annotations.
|
||||
* Contains the infrastructure classes for handling the {@code @PreAuthorize},
|
||||
* {@code @PreFilter}, {@code @PostAuthorize} and {@code @PostFilter} annotations.
|
||||
* <p>
|
||||
* Other than the annotations themselves, the classes should be regarded as for internal framework use and
|
||||
* are liable to change without notice.
|
||||
* Other than the annotations themselves, the classes should be regarded as for internal
|
||||
* framework use and are liable to change without notice.
|
||||
*/
|
||||
package org.springframework.security.access.prepost;
|
||||
|
||||
|
||||
+7
-7
@@ -39,8 +39,9 @@ import org.springframework.util.Assert;
|
||||
* and the access control behaviour if all voters abstain from voting (defaults to deny
|
||||
* access).
|
||||
*/
|
||||
public abstract class AbstractAccessDecisionManager implements AccessDecisionManager,
|
||||
InitializingBean, MessageSourceAware {
|
||||
public abstract class AbstractAccessDecisionManager
|
||||
implements AccessDecisionManager, InitializingBean, MessageSourceAware {
|
||||
|
||||
// ~ Instance fields
|
||||
// ================================================================================================
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
@@ -51,8 +52,7 @@ public abstract class AbstractAccessDecisionManager implements AccessDecisionMan
|
||||
|
||||
private boolean allowIfAllAbstainDecisions = false;
|
||||
|
||||
protected AbstractAccessDecisionManager(
|
||||
List<AccessDecisionVoter<?>> decisionVoters) {
|
||||
protected AbstractAccessDecisionManager(List<AccessDecisionVoter<?>> decisionVoters) {
|
||||
Assert.notEmpty(decisionVoters, "A list of AccessDecisionVoters is required");
|
||||
this.decisionVoters = decisionVoters;
|
||||
}
|
||||
@@ -67,8 +67,8 @@ public abstract class AbstractAccessDecisionManager implements AccessDecisionMan
|
||||
|
||||
protected final void checkAllowIfAllAbstainDecisions() {
|
||||
if (!this.isAllowIfAllAbstainDecisions()) {
|
||||
throw new AccessDeniedException(messages.getMessage(
|
||||
"AbstractAccessDecisionManager.accessDenied", "Access is denied"));
|
||||
throw new AccessDeniedException(
|
||||
messages.getMessage("AbstractAccessDecisionManager.accessDenied", "Access is denied"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,7 +104,6 @@ public abstract class AbstractAccessDecisionManager implements AccessDecisionMan
|
||||
* <p>
|
||||
* If one or more voters cannot support the presented class, <code>false</code> is
|
||||
* returned.
|
||||
*
|
||||
* @param clazz the type of secured object being presented
|
||||
* @return true if this type is supported
|
||||
*/
|
||||
@@ -117,4 +116,5 @@ public abstract class AbstractAccessDecisionManager implements AccessDecisionMan
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import org.springframework.util.Assert;
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public abstract class AbstractAclVoter implements AccessDecisionVoter<MethodInvocation> {
|
||||
|
||||
// ~ Instance fields
|
||||
// ================================================================================================
|
||||
|
||||
@@ -57,21 +58,19 @@ public abstract class AbstractAclVoter implements AccessDecisionVoter<MethodInvo
|
||||
}
|
||||
|
||||
public void setProcessDomainObjectClass(Class<?> processDomainObjectClass) {
|
||||
Assert.notNull(processDomainObjectClass,
|
||||
"processDomainObjectClass cannot be set to null");
|
||||
Assert.notNull(processDomainObjectClass, "processDomainObjectClass cannot be set to null");
|
||||
this.processDomainObjectClass = processDomainObjectClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation supports only <code>MethodSecurityInterceptor</code>, because
|
||||
* it queries the presented <code>MethodInvocation</code>.
|
||||
*
|
||||
* @param clazz the secure object
|
||||
*
|
||||
* @return <code>true</code> if the secure object is <code>MethodInvocation</code>,
|
||||
* <code>false</code> otherwise
|
||||
*/
|
||||
public boolean supports(Class<?> clazz) {
|
||||
return (MethodInvocation.class.isAssignableFrom(clazz));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -47,16 +47,14 @@ public class AffirmativeBased extends AbstractAccessDecisionManager {
|
||||
* be based on the {@link #isAllowIfAllAbstainDecisions()} property (defaults to
|
||||
* false).
|
||||
* </p>
|
||||
*
|
||||
* @param authentication the caller invoking the method
|
||||
* @param object the secured object
|
||||
* @param configAttributes the configuration attributes associated with the method
|
||||
* being invoked
|
||||
*
|
||||
* @throws AccessDeniedException if access is denied
|
||||
*/
|
||||
public void decide(Authentication authentication, Object object,
|
||||
Collection<ConfigAttribute> configAttributes) throws AccessDeniedException {
|
||||
public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes)
|
||||
throws AccessDeniedException {
|
||||
int deny = 0;
|
||||
|
||||
for (AccessDecisionVoter voter : getDecisionVoters()) {
|
||||
@@ -81,11 +79,12 @@ public class AffirmativeBased extends AbstractAccessDecisionManager {
|
||||
}
|
||||
|
||||
if (deny > 0) {
|
||||
throw new AccessDeniedException(messages.getMessage(
|
||||
"AbstractAccessDecisionManager.accessDenied", "Access is denied"));
|
||||
throw new AccessDeniedException(
|
||||
messages.getMessage("AbstractAccessDecisionManager.accessDenied", "Access is denied"));
|
||||
}
|
||||
|
||||
// To get this far, every AccessDecisionVoter abstained
|
||||
checkAllowIfAllAbstainDecisions();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+14
-16
@@ -47,12 +47,16 @@ import org.springframework.util.Assert;
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public class AuthenticatedVoter implements AccessDecisionVoter<Object> {
|
||||
|
||||
// ~ Static fields/initializers
|
||||
// =====================================================================================
|
||||
|
||||
public static final String IS_AUTHENTICATED_FULLY = "IS_AUTHENTICATED_FULLY";
|
||||
|
||||
public static final String IS_AUTHENTICATED_REMEMBERED = "IS_AUTHENTICATED_REMEMBERED";
|
||||
|
||||
public static final String IS_AUTHENTICATED_ANONYMOUSLY = "IS_AUTHENTICATED_ANONYMOUSLY";
|
||||
|
||||
// ~ Instance fields
|
||||
// ================================================================================================
|
||||
|
||||
@@ -62,22 +66,19 @@ public class AuthenticatedVoter implements AccessDecisionVoter<Object> {
|
||||
// ========================================================================================================
|
||||
|
||||
private boolean isFullyAuthenticated(Authentication authentication) {
|
||||
return (!authenticationTrustResolver.isAnonymous(authentication) && !authenticationTrustResolver
|
||||
.isRememberMe(authentication));
|
||||
return (!authenticationTrustResolver.isAnonymous(authentication)
|
||||
&& !authenticationTrustResolver.isRememberMe(authentication));
|
||||
}
|
||||
|
||||
public void setAuthenticationTrustResolver(
|
||||
AuthenticationTrustResolver authenticationTrustResolver) {
|
||||
Assert.notNull(authenticationTrustResolver,
|
||||
"AuthenticationTrustResolver cannot be set to null");
|
||||
public void setAuthenticationTrustResolver(AuthenticationTrustResolver authenticationTrustResolver) {
|
||||
Assert.notNull(authenticationTrustResolver, "AuthenticationTrustResolver cannot be set to null");
|
||||
this.authenticationTrustResolver = authenticationTrustResolver;
|
||||
}
|
||||
|
||||
public boolean supports(ConfigAttribute attribute) {
|
||||
if ((attribute.getAttribute() != null)
|
||||
&& (IS_AUTHENTICATED_FULLY.equals(attribute.getAttribute())
|
||||
|| IS_AUTHENTICATED_REMEMBERED.equals(attribute.getAttribute()) || IS_AUTHENTICATED_ANONYMOUSLY
|
||||
.equals(attribute.getAttribute()))) {
|
||||
if ((attribute.getAttribute() != null) && (IS_AUTHENTICATED_FULLY.equals(attribute.getAttribute())
|
||||
|| IS_AUTHENTICATED_REMEMBERED.equals(attribute.getAttribute())
|
||||
|| IS_AUTHENTICATED_ANONYMOUSLY.equals(attribute.getAttribute()))) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
@@ -88,17 +89,14 @@ public class AuthenticatedVoter implements AccessDecisionVoter<Object> {
|
||||
/**
|
||||
* This implementation supports any type of class, because it does not query the
|
||||
* presented secure object.
|
||||
*
|
||||
* @param clazz the secure object type
|
||||
*
|
||||
* @return always {@code true}
|
||||
*/
|
||||
public boolean supports(Class<?> clazz) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public int vote(Authentication authentication, Object object,
|
||||
Collection<ConfigAttribute> attributes) {
|
||||
public int vote(Authentication authentication, Object object, Collection<ConfigAttribute> attributes) {
|
||||
int result = ACCESS_ABSTAIN;
|
||||
|
||||
for (ConfigAttribute attribute : attributes) {
|
||||
@@ -119,8 +117,7 @@ public class AuthenticatedVoter implements AccessDecisionVoter<Object> {
|
||||
}
|
||||
|
||||
if (IS_AUTHENTICATED_ANONYMOUSLY.equals(attribute.getAttribute())) {
|
||||
if (authenticationTrustResolver.isAnonymous(authentication)
|
||||
|| isFullyAuthenticated(authentication)
|
||||
if (authenticationTrustResolver.isAnonymous(authentication) || isFullyAuthenticated(authentication)
|
||||
|| authenticationTrustResolver.isRememberMe(authentication)) {
|
||||
return ACCESS_GRANTED;
|
||||
}
|
||||
@@ -130,4 +127,5 @@ public class AuthenticatedVoter implements AccessDecisionVoter<Object> {
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ import org.springframework.security.core.Authentication;
|
||||
* {@link UnanimousBased}.
|
||||
*/
|
||||
public class ConsensusBased extends AbstractAccessDecisionManager {
|
||||
|
||||
// ~ Instance fields
|
||||
// ================================================================================================
|
||||
|
||||
@@ -56,16 +57,14 @@ public class ConsensusBased extends AbstractAccessDecisionManager {
|
||||
* If every <code>AccessDecisionVoter</code> abstained from voting, the decision will
|
||||
* be based on the {@link #isAllowIfAllAbstainDecisions()} property (defaults to
|
||||
* false).
|
||||
*
|
||||
* @param authentication the caller invoking the method
|
||||
* @param object the secured object
|
||||
* @param configAttributes the configuration attributes associated with the method
|
||||
* being invoked
|
||||
*
|
||||
* @throws AccessDeniedException if access is denied
|
||||
*/
|
||||
public void decide(Authentication authentication, Object object,
|
||||
Collection<ConfigAttribute> configAttributes) throws AccessDeniedException {
|
||||
public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes)
|
||||
throws AccessDeniedException {
|
||||
int grant = 0;
|
||||
int deny = 0;
|
||||
|
||||
@@ -97,8 +96,8 @@ public class ConsensusBased extends AbstractAccessDecisionManager {
|
||||
}
|
||||
|
||||
if (deny > grant) {
|
||||
throw new AccessDeniedException(messages.getMessage(
|
||||
"AbstractAccessDecisionManager.accessDenied", "Access is denied"));
|
||||
throw new AccessDeniedException(
|
||||
messages.getMessage("AbstractAccessDecisionManager.accessDenied", "Access is denied"));
|
||||
}
|
||||
|
||||
if ((grant == deny) && (grant != 0)) {
|
||||
@@ -106,8 +105,8 @@ public class ConsensusBased extends AbstractAccessDecisionManager {
|
||||
return;
|
||||
}
|
||||
else {
|
||||
throw new AccessDeniedException(messages.getMessage(
|
||||
"AbstractAccessDecisionManager.accessDenied", "Access is denied"));
|
||||
throw new AccessDeniedException(
|
||||
messages.getMessage("AbstractAccessDecisionManager.accessDenied", "Access is denied"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,8 +118,8 @@ public class ConsensusBased extends AbstractAccessDecisionManager {
|
||||
return allowIfEqualGrantedDeniedDecisions;
|
||||
}
|
||||
|
||||
public void setAllowIfEqualGrantedDeniedDecisions(
|
||||
boolean allowIfEqualGrantedDeniedDecisions) {
|
||||
public void setAllowIfEqualGrantedDeniedDecisions(boolean allowIfEqualGrantedDeniedDecisions) {
|
||||
this.allowIfEqualGrantedDeniedDecisions = allowIfEqualGrantedDeniedDecisions;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ import org.springframework.util.Assert;
|
||||
* @since 2.0.4
|
||||
*/
|
||||
public class RoleHierarchyVoter extends RoleVoter {
|
||||
|
||||
private RoleHierarchy roleHierarchy = null;
|
||||
|
||||
public RoleHierarchyVoter(RoleHierarchy roleHierarchy) {
|
||||
@@ -41,9 +42,8 @@ public class RoleHierarchyVoter extends RoleVoter {
|
||||
* Calls the <tt>RoleHierarchy</tt> to obtain the complete set of user authorities.
|
||||
*/
|
||||
@Override
|
||||
Collection<? extends GrantedAuthority> extractAuthorities(
|
||||
Authentication authentication) {
|
||||
return roleHierarchy.getReachableGrantedAuthorities(authentication
|
||||
.getAuthorities());
|
||||
Collection<? extends GrantedAuthority> extractAuthorities(Authentication authentication) {
|
||||
return roleHierarchy.getReachableGrantedAuthorities(authentication.getAuthorities());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -50,6 +50,7 @@ import org.springframework.security.core.GrantedAuthority;
|
||||
* @author colin sampaleanu
|
||||
*/
|
||||
public class RoleVoter implements AccessDecisionVoter<Object> {
|
||||
|
||||
// ~ Instance fields
|
||||
// ================================================================================================
|
||||
|
||||
@@ -65,7 +66,6 @@ public class RoleVoter implements AccessDecisionVoter<Object> {
|
||||
/**
|
||||
* Allows the default role prefix of <code>ROLE_</code> to be overridden. May be set
|
||||
* to an empty value, although this is usually not desirable.
|
||||
*
|
||||
* @param rolePrefix the new prefix
|
||||
*/
|
||||
public void setRolePrefix(String rolePrefix) {
|
||||
@@ -73,8 +73,7 @@ public class RoleVoter implements AccessDecisionVoter<Object> {
|
||||
}
|
||||
|
||||
public boolean supports(ConfigAttribute attribute) {
|
||||
if ((attribute.getAttribute() != null)
|
||||
&& attribute.getAttribute().startsWith(getRolePrefix())) {
|
||||
if ((attribute.getAttribute() != null) && attribute.getAttribute().startsWith(getRolePrefix())) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
@@ -85,17 +84,14 @@ public class RoleVoter implements AccessDecisionVoter<Object> {
|
||||
/**
|
||||
* This implementation supports any type of class, because it does not query the
|
||||
* presented secure object.
|
||||
*
|
||||
* @param clazz the secure object
|
||||
*
|
||||
* @return always <code>true</code>
|
||||
*/
|
||||
public boolean supports(Class<?> clazz) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public int vote(Authentication authentication, Object object,
|
||||
Collection<ConfigAttribute> attributes) {
|
||||
public int vote(Authentication authentication, Object object, Collection<ConfigAttribute> attributes) {
|
||||
if (authentication == null) {
|
||||
return ACCESS_DENIED;
|
||||
}
|
||||
@@ -118,8 +114,8 @@ public class RoleVoter implements AccessDecisionVoter<Object> {
|
||||
return result;
|
||||
}
|
||||
|
||||
Collection<? extends GrantedAuthority> extractAuthorities(
|
||||
Authentication authentication) {
|
||||
Collection<? extends GrantedAuthority> extractAuthorities(Authentication authentication) {
|
||||
return authentication.getAuthorities();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -52,16 +52,14 @@ public class UnanimousBased extends AbstractAccessDecisionManager {
|
||||
* If every <code>AccessDecisionVoter</code> abstained from voting, the decision will
|
||||
* be based on the {@link #isAllowIfAllAbstainDecisions()} property (defaults to
|
||||
* false).
|
||||
*
|
||||
* @param authentication the caller invoking the method
|
||||
* @param object the secured object
|
||||
* @param attributes the configuration attributes associated with the method being
|
||||
* invoked
|
||||
*
|
||||
* @throws AccessDeniedException if access is denied
|
||||
*/
|
||||
public void decide(Authentication authentication, Object object,
|
||||
Collection<ConfigAttribute> attributes) throws AccessDeniedException {
|
||||
public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> attributes)
|
||||
throws AccessDeniedException {
|
||||
|
||||
int grant = 0;
|
||||
|
||||
@@ -85,9 +83,8 @@ public class UnanimousBased extends AbstractAccessDecisionManager {
|
||||
break;
|
||||
|
||||
case AccessDecisionVoter.ACCESS_DENIED:
|
||||
throw new AccessDeniedException(messages.getMessage(
|
||||
"AbstractAccessDecisionManager.accessDenied",
|
||||
"Access is denied"));
|
||||
throw new AccessDeniedException(
|
||||
messages.getMessage("AbstractAccessDecisionManager.accessDenied", "Access is denied"));
|
||||
|
||||
default:
|
||||
break;
|
||||
@@ -103,4 +100,5 @@ public class UnanimousBased extends AbstractAccessDecisionManager {
|
||||
// To get this far, every AccessDecisionVoter abstained
|
||||
checkAllowIfAllAbstainDecisions();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,4 +17,3 @@
|
||||
* Implements a vote-based approach to authorization decisions.
|
||||
*/
|
||||
package org.springframework.security.access.vote;
|
||||
|
||||
|
||||
+12
-13
@@ -36,13 +36,15 @@ import org.springframework.security.core.userdetails.UserDetails;
|
||||
* @author Ben Alex
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public abstract class AbstractAuthenticationToken implements Authentication,
|
||||
CredentialsContainer {
|
||||
public abstract class AbstractAuthenticationToken implements Authentication, CredentialsContainer {
|
||||
|
||||
// ~ Instance fields
|
||||
// ================================================================================================
|
||||
|
||||
private final Collection<GrantedAuthority> authorities;
|
||||
|
||||
private Object details;
|
||||
|
||||
private boolean authenticated = false;
|
||||
|
||||
// ~ Constructors
|
||||
@@ -50,9 +52,8 @@ public abstract class AbstractAuthenticationToken implements Authentication,
|
||||
|
||||
/**
|
||||
* Creates a token with the supplied array of authorities.
|
||||
*
|
||||
* @param authorities the collection of <tt>GrantedAuthority</tt>s for the principal
|
||||
* represented by this authentication object.
|
||||
* represented by this authentication object.
|
||||
*/
|
||||
public AbstractAuthenticationToken(Collection<? extends GrantedAuthority> authorities) {
|
||||
if (authorities == null) {
|
||||
@@ -62,12 +63,10 @@ public abstract class AbstractAuthenticationToken implements Authentication,
|
||||
|
||||
for (GrantedAuthority a : authorities) {
|
||||
if (a == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Authorities collection cannot contain any null elements");
|
||||
throw new IllegalArgumentException("Authorities collection cannot contain any null elements");
|
||||
}
|
||||
}
|
||||
ArrayList<GrantedAuthority> temp = new ArrayList<>(
|
||||
authorities.size());
|
||||
ArrayList<GrantedAuthority> temp = new ArrayList<>(authorities.size());
|
||||
temp.addAll(authorities);
|
||||
this.authorities = Collections.unmodifiableList(temp);
|
||||
}
|
||||
@@ -154,8 +153,7 @@ public abstract class AbstractAuthenticationToken implements Authentication,
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((this.getCredentials() != null)
|
||||
&& !this.getCredentials().equals(test.getCredentials())) {
|
||||
if ((this.getCredentials() != null) && !this.getCredentials().equals(test.getCredentials())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -163,8 +161,7 @@ public abstract class AbstractAuthenticationToken implements Authentication,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.getPrincipal() != null
|
||||
&& !this.getPrincipal().equals(test.getPrincipal())) {
|
||||
if (this.getPrincipal() != null && !this.getPrincipal().equals(test.getPrincipal())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -218,10 +215,12 @@ public abstract class AbstractAuthenticationToken implements Authentication,
|
||||
|
||||
sb.append(authority);
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
sb.append("Not granted any authorities");
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+24
-33
@@ -33,8 +33,8 @@ import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A base {@link ReactiveAuthenticationManager} that allows subclasses to override and work with
|
||||
* {@link UserDetails} objects.
|
||||
* A base {@link ReactiveAuthenticationManager} that allows subclasses to override and
|
||||
* work with {@link UserDetails} objects.
|
||||
*
|
||||
* <p>
|
||||
* Upon successful validation, a <code>UsernamePasswordAuthenticationToken</code> will be
|
||||
@@ -61,25 +61,22 @@ public abstract class AbstractUserDetailsReactiveAuthenticationManager implement
|
||||
if (!user.isAccountNonLocked()) {
|
||||
logger.debug("User account is locked");
|
||||
|
||||
throw new LockedException(this.messages.getMessage(
|
||||
"AbstractUserDetailsAuthenticationProvider.locked",
|
||||
throw new LockedException(this.messages.getMessage("AbstractUserDetailsAuthenticationProvider.locked",
|
||||
"User account is locked"));
|
||||
}
|
||||
|
||||
if (!user.isEnabled()) {
|
||||
logger.debug("User account is disabled");
|
||||
|
||||
throw new DisabledException(this.messages.getMessage(
|
||||
"AbstractUserDetailsAuthenticationProvider.disabled",
|
||||
"User is disabled"));
|
||||
throw new DisabledException(
|
||||
this.messages.getMessage("AbstractUserDetailsAuthenticationProvider.disabled", "User is disabled"));
|
||||
}
|
||||
|
||||
if (!user.isAccountNonExpired()) {
|
||||
logger.debug("User account is expired");
|
||||
|
||||
throw new AccountExpiredException(this.messages.getMessage(
|
||||
"AbstractUserDetailsAuthenticationProvider.expired",
|
||||
"User account has expired"));
|
||||
throw new AccountExpiredException(this.messages
|
||||
.getMessage("AbstractUserDetailsAuthenticationProvider.expired", "User account has expired"));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -88,8 +85,7 @@ public abstract class AbstractUserDetailsReactiveAuthenticationManager implement
|
||||
logger.debug("User account credentials have expired");
|
||||
|
||||
throw new CredentialsExpiredException(this.messages.getMessage(
|
||||
"AbstractUserDetailsAuthenticationProvider.credentialsExpired",
|
||||
"User credentials have expired"));
|
||||
"AbstractUserDetailsAuthenticationProvider.credentialsExpired", "User credentials have expired"));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -97,9 +93,7 @@ public abstract class AbstractUserDetailsReactiveAuthenticationManager implement
|
||||
public Mono<Authentication> authenticate(Authentication authentication) {
|
||||
final String username = authentication.getName();
|
||||
final String presentedPassword = (String) authentication.getCredentials();
|
||||
return retrieveUser(username)
|
||||
.doOnNext(this.preAuthenticationChecks::check)
|
||||
.publishOn(this.scheduler)
|
||||
return retrieveUser(username).doOnNext(this.preAuthenticationChecks::check).publishOn(this.scheduler)
|
||||
.filter(u -> this.passwordEncoder.matches(presentedPassword, u.getPassword()))
|
||||
.switchIfEmpty(Mono.defer(() -> Mono.error(new BadCredentialsException("Invalid Credentials"))))
|
||||
.flatMap(u -> {
|
||||
@@ -110,14 +104,13 @@ public abstract class AbstractUserDetailsReactiveAuthenticationManager implement
|
||||
return this.userDetailsPasswordService.updatePassword(u, newPassword);
|
||||
}
|
||||
return Mono.just(u);
|
||||
})
|
||||
.doOnNext(this.postAuthenticationChecks::check)
|
||||
.map(u -> new UsernamePasswordAuthenticationToken(u, u.getPassword(), u.getAuthorities()) );
|
||||
}).doOnNext(this.postAuthenticationChecks::check)
|
||||
.map(u -> new UsernamePasswordAuthenticationToken(u, u.getPassword(), u.getAuthorities()));
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@link PasswordEncoder} that is used for validating the password. The default is
|
||||
* {@link PasswordEncoderFactories#createDelegatingPasswordEncoder()}
|
||||
* The {@link PasswordEncoder} that is used for validating the password. The default
|
||||
* is {@link PasswordEncoderFactories#createDelegatingPasswordEncoder()}
|
||||
* @param passwordEncoder the {@link PasswordEncoder} to use. Cannot be null
|
||||
*/
|
||||
public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
|
||||
@@ -126,13 +119,14 @@ public abstract class AbstractUserDetailsReactiveAuthenticationManager implement
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link Scheduler} used by the {@link UserDetailsRepositoryReactiveAuthenticationManager}.
|
||||
* The default is {@code Schedulers.newParallel(String)} because modern password encoding is
|
||||
* a CPU intensive task that is non blocking. This means validation is bounded by the
|
||||
* number of CPUs. Some applications may want to customize the {@link Scheduler}. For
|
||||
* example, if users are stuck using the insecure {@link org.springframework.security.crypto.password.NoOpPasswordEncoder}
|
||||
* they might want to leverage {@code Schedulers.immediate()}.
|
||||
*
|
||||
* Sets the {@link Scheduler} used by the
|
||||
* {@link UserDetailsRepositoryReactiveAuthenticationManager}. The default is
|
||||
* {@code Schedulers.newParallel(String)} because modern password encoding is a CPU
|
||||
* intensive task that is non blocking. This means validation is bounded by the number
|
||||
* of CPUs. Some applications may want to customize the {@link Scheduler}. For
|
||||
* example, if users are stuck using the insecure
|
||||
* {@link org.springframework.security.crypto.password.NoOpPasswordEncoder} they might
|
||||
* want to leverage {@code Schedulers.immediate()}.
|
||||
* @param scheduler the {@link Scheduler} to use. Cannot be null.
|
||||
* @since 5.0.6
|
||||
*/
|
||||
@@ -145,15 +139,13 @@ public abstract class AbstractUserDetailsReactiveAuthenticationManager implement
|
||||
* Sets the service to use for upgrading passwords on successful authentication.
|
||||
* @param userDetailsPasswordService the service to use
|
||||
*/
|
||||
public void setUserDetailsPasswordService(
|
||||
ReactiveUserDetailsPasswordService userDetailsPasswordService) {
|
||||
public void setUserDetailsPasswordService(ReactiveUserDetailsPasswordService userDetailsPasswordService) {
|
||||
this.userDetailsPasswordService = userDetailsPasswordService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the strategy which will be used to validate the loaded <tt>UserDetails</tt>
|
||||
* object after authentication occurs.
|
||||
*
|
||||
* @param postAuthenticationChecks The {@link UserDetailsChecker}
|
||||
* @since 5.2
|
||||
*/
|
||||
@@ -163,9 +155,8 @@ public abstract class AbstractUserDetailsReactiveAuthenticationManager implement
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows subclasses to retrieve the <code>UserDetails</code>
|
||||
* from an implementation-specific location.
|
||||
*
|
||||
* Allows subclasses to retrieve the <code>UserDetails</code> from an
|
||||
* implementation-specific location.
|
||||
* @param username The username to retrieve
|
||||
* @return the user information. If authentication fails, a Mono error is returned.
|
||||
*/
|
||||
|
||||
+2
-2
@@ -23,12 +23,12 @@ package org.springframework.security.authentication;
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public class AccountExpiredException extends AccountStatusException {
|
||||
|
||||
// ~ Constructors
|
||||
// ===================================================================================================
|
||||
|
||||
/**
|
||||
* Constructs a <code>AccountExpiredException</code> with the specified message.
|
||||
*
|
||||
* @param msg the detail message
|
||||
*/
|
||||
public AccountExpiredException(String msg) {
|
||||
@@ -38,11 +38,11 @@ public class AccountExpiredException extends AccountStatusException {
|
||||
/**
|
||||
* Constructs a <code>AccountExpiredException</code> with the specified message and
|
||||
* root cause.
|
||||
*
|
||||
* @param msg the detail message
|
||||
* @param t root cause
|
||||
*/
|
||||
public AccountExpiredException(String msg, Throwable t) {
|
||||
super(msg, t);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user