blob: e9b8b2241d94a3ec9bf77ca9ee95af7254b94b80 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.qpid.server.security.access.config;
import static org.mockito.Mockito.mock;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.util.List;
import org.apache.qpid.server.configuration.IllegalConfigurationException;
import org.apache.qpid.server.logging.EventLoggerProvider;
import org.apache.qpid.server.security.access.config.ObjectProperties.Property;
import org.apache.qpid.test.utils.QpidTestCase;
public class AclFileParserTest extends QpidTestCase
{
private RuleSet writeACLConfig(String...aclData) throws Exception
{
File acl = File.createTempFile(getClass().getName() + getName(), "acl");
acl.deleteOnExit();
// Write ACL file
PrintWriter aclWriter = new PrintWriter(new FileWriter(acl));
for (String line : aclData)
{
aclWriter.println(line);
}
aclWriter.close();
// Load ruleset
return AclFileParser.parse(new FileReader(acl), mock(EventLoggerProvider.class));
}
public void testACLFileSyntaxContinuation() throws Exception
{
try
{
writeACLConfig("ACL ALLOW ALL \\ ALL");
fail("fail");
}
catch (IllegalConfigurationException ce)
{
assertEquals(String.format(AclFileParser.PREMATURE_CONTINUATION_MSG, 1), ce.getMessage());
}
}
public void testACLFileSyntaxTokens() throws Exception
{
try
{
writeACLConfig("ACL unparsed ALL ALL");
fail("fail");
}
catch (IllegalConfigurationException ce)
{
assertEquals(String.format(AclFileParser.PARSE_TOKEN_FAILED_MSG, 1), ce.getMessage());
assertTrue(ce.getCause() instanceof IllegalArgumentException);
assertEquals("Not a valid permission: unparsed", ce.getCause().getMessage());
}
}
public void testACLFileSyntaxNotEnoughACL() throws Exception
{
try
{
writeACLConfig("ACL ALLOW");
fail("fail");
}
catch (IllegalConfigurationException ce)
{
assertEquals(String.format(AclFileParser.NOT_ENOUGH_ACL_MSG, 1), ce.getMessage());
}
}
public void testACLFileSyntaxNotEnoughConfig() throws Exception
{
try
{
writeACLConfig("CONFIG");
fail("fail");
}
catch (IllegalConfigurationException ce)
{
assertEquals(String.format(AclFileParser.NOT_ENOUGH_TOKENS_MSG, 1), ce.getMessage());
}
}
public void testACLFileSyntaxNotEnough() throws Exception
{
try
{
writeACLConfig("INVALID");
fail("fail");
}
catch (IllegalConfigurationException ce)
{
assertEquals(String.format(AclFileParser.NOT_ENOUGH_TOKENS_MSG, 1), ce.getMessage());
}
}
public void testACLFileSyntaxPropertyKeyOnly() throws Exception
{
try
{
writeACLConfig("ACL ALLOW adk CREATE QUEUE name");
fail("fail");
}
catch (IllegalConfigurationException ce)
{
assertEquals(String.format(AclFileParser.PROPERTY_KEY_ONLY_MSG, 1), ce.getMessage());
}
}
public void testACLFileSyntaxPropertyNoEquals() throws Exception
{
try
{
writeACLConfig("ACL ALLOW adk CREATE QUEUE name test");
fail("fail");
}
catch (IllegalConfigurationException ce)
{
assertEquals(String.format(AclFileParser.PROPERTY_NO_EQUALS_MSG, 1), ce.getMessage());
}
}
public void testACLFileSyntaxPropertyNoValue() throws Exception
{
try
{
writeACLConfig("ACL ALLOW adk CREATE QUEUE name =");
fail("fail");
}
catch (IllegalConfigurationException ce)
{
assertEquals(String.format(AclFileParser.PROPERTY_NO_VALUE_MSG, 1), ce.getMessage());
}
}
/**
* Tests interpretation of an acl rule with no object properties.
*
*/
public void testValidRule() throws Exception
{
final RuleSet rs = writeACLConfig("ACL DENY-LOG user1 ACCESS VIRTUALHOST");
assertEquals(1, rs.getRuleCount());
final List<Rule> rules = rs.getAllRules();
assertEquals(1, rules.size());
final Rule rule = rules.get(0);
assertEquals("Rule has unexpected identity", "user1", rule.getIdentity());
assertEquals("Rule has unexpected operation", LegacyOperation.ACCESS, rule.getAction().getOperation());
assertEquals("Rule has unexpected operation", ObjectType.VIRTUALHOST, rule.getAction().getObjectType());
assertEquals("Rule has unexpected object properties", ObjectProperties.EMPTY, rule.getAction().getProperties());
}
/**
* Tests interpretation of an acl rule with object properties quoted in single quotes.
*/
public void testValidRuleWithSingleQuotedProperty() throws Exception
{
final RuleSet rs = writeACLConfig("ACL ALLOW all CREATE EXCHANGE name = \'value\'");
assertEquals(1, rs.getRuleCount());
final List<Rule> rules = rs.getAllRules();
assertEquals(1, rules.size());
final Rule rule = rules.get(0);
assertEquals("Rule has unexpected identity", "all", rule.getIdentity());
assertEquals("Rule has unexpected operation", LegacyOperation.CREATE, rule.getAction().getOperation());
assertEquals("Rule has unexpected operation", ObjectType.EXCHANGE, rule.getAction().getObjectType());
final ObjectProperties expectedProperties = new ObjectProperties();
expectedProperties.setName("value");
assertEquals("Rule has unexpected object properties", expectedProperties, rule.getAction().getProperties());
}
/**
* Tests interpretation of an acl rule with object properties quoted in double quotes.
*/
public void testValidRuleWithDoubleQuotedProperty() throws Exception
{
final RuleSet rs = writeACLConfig("ACL ALLOW all CREATE EXCHANGE name = \"value\"");
assertEquals(1, rs.getRuleCount());
final List<Rule> rules = rs.getAllRules();
assertEquals(1, rules.size());
final Rule rule = rules.get(0);
assertEquals("Rule has unexpected identity", "all", rule.getIdentity());
assertEquals("Rule has unexpected operation", LegacyOperation.CREATE, rule.getAction().getOperation());
assertEquals("Rule has unexpected operation", ObjectType.EXCHANGE, rule.getAction().getObjectType());
final ObjectProperties expectedProperties = new ObjectProperties();
expectedProperties.setName("value");
assertEquals("Rule has unexpected object properties", expectedProperties, rule.getAction().getProperties());
}
/**
* Tests interpretation of an acl rule with many object properties.
*/
public void testValidRuleWithManyProperties() throws Exception
{
final RuleSet rs = writeACLConfig("ACL ALLOW admin DELETE QUEUE name=name1 owner = owner1");
assertEquals(1, rs.getRuleCount());
final List<Rule> rules = rs.getAllRules();
assertEquals(1, rules.size());
final Rule rule = rules.get(0);
assertEquals("Rule has unexpected identity", "admin", rule.getIdentity());
assertEquals("Rule has unexpected operation", LegacyOperation.DELETE, rule.getAction().getOperation());
assertEquals("Rule has unexpected operation", ObjectType.QUEUE, rule.getAction().getObjectType());
final ObjectProperties expectedProperties = new ObjectProperties();
expectedProperties.setName("name1");
expectedProperties.put(Property.OWNER, "owner1");
assertEquals("Rule has unexpected operation", expectedProperties, rule.getAction().getProperties());
}
/**
* Tests interpretation of an acl rule with object properties containing wildcards. Values containing
* hashes must be quoted otherwise they are interpreted as comments.
*/
public void testValidRuleWithWildcardProperties() throws Exception
{
final RuleSet rs = writeACLConfig("ACL ALLOW all CREATE EXCHANGE routingKey = \'news.#\'",
"ACL ALLOW all CREATE EXCHANGE routingKey = \'news.co.#\'",
"ACL ALLOW all CREATE EXCHANGE routingKey = *.co.medellin");
assertEquals(3, rs.getRuleCount());
final List<Rule> rules = rs.getAllRules();
assertEquals(3, rules.size());
final Rule rule1 = rules.get(0);
assertEquals("Rule has unexpected identity", "all", rule1.getIdentity());
assertEquals("Rule has unexpected operation", LegacyOperation.CREATE, rule1.getAction().getOperation());
assertEquals("Rule has unexpected operation", ObjectType.EXCHANGE, rule1.getAction().getObjectType());
final ObjectProperties expectedProperties1 = new ObjectProperties();
expectedProperties1.put(Property.ROUTING_KEY,"news.#");
assertEquals("Rule has unexpected object properties", expectedProperties1, rule1.getAction().getProperties());
final Rule rule2 = rules.get(1);
final ObjectProperties expectedProperties2 = new ObjectProperties();
expectedProperties2.put(Property.ROUTING_KEY,"news.co.#");
assertEquals("Rule has unexpected object properties", expectedProperties2, rule2.getAction().getProperties());
final Rule rule3 = rules.get(2);
final ObjectProperties expectedProperties3 = new ObjectProperties();
expectedProperties3.put(Property.ROUTING_KEY,"*.co.medellin");
assertEquals("Rule has unexpected object properties", expectedProperties3, rule3.getAction().getProperties());
}
/**
* Tests that rules are case insignificant.
*/
public void testMixedCaseRuleInterpretation() throws Exception
{
final RuleSet rs = writeACLConfig("AcL deny-LOG User1 BiND Exchange Name=AmQ.dIrect");
assertEquals(1, rs.getRuleCount());
final List<Rule> rules = rs.getAllRules();
assertEquals(1, rules.size());
final Rule rule = rules.get(0);
assertEquals("Rule has unexpected identity", "User1", rule.getIdentity());
assertEquals("Rule has unexpected operation", LegacyOperation.BIND, rule.getAction().getOperation());
assertEquals("Rule has unexpected operation", ObjectType.EXCHANGE, rule.getAction().getObjectType());
final ObjectProperties expectedProperties = new ObjectProperties("AmQ.dIrect");
assertEquals("Rule has unexpected object properties", expectedProperties, rule.getAction().getProperties());
}
/**
* Tests whitespace is supported. Note that currently the Java implementation permits comments to
* be introduced anywhere in the ACL, whereas the C++ supports only whitespace at the beginning of
* of line.
*/
public void testCommentsSupported() throws Exception
{
final RuleSet rs = writeACLConfig("#Comment",
"ACL DENY-LOG user1 ACCESS VIRTUALHOST # another comment",
" # final comment with leading whitespace");
assertEquals(1, rs.getRuleCount());
final List<Rule> rules = rs.getAllRules();
assertEquals(1, rules.size());
final Rule rule = rules.get(0);
assertEquals("Rule has unexpected identity", "user1", rule.getIdentity());
assertEquals("Rule has unexpected operation", LegacyOperation.ACCESS, rule.getAction().getOperation());
assertEquals("Rule has unexpected operation", ObjectType.VIRTUALHOST, rule.getAction().getObjectType());
assertEquals("Rule has unexpected object properties", ObjectProperties.EMPTY, rule.getAction().getProperties());
}
/**
* Tests interpretation of an acl rule using mixtures of tabs/spaces as token separators.
*
*/
public void testWhitespace() throws Exception
{
final RuleSet rs = writeACLConfig("ACL\tDENY-LOG\t\t user1\t \tACCESS VIRTUALHOST");
assertEquals(1, rs.getRuleCount());
final List<Rule> rules = rs.getAllRules();
assertEquals(1, rules.size());
final Rule rule = rules.get(0);
assertEquals("Rule has unexpected identity", "user1", rule.getIdentity());
assertEquals("Rule has unexpected operation", LegacyOperation.ACCESS, rule.getAction().getOperation());
assertEquals("Rule has unexpected operation", ObjectType.VIRTUALHOST, rule.getAction().getObjectType());
assertEquals("Rule has unexpected object properties", ObjectProperties.EMPTY, rule.getAction().getProperties());
}
/**
* Tests interpretation of an acl utilising line continuation.
*/
public void testLineContinuation() throws Exception
{
final RuleSet rs = writeACLConfig("ACL DENY-LOG user1 \\",
"ACCESS VIRTUALHOST");
assertEquals(1, rs.getRuleCount());
final List<Rule> rules = rs.getAllRules();
assertEquals(1, rules.size());
final Rule rule = rules.get(0);
assertEquals("Rule has unexpected identity", "user1", rule.getIdentity());
assertEquals("Rule has unexpected operation", LegacyOperation.ACCESS, rule.getAction().getOperation());
assertEquals("Rule has unexpected operation", ObjectType.VIRTUALHOST, rule.getAction().getObjectType());
assertEquals("Rule has unexpected object properties", ObjectProperties.EMPTY, rule.getAction().getProperties());
}
public void testUserRuleParsing() throws Exception
{
validateRule(writeACLConfig("ACL ALLOW user1 CREATE USER"),
"user1", LegacyOperation.CREATE, ObjectType.USER, ObjectProperties.EMPTY);
validateRule(writeACLConfig("ACL ALLOW user1 CREATE USER name=\"otherUser\""),
"user1", LegacyOperation.CREATE, ObjectType.USER, new ObjectProperties("otherUser"));
validateRule(writeACLConfig("ACL ALLOW user1 DELETE USER"),
"user1", LegacyOperation.DELETE, ObjectType.USER, ObjectProperties.EMPTY);
validateRule(writeACLConfig("ACL ALLOW user1 DELETE USER name=\"otherUser\""),
"user1", LegacyOperation.DELETE, ObjectType.USER, new ObjectProperties("otherUser"));
validateRule(writeACLConfig("ACL ALLOW user1 UPDATE USER"),
"user1", LegacyOperation.UPDATE, ObjectType.USER, ObjectProperties.EMPTY);
validateRule(writeACLConfig("ACL ALLOW user1 UPDATE USER name=\"otherUser\""),
"user1", LegacyOperation.UPDATE, ObjectType.USER, new ObjectProperties("otherUser"));
validateRule(writeACLConfig("ACL ALLOW user1 ALL USER"),
"user1", LegacyOperation.ALL, ObjectType.USER, ObjectProperties.EMPTY);
validateRule(writeACLConfig("ACL ALLOW user1 ALL USER name=\"otherUser\""),
"user1", LegacyOperation.ALL, ObjectType.USER, new ObjectProperties("otherUser"));
}
public void testGroupRuleParsing() throws Exception
{
validateRule(writeACLConfig("ACL ALLOW user1 CREATE GROUP"),
"user1", LegacyOperation.CREATE, ObjectType.GROUP, ObjectProperties.EMPTY);
validateRule(writeACLConfig("ACL ALLOW user1 CREATE GROUP name=\"groupName\""),
"user1", LegacyOperation.CREATE, ObjectType.GROUP, new ObjectProperties("groupName"));
validateRule(writeACLConfig("ACL ALLOW user1 DELETE GROUP"),
"user1", LegacyOperation.DELETE, ObjectType.GROUP, ObjectProperties.EMPTY);
validateRule(writeACLConfig("ACL ALLOW user1 DELETE GROUP name=\"groupName\""),
"user1", LegacyOperation.DELETE, ObjectType.GROUP, new ObjectProperties("groupName"));
validateRule(writeACLConfig("ACL ALLOW user1 UPDATE GROUP"),
"user1", LegacyOperation.UPDATE, ObjectType.GROUP, ObjectProperties.EMPTY);
validateRule(writeACLConfig("ACL ALLOW user1 UPDATE GROUP name=\"groupName\""),
"user1", LegacyOperation.UPDATE, ObjectType.GROUP, new ObjectProperties("groupName"));
validateRule(writeACLConfig("ACL ALLOW user1 ALL GROUP"),
"user1", LegacyOperation.ALL, ObjectType.GROUP, ObjectProperties.EMPTY);
validateRule(writeACLConfig("ACL ALLOW user1 ALL GROUP name=\"groupName\""),
"user1", LegacyOperation.ALL, ObjectType.GROUP, new ObjectProperties("groupName"));
}
/** explicitly test for exception indicating that this functionality has been moved to Group Providers */
public void testGroupDefinitionThrowsException() throws Exception
{
try
{
writeACLConfig("GROUP group1 bob alice");
fail("Expected exception not thrown");
}
catch(IllegalConfigurationException e)
{
assertTrue(e.getMessage().contains("GROUP keyword not supported"));
}
}
public void testManagementRuleParsing() throws Exception
{
validateRule(writeACLConfig("ACL ALLOW user1 ALL MANAGEMENT"),
"user1", LegacyOperation.ALL, ObjectType.MANAGEMENT, ObjectProperties.EMPTY);
validateRule(writeACLConfig("ACL ALLOW user1 ACCESS MANAGEMENT"),
"user1", LegacyOperation.ACCESS, ObjectType.MANAGEMENT, ObjectProperties.EMPTY);
}
public void testBrokerRuleParsing() throws Exception
{
validateRule(writeACLConfig("ACL ALLOW user1 CONFIGURE BROKER"), "user1", LegacyOperation.CONFIGURE, ObjectType.BROKER,
ObjectProperties.EMPTY);
validateRule(writeACLConfig("ACL ALLOW user1 ALL BROKER"), "user1", LegacyOperation.ALL, ObjectType.BROKER, ObjectProperties.EMPTY);
}
private void validateRule(final RuleSet rs, String username, LegacyOperation operation, ObjectType objectType, ObjectProperties objectProperties)
{
assertEquals(1, rs.getRuleCount());
final List<Rule> rules = rs.getAllRules();
assertEquals(1, rules.size());
final Rule rule = rules.get(0);
assertEquals("Rule has unexpected identity", username, rule.getIdentity());
assertEquals("Rule has unexpected operation", operation, rule.getAction().getOperation());
assertEquals("Rule has unexpected operation", objectType, rule.getAction().getObjectType());
assertEquals("Rule has unexpected object properties", objectProperties, rule.getAction().getProperties());
}
}