SEC-1452: Added namespace support for custom expression handler for use with web access expressions.
This commit is contained in:
parent
63f160dc72
commit
27caecd53f
|
@ -8,6 +8,7 @@ import org.springframework.beans.factory.config.BeanDefinition;
|
|||
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.ManagedMap;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
|
@ -59,7 +60,7 @@ public class FilterInvocationSecurityMetadataSourceParser implements BeanDefinit
|
|||
return mds;
|
||||
}
|
||||
|
||||
static BeanDefinition createSecurityMetadataSource(List<Element> interceptUrls, Element elt, ParserContext pc) {
|
||||
static RootBeanDefinition createSecurityMetadataSource(List<Element> interceptUrls, Element elt, ParserContext pc) {
|
||||
MatcherType matcherType = MatcherType.fromElement(elt);
|
||||
boolean useExpressions = isUseExpressions(elt);
|
||||
|
||||
|
@ -87,7 +88,7 @@ public class FilterInvocationSecurityMetadataSourceParser implements BeanDefinit
|
|||
|
||||
fidsBuilder.getRawBeanDefinition().setSource(pc.extractSource(elt));
|
||||
|
||||
return fidsBuilder.getBeanDefinition();
|
||||
return (RootBeanDefinition) fidsBuilder.getBeanDefinition();
|
||||
}
|
||||
|
||||
static String registerDefaultExpressionHandler(ParserContext pc) {
|
||||
|
|
|
@ -451,15 +451,17 @@ class HttpConfigurationBuilder {
|
|||
|
||||
private void createFilterSecurityInterceptor(BeanReference authManager) {
|
||||
boolean useExpressions = FilterInvocationSecurityMetadataSourceParser.isUseExpressions(httpElt);
|
||||
BeanDefinition securityMds = FilterInvocationSecurityMetadataSourceParser.createSecurityMetadataSource(interceptUrls, httpElt, pc);
|
||||
RootBeanDefinition securityMds = FilterInvocationSecurityMetadataSourceParser.createSecurityMetadataSource(interceptUrls, httpElt, pc);
|
||||
|
||||
RootBeanDefinition accessDecisionMgr;
|
||||
ManagedList<BeanDefinition> voters = new ManagedList<BeanDefinition>(2);
|
||||
|
||||
if (useExpressions) {
|
||||
BeanDefinitionBuilder expressionVoter = BeanDefinitionBuilder.rootBeanDefinition(WebExpressionVoter.class);
|
||||
RuntimeBeanReference expressionHandler = new RuntimeBeanReference(
|
||||
FilterInvocationSecurityMetadataSourceParser.registerDefaultExpressionHandler(pc));
|
||||
// Read the expression handler from the FISMS
|
||||
RuntimeBeanReference expressionHandler = (RuntimeBeanReference)
|
||||
securityMds.getConstructorArgumentValues().getArgumentValue(1, RuntimeBeanReference.class).getValue();
|
||||
|
||||
expressionVoter.addPropertyValue("expressionHandler", expressionHandler);
|
||||
|
||||
voters.add(expressionVoter.getBeanDefinition());
|
||||
|
|
|
@ -268,7 +268,7 @@ http-firewall =
|
|||
|
||||
http =
|
||||
## Container element for HTTP security configuration. Multiple elements can now be defined, each with a specific pattern to which the enclosed security configuration applies. A pattern can also be configured to bypass Spring Security's filters completely by setting the "secured" attribute to "false".
|
||||
element http {http.attlist, (intercept-url* & access-denied-handler? & form-login? & openid-login? & x509? & jee? & http-basic? & logout? & session-management & remember-me? & anonymous? & port-mappings & custom-filter* & request-cache?) }
|
||||
element http {http.attlist, (intercept-url* & access-denied-handler? & form-login? & openid-login? & x509? & jee? & http-basic? & logout? & session-management & remember-me? & anonymous? & port-mappings & custom-filter* & request-cache? & expression-handler?) }
|
||||
http.attlist &=
|
||||
## The request URL pattern which will be mapped to the filter chain created by this <http> element. If omitted, the filter chain will match all requests.
|
||||
attribute pattern {xsd:token}?
|
||||
|
|
|
@ -682,6 +682,11 @@
|
|||
</xs:complexType></xs:element>
|
||||
<xs:element ref="security:custom-filter"/>
|
||||
<xs:element ref="security:request-cache"/>
|
||||
<xs:element name="expression-handler"><xs:annotation>
|
||||
<xs:documentation>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.</xs:documentation>
|
||||
</xs:annotation><xs:complexType>
|
||||
<xs:attributeGroup ref="security:ref"/>
|
||||
</xs:complexType></xs:element>
|
||||
</xs:choice>
|
||||
<xs:attributeGroup ref="security:http.attlist"/>
|
||||
</xs:complexType></xs:element>
|
||||
|
|
|
@ -50,6 +50,9 @@ import org.springframework.security.authentication.dao.DaoAuthenticationProvider
|
|||
import org.springframework.security.access.vote.RoleVoter
|
||||
import org.springframework.security.web.access.expression.WebExpressionVoter
|
||||
import org.springframework.security.access.vote.AffirmativeBased
|
||||
import org.springframework.security.access.PermissionEvaluator
|
||||
import org.springframework.security.core.Authentication
|
||||
import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler
|
||||
|
||||
class MiscHttpConfigTests extends AbstractHttpConfigTests {
|
||||
def 'Minimal configuration parses'() {
|
||||
|
@ -497,6 +500,25 @@ class MiscHttpConfigTests extends AbstractHttpConfigTests {
|
|||
thrown(AccessDeniedException)
|
||||
}
|
||||
|
||||
def expressionBasedAccessSupportsExternalExpressionHandler() {
|
||||
setup:
|
||||
xml.http('auto-config': 'true', 'use-expressions': 'true') {
|
||||
interceptUrl('/**', "hasPermission('AnyObject','R')")
|
||||
'expression-handler'(ref: 'expressionHandler')
|
||||
}
|
||||
bean('expressionHandler', DefaultWebSecurityExpressionHandler.class.name, [:], [permissionEvaluator: 'pe'])
|
||||
bean('pe', MockPermissionEvaluator)
|
||||
createAppContext()
|
||||
|
||||
def fis = getFilter(FilterSecurityInterceptor)
|
||||
|
||||
when: "Invoking allowed URL protected by hasPermission() expression succeeds"
|
||||
SecurityContextHolder.getContext().setAuthentication(new TestingAuthenticationToken("joe", "", "ANY"));
|
||||
fis.invoke(createFilterinvocation("/secure", null));
|
||||
then:
|
||||
notThrown(AccessDeniedException)
|
||||
}
|
||||
|
||||
def protectedLoginPageReportsWarning() {
|
||||
when:
|
||||
xml.http('use-expressions': 'true') {
|
||||
|
@ -647,6 +669,17 @@ class MiscHttpConfigTests extends AbstractHttpConfigTests {
|
|||
}
|
||||
}
|
||||
|
||||
class MockPermissionEvaluator implements PermissionEvaluator {
|
||||
boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) {
|
||||
return true
|
||||
}
|
||||
|
||||
boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) {
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class MockEntryPoint extends LoginUrlAuthenticationEntryPoint {
|
||||
public MockEntryPoint() {
|
||||
super.setLoginFormUrl("/notused");
|
||||
|
|
Loading…
Reference in New Issue