SEC-1158: Decoupling of Pre/Post annotations implementation from Spring EL.

This commit is contained in:
Luke Taylor 2009-05-11 05:18:20 +00:00
parent acd7dc1f2d
commit 14c4739605
84 changed files with 2489 additions and 2028 deletions

View File

@ -12,7 +12,6 @@ import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.security.access.expression.method.MethodExpressionVoter;
import org.springframework.security.access.intercept.AfterInvocationProviderManager;
import org.springframework.security.access.vote.AccessDecisionVoter;
import org.springframework.security.access.vote.AffirmativeBased;
@ -35,7 +34,7 @@ abstract class ConfigUtils {
static void registerDefaultMethodAccessManagerIfNecessary(ParserContext parserContext) {
if (!parserContext.getRegistry().containsBeanDefinition(BeanIds.METHOD_ACCESS_MANAGER)) {
parserContext.getRegistry().registerBeanDefinition(BeanIds.METHOD_ACCESS_MANAGER,
createAccessManagerBean(MethodExpressionVoter.class, RoleVoter.class, AuthenticatedVoter.class));
createAccessManagerBean(RoleVoter.class, AuthenticatedVoter.class));
}
}

View File

@ -14,7 +14,7 @@ import org.springframework.util.ClassUtils;
*
* @author Luke Taylor
* @version $Id$
* @since 2.5
* @since 3.0
*/
class ContextSourceSettingPostProcessor implements BeanFactoryPostProcessor, Ordered {
private static final String REQUIRED_CONTEXT_SOURCE_CLASS_NAME = "org.springframework.ldap.core.support.BaseLdapPathContextSource";
@ -27,7 +27,7 @@ class ContextSourceSettingPostProcessor implements BeanFactoryPostProcessor, Ord
Class<?> contextSourceClass;
try {
contextSourceClass = ClassUtils.forName(REQUIRED_CONTEXT_SOURCE_CLASS_NAME);
contextSourceClass = ClassUtils.forName(REQUIRED_CONTEXT_SOURCE_CLASS_NAME, ClassUtils.getDefaultClassLoader());
} catch (ClassNotFoundException e) {
throw new SecurityConfigurationException("Couldn't locate: " + REQUIRED_CONTEXT_SOURCE_CLASS_NAME + ". " +
" If you are using LDAP with Spring Security, please ensure that you include the spring-ldap " +

View File

@ -22,6 +22,10 @@ public abstract class Elements {
public static final String LDAP_USER_SERVICE = "ldap-user-service";
public static final String PROTECT_POINTCUT = "protect-pointcut";
public static final String EXPRESSION_HANDLER = "expression-handler";
public static final String INVOCATION_HANDLING = "pre-post-annotation-handling";
public static final String INVOCATION_ATTRIBUTE_FACTORY = "invocation-attribute-factory";
public static final String PRE_INVOCATION_ADVICE = "pre-invocation-advice";
public static final String POST_INVOCATION_ADVICE = "post-invocation-advice";
public static final String PROTECT = "protect";
public static final String CONCURRENT_SESSIONS = "concurrent-session-control";
public static final String LOGOUT = "logout";

View File

@ -1,5 +1,7 @@
package org.springframework.security.config;
import static org.springframework.security.config.Elements.*;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
@ -18,14 +20,21 @@ import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.access.expression.method.MethodExpressionAfterInvocationProvider;
import org.springframework.security.access.expression.method.MethodExpressionVoter;
import org.springframework.security.access.expression.support.DefaultMethodSecurityExpressionHandler;
import org.springframework.security.access.annotation.Jsr250MethodSecurityMetadataSource;
import org.springframework.security.access.annotation.Jsr250Voter;
import org.springframework.security.access.annotation.SecuredAnnotationSecurityMetadataSource;
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
import org.springframework.security.access.expression.method.ExpressionBasedAnnotationAttributeFactory;
import org.springframework.security.access.expression.method.ExpressionBasedPostInvocationAdvice;
import org.springframework.security.access.expression.method.ExpressionBasedPreInvocationAdvice;
import org.springframework.security.access.intercept.method.DelegatingMethodSecurityMetadataSource;
import org.springframework.security.access.intercept.method.MapBasedMethodSecurityMetadataSource;
import org.springframework.security.access.intercept.method.ProtectPointcutPostProcessor;
import org.springframework.security.access.intercept.method.aopalliance.MethodSecurityInterceptor;
import org.springframework.security.access.intercept.method.aopalliance.MethodSecurityMetadataSourceAdvisor;
import org.springframework.security.access.prepost.PostInvocationAdviceProvider;
import org.springframework.security.access.prepost.PreInvocationAuthorizationAdviceVoter;
import org.springframework.security.access.prepost.PrePostAnnotationSecurityMetadataSource;
import org.springframework.security.access.vote.AffirmativeBased;
import org.springframework.security.access.vote.AuthenticatedVoter;
import org.springframework.security.access.vote.RoleVoter;
@ -45,11 +54,6 @@ class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionParser {
private final Log logger = LogFactory.getLog(getClass());
static final String SECURED_METHOD_DEFINITION_SOURCE_CLASS = "org.springframework.security.access.annotation.SecuredMethodSecurityMetadataSource";
static final String EXPRESSION_METHOD_DEFINITION_SOURCE_CLASS = "org.springframework.security.access.expression.method.ExpressionAnnotationMethodSecurityMetadataSource";
static final String JSR_250_SECURITY_METHOD_DEFINITION_SOURCE_CLASS = "org.springframework.security.access.annotation.Jsr250MethodSecurityMetadataSource";
static final String JSR_250_VOTER_CLASS = "org.springframework.security.access.annotation.Jsr250Voter";
/*
* Internal Bean IDs which are only used within this class
*/
@ -65,7 +69,7 @@ class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionParser {
private static final String ATT_RUN_AS_MGR = "run-as-manager-ref";
private static final String ATT_USE_JSR250 = "jsr250-annotations";
private static final String ATT_USE_SECURED = "secured-annotations";
private static final String ATT_USE_EXPRESSIONS = "expression-annotations";
private static final String ATT_USE_PREPOST = "pre-post-annotations";
@SuppressWarnings("unchecked")
public BeanDefinition parse(Element element, ParserContext parserContext) {
@ -75,12 +79,12 @@ class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionParser {
boolean jsr250Enabled = "enabled".equals(element.getAttribute(ATT_USE_JSR250));
boolean useSecured = "enabled".equals(element.getAttribute(ATT_USE_SECURED));
boolean expressionsEnabled = "enabled".equals(element.getAttribute(ATT_USE_EXPRESSIONS));
BeanDefinition expressionVoter = null;
boolean prePostAnnotationsEnabled = "enabled".equals(element.getAttribute(ATT_USE_PREPOST));
BeanDefinition preInvocationVoter = null;
// Now create a Map<String, ConfigAttribute> for each <protect-pointcut> sub-element
Map<String, List<ConfigAttribute>> pointcutMap = parseProtectPointcuts(parserContext,
DomUtils.getChildElementsByTagName(element, Elements.PROTECT_POINTCUT));
DomUtils.getChildElementsByTagName(element, PROTECT_POINTCUT));
if (pointcutMap.size() > 0) {
// SEC-1016: Put the pointcut MDS first, but only add it if there are actually any pointcuts defined.
@ -89,39 +93,70 @@ class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionParser {
registerProtectPointcutPostProcessor(parserContext, pointcutMap, mapBasedMethodSecurityMetadataSource, source);
}
if (expressionsEnabled) {
Element expressionHandlerElt = DomUtils.getChildElementByTagName(element, Elements.EXPRESSION_HANDLER);
String expressionHandlerRef = expressionHandlerElt == null ? null : expressionHandlerElt.getAttribute("ref");
if (prePostAnnotationsEnabled) {
Element prePostElt = DomUtils.getChildElementByTagName(element, INVOCATION_HANDLING);
Element expressionHandlerElt = DomUtils.getChildElementByTagName(element, EXPRESSION_HANDLER);
if (StringUtils.hasText(expressionHandlerRef)) {
logger.info("Using bean '" + expressionHandlerRef + "' as method SecurityExpressionHandler implementation");
} else {
parserContext.getRegistry().registerBeanDefinition(EXPRESSION_HANDLER_ID, new RootBeanDefinition(DefaultMethodSecurityExpressionHandler.class));
logger.warn("Expressions were enabled for method security but no SecurityExpressionHandler was configured. " +
"All hasPermision() expressions will evaluate to false.");
expressionHandlerRef = EXPRESSION_HANDLER_ID;
if (prePostElt != null && expressionHandlerElt != null) {
parserContext.getReaderContext().error(INVOCATION_HANDLING + " and " +
EXPRESSION_HANDLER + " cannot be used together ", source);
}
BeanDefinitionBuilder expressionVoterBldr = BeanDefinitionBuilder.rootBeanDefinition(MethodExpressionVoter.class);
BeanDefinitionBuilder afterInvocationProvider = BeanDefinitionBuilder.rootBeanDefinition(MethodExpressionAfterInvocationProvider.class);
expressionVoterBldr.addPropertyReference("expressionHandler", expressionHandlerRef);
expressionVoter = expressionVoterBldr.getBeanDefinition();
// After-invocation provider to handle post-invocation filtering and authorization expression annotations.
afterInvocationProvider.addPropertyReference("expressionHandler", expressionHandlerRef);
ConfigUtils.getRegisteredAfterInvocationProviders(parserContext).add(afterInvocationProvider.getBeanDefinition());
// Add the expression method definition source, which will obtain its parser from the registered expression
// handler
BeanDefinitionBuilder mds = BeanDefinitionBuilder.rootBeanDefinition(EXPRESSION_METHOD_DEFINITION_SOURCE_CLASS);
mds.addConstructorArgReference(expressionHandlerRef);
BeanDefinitionBuilder preInvocationVoterBldr = BeanDefinitionBuilder.rootBeanDefinition(PreInvocationAuthorizationAdviceVoter.class);
// After-invocation provider to handle post-invocation filtering and authorization expression annotations.
BeanDefinitionBuilder afterInvocationBldr = BeanDefinitionBuilder.rootBeanDefinition(PostInvocationAdviceProvider.class);
// The metadata source for the security interceptor
BeanDefinitionBuilder mds = BeanDefinitionBuilder.rootBeanDefinition(PrePostAnnotationSecurityMetadataSource.class);
if (prePostElt != null) {
// Customized override of expression handling system
String attributeFactoryRef =
DomUtils.getChildElementByTagName(prePostElt, INVOCATION_ATTRIBUTE_FACTORY).getAttribute("ref");
String preAdviceRef =
DomUtils.getChildElementByTagName(prePostElt, PRE_INVOCATION_ADVICE).getAttribute("ref");
String postAdviceRef =
DomUtils.getChildElementByTagName(prePostElt, POST_INVOCATION_ADVICE).getAttribute("ref");
mds.addConstructorArgReference(attributeFactoryRef);
preInvocationVoterBldr.addConstructorArgReference(preAdviceRef);
afterInvocationBldr.addConstructorArgReference(postAdviceRef);
} else {
// The default expression-based system
String expressionHandlerRef = expressionHandlerElt == null ? null : expressionHandlerElt.getAttribute("ref");
if (StringUtils.hasText(expressionHandlerRef)) {
logger.info("Using bean '" + expressionHandlerRef + "' as method ExpressionHandler implementation");
} else {
parserContext.getRegistry().registerBeanDefinition(EXPRESSION_HANDLER_ID, new RootBeanDefinition(DefaultMethodSecurityExpressionHandler.class));
logger.warn("Expressions were enabled for method security but no SecurityExpressionHandler was configured. " +
"All hasPermision() expressions will evaluate to false.");
expressionHandlerRef = EXPRESSION_HANDLER_ID;
}
BeanDefinitionBuilder expressionPreAdviceBldr = BeanDefinitionBuilder.rootBeanDefinition(ExpressionBasedPreInvocationAdvice.class);
expressionPreAdviceBldr.addPropertyReference("expressionHandler", expressionHandlerRef);
preInvocationVoterBldr.addConstructorArgValue(expressionPreAdviceBldr.getBeanDefinition());
BeanDefinitionBuilder expressionPostAdviceBldr = BeanDefinitionBuilder.rootBeanDefinition(ExpressionBasedPostInvocationAdvice.class);
expressionPostAdviceBldr.addConstructorArgReference(expressionHandlerRef);
afterInvocationBldr.addConstructorArgValue(expressionPostAdviceBldr.getBeanDefinition());
BeanDefinitionBuilder annotationInvocationFactory = BeanDefinitionBuilder.rootBeanDefinition(ExpressionBasedAnnotationAttributeFactory.class);
annotationInvocationFactory.addConstructorArgReference(expressionHandlerRef);
mds.addConstructorArgValue(annotationInvocationFactory.getBeanDefinition());
}
preInvocationVoter = preInvocationVoterBldr.getBeanDefinition();
ConfigUtils.getRegisteredAfterInvocationProviders(parserContext).add(afterInvocationBldr.getBeanDefinition());
delegates.add(mds.getBeanDefinition());
}
if (useSecured) {
delegates.add(BeanDefinitionBuilder.rootBeanDefinition(SECURED_METHOD_DEFINITION_SOURCE_CLASS).getBeanDefinition());
delegates.add(BeanDefinitionBuilder.rootBeanDefinition(SecuredAnnotationSecurityMetadataSource.class).getBeanDefinition());
}
if (jsr250Enabled) {
delegates.add(BeanDefinitionBuilder.rootBeanDefinition(JSR_250_SECURITY_METHOD_DEFINITION_SOURCE_CLASS).getBeanDefinition());
delegates.add(BeanDefinitionBuilder.rootBeanDefinition(Jsr250MethodSecurityMetadataSource.class).getBeanDefinition());
}
registerDelegatingMethodSecurityMetadataSource(parserContext, delegates, source);
@ -129,7 +164,7 @@ class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionParser {
String accessManagerId = element.getAttribute(ATT_ACCESS_MGR);
if (!StringUtils.hasText(accessManagerId)) {
registerAccessManager(parserContext, jsr250Enabled, expressionVoter);
registerAccessManager(parserContext, jsr250Enabled, preInvocationVoter);
accessManagerId = ACCESS_MANAGER_ID;
}
@ -161,7 +196,7 @@ class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionParser {
voters.add(new RootBeanDefinition(AuthenticatedVoter.class));
if (jsr250Enabled) {
voters.add(new RootBeanDefinition(JSR_250_VOTER_CLASS, null, null));
voters.add(new RootBeanDefinition(Jsr250Voter.class));
}
accessMgrBuilder.addPropertyValue("decisionVoters", voters);

View File

@ -5,8 +5,8 @@ import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.security.authentication.dao.salt.ReflectionSaltSource;
import org.springframework.security.authentication.dao.salt.SystemWideSaltSource;
import org.springframework.security.authentication.dao.ReflectionSaltSource;
import org.springframework.security.authentication.dao.SystemWideSaltSource;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;

View File

@ -184,10 +184,10 @@ protect.attlist &=
global-method-security =
## Provides method security for all beans registered in the Spring application context. Specifically, beans will be scanned for matches with the ordered list of "protect-pointcut" sub-elements, Spring Security annotations and/or. Where there is a match, the beans will automatically be proxied and security authorization applied to the methods accordingly. If you use and enable all four sources of method security metadata (ie "protect-pointcut" declarations, expression annotations, @Secured and also JSR250 security annotations), the metadata sources will be queried in that order. In practical terms, this enables you to use XML to override method security metadata expressed in annotations. If using annotations, the order of precedence is EL-based (@PreAuthorize etc.), @Secured and finally JSR-250.
element global-method-security {global-method-security.attlist, expression-handler?, protect-pointcut*}
element global-method-security {global-method-security.attlist, (pre-post-annotation-handling | expression-handler)?, protect-pointcut*}
global-method-security.attlist &=
## Specifies whether the use of Spring Security's expression-based annotations (@PreFilter, @PreAuthorize, @PostFilter, @PostAuthorize) should be enabled for this application context. Defaults to "disabled".
attribute expression-annotations {"disabled" | "enabled" }?
## Specifies whether the use of Spring Security's pre and post invocation annotations (@PreFilter, @PreAuthorize, @PostFilter, @PostAuthorize) should be enabled for this application context. Defaults to "disabled".
attribute pre-post-annotations {"disabled" | "enabled" }?
global-method-security.attlist &=
## Specifies whether the use of Spring Security's @Secured annotations should be enabled for this application context. Defaults to "disabled".
attribute secured-annotations {"disabled" | "enabled" }?
@ -201,6 +201,21 @@ global-method-security.attlist &=
## Optional RunAsmanager implementation which will be used by the configured MethodSecurityInterceptor
attribute run-as-manager-ref {xsd:token}?
pre-post-annotation-handling =
## Allows the default expression-based mechanism for handling Spring Security's pre and post invocation annotations (@PreFilter, @PreAuthorize, @PostFilter, @PostAuthorize) to be replace entirely. Only applies if these annotations are enabled.
element pre-post-annotation-handling {invocation-attribute-factory, pre-invocation-advice, post-invocation-advice}
invocation-attribute-factory =
## Defines the PrePostInvocationAttributeFactory instance which is used to generate pre and post invocation metadata from the annotated methods.
element invocation-attribute-factory {ref}
pre-invocation-advice =
element pre-invocation-advice {ref}
post-invocation-advice =
element post-invocation-advice {ref}
expression-handler =
## Defines the SecurityExpressionHandler instance which will be used if expression-based access-control is enabled. A default implementation (with no ACL support) will be used if not supplied.
element expression-handler {ref}

View File

@ -10,7 +10,7 @@
<xsl:output method="xml" indent="yes"/>
<xsl:variable name="elts-to-inline">
<xsl:text>,access-denied-handler,anonymous,concurrent-session-control,filter-chain,form-login,http-basic,intercept-url,logout,password-encoder,port-mappings,port-mapper,password-compare,protect,protect-pointcut,remember-me,salt-source,x509,</xsl:text>
<xsl:text>,access-denied-handler,anonymous,concurrent-session-control,filter-chain,form-login,http-basic,intercept-url,logout,password-encoder,port-mappings,port-mapper,password-compare,protect,protect-pointcut,pre-post-annotation-handling,pre-invocation-advice,post-invocation-advice,invocation-attribute-factory,remember-me,salt-source,x509,</xsl:text>
</xsl:variable>
<xsl:template match="xs:element">

View File

@ -5,6 +5,7 @@ import static org.junit.Assert.*;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.dao.ReflectionSaltSource;
import org.springframework.security.authentication.encoding.ShaPasswordEncoder;
import org.springframework.security.config.util.InMemoryXmlApplicationContext;
import org.springframework.security.util.FieldUtils;
@ -111,7 +112,7 @@ public class AuthenticationProviderBeanDefinitionParserTests {
" <b:bean id='customPasswordEncoder' " +
"class='org.springframework.security.authentication.encoding.Md5PasswordEncoder'/>" +
" <b:bean id='saltSource' " +
" class='org.springframework.security.authentication.dao.salt.ReflectionSaltSource'>" +
" class='" + ReflectionSaltSource.class.getName() +"'>" +
" <b:property name='userPropertyToUse' value='username'/>" +
" </b:bean>" +
" <b:bean id='customUserService' " +

View File

@ -2,7 +2,6 @@ package org.springframework.security.config;
import static org.junit.Assert.*;
import static org.springframework.security.config.ConfigTestUtils.AUTH_PROVIDER_XML;
import static org.springframework.security.config.GlobalMethodSecurityBeanDefinitionParser.*;
import java.util.ArrayList;
import java.util.List;
@ -16,14 +15,10 @@ import org.springframework.context.support.AbstractXmlApplicationContext;
import org.springframework.context.support.StaticApplicationContext;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.annotation.BusinessService;
import org.springframework.security.access.annotation.Jsr250MethodSecurityMetadataSource;
import org.springframework.security.access.annotation.Jsr250Voter;
import org.springframework.security.access.annotation.SecuredMethodSecurityMetadataSource;
import org.springframework.security.access.expression.method.ExpressionAnnotationMethodSecurityMetadataSource;
import org.springframework.security.access.expression.method.MethodExpressionAfterInvocationProvider;
import org.springframework.security.access.expression.method.MethodExpressionVoter;
import org.springframework.security.access.intercept.AfterInvocationProviderManager;
import org.springframework.security.access.intercept.RunAsManagerImpl;
import org.springframework.security.access.prepost.PostInvocationAdviceProvider;
import org.springframework.security.access.prepost.PreInvocationAuthorizationAdviceVoter;
import org.springframework.security.access.vote.AffirmativeBased;
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
import org.springframework.security.authentication.TestingAuthenticationToken;
@ -65,14 +60,6 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
target = null;
}
@Test
public void beanClassNamesAreCorrect() throws Exception {
assertEquals(SecuredMethodSecurityMetadataSource.class.getName(), SECURED_METHOD_DEFINITION_SOURCE_CLASS);
assertEquals(ExpressionAnnotationMethodSecurityMetadataSource.class.getName(), EXPRESSION_METHOD_DEFINITION_SOURCE_CLASS);
assertEquals(Jsr250MethodSecurityMetadataSource.class.getName(), JSR_250_SECURITY_METHOD_DEFINITION_SOURCE_CLASS);
assertEquals(Jsr250Voter.class.getName(), JSR_250_VOTER_CLASS);
}
@Test(expected=AuthenticationCredentialsNotFoundException.class)
public void targetShouldPreventProtectedMethodInvocationWithNoContext() {
loadContext();
@ -211,19 +198,19 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
@SuppressWarnings("unchecked")
@Test
public void expressionVoterAndAfterInvocationProviderUseSameExpressionHandlerInstance() throws Exception {
setContext("<global-method-security expression-annotations='enabled'/>" + AUTH_PROVIDER_XML);
setContext("<global-method-security pre-post-annotations='enabled'/>" + AUTH_PROVIDER_XML);
AffirmativeBased adm = (AffirmativeBased) appContext.getBean(GlobalMethodSecurityBeanDefinitionParser.ACCESS_MANAGER_ID);
List voters = (List) FieldUtils.getFieldValue(adm, "decisionVoters");
MethodExpressionVoter mev = (MethodExpressionVoter) voters.get(0);
PreInvocationAuthorizationAdviceVoter mev = (PreInvocationAuthorizationAdviceVoter) voters.get(0);
AfterInvocationProviderManager pm = (AfterInvocationProviderManager) appContext.getBean(BeanIds.AFTER_INVOCATION_MANAGER);
MethodExpressionAfterInvocationProvider aip = (MethodExpressionAfterInvocationProvider) pm.getProviders().get(0);
assertTrue(FieldUtils.getFieldValue(mev, "expressionHandler") == FieldUtils.getFieldValue(aip, "expressionHandler"));
PostInvocationAdviceProvider aip = (PostInvocationAdviceProvider) pm.getProviders().get(0);
assertTrue(FieldUtils.getFieldValue(mev, "preAdvice.expressionHandler") == FieldUtils.getFieldValue(aip, "postAdvice.expressionHandler"));
}
@Test(expected=AccessDeniedException.class)
public void accessIsDeniedForHasRoleExpression() {
setContext(
"<global-method-security expression-annotations='enabled'/>" +
"<global-method-security pre-post-annotations='enabled'/>" +
"<b:bean id='target' class='org.springframework.security.access.annotation.ExpressionProtectedBusinessServiceImpl'/>" +
AUTH_PROVIDER_XML);
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken("bob","bobspassword"));
@ -234,7 +221,7 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
@Test
public void preAndPostFilterAnnotationsWorkWithLists() {
setContext(
"<global-method-security expression-annotations='enabled'/>" +
"<global-method-security pre-post-annotations='enabled'/>" +
"<b:bean id='target' class='org.springframework.security.access.annotation.ExpressionProtectedBusinessServiceImpl'/>" +
AUTH_PROVIDER_XML);
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken("bob","bobspassword"));
@ -253,7 +240,7 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
@Test
public void prePostFilterAnnotationWorksWithArrays() {
setContext(
"<global-method-security expression-annotations='enabled'/>" +
"<global-method-security pre-post-annotations='enabled'/>" +
"<b:bean id='target' class='org.springframework.security.access.annotation.ExpressionProtectedBusinessServiceImpl'/>" +
AUTH_PROVIDER_XML);
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken("bob","bobspassword"));

View File

@ -13,9 +13,11 @@
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/security ../../main/resources/org/springframework/security/config/spring-security-3.0.xsd">
<global-method-security run-as-manager-ref="myRunAsManager">
<expression-handler ref="myExpressionhandler"/>
<pre-post-annotation-handling>
<
</pre-post-annotation-handling>
</global-method-security>
<http>

View File

@ -1,4 +1,4 @@
package org.springframework.security.access.expression;
package org.springframework.security.access;
import java.io.Serializable;
@ -11,7 +11,7 @@ import org.springframework.security.core.Authentication;
*
* @author Luke Taylor
* @version $Id$
* @since 2.5
* @since 3.0
*/
public interface PermissionEvaluator {
/**

View File

@ -47,9 +47,9 @@ import java.lang.annotation.Target;
@Inherited
@Documented
public @interface Secured {
/**
* Returns the list of security configuration attributes.
* (i.e. ROLE_USER, ROLE_ADMIN etc.)
/**
* Returns the list of security configuration attributes (e.g. ROLE_USER, ROLE_ADMIN).
*
* @return String[] The secure method attributes
*/
public String[] value();

View File

@ -33,7 +33,7 @@ import org.springframework.security.access.intercept.method.AbstractFallbackMeth
* @author Ben Alex
* @version $Id$
*/
public class SecuredMethodSecurityMetadataSource extends AbstractFallbackMethodSecurityMetadataSource {
public class SecuredAnnotationSecurityMetadataSource extends AbstractFallbackMethodSecurityMetadataSource {
protected List<ConfigAttribute> findAttributes(Class<?> clazz) {
return processAnnotation(clazz.getAnnotation(Secured.class));

View File

@ -4,7 +4,7 @@ import org.springframework.expression.EvaluationContext;
import org.springframework.expression.EvaluationException;
import org.springframework.expression.Expression;
public class ExpressionUtils {
public final class ExpressionUtils {
public static boolean evaluateAsBoolean(Expression expr, EvaluationContext ctx) {
try {

View File

@ -1,4 +1,4 @@
package org.springframework.security.access.expression.support;
package org.springframework.security.access.expression;
import java.util.Set;
@ -13,7 +13,7 @@ import org.springframework.security.core.authority.AuthorityUtils;
*
* @author Luke Taylor
* @version $Id$
* @since 2.5
* @since 3.0
*/
public abstract class SecurityExpressionRoot {
protected final Authentication authentication;

View File

@ -15,7 +15,7 @@ import org.springframework.util.Assert;
*
* @author Luke Taylor
* @version $Id$
* @since 2.5
* @since 3.0
*/
abstract class AbstractExpressionBasedMethodConfigAttribute implements ConfigAttribute {
private final Expression filterExpression;

View File

@ -1,4 +1,4 @@
package org.springframework.security.access.expression.support;
package org.springframework.security.access.expression.method;
import java.lang.reflect.Array;
import java.util.ArrayList;
@ -14,9 +14,9 @@ import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.antlr.SpelAntlrExpressionParser;
import org.springframework.security.access.PermissionEvaluator;
import org.springframework.security.access.expression.ExpressionUtils;
import org.springframework.security.access.expression.MethodSecurityExpressionHandler;
import org.springframework.security.access.expression.PermissionEvaluator;
import org.springframework.security.access.expression.SecurityExpressionRoot;
import org.springframework.security.authentication.AuthenticationTrustResolver;
import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
import org.springframework.security.core.Authentication;
@ -28,7 +28,7 @@ import org.springframework.security.core.Authentication;
*
* @author Luke Taylor
* @version $Id$
* @since 2.5
* @since 3.0
*/
public class DefaultMethodSecurityExpressionHandler implements MethodSecurityExpressionHandler {

View File

@ -1,10 +1,10 @@
package org.springframework.security.access.expression.support;
package org.springframework.security.access.expression.method;
import java.io.Serializable;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.access.expression.PermissionEvaluator;
import org.springframework.security.access.PermissionEvaluator;
import org.springframework.security.core.Authentication;
/**
@ -13,7 +13,7 @@ import org.springframework.security.core.Authentication;
*
* @author Luke Taylor
* @version $Id$
* @since 2.5
* @since 3.0
*/
class DenyAllPermissionEvaluator implements PermissionEvaluator {

View File

@ -0,0 +1,58 @@
/**
*
*/
package org.springframework.security.access.expression.method;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.ParseException;
import org.springframework.security.access.prepost.PostAuthorize;
import org.springframework.security.access.prepost.PostFilter;
import org.springframework.security.access.prepost.PostInvocationAttribute;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.access.prepost.PreFilter;
import org.springframework.security.access.prepost.PreInvocationAttribute;
import org.springframework.security.access.prepost.PrePostInvocationAttributeFactory;
/**
* {@link PrePostInvocationAttributeFactory} which interprets the annotation value as
* an expression to be evaluated at runtime.
*
* @author Luke Taylor
* @version $Id$
* @since 3.0
*/
public class ExpressionBasedAnnotationAttributeFactory implements PrePostInvocationAttributeFactory {
private ExpressionParser parser;
public ExpressionBasedAnnotationAttributeFactory(MethodSecurityExpressionHandler handler) {
parser = handler.getExpressionParser();
}
public PreInvocationAttribute createPreInvocationAttribute(PreFilter preFilter, PreAuthorize preAuthorize) {
try {
// TODO: Optimization of permitAll
Expression preAuthorizeExpression = preAuthorize == null ? parser.parseExpression("permitAll") : parser.parseExpression(preAuthorize.value());
Expression preFilterExpression = preFilter == null ? null : parser.parseExpression(preFilter.value());
String filterObject = preFilter == null ? null : preFilter.filterTarget();
return new PreInvocationExpressionAttribute(preFilterExpression, filterObject, preAuthorizeExpression);
} catch (ParseException e) {
throw new IllegalArgumentException("Failed to parse expression '" + e.getExpressionString() + "'", e);
}
}
public PostInvocationAttribute createPostInvocationAttribute(PostFilter postFilter, PostAuthorize postAuthorize) {
try {
Expression postAuthorizeExpression = postAuthorize == null ? null : parser.parseExpression(postAuthorize.value());
Expression postFilterExpression = postFilter == null ? null : parser.parseExpression(postFilter.value());
if (postFilterExpression != null || postAuthorizeExpression != null) {
return new PostInvocationExpressionAttribute(postFilterExpression, postAuthorizeExpression);
}
} catch (ParseException e) {
throw new IllegalArgumentException("Failed to parse expression '" + e.getExpressionString() + "'", e);
}
return null;
}
}

View File

@ -0,0 +1,61 @@
package org.springframework.security.access.expression.method;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.expression.ExpressionUtils;
import org.springframework.security.access.prepost.PostInvocationAttribute;
import org.springframework.security.access.prepost.PostInvocationAuthorizationAdvice;
import org.springframework.security.core.Authentication;
/**
*
* @author Luke Taylor
* @version $Id$
* @since 3.0
*/
public class ExpressionBasedPostInvocationAdvice implements PostInvocationAuthorizationAdvice{
protected final Log logger = LogFactory.getLog(getClass());
private MethodSecurityExpressionHandler expressionHandler;
public ExpressionBasedPostInvocationAdvice(MethodSecurityExpressionHandler expressionHandler) {
this.expressionHandler = expressionHandler;
}
public Object after(Authentication authentication, MethodInvocation mi,
PostInvocationAttribute postAttr, Object returnedObject) throws AccessDeniedException{
PostInvocationExpressionAttribute pia = (PostInvocationExpressionAttribute) postAttr;
EvaluationContext ctx = expressionHandler.createEvaluationContext(authentication, mi);
Expression postFilter = pia.getFilterExpression();
Expression postAuthorize = pia.getAuthorizeExpression();
if (postFilter != null) {
if (logger.isDebugEnabled()) {
logger.debug("Applying PostFilter expression " + postFilter);
}
if (returnedObject != null) {
returnedObject = expressionHandler.filter(returnedObject, postFilter, ctx);
} else {
if (logger.isDebugEnabled()) {
logger.debug("Return object is null, filtering will be skipped");
}
}
}
expressionHandler.setReturnObject(returnedObject, ctx);
if (postAuthorize != null && !ExpressionUtils.evaluateAsBoolean(postAuthorize, ctx)) {
if (logger.isDebugEnabled()) {
logger.debug("PostAuthorize expression rejected access");
}
throw new AccessDeniedException("Access is denied");
}
return returnedObject;
}
}

View File

@ -1,68 +1,47 @@
/**
*
*/
package org.springframework.security.access.expression.method;
import java.util.Collection;
import java.util.List;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.expression.ExpressionUtils;
import org.springframework.security.access.expression.MethodSecurityExpressionHandler;
import org.springframework.security.access.expression.support.DefaultMethodSecurityExpressionHandler;
import org.springframework.security.access.vote.AccessDecisionVoter;
import org.springframework.security.access.prepost.PreInvocationAttribute;
import org.springframework.security.access.prepost.PreInvocationAuthorizationAdvice;
import org.springframework.security.core.Authentication;
/**
* Voter which performs the actions for @PreFilter and @PostAuthorize annotations.
* <p>
* If only a @PreFilter condition is specified, it will vote to grant access, otherwise it will vote
* to grant or deny access depending on whether the @PostAuthorize expression evaluates to 'true' or 'false',
* to grant or deny access depending on whether the @PreAuthorize expression evaluates to 'true' or 'false',
* respectively.
*
* @author Luke Taylor
* @version $Id$
* @since 2.5
* @since
*/
public class MethodExpressionVoter implements AccessDecisionVoter {
protected final Log logger = LogFactory.getLog(getClass());
public class ExpressionBasedPreInvocationAdvice implements PreInvocationAuthorizationAdvice {
private MethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
public boolean supports(ConfigAttribute attribute) {
return attribute instanceof AbstractExpressionBasedMethodConfigAttribute;
}
public boolean supports(Class<?> clazz) {
return clazz.isAssignableFrom(MethodInvocation.class);
}
public int vote(Authentication authentication, Object object, List<ConfigAttribute> attributes) {
PreInvocationExpressionAttribute mace = findMethodAccessControlExpression(attributes);
if (mace == null) {
// No expression based metadata, so abstain
return ACCESS_ABSTAIN;
}
MethodInvocation mi = (MethodInvocation)object;
public boolean before(Authentication authentication, MethodInvocation mi, PreInvocationAttribute attr) {
PreInvocationExpressionAttribute preAttr = (PreInvocationExpressionAttribute) attr;
EvaluationContext ctx = expressionHandler.createEvaluationContext(authentication, mi);
Expression preFilter = mace.getFilterExpression();
Expression preAuthorize = mace.getAuthorizeExpression();
Expression preFilter = preAttr.getFilterExpression();
Expression preAuthorize = preAttr.getAuthorizeExpression();
if (preFilter != null) {
Object filterTarget = findFilterTarget(mace.getFilterTarget(), ctx, mi);
Object filterTarget = findFilterTarget(preAttr.getFilterTarget(), ctx, mi);
expressionHandler.filter(filterTarget, preFilter, ctx);
}
if (preAuthorize == null) {
return ACCESS_GRANTED;
return true;
}
return ExpressionUtils.evaluateAsBoolean(preAuthorize, ctx) ? ACCESS_GRANTED : ACCESS_DENIED;
return ExpressionUtils.evaluateAsBoolean(preAuthorize, ctx);
}
private Object findFilterTarget(String filterTargetName, EvaluationContext ctx, MethodInvocation mi) {
@ -94,16 +73,6 @@ public class MethodExpressionVoter implements AccessDecisionVoter {
return filterTarget;
}
private PreInvocationExpressionAttribute findMethodAccessControlExpression(List<ConfigAttribute> config) {
// Find the MethodAccessControlExpression attribute
for (ConfigAttribute attribute : config) {
if (attribute instanceof PreInvocationExpressionAttribute) {
return (PreInvocationExpressionAttribute)attribute;
}
}
return null;
}
public void setExpressionHandler(MethodSecurityExpressionHandler expressionHandler) {
this.expressionHandler = expressionHandler;

View File

@ -1,96 +0,0 @@
package org.springframework.security.access.expression.method;
import java.util.List;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.expression.ExpressionUtils;
import org.springframework.security.access.expression.MethodSecurityExpressionHandler;
import org.springframework.security.access.expression.support.DefaultMethodSecurityExpressionHandler;
import org.springframework.security.access.intercept.AfterInvocationProvider;
import org.springframework.security.core.Authentication;
/**
* AfterInvocationProvider which handles the @PostAuthorize and @PostFilter annotation expressions.
*
* @author Luke Taylor
* @verson $Id$
* @since 2.5
*/
public class MethodExpressionAfterInvocationProvider implements AfterInvocationProvider {
protected final Log logger = LogFactory.getLog(getClass());
private MethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
public Object decide(Authentication authentication, Object object, List<ConfigAttribute> config, Object returnedObject)
throws AccessDeniedException {
PostInvocationExpressionAttribute mca = findMethodAccessControlExpression(config);
if (mca == null) {
return returnedObject;
}
EvaluationContext ctx =
expressionHandler.createEvaluationContext(authentication, (MethodInvocation)object);
//SecurityExpressionRoot expressionRoot = new SecurityExpressionRoot(authentication);
//ctx.setRootObject(expressionRoot);
Expression postFilter = mca.getFilterExpression();
Expression postAuthorize = mca.getAuthorizeExpression();
if (postFilter != null) {
if (logger.isDebugEnabled()) {
logger.debug("Applying PostFilter expression " + postFilter);
}
if (returnedObject != null) {
returnedObject = expressionHandler.filter(returnedObject, postFilter, ctx);
} else {
if (logger.isDebugEnabled()) {
logger.debug("Return object is null, filtering will be skipped");
}
}
}
expressionHandler.setReturnObject(returnedObject, ctx);
if (postAuthorize != null && !ExpressionUtils.evaluateAsBoolean(postAuthorize, ctx)) {
if (logger.isDebugEnabled()) {
logger.debug("PostAuthorize expression rejected access");
}
throw new AccessDeniedException("Access is denied");
}
return returnedObject;
}
private PostInvocationExpressionAttribute findMethodAccessControlExpression(List<ConfigAttribute> config) {
// Find the MethodAccessControlExpression attribute
for (ConfigAttribute attribute : config) {
if (attribute instanceof PostInvocationExpressionAttribute) {
return (PostInvocationExpressionAttribute)attribute;
}
}
return null;
}
public boolean supports(ConfigAttribute attribute) {
return attribute instanceof PostInvocationExpressionAttribute;
}
public boolean supports(Class<?> clazz) {
return clazz.isAssignableFrom(MethodInvocation.class);
}
public void setExpressionHandler(MethodSecurityExpressionHandler expressionHandler) {
this.expressionHandler = expressionHandler;
}
}

View File

@ -1,4 +1,4 @@
package org.springframework.security.access.expression.support;
package org.springframework.security.access.expression.method;
import java.lang.reflect.Method;
@ -15,7 +15,7 @@ import org.springframework.util.ClassUtils;
* and when they are required.
*
* @author Luke Taylor
* @since 2.5
* @since 3.0
*/
class MethodSecurityEvaluationContext extends StandardEvaluationContext {
private ParameterNameDiscoverer parameterNameDiscoverer;

View File

@ -1,4 +1,4 @@
package org.springframework.security.access.expression;
package org.springframework.security.access.expression.method;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.expression.EvaluationContext;
@ -12,7 +12,7 @@ import org.springframework.security.core.Authentication;
*
* @author Luke Taylor
* @version $Id$
* @since 2.5
* @since 3.0
*/
public interface MethodSecurityExpressionHandler {
/**

View File

@ -1,8 +1,9 @@
package org.springframework.security.access.expression.support;
package org.springframework.security.access.expression.method;
import java.io.Serializable;
import org.springframework.security.access.expression.PermissionEvaluator;
import org.springframework.security.access.PermissionEvaluator;
import org.springframework.security.access.expression.SecurityExpressionRoot;
import org.springframework.security.core.Authentication;
@ -11,7 +12,7 @@ import org.springframework.security.core.Authentication;
*
* @author Luke Taylor
* @version $Id$
* @since 2.5
* @since 3.0
*/
class MethodSecurityExpressionRoot extends SecurityExpressionRoot {
private PermissionEvaluator permissionEvaluator;

View File

@ -2,8 +2,16 @@ package org.springframework.security.access.expression.method;
import org.springframework.expression.Expression;
import org.springframework.expression.ParseException;
import org.springframework.security.access.prepost.PostInvocationAttribute;
class PostInvocationExpressionAttribute extends AbstractExpressionBasedMethodConfigAttribute {
/**
*
* @author Luke Taylor
* @version $Id$
* @since 3.0
*/
class PostInvocationExpressionAttribute extends AbstractExpressionBasedMethodConfigAttribute
implements PostInvocationAttribute {
PostInvocationExpressionAttribute(String filterExpression, String authorizeExpression)
throws ParseException {

View File

@ -2,8 +2,17 @@ package org.springframework.security.access.expression.method;
import org.springframework.expression.Expression;
import org.springframework.expression.ParseException;
import org.springframework.security.access.prepost.PreInvocationAttribute;
/**
*
* @author Luke Taylor
* @version $Id$
* @since 3.0
*/
class PreInvocationExpressionAttribute extends AbstractExpressionBasedMethodConfigAttribute
implements PreInvocationAttribute {
class PreInvocationExpressionAttribute extends AbstractExpressionBasedMethodConfigAttribute {
private final String filterTarget;
PreInvocationExpressionAttribute(String filterExpression, String filterTarget, String authorizeExpression)

View File

@ -0,0 +1,2 @@
Expression handling code to support the use of Spring-EL based expressions in @PreAuthorize, @PreFilter,
@PostAuthorizue and @PostFilter annotations. Mainly for internal framework use and liable to change.

View File

@ -1,5 +0,0 @@
package org.springframework.security.access.expression.support;
public class AbstractSecurityExpressionHandler {
}

View File

@ -1,4 +1,4 @@
package org.springframework.security.access.expression.annotation;
package org.springframework.security.access.prepost;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
@ -12,7 +12,7 @@ import java.lang.annotation.Target;
*
* @author Luke Taylor
* @version $Id$
* @since 2.5
* @since 3.0
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)

View File

@ -1,4 +1,4 @@
package org.springframework.security.access.expression.annotation;
package org.springframework.security.access.prepost;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
@ -12,7 +12,7 @@ import java.lang.annotation.Target;
*
* @author Luke Taylor
* @version $Id$
* @since 2.5
* @since 3.0
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)

View File

@ -0,0 +1,59 @@
package org.springframework.security.access.prepost;
import java.util.List;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.intercept.AfterInvocationProvider;
import org.springframework.security.core.Authentication;
/**
* <tt>AfterInvocationProvider</tt> which delegates to a {@link PostInvocationAuthorizationAdvice} instance
* passing it the <tt>PostInvocationAttribute</tt> created from @PostAuthorize and @PostFilter annotations.
*
* @author Luke Taylor
* @version $Id$
* @since 3.0
*/
public class PostInvocationAdviceProvider implements AfterInvocationProvider {
protected final Log logger = LogFactory.getLog(getClass());
private PostInvocationAuthorizationAdvice postAdvice;
public PostInvocationAdviceProvider(PostInvocationAuthorizationAdvice postAdvice) {
this.postAdvice = postAdvice;
}
public Object decide(Authentication authentication, Object object, List<ConfigAttribute> config, Object returnedObject)
throws AccessDeniedException {
PostInvocationAttribute pia = findPostInvocationAttribute(config);
if (pia == null) {
return returnedObject;
}
return postAdvice.after(authentication, (MethodInvocation)object, pia, returnedObject);
}
private PostInvocationAttribute findPostInvocationAttribute(List<ConfigAttribute> config) {
for (ConfigAttribute attribute : config) {
if (attribute instanceof PostInvocationAttribute) {
return (PostInvocationAttribute)attribute;
}
}
return null;
}
public boolean supports(ConfigAttribute attribute) {
return attribute instanceof PostInvocationAttribute;
}
public boolean supports(Class<?> clazz) {
return clazz.isAssignableFrom(MethodInvocation.class);
}
}

View File

@ -0,0 +1,16 @@
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.
* <p>
* Consumed by a {@link PostInvocationAuthorizationAdvice}.
*
* @author Luke Taylor
* @version $Id$
* @since 3.0
*/
public interface PostInvocationAttribute extends ConfigAttribute{
}

View File

@ -0,0 +1,18 @@
package org.springframework.security.access.prepost;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.core.Authentication;
/**
* Performs filtering and authorization logic after a method is invoked.
*
* @author Luke Taylor
* @version $Id$
* @since 3.0
*/
public interface PostInvocationAuthorizationAdvice {
Object after(Authentication authentication, MethodInvocation mi,
PostInvocationAttribute pia, Object returnedObject) throws AccessDeniedException;
}

View File

@ -1,4 +1,4 @@
package org.springframework.security.access.expression.annotation;
package org.springframework.security.access.prepost;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
@ -13,7 +13,7 @@ import java.lang.annotation.Target;
*
* @author Luke Taylor
* @version $Id$
* @since 2.5
* @since 3.0
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)

View File

@ -1,4 +1,4 @@
package org.springframework.security.access.expression.annotation;
package org.springframework.security.access.prepost;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
@ -23,7 +23,7 @@ import java.lang.annotation.Target;
*
* @author Luke Taylor
* @version $Id$
* @since 2.5
* @since 3.0
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)

View File

@ -0,0 +1,16 @@
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.
* <p>
* Consumed by a {@link PreInvocationAuthorizationAdvice}.
*
* @author Luke Taylor
* @version $Id$
* @since 3.0
*/
public interface PreInvocationAttribute extends ConfigAttribute{
}

View File

@ -0,0 +1,16 @@
package org.springframework.security.access.prepost;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.security.core.Authentication;
/**
* Performs argument filtering and authorization logic before a method is invoked.
*
* @author Luke Taylor
* @version $Id$
* @since 3.0
*/
public interface PreInvocationAuthorizationAdvice {
boolean before(Authentication authentication, MethodInvocation mi, PreInvocationAttribute preInvocationAttribute);
}

View File

@ -0,0 +1,69 @@
package org.springframework.security.access.prepost;
import java.util.List;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.vote.AccessDecisionVoter;
import org.springframework.security.core.Authentication;
/**
* Voter which performs the actions using a PreInvocationAuthorizationAdvice implementation
* generated from @PreFilter and @PreAuthorize annotations.
* <p>
* In practice, if these annotations are being used, they will normally contain all the necessary
* access control logic, so a voter-based system is not really necessary and a single <tt>AccessDecisionManager</tt>
* which contained the same logic would suffice. However, this class fits in readily with the traditional
* voter-based <tt>AccessDecisionManager</tt> implementations used by Spring Security.
*
* @author Luke Taylor
* @version $Id$
* @since 3.0
*/
public class PreInvocationAuthorizationAdviceVoter implements AccessDecisionVoter {
protected final Log logger = LogFactory.getLog(getClass());
private PreInvocationAuthorizationAdvice preAdvice;
public PreInvocationAuthorizationAdviceVoter(PreInvocationAuthorizationAdvice pre) {
this.preAdvice = pre;
}
public boolean supports(ConfigAttribute attribute) {
return attribute instanceof PreInvocationAuthorizationAdvice;
}
public boolean supports(Class<?> clazz) {
return clazz.isAssignableFrom(MethodInvocation.class);
}
public int vote(Authentication authentication, Object object, List<ConfigAttribute> attributes) {
// Find prefilter and preauth (or combined) attributes
// if both null, abstain
// else call advice with them
PreInvocationAttribute preAttr = findPreInvocationAttribute(attributes);
if (preAttr == null) {
// No expression based metadata, so abstain
return ACCESS_ABSTAIN;
}
boolean allowed = preAdvice.before(authentication, (MethodInvocation)object, preAttr);
return allowed ? ACCESS_GRANTED : ACCESS_DENIED;
}
private PreInvocationAttribute findPreInvocationAttribute(List<ConfigAttribute> config) {
for (ConfigAttribute attribute : config) {
if (attribute instanceof PreInvocationAttribute) {
return (PreInvocationAttribute)attribute;
}
}
return null;
}
}

View File

@ -1,4 +1,4 @@
package org.springframework.security.access.expression.method;
package org.springframework.security.access.prepost;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
@ -7,22 +7,15 @@ import java.util.Collection;
import java.util.List;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.ParseException;
import org.springframework.expression.spel.antlr.SpelAntlrExpressionParser;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.expression.MethodSecurityExpressionHandler;
import org.springframework.security.access.expression.annotation.PostAuthorize;
import org.springframework.security.access.expression.annotation.PostFilter;
import org.springframework.security.access.expression.annotation.PreAuthorize;
import org.springframework.security.access.expression.annotation.PreFilter;
import org.springframework.security.access.intercept.method.AbstractMethodSecurityMetadataSource;
import org.springframework.util.ClassUtils;
/**
* <tt>MethodSecurityMetadataSource</tt> which extracts metadata from the @PreFilter and @PreAuthorize annotations
* placed on a method. The metadata is encapsulated in a {@link AbstractExpressionBasedMethodConfigAttribute} instance.
* 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 condition, then the method will be
@ -31,25 +24,18 @@ import org.springframework.util.ClassUtils;
* Since we are handling multiple annotations here, it's possible that we may have to combine annotations defined in
* multiple locations for a single method - they may be defined on the method itself, or at interface or class level.
*
* @see MethodExpressionVoter
* @see PreInvocationAuthorizationAdviceVoter
*
* @author Luke Taylor
* @since 2.5
* @since 3.0
* @version $Id$
*/
public class ExpressionAnnotationMethodSecurityMetadataSource extends AbstractMethodSecurityMetadataSource {
private ExpressionParser parser;
public class PrePostAnnotationSecurityMetadataSource extends AbstractMethodSecurityMetadataSource {
public ExpressionAnnotationMethodSecurityMetadataSource() {
parser = new SpelAntlrExpressionParser();
}
private final PrePostInvocationAttributeFactory attributeFactory;
/**
* Constructor which obtains the expression parser from the {@link MethodSecurityExpressionHandler#getExpressionParser() }
* method on the supplied <tt>SecurityExpressionHandler</tt>.
*/
public ExpressionAnnotationMethodSecurityMetadataSource(MethodSecurityExpressionHandler handler) {
parser = handler.getExpressionParser();
public PrePostAnnotationSecurityMetadataSource(PrePostInvocationAttributeFactory attributeFactory) {
this.attributeFactory = attributeFactory;
}
public List<ConfigAttribute> getAttributes(Method method, Class<?> targetClass) {
@ -57,7 +43,7 @@ public class ExpressionAnnotationMethodSecurityMetadataSource extends AbstractMe
return null;
}
logger.trace("Looking for expression annotations for method '" +
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);
@ -71,7 +57,27 @@ public class ExpressionAnnotationMethodSecurityMetadataSource extends AbstractMe
return null;
}
return createAttributeList(preFilter, preAuthorize, postFilter, postAuthorize);
ArrayList<ConfigAttribute> attrs = new ArrayList<ConfigAttribute>();
PreInvocationAttribute pre = attributeFactory.createPreInvocationAttribute(preFilter, preAuthorize);
if (pre != null) {
attrs.add(pre);
}
PostInvocationAttribute post = attributeFactory.createPostInvocationAttribute(postFilter, postAuthorize);
if (post != null) {
attrs.add(post);
}
attrs.trimToSize();
return attrs.isEmpty() ? null : attrs;
}
public Collection<ConfigAttribute> getAllConfigAttributes() {
return null;
}
/**
@ -121,40 +127,4 @@ public class ExpressionAnnotationMethodSecurityMetadataSource extends AbstractMe
return null;
}
public Collection<ConfigAttribute> getAllConfigAttributes() {
return null;
}
private List<ConfigAttribute> createAttributeList(PreFilter preFilter, PreAuthorize preAuthorize,
PostFilter postFilter, PostAuthorize postAuthorize) {
ConfigAttribute pre = null;
ConfigAttribute post = null;
// TODO: Optimization of permitAll
try {
Expression preAuthorizeExpression = preAuthorize == null ? parser.parseExpression("permitAll") : parser.parseExpression(preAuthorize.value());
Expression preFilterExpression = preFilter == null ? null : parser.parseExpression(preFilter.value());
String filterObject = preFilter == null ? null : preFilter.filterTarget();
Expression postAuthorizeExpression = postAuthorize == null ? null : parser.parseExpression(postAuthorize.value());
Expression postFilterExpression = postFilter == null ? null : parser.parseExpression(postFilter.value());
pre = new PreInvocationExpressionAttribute(preFilterExpression, filterObject, preAuthorizeExpression);
if (postFilterExpression != null || postAuthorizeExpression != null) {
post = new PostInvocationExpressionAttribute(postFilterExpression, postAuthorizeExpression);
}
} catch (ParseException e) {
throw new IllegalArgumentException("Failed to parse expression '" + e.getExpressionString() + "'", e);
}
List<ConfigAttribute> attrs = new ArrayList<ConfigAttribute>(2);
if (pre != null) {
attrs.add(pre);
}
if (post != null) {
attrs.add(post);
}
return attrs;
}
}

View File

@ -0,0 +1,14 @@
package org.springframework.security.access.prepost;
/**
*
* @author Luke Taylor
* @version $Id$
* @since 3.0
*/
public interface PrePostInvocationAttributeFactory {
PreInvocationAttribute createPreInvocationAttribute(PreFilter preFilter, PreAuthorize preAuthorize);
PostInvocationAttribute createPostInvocationAttribute(PostFilter postFilter, PostAuthorize postAuthorize);
}

View File

@ -0,0 +1,6 @@
<p>
Contains the infrastructure classes for handling the @PreAuthorize, @PreFilter, @PostAuthorize and
@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.

View File

@ -13,11 +13,10 @@
* limitations under the License.
*/
package org.springframework.security.authentication.dao.salt;
package org.springframework.security.authentication.dao;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.dao.SaltSource;
import org.springframework.security.core.userdetails.UserDetails;

View File

@ -13,9 +13,8 @@
* limitations under the License.
*/
package org.springframework.security.authentication.dao.salt;
package org.springframework.security.authentication.dao;
import org.springframework.security.authentication.dao.SaltSource;
import org.springframework.security.core.userdetails.UserDetails;

View File

@ -1,5 +0,0 @@
<html>
<body>
Implementations that provide salts for more secure password encoding.
</body>
</html>

View File

@ -8,7 +8,7 @@ import org.springframework.context.ApplicationEvent;
*
* @author Luke Taylor
* @version $Id$
* @since 2.5
* @since 3.0
*/
public abstract class SessionCreationEvent extends ApplicationEvent {

View File

@ -9,7 +9,7 @@ import org.springframework.security.core.context.SecurityContext;
*
* @author Luke Taylor
* @version $Id$
* @since 2.5
* @since 3.0
*/
public abstract class SessionDestroyedEvent extends ApplicationEvent {

View File

@ -21,7 +21,7 @@ import javax.annotation.security.RolesAllowed;
import javax.annotation.security.PermitAll;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.access.expression.annotation.PreAuthorize;
import org.springframework.security.access.prepost.PreAuthorize;
/**
* @version $Id$

View File

@ -3,8 +3,9 @@ package org.springframework.security.access.annotation;
import java.util.ArrayList;
import java.util.List;
import org.springframework.security.access.expression.annotation.PostFilter;
import org.springframework.security.access.expression.annotation.PreFilter;
import org.springframework.security.access.prepost.PostFilter;
import org.springframework.security.access.prepost.PreFilter;
public class ExpressionProtectedBusinessServiceImpl implements BusinessService {

View File

@ -6,6 +6,7 @@ import java.util.List;
import javax.annotation.security.RolesAllowed;
import javax.annotation.security.PermitAll;
/**
*
* @author Luke Taylor

View File

@ -23,23 +23,23 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.access.annotation.SecuredMethodSecurityMetadataSource;
import org.springframework.security.access.annotation.SecuredAnnotationSecurityMetadataSource;
import org.springframework.util.StringUtils;
/**
* Tests for {@link org.springframework.security.access.annotation.SecuredMethodSecurityMetadataSource}
* Tests for {@link org.springframework.security.access.annotation.SecuredAnnotationSecurityMetadataSource}
*
* @author Mark St.Godard
* @author Joe Scalise
* @author Ben Alex
* @version $Id$
*/
public class SecuredMethodDefinitionSourceTests extends TestCase {
public class SecuredAnnotationSecurityMetadataDefinitionSourceTests extends TestCase {
//~ Instance fields ================================================================================================
private SecuredMethodSecurityMetadataSource mds = new SecuredMethodSecurityMetadataSource();;
private Log logger = LogFactory.getLog(SecuredMethodDefinitionSourceTests.class);
private SecuredAnnotationSecurityMetadataSource mds = new SecuredAnnotationSecurityMetadataSource();;
private Log logger = LogFactory.getLog(SecuredAnnotationSecurityMetadataDefinitionSourceTests.class);
//~ Methods ========================================================================================================

View File

@ -11,8 +11,8 @@ import java.util.List;
import org.aopalliance.intercept.MethodInvocation;
import org.junit.Test;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.expression.method.MethodExpressionVoter;
import org.springframework.security.access.expression.method.PreInvocationExpressionAttribute;
import org.springframework.security.access.prepost.PreInvocationAuthorizationAdviceVoter;
import org.springframework.security.access.vote.AccessDecisionVoter;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.util.SimpleMethodInvocation;
@ -20,7 +20,8 @@ import org.springframework.security.util.SimpleMethodInvocation;
@SuppressWarnings("unchecked")
public class MethodExpressionVoterTests {
private TestingAuthenticationToken joe = new TestingAuthenticationToken("joe", "joespass", "blah");
private MethodExpressionVoter am = new MethodExpressionVoter();
private PreInvocationAuthorizationAdviceVoter am =
new PreInvocationAuthorizationAdviceVoter(new ExpressionBasedPreInvocationAdvice());
@Test
public void hasRoleExpressionAllowsUserWithRole() throws Exception {

View File

@ -1,4 +1,4 @@
package org.springframework.security.access.expression.support;
package org.springframework.security.access.expression.method;
import static org.junit.Assert.*;
@ -9,9 +9,9 @@ import org.junit.Test;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.antlr.SpelAntlrExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.security.access.PermissionEvaluator;
import org.springframework.security.access.expression.ExpressionUtils;
import org.springframework.security.access.expression.PermissionEvaluator;
import org.springframework.security.access.expression.support.MethodSecurityExpressionRoot;
import org.springframework.security.access.expression.method.MethodSecurityExpressionRoot;
import org.springframework.security.authentication.AuthenticationTrustResolver;
import org.springframework.security.core.Authentication;

View File

@ -7,18 +7,22 @@ import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.expression.annotation.PostAuthorize;
import org.springframework.security.access.expression.annotation.PostFilter;
import org.springframework.security.access.expression.annotation.PreAuthorize;
import org.springframework.security.access.expression.annotation.PreFilter;
import org.springframework.security.access.expression.method.ExpressionAnnotationMethodSecurityMetadataSource;
import org.springframework.security.access.expression.method.PostInvocationExpressionAttribute;
import org.springframework.security.access.expression.method.PreInvocationExpressionAttribute;
import org.springframework.security.access.intercept.method.MockMethodInvocation;
import org.springframework.security.access.prepost.PostAuthorize;
import org.springframework.security.access.prepost.PostFilter;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.access.prepost.PreFilter;
import org.springframework.security.access.prepost.PrePostAnnotationSecurityMetadataSource;
public class ExpressionAnnotationMethodDefinitionSourceTests {
private ExpressionAnnotationMethodSecurityMetadataSource mds = new ExpressionAnnotationMethodSecurityMetadataSource();
/**
*
* @author Luke Taylor
* @version $Id$
* @since 3.0
*/
public class PrePostAnnotationSecurityMetadataSourceTests {
private PrePostAnnotationSecurityMetadataSource mds =
new PrePostAnnotationSecurityMetadataSource(new ExpressionBasedAnnotationAttributeFactory(new DefaultMethodSecurityExpressionHandler()));
private MockMethodInvocation voidImpl1;
private MockMethodInvocation voidImpl2;

View File

@ -29,7 +29,6 @@ import org.springframework.security.authentication.LockedException;
import org.springframework.security.authentication.TestingAuthenticationToken;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.authentication.dao.salt.SystemWideSaltSource;
import org.springframework.security.authentication.encoding.ShaPasswordEncoder;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;

View File

@ -19,7 +19,7 @@ import static junit.framework.Assert.assertEquals;
import org.junit.Test;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.dao.salt.ReflectionSaltSource;
import org.springframework.security.authentication.dao.ReflectionSaltSource;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;

View File

@ -15,7 +15,7 @@
package org.springframework.security.authentication.dao.salt;
import org.springframework.security.authentication.dao.salt.SystemWideSaltSource;
import org.springframework.security.authentication.dao.SystemWideSaltSource;
import junit.framework.TestCase;

View File

@ -0,0 +1,9 @@
print authentication.name;
for authority in authentication.authorities:
print authority
print "Granting access"
allow = 1

View File

@ -17,5 +17,10 @@
<version>2.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>jython</groupId>
<artifactId>jython</artifactId>
<version>2.1</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,15 @@
package org.springframework.security.integration.python;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.prepost.PostInvocationAttribute;
import org.springframework.security.access.prepost.PostInvocationAuthorizationAdvice;
import org.springframework.security.core.Authentication;
public class PythonInterpreterPostInvocationAdvice implements PostInvocationAuthorizationAdvice{
public Object after(Authentication authentication, MethodInvocation mi, PostInvocationAttribute pia,
Object returnedObject) throws AccessDeniedException {
return returnedObject;
}
}

View File

@ -0,0 +1,62 @@
package org.springframework.security.integration.python;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import org.aopalliance.intercept.MethodInvocation;
import org.python.core.Py;
import org.python.core.PyObject;
import org.python.util.PythonInterpreter;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.security.access.prepost.PreInvocationAttribute;
import org.springframework.security.access.prepost.PreInvocationAuthorizationAdvice;
import org.springframework.security.core.Authentication;
import org.springframework.util.ClassUtils;
public class PythonInterpreterPreInvocationAdvice implements PreInvocationAuthorizationAdvice{
private ParameterNameDiscoverer parameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
public boolean before(Authentication authentication, MethodInvocation mi, PreInvocationAttribute preAttr) {
PythonInterpreterPreInvocationAttribute pythonAttr = (PythonInterpreterPreInvocationAttribute) preAttr;
String script = pythonAttr.getScript();
PythonInterpreter python = new PythonInterpreter();
python.set("authentication", authentication);
python.set("args", createArgumentMap(mi));
python.set("method", mi.getMethod().getName());
Resource scriptResource = new PathMatchingResourcePatternResolver().getResource(script);
try {
python.execfile(scriptResource.getInputStream());
} catch (IOException e) {
throw new IllegalArgumentException("Couldn't run python script, " + script, e);
}
PyObject allowed = python.get("allow");
if (allowed == null) {
throw new IllegalStateException("Python script did not set the permit flag");
}
return Py.tojava(allowed, Boolean.class);
}
private Map<String,Object> createArgumentMap(MethodInvocation mi) {
Object[] args = mi.getArguments();
Object targetObject = mi.getThis();
Method method = ClassUtils.getMostSpecificMethod(mi.getMethod(), targetObject.getClass());
String[] paramNames = parameterNameDiscoverer.getParameterNames(method);
Map<String,Object> argMap = new HashMap<String,Object>();
for(int i=0; i < args.length; i++) {
argMap.put(paramNames[i], args[i]);
}
return argMap;
}
}

View File

@ -0,0 +1,19 @@
package org.springframework.security.integration.python;
import org.springframework.security.access.prepost.PreInvocationAttribute;
public class PythonInterpreterPreInvocationAttribute implements PreInvocationAttribute {
private String script;
PythonInterpreterPreInvocationAttribute(String script) {
this.script = script;
}
public String getAttribute() {
return null;
}
public String getScript() {
return script;
}
}

View File

@ -0,0 +1,26 @@
package org.springframework.security.integration.python;
import org.python.util.PythonInterpreter;
import org.springframework.security.access.prepost.PostAuthorize;
import org.springframework.security.access.prepost.PostFilter;
import org.springframework.security.access.prepost.PostInvocationAttribute;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.access.prepost.PreFilter;
import org.springframework.security.access.prepost.PreInvocationAttribute;
import org.springframework.security.access.prepost.PrePostInvocationAttributeFactory;
public class PythonInterpreterPrePostInvocationAttributeFactory implements PrePostInvocationAttributeFactory{
public PythonInterpreterPrePostInvocationAttributeFactory() {
PythonInterpreter.initialize(System.getProperties(), null, new String[] {});
}
public PreInvocationAttribute createPreInvocationAttribute(PreFilter preFilter, PreAuthorize preAuthorize) {
return new PythonInterpreterPreInvocationAttribute(preAuthorize.value());
}
public PostInvocationAttribute createPostInvocationAttribute(PostFilter postFilter, PostAuthorize postAuthorize) {
return null;
}
}

View File

@ -0,0 +1,10 @@
package org.springframework.security.integration.python;
import org.springframework.security.access.prepost.PreAuthorize;
public interface TestService {
@PreAuthorize("someMethod.py")
public void someMethod();
}

View File

@ -0,0 +1,9 @@
package org.springframework.security.integration.python;
public class TestServiceImpl implements TestService {
public void someMethod() {
System.out.print("Invoked someMethod()");
}
}

View File

@ -0,0 +1,26 @@
package org.springframework.security.integration.python;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@ContextConfiguration(locations={"/python-method-access-app-context.xml"})
@RunWith(SpringJUnit4ClassRunner.class)
public class PythonInterpreterBasedSecurityTests {
@Autowired
private TestService service;
@Test
public void serviceMethod() throws Exception {
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken("bob","bobspassword"));
// for (int i=0; i < 1000; i++) {
service.someMethod();
// }
}
}

View File

@ -0,0 +1,32 @@
<b:beans xmlns="http://www.springframework.org/schema/security"
xmlns:b="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd">
<global-method-security pre-post-annotations="enabled">
<pre-post-annotation-handling>
<invocation-attribute-factory ref="attributeFactory"/>
<pre-invocation-advice ref="preAdvice"/>
<post-invocation-advice ref="postAdvice"/>
</pre-post-annotation-handling>
</global-method-security>
<b:bean id="attributeFactory" class="org.springframework.security.integration.python.PythonInterpreterPrePostInvocationAttributeFactory"/>
<b:bean id="preAdvice" class="org.springframework.security.integration.python.PythonInterpreterPreInvocationAdvice"/>
<b:bean id="postAdvice" class="org.springframework.security.integration.python.PythonInterpreterPostInvocationAdvice"/>
<b:bean id="service" class="org.springframework.security.integration.python.TestServiceImpl"/>
<authentication-provider>
<user-service>
<user name="bob" password="bobspassword" authorities="ROLE_A,ROLE_B"/>
</user-service>
</authentication-provider>
</b:beans>

View File

@ -1,30 +1,30 @@
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.2.xsd">
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd">
<bean id="userRepository" class="org.springframework.security.integration.StubUserRepository"/>
<bean id="userRepository" class="org.springframework.security.integration.StubUserRepository"/>
<security:authentication-provider
user-service-ref="userDetailsService" />
<bean id="userDetailsService" class="org.springframework.security.integration.UserDetailsServiceImpl">
<property name="userRepository" ref="userRepository"/>
</bean>
<security:authentication-provider
user-service-ref="userDetailsService" />
<security:global-method-security>
<security:protect-pointcut
expression="execution(* org.springframework.security.integration.*Repository+.*(..))"
access="ROLE_LOGGEDIN" />
</security:global-method-security>
<aop:aspectj-autoproxy/>
</beans>
<bean id="userDetailsService" class="org.springframework.security.integration.UserDetailsServiceImpl">
<property name="userRepository" ref="userRepository"/>
</bean>
<security:global-method-security>
<security:protect-pointcut
expression="execution(* org.springframework.security.integration.*Repository+.*(..))"
access="ROLE_LOGGEDIN" />
</security:global-method-security>
<aop:aspectj-autoproxy/>
</beans>

View File

@ -5,7 +5,7 @@
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.2.xsd">
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd">
<security:authentication-provider>
<security:user-service>

View File

@ -4,7 +4,7 @@
xmlns:sec="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.xsd">
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd">
<sec:http entry-point-ref="casProcessingFilterEntryPoint">
<sec:intercept-url pattern="/secure/extreme/**" access="ROLE_SUPERVISOR" requires-channel="https"/>
<sec:intercept-url pattern="/secure/**" access="ROLE_USER" />

View File

@ -9,13 +9,13 @@ import org.springframework.context.MessageSource;
import org.springframework.context.MessageSourceAware;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.dao.DataAccessException;
import org.springframework.security.acls.Acl;
import org.springframework.security.acls.AclService;
import org.springframework.security.acls.Permission;
import org.springframework.security.acls.domain.BasePermission;
import org.springframework.security.acls.objectidentity.ObjectIdentityImpl;
import org.springframework.security.acls.sid.PrincipalSid;
import org.springframework.security.acls.sid.Sid;
import org.springframework.security.acls.domain.ObjectIdentityImpl;
import org.springframework.security.acls.domain.PrincipalSid;
import org.springframework.security.acls.model.Acl;
import org.springframework.security.acls.model.AclService;
import org.springframework.security.acls.model.Permission;
import org.springframework.security.acls.model.Sid;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;

View File

@ -14,10 +14,10 @@
*/
package sample.contact;
import org.springframework.security.access.expression.annotation.PostFilter;
import org.springframework.security.access.expression.annotation.PreAuthorize;
import org.springframework.security.acls.Permission;
import org.springframework.security.acls.sid.Sid;
import org.springframework.security.access.prepost.PostFilter;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.acls.model.Permission;
import org.springframework.security.acls.model.Sid;
import java.util.List;

View File

@ -15,16 +15,16 @@
package sample.contact;
import org.springframework.security.acls.AccessControlEntry;
import org.springframework.security.acls.MutableAcl;
import org.springframework.security.acls.MutableAclService;
import org.springframework.security.acls.NotFoundException;
import org.springframework.security.acls.Permission;
import org.springframework.security.acls.domain.BasePermission;
import org.springframework.security.acls.objectidentity.ObjectIdentity;
import org.springframework.security.acls.objectidentity.ObjectIdentityImpl;
import org.springframework.security.acls.sid.PrincipalSid;
import org.springframework.security.acls.sid.Sid;
import org.springframework.security.acls.domain.ObjectIdentityImpl;
import org.springframework.security.acls.domain.PrincipalSid;
import org.springframework.security.acls.model.AccessControlEntry;
import org.springframework.security.acls.model.MutableAcl;
import org.springframework.security.acls.model.MutableAclService;
import org.springframework.security.acls.model.NotFoundException;
import org.springframework.security.acls.model.ObjectIdentity;
import org.springframework.security.acls.model.Permission;
import org.springframework.security.acls.model.Sid;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;

View File

@ -20,14 +20,14 @@ import javax.sql.DataSource;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.acls.MutableAcl;
import org.springframework.security.acls.MutableAclService;
import org.springframework.security.acls.Permission;
import org.springframework.security.acls.domain.AclImpl;
import org.springframework.security.acls.domain.BasePermission;
import org.springframework.security.acls.objectidentity.ObjectIdentity;
import org.springframework.security.acls.objectidentity.ObjectIdentityImpl;
import org.springframework.security.acls.sid.PrincipalSid;
import org.springframework.security.acls.domain.ObjectIdentityImpl;
import org.springframework.security.acls.domain.PrincipalSid;
import org.springframework.security.acls.model.MutableAcl;
import org.springframework.security.acls.model.MutableAclService;
import org.springframework.security.acls.model.ObjectIdentity;
import org.springframework.security.acls.model.Permission;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.AuthorityUtils;

View File

@ -5,10 +5,10 @@ import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.expression.PermissionEvaluator;
import org.springframework.security.acls.Permission;
import org.springframework.security.access.PermissionEvaluator;
import org.springframework.security.acls.AclPermissionEvaluator;
import org.springframework.security.acls.domain.BasePermission;
import org.springframework.security.acls.expression.AclPermissionEvaluator;
import org.springframework.security.acls.model.Permission;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;

View File

@ -12,9 +12,9 @@
xmlns:b="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.5.xsd">
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd">
<global-method-security expression-annotations="enabled">
<global-method-security pre-post-annotations="enabled">
<expression-handler ref="expressionHandler"/>
</global-method-security>
@ -48,12 +48,11 @@
<b:property name="targetUrl" value="/secure/index.htm"/>
</b:bean>
<b:bean id="expressionHandler" class="org.springframework.security.access.expression.support.DefaultMethodSecurityExpressionHandler">
<b:property name="permissionEvaluator" ref="permissionEvaluator" />
<b:bean id="expressionHandler" class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">
<b:property name="permissionEvaluator">
<b:bean class="org.springframework.security.acls.AclPermissionEvaluator">
<b:constructor-arg ref="aclService"/>
</b:bean>
</b:property>
</b:bean>
<b:bean id="permissionEvaluator" class="org.springframework.security.acls.expression.AclPermissionEvaluator">
<b:constructor-arg ref="aclService"/>
</b:bean>
</b:beans>

View File

@ -24,7 +24,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.acls.domain.BasePermission;
import org.springframework.security.acls.sid.PrincipalSid;
import org.springframework.security.acls.domain.PrincipalSid;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;

View File

@ -11,25 +11,23 @@
xmlns:b="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.5.xsd">
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd">
<global-method-security expression-annotations="enabled">
<global-method-security pre-post-annotations="enabled">
<expression-handler ref="expressionHandler"/>
</global-method-security>
<!-- ======================== AUTHENTICATION ======================= -->
<authentication-provider>
<password-encoder hash="md5"/>
<jdbc-user-service data-source-ref="dataSource"/>
</authentication-provider>
<b:bean id="expressionHandler" class="org.springframework.security.access.expression.support.DefaultMethodSecurityExpressionHandler">
<b:property name="permissionEvaluator" ref="permissionEvaluator" />
</b:bean>
<b:bean id="permissionEvaluator" class="org.springframework.security.acls.expression.AclPermissionEvaluator">
<b:constructor-arg ref="aclService"/>
<b:bean id="expressionHandler" class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">
<b:property name="permissionEvaluator">
<b:bean class="org.springframework.security.acls.AclPermissionEvaluator">
<b:constructor-arg ref="aclService"/>
</b:bean>
</b:property>
</b:bean>
</b:beans>

View File

@ -2,16 +2,16 @@ package sample.dms.secured;
import javax.sql.DataSource;
import org.springframework.security.acls.MutableAcl;
import org.springframework.security.acls.MutableAclService;
import org.springframework.security.acls.NotFoundException;
import org.springframework.security.acls.Permission;
import org.springframework.security.acls.domain.BasePermission;
import org.springframework.security.acls.objectidentity.ObjectIdentity;
import org.springframework.security.acls.objectidentity.ObjectIdentityImpl;
import org.springframework.security.acls.sid.GrantedAuthoritySid;
import org.springframework.security.acls.sid.PrincipalSid;
import org.springframework.security.acls.sid.Sid;
import org.springframework.security.acls.domain.GrantedAuthoritySid;
import org.springframework.security.acls.domain.ObjectIdentityImpl;
import org.springframework.security.acls.domain.PrincipalSid;
import org.springframework.security.acls.model.MutableAcl;
import org.springframework.security.acls.model.MutableAclService;
import org.springframework.security.acls.model.NotFoundException;
import org.springframework.security.acls.model.ObjectIdentity;
import org.springframework.security.acls.model.Permission;
import org.springframework.security.acls.model.Sid;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.util.Assert;

View File

@ -4,12 +4,12 @@ import java.sql.ResultSet;
import java.sql.SQLException;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.security.acls.MutableAcl;
import org.springframework.security.acls.MutableAclService;
import org.springframework.security.acls.domain.BasePermission;
import org.springframework.security.acls.objectidentity.ObjectIdentity;
import org.springframework.security.acls.objectidentity.ObjectIdentityImpl;
import org.springframework.security.acls.sid.PrincipalSid;
import org.springframework.security.acls.domain.ObjectIdentityImpl;
import org.springframework.security.acls.domain.PrincipalSid;
import org.springframework.security.acls.model.MutableAcl;
import org.springframework.security.acls.model.MutableAclService;
import org.springframework.security.acls.model.ObjectIdentity;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.util.Assert;

View File

@ -24,8 +24,8 @@
<value>
sample.dms.secured.SecureDocumentDao.*=PROPAGATION_REQUIRED
sample.dms.DocumentDao.*=PROPAGATION_REQUIRED
org.springframework.security.acls.AclService.*=PROPAGATION_REQUIRED
org.springframework.security.acls.MutableAclService.*=PROPAGATION_REQUIRED
org.springframework.security.acls.model.AclService.*=PROPAGATION_REQUIRED
org.springframework.security.acls.model.MutableAclService.*=PROPAGATION_REQUIRED
org.springframework.security.acls.jdbc.JdbcMutableAclService.*=PROPAGATION_REQUIRED
org.springframework.security.acls.jdbc.JdbcAclService.*=PROPAGATION_REQUIRED
</value>
@ -114,7 +114,7 @@
<bean id="roleVoter" class="org.springframework.security.access.vote.RoleVoter"/>
<!-- An access decision voter that reads ACL_ABSTRACT_ELEMENT_WRITE_PARENT configuration settings -->
<bean id="aclAbstractElementWriteParentVoter" class="org.springframework.security.acls.vote.AclEntryVoter">
<bean id="aclAbstractElementWriteParentVoter" class="org.springframework.security.acls.AclEntryVoter">
<constructor-arg ref="aclService"/>
<constructor-arg value="ACL_ABSTRACT_ELEMENT_WRITE_PARENT"/>
<constructor-arg>
@ -128,7 +128,7 @@
</bean>
<!-- An access decision voter that reads ACL_ABSTRACT_ELEMENT_WRITE configuration settings -->
<bean id="aclAbstractElementWriteVoter" class="org.springframework.security.acls.vote.AclEntryVoter">
<bean id="aclAbstractElementWriteVoter" class="org.springframework.security.acls.AclEntryVoter">
<constructor-arg ref="aclService"/>
<constructor-arg value="ACL_ABSTRACT_ELEMENT_WRITE"/>
<constructor-arg>

View File

@ -1,6 +1,6 @@
package bigbank;
import org.springframework.security.access.expression.annotation.PreAuthorize;
import org.springframework.security.access.prepost.PreAuthorize;
public interface BankService {

View File

@ -10,9 +10,9 @@
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.5.xsd">
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd">
<global-method-security expression-annotations="enabled">
<global-method-security prepost-annotations="enabled">
<!-- AspectJ pointcut expression that locates our "post" method and applies security that way
<protect-pointcut expression="execution(* bigbank.*Service.post*(..))" access="ROLE_TELLER"/>
-->