interceptor for securing endpoints based on new endpoint interception model

namespace support to follow
This commit is contained in:
Jonas Partner
2008-06-27 17:47:17 +00:00
parent 8623920db5
commit f9ad394850
33 changed files with 493 additions and 969 deletions

View File

@@ -1,64 +0,0 @@
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.integration.security;
import org.springframework.integration.handler.InterceptingMessageHandler;
import org.springframework.integration.handler.MessageHandler;
import org.springframework.integration.message.Message;
import org.springframework.security.context.SecurityContext;
import org.springframework.security.context.SecurityContextHolder;
/**
* Associates the {@link SecurityContext} propagated in the message header with
* the thread executing the handle call to a {@link MessageHandler}.
*
* @author Jonas Partner
*/
public class SecurityContextAssociatingHandlerInterceptor extends InterceptingMessageHandler {
/**
* One time only set the strategy to be stack based to allow use of direct
* channels where push and pop is required rather than set and clear
*/
static {
SecurityContextHolder.setStrategyName(StackBasedSecurityContextHolderStrategy.class.getName());
}
public SecurityContextAssociatingHandlerInterceptor(MessageHandler target) {
super(target);
}
@Override
public Message<?> handle(Message<?> message, MessageHandler target) {
if (message.getHeader().getAttributeNames().contains(SecurityContextUtils.SECURITY_CONTEXT_HEADER_ATTRIBUTE)) {
return handleInSecurityContext(message, target);
}
return target.handle(message);
}
private Message<?> handleInSecurityContext(Message<?> message, MessageHandler target) {
SecurityContext context = SecurityContextUtils.getSecurityContextFromHeader(message);
SecurityContextHolder.setContext(context);
try {
return target.handle(message);
}
finally {
SecurityContextHolder.clearContext();
}
}
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.integration.security.config;
package org.springframework.integration.security.channel.config;
import java.util.ArrayList;
import java.util.List;
@@ -61,7 +61,6 @@ public class SecuredChannelsParser extends AbstractSingleBeanDefinitionParser {
String receiveAccess = element.getAttribute("receive-access");
String sendAccess = element.getAttribute("send-access");
String accessDecisionManager = element.getAttribute("access-decision-manager");
String propagation = element.getAttribute("propagate");
BeanDefinition interceptorBeanDefinition = createSecurityEnforcingChannelInterceptor(accessDecisionManager,
sendAccess, receiveAccess);
@@ -75,7 +74,6 @@ public class SecuredChannelsParser extends AbstractSingleBeanDefinitionParser {
builder.getBeanDefinition().getConstructorArgumentValues()
.addGenericArgumentValue(new ValueHolder(patternList));
setPropagation(Boolean.parseBoolean(propagation), patternList, parserContext);
}
protected List<String> processPatterns(NodeList patternList) {
@@ -85,19 +83,6 @@ public class SecuredChannelsParser extends AbstractSingleBeanDefinitionParser {
patterns.add(patternElement.getTextContent());
}
return patterns;
}
protected void setPropagation(boolean propagation, List<String> patterns, ParserContext parserContext) {
for (String pattern : patterns) {
if (propagation) {
SecurityPropagatingBeanPostProcessorDefinitionHelper.addToIncludeChannelList(pattern, parserContext);
}
else {
SecurityPropagatingBeanPostProcessorDefinitionHelper.addToExcludeChannelList(pattern, parserContext);
}
}
}
protected BeanDefinition createSecurityEnforcingChannelInterceptor(String accessDecisionManager, String sendAccess,

View File

@@ -14,11 +14,7 @@
* limitations under the License.
*/
package org.springframework.integration.security.config;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
package org.springframework.integration.security.channel.config;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -27,6 +23,7 @@ import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.Ordered;
import org.springframework.integration.channel.AbstractMessageChannel;
import org.springframework.integration.security.channel.SecurityContextPropagatingChannelInterceptor;
import org.springframework.integration.security.config.OrderedIncludeExcludeList;
/**
* Post processes channels applying appropriate propagation behaviour. If
@@ -43,36 +40,12 @@ public class SecurityPropagatingBeanPostProcessor implements BeanPostProcessor,
private final SecurityContextPropagatingChannelInterceptor interceptor = new SecurityContextPropagatingChannelInterceptor();
private boolean propagateByDefault;
private final Log logger = LogFactory.getLog(this.getClass());
private List<Pattern> channelsToInclude = new ArrayList<Pattern>();
private final OrderedIncludeExcludeList includeExcludeList;
private List<Pattern> channelsToExclude = new ArrayList<Pattern>();
public boolean isPropagateByDefault() {
return this.propagateByDefault;
}
public void setPropagateByDefault(boolean propagateByDefault) {
this.propagateByDefault = propagateByDefault;
}
public List<Pattern> getChannelsToInclude() {
return this.channelsToInclude;
}
public void setChannelsToInclude(List<Pattern> channelsToInclude) {
this.channelsToInclude = channelsToInclude;
}
public List<Pattern> getChannelsToExclude() {
return this.channelsToExclude;
}
public void setChannelsToExclude(List<Pattern> channelsToExclude) {
this.channelsToExclude = channelsToExclude;
public SecurityPropagatingBeanPostProcessor(OrderedIncludeExcludeList includeExcludeList) {
this.includeExcludeList = includeExcludeList;
}
public int getOrder() {
@@ -86,7 +59,7 @@ public class SecurityPropagatingBeanPostProcessor implements BeanPostProcessor,
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (AbstractMessageChannel.class.isAssignableFrom(bean.getClass())) {
AbstractMessageChannel channel = (AbstractMessageChannel) bean;
if (isIncluded(beanName) || (this.propagateByDefault && !isExcluded(beanName))) {
if (includeExcludeList.isIncluded(beanName)) {
channel.addInterceptor(this.interceptor);
if (logger.isDebugEnabled()) {
logger.debug("Channel '" + beanName + "' will propagate a SecurityContext.");
@@ -99,21 +72,4 @@ public class SecurityPropagatingBeanPostProcessor implements BeanPostProcessor,
return bean;
}
protected boolean isExcluded(String str) {
return matchesOnePattern(channelsToExclude, str);
}
protected boolean isIncluded(String str) {
return matchesOnePattern(channelsToInclude, str);
}
protected boolean matchesOnePattern(List<Pattern> patterns, String str) {
for (Pattern pattern : patterns) {
if (pattern.matcher(str).matches()) {
return true;
}
}
return false;
}
}

View File

@@ -14,15 +14,23 @@
* limitations under the License.
*/
package org.springframework.integration.security.config;
package org.springframework.integration.security.channel.config;
import java.util.ArrayList;
import java.util.List;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.config.ConstructorArgumentValues.ValueHolder;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.security.config.IncludeExcludePattern;
import org.springframework.integration.security.config.IncludeExcludePatternParser;
import org.springframework.integration.security.config.OrderedIncludeExcludeList;
import org.springframework.security.context.SecurityContext;
import org.springframework.util.StringUtils;
@@ -34,17 +42,17 @@ import org.springframework.util.StringUtils;
*/
public class SecurityPropagatingChannelsParser extends AbstractSingleBeanDefinitionParser {
IncludeExcludePatternParser includeExcludePatternParser = new IncludeExcludePatternParser();
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
builder.getBeanDefinition().setAbstract(true);
String propagation = element.getAttribute("propagate");
boolean propagateByDefault = true;
if (StringUtils.hasText(propagation)) {
propagateByDefault = Boolean.parseBoolean(propagation);
}
if (propagateByDefault) {
SecurityPropagatingBeanPostProcessorDefinitionHelper.setPropagationDefault(true, parserContext);
}
boolean propagateByDefault = Boolean.parseBoolean(element.getAttribute("propagate-by-default"));
OrderedIncludeExcludeList includeExcludeList = includeExcludePatternParser.createFromNodeList(
propagateByDefault, element.getChildNodes());
builder.getBeanDefinition().setBeanClass(SecurityPropagatingBeanPostProcessor.class);
builder.getBeanDefinition().getConstructorArgumentValues().addGenericArgumentValue(
new ValueHolder(includeExcludeList));
}
@Override

View File

@@ -1,14 +1,30 @@
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.integration.security.config;
/**
*
* @author Jonas Partner
*
*
*/
public class IncludeExcludePattern {
private final boolean isIncludePattern;
private final String pattern;
public IncludeExcludePattern(boolean isIncludePattern, String pattern) {
@@ -17,9 +33,9 @@ public class IncludeExcludePattern {
}
public IncludeExcludePattern(String pattern) {
this(true,pattern);
this(true, pattern);
}
public boolean isIncludePattern() {
return isIncludePattern;
}
@@ -27,5 +43,5 @@ public class IncludeExcludePattern {
public String getPattern() {
return pattern;
}
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.integration.security.config;
import java.util.ArrayList;
import java.util.List;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
public class IncludeExcludePatternParser {
public OrderedIncludeExcludeList createFromNodeList(boolean includeByDefault, NodeList nodeList) {
List<IncludeExcludePattern> patterns = new ArrayList<IncludeExcludePattern>();
for (int i = 0; i < nodeList.getLength(); i++) {
if (nodeList.item(i).getNodeName().equals("includePattern")) {
patterns.add(new IncludeExcludePattern(true, ((Element) nodeList.item(i)).getTextContent()));
}
else if (nodeList.item(i).getNodeName().equals("excludePattern")) {
patterns.add(new IncludeExcludePattern(false, ((Element) nodeList.item(i)).getTextContent()));
}
}
return new JdkRegExpOrderedIncludeExcludeList(includeByDefault, patterns);
}
}

View File

@@ -17,6 +17,8 @@
package org.springframework.integration.security.config;
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
import org.springframework.integration.security.channel.config.SecuredChannelsParser;
import org.springframework.integration.security.channel.config.SecurityPropagatingChannelsParser;
/**
* Namespace handler for the security namespace.

View File

@@ -1,3 +1,19 @@
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.integration.security.config;
import java.util.ArrayList;
@@ -6,38 +22,38 @@ import java.util.List;
import java.util.regex.Pattern;
public class JdkRegExpOrderedIncludeExcludeList implements OrderedIncludeExcludeList {
private final boolean includeByDefault;
private final List<PatternHolder> patternHolders;
public JdkRegExpOrderedIncludeExcludeList(List<IncludeExcludePattern> patterns){
public JdkRegExpOrderedIncludeExcludeList(List<IncludeExcludePattern> patterns) {
this(true, patterns);
}
public JdkRegExpOrderedIncludeExcludeList(boolean includeByDefault, List<IncludeExcludePattern> patterns) {
super();
this.includeByDefault = includeByDefault;
List<PatternHolder> patternHolders = new ArrayList<PatternHolder>();
for(int i = 0 ; i <patterns.size(); i++){
patternHolders.add(new PatternHolder(Pattern.compile(patterns.get(i).getPattern()), patterns.get(i)) );
for (int i = 0; i < patterns.size(); i++) {
patternHolders.add(new PatternHolder(Pattern.compile(patterns.get(i).getPattern()), patterns.get(i)));
}
this.patternHolders = Collections.unmodifiableList(patternHolders);
}
public boolean isIncluded(String name) {
for(int i = 0; i < patternHolders.size(); i++){
if(patternHolders.get(i).compiledPattern.matcher(name).matches()){
for (int i = 0; i < patternHolders.size(); i++) {
if (patternHolders.get(i).compiledPattern.matcher(name).matches()) {
return (patternHolders.get(i).includeExcludePattern.isIncludePattern());
}
}
return includeByDefault;
}
private static class PatternHolder{
private static class PatternHolder {
private final Pattern compiledPattern;
private final IncludeExcludePattern includeExcludePattern;
public PatternHolder(Pattern compiledPattern, IncludeExcludePattern includeExcludePattern) {
@@ -46,11 +62,6 @@ public class JdkRegExpOrderedIncludeExcludeList implements OrderedIncludeExclude
this.includeExcludePattern = includeExcludePattern;
}
}
}

View File

@@ -1,3 +1,19 @@
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.integration.security.config;

View File

@@ -1,93 +0,0 @@
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.integration.security.config;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.RuntimeBeanNameReference;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.context.ApplicationContext;
/**
* Helper to configure the per {@link ApplicationContext}
* {@link SecurityPropagatingBeanPostProcessor} which determines
* {@link SecurityContext} propagation.
*
* @author Jonas Partner
*/
public class SecurityPropagatingBeanPostProcessorDefinitionHelper {
private static final String CHANNELS_TO_INCLUDE = "channelsToInclude";
private static final String CHANNELS_TO_EXCLUDE = "channelsToExclude";
private static final String PROPAGATE_BY_DEFAULT = "propagateByDefault";
public static void setPropagationDefault(boolean valueForPropagationDefault, ParserContext context) {
BeanDefinition beanDefintion = getOrCreateSecurityPropagatingBeanPostProcessor(context);
beanDefintion.getPropertyValues().addPropertyValue(PROPAGATE_BY_DEFAULT,
Boolean.valueOf(valueForPropagationDefault));
}
@SuppressWarnings("unchecked")
public static void addToExcludeChannelList(String channelName, ParserContext context) {
BeanDefinition beanDefintion = getOrCreateSecurityPropagatingBeanPostProcessor(context);
List channelsToExclude;
if (beanDefintion.getPropertyValues().contains(CHANNELS_TO_EXCLUDE)) {
channelsToExclude = (List) beanDefintion.getPropertyValues().getPropertyValue(CHANNELS_TO_EXCLUDE)
.getValue();
}
else {
channelsToExclude = new ArrayList<RuntimeBeanNameReference>();
beanDefintion.getPropertyValues().addPropertyValue(CHANNELS_TO_EXCLUDE, channelsToExclude);
}
channelsToExclude.add(channelName);
}
@SuppressWarnings("unchecked")
public static void addToIncludeChannelList(String channelName, ParserContext context) {
BeanDefinition beanDefintion = getOrCreateSecurityPropagatingBeanPostProcessor(context);
List channelsToExclude;
if (beanDefintion.getPropertyValues().contains(CHANNELS_TO_INCLUDE)) {
channelsToExclude = (List) beanDefintion.getPropertyValues().getPropertyValue(CHANNELS_TO_INCLUDE)
.getValue();
}
else {
channelsToExclude = new ArrayList<RuntimeBeanNameReference>();
beanDefintion.getPropertyValues().addPropertyValue(CHANNELS_TO_INCLUDE, channelsToExclude);
}
channelsToExclude.add(channelName);
}
private static BeanDefinition getOrCreateSecurityPropagatingBeanPostProcessor(ParserContext context) {
BeanDefinition beanDefinition = null;
String postProcessorBeanName = SecurityPropagatingBeanPostProcessor.SECURITY_PROPAGATING_BEAN_POST_PROCESSOR_NAME;
if (context.getRegistry().containsBeanDefinition(postProcessorBeanName)) {
beanDefinition = context.getRegistry().getBeanDefinition(postProcessorBeanName);
}
if (beanDefinition == null) {
beanDefinition = new RootBeanDefinition(SecurityPropagatingBeanPostProcessor.class);
context.registerBeanComponent(new BeanComponentDefinition(beanDefinition, postProcessorBeanName));
}
return beanDefinition;
}
}

View File

@@ -24,7 +24,6 @@
<xsd:attribute name="receive-access" type="xsd:string" />
<xsd:attribute name="send-access" type="xsd:string" />
<xsd:attribute name="access-decision-manager" type="xsd:string" default="accessDecisionManager"/>
<xsd:attribute name="propagate" type="xsd:boolean" default="true" />
</xsd:complexType>
</xsd:element>
@@ -49,14 +48,26 @@
<xsd:element name="security-propagating-channels">
<xsd:complexType>
<xsd:annotation>
<xsd:documentation>
Defines a bean post processor which propagates the
security context.
security context by registering interceptors with channels.
</xsd:documentation>
</xsd:annotation>
<xsd:attribute name="propagate" type="xsd:boolean" default="true" />
<xsd:sequence>
<xsd:element name="propagation-patterns" type="propagationPatternType" maxOccurs="1" minOccurs="0"/>
</xsd:sequence>
<xsd:attribute name="propagate-by-default" type="xsd:boolean" default="true" />
</xsd:complexType>
</xsd:element>
<xsd:complexType name="propagationPatternType">
<xsd:choice maxOccurs="unbounded" minOccurs="0">
<xsd:element name="includePattern" type="xsd:string"/>
<xsd:element name="excludePattern" type="xsd:string"/>
</xsd:choice>
</xsd:complexType>
</xsd:schema>

View File

@@ -14,9 +14,8 @@
* limitations under the License.
*/
package org.springframework.integration.security.target;
package org.springframework.integration.security.endpoint;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.integration.message.Message;
import org.springframework.integration.security.SecurityContextUtils;
@@ -24,33 +23,35 @@ import org.springframework.security.AccessDecisionManager;
import org.springframework.security.ConfigAttributeDefinition;
import org.springframework.security.context.SecurityContext;
import org.springframework.security.context.SecurityContextHolder;
import org.springframework.temp.endpoint.EndpointInterceptor;
/**
*
* @author Jonas Partner
*
*/
public class TargetSecuringInterceptor implements MethodInterceptor {
public class SecurityEndpointInterceptor implements EndpointInterceptor {
private final ConfigAttributeDefinition targetSecurityAttributes;
private final AccessDecisionManager accessDecisionManager;
public TargetSecuringInterceptor(ConfigAttributeDefinition targetSecurityAttributes,
public SecurityEndpointInterceptor(ConfigAttributeDefinition endpointSecurityAttributes,
AccessDecisionManager accessDecisionManager) {
this.targetSecurityAttributes = targetSecurityAttributes;
super();
this.targetSecurityAttributes = endpointSecurityAttributes;
this.accessDecisionManager = accessDecisionManager;
}
public Object invoke(MethodInvocation invocation) throws Throwable {
public void aroundInvoke(MethodInvocation invocation) throws Throwable {
Message<?> message = (Message<?>) invocation.getArguments()[0];
SecurityContext ctx = SecurityContextUtils.getSecurityContextFromHeader(message);
if (ctx != null) {
SecurityContext securityCtx = null;
if(message != null){
securityCtx = SecurityContextUtils.getSecurityContextFromHeader(message);
}
if (securityCtx != null) {
try {
SecurityContextHolder.setContext(ctx);
SecurityContextHolder.setContext(securityCtx);
accessDecisionManager.decide(SecurityContextHolder.getContext().getAuthentication(), invocation
.getThis(), targetSecurityAttributes);
return invocation.proceed();
invocation.proceed();
}
finally {
SecurityContextHolder.clearContext();
@@ -59,8 +60,16 @@ public class TargetSecuringInterceptor implements MethodInterceptor {
else {
accessDecisionManager.decide(SecurityContextHolder.getContext().getAuthentication(), invocation.getThis(),
targetSecurityAttributes);
return invocation.proceed();
invocation.proceed();
}
}
public void postInvoke(Message message) {
}
public void preInvoke(Message message) {
}
}

View File

@@ -1,68 +0,0 @@
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.integration.security.target;
import org.aopalliance.aop.Advice;
import org.springframework.aop.ClassFilter;
import org.springframework.aop.MethodMatcher;
import org.springframework.aop.Pointcut;
import org.springframework.aop.support.AbstractPointcutAdvisor;
import org.springframework.aop.support.ClassFilters;
import org.springframework.aop.support.MethodMatchers;
import org.springframework.aop.support.NameMatchMethodPointcut;
import org.springframework.aop.support.RootClassFilter;
import org.springframework.integration.message.BlockingTarget;
import org.springframework.integration.message.Target;
import org.springframework.security.AccessDecisionManager;
import org.springframework.security.ConfigAttributeDefinition;
import org.springframework.util.StringUtils;
@SuppressWarnings("serial")
public class TargetSecuringAdvisor extends AbstractPointcutAdvisor implements Pointcut {
private ClassFilter classFilter;
private MethodMatcher matcher;
private Advice targetSecuringInterceptor;
public TargetSecuringAdvisor(AccessDecisionManager accessDecisionManager, String securityConfig) {
targetSecuringInterceptor = new TargetSecuringInterceptor(new ConfigAttributeDefinition(StringUtils
.tokenizeToStringArray(securityConfig, ",")), accessDecisionManager);
classFilter = ClassFilters.union(new RootClassFilter(Target.class), new RootClassFilter(BlockingTarget.class));
NameMatchMethodPointcut nameMatcher = new NameMatchMethodPointcut();
nameMatcher.addMethodName("send");
matcher = MethodMatchers.intersection(nameMatcher, new TargetSendMethodArgMatcher());
}
public Pointcut getPointcut() {
return this;
}
public Advice getAdvice() {
return targetSecuringInterceptor;
}
public ClassFilter getClassFilter() {
return classFilter;
}
public MethodMatcher getMethodMatcher() {
return matcher;
}
}

View File

@@ -1,59 +0,0 @@
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.integration.security.target;
import java.lang.reflect.Method;
import org.springframework.aop.support.StaticMethodMatcher;
import org.springframework.integration.message.Message;
/**
*
* @author Jonas Partner
*
*/
public class TargetSendMethodArgMatcher extends StaticMethodMatcher{
@SuppressWarnings("unchecked")
public boolean matches(Method method, Class targetClass) {
return argsTypesMatch(method.getParameterTypes());
}
@SuppressWarnings("unchecked")
protected boolean argsTypesMatch(Class[] args){
if(args.length > 2){
return false;
}
if(args.length > 0){
if(!Message.class.isAssignableFrom(args[0] )){
return false;
}
}
if (args.length > 1 ){
if(!long.class.isAssignableFrom(args[1])){
return false;
}
}
return true;
}
}

View File

@@ -1,30 +0,0 @@
package org.springframework.integration.security.target.config;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.w3c.dom.Element;
public class SecuredTargetsParser extends AbstractSingleBeanDefinitionParser {
public SecuredTargetsParser() {
super();
}
@Override
protected boolean shouldGenerateId() {
return true;
}
@Override
protected boolean shouldGenerateIdAsFallback() {
return true;
}
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
}
}

View File

@@ -0,0 +1,28 @@
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.temp.endpoint;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.integration.message.Message;
public interface EndpointInterceptor {
void preInvoke(Message message);
void aroundInvoke(MethodInvocation invocation) throws Throwable;
void postInvoke(Message message);
}

View File

@@ -33,7 +33,7 @@ import org.springframework.integration.message.selector.MessageSelector;
/**
*
* @author Jonas Partner
*
*
*/
public class ChannelInterceptorRegisteringBeanPostProcessorTests {

View File

@@ -1,171 +0,0 @@
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.integration.security;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertNull;
import org.junit.After;
import org.junit.Test;
import org.springframework.integration.handler.MessageHandler;
import org.springframework.integration.message.Message;
import org.springframework.integration.message.StringMessage;
import org.springframework.security.AccessDeniedException;
import org.springframework.security.Authentication;
import org.springframework.security.GrantedAuthority;
import org.springframework.security.context.SecurityContext;
import org.springframework.security.context.SecurityContextHolder;
/**
* @author Jonas Partner
*/
public class SecurityContextAssociatingHandlerInterceptorTests {
@After
public void clearSecurityContext(){
SecurityContextHolder.clearContext();
}
@Test
public void testMessageWithSecurityContext() {
final StubSecurityContext securityContext = new StubSecurityContext();
StringMessage message = new StringMessage("test");
SecurityContextUtils.setSecurityContextHeader(securityContext, message);
MessageHandler handler = new MessageHandler() {
public Message<?> handle(Message<?> message) {
SecurityContext associatedContext = SecurityContextHolder.getContext();
assertEquals("Wrong security context", securityContext, associatedContext);
return null;
}
};
SecurityContextAssociatingHandlerInterceptor associatingInterceptor =
new SecurityContextAssociatingHandlerInterceptor(handler);
associatingInterceptor.handle(message);
assertNull("Security context still present after handler returned",
SecurityContextHolder.getContext().getAuthentication());
}
@Test(expected = AccessDeniedException.class)
public void testForSecurityLeakageIfHandlerThrowsException() {
final StubSecurityContext securityContext = new StubSecurityContext();
StringMessage message = new StringMessage("test");
SecurityContextUtils.setSecurityContextHeader(securityContext, message);
MessageHandler handler = new MessageHandler() {
public Message<?> handle(Message<?> message) {
SecurityContext associatedContext = SecurityContextHolder.getContext();
assertEquals("Wrong security context", securityContext, associatedContext);
throw new AccessDeniedException("Not allowed");
}
};
SecurityContextAssociatingHandlerInterceptor associatingInterceptor =
new SecurityContextAssociatingHandlerInterceptor(handler);
try {
associatingInterceptor.handle(message);
}
finally {
assertNull("Security context still present after handler threw exception",
SecurityContextHolder.getContext().getAuthentication());
}
}
@Test
public void testMessageWithoutSecurityContext() {
final StubSecurityContext securityContext = new StubSecurityContext();
StringMessage message = new StringMessage("test");
MessageHandler handler = new MessageHandler() {
public Message<?> handle(Message<?> message) {
SecurityContext associatedContext = SecurityContextHolder.getContext();
assertNotSame("Wrong security context", securityContext, associatedContext);
return null;
}
};
SecurityContextAssociatingHandlerInterceptor associatingInterceptor =
new SecurityContextAssociatingHandlerInterceptor(handler);
associatingInterceptor.handle(message);
assertNull("Security context still present after handler returned",
SecurityContextHolder.getContext().getAuthentication());
}
@Test
public void testExistingSecurityContextIsNotCleared(){
SecurityContextHolder.setStrategyName(StackBasedSecurityContextHolderStrategy.class.getName());
final StubSecurityContext securityContext = new StubSecurityContext();
SecurityContextHolder.setContext(securityContext);
StringMessage message = new StringMessage("test");
final MessageHandler handler = new MessageHandler() {
public Message<?> handle(Message<?> message) {
SecurityContext associatedContext = SecurityContextHolder.getContext();
assertEquals("Wrong security context", securityContext, associatedContext);
return null;
}
};
SecurityContextAssociatingHandlerInterceptor associatingInterceptor =
new SecurityContextAssociatingHandlerInterceptor(handler);
associatingInterceptor.handle(message);
assertEquals("Security context no logner set", securityContext, SecurityContextHolder.getContext());
}
@SuppressWarnings("serial")
private static class StubSecurityContext implements SecurityContext {
StubAuthentication stubAuthentication = new StubAuthentication();
public Authentication getAuthentication() {
return stubAuthentication;
}
public void setAuthentication(Authentication authentication) {
}
}
@SuppressWarnings("serial")
private static class StubAuthentication implements Authentication {
public GrantedAuthority[] getAuthorities() {
return null;
}
public Object getCredentials() {
return null;
}
public Object getDetails() {
return null;
}
public Object getPrincipal() {
return null;
}
public boolean isAuthenticated() {
return false;
}
public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
}
public String getName() {
return null;
}
}
}

View File

@@ -16,9 +16,7 @@
package org.springframework.integration.security.channel;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.*;
import org.junit.After;
import org.junit.Before;
@@ -36,13 +34,12 @@ import org.springframework.security.context.SecurityContextHolder;
* @author Jonas Partner
*/
public class SecurityContextPropagatingChannelInterceptorTests {
private QueueChannel channel;
private SecurityContextPropagatingChannelInterceptor securityPropogatingChannelInterceptor;
private StubSecurityContext securityContext;
private StubSecurityContext securityContext;
@Before
public void setUp() {
@@ -53,11 +50,10 @@ public class SecurityContextPropagatingChannelInterceptorTests {
}
@After
public void tearDown(){
public void tearDown() {
SecurityContextHolder.clearContext();
}
@Test
public void testPropogationWhenSecurityContextExists() {
this.associateContextWithThread();
@@ -65,11 +61,11 @@ public class SecurityContextPropagatingChannelInterceptorTests {
this.channel.send(message);
message = (StringMessage) channel.receive(0);
MessageHeader header = message.getHeader();
assertTrue("No security context attribute found in header.",
header.getAttributeNames().contains(SecurityContextUtils.SECURITY_CONTEXT_HEADER_ATTRIBUTE));
assertTrue("No security context attribute found in header.", header.getAttributeNames().contains(
SecurityContextUtils.SECURITY_CONTEXT_HEADER_ATTRIBUTE));
SecurityContext contextFromHeader = SecurityContextUtils.getSecurityContextFromHeader(message);
assertEquals("Incorrect security context in message header.", securityContext, contextFromHeader);
}
}
@Test
public void testHeaderNotSetWhenNoSecurityContextExists() {
@@ -77,19 +73,16 @@ public class SecurityContextPropagatingChannelInterceptorTests {
channel.send(message);
message = (StringMessage) channel.receive(0);
MessageHeader header = message.getHeader();
assertFalse("Security context header found when no security context existed.",
header.getAttributeNames().contains(SecurityContextUtils.SECURITY_CONTEXT_HEADER_ATTRIBUTE));
assertFalse("Security context header found when no security context existed.", header.getAttributeNames()
.contains(SecurityContextUtils.SECURITY_CONTEXT_HEADER_ATTRIBUTE));
}
private void associateContextWithThread(){
private void associateContextWithThread() {
SecurityContextHolder.setContext(securityContext);
}
}
@SuppressWarnings("serial")
private static class StubSecurityContext implements SecurityContext{
private static class StubSecurityContext implements SecurityContext {
private Authentication authentication = new Authentication() {
@@ -113,8 +106,7 @@ public class SecurityContextPropagatingChannelInterceptorTests {
return false;
}
public void setAuthenticated(boolean isAuthenticated)
throws IllegalArgumentException {
public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
}
public String getName() {

View File

@@ -12,25 +12,25 @@
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<beans:import resource="commonSecurityConfiguration.xml"/>
<beans:import resource="classpath:org/springframework/integration/security/config/commonSecurityConfiguration.xml"/>
<si-security:secured-channels send-access="ROLE_ADMIN" propagate="false">
<si-security:secured-channels send-access="ROLE_ADMIN">
<si-security:channel-name-pattern>adminRequiredForSend</si-security:channel-name-pattern>
</si-security:secured-channels>
<si-security:secured-channels send-access="ROLE_ADMIN, ROLE_USER" propagate="false">
<si-security:secured-channels send-access="ROLE_ADMIN, ROLE_USER">
<si-security:channel-name-pattern>adminOrUserRequiredForSend</si-security:channel-name-pattern>
</si-security:secured-channels>
<si-security:secured-channels receive-access="ROLE_ADMIN" propagate="false">
<si-security:secured-channels receive-access="ROLE_ADMIN">
<si-security:channel-name-pattern>adminRequiredForReceive</si-security:channel-name-pattern>
</si-security:secured-channels>
<si-security:secured-channels receive-access="ROLE_ADMIN, ROLE_USER" propagate="false">
<si-security:secured-channels receive-access="ROLE_ADMIN, ROLE_USER">
<si-security:channel-name-pattern>adminOrUserRequiredForReceive</si-security:channel-name-pattern>
</si-security:secured-channels>
<si-security:secured-channels receive-access="ROLE_ADMIN" send-access="ROLE_ADMIN" propagate="false">
<si-security:secured-channels receive-access="ROLE_ADMIN" send-access="ROLE_ADMIN">
<si-security:channel-name-pattern>adminForSendAndReceive</si-security:channel-name-pattern>
</si-security:secured-channels>

View File

@@ -14,11 +14,9 @@
* limitations under the License.
*/
package org.springframework.integration.security.config;
package org.springframework.integration.security.channel.config;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.*;
import java.util.ArrayList;
import java.util.List;

View File

@@ -11,23 +11,11 @@
http://www.springframework.org/schema/integration-security http://www.springframework.org/schema/integration/spring-integration-security-1.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<beans:import resource="commonSecurityConfiguration.xml"/>
<message-bus/>
<channel id="propagationDefault"/>
<si-security:secured-channels send-access="ROLE_ADMIN" >
<si-security:channel-name-pattern>adminRequiredForSend</si-security:channel-name-pattern>
</si-security:secured-channels>
<si-security:secured-channels propagate="false">
<si-security:channel-name-pattern>excludedFromPropagation</si-security:channel-name-pattern>
</si-security:secured-channels>
<channel id="excludedFromPropagation"/>
<si-security:security-propagating-channels propagate-by-default="false">
<si-security:propagation-patterns>
<si-security:excludePattern>adminSpecial</si-security:excludePattern>
<si-security:excludePattern>admin.*</si-security:excludePattern>
</si-security:propagation-patterns>
</si-security:security-propagating-channels>
</beans:beans>

View File

@@ -11,32 +11,6 @@
http://www.springframework.org/schema/integration-security http://www.springframework.org/schema/integration/spring-integration-security-1.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<beans:import resource="commonSecurityConfiguration.xml"/>
<message-bus/>
<si-security:security-propagating-channels propagate="true"/>
<channel id="propagationDefault"/>
<channel id="excludedFromPropagation" />
<si-security:secured-channels propagate="false">
<si-security:channel-name-pattern>excludedFromPropagation</si-security:channel-name-pattern>
</si-security:secured-channels>
<channel id="includedInPropagation" />
<si-security:secured-channels propagate="true">
<si-security:channel-name-pattern>includedInPropagation</si-security:channel-name-pattern>
</si-security:secured-channels>
<security:authentication-provider user-service-ref="userDetailsService"/>
<security:user-service id="userDetailsService">
<security:user name="jimi" password="jimispassword" authorities="ROLE_USER, ROLE_ADMIN"/>
<security:user name="bob" password="bobspassword" authorities="ROLE_USER"/>
</security:user-service>
<si-security:security-propagating-channels propagate-by-default="true"/>
</beans:beans>

View File

@@ -14,19 +14,16 @@
* limitations under the License.
*/
package org.springframework.integration.security.config;
package org.springframework.integration.security.channel.config;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.*;
import org.junit.After;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.integration.channel.MessageChannel;
import org.springframework.integration.channel.QueueChannel;
import org.springframework.integration.message.StringMessage;
import org.springframework.security.context.SecurityContext;
import org.springframework.security.context.SecurityContextHolder;
@@ -40,15 +37,6 @@ public class SecurityPropagatingChannelsParserTests {
private ClassPathXmlApplicationContext applicationContext;
@Autowired
@Qualifier("propagationDefault")
MessageChannel propagationDefault;
@Autowired
@Qualifier("excludedFromPropagation")
MessageChannel excludedFromPropagation;
@After
public void tearDown() {
if (applicationContext != null) {
@@ -57,34 +45,39 @@ public class SecurityPropagatingChannelsParserTests {
SecurityContextHolder.clearContext();
}
@Test
public void testPropagationByDefault() {
loadApplicationContext(this.getClass().getSimpleName() + "-propagateByDefaultContext.xml");
MessageChannel channel = new QueueChannel();
applicationContext.getAutowireCapableBeanFactory().applyBeanPostProcessorsAfterInitialization(channel,
"Does not matter");
assertTrue("security context did not propagate by setting message bus level default",
channelPropagatesSecurityContext(propagationDefault));
channelPropagatesSecurityContext(channel));
}
// @Test
// public void testNoPropagationOnExcludedChannel() {
// loadApplicationContext(this.getClass().getSimpleName() +
// "-propagateByDefaultContext.xml");
// assertFalse("security context propagated when channel was explicitly
// excluded",
// channelPropagatesSecurityContext(excludedFromPropagation));
// }
//
@Test
public void testNoPropagationOnExcludedChannel() {
loadApplicationContext(this.getClass().getSimpleName() + "-propagateByDefaultContext.xml");
assertFalse("security context propagated when channel was explicitly excluded",
channelPropagatesSecurityContext(excludedFromPropagation));
}
@Test
public void testNoPropagationWithNoDefaultPropagation() {
public void testNoPropagationWithExcludedChannel() {
loadApplicationContext(this.getClass().getSimpleName() + "-noPropagationByDefaultContext.xml");
assertFalse("security context propagated when channel default was false and no secured tag present",
channelPropagatesSecurityContext(propagationDefault));
MessageChannel channel = new QueueChannel();
applicationContext.getAutowireCapableBeanFactory().applyBeanPostProcessorsAfterInitialization(channel,
"adminSpecial");
assertFalse("security context propagated when channel excluded", channelPropagatesSecurityContext(channel));
}
private boolean channelPropagatesSecurityContext(MessageChannel channel) {
login("bob", "bobspassword");
channel.send(new StringMessage("testMessage"));
SecurityContext context = (SecurityContext)
channel.receive(-1).getHeader().getAttribute("SPRING_SECURITY_CONTEXT");
SecurityContext context = (SecurityContext) channel.receive(-1).getHeader().getAttribute(
"SPRING_SECURITY_CONTEXT");
return context != null;
}

View File

@@ -0,0 +1,68 @@
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.integration.security.config;
import static org.junit.Assert.*;
import java.io.StringReader;
import javax.xml.parsers.DocumentBuilderFactory;
import org.junit.Before;
import org.junit.Test;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
public class IncludeExcludePatternParserTests {
IncludeExcludePatternParser patternParser;
@Before
public void setUp() {
patternParser = new IncludeExcludePatternParser();
}
@Test
public void testSimpleIncludeWithIncludeByDefaultFalse() throws Exception {
NodeList nodeList = getNodeList("<doc><includePattern>includeMe</includePattern><excludePattern>.*</excludePattern></doc>");
OrderedIncludeExcludeList matcher = patternParser.createFromNodeList(false, nodeList);
assertTrue("Did not match expected entry includeMe", matcher.isIncluded("includeMe"));
assertFalse("Matched unexpected entry notMe", matcher.isIncluded("notMe"));
}
@Test
public void testIncludeByDefaultTrue() throws Exception {
NodeList nodeList = getNodeList("<doc></doc>");
OrderedIncludeExcludeList matcher = patternParser.createFromNodeList(true, nodeList);
assertTrue("Did not match expected entry includeMe", matcher.isIncluded("anything"));
}
@Test
public void testIncludeByDefaultTrueButExcluded() throws Exception {
NodeList nodeList = getNodeList("<doc><excludePattern>ex.*</excludePattern><includePattern>exShouldNotMatter</includePattern></doc>");
OrderedIncludeExcludeList matcher = patternParser.createFromNodeList(true, nodeList);
assertFalse("Matched unexpected entry exNotMe", matcher.isIncluded("exNotMe"));
assertFalse("Matched unexpected entry exShouldNotMatter", matcher.isIncluded("exShouldNotMatter"));
}
public NodeList getNodeList(String xmlString) throws Exception {
StringReader reader = new StringReader(xmlString);
Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new InputSource(reader));
return doc.getDocumentElement().getChildNodes();
}
}

View File

@@ -1,19 +1,31 @@
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.integration.security.config;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.*;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
/**
*
* @author Jonas Partner
*
*
*/
public class JdkRegExpOrderedIncludeExcludeListTests {
@@ -39,15 +51,15 @@ public class JdkRegExpOrderedIncludeExcludeListTests {
assertFalse("Unexpected match when match by default false and no patterns", matcher.isIncluded("anyoldthing"));
}
@Test
public void testExcludeThenIncludeWithIncludeByDefaultFalse() {
List<IncludeExcludePattern> patterns = createIncludeExcludeList(new boolean[] {false, true}, new String[] {"admin.*",".*"});
List<IncludeExcludePattern> patterns = createIncludeExcludeList(new boolean[] { false, true }, new String[] {
"admin.*", ".*" });
JdkRegExpOrderedIncludeExcludeList matcher = new JdkRegExpOrderedIncludeExcludeList(false, patterns);
assertFalse("Unexpected match when match by default false and should have been excluded", matcher.isIncluded("adminChannel"));
assertFalse("Unexpected match when match by default false and should have been excluded", matcher
.isIncluded("adminChannel"));
}
List<IncludeExcludePattern> createIncludeExcludeList(boolean[] includeExclude, String[] patterns) {
assertEquals("flag and patterns arrays must be same length", includeExclude.length, patterns.length);

View File

@@ -24,20 +24,21 @@ import org.springframework.security.providers.UsernamePasswordAuthenticationToke
/**
*
* @author Jonas Partner
*
*
*/
public class SecurityTestUtil {
public static SecurityContext createContext(String username, String password, String... roles){
public static SecurityContext createContext(String username, String password, String... roles) {
SecurityContextImpl ctxImpl = new SecurityContextImpl();
UsernamePasswordAuthenticationToken authToken;
if(roles != null && roles.length > 0){
if (roles != null && roles.length > 0) {
GrantedAuthority[] authorities = new GrantedAuthority[roles.length];
for (int i =0; i < roles.length; i++) {
for (int i = 0; i < roles.length; i++) {
authorities[i] = new GrantedAuthorityImpl(roles[i]);
}
authToken = new UsernamePasswordAuthenticationToken(username,password,authorities);
} else {
authToken = new UsernamePasswordAuthenticationToken(username, password, authorities);
}
else {
authToken = new UsernamePasswordAuthenticationToken(username, password);
}
ctxImpl.setAuthentication(authToken);

View File

@@ -0,0 +1,142 @@
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.integration.security.endpoint;
import static org.easymock.EasyMock.*;
import static org.junit.Assert.assertNull;
import org.aopalliance.intercept.MethodInvocation;
import org.junit.Test;
import org.springframework.integration.message.Message;
import org.springframework.integration.message.StringMessage;
import org.springframework.integration.security.SecurityContextUtils;
import org.springframework.integration.security.config.SecurityTestUtil;
import org.springframework.security.AccessDecisionManager;
import org.springframework.security.AccessDeniedException;
import org.springframework.security.ConfigAttributeDefinition;
import org.springframework.security.context.SecurityContext;
import org.springframework.security.context.SecurityContextHolder;
/**
*
* @author Jonas Partner
*
*/
public class SecurityEndpointInterceptorTests {
@Test(expected = AccessDeniedException.class)
public void testUnauthenticatedAccessToSecuredEndpointWithNullMessage() throws Throwable {
try {
Object target = new Object();
MethodInvocation invocation = createTestMethodInvocationWithNullMessage(target);
ConfigAttributeDefinition attDefintion = new ConfigAttributeDefinition("ROLE_ADMIN");
AccessDecisionManager adm = createMock(AccessDecisionManager.class);
adm.decide(null, target, attDefintion);
expectLastCall().andThrow(new AccessDeniedException("nope"));
replay(invocation);
replay(adm);
SecurityEndpointInterceptor interceptor = new SecurityEndpointInterceptor(attDefintion, adm);
interceptor.aroundInvoke(invocation);
verify(invocation, adm);
}
finally {
assertNull("Authentication was not null after invocation threw AccessDeniedException",
SecurityContextHolder.getContext().getAuthentication());
}
}
@Test(expected = AccessDeniedException.class)
public void testUnauthenticatedAccessToSecuredEndpoint() throws Throwable {
try {
Object target = new Object();
MethodInvocation invocation = createTestMethodInvocationNoSecurityHeaderInMessage(target);
ConfigAttributeDefinition attDefintion = new ConfigAttributeDefinition("ROLE_ADMIN");
AccessDecisionManager adm = createMock(AccessDecisionManager.class);
adm.decide(null, target, attDefintion);
expectLastCall().andThrow(new AccessDeniedException("nope"));
replay(invocation);
replay(adm);
SecurityEndpointInterceptor interceptor = new SecurityEndpointInterceptor(attDefintion, adm);
interceptor.aroundInvoke(invocation);
verify(invocation, adm);
}
finally {
assertNull("Authentication was not null after invocation threw AccessDeniedException",
SecurityContextHolder.getContext().getAuthentication());
}
}
@Test
public void testAuthenticatedAccessToSecuredEndpoint() throws Throwable {
try {
Object target = new Object();
SecurityContext context = SecurityTestUtil.createContext("bob", "bobspassword",
new String[] { "ROLE_ADMIN" });
MethodInvocation invocation = createTestMethodInvocation(target, context);
expect(invocation.proceed()).andReturn(null);
replay(invocation);
ConfigAttributeDefinition attDefintion = new ConfigAttributeDefinition("ROLE_ADMIN");
AccessDecisionManager adm = createMock(AccessDecisionManager.class);
adm.decide(context.getAuthentication(), target, attDefintion);
expectLastCall();
replay(adm);
SecurityEndpointInterceptor interceptor = new SecurityEndpointInterceptor(attDefintion, adm);
interceptor.aroundInvoke(invocation);
verify(invocation, adm);
}
finally {
assertNull("Authentication was not null after successful invocation", SecurityContextHolder.getContext()
.getAuthentication());
}
}
public MethodInvocation createTestMethodInvocation(Object target, SecurityContext securityContext) {
Message message = new StringMessage("test");
SecurityContextUtils.setSecurityContextHeader(securityContext, message);
MethodInvocation mockInvocation = createMock(MethodInvocation.class);
expect(mockInvocation.getArguments()).andReturn(new Object[] { message });
expect(mockInvocation.getThis()).andReturn(target);
return mockInvocation;
}
public MethodInvocation createTestMethodInvocationNoSecurityHeaderInMessage(Object target) {
Message message = new StringMessage("test");
MethodInvocation mockInvocation = createMock(MethodInvocation.class);
expect(mockInvocation.getArguments()).andReturn(new Object[] { message });
expect(mockInvocation.getThis()).andReturn(target);
return mockInvocation;
}
public MethodInvocation createTestMethodInvocationWithNullMessage(Object target) {
MethodInvocation mockInvocation = createMock(MethodInvocation.class);
expect(mockInvocation.getArguments()).andReturn(new Object[] { null });
expect(mockInvocation.getThis()).andReturn(target);
return mockInvocation;
}
}

View File

@@ -1,131 +0,0 @@
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.integration.security.target;
import org.junit.Test;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.integration.message.BlockingTarget;
import org.springframework.integration.message.Message;
import org.springframework.integration.message.StringMessage;
import org.springframework.integration.message.Target;
import org.springframework.integration.security.target.TargetSecuringAdvisor;
import org.springframework.security.AccessDecisionManager;
import org.springframework.security.AccessDeniedException;
import org.springframework.security.Authentication;
import org.springframework.security.ConfigAttribute;
import org.springframework.security.ConfigAttributeDefinition;
import org.springframework.security.InsufficientAuthenticationException;
/**
*
* @author Jonas Partner
*
*/
public class TargetSecuringAdvisorTests {
public Object proxy(Object target, TargetSecuringAdvisor advisor) {
ProxyFactory proxyFactory = new ProxyFactory(target);
proxyFactory.addAdvisor(advisor);
return proxyFactory.getProxy();
}
@Test(expected = AccessDeniedException.class)
public void testTargetSendAdvised() {
TargetSecuringAdvisor advisor = new TargetSecuringAdvisor(new AlwaysDenyAccessDecisionManager(), "ROLE_ADMIN");
Target target = (Target) proxy(new TestTarget(), advisor);
target.send(new StringMessage("test"));
}
@Test(expected = AccessDeniedException.class)
public void testBlockingTargetSendAdvised() {
TargetSecuringAdvisor advisor = new TargetSecuringAdvisor(new AlwaysDenyAccessDecisionManager(), "ROLE_ADMIN");
Target target = (Target) proxy(new BlockingTestTarget(), advisor);
target.send(new StringMessage("test"));
}
@Test(expected = AccessDeniedException.class)
public void testBlockingTargetSendWithTimeoutAdvised() {
TargetSecuringAdvisor advisor = new TargetSecuringAdvisor(new AlwaysDenyAccessDecisionManager(), "ROLE_ADMIN");
BlockingTarget target = (BlockingTarget) proxy(new BlockingTestTarget(), advisor);
target.send(new StringMessage("test"), 10l);
}
@Test
public void testTargetSendNotFromTargetInterface() {
TargetSecuringAdvisor advisor = new TargetSecuringAdvisor(new AlwaysDenyAccessDecisionManager(), "ROLE_ADMIN");
OtherSend target = (OtherSend) proxy(new TestTarget(), advisor);
target.send(10l);
}
static interface OtherSend {
public void send(long l);
}
static class AlwaysDenyAccessDecisionManager implements AccessDecisionManager {
public void decide(Authentication authentication, Object object, ConfigAttributeDefinition config)
throws AccessDeniedException, InsufficientAuthenticationException {
throw new AccessDeniedException("dave");
}
public boolean supports(ConfigAttribute attribute) {
return true;
}
@SuppressWarnings("unchecked")
public boolean supports(Class clazz) {
return true;
}
}
static class TestTarget implements Target, OtherSend {
boolean invoked;
public boolean send(Message<?> message) {
invoked = true;
return false;
}
public void send(long a) {
}
}
static class BlockingTestTarget implements BlockingTarget {
boolean invoked;
public boolean send(Message<?> message) {
invoked = true;
return false;
}
public void send() {
}
public boolean send(Message<?> message, long timeout) {
return false;
}
}
}

View File

@@ -1,110 +0,0 @@
/*
* Copyright 2002-2008 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.integration.security.target;
import java.util.ArrayList;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.integration.message.Message;
import org.springframework.integration.message.StringMessage;
import org.springframework.integration.message.Target;
import org.springframework.integration.security.SecurityContextUtils;
import org.springframework.integration.security.config.SecurityTestUtil;
import org.springframework.integration.security.target.TargetSecuringInterceptor;
import org.springframework.security.AccessDecisionManager;
import org.springframework.security.AccessDeniedException;
import org.springframework.security.ConfigAttributeDefinition;
import org.springframework.security.context.SecurityContext;
import org.springframework.security.vote.AccessDecisionVoter;
import org.springframework.security.vote.AuthenticatedVoter;
import org.springframework.security.vote.RoleVoter;
import org.springframework.security.vote.UnanimousBased;
import org.springframework.util.StringUtils;
/**
*
* @author Jonas Partner
*
*/
public class TargetSecuringInterceptorTests {
UnanimousBased accessDecisionManager;
@Before
public void setup(){
accessDecisionManager = new UnanimousBased();
List<AccessDecisionVoter> voterList = new ArrayList<AccessDecisionVoter>();
voterList.add(new AuthenticatedVoter());
voterList.add(new RoleVoter());
accessDecisionManager.setDecisionVoters(voterList);
}
public Object createProxy(Object target,String securityAttributes, AccessDecisionManager accessDecisionManager){
TargetSecuringInterceptor interceptor = new TargetSecuringInterceptor(new ConfigAttributeDefinition(StringUtils.tokenizeToStringArray(securityAttributes,",")), accessDecisionManager);
ProxyFactory factory = new ProxyFactory(target);
factory.addAdvice(interceptor);
return factory.getProxy();
}
@Test(expected=AccessDeniedException.class)
public void testAccessDenied(){
Target proxiedTarget = (Target) createProxy(new TestTarget(), "IS_AUTHENTICATED_FULLY, ROLE_ADMIN", accessDecisionManager);
SecurityContext sctx = SecurityTestUtil.createContext("bob", "password", "IS_AUTHENTICATED_ANONYMOUSLY", "ROLE_USER");
StringMessage message = new StringMessage("test");
SecurityContextUtils.setSecurityContextHeader(sctx, message);
proxiedTarget.send(message);
}
@Test
public void testAccessGranted(){
Target proxiedTarget = (Target) createProxy(new TestTarget(), "IS_AUTHENTICATED_FULLY, ROLE_ADMIN", accessDecisionManager);
SecurityContext sctx = SecurityTestUtil.createContext("bob", "password", "IS_AUTHENTICATED_ANONYMOUSLY", "ROLE_USER", "ROLE_ADMIN");
StringMessage message = new StringMessage("test");
SecurityContextUtils.setSecurityContextHeader(sctx, message);
proxiedTarget.send(message);
}
@Test(expected=RuntimeException.class)
public void testNotAuthenticated(){
Target proxiedTarget = (Target) createProxy(new TestTarget(), "IS_AUTHENTICATED_FULLY, ROLE_ADMIN", accessDecisionManager);
StringMessage message = new StringMessage("test");
proxiedTarget.send(message);
}
static class TestTarget implements Target{
boolean invoked;
public boolean send(Message<?> message) {
invoked = true;
return false;
}
public void send(long l) {
// TODO Auto-generated method stub
}
}
}