From 1b4a098760eff0270828435c57ba9053f9223597 Mon Sep 17 00:00:00 2001 From: Ben Alex Date: Tue, 14 Nov 2006 22:07:36 +0000 Subject: [PATCH] SEC-354: Add label-based voter. --- .../InterfaceBasedLabelParameterStrategy.java | 74 +++++ .../vote/LabelBasedAclVoter.java | 288 ++++++++++++++++++ .../vote/LabelParameterStrategy.java | 52 ++++ .../org/acegisecurity/vote/LabeledData.java | 35 +++ .../vote/LabelBasedAclVoterTests.java | 184 +++++++++++ .../acegisecurity/vote/SampleBlockOfData.java | 67 ++++ .../org/acegisecurity/vote/SampleService.java | 31 ++ .../acegisecurity/vote/SampleServiceImpl.java | 78 +++++ .../labelBasedSecurityApplicationContext.xml | 91 ++++++ 9 files changed, 900 insertions(+) create mode 100644 core/src/main/java/org/acegisecurity/vote/InterfaceBasedLabelParameterStrategy.java create mode 100644 core/src/main/java/org/acegisecurity/vote/LabelBasedAclVoter.java create mode 100644 core/src/main/java/org/acegisecurity/vote/LabelParameterStrategy.java create mode 100644 core/src/main/java/org/acegisecurity/vote/LabeledData.java create mode 100644 core/src/test/java/org/acegisecurity/vote/LabelBasedAclVoterTests.java create mode 100644 core/src/test/java/org/acegisecurity/vote/SampleBlockOfData.java create mode 100644 core/src/test/java/org/acegisecurity/vote/SampleService.java create mode 100644 core/src/test/java/org/acegisecurity/vote/SampleServiceImpl.java create mode 100644 core/src/test/resources/org/acegisecurity/vote/labelBasedSecurityApplicationContext.xml diff --git a/core/src/main/java/org/acegisecurity/vote/InterfaceBasedLabelParameterStrategy.java b/core/src/main/java/org/acegisecurity/vote/InterfaceBasedLabelParameterStrategy.java new file mode 100644 index 0000000000..2521e84051 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/vote/InterfaceBasedLabelParameterStrategy.java @@ -0,0 +1,74 @@ +/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited + * + * 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.acegisecurity.vote; + +import java.lang.reflect.Method; + + +/** + * This is a very useful implementation of the LabelParameterStrategy. Data objects which are meant to be labeled + * should implement the LabeledData interface. This strategy will then castdown to that interface for either testing + * or retrieval of the label. + * + * @author Greg Turnquist + * @version $Id$ + */ +public class InterfaceBasedLabelParameterStrategy implements LabelParameterStrategy { + //~ Instance fields ================================================================================================ + + private String noLabel = ""; + + //~ Methods ======================================================================================================== + + /** + * Test if the argument is labeled, and if so, downcast to LabeledData and retrieve the domain object's + * labeled value. Otherwise, return an empty string. NOTE: The default for no label is an empty string. If somehow + * the user wants to make that a label itself, he or she must inject an alternate value to the noLabel property. + * + * @param method DOCUMENT ME! + * @param arg DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public String getLabel(Method method, Object arg) { + if (isLabeled(method, arg)) { + return ((LabeledData) arg).getLabel(); + } else { + return noLabel; + } + } + + public String getNoLabel() { + return noLabel; + } + + /** + * Test if the argument implemented the LabeledData interface. NOTE: The invoking method has no bearing for + * this strategy, only the argument itself. + * + * @param method DOCUMENT ME! + * @param arg DOCUMENT ME! + * + * @return DOCUMENT ME! + */ + public boolean isLabeled(Method method, Object arg) { + return (arg instanceof LabeledData); + } + + public void setNoLabel(String noLabel) { + this.noLabel = noLabel; + } +} diff --git a/core/src/main/java/org/acegisecurity/vote/LabelBasedAclVoter.java b/core/src/main/java/org/acegisecurity/vote/LabelBasedAclVoter.java new file mode 100644 index 0000000000..5e62d4b3c7 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/vote/LabelBasedAclVoter.java @@ -0,0 +1,288 @@ +/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited + * + * 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.acegisecurity.vote; + +import org.acegisecurity.Authentication; +import org.acegisecurity.ConfigAttribute; +import org.acegisecurity.ConfigAttributeDefinition; + +import org.acegisecurity.vote.AbstractAclVoter; + +import org.aopalliance.intercept.MethodInvocation; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.springframework.util.Assert; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Vector; + + +/** + *

This Acl voter will evaluate methods based on labels applied to incoming arguments. It will only check + * methods that have been properly tagged in the MethodSecurityInterceptor with the value stored in + * attributeIndicatingLabeledOperation. If a method has been tagged, then it examines each argument, and if the + * argument implements {@link LabeledData}, then it will asses if the user's list of granted authorities matches.

+ *

By default, if none of the arguments are labeled, then the access will be granted. This can be overridden by + * setting allowAccessIfNoAttributesAreLabeled to false in the Spring context file.

+ *

In many situations, different values are linked together to define a common label, it is necessary to + * define a map in the application context that links user-assigned label access to domain object labels. This is done + * by setting up the labelMap in the application context.

+ * + * @author Greg Turnquist + * @version $Id$ + * + * @see org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor + */ +public class LabelBasedAclVoter extends AbstractAclVoter { + //~ Instance fields ================================================================================================ + + private HashMap labelMap = null; + Log logger = LogFactory.getLog(LabelBasedAclVoter.class); + private String attributeIndicatingLabeledOperation = null; + private boolean allowAccessIfNoAttributesAreLabeled = true; + + //~ Methods ======================================================================================================== + + /** + * Set whether or not to allow the user to run methods in which none of the incoming arguments are labeled.

Default + * value: true, users can run such methods.

+ * + * @param allowAccessIfNoAttributesAreLabeled boolean + */ + public void setAllowAccessIfNoAttributesAreLabeled(boolean allowAccessIfNoAttributesAreLabeled) { + this.allowAccessIfNoAttributesAreLabeled = allowAccessIfNoAttributesAreLabeled; + } + + /** + * Each method intended for evaluation by this voter must include this tag name in the definition of the + * MethodSecurityInterceptor, indicating if this voter should evaluate the arguments and compare them against the + * label map. + * + * @param attributeIndicatingLabeledOperation string + */ + public void setAttributeIndicatingLabeledOperation(String attributeIndicatingLabeledOperation) { + this.attributeIndicatingLabeledOperation = attributeIndicatingLabeledOperation; + } + + /** + * Set the map that correlate a user's assigned label against domain object values that are considered data + * labels.

+ * + * @param labelMap - HashMap Example application context configuration of a labelMap: + * + *
+	 *  <bean id="accessDecisionManager" class="org.acegisecurity.vote.UnanimousBased">
+ * <property name="allowIfAllAbstainDecisions"><value>false</value></property>
+ * <property name="decisionVoters">
+ * <list>
+ * <bean class="org.acegisecurity.vote.RoleVoter"/>
+ * <bean class="net.homelinux.scifi.LabelBasedAclVoter">
+ * <property name="attributeIndicatingLabeledOperation"><value>LABELED_OPERATION</value></property>
+ * <property name="labelMap">
+ * <map>
+ * <entry key="DATA_LABEL_BLUE">
+ * <list>
+ * <value>blue</value>
+ * <value>indigo</value>
+ * <value>purple</value>
+ * </list>
+ * </entry>
+ * <entry key="LABEL_ORANGE">
+ * <list>
+ * <value>orange</value>
+ * <value>sunshine</value>
+ * <value>amber</value>
+ * </list>
+ * </entry>
+ * <entry key="LABEL_ADMIN">
+ * <list>
+ * <value>blue</value>
+ * <value>indigo</value>
+ * <value>purple</value>
+ * <value>orange</value>
+ * <value>sunshine</value>
+ * <value>amber</value>
+ * </list>
+ * </entry>
+ * </map>
+ * </property>
+ * </bean>
+ * </list>
+ * </property>
+ * </bean>
+ *
+ */ + public void setLabelMap(HashMap labelMap) { + this.labelMap = labelMap; + } + + /** + * This acl voter will only evaluate labeled methods if they are marked in the security interceptor's + * configuration with the attribute stored in attributeIndicatingLabeledOperation. + * + * @param attribute DOCUMENT ME! + * + * @return DOCUMENT ME! + * + * @see org.acegisecurity.vote.AbstractAclVoter + * @see org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor + */ + public boolean supports(ConfigAttribute attribute) { + if (attribute.getAttribute().equals(attributeIndicatingLabeledOperation)) { + logger.debug(attribute + " is supported."); + + return true; + } + + if (logger.isDebugEnabled()) { + logger.debug(attribute + " is unsupported."); + } + + return false; + } + + /** + * Vote on whether or not the user has all the labels necessary to match the method argument's labeled + * data. + * + * @param authentication DOCUMENT ME! + * @param object DOCUMENT ME! + * @param config DOCUMENT ME! + * + * @return ACCESS_ABSTAIN, ACCESS_GRANTED, or ACCESS_DENIED. + */ + public int vote(Authentication authentication, Object object, ConfigAttributeDefinition config) { + int result = ACCESS_ABSTAIN; + + if (logger.isDebugEnabled()) { + logger.debug("=========================================================="); + } + + if (this.supports((ConfigAttribute) config.getConfigAttributes().next())) { + result = ACCESS_DENIED; + + /* Parse out the user's labels by examining the security context, and checking + * for matches against the label map. + */ + List userLabels = new Vector(); + + for (int i = 0; i < authentication.getAuthorities().length; i++) { + if (labelMap.containsKey(authentication.getAuthorities()[i].getAuthority())) { + String userLabel = authentication.getAuthorities()[i].getAuthority(); + userLabels.add(userLabel); + logger.debug("Adding " + userLabel + " to <<<" + authentication.getName() + + "'s>>> authorized label list"); + } + } + + MethodInvocation invocation = (MethodInvocation) object; + + int matches = 0; + int misses = 0; + int labeledArguments = 0; + + for (int j = 0; j < invocation.getArguments().length; j++) { + if (invocation.getArguments()[j] instanceof LabeledData) { + labeledArguments++; + + boolean matched = false; + + String argumentDataLabel = ((LabeledData) invocation.getArguments()[j]).getLabel(); + logger.debug("Argument[" + j + "/" + invocation.getArguments()[j].getClass().getName() + + "] has a data label of " + argumentDataLabel); + + List validDataLabels = new Vector(); + + for (int i = 0; i < userLabels.size(); i++) { + validDataLabels.addAll((List) labelMap.get(userLabels.get(i))); + } + + logger.debug("The valid labels for user label " + userLabels + " are " + validDataLabels); + + Iterator dataLabelIter = validDataLabels.iterator(); + + while (dataLabelIter.hasNext()) { + String validDataLabel = (String) dataLabelIter.next(); + + if (argumentDataLabel.equals(validDataLabel)) { + logger.debug(userLabels + " maps to " + validDataLabel + " which matches the argument"); + matched = true; + } + } + + if (matched) { + logger.debug("We have a match!"); + matches++; + } else { + logger.debug("We have a miss!"); + misses++; + } + } /* if arguments is an ILabel */} /* loop through all arguments */ + Assert.isTrue((matches + misses) == labeledArguments, + "The matches (" + matches + ") and misses (" + misses + " ) don't add up (" + labeledArguments + ")"); + + logger.debug("We have " + matches + " matches and " + misses + " misses and " + labeledArguments + + " labeled arguments."); + + /* The result has already been set to ACCESS_DENIED. Only if there is a proper match of + * labels will this be overturned. However, if none of the attributes are actually labeled, + * the result is dependent on allowAccessIfNoAttributesAreLabeled. + */ + if ((matches > 0) && (misses == 0)) { + result = ACCESS_GRANTED; + } else if (labeledArguments == 0) { + if (allowAccessIfNoAttributesAreLabeled) { + result = ACCESS_GRANTED; + } else { + result = ACCESS_DENIED; + } + } + } + + if (logger.isDebugEnabled()) { + switch (result) { + case ACCESS_GRANTED: + + if (logger.isDebugEnabled()) { + logger.debug("===== Access is granted ====="); + } + + break; + + case ACCESS_DENIED: + + if (logger.isDebugEnabled()) { + logger.debug("===== Access is denied ====="); + } + + break; + + case ACCESS_ABSTAIN: + + if (logger.isDebugEnabled()) { + logger.debug("===== Abstaining ====="); + } + + break; + } + } + + return result; + } +} diff --git a/core/src/main/java/org/acegisecurity/vote/LabelParameterStrategy.java b/core/src/main/java/org/acegisecurity/vote/LabelParameterStrategy.java new file mode 100644 index 0000000000..fe1e8e2369 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/vote/LabelParameterStrategy.java @@ -0,0 +1,52 @@ +/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited + * + * 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.acegisecurity.vote; + +import java.lang.reflect.Method; + + +/** + * This is a strategy interface for determining which parts of a method invocation + * are labeled. Not all arguments are necessarily labeled. This offers a plugabble + * mechanism to define various ways to label data. + * + * @author Greg Turnquist + * @version $Id$ + */ +public interface LabelParameterStrategy { + //~ Methods ======================================================================================================== + + /** + * Get the actual label associated with the argument. NOTE: This currently only supports one label per + * argument. + * + * @param method + * @param arg + * + * @return string value of the label + */ + public String getLabel(Method method, Object arg); + + /** + * Evaluate if one particular argument is labeled. The context of the method is also provided should that + * have bearing on the label. + * + * @param method + * @param arg + * + * @return boolean + */ + public boolean isLabeled(Method method, Object arg); +} diff --git a/core/src/main/java/org/acegisecurity/vote/LabeledData.java b/core/src/main/java/org/acegisecurity/vote/LabeledData.java new file mode 100644 index 0000000000..8499b8ebc5 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/vote/LabeledData.java @@ -0,0 +1,35 @@ +/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited + * + * 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.acegisecurity.vote; + +/** + * This interface indicates data objects that carry a label. The purpose is to support + * the {@link LabelBasedAclVoter}. When it votes, it evaluates all method arguments + * tagged with this interface, and votes if they match the user's granted authorities list. + * + * @author Greg Turnquist + */ +public interface LabeledData { + //~ Methods ======================================================================================================== + + /** + * Retrieve the domain object's data label. NOTE: This implementation only supports one data label per + * object. + * + * @return The label value of data object as a string. + */ + public String getLabel(); +} diff --git a/core/src/test/java/org/acegisecurity/vote/LabelBasedAclVoterTests.java b/core/src/test/java/org/acegisecurity/vote/LabelBasedAclVoterTests.java new file mode 100644 index 0000000000..8be9cb7d2a --- /dev/null +++ b/core/src/test/java/org/acegisecurity/vote/LabelBasedAclVoterTests.java @@ -0,0 +1,184 @@ +/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited + * + * 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.acegisecurity.vote; + +import org.acegisecurity.AccessDeniedException; +import org.acegisecurity.AuthenticationManager; + +import org.acegisecurity.context.SecurityContextHolder; + +import org.acegisecurity.providers.UsernamePasswordAuthenticationToken; + +import org.springframework.test.AbstractDependencyInjectionSpringContextTests; + +import java.util.List; + + +/** + * +DOCUMENT ME! + * + * @author Greg Turnquist + * @version $Id$ + */ +public class LabelBasedAclVoterTests extends AbstractDependencyInjectionSpringContextTests { + //~ Instance fields ================================================================================================ + + private SampleService sampleService = null; + + //~ Methods ======================================================================================================== + + protected String[] getConfigLocations() { + return new String[] {"org/acegisecurity/vote/labelBasedSecurityApplicationContext.xml"}; + } + + public SampleService getSampleService() { + return sampleService; + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(LabelBasedAclVoterTests.class); + } + + public void setSampleService(SampleService sampleService) { + this.sampleService = sampleService; + } + + private void setupContext(String username, String password) { + UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, password); + AuthenticationManager authenticationManager = (AuthenticationManager) applicationContext.getBean( + "authenticationManager"); + SecurityContextHolder.getContext().setAuthentication(authenticationManager.authenticate(token)); + } + + public void testDoingSomethingForBlueUser() { + setupContext("blueuser", "password"); + + List dataList = sampleService.getTheSampleData(); + assertNotNull(dataList); + + SampleBlockOfData block1 = (SampleBlockOfData) dataList.get(0); + SampleBlockOfData block2 = (SampleBlockOfData) dataList.get(1); + SampleBlockOfData block3 = (SampleBlockOfData) dataList.get(2); + + sampleService.doSomethingOnThis(block1, block1); + + try { + sampleService.doSomethingOnThis(block2, block2); + fail("Expected an AccessDeniedException"); + } catch (AccessDeniedException e) {} + catch (RuntimeException e) { + fail("Expected an AccessDeniedException"); + } + + try { + sampleService.doSomethingOnThis(block1, block2); + fail("Expected an AccessDeniedException"); + } catch (AccessDeniedException e) {} + catch (RuntimeException e) { + fail("Expected an AccessDeniedException"); + } + + try { + sampleService.doSomethingOnThis(block2, block1); + fail("Expected an AccessDeniedException"); + } catch (AccessDeniedException e) {} + catch (RuntimeException e) { + fail("Expected an AccessDeniedException"); + } + + sampleService.doSomethingOnThis(block3, block3); + } + + public void testDoingSomethingForMultiUser() { + setupContext("multiuser", "password4"); + + List dataList = sampleService.getTheSampleData(); + assertNotNull(dataList); + + SampleBlockOfData block1 = (SampleBlockOfData) dataList.get(0); + SampleBlockOfData block2 = (SampleBlockOfData) dataList.get(1); + SampleBlockOfData block3 = (SampleBlockOfData) dataList.get(2); + + sampleService.doSomethingOnThis(block1, block1); + sampleService.doSomethingOnThis(block2, block2); + sampleService.doSomethingOnThis(block1, block2); + sampleService.doSomethingOnThis(block2, block1); + sampleService.doSomethingOnThis(block3, block3); + } + + public void testDoingSomethingForOrangeUser() { + setupContext("orangeuser", "password3"); + + List dataList = sampleService.getTheSampleData(); + assertNotNull(dataList); + + SampleBlockOfData block1 = (SampleBlockOfData) dataList.get(0); + SampleBlockOfData block2 = (SampleBlockOfData) dataList.get(1); + SampleBlockOfData block3 = (SampleBlockOfData) dataList.get(2); + + sampleService.doSomethingOnThis(block2, block2); + + try { + sampleService.doSomethingOnThis(block1, block1); + fail("Expected an AccessDeniedException"); + } catch (AccessDeniedException e) {} + catch (RuntimeException e) { + fail("Expected an AccessDeniedException"); + } + + try { + sampleService.doSomethingOnThis(block1, block2); + fail("Expected an AccessDeniedException"); + } catch (AccessDeniedException e) {} + catch (RuntimeException e) { + fail("Expected an AccessDeniedException"); + } + + try { + sampleService.doSomethingOnThis(block2, block1); + fail("Expected an AccessDeniedException"); + } catch (AccessDeniedException e) {} + catch (RuntimeException e) { + fail("Expected an AccessDeniedException"); + } + + sampleService.doSomethingOnThis(block3, block3); + } + + public void testDoingSomethingForSuperUser() { + setupContext("superuser", "password2"); + + List dataList = sampleService.getTheSampleData(); + assertNotNull(dataList); + + SampleBlockOfData block1 = (SampleBlockOfData) dataList.get(0); + SampleBlockOfData block2 = (SampleBlockOfData) dataList.get(1); + SampleBlockOfData block3 = (SampleBlockOfData) dataList.get(2); + + sampleService.doSomethingOnThis(block1, block1); + sampleService.doSomethingOnThis(block2, block2); + sampleService.doSomethingOnThis(block1, block2); + sampleService.doSomethingOnThis(block2, block1); + sampleService.doSomethingOnThis(block3, block3); + } + + public void testSampleBlockOfDataPOJO() { + SampleBlockOfData block = new SampleBlockOfData(); + block.setId("ID-ABC"); + assertEquals(block.getId(), "ID-ABC"); + } +} diff --git a/core/src/test/java/org/acegisecurity/vote/SampleBlockOfData.java b/core/src/test/java/org/acegisecurity/vote/SampleBlockOfData.java new file mode 100644 index 0000000000..1f10a22fcf --- /dev/null +++ b/core/src/test/java/org/acegisecurity/vote/SampleBlockOfData.java @@ -0,0 +1,67 @@ +/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited + * + * 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.acegisecurity.vote; + +import org.acegisecurity.vote.LabeledData; + +import java.io.Serializable; + + +/** + * For label unit tests. + * + * @author Greg Turnquist + * @version $Id$ + */ +public class SampleBlockOfData implements Serializable, LabeledData { + //~ Static fields/initializers ===================================================================================== + + private static final long serialVersionUID = 1L; + public static final String DATA_LABEL_BLUE = "blue"; + public static final String DATA_LABEL_ORANGE = "orange"; + public static final String DATA_LABEL_SHARED = "blue-orange"; + + //~ Instance fields ================================================================================================ + + private String dataType; + private String id; + + //~ Methods ======================================================================================================== + + public String getId() { + return id; + } + + public String getLabel() { + return dataType; + } + + public String getSomeData() { + return dataType; + } + + public void setId(String ticketNumber) { + this.id = ticketNumber; + } + + public void setSomeData(String trafficType) { + this.dataType = trafficType; + } + + public String toString() { + return this.id + "/" + this.dataType; + } +} diff --git a/core/src/test/java/org/acegisecurity/vote/SampleService.java b/core/src/test/java/org/acegisecurity/vote/SampleService.java new file mode 100644 index 0000000000..ea09c2574a --- /dev/null +++ b/core/src/test/java/org/acegisecurity/vote/SampleService.java @@ -0,0 +1,31 @@ +/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited + * + * 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.acegisecurity.vote; + +import java.util.List; + + +/** + * @author Greg Turnquist + * @version $Id$ + */ +public interface SampleService { + //~ Methods ======================================================================================================== + + public void doSomethingOnThis(SampleBlockOfData block1, SampleBlockOfData block2); + + public List getTheSampleData(); +} diff --git a/core/src/test/java/org/acegisecurity/vote/SampleServiceImpl.java b/core/src/test/java/org/acegisecurity/vote/SampleServiceImpl.java new file mode 100644 index 0000000000..b535598019 --- /dev/null +++ b/core/src/test/java/org/acegisecurity/vote/SampleServiceImpl.java @@ -0,0 +1,78 @@ +/* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited + * + * 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.acegisecurity.vote; + +import org.acegisecurity.context.SecurityContextHolder; + +import org.apache.log4j.Logger; + +import java.util.List; +import java.util.Vector; + + +/** + * For label unit tests. + * + * @author Greg Turnquist + * @version $Id$ + */ +public class SampleServiceImpl implements SampleService { + //~ Instance fields ================================================================================================ + + Logger logger = Logger.getLogger(SampleServiceImpl.class); + + //~ Methods ======================================================================================================== + + public void doSomethingOnThis(SampleBlockOfData block1, SampleBlockOfData block2) { + if (logger.isDebugEnabled()) { + logger.debug("You made it! Your context is " + SecurityContextHolder.getContext().getAuthentication()); + } + + if (logger.isDebugEnabled()) { + logger.debug("Block1 is " + block1); + } + + if (logger.isDebugEnabled()) { + logger.debug("Block2 is " + block2); + } + } + + public List getTheSampleData() { + if (logger.isDebugEnabled()) { + logger.debug(SecurityContextHolder.getContext().getAuthentication().getName() + + " is requesting some sample data."); + } + + List dataList = new Vector(); + SampleBlockOfData block; + + block = new SampleBlockOfData(); + block.setId("001"); + block.setSomeData(SampleBlockOfData.DATA_LABEL_BLUE); + dataList.add(block); + + block = new SampleBlockOfData(); + block.setId("002"); + block.setSomeData(SampleBlockOfData.DATA_LABEL_ORANGE); + dataList.add(block); + + block = new SampleBlockOfData(); + block.setId("003"); + block.setSomeData(SampleBlockOfData.DATA_LABEL_SHARED); + dataList.add(block); + + return dataList; + } +} diff --git a/core/src/test/resources/org/acegisecurity/vote/labelBasedSecurityApplicationContext.xml b/core/src/test/resources/org/acegisecurity/vote/labelBasedSecurityApplicationContext.xml new file mode 100644 index 0000000000..30e5ce0dbc --- /dev/null +++ b/core/src/test/resources/org/acegisecurity/vote/labelBasedSecurityApplicationContext.xml @@ -0,0 +1,91 @@ + + + + + + + blueuser=password,ROLE_BASIC,LABEL_BLUE + superuser=password2,ROLE_BASIC,LABEL_SHARED + orangeuser=password3,ROLE_BASIC,LABEL_ORANGE + multiuser=password4,ROLE_BASIC,LABEL_BLUE,LABEL_ORANGE + + + + + + + + + + + + + + + + + + false + + + + + LABELED_OPERATION + + + + + blue + blue-orange + + + + + orange + blue-orange + + + + + blue + orange + blue-orange + + + + + + + + + + + false + + + + + org.acegisecurity.vote.SampleService.get*=ROLE_BASIC + org.acegisecurity.vote.SampleService.do*=ROLE_BASIC,LABELED_OPERATION + + + + + + Security: + + + + + + sampleService + + + perfOfSecurity + securityInteceptor + + + + +