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.parsing.BeanComponentDefinition;
|
||||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||||
import org.springframework.beans.factory.support.ManagedMap;
|
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.AbstractBeanDefinitionParser;
|
||||||
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
import org.springframework.beans.factory.xml.BeanDefinitionParser;
|
||||||
import org.springframework.beans.factory.xml.ParserContext;
|
import org.springframework.beans.factory.xml.ParserContext;
|
||||||
|
@ -59,7 +60,7 @@ public class FilterInvocationSecurityMetadataSourceParser implements BeanDefinit
|
||||||
return mds;
|
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);
|
MatcherType matcherType = MatcherType.fromElement(elt);
|
||||||
boolean useExpressions = isUseExpressions(elt);
|
boolean useExpressions = isUseExpressions(elt);
|
||||||
|
|
||||||
|
@ -87,7 +88,7 @@ public class FilterInvocationSecurityMetadataSourceParser implements BeanDefinit
|
||||||
|
|
||||||
fidsBuilder.getRawBeanDefinition().setSource(pc.extractSource(elt));
|
fidsBuilder.getRawBeanDefinition().setSource(pc.extractSource(elt));
|
||||||
|
|
||||||
return fidsBuilder.getBeanDefinition();
|
return (RootBeanDefinition) fidsBuilder.getBeanDefinition();
|
||||||
}
|
}
|
||||||
|
|
||||||
static String registerDefaultExpressionHandler(ParserContext pc) {
|
static String registerDefaultExpressionHandler(ParserContext pc) {
|
||||||
|
|
|
@ -451,15 +451,17 @@ class HttpConfigurationBuilder {
|
||||||
|
|
||||||
private void createFilterSecurityInterceptor(BeanReference authManager) {
|
private void createFilterSecurityInterceptor(BeanReference authManager) {
|
||||||
boolean useExpressions = FilterInvocationSecurityMetadataSourceParser.isUseExpressions(httpElt);
|
boolean useExpressions = FilterInvocationSecurityMetadataSourceParser.isUseExpressions(httpElt);
|
||||||
BeanDefinition securityMds = FilterInvocationSecurityMetadataSourceParser.createSecurityMetadataSource(interceptUrls, httpElt, pc);
|
RootBeanDefinition securityMds = FilterInvocationSecurityMetadataSourceParser.createSecurityMetadataSource(interceptUrls, httpElt, pc);
|
||||||
|
|
||||||
RootBeanDefinition accessDecisionMgr;
|
RootBeanDefinition accessDecisionMgr;
|
||||||
ManagedList<BeanDefinition> voters = new ManagedList<BeanDefinition>(2);
|
ManagedList<BeanDefinition> voters = new ManagedList<BeanDefinition>(2);
|
||||||
|
|
||||||
if (useExpressions) {
|
if (useExpressions) {
|
||||||
BeanDefinitionBuilder expressionVoter = BeanDefinitionBuilder.rootBeanDefinition(WebExpressionVoter.class);
|
BeanDefinitionBuilder expressionVoter = BeanDefinitionBuilder.rootBeanDefinition(WebExpressionVoter.class);
|
||||||
RuntimeBeanReference expressionHandler = new RuntimeBeanReference(
|
// Read the expression handler from the FISMS
|
||||||
FilterInvocationSecurityMetadataSourceParser.registerDefaultExpressionHandler(pc));
|
RuntimeBeanReference expressionHandler = (RuntimeBeanReference)
|
||||||
|
securityMds.getConstructorArgumentValues().getArgumentValue(1, RuntimeBeanReference.class).getValue();
|
||||||
|
|
||||||
expressionVoter.addPropertyValue("expressionHandler", expressionHandler);
|
expressionVoter.addPropertyValue("expressionHandler", expressionHandler);
|
||||||
|
|
||||||
voters.add(expressionVoter.getBeanDefinition());
|
voters.add(expressionVoter.getBeanDefinition());
|
||||||
|
|
|
@ -268,7 +268,7 @@ http-firewall =
|
||||||
|
|
||||||
http =
|
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".
|
## 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 &=
|
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.
|
## 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}?
|
attribute pattern {xsd:token}?
|
||||||
|
|
|
@ -682,6 +682,11 @@
|
||||||
</xs:complexType></xs:element>
|
</xs:complexType></xs:element>
|
||||||
<xs:element ref="security:custom-filter"/>
|
<xs:element ref="security:custom-filter"/>
|
||||||
<xs:element ref="security:request-cache"/>
|
<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:choice>
|
||||||
<xs:attributeGroup ref="security:http.attlist"/>
|
<xs:attributeGroup ref="security:http.attlist"/>
|
||||||
</xs:complexType></xs:element>
|
</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.access.vote.RoleVoter
|
||||||
import org.springframework.security.web.access.expression.WebExpressionVoter
|
import org.springframework.security.web.access.expression.WebExpressionVoter
|
||||||
import org.springframework.security.access.vote.AffirmativeBased
|
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 {
|
class MiscHttpConfigTests extends AbstractHttpConfigTests {
|
||||||
def 'Minimal configuration parses'() {
|
def 'Minimal configuration parses'() {
|
||||||
|
@ -497,6 +500,25 @@ class MiscHttpConfigTests extends AbstractHttpConfigTests {
|
||||||
thrown(AccessDeniedException)
|
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() {
|
def protectedLoginPageReportsWarning() {
|
||||||
when:
|
when:
|
||||||
xml.http('use-expressions': 'true') {
|
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 {
|
class MockEntryPoint extends LoginUrlAuthenticationEntryPoint {
|
||||||
public MockEntryPoint() {
|
public MockEntryPoint() {
|
||||||
super.setLoginFormUrl("/notused");
|
super.setLoginFormUrl("/notused");
|
||||||
|
|
Loading…
Reference in New Issue