SEC-1023: Add hasPermission() support to SecurityExpressionRoot
http://jira.springframework.org/browse/SEC-1023. hasPermission() now delegates to a PermissionEvaluator interface, with a default implementation provided by the Acl module. The contacts sample now uses expressions on the ContactManager interface. The permission-evaluator element on global-method-security can be used to set the instance to an AclPermissionEvaluator. If not set, all hasPermission() expressions will evaluate to 'false'.
This commit is contained in:
parent
fa6f57e3dd
commit
e11114ce77
|
@ -105,9 +105,11 @@ public class AclPermissionEvaluator implements PermissionEvaluator {
|
|||
|
||||
if (permission instanceof String) {
|
||||
String permString = (String)permission;
|
||||
Permission p = BasePermission.buildFromName(permString);
|
||||
Permission p = null;
|
||||
|
||||
if (p == null) {
|
||||
try {
|
||||
p = BasePermission.buildFromName(permString);
|
||||
} catch(IllegalArgumentException notfound) {
|
||||
p = BasePermission.buildFromName(permString.toUpperCase());
|
||||
}
|
||||
|
||||
|
@ -123,6 +125,10 @@ public class AclPermissionEvaluator implements PermissionEvaluator {
|
|||
this.objectIdentityRetrievalStrategy = objectIdentityRetrievalStrategy;
|
||||
}
|
||||
|
||||
public void setObjectIdentityGenerator(ObjectIdentityGenerator objectIdentityGenerator) {
|
||||
this.objectIdentityGenerator = objectIdentityGenerator;
|
||||
}
|
||||
|
||||
public void setSidRetrievalStrategy(SidRetrievalStrategy sidRetrievalStrategy) {
|
||||
this.sidRetrievalStrategy = sidRetrievalStrategy;
|
||||
}
|
||||
|
|
|
@ -466,10 +466,6 @@ public class AclImplTests {
|
|||
|
||||
@Test
|
||||
public void testIsSidLoaded() throws Exception {
|
||||
AclAuthorizationStrategyImpl strategy = new AclAuthorizationStrategyImpl(new GrantedAuthority[] {
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL"), new GrantedAuthorityImpl("ROLE_GENERAL"),
|
||||
new GrantedAuthorityImpl("ROLE_GENERAL") });
|
||||
AuditLogger auditLogger = new ConsoleAuditLogger();
|
||||
Sid[] loadedSids = new Sid[] { new PrincipalSid("ben"), new GrantedAuthoritySid("ROLE_IGNORED") };
|
||||
MutableAcl acl = new AclImpl(objectIdentity, new Long(1), mockAuthzStrategy, mockAuditLogger, null, loadedSids, true, new PrincipalSid(
|
||||
"johndoe"));
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
package org.springframework.security.config;
|
||||
|
||||
/**
|
||||
* Contains all the default Bean IDs created by the namespace support in Spring Security 2.
|
||||
* Contains globally used default Bean IDs for beans created by the namespace support in Spring Security 2.
|
||||
* <p>
|
||||
* These are mainly intended for internal use.
|
||||
* These are intended for internal use.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
|
@ -31,7 +31,7 @@ public abstract class BeanIds {
|
|||
public static final String SESSION_REGISTRY = "_sessionRegistry";
|
||||
public static final String CONCURRENT_SESSION_FILTER = "_concurrentSessionFilter";
|
||||
public static final String CONCURRENT_SESSION_CONTROLLER = "_concurrentSessionController";
|
||||
public static final String METHOD_ACCESS_MANAGER = "_methodAccessManager";
|
||||
public static final String METHOD_ACCESS_MANAGER = "_defaultMethodAccessManager";
|
||||
public static final String WEB_ACCESS_MANAGER = "_webAccessManager";
|
||||
public static final String AUTHENTICATION_MANAGER = "_authenticationManager";
|
||||
public static final String AFTER_INVOCATION_MANAGER = "_afterInvocationManager";
|
||||
|
@ -55,11 +55,11 @@ public abstract class BeanIds {
|
|||
public static final String DEFAULT_LOGIN_PAGE_GENERATING_FILTER = "_defaultLoginPageFilter";
|
||||
public static final String SECURITY_CONTEXT_HOLDER_AWARE_REQUEST_FILTER = "_securityContextHolderAwareRequestFilter";
|
||||
public static final String SESSION_FIXATION_PROTECTION_FILTER = "_sessionFixationProtectionFilter";
|
||||
public static final String METHOD_SECURITY_INTERCEPTOR = "_methodSecurityInterceptor";
|
||||
public static final String METHOD_SECURITY_INTERCEPTOR_POST_PROCESSOR = "_methodSecurityInterceptorPostProcessor";
|
||||
// public static final String GLOBAL_METHOD_SECURITY_INTERCEPTOR = "_methodSecurityInterceptor";
|
||||
// public static final String METHOD_SECURITY_INTERCEPTOR_POST_PROCESSOR = "_methodSecurityInterceptorPostProcessor";
|
||||
public static final String METHOD_DEFINITION_SOURCE_ADVISOR = "_methodDefinitionSourceAdvisor";
|
||||
public static final String PROTECT_POINTCUT_POST_PROCESSOR = "_protectPointcutPostProcessor";
|
||||
public static final String DELEGATING_METHOD_DEFINITION_SOURCE = "_delegatingMethodDefinitionSource";
|
||||
// public static final String DELEGATING_METHOD_DEFINITION_SOURCE = "_delegatingMethodDefinitionSource";
|
||||
public static final String SECURED_METHOD_DEFINITION_SOURCE = "_securedMethodDefinitionSource";
|
||||
public static final String JSR_250_METHOD_DEFINITION_SOURCE = "_jsr250MethodDefinitionSource";
|
||||
public static final String EMBEDDED_APACHE_DS = "_apacheDirectoryServerContainer";
|
||||
|
|
|
@ -68,17 +68,6 @@ abstract class ConfigUtils {
|
|||
return nonNulls;
|
||||
}
|
||||
|
||||
static void addVoter(BeanDefinition voter, ParserContext parserContext) {
|
||||
registerDefaultMethodAccessManagerIfNecessary(parserContext);
|
||||
|
||||
BeanDefinition accessMgr = parserContext.getRegistry().getBeanDefinition(BeanIds.METHOD_ACCESS_MANAGER);
|
||||
|
||||
ManagedList voters = (ManagedList) accessMgr.getPropertyValues().getPropertyValue("decisionVoters").getValue();
|
||||
voters.add(voter);
|
||||
|
||||
accessMgr.getPropertyValues().addPropertyValue("decisionVoters", voters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and registers the bean definition for the default ProviderManager instance and returns
|
||||
* the BeanDefinition for it. This method will typically be called when registering authentication providers
|
||||
|
|
|
@ -10,34 +10,35 @@ abstract class Elements {
|
|||
|
||||
public static final String AUTHENTICATION_MANAGER = "authentication-manager";
|
||||
public static final String USER_SERVICE = "user-service";
|
||||
public static final String JDBC_USER_SERVICE = "jdbc-user-service";
|
||||
public static final String FILTER_CHAIN_MAP = "filter-chain-map";
|
||||
public static final String INTERCEPT_METHODS = "intercept-methods";
|
||||
public static final String INTERCEPT_URL = "intercept-url";
|
||||
public static final String AUTHENTICATION_PROVIDER = "authentication-provider";
|
||||
public static final String HTTP = "http";
|
||||
public static final String LDAP_PROVIDER = "ldap-authentication-provider";
|
||||
public static final String LDAP_SERVER = "ldap-server";
|
||||
public static final String JDBC_USER_SERVICE = "jdbc-user-service";
|
||||
public static final String FILTER_CHAIN_MAP = "filter-chain-map";
|
||||
public static final String INTERCEPT_METHODS = "intercept-methods";
|
||||
public static final String INTERCEPT_URL = "intercept-url";
|
||||
public static final String AUTHENTICATION_PROVIDER = "authentication-provider";
|
||||
public static final String HTTP = "http";
|
||||
public static final String LDAP_PROVIDER = "ldap-authentication-provider";
|
||||
public static final String LDAP_SERVER = "ldap-server";
|
||||
public static final String LDAP_USER_SERVICE = "ldap-user-service";
|
||||
public static final String PROTECT_POINTCUT = "protect-pointcut";
|
||||
public static final String PERMISSON_EVALUATOR = "permission-evaluator";
|
||||
public static final String PROTECT = "protect";
|
||||
public static final String CONCURRENT_SESSIONS = "concurrent-session-control";
|
||||
public static final String LOGOUT = "logout";
|
||||
public static final String FORM_LOGIN = "form-login";
|
||||
public static final String OPENID_LOGIN = "openid-login";
|
||||
public static final String BASIC_AUTH = "http-basic";
|
||||
public static final String REMEMBER_ME = "remember-me";
|
||||
public static final String ANONYMOUS = "anonymous";
|
||||
public static final String FILTER_CHAIN = "filter-chain";
|
||||
public static final String GLOBAL_METHOD_SECURITY = "global-method-security";
|
||||
public static final String PASSWORD_ENCODER = "password-encoder";
|
||||
public static final String SALT_SOURCE = "salt-source";
|
||||
public static final String PORT_MAPPINGS = "port-mappings";
|
||||
public static final String CONCURRENT_SESSIONS = "concurrent-session-control";
|
||||
public static final String LOGOUT = "logout";
|
||||
public static final String FORM_LOGIN = "form-login";
|
||||
public static final String OPENID_LOGIN = "openid-login";
|
||||
public static final String BASIC_AUTH = "http-basic";
|
||||
public static final String REMEMBER_ME = "remember-me";
|
||||
public static final String ANONYMOUS = "anonymous";
|
||||
public static final String FILTER_CHAIN = "filter-chain";
|
||||
public static final String GLOBAL_METHOD_SECURITY = "global-method-security";
|
||||
public static final String PASSWORD_ENCODER = "password-encoder";
|
||||
public static final String SALT_SOURCE = "salt-source";
|
||||
public static final String PORT_MAPPINGS = "port-mappings";
|
||||
public static final String PORT_MAPPING = "port-mapping";
|
||||
public static final String CUSTOM_FILTER = "custom-filter";
|
||||
public static final String CUSTOM_AUTH_PROVIDER = "custom-authentication-provider";
|
||||
public static final String CUSTOM_AFTER_INVOCATION_PROVIDER = "custom-after-invocation-provider";
|
||||
public static final String CUSTOM_AFTER_INVOCATION_PROVIDER = "custom-after-invocation-provider";
|
||||
public static final String X509 = "x509";
|
||||
public static final String FILTER_INVOCATION_DEFINITION_SOURCE = "filter-invocation-definition-source";
|
||||
public static final String FILTER_INVOCATION_DEFINITION_SOURCE = "filter-invocation-definition-source";
|
||||
public static final String LDAP_PASSWORD_COMPARE = "password-compare";
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@ import java.util.LinkedHashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.aop.config.AopNamespaceUtils;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
|
@ -17,12 +19,17 @@ import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
|||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.security.ConfigAttribute;
|
||||
import org.springframework.security.SecurityConfig;
|
||||
import org.springframework.security.expression.DefaultSecurityExpressionHandler;
|
||||
import org.springframework.security.expression.support.MethodExpressionAfterInvocationProvider;
|
||||
import org.springframework.security.expression.support.MethodExpressionVoter;
|
||||
import org.springframework.security.intercept.method.DelegatingMethodDefinitionSource;
|
||||
import org.springframework.security.intercept.method.MapBasedMethodDefinitionSource;
|
||||
import org.springframework.security.intercept.method.ProtectPointcutPostProcessor;
|
||||
import org.springframework.security.intercept.method.aopalliance.MethodDefinitionSourceAdvisor;
|
||||
import org.springframework.security.intercept.method.aopalliance.MethodSecurityInterceptor;
|
||||
import org.springframework.security.vote.AffirmativeBased;
|
||||
import org.springframework.security.vote.AuthenticatedVoter;
|
||||
import org.springframework.security.vote.RoleVoter;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
@ -34,24 +41,51 @@ import org.w3c.dom.Element;
|
|||
* @version $Id$
|
||||
*/
|
||||
class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
||||
public static final String SECURED_DEPENDENCY_CLASS = "org.springframework.security.annotation.Secured";
|
||||
public static final String SECURED_METHOD_DEFINITION_SOURCE_CLASS = "org.springframework.security.annotation.SecuredMethodDefinitionSource";
|
||||
public static final String EXPRESSION_METHOD_DEFINITION_SOURCE_CLASS = "org.springframework.security.expression.support.ExpressionAnnotationMethodDefinitionSource";
|
||||
public static final String JSR_250_SECURITY_METHOD_DEFINITION_SOURCE_CLASS = "org.springframework.security.annotation.Jsr250MethodDefinitionSource";
|
||||
public static final String JSR_250_VOTER_CLASS = "org.springframework.security.annotation.Jsr250Voter";
|
||||
|
||||
private final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
static final String SECURED_DEPENDENCY_CLASS = "org.springframework.security.annotation.Secured";
|
||||
static final String SECURED_METHOD_DEFINITION_SOURCE_CLASS = "org.springframework.security.annotation.SecuredMethodDefinitionSource";
|
||||
static final String EXPRESSION_METHOD_DEFINITION_SOURCE_CLASS = "org.springframework.security.expression.support.ExpressionAnnotationMethodDefinitionSource";
|
||||
static final String JSR_250_SECURITY_METHOD_DEFINITION_SOURCE_CLASS = "org.springframework.security.annotation.Jsr250MethodDefinitionSource";
|
||||
static final String JSR_250_VOTER_CLASS = "org.springframework.security.annotation.Jsr250Voter";
|
||||
|
||||
/*
|
||||
* Internal Bean IDs which are only used within this class
|
||||
*/
|
||||
static final String SECURITY_INTERCEPTOR_ID = "_globalMethodSecurityInterceptor";
|
||||
static final String INTERCEPTOR_POST_PROCESSOR_ID = "_globalMethodSecurityInterceptorPostProcessor";
|
||||
static final String ACCESS_MANAGER_ID = "_globalMethodSecurityAccessManager";
|
||||
static final String DELEGATING_METHOD_DEFINITION_SOURCE_ID = "_delegatingMethodDefinitionSource";
|
||||
static final String EXPRESSION_HANDLER_ID = "_expressionHandler";
|
||||
|
||||
private static final String ATT_ACCESS = "access";
|
||||
private static final String ATT_EXPRESSION = "expression";
|
||||
private static final String ATT_ACCESS_MGR = "access-decision-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 = "spel-annotations";
|
||||
private static final String ATT_USE_EXPRESSIONS = "expression-annotations";
|
||||
|
||||
public BeanDefinition parse(Element element, ParserContext parserContext) {
|
||||
Object source = parserContext.extractSource(element);
|
||||
// The list of method metadata delegates
|
||||
ManagedList delegates = new ManagedList();
|
||||
|
||||
boolean jsr250Enabled = registerAnnotationBasedMethodDefinitionSources(element, parserContext, delegates);
|
||||
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));
|
||||
|
||||
if (expressionsEnabled) {
|
||||
delegates.add(BeanDefinitionBuilder.rootBeanDefinition(EXPRESSION_METHOD_DEFINITION_SOURCE_CLASS).getBeanDefinition());
|
||||
}
|
||||
|
||||
if (useSecured) {
|
||||
delegates.add(BeanDefinitionBuilder.rootBeanDefinition(SECURED_METHOD_DEFINITION_SOURCE_CLASS).getBeanDefinition());
|
||||
}
|
||||
|
||||
if (jsr250Enabled) {
|
||||
delegates.add(BeanDefinitionBuilder.rootBeanDefinition(JSR_250_SECURITY_METHOD_DEFINITION_SOURCE_CLASS).getBeanDefinition());
|
||||
}
|
||||
|
||||
MapBasedMethodDefinitionSource mapBasedMethodDefinitionSource = new MapBasedMethodDefinitionSource();
|
||||
delegates.add(mapBasedMethodDefinitionSource);
|
||||
|
@ -66,21 +100,11 @@ class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
|||
|
||||
registerDelegatingMethodDefinitionSource(parserContext, delegates, source);
|
||||
|
||||
// Add the expression-based after invocation provider
|
||||
ConfigUtils.getRegisteredAfterInvocationProviders(parserContext).add(
|
||||
new RootBeanDefinition(MethodExpressionAfterInvocationProvider.class));
|
||||
|
||||
// Register the applicable AccessDecisionManager, handling the special JSR 250 voter if being used
|
||||
String accessManagerId = element.getAttribute(ATT_ACCESS_MGR);
|
||||
|
||||
if (!StringUtils.hasText(accessManagerId)) {
|
||||
ConfigUtils.registerDefaultMethodAccessManagerIfNecessary(parserContext);
|
||||
|
||||
if (jsr250Enabled) {
|
||||
ConfigUtils.addVoter(new RootBeanDefinition(JSR_250_VOTER_CLASS, null, null), parserContext);
|
||||
}
|
||||
|
||||
accessManagerId = BeanIds.METHOD_ACCESS_MANAGER;
|
||||
registerAccessManager(element, parserContext, jsr250Enabled, expressionsEnabled);
|
||||
accessManagerId = ACCESS_MANAGER_ID;
|
||||
}
|
||||
|
||||
registerMethodSecurityInterceptor(parserContext, accessManagerId, source);
|
||||
|
@ -93,38 +117,58 @@ class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
|||
}
|
||||
|
||||
/**
|
||||
* Checks whether el-based, JSR-250 and/or Secured annotations are enabled and adds the appropriate
|
||||
* MethodDefinitionSource delegates if required.
|
||||
* Register the default AccessDecisionManager. Adds the special JSR 250 voter jsr-250 is enabled and an
|
||||
* expression voter if expression-based access control is enabled. If expressions are in use, a after-invocation
|
||||
* provider will also be registered to handle post-invocation filtering and authorization expression annotations.
|
||||
*/
|
||||
private boolean registerAnnotationBasedMethodDefinitionSources(Element element, ParserContext pc, ManagedList delegates) {
|
||||
boolean useJsr250 = "enabled".equals(element.getAttribute(ATT_USE_JSR250));
|
||||
boolean useSecured = "enabled".equals(element.getAttribute(ATT_USE_SECURED));
|
||||
boolean useExpressions = "enabled".equals(element.getAttribute(ATT_USE_EXPRESSIONS));
|
||||
private void registerAccessManager(Element element, ParserContext pc, boolean jsr250Enabled, boolean expressionsEnabled) {
|
||||
Element permissionEvaluatorElt = DomUtils.getChildElementByTagName(element, Elements.PERMISSON_EVALUATOR);
|
||||
BeanDefinitionBuilder accessMgrBuilder = BeanDefinitionBuilder.rootBeanDefinition(AffirmativeBased.class);
|
||||
ManagedList voters = new ManagedList(4);
|
||||
|
||||
if (useExpressions) {
|
||||
delegates.add(BeanDefinitionBuilder.rootBeanDefinition(EXPRESSION_METHOD_DEFINITION_SOURCE_CLASS).getBeanDefinition());
|
||||
if (expressionsEnabled) {
|
||||
BeanDefinitionBuilder expressionHandler = BeanDefinitionBuilder.rootBeanDefinition(DefaultSecurityExpressionHandler.class);
|
||||
BeanDefinitionBuilder expressionVoter = BeanDefinitionBuilder.rootBeanDefinition(MethodExpressionVoter.class);
|
||||
BeanDefinitionBuilder afterInvocationProvider = BeanDefinitionBuilder.rootBeanDefinition(MethodExpressionAfterInvocationProvider.class);
|
||||
|
||||
if (permissionEvaluatorElt != null) {
|
||||
String ref = permissionEvaluatorElt.getAttribute("ref");
|
||||
logger.info("Using bean '" + ref + "' as PermissionEvaluator implementation");
|
||||
expressionHandler.addPropertyReference("permissionEvaluator", ref);
|
||||
} else {
|
||||
logger.warn("Expressions were enabled but no PermissionEvaluator was configured. " +
|
||||
"All hasPermision() expressions will evaluate to false.");
|
||||
}
|
||||
|
||||
pc.getRegistry().registerBeanDefinition(EXPRESSION_HANDLER_ID, expressionHandler.getBeanDefinition());
|
||||
|
||||
expressionVoter.addPropertyReference("expressionHandler", EXPRESSION_HANDLER_ID);
|
||||
afterInvocationProvider.addPropertyReference("expressionHandler", EXPRESSION_HANDLER_ID);
|
||||
ConfigUtils.getRegisteredAfterInvocationProviders(pc).add(afterInvocationProvider.getBeanDefinition());
|
||||
voters.add(expressionVoter.getBeanDefinition());
|
||||
}
|
||||
|
||||
if (useSecured) {
|
||||
delegates.add(BeanDefinitionBuilder.rootBeanDefinition(SECURED_METHOD_DEFINITION_SOURCE_CLASS).getBeanDefinition());
|
||||
voters.add(new RootBeanDefinition(RoleVoter.class));
|
||||
voters.add(new RootBeanDefinition(AuthenticatedVoter.class));
|
||||
|
||||
if (jsr250Enabled) {
|
||||
voters.add(new RootBeanDefinition(JSR_250_VOTER_CLASS, null, null));
|
||||
}
|
||||
|
||||
if (useJsr250) {
|
||||
delegates.add(BeanDefinitionBuilder.rootBeanDefinition(JSR_250_SECURITY_METHOD_DEFINITION_SOURCE_CLASS).getBeanDefinition());
|
||||
}
|
||||
accessMgrBuilder.addPropertyValue("decisionVoters", voters);
|
||||
|
||||
return useJsr250;
|
||||
pc.getRegistry().registerBeanDefinition(ACCESS_MANAGER_ID, accessMgrBuilder.getBeanDefinition());
|
||||
}
|
||||
|
||||
private void registerDelegatingMethodDefinitionSource(ParserContext parserContext, ManagedList delegates, Object source) {
|
||||
if (parserContext.getRegistry().containsBeanDefinition(BeanIds.DELEGATING_METHOD_DEFINITION_SOURCE)) {
|
||||
if (parserContext.getRegistry().containsBeanDefinition(DELEGATING_METHOD_DEFINITION_SOURCE_ID)) {
|
||||
parserContext.getReaderContext().error("Duplicate <global-method-security> detected.", source);
|
||||
}
|
||||
RootBeanDefinition delegatingMethodDefinitionSource = new RootBeanDefinition(DelegatingMethodDefinitionSource.class);
|
||||
delegatingMethodDefinitionSource.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
delegatingMethodDefinitionSource.setSource(source);
|
||||
delegatingMethodDefinitionSource.getPropertyValues().addPropertyValue("methodDefinitionSources", delegates);
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.DELEGATING_METHOD_DEFINITION_SOURCE, delegatingMethodDefinitionSource);
|
||||
parserContext.getRegistry().registerBeanDefinition(DELEGATING_METHOD_DEFINITION_SOURCE_ID, delegatingMethodDefinitionSource);
|
||||
}
|
||||
|
||||
private void registerProtectPointcutPostProcessor(ParserContext parserContext, Map pointcutMap,
|
||||
|
@ -173,11 +217,11 @@ class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
|||
|
||||
interceptor.getPropertyValues().addPropertyValue("accessDecisionManager", new RuntimeBeanReference(accessManagerId));
|
||||
interceptor.getPropertyValues().addPropertyValue("authenticationManager", new RuntimeBeanReference(BeanIds.AUTHENTICATION_MANAGER));
|
||||
interceptor.getPropertyValues().addPropertyValue("objectDefinitionSource", new RuntimeBeanReference(BeanIds.DELEGATING_METHOD_DEFINITION_SOURCE));
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.METHOD_SECURITY_INTERCEPTOR, interceptor);
|
||||
parserContext.registerComponent(new BeanComponentDefinition(interceptor, BeanIds.METHOD_SECURITY_INTERCEPTOR));
|
||||
interceptor.getPropertyValues().addPropertyValue("objectDefinitionSource", new RuntimeBeanReference(DELEGATING_METHOD_DEFINITION_SOURCE_ID));
|
||||
parserContext.getRegistry().registerBeanDefinition(SECURITY_INTERCEPTOR_ID, interceptor);
|
||||
parserContext.registerComponent(new BeanComponentDefinition(interceptor, SECURITY_INTERCEPTOR_ID));
|
||||
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.METHOD_SECURITY_INTERCEPTOR_POST_PROCESSOR,
|
||||
parserContext.getRegistry().registerBeanDefinition(INTERCEPTOR_POST_PROCESSOR_ID,
|
||||
new RootBeanDefinition(MethodSecurityInterceptorPostProcessor.class));
|
||||
}
|
||||
|
||||
|
@ -185,8 +229,8 @@ class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionParser {
|
|||
RootBeanDefinition advisor = new RootBeanDefinition(MethodDefinitionSourceAdvisor.class);
|
||||
advisor.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
advisor.setSource(source);
|
||||
advisor.getConstructorArgumentValues().addGenericArgumentValue(BeanIds.METHOD_SECURITY_INTERCEPTOR);
|
||||
advisor.getConstructorArgumentValues().addGenericArgumentValue(new RuntimeBeanReference(BeanIds.DELEGATING_METHOD_DEFINITION_SOURCE));
|
||||
advisor.getConstructorArgumentValues().addGenericArgumentValue(SECURITY_INTERCEPTOR_ID);
|
||||
advisor.getConstructorArgumentValues().addGenericArgumentValue(new RuntimeBeanReference(DELEGATING_METHOD_DEFINITION_SOURCE_ID));
|
||||
|
||||
parserContext.getRegistry().registerBeanDefinition(BeanIds.METHOD_DEFINITION_SOURCE_ADVISOR, advisor);
|
||||
}
|
||||
|
|
|
@ -10,12 +10,12 @@ import org.springframework.security.AfterInvocationManager;
|
|||
import org.springframework.security.intercept.method.aopalliance.MethodSecurityInterceptor;
|
||||
|
||||
/**
|
||||
* BeanPostProcessor which sets the AfterInvocationManager on the default MethodSecurityInterceptor,
|
||||
* if one has been configured.
|
||||
*
|
||||
* BeanPostProcessor which sets the AfterInvocationManager on the global MethodSecurityInterceptor,
|
||||
* if one has been configured.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class MethodSecurityInterceptorPostProcessor implements BeanPostProcessor, BeanFactoryAware{
|
||||
private Log logger = LogFactory.getLog(getClass());
|
||||
|
@ -23,26 +23,26 @@ public class MethodSecurityInterceptorPostProcessor implements BeanPostProcessor
|
|||
private BeanFactory beanFactory;
|
||||
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
if(!BeanIds.METHOD_SECURITY_INTERCEPTOR.equals(beanName)) {
|
||||
if(!GlobalMethodSecurityBeanDefinitionParser.SECURITY_INTERCEPTOR_ID.equals(beanName)) {
|
||||
return bean;
|
||||
}
|
||||
|
||||
MethodSecurityInterceptor interceptor = (MethodSecurityInterceptor) bean;
|
||||
|
||||
if (beanFactory.containsBean(BeanIds.AFTER_INVOCATION_MANAGER)) {
|
||||
logger.debug("Setting AfterInvocationManaer on MethodSecurityInterceptor");
|
||||
interceptor.setAfterInvocationManager((AfterInvocationManager)
|
||||
beanFactory.getBean(BeanIds.AFTER_INVOCATION_MANAGER));
|
||||
logger.debug("Setting AfterInvocationManaer on MethodSecurityInterceptor");
|
||||
interceptor.setAfterInvocationManager((AfterInvocationManager)
|
||||
beanFactory.getBean(BeanIds.AFTER_INVOCATION_MANAGER));
|
||||
}
|
||||
|
||||
return bean;
|
||||
}
|
||||
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) {
|
||||
return bean;
|
||||
}
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) {
|
||||
return bean;
|
||||
}
|
||||
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,8 @@ import java.util.HashSet;
|
|||
import java.util.Set;
|
||||
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
|
||||
import org.springframework.core.ParameterNameDiscoverer;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
|
@ -14,7 +16,22 @@ import org.springframework.security.Authentication;
|
|||
import org.springframework.security.AuthenticationTrustResolver;
|
||||
import org.springframework.security.AuthenticationTrustResolverImpl;
|
||||
|
||||
/**
|
||||
* The standard implementation of <tt>SecurityExpressionHandler</tt> which uses a {@link SecurityEvaluationContext}
|
||||
* as the <tt>EvaluationContext</tt> implementation and configures it with a {@link SecurityExpressionRoot} instance
|
||||
* as the expression root object.
|
||||
* <p>
|
||||
* A single instance should usually be shared between the expression voter and after-invocation provider.
|
||||
*
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
* @since 2.5
|
||||
*/
|
||||
public class DefaultSecurityExpressionHandler implements SecurityExpressionHandler {
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private ParameterNameDiscoverer parameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();
|
||||
private PermissionEvaluator permissionEvaluator = new DenyAllPermissionEvaluator();
|
||||
private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
|
||||
|
@ -32,11 +49,20 @@ public class DefaultSecurityExpressionHandler implements SecurityExpressionHandl
|
|||
return ctx;
|
||||
}
|
||||
|
||||
public Object doFilter(Object filterTarget, Expression filterExpression, EvaluationContext ctx) {
|
||||
public Object filter(Object filterTarget, Expression filterExpression, EvaluationContext ctx) {
|
||||
SecurityExpressionRoot rootObject = (SecurityExpressionRoot) ctx.getRootContextObject();
|
||||
Set removeList = new HashSet();
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Filtering with expression: " + filterExpression.getExpressionString());
|
||||
}
|
||||
|
||||
if (filterTarget instanceof Collection) {
|
||||
Collection collection = (Collection)filterTarget;
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Filtering collection with " + collection.size() + " elements");
|
||||
}
|
||||
for (Object filterObject : (Collection)filterTarget) {
|
||||
rootObject.setFilterObject(filterObject);
|
||||
|
||||
|
@ -45,6 +71,10 @@ public class DefaultSecurityExpressionHandler implements SecurityExpressionHandl
|
|||
}
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Removing elements: " + removeList);
|
||||
}
|
||||
|
||||
for(Object toRemove : removeList) {
|
||||
((Collection)filterTarget).remove(toRemove);
|
||||
}
|
||||
|
@ -55,6 +85,10 @@ public class DefaultSecurityExpressionHandler implements SecurityExpressionHandl
|
|||
if (filterTarget.getClass().isArray()) {
|
||||
Object[] array = (Object[])filterTarget;
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Filtering collection with " + array.length + " elements");
|
||||
}
|
||||
|
||||
for (int i = 0; i < array.length; i++) {
|
||||
rootObject.setFilterObject(array[i]);
|
||||
|
||||
|
@ -63,6 +97,10 @@ public class DefaultSecurityExpressionHandler implements SecurityExpressionHandl
|
|||
}
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Removing elements: " + removeList);
|
||||
}
|
||||
|
||||
Object[] filtered = (Object[]) Array.newInstance(filterTarget.getClass().getComponentType(),
|
||||
array.length - removeList.size());
|
||||
for (int i = 0, j = 0; i < array.length; i++) {
|
||||
|
|
|
@ -2,6 +2,8 @@ package org.springframework.security.expression;
|
|||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.security.Authentication;
|
||||
|
||||
/**
|
||||
|
@ -12,12 +14,15 @@ import org.springframework.security.Authentication;
|
|||
* @version $Id$
|
||||
* @since 2.5
|
||||
*/
|
||||
public class DenyAllPermissionEvaluator implements PermissionEvaluator {
|
||||
public final class DenyAllPermissionEvaluator implements PermissionEvaluator {
|
||||
|
||||
private final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
/**
|
||||
* @return false always
|
||||
*/
|
||||
public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) {
|
||||
public boolean hasPermission(Authentication authentication, Object target, Object permission) {
|
||||
logger.warn("Denying user " + authentication.getName() + " permission '" + permission + "' on object " + target);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -26,6 +31,8 @@ public class DenyAllPermissionEvaluator implements PermissionEvaluator {
|
|||
*/
|
||||
public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType,
|
||||
Object permission) {
|
||||
logger.warn("Denying user " + authentication.getName() + " permission '" + permission + "' on object with Id '"
|
||||
+ targetId);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -30,10 +30,10 @@ public interface SecurityExpressionHandler {
|
|||
* {@link #createEvaluationContext(Authentication, MethodInvocation)}
|
||||
* @return the filtered collection or array
|
||||
*/
|
||||
Object doFilter(Object filterTarget, Expression filterExpression, EvaluationContext ctx);
|
||||
Object filter(Object filterTarget, Expression filterExpression, EvaluationContext ctx);
|
||||
|
||||
/**
|
||||
* Used to inform the expression system of the return object
|
||||
* Used to inform the expression system of the return object for the given evaluation context.
|
||||
*
|
||||
* @param returnObject the return object value
|
||||
* @param ctx the context within which the object should be set
|
||||
|
|
|
@ -33,7 +33,7 @@ public class SecurityExpressionRoot {
|
|||
public final String write = "write";
|
||||
public final String create = "create";
|
||||
public final String delete = "delete";
|
||||
public final String admin = "admin";
|
||||
public final String admin = "administration";
|
||||
|
||||
|
||||
SecurityExpressionRoot(Authentication a) {
|
||||
|
|
|
@ -51,7 +51,7 @@ public class MethodExpressionAfterInvocationProvider implements AfterInvocationP
|
|||
}
|
||||
|
||||
if (returnedObject != null) {
|
||||
returnedObject = expressionHandler.doFilter(returnedObject, postFilter, ctx);
|
||||
returnedObject = expressionHandler.filter(returnedObject, postFilter, ctx);
|
||||
} else {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Return object is null, filtering will be skipped");
|
||||
|
@ -90,6 +90,7 @@ public class MethodExpressionAfterInvocationProvider implements AfterInvocationP
|
|||
return clazz.isAssignableFrom(MethodInvocation.class);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void setExpressionHandler(SecurityExpressionHandler expressionHandler) {
|
||||
this.expressionHandler = expressionHandler;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -55,7 +55,7 @@ public class MethodExpressionVoter implements AccessDecisionVoter {
|
|||
if (preFilter != null) {
|
||||
Object filterTarget = findFilterTarget(mace.getFilterTarget(), ctx, mi);
|
||||
|
||||
expressionHandler.doFilter(filterTarget, preFilter, ctx);
|
||||
expressionHandler.filter(filterTarget, preFilter, ctx);
|
||||
}
|
||||
|
||||
if (preAuthorize == null) {
|
||||
|
@ -104,4 +104,8 @@ public class MethodExpressionVoter implements AccessDecisionVoter {
|
|||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void setExpressionHandler(SecurityExpressionHandler expressionHandler) {
|
||||
this.expressionHandler = expressionHandler;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -181,10 +181,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, protect-pointcut*}
|
||||
element global-method-security {global-method-security.attlist, permission-evaluator?, 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 spel-annotations {"disabled" | "enabled" }?
|
||||
attribute expression-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" }?
|
||||
|
@ -195,6 +195,10 @@ global-method-security.attlist &=
|
|||
## Optional AccessDecisionManager bean ID to override the default used for method security.
|
||||
attribute access-decision-manager-ref {xsd:string}?
|
||||
|
||||
permission-evaluator =
|
||||
## Defines the PermissionEvaluator implementation which will be used to evaluate calls to hasPermission() expressions
|
||||
element permission-evaluator {ref}
|
||||
|
||||
custom-after-invocation-provider =
|
||||
## Used to decorate an AfterInvocationProvider to specify that it should be used with method security.
|
||||
element custom-after-invocation-provider {empty}
|
||||
|
|
|
@ -565,6 +565,7 @@
|
|||
</xs:annotation>
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element minOccurs="0" ref="security:permission-evaluator"/>
|
||||
<xs:element minOccurs="0" maxOccurs="unbounded" name="protect-pointcut">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Defines a protected pointcut and the access control configuration
|
||||
|
@ -581,7 +582,7 @@
|
|||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:attributeGroup name="global-method-security.attlist">
|
||||
<xs:attribute name="spel-annotations">
|
||||
<xs:attribute name="expression-annotations">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Specifies whether the use of Spring Security's expression-based
|
||||
annotations (@PreFilter, @PreAuthorize, @PostFilter, @PostAuthorize) should be enabled for
|
||||
|
@ -626,6 +627,15 @@
|
|||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:attributeGroup>
|
||||
<xs:element name="permission-evaluator">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Defines the PermissionEvaluator implementation which will be used to
|
||||
evaluate calls to hasPermission() expressions</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexType>
|
||||
<xs:attributeGroup ref="security:ref"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:element name="custom-after-invocation-provider">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Used to decorate an AfterInvocationProvider to specify that it should be
|
||||
|
|
|
@ -30,11 +30,11 @@ public class CustomAfterInvocationProviderBeanDefinitionDecoratorTests {
|
|||
ConfigTestUtils.AUTH_PROVIDER_XML
|
||||
);
|
||||
|
||||
MethodSecurityInterceptor msi = (MethodSecurityInterceptor) appContext.getBean(BeanIds.METHOD_SECURITY_INTERCEPTOR);
|
||||
MethodSecurityInterceptor msi = (MethodSecurityInterceptor) appContext.getBean(GlobalMethodSecurityBeanDefinitionParser.SECURITY_INTERCEPTOR_ID);
|
||||
AfterInvocationProviderManager apm = (AfterInvocationProviderManager) msi.getAfterInvocationManager();
|
||||
assertNotNull(apm);
|
||||
assertEquals(2, apm.getProviders().size());
|
||||
assertTrue(apm.getProviders().get(1) instanceof MockAfterInvocationProvider);
|
||||
assertEquals(1, apm.getProviders().size());
|
||||
assertTrue(apm.getProviders().get(0) instanceof MockAfterInvocationProvider);
|
||||
}
|
||||
|
||||
private void setContext(String context) {
|
||||
|
|
|
@ -11,11 +11,13 @@ import org.junit.Test;
|
|||
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
|
||||
import org.springframework.context.support.AbstractXmlApplicationContext;
|
||||
import org.springframework.security.AccessDeniedException;
|
||||
import org.springframework.security.Authentication;
|
||||
import org.springframework.security.AuthenticationCredentialsNotFoundException;
|
||||
import org.springframework.security.GrantedAuthority;
|
||||
import org.springframework.security.GrantedAuthorityImpl;
|
||||
import org.springframework.security.annotation.BusinessService;
|
||||
import org.springframework.security.context.SecurityContextHolder;
|
||||
import org.springframework.security.providers.TestingAuthenticationToken;
|
||||
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.userdetails.UserDetailsService;
|
||||
import org.springframework.security.util.InMemoryXmlApplicationContext;
|
||||
|
@ -69,8 +71,9 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
|
|||
@Test(expected=AccessDeniedException.class)
|
||||
public void targetShouldPreventProtectedMethodInvocationWithIncorrectRole() {
|
||||
loadContext();
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", "Password",
|
||||
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_SOMEOTHERROLE")});
|
||||
TestingAuthenticationToken token = new TestingAuthenticationToken("Test", "Password", "ROLE_SOMEOTHERROLE");
|
||||
token.setAuthenticated(true);
|
||||
|
||||
SecurityContextHolder.getContext().setAuthentication(token);
|
||||
|
||||
target.someAdminMethod();
|
||||
|
@ -186,7 +189,7 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
|
|||
@Test(expected=AccessDeniedException.class)
|
||||
public void accessIsDeniedForHasRoleExpression() {
|
||||
setContext(
|
||||
"<global-method-security spel-annotations='enabled'/>" +
|
||||
"<global-method-security expression-annotations='enabled'/>" +
|
||||
"<b:bean id='target' class='org.springframework.security.annotation.ExpressionProtectedBusinessServiceImpl'/>" +
|
||||
AUTH_PROVIDER_XML);
|
||||
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken("bob","bobspassword"));
|
||||
|
@ -197,7 +200,7 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
|
|||
@Test
|
||||
public void preAndPostFilterAnnotationsWorkWithLists() {
|
||||
setContext(
|
||||
"<global-method-security spel-annotations='enabled'/>" +
|
||||
"<global-method-security expression-annotations='enabled'/>" +
|
||||
"<b:bean id='target' class='org.springframework.security.annotation.ExpressionProtectedBusinessServiceImpl'/>" +
|
||||
AUTH_PROVIDER_XML);
|
||||
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken("bob","bobspassword"));
|
||||
|
@ -216,7 +219,7 @@ public class GlobalMethodSecurityBeanDefinitionParserTests {
|
|||
@Test
|
||||
public void prePostFilterAnnotationWorksWithArrays() {
|
||||
setContext(
|
||||
"<global-method-security spel-annotations='enabled'/>" +
|
||||
"<global-method-security expression-annotations='enabled'/>" +
|
||||
"<b:bean id='target' class='org.springframework.security.annotation.ExpressionProtectedBusinessServiceImpl'/>" +
|
||||
AUTH_PROVIDER_XML);
|
||||
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken("bob","bobspassword"));
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
*/
|
||||
package sample.contact;
|
||||
|
||||
import org.springframework.security.acl.basic.SimpleAclEntry;
|
||||
import org.springframework.security.acls.domain.BasePermission;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -27,7 +27,7 @@ public class AddPermission {
|
|||
//~ Instance fields ================================================================================================
|
||||
|
||||
public Contact contact;
|
||||
public Integer permission = new Integer(SimpleAclEntry.READ);
|
||||
public Integer permission = BasePermission.READ.getMask();
|
||||
public String recipient;
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
|
|
@ -26,7 +26,7 @@ import org.springframework.util.Assert;
|
|||
|
||||
import org.springframework.validation.BindException;
|
||||
|
||||
import org.springframework.web.bind.RequestUtils;
|
||||
import org.springframework.web.bind.ServletRequestUtils;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
import org.springframework.web.servlet.mvc.SimpleFormController;
|
||||
import org.springframework.web.servlet.view.RedirectView;
|
||||
|
@ -67,7 +67,7 @@ public class AddPermissionController extends SimpleFormController implements Ini
|
|||
|
||||
protected Object formBackingObject(HttpServletRequest request)
|
||||
throws Exception {
|
||||
int contactId = RequestUtils.getRequiredIntParameter(request, "contactId");
|
||||
int contactId = ServletRequestUtils.getRequiredIntParameter(request, "contactId");
|
||||
|
||||
Contact contact = contactManager.getById(new Long(contactId));
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ import org.springframework.beans.factory.InitializingBean;
|
|||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import org.springframework.web.bind.RequestUtils;
|
||||
import org.springframework.web.bind.ServletRequestUtils;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
import org.springframework.web.servlet.mvc.Controller;
|
||||
|
||||
|
@ -57,7 +57,7 @@ public class AdminPermissionController implements Controller, InitializingBean {
|
|||
|
||||
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
|
||||
throws ServletException, IOException {
|
||||
int id = RequestUtils.getRequiredIntParameter(request, "contactId");
|
||||
int id = ServletRequestUtils.getRequiredIntParameter(request, "contactId");
|
||||
|
||||
Contact contact = contactManager.getById(new Long(id));
|
||||
Acl acl = aclService.readAclById(new ObjectIdentityImpl(contact));
|
||||
|
|
|
@ -36,8 +36,9 @@ import java.util.Map;
|
|||
|
||||
|
||||
/**
|
||||
* Demonstrates accessing the {@link ContactManager} via remoting protocols.<P>Based on Spring's JPetStore sample,
|
||||
* written by Juergen Hoeller.</p>
|
||||
* Demonstrates accessing the {@link ContactManager} via remoting protocols.
|
||||
* <p>
|
||||
* Based on Spring's JPetStore sample, written by Juergen Hoeller.
|
||||
*
|
||||
* @author Ben Alex
|
||||
*/
|
||||
|
|
|
@ -43,8 +43,6 @@ public class Contact implements Serializable {
|
|||
//~ Methods ========================================================================================================
|
||||
|
||||
/**
|
||||
* DOCUMENT ME!
|
||||
*
|
||||
* @return Returns the email.
|
||||
*/
|
||||
public String getEmail() {
|
||||
|
@ -52,8 +50,6 @@ public class Contact implements Serializable {
|
|||
}
|
||||
|
||||
/**
|
||||
* DOCUMENT ME!
|
||||
*
|
||||
* @return Returns the id.
|
||||
*/
|
||||
public Long getId() {
|
||||
|
@ -61,8 +57,6 @@ public class Contact implements Serializable {
|
|||
}
|
||||
|
||||
/**
|
||||
* DOCUMENT ME!
|
||||
*
|
||||
* @return Returns the name.
|
||||
*/
|
||||
public String getName() {
|
||||
|
@ -70,8 +64,6 @@ public class Contact implements Serializable {
|
|||
}
|
||||
|
||||
/**
|
||||
* DOCUMENT ME!
|
||||
*
|
||||
* @param email The email to set.
|
||||
*/
|
||||
public void setEmail(String email) {
|
||||
|
@ -83,8 +75,6 @@ public class Contact implements Serializable {
|
|||
}
|
||||
|
||||
/**
|
||||
* DOCUMENT ME!
|
||||
*
|
||||
* @param name The name to set.
|
||||
*/
|
||||
public void setName(String name) {
|
||||
|
|
|
@ -16,6 +16,8 @@ package sample.contact;
|
|||
|
||||
import org.springframework.security.acls.Permission;
|
||||
import org.springframework.security.acls.sid.Sid;
|
||||
import org.springframework.security.expression.annotation.PostFilter;
|
||||
import org.springframework.security.expression.annotation.PreAuthorize;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
@ -28,19 +30,28 @@ import java.util.List;
|
|||
*/
|
||||
public interface ContactManager {
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
@PreAuthorize("hasPermission(#contact, admin)")
|
||||
public void addPermission(Contact contact, Sid recipient, Permission permission);
|
||||
|
||||
public void create(Contact contact);
|
||||
|
||||
public void delete(Contact contact);
|
||||
|
||||
@PreAuthorize("hasPermission(#contact, admin)")
|
||||
public void deletePermission(Contact contact, Sid recipient, Permission permission);
|
||||
|
||||
@PreAuthorize("hasRole('ROLE_USER')")
|
||||
public void create(Contact contact);
|
||||
|
||||
@PreAuthorize("hasPermission(#contact, 'delete') or hasPermission(#contact, admin)")
|
||||
public void delete(Contact contact);
|
||||
|
||||
@PreAuthorize("hasRole('ROLE_USER')")
|
||||
@PostFilter("hasPermission(filterObject, 'read') or hasPermission(filterObject, admin)")
|
||||
public List getAll();
|
||||
|
||||
@PreAuthorize("hasRole('ROLE_USER')")
|
||||
public List getAllRecipients();
|
||||
|
||||
@PreAuthorize(
|
||||
"hasPermission(#id, 'sample.contact.Contact', read) or " +
|
||||
"hasPermission(#id, 'sample.contact.Contact', admin)")
|
||||
public Contact getById(Long id);
|
||||
|
||||
public Contact getRandomContact();
|
||||
|
|
|
@ -30,6 +30,7 @@ import org.springframework.security.acls.sid.Sid;
|
|||
import org.springframework.security.context.SecurityContextHolder;
|
||||
|
||||
import org.springframework.security.userdetails.UserDetails;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
|
||||
|
@ -47,6 +48,7 @@ import java.util.Random;
|
|||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
@Transactional
|
||||
public class ContactManagerBackend extends ApplicationObjectSupport implements ContactManager, InitializingBean {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
|
@ -124,6 +126,7 @@ public class ContactManagerBackend extends ApplicationObjectSupport implements C
|
|||
}
|
||||
}
|
||||
|
||||
@Transactional(readOnly=true)
|
||||
public List getAll() {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Returning all contacts");
|
||||
|
@ -132,6 +135,7 @@ public class ContactManagerBackend extends ApplicationObjectSupport implements C
|
|||
return contactDao.findAll();
|
||||
}
|
||||
|
||||
@Transactional(readOnly=true)
|
||||
public List getAllRecipients() {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Returning all recipients");
|
||||
|
@ -142,6 +146,7 @@ public class ContactManagerBackend extends ApplicationObjectSupport implements C
|
|||
return list;
|
||||
}
|
||||
|
||||
@Transactional(readOnly=true)
|
||||
public Contact getById(Long id) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Returning contact with id: " + id);
|
||||
|
@ -152,9 +157,8 @@ public class ContactManagerBackend extends ApplicationObjectSupport implements C
|
|||
|
||||
/**
|
||||
* This is a public method.
|
||||
*
|
||||
* @return DOCUMENT ME!
|
||||
*/
|
||||
@Transactional(readOnly=true)
|
||||
public Contact getRandomContact() {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Returning random contact");
|
||||
|
|
|
@ -24,7 +24,7 @@ import org.springframework.beans.factory.InitializingBean;
|
|||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import org.springframework.web.bind.RequestUtils;
|
||||
import org.springframework.web.bind.ServletRequestUtils;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
import org.springframework.web.servlet.mvc.Controller;
|
||||
|
||||
|
@ -60,9 +60,9 @@ public class DeletePermissionController implements Controller, InitializingBean
|
|||
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
|
||||
throws ServletException, IOException {
|
||||
// <c:param name="sid" value="${acl.sid.principal}"/><c:param name="permission" value="${acl.permission.mask}"/></c:url>">Del</A>
|
||||
int contactId = RequestUtils.getRequiredIntParameter(request, "contactId");
|
||||
String sid = RequestUtils.getRequiredStringParameter(request, "sid");
|
||||
int mask = RequestUtils.getRequiredIntParameter(request, "permission");
|
||||
int contactId = ServletRequestUtils.getRequiredIntParameter(request, "contactId");
|
||||
String sid = ServletRequestUtils.getRequiredStringParameter(request, "sid");
|
||||
int mask = ServletRequestUtils.getRequiredIntParameter(request, "permission");
|
||||
|
||||
Contact contact = contactManager.getById(new Long(contactId));
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ public class PublicIndexController implements Controller, InitializingBean {
|
|||
}
|
||||
|
||||
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
|
||||
throws ServletException, IOException {
|
||||
throws ServletException, IOException {
|
||||
Contact rnd = contactManager.getRandomContact();
|
||||
|
||||
return new ModelAndView("hello", "contact", rnd);
|
||||
|
|
|
@ -17,6 +17,11 @@ package sample.contact;
|
|||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
|
||||
import org.springframework.security.Authentication;
|
||||
import org.springframework.security.acls.Permission;
|
||||
import org.springframework.security.acls.domain.BasePermission;
|
||||
import org.springframework.security.context.SecurityContextHolder;
|
||||
import org.springframework.security.expression.PermissionEvaluator;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
@ -35,38 +40,55 @@ import javax.servlet.http.HttpServletResponse;
|
|||
|
||||
/**
|
||||
* Controller for secure index page.
|
||||
* <p>
|
||||
* This controller displays a list of all the contacts for which the current user has read or admin permissions.
|
||||
* It makes a call to {@link ContactManager#getAll()} which automatically filters the returned list using Spring
|
||||
* Security's ACL mechanism (see the expression annotations on this interface for the details).
|
||||
* <p>
|
||||
* In addition to rendering the list of contacts, the view will also include a "Del" or "Admin" link beside the
|
||||
* contact, depending on whether the user has the corresponding permissions (admin permission is assumed to imply
|
||||
* delete here). This information is stored in the model using the injected {@link PermissionEvaluator} instance.
|
||||
* The implementation should be an instance of {@link AclPermissionEvaluator} or one which is compatible with Spring
|
||||
* Security's ACL module.
|
||||
*
|
||||
* @author Ben Alex
|
||||
* @version $Id$
|
||||
*/
|
||||
public class SecureIndexController implements Controller, InitializingBean {
|
||||
private final static Permission[] HAS_DELETE = new Permission[] {BasePermission.DELETE, BasePermission.ADMINISTRATION};
|
||||
private final static Permission[] HAS_ADMIN = new Permission[] {BasePermission.ADMINISTRATION};
|
||||
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
private ContactManager contactManager;
|
||||
private PermissionEvaluator permissionEvaluator;
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.notNull(contactManager, "A ContactManager implementation is required");
|
||||
}
|
||||
|
||||
public ContactManager getContactManager() {
|
||||
return contactManager;
|
||||
Assert.notNull(permissionEvaluator, "A PermissionEvaluator implementation is required");
|
||||
}
|
||||
|
||||
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
|
||||
throws ServletException, IOException {
|
||||
List myContactsList = contactManager.getAll();
|
||||
Contact[] myContacts;
|
||||
throws ServletException, IOException {
|
||||
List<Contact> myContactsList = contactManager.getAll();
|
||||
Map<Contact,Boolean> hasDelete = new HashMap<Contact,Boolean>(myContactsList.size());
|
||||
Map<Contact,Boolean> hasAdmin = new HashMap<Contact,Boolean>(myContactsList.size());
|
||||
|
||||
if (myContactsList.size() == 0) {
|
||||
myContacts = null;
|
||||
} else {
|
||||
myContacts = (Contact[]) myContactsList.toArray(new Contact[] {});
|
||||
Authentication user = SecurityContextHolder.getContext().getAuthentication();
|
||||
|
||||
for (Contact contact : myContactsList) {
|
||||
hasDelete.put(contact,
|
||||
permissionEvaluator.hasPermission(user, contact, HAS_DELETE) ? Boolean.TRUE : Boolean.FALSE);
|
||||
hasAdmin.put(contact,
|
||||
permissionEvaluator.hasPermission(user, contact, HAS_ADMIN) ? Boolean.TRUE : Boolean.FALSE);
|
||||
}
|
||||
|
||||
Map model = new HashMap();
|
||||
model.put("contacts", myContacts);
|
||||
model.put("contacts", myContactsList);
|
||||
model.put("hasDeletePermission", hasDelete);
|
||||
model.put("hasAdminPermission", hasAdmin);
|
||||
|
||||
return new ModelAndView("index", "model", model);
|
||||
}
|
||||
|
@ -74,4 +96,8 @@ public class SecureIndexController implements Controller, InitializingBean {
|
|||
public void setContactManager(ContactManager contact) {
|
||||
this.contactManager = contact;
|
||||
}
|
||||
|
||||
public void setPermissionEvaluator(PermissionEvaluator pe) {
|
||||
this.permissionEvaluator = pe;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,77 +14,7 @@
|
|||
- $Id$
|
||||
-->
|
||||
|
||||
<!-- ~~~~~~~~~~~~~~~~~~ "BEFORE INVOCATION" AUTHORIZATION DEFINITIONS ~~~~~~~~~~~~~~~~ -->
|
||||
|
||||
<!-- ACL permission masks used by this application -->
|
||||
<bean id="org.springframework.security.acls.domain.BasePermission.ADMINISTRATION"
|
||||
class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
|
||||
<property name="staticField" value="org.springframework.security.acls.domain.BasePermission.ADMINISTRATION"/>
|
||||
</bean>
|
||||
<bean id="org.springframework.security.acls.domain.BasePermission.READ"
|
||||
class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
|
||||
<property name="staticField" value="org.springframework.security.acls.domain.BasePermission.READ"/>
|
||||
</bean>
|
||||
<bean id="org.springframework.security.acls.domain.BasePermission.DELETE"
|
||||
class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean">
|
||||
<property name="staticField" value="org.springframework.security.acls.domain.BasePermission.DELETE"/>
|
||||
</bean>
|
||||
|
||||
<!-- An access decision voter that reads ROLE_* configuration settings -->
|
||||
<bean id="roleVoter" class="org.springframework.security.vote.RoleVoter"/>
|
||||
|
||||
<!-- An access decision voter that reads ACL_CONTACT_READ configuration settings -->
|
||||
<bean id="aclContactReadVoter" class="org.springframework.security.vote.AclEntryVoter">
|
||||
<constructor-arg ref="aclService"/>
|
||||
<constructor-arg value="ACL_CONTACT_READ"/>
|
||||
<constructor-arg>
|
||||
<list>
|
||||
<ref local="org.springframework.security.acls.domain.BasePermission.ADMINISTRATION"/>
|
||||
<ref local="org.springframework.security.acls.domain.BasePermission.READ"/>
|
||||
</list>
|
||||
</constructor-arg>
|
||||
<property name="processDomainObjectClass" value="sample.contact.Contact"/>
|
||||
</bean>
|
||||
|
||||
<!-- An access decision voter that reads ACL_CONTACT_DELETE configuration settings -->
|
||||
<bean id="aclContactDeleteVoter" class="org.springframework.security.vote.AclEntryVoter">
|
||||
<constructor-arg ref="aclService"/>
|
||||
<constructor-arg value="ACL_CONTACT_DELETE"/>
|
||||
<constructor-arg>
|
||||
<list>
|
||||
<ref local="org.springframework.security.acls.domain.BasePermission.ADMINISTRATION"/>
|
||||
<ref local="org.springframework.security.acls.domain.BasePermission.DELETE"/>
|
||||
</list>
|
||||
</constructor-arg>
|
||||
<property name="processDomainObjectClass" value="sample.contact.Contact"/>
|
||||
</bean>
|
||||
|
||||
<!-- An access decision voter that reads ACL_CONTACT_ADMIN configuration settings -->
|
||||
<bean id="aclContactAdminVoter" class="org.springframework.security.vote.AclEntryVoter">
|
||||
<constructor-arg ref="aclService"/>
|
||||
<constructor-arg value="ACL_CONTACT_ADMIN"/>
|
||||
<constructor-arg>
|
||||
<list>
|
||||
<ref local="org.springframework.security.acls.domain.BasePermission.ADMINISTRATION"/>
|
||||
</list>
|
||||
</constructor-arg>
|
||||
<property name="processDomainObjectClass" value="sample.contact.Contact"/>
|
||||
</bean>
|
||||
|
||||
<!-- An access decision manager used by the business objects -->
|
||||
<bean id="businessAccessDecisionManager" class="org.springframework.security.vote.AffirmativeBased">
|
||||
<property name="allowIfAllAbstainDecisions" value="false"/>
|
||||
<property name="decisionVoters">
|
||||
<list>
|
||||
<ref local="roleVoter"/>
|
||||
<ref local="aclContactReadVoter"/>
|
||||
<ref local="aclContactDeleteVoter"/>
|
||||
<ref local="aclContactAdminVoter"/>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- ========= ACCESS CONTROL LIST LOOKUP MANAGER DEFINITIONS ========= -->
|
||||
<!-- ========= ACL SERVICE DEFINITIONS ========= -->
|
||||
|
||||
<bean id="aclCache" class="org.springframework.security.acls.jdbc.EhCacheBasedAclCache">
|
||||
<constructor-arg>
|
||||
|
@ -128,38 +58,4 @@
|
|||
<constructor-arg ref="aclCache"/>
|
||||
</bean>
|
||||
|
||||
<!-- ============== "AFTER INTERCEPTION" AUTHORIZATION DEFINITIONS =========== -->
|
||||
|
||||
<bean id="afterInvocationManager" class="org.springframework.security.afterinvocation.AfterInvocationProviderManager">
|
||||
<property name="providers">
|
||||
<list>
|
||||
<ref local="afterAclRead"/>
|
||||
<ref local="afterAclCollectionRead"/>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- Processes AFTER_ACL_COLLECTION_READ configuration settings -->
|
||||
<bean id="afterAclCollectionRead"
|
||||
class="org.springframework.security.afterinvocation.AclEntryAfterInvocationCollectionFilteringProvider">
|
||||
<constructor-arg ref="aclService"/>
|
||||
<constructor-arg>
|
||||
<list>
|
||||
<ref local="org.springframework.security.acls.domain.BasePermission.ADMINISTRATION"/>
|
||||
<ref local="org.springframework.security.acls.domain.BasePermission.READ"/>
|
||||
</list>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
|
||||
<!-- Processes AFTER_ACL_READ configuration settings -->
|
||||
<bean id="afterAclRead" class="org.springframework.security.afterinvocation.AclEntryAfterInvocationProvider">
|
||||
<constructor-arg ref="aclService"/>
|
||||
<constructor-arg>
|
||||
<list>
|
||||
<ref local="org.springframework.security.acls.domain.BasePermission.ADMINISTRATION"/>
|
||||
<ref local="org.springframework.security.acls.domain.BasePermission.READ"/>
|
||||
</list>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
|
|
|
@ -9,10 +9,10 @@
|
|||
-->
|
||||
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:sec="http://www.springframework.org/schema/security"
|
||||
xmlns:tx="http://www.springframework.org/schema/tx"
|
||||
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">
|
||||
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">
|
||||
|
||||
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
|
||||
<property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
|
||||
|
@ -26,38 +26,31 @@
|
|||
<property name="dataSource" ref="dataSource"/>
|
||||
</bean>
|
||||
|
||||
<tx:annotation-driven transaction-manager="transactionManager" />
|
||||
<!--
|
||||
<bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor">
|
||||
<property name="transactionManager" ref="transactionManager"/>
|
||||
<property name="transactionAttributeSource">
|
||||
<value>
|
||||
sample.contact.ContactManager.create=PROPAGATION_REQUIRED
|
||||
sample.contact.ContactManager.getAllRecipients=PROPAGATION_REQUIRED,readOnly
|
||||
sample.contact.ContactManager.getAll=PROPAGATION_REQUIRED,readOnly
|
||||
sample.contact.ContactManager.getById=PROPAGATION_REQUIRED,readOnly
|
||||
sample.contact.ContactManager.delete=PROPAGATION_REQUIRED
|
||||
sample.contact.ContactManager.deletePermission=PROPAGATION_REQUIRED
|
||||
sample.contact.ContactManager.addPermission=PROPAGATION_REQUIRED
|
||||
</value>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<property name="transactionAttributeSource">
|
||||
<value>
|
||||
sample.contact.ContactManager.create=PROPAGATION_REQUIRED
|
||||
sample.contact.ContactManager.getAllRecipients=PROPAGATION_REQUIRED,readOnly
|
||||
sample.contact.ContactManager.getAll=PROPAGATION_REQUIRED,readOnly
|
||||
sample.contact.ContactManager.getById=PROPAGATION_REQUIRED,readOnly
|
||||
sample.contact.ContactManager.delete=PROPAGATION_REQUIRED
|
||||
sample.contact.ContactManager.deletePermission=PROPAGATION_REQUIRED
|
||||
sample.contact.ContactManager.addPermission=PROPAGATION_REQUIRED
|
||||
</value>
|
||||
</property>
|
||||
</bean>
|
||||
-->
|
||||
<bean id="dataSourcePopulator" class="sample.contact.DataSourcePopulator">
|
||||
<property name="dataSource" ref="dataSource"/>
|
||||
<property name="mutableAclService" ref="aclService"/>
|
||||
<property name="platformTransactionManager" ref="transactionManager"/>
|
||||
</bean>
|
||||
|
||||
<bean id="contactManager" class="org.springframework.aop.framework.ProxyFactoryBean">
|
||||
<property name="proxyInterfaces" value="sample.contact.ContactManager"/>
|
||||
<property name="interceptorNames">
|
||||
<list>
|
||||
<idref local="transactionInterceptor"/>
|
||||
<idref local="contactManagerTarget"/>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="contactManagerTarget" class="sample.contact.ContactManagerBackend">
|
||||
<bean id="contactManager" class="sample.contact.ContactManagerBackend">
|
||||
<!--
|
||||
<sec:intercept-methods access-decision-manager-ref="businessAccessDecisionManager">
|
||||
<sec:protect method="sample.contact.ContactManager.create" access="ROLE_USER"/>
|
||||
<sec:protect method="sample.contact.ContactManager.getAllRecipients" access="ROLE_USER"/>
|
||||
|
@ -67,6 +60,7 @@
|
|||
<sec:protect method="sample.contact.ContactManager.deletePermission" access="ACL_CONTACT_ADMIN"/>
|
||||
<sec:protect method="sample.contact.ContactManager.addPermission" access="ACL_CONTACT_ADMIN"/>
|
||||
</sec:intercept-methods>
|
||||
-->
|
||||
<property name="contactDao">
|
||||
<bean class="sample.contact.ContactDaoSpring">
|
||||
<property name="dataSource" ref="dataSource"/>
|
||||
|
|
|
@ -11,15 +11,18 @@
|
|||
<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"
|
||||
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.1.xsd">
|
||||
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">
|
||||
|
||||
<global-method-security expression-annotations="enabled">
|
||||
<permission-evaluator ref="permissionEvaluator"/>
|
||||
</global-method-security>
|
||||
|
||||
<http auto-config="true" realm="Contacts Realm">
|
||||
<intercept-url pattern="/" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
|
||||
<intercept-url pattern="/index.jsp" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
|
||||
<intercept-url pattern="/hello.htm" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
|
||||
<intercept-url pattern="/login.jsp*" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
|
||||
<intercept-url pattern="/login.jsp*" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
|
||||
<intercept-url pattern="/switchuser.jsp" access="ROLE_SUPERVISOR"/>
|
||||
<intercept-url pattern="/j_spring_security_switch_user" access="ROLE_SUPERVISOR"/>
|
||||
<intercept-url pattern="/**" access="ROLE_USER"/>
|
||||
|
@ -28,20 +31,24 @@
|
|||
<logout logout-success-url="/index.jsp"/>
|
||||
</http>
|
||||
|
||||
<authentication-provider>
|
||||
<authentication-provider>
|
||||
<password-encoder hash="md5"/>
|
||||
<jdbc-user-service data-source-ref="dataSource"/>
|
||||
</authentication-provider>
|
||||
</authentication-provider>
|
||||
|
||||
<!-- Automatically receives AuthenticationEvent messages -->
|
||||
<b:bean id="loggerListener" class="org.springframework.security.event.authentication.LoggerListener"/>
|
||||
<!-- Automatically receives AuthenticationEvent messages -->
|
||||
<b:bean id="loggerListener" class="org.springframework.security.event.authentication.LoggerListener"/>
|
||||
|
||||
<!-- Filter used to switch the user context. Note: the switch and exit url must be secured
|
||||
<!-- Filter used to switch the user context. Note: the switch and exit url must be secured
|
||||
based on the role granted the ability to 'switch' to another user -->
|
||||
<!-- In this example 'rod' has ROLE_SUPERVISOR that can switch to regular ROLE_USER(s) -->
|
||||
<b:bean id="switchUserProcessingFilter" class="org.springframework.security.ui.switchuser.SwitchUserProcessingFilter" autowire="byType">
|
||||
<custom-filter position="SWITCH_USER_FILTER"/>
|
||||
<!-- In this example 'rod' has ROLE_SUPERVISOR that can switch to regular ROLE_USER(s) -->
|
||||
<b:bean id="switchUserProcessingFilter" class="org.springframework.security.ui.switchuser.SwitchUserProcessingFilter" autowire="byType">
|
||||
<custom-filter position="SWITCH_USER_FILTER"/>
|
||||
<b:property name="targetUrl" value="/secure/index.htm"/>
|
||||
</b:bean>
|
||||
</b:bean>
|
||||
|
||||
<b:bean id="permissionEvaluator" class="org.springframework.security.acls.AclPermissionEvaluator">
|
||||
<b:constructor-arg ref="aclService" />
|
||||
</b:bean>
|
||||
|
||||
</b:beans>
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
<beans>
|
||||
|
||||
<!-- ========================== WEB DEFINITIONS ======================= -->
|
||||
<!-- ========================== WEB DEFINITIONS ======================= -->
|
||||
|
||||
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
|
||||
<property name="basename" value="messages"/>
|
||||
|
@ -21,6 +21,7 @@
|
|||
|
||||
<bean id="secureIndexController" class="sample.contact.SecureIndexController">
|
||||
<property name="contactManager" ref="contactManager"/>
|
||||
<property name="permissionEvaluator" ref="permissionEvaluator" />
|
||||
</bean>
|
||||
|
||||
<bean id="secureDeleteController" class="sample.contact.DeleteController">
|
||||
|
@ -75,9 +76,9 @@
|
|||
<property name="contactManager" ref="contactManager"/>
|
||||
</bean>
|
||||
|
||||
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
|
||||
<property name="prefix" value="/WEB-INF/jsp/"/>
|
||||
<property name="suffix" value=".jsp"/>
|
||||
</bean>
|
||||
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
|
||||
<property name="prefix" value="/WEB-INF/jsp/"/>
|
||||
<property name="suffix" value=".jsp"/>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<P>
|
||||
<table cellpadding=3 border=0>
|
||||
<tr><td><b>id</b></td><td><b>Name</b></td><td><b>Email</b></td></tr>
|
||||
<c:forEach var="contact" items="${model.contacts}">
|
||||
<c:forEach var="contact" items="${model.contacts}" >
|
||||
<tr>
|
||||
<td>
|
||||
<c:out value="${contact.id}"/>
|
||||
|
@ -18,12 +18,12 @@
|
|||
<td>
|
||||
<c:out value="${contact.email}"/>
|
||||
</td>
|
||||
<security:accesscontrollist domainObject="${contact}" hasPermission="8,16">
|
||||
<td><A HREF="<c:url value="del.htm"><c:param name="contactId" value="${contact.id}"/></c:url>">Del</A></td>
|
||||
</security:accesscontrollist>
|
||||
<security:accesscontrollist domainObject="${contact}" hasPermission="16">
|
||||
<td><A HREF="<c:url value="adminPermission.htm"><c:param name="contactId" value="${contact.id}"/></c:url>">Admin Permission</A></td>
|
||||
</security:accesscontrollist>
|
||||
<c:if test="${model.hasDeletePermission[contact]}">
|
||||
<td><a href="<c:url value="del.htm"><c:param name="contactId" value="${contact.id}"/></c:url>">Del</a></td>
|
||||
</c:if>
|
||||
<c:if test="${model.hasAdminPermission[contact]}">
|
||||
<td><a href="<c:url value="adminPermission.htm"><c:param name="contactId" value="${contact.id}"/></c:url>">Admin Permission</a></td>
|
||||
</c:if>
|
||||
</tr>
|
||||
</c:forEach>
|
||||
</table>
|
||||
|
|
|
@ -14,22 +14,24 @@
|
|||
*/
|
||||
package sample.contact;
|
||||
|
||||
import org.springframework.security.Authentication;
|
||||
|
||||
import org.springframework.security.acls.domain.BasePermission;
|
||||
import org.springframework.security.acls.sid.PrincipalSid;
|
||||
|
||||
import org.springframework.security.context.SecurityContextHolder;
|
||||
|
||||
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
|
||||
|
||||
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
|
||||
|
||||
import org.springframework.test.AbstractTransactionalSpringContextTests;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.Authentication;
|
||||
import org.springframework.security.acls.domain.BasePermission;
|
||||
import org.springframework.security.acls.sid.PrincipalSid;
|
||||
import org.springframework.security.context.SecurityContextHolder;
|
||||
import org.springframework.security.providers.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
|
||||
/**
|
||||
* Tests {@link ContactManager}.
|
||||
|
@ -37,9 +39,15 @@ import java.util.List;
|
|||
* @author David Leal
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public class GetAllContactsTests extends AbstractTransactionalSpringContextTests {
|
||||
@ContextConfiguration(locations={
|
||||
"/applicationContext-common-authorization.xml",
|
||||
"/applicationContext-common-business.xml",
|
||||
"/applicationContext-contacts-test.xml"})
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
public class GetAllContactsTests {
|
||||
//~ Instance fields ================================================================================================
|
||||
|
||||
@Autowired
|
||||
protected ContactManager contactManager;
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
|
@ -59,7 +67,7 @@ public class GetAllContactsTests extends AbstractTransactionalSpringContextTests
|
|||
fail("List of contacts should have contained: " + id);
|
||||
}
|
||||
|
||||
protected void assertNotContainsContact(String id, List contacts) {
|
||||
void assertDoestNotContainContact(String id, List contacts) {
|
||||
Iterator iter = contacts.iterator();
|
||||
|
||||
while (iter.hasNext()) {
|
||||
|
@ -71,15 +79,6 @@ public class GetAllContactsTests extends AbstractTransactionalSpringContextTests
|
|||
}
|
||||
}
|
||||
|
||||
protected String[] getConfigLocations() {
|
||||
setAutowireMode(AutowireCapableBeanFactory.AUTOWIRE_BY_NAME);
|
||||
|
||||
return new String[] {
|
||||
"applicationContext-common-authorization.xml", "applicationContext-common-business.xml",
|
||||
"applicationContext-contacts-test.xml"
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Locates the first <code>Contact</code> of the exact name specified.<p>Uses the {@link
|
||||
* ContactManager#getAll()} method.</p>
|
||||
|
@ -120,14 +119,12 @@ public class GetAllContactsTests extends AbstractTransactionalSpringContextTests
|
|||
SecurityContextHolder.getContext().setAuthentication(authRequest);
|
||||
}
|
||||
|
||||
protected void onTearDownInTransaction() {
|
||||
@After
|
||||
public void onTearDownInTransaction() {
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
public void setContactManager(ContactManager contactManager) {
|
||||
this.contactManager = contactManager;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDianne() {
|
||||
makeActiveUser("dianne"); // has ROLE_USER
|
||||
|
||||
|
@ -139,11 +136,12 @@ public class GetAllContactsTests extends AbstractTransactionalSpringContextTests
|
|||
assertContainsContact(Long.toString(6), contacts);
|
||||
assertContainsContact(Long.toString(8), contacts);
|
||||
|
||||
assertNotContainsContact(Long.toString(1), contacts);
|
||||
assertNotContainsContact(Long.toString(2), contacts);
|
||||
assertNotContainsContact(Long.toString(3), contacts);
|
||||
assertDoestNotContainContact(Long.toString(1), contacts);
|
||||
assertDoestNotContainContact(Long.toString(2), contacts);
|
||||
assertDoestNotContainContact(Long.toString(3), contacts);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testrod() {
|
||||
makeActiveUser("rod"); // has ROLE_SUPERVISOR
|
||||
|
||||
|
@ -156,13 +154,14 @@ public class GetAllContactsTests extends AbstractTransactionalSpringContextTests
|
|||
assertContainsContact(Long.toString(3), contacts);
|
||||
assertContainsContact(Long.toString(4), contacts);
|
||||
|
||||
assertNotContainsContact(Long.toString(5), contacts);
|
||||
assertDoestNotContainContact(Long.toString(5), contacts);
|
||||
|
||||
Contact c1 = contactManager.getById(new Long(4));
|
||||
|
||||
contactManager.deletePermission(c1, new PrincipalSid("bob"), BasePermission.ADMINISTRATION);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testScott() {
|
||||
makeActiveUser("scott"); // has ROLE_USER
|
||||
|
||||
|
@ -176,6 +175,6 @@ public class GetAllContactsTests extends AbstractTransactionalSpringContextTests
|
|||
assertContainsContact(Long.toString(8), contacts);
|
||||
assertContainsContact(Long.toString(9), contacts);
|
||||
|
||||
assertNotContainsContact(Long.toString(1), contacts);
|
||||
assertDoestNotContainContact(Long.toString(1), contacts);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,9 +10,12 @@
|
|||
<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"
|
||||
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">
|
||||
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">
|
||||
|
||||
<global-method-security expression-annotations="enabled">
|
||||
<permission-evaluator ref="permissionEvaluator"/>
|
||||
</global-method-security>
|
||||
|
||||
<!-- ======================== AUTHENTICATION ======================= -->
|
||||
|
||||
|
@ -21,8 +24,8 @@
|
|||
<jdbc-user-service data-source-ref="dataSource"/>
|
||||
</authentication-provider>
|
||||
|
||||
|
||||
<!-- Automatically receives AuthenticationEvent messages -->
|
||||
<b:bean id="loggerListener" class="org.springframework.security.event.authentication.LoggerListener"/>
|
||||
<b:bean id="permissionEvaluator" class="org.springframework.security.acls.AclPermissionEvaluator">
|
||||
<b:constructor-arg ref="aclService" />
|
||||
</b:bean>
|
||||
|
||||
</b:beans>
|
||||
|
|
Loading…
Reference in New Issue