blob: 181d693614cad83007649b652dafc369caf4ffd0 [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.plugins;
import java.security.Principal;
import javax.security.auth.Subject;
import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.server.security.Result;
import org.apache.qpid.server.security.access.ObjectProperties;
import org.apache.qpid.server.security.access.ObjectType;
import org.apache.qpid.server.security.access.Operation;
import org.apache.qpid.server.security.access.Permission;
import org.apache.qpid.server.security.access.config.Rule;
import org.apache.qpid.server.security.access.config.RuleSet;
import org.apache.qpid.server.security.auth.TestPrincipalUtils;
import org.apache.qpid.test.utils.QpidTestCase;
/**
* This test checks that the {@link RuleSet} object which forms the core of the access control plugin performs correctly.
*
* The ruleset is configured directly rather than using an external file by adding rules individually, calling the
* {@link RuleSet#grant(Integer, String, Permission, Operation, ObjectType, ObjectProperties)} method. Then, the
* access control mechanism is validated by checking whether operations would be authorised by calling the
* {@link RuleSet#check(Principal, Operation, ObjectType, ObjectProperties)} method.
*
* It ensure that permissions can be granted correctly on users directly and on groups.
*/
public class RuleSetTest extends QpidTestCase
{
private RuleSet _ruleSet; // Object under test
private static final String TEST_USER = "user";
// Common things that are passed to frame constructors
private AMQShortString _queueName = new AMQShortString(this.getClass().getName() + "queue");
private AMQShortString _exchangeName = new AMQShortString("amq.direct");
private AMQShortString _exchangeType = new AMQShortString("direct");
private Subject _testSubject = TestPrincipalUtils.createTestSubject(TEST_USER);
@Override
public void setUp() throws Exception
{
super.setUp();
_ruleSet = new RuleSet();
}
@Override
public void tearDown() throws Exception
{
_ruleSet.clear();
super.tearDown();
}
public void assertDenyGrantAllow(Subject subject, Operation operation, ObjectType objectType)
{
assertDenyGrantAllow(subject, operation, objectType, ObjectProperties.EMPTY);
}
public void assertDenyGrantAllow(Subject subject, Operation operation, ObjectType objectType, ObjectProperties properties)
{
final Principal identity = subject.getPrincipals().iterator().next();
assertEquals(Result.DENIED, _ruleSet.check(subject, operation, objectType, properties));
_ruleSet.grant(0, identity.getName(), Permission.ALLOW, operation, objectType, properties);
assertEquals(1, _ruleSet.getRuleCount());
assertEquals(Result.ALLOWED, _ruleSet.check(subject, operation, objectType, properties));
}
public void testEmptyRuleSet()
{
assertNotNull(_ruleSet);
assertEquals(_ruleSet.getRuleCount(), 0);
assertEquals(_ruleSet.getDefault(), _ruleSet.check(_testSubject, Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY));
}
public void testVirtualHostAccess() throws Exception
{
assertDenyGrantAllow(_testSubject, Operation.ACCESS, ObjectType.VIRTUALHOST);
}
public void testQueueCreateNamed() throws Exception
{
assertDenyGrantAllow(_testSubject, Operation.CREATE, ObjectType.QUEUE, new ObjectProperties(_queueName));
}
public void testQueueCreatenamedNullRoutingKey()
{
ObjectProperties properties = new ObjectProperties(_queueName);
properties.put(ObjectProperties.Property.ROUTING_KEY, (String) null);
assertDenyGrantAllow(_testSubject, Operation.CREATE, ObjectType.QUEUE, properties);
}
public void testExchangeCreate()
{
ObjectProperties properties = new ObjectProperties(_exchangeName);
properties.put(ObjectProperties.Property.TYPE, _exchangeType.asString());
assertDenyGrantAllow(_testSubject, Operation.CREATE, ObjectType.EXCHANGE, properties);
}
public void testConsume()
{
assertDenyGrantAllow(_testSubject, Operation.CONSUME, ObjectType.QUEUE);
}
public void testPublish()
{
assertDenyGrantAllow(_testSubject, Operation.PUBLISH, ObjectType.EXCHANGE);
}
/**
* If the consume permission for temporary queues is for an unnamed queue then it should
* be global for any temporary queue but not for any non-temporary queue
*/
public void testTemporaryUnnamedQueueConsume()
{
ObjectProperties temporary = new ObjectProperties();
temporary.put(ObjectProperties.Property.AUTO_DELETE, Boolean.TRUE);
ObjectProperties normal = new ObjectProperties();
normal.put(ObjectProperties.Property.AUTO_DELETE, Boolean.FALSE);
assertEquals(Result.DENIED, _ruleSet.check(_testSubject, Operation.CONSUME, ObjectType.QUEUE, temporary));
_ruleSet.grant(0, TEST_USER, Permission.ALLOW, Operation.CONSUME, ObjectType.QUEUE, temporary);
assertEquals(1, _ruleSet.getRuleCount());
assertEquals(Result.ALLOWED, _ruleSet.check(_testSubject, Operation.CONSUME, ObjectType.QUEUE, temporary));
// defer to global if exists, otherwise default answer - this is handled by the security manager
assertEquals(Result.DEFER, _ruleSet.check(_testSubject, Operation.CONSUME, ObjectType.QUEUE, normal));
}
/**
* Test that temporary queue permissions before queue perms in the ACL config work correctly
*/
public void testTemporaryQueueFirstConsume()
{
ObjectProperties temporary = new ObjectProperties(_queueName);
temporary.put(ObjectProperties.Property.AUTO_DELETE, Boolean.TRUE);
ObjectProperties normal = new ObjectProperties(_queueName);
normal.put(ObjectProperties.Property.AUTO_DELETE, Boolean.FALSE);
assertEquals(Result.DENIED, _ruleSet.check(_testSubject, Operation.CONSUME, ObjectType.QUEUE, temporary));
// should not matter if the temporary permission is processed first or last
_ruleSet.grant(1, TEST_USER, Permission.ALLOW, Operation.CONSUME, ObjectType.QUEUE, normal);
_ruleSet.grant(2, TEST_USER, Permission.ALLOW, Operation.CONSUME, ObjectType.QUEUE, temporary);
assertEquals(2, _ruleSet.getRuleCount());
assertEquals(Result.ALLOWED, _ruleSet.check(_testSubject, Operation.CONSUME, ObjectType.QUEUE, normal));
assertEquals(Result.ALLOWED, _ruleSet.check(_testSubject, Operation.CONSUME, ObjectType.QUEUE, temporary));
}
/**
* Test that temporary queue permissions after queue perms in the ACL config work correctly
*/
public void testTemporaryQueueLastConsume()
{
ObjectProperties temporary = new ObjectProperties(_queueName);
temporary.put(ObjectProperties.Property.AUTO_DELETE, Boolean.TRUE);
ObjectProperties normal = new ObjectProperties(_queueName);
normal.put(ObjectProperties.Property.AUTO_DELETE, Boolean.FALSE);
assertEquals(Result.DENIED, _ruleSet.check(_testSubject, Operation.CONSUME, ObjectType.QUEUE, temporary));
// should not matter if the temporary permission is processed first or last
_ruleSet.grant(1, TEST_USER, Permission.ALLOW, Operation.CONSUME, ObjectType.QUEUE, temporary);
_ruleSet.grant(2, TEST_USER, Permission.ALLOW, Operation.CONSUME, ObjectType.QUEUE, normal);
assertEquals(2, _ruleSet.getRuleCount());
assertEquals(Result.ALLOWED, _ruleSet.check(_testSubject, Operation.CONSUME, ObjectType.QUEUE, normal));
assertEquals(Result.ALLOWED, _ruleSet.check(_testSubject, Operation.CONSUME, ObjectType.QUEUE, temporary));
}
/*
* Test different rules for temporary queues.
*/
/**
* The more generic rule first is used, so both requests are allowed.
*/
public void testFirstNamedSecondTemporaryQueueDenied()
{
ObjectProperties named = new ObjectProperties(_queueName);
ObjectProperties namedTemporary = new ObjectProperties(_queueName);
namedTemporary.put(ObjectProperties.Property.AUTO_DELETE, Boolean.TRUE);
assertEquals(Result.DENIED, _ruleSet.check(_testSubject, Operation.CREATE, ObjectType.QUEUE, named));
assertEquals(Result.DENIED, _ruleSet.check(_testSubject, Operation.CREATE, ObjectType.QUEUE, namedTemporary));
_ruleSet.grant(1, TEST_USER, Permission.ALLOW, Operation.CREATE, ObjectType.QUEUE, named);
_ruleSet.grant(2, TEST_USER, Permission.DENY, Operation.CREATE, ObjectType.QUEUE, namedTemporary);
assertEquals(2, _ruleSet.getRuleCount());
assertEquals(Result.ALLOWED, _ruleSet.check(_testSubject, Operation.CREATE, ObjectType.QUEUE, named));
assertEquals(Result.ALLOWED, _ruleSet.check(_testSubject, Operation.CREATE, ObjectType.QUEUE, namedTemporary));
}
/**
* The more specific rule is first, so those requests are denied.
*/
public void testFirstTemporarySecondNamedQueueDenied()
{
ObjectProperties named = new ObjectProperties(_queueName);
ObjectProperties namedTemporary = new ObjectProperties(_queueName);
namedTemporary.put(ObjectProperties.Property.AUTO_DELETE, Boolean.TRUE);
assertEquals(Result.DENIED, _ruleSet.check(_testSubject, Operation.CREATE, ObjectType.QUEUE, named));
assertEquals(Result.DENIED, _ruleSet.check(_testSubject, Operation.CREATE, ObjectType.QUEUE, namedTemporary));
_ruleSet.grant(1, TEST_USER, Permission.DENY, Operation.CREATE, ObjectType.QUEUE, namedTemporary);
_ruleSet.grant(2, TEST_USER, Permission.ALLOW, Operation.CREATE, ObjectType.QUEUE, named);
assertEquals(2, _ruleSet.getRuleCount());
assertEquals(Result.ALLOWED, _ruleSet.check(_testSubject, Operation.CREATE, ObjectType.QUEUE, named));
assertEquals(Result.DENIED, _ruleSet.check(_testSubject, Operation.CREATE, ObjectType.QUEUE, namedTemporary));
}
/**
* The more specific rules are first, so those requests are denied.
*/
public void testFirstTemporarySecondDurableThirdNamedQueueDenied()
{
ObjectProperties named = new ObjectProperties(_queueName);
ObjectProperties namedTemporary = new ObjectProperties(_queueName);
namedTemporary.put(ObjectProperties.Property.AUTO_DELETE, Boolean.TRUE);
ObjectProperties namedDurable = new ObjectProperties(_queueName);
namedDurable.put(ObjectProperties.Property.DURABLE, Boolean.TRUE);
assertEquals(Result.DENIED, _ruleSet.check(_testSubject, Operation.CREATE, ObjectType.QUEUE, named));
assertEquals(Result.DENIED, _ruleSet.check(_testSubject, Operation.CREATE, ObjectType.QUEUE, namedTemporary));
assertEquals(Result.DENIED, _ruleSet.check(_testSubject, Operation.CREATE, ObjectType.QUEUE, namedDurable));
_ruleSet.grant(1, TEST_USER, Permission.DENY, Operation.CREATE, ObjectType.QUEUE, namedTemporary);
_ruleSet.grant(2, TEST_USER, Permission.DENY, Operation.CREATE, ObjectType.QUEUE, namedDurable);
_ruleSet.grant(3, TEST_USER, Permission.ALLOW, Operation.CREATE, ObjectType.QUEUE, named);
assertEquals(3, _ruleSet.getRuleCount());
assertEquals(Result.ALLOWED, _ruleSet.check(_testSubject, Operation.CREATE, ObjectType.QUEUE, named));
assertEquals(Result.DENIED, _ruleSet.check(_testSubject, Operation.CREATE, ObjectType.QUEUE, namedTemporary));
assertEquals(Result.DENIED, _ruleSet.check(_testSubject, Operation.CREATE, ObjectType.QUEUE, namedDurable));
}
public void testNamedTemporaryQueueAllowed()
{
ObjectProperties named = new ObjectProperties(_queueName);
ObjectProperties namedTemporary = new ObjectProperties(_queueName);
namedTemporary.put(ObjectProperties.Property.AUTO_DELETE, Boolean.TRUE);
assertEquals(Result.DENIED, _ruleSet.check(_testSubject, Operation.CREATE, ObjectType.QUEUE, named));
assertEquals(Result.DENIED, _ruleSet.check(_testSubject, Operation.CREATE, ObjectType.QUEUE, namedTemporary));
_ruleSet.grant(1, TEST_USER, Permission.ALLOW, Operation.CREATE, ObjectType.QUEUE, namedTemporary);
_ruleSet.grant(2, TEST_USER, Permission.ALLOW, Operation.CREATE, ObjectType.QUEUE, named);
assertEquals(2, _ruleSet.getRuleCount());
assertEquals(Result.ALLOWED, _ruleSet.check(_testSubject, Operation.CREATE, ObjectType.QUEUE, named));
assertEquals(Result.ALLOWED, _ruleSet.check(_testSubject, Operation.CREATE, ObjectType.QUEUE, namedTemporary));
}
public void testNamedTemporaryQueueDeniedAllowed()
{
ObjectProperties named = new ObjectProperties(_queueName);
ObjectProperties namedTemporary = new ObjectProperties(_queueName);
namedTemporary.put(ObjectProperties.Property.AUTO_DELETE, Boolean.TRUE);
assertEquals(Result.DENIED, _ruleSet.check(_testSubject, Operation.CREATE, ObjectType.QUEUE, named));
assertEquals(Result.DENIED, _ruleSet.check(_testSubject, Operation.CREATE, ObjectType.QUEUE, namedTemporary));
_ruleSet.grant(1, TEST_USER, Permission.ALLOW, Operation.CREATE, ObjectType.QUEUE, namedTemporary);
_ruleSet.grant(2, TEST_USER, Permission.DENY, Operation.CREATE, ObjectType.QUEUE, named);
assertEquals(2, _ruleSet.getRuleCount());
assertEquals(Result.DENIED, _ruleSet.check(_testSubject, Operation.CREATE, ObjectType.QUEUE, named));
assertEquals(Result.ALLOWED, _ruleSet.check(_testSubject, Operation.CREATE, ObjectType.QUEUE, namedTemporary));
}
/**
* Tests support for the {@link Rule#ALL} keyword.
*/
public void testAllowToAll()
{
_ruleSet.grant(1, Rule.ALL, Permission.ALLOW, Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY);
assertEquals(1, _ruleSet.getRuleCount());
assertEquals(Result.ALLOWED, _ruleSet.check(TestPrincipalUtils.createTestSubject("usera"),Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY));
assertEquals(Result.ALLOWED, _ruleSet.check(TestPrincipalUtils.createTestSubject("userb"),Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY));
}
public void testGroupsSupported()
{
String allowGroup = "allowGroup";
String deniedGroup = "deniedGroup";
_ruleSet.grant(1, allowGroup, Permission.ALLOW, Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY);
_ruleSet.grant(2, deniedGroup, Permission.DENY, Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY);
assertEquals(2, _ruleSet.getRuleCount());
assertEquals(Result.ALLOWED, _ruleSet.check(TestPrincipalUtils.createTestSubject("usera", allowGroup),Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY));
assertEquals(Result.DENIED, _ruleSet.check(TestPrincipalUtils.createTestSubject("userb", deniedGroup),Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY));
assertEquals(Result.DEFER, _ruleSet.check(TestPrincipalUtils.createTestSubject("user", "group not mentioned in acl"),Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY));
}
/**
* Rule order in the ACL determines the outcome of the check. This test ensures that a user who is
* granted explicit permission on an object, is granted that access even though a group
* to which the user belongs is later denied the permission.
*/
public void testAllowDeterminedByRuleOrder()
{
String group = "group";
String user = "user";
_ruleSet.grant(1, user, Permission.ALLOW, Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY);
_ruleSet.grant(2, group, Permission.DENY, Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY);
assertEquals(2, _ruleSet.getRuleCount());
assertEquals(Result.ALLOWED, _ruleSet.check(TestPrincipalUtils.createTestSubject(user, group),Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY));
}
/**
* Rule order in the ACL determines the outcome of the check. This tests ensures that a user who is denied
* access by group, is denied access, despite there being a later rule granting permission to that user.
*/
public void testDenyDeterminedByRuleOrder()
{
String group = "aclgroup";
String user = "usera";
_ruleSet.grant(1, group, Permission.DENY, Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY);
_ruleSet.grant(2, user, Permission.ALLOW, Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY);
assertEquals(2, _ruleSet.getRuleCount());
assertEquals(Result.DENIED, _ruleSet.check(TestPrincipalUtils.createTestSubject(user, group),Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY));
}
public void testUserInMultipleGroups()
{
String allowedGroup = "group1";
String deniedGroup = "group2";
_ruleSet.grant(1, allowedGroup, Permission.ALLOW, Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY);
_ruleSet.grant(2, deniedGroup, Permission.DENY, Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY);
Subject subjectInBothGroups = TestPrincipalUtils.createTestSubject("user", allowedGroup, deniedGroup);
Subject subjectInDeniedGroupAndOneOther = TestPrincipalUtils.createTestSubject("user", deniedGroup, "some other group");
Subject subjectInAllowedGroupAndOneOther = TestPrincipalUtils.createTestSubject("user", allowedGroup, "some other group");
assertEquals(Result.ALLOWED, _ruleSet.check(subjectInBothGroups,Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY));
assertEquals(Result.DENIED, _ruleSet.check(subjectInDeniedGroupAndOneOther,Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY));
assertEquals(Result.ALLOWED, _ruleSet.check(subjectInAllowedGroupAndOneOther,Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY));
}
}