1
0
mirror of synced 2026-05-22 21:33:16 +00:00

Reformat code using spring-javaformat

Run `./gradlew format` to reformat all java files.

Issue gh-8945
This commit is contained in:
Phillip Webb
2020-08-10 16:39:17 -05:00
committed by Rob Winch
parent 81d9c6cac5
commit b7fc18262d
2487 changed files with 41506 additions and 46548 deletions
@@ -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);
}
@@ -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();
}
@@ -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);
}
@@ -31,4 +31,5 @@ import java.util.*;
public interface AnnotationMetadataExtractor<A extends Annotation> {
Collection<? extends ConfigAttribute> extractAttributes(A securityAnnotation);
}
@@ -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;
}
}
@@ -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.&nbsp;ROLE_USER, ROLE_ADMIN).
*
* Returns the list of security configuration attributes (e.g.&nbsp;ROLE_USER,
* ROLE_ADMIN).
* @return String[] The secure method attributes
*/
String[] value();
}
@@ -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;
}
}
@@ -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);
}
}
@@ -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;
}
}
@@ -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());
}
}
}
}
@@ -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;
@@ -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);
}
}
@@ -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;
}
@@ -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);
}
}
}
@@ -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);
}
@@ -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
*/
@@ -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;
}
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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()));
}
}
@@ -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
@@ -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();
}
@@ -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;
}
}
@@ -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();
}
}
@@ -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();
}
}
@@ -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;
@@ -20,7 +20,6 @@ import java.util.Collection;
import org.springframework.security.core.GrantedAuthority;
/**
*
* @author Luke Taylor
* @since 3.0
*/
@@ -36,7 +36,6 @@ public interface RoleHierarchy {
* Role hierarchy: ROLE_A &gt; ROLE_B &gt; 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.
*/
@@ -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);
}
}
@@ -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 "&gt;" sign as "includes"):
* Here is an example configuration of a role hierarchy (hint: read the "&gt;" sign as
* "includes"):
*
* <pre>
* &lt;property name="hierarchy"&gt;
@@ -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.");
}
}
@@ -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) {
@@ -17,4 +17,3 @@
* Role hierarchy implementation.
*/
package org.springframework.security.access.hierarchicalroles;
@@ -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);
}
}
}
@@ -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);
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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);
}
@@ -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;
}
}
@@ -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();
}
}
@@ -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;
}
}
@@ -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();
}
}
}
@@ -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;
@@ -24,8 +24,10 @@ package org.springframework.security.access.intercept.aspectj;
* @author Ben Alex
*/
public interface AspectJCallback {
// ~ Methods
// ========================================================================================================
Object proceedWithObject();
}
@@ -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);
}
}
@@ -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();
}
}
@@ -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;
@@ -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;
@@ -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)
*/
@@ -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));
}
}
@@ -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 + "]";
}
}
}
@@ -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 + "]";
}
}
}
@@ -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();
}
@@ -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);
}
}
@@ -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}.
*
@@ -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 "";
}
@@ -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}.
*
@@ -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);
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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;
}
@@ -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;
@@ -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();
}
}
@@ -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;
@@ -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();
}
}
@@ -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.
*/
@@ -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