summaryrefslogtreecommitdiff
path: root/qpid/java
diff options
context:
space:
mode:
Diffstat (limited to 'qpid/java')
-rw-r--r--qpid/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/PlainConfiguration.java70
-rw-r--r--qpid/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/Rule.java20
-rw-r--r--qpid/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/RuleSet.java61
-rw-r--r--qpid/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/AccessControl.java8
-rw-r--r--qpid/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/AccessControlConfiguration.java4
-rw-r--r--qpid/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/AccessControlTest.java51
-rw-r--r--qpid/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/PlainConfigurationTest.java86
-rw-r--r--qpid/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/RuleSetTest.java92
-rw-r--r--qpid/java/broker-plugins/management-http/MANIFEST.MF1
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/Management.java6
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/AbstractServlet.java319
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/LogRecordsServlet.java2
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageContentServlet.java2
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageServlet.java6
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/RestServlet.java16
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/SaslServlet.java44
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/StructureServlet.java4
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/authenticationprovider/showPrincipalDatabaseAuthenticationManager.html2
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/group/addGroupMember.html37
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/group/showGroup.html30
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/groupprovider/addGroup.html38
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/groupprovider/showFileGroupManager.html28
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/util.js7
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Exchange.js2
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/GroupProvider.js109
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/VirtualHost.js4
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/controller.js8
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/group/Group.js215
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/group/addGroupMember.js108
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/groupprovider/FileGroupManager.js251
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/treeView.js6
-rw-r--r--qpid/java/broker-plugins/management-http/src/main/java/resources/showGroupProvider.html25
-rw-r--r--qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/AuthenticationProviderRestTest.java4
-rw-r--r--qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/BindingRestTest.java32
-rw-r--r--qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/BrokerRestHttpsTest.java32
-rw-r--r--qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/BrokerRestTest.java12
-rw-r--r--qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/ConnectionRestTest.java16
-rw-r--r--qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/ExchangeRestTest.java10
-rw-r--r--qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/GroupProviderRestTest.java160
-rw-r--r--qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/GroupRestTest.java109
-rw-r--r--qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/LogRecordsRestTest.java4
-rw-r--r--qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/MessagesRestTest.java48
-rw-r--r--qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/PortRestTest.java10
-rw-r--r--qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/QpidRestTestCase.java204
-rw-r--r--qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/QueueRestTest.java22
-rw-r--r--qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/RestTestHelper.java417
-rw-r--r--qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/SaslRestTest.java2
-rw-r--r--qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/StructureRestTest.java14
-rw-r--r--qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/UserRestTest.java51
-rw-r--r--qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/VirtualHostRestTest.java116
-rw-r--r--qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/systest/rest/acl/GroupRestACLTest.java187
-rw-r--r--qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/systest/rest/acl/UserRestACLTest.java188
-rw-r--r--qpid/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXManagedObjectRegistry.java13
-rw-r--r--qpid/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/MBeanInvocationHandlerImpl.java16
-rw-r--r--qpid/java/broker/etc/broker_example.acl24
-rw-r--r--qpid/java/broker/etc/config.xml19
-rw-r--r--qpid/java/broker/etc/groups29
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java9
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java11
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AbstractManagementActor.java48
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/HttpManagementActor.java62
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/ManagementActor.java62
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/LogSubjectFormat.java8
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/model/Group.java52
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/model/GroupMember.java52
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/model/GroupProvider.java51
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/model/Model.java5
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/model/UUIDGenerator.java10
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/model/User.java2
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AuthenticationProviderAdapter.java62
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapter.java75
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/GroupProviderAdapter.java548
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java23
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java5
-rwxr-xr-xqpid/java/broker/src/main/java/org/apache/qpid/server/protocol/MultiVersionProtocolEngine.java2
-rwxr-xr-xqpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngine_1_0_0.java7
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngine_1_0_0_SASL.java10
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java55
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java22
-rwxr-xr-xqpid/java/broker/src/main/java/org/apache/qpid/server/security/AuthorizationHolder.java12
-rwxr-xr-xqpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java23
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/security/SubjectCreator.java137
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectType.java6
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticatedPrincipal.java126
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationResult.java63
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/SubjectAuthenticationResult.java76
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/UsernamePrincipal.java (renamed from qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePrincipal.java)29
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/AbstractPasswordFilePrincipalDatabase.java2
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java2
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AnonymousAuthenticationManager.java12
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java12
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManagerRegistry.java39
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationManager.java7
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/IAuthenticationManagerRegistry.java18
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/KerberosAuthenticationManager.java8
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java32
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManager.java16
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticator.java26
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePasswordInitialiser.java1
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/anonymous/AnonymousSaslServer.java4
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/security/group/FileGroupDatabase.java265
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/security/group/FileGroupManager.java251
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/security/group/GroupDatabase.java34
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/security/group/GroupManager.java42
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/security/group/GroupManagerPluginFactory.java27
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/security/group/GroupPrincipal.java (renamed from qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/GroupPrincipal.java)10
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/security/group/GroupPrincipalAccessor.java51
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java11
-rw-r--r--qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java20
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/logging/actors/AbstractManagementActorTest.java86
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/logging/actors/HttpManagementActorTest.java94
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/logging/actors/ManagementActorTest.java12
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/model/UUIDGeneratorTest.java6
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/protocol/InternalTestProtocolSession.java22
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/security/SubjectCreatorTest.java138
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/AuthenticatedPrincipalTest.java147
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/AuthenticatedPrincipalTestHelper.java54
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/AuthenticationResultTest.java112
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/TestPrincipalUtils.java (renamed from qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/sasl/TestPrincipalUtils.java)15
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/UsernamePrincipalTest.java (renamed from qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/sasl/UsernamePrincipalTest.java)55
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabaseTest.java2
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabaseTest.java2
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/manager/AnonymousAuthenticationManagerTest.java5
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/manager/AuthenticationManagerRegistryTest.java38
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationManagerTest.java9
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManagerTest.java56
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticatorTest.java102
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/security/group/FileGroupDatabaseTest.java456
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/security/group/FileGroupManagerTest.java236
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/security/group/GroupPrincipalAccessorTest.java81
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/security/group/GroupPrincipalTest.java (renamed from qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/sasl/GroupPrincipalTest.java)14
-rw-r--r--qpid/java/broker/src/test/java/org/apache/qpid/server/util/TestApplicationRegistry.java9
-rw-r--r--qpid/java/systests/etc/config-systests-settings.xml14
-rw-r--r--qpid/java/systests/etc/groups-systests29
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/server/logging/AccessControlLoggingTest.java42
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/AbstractACLTestCase.java2
-rw-r--r--qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/ExternalACLTest.java15
137 files changed, 6481 insertions, 1316 deletions
diff --git a/qpid/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/PlainConfiguration.java b/qpid/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/PlainConfiguration.java
index 9a08eb6499..afaece6138 100644
--- a/qpid/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/PlainConfiguration.java
+++ b/qpid/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/PlainConfiguration.java
@@ -1,5 +1,5 @@
/*
- *
+ *
* 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
@@ -7,16 +7,16 @@
* 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;
@@ -44,43 +44,41 @@ public class PlainConfiguration extends AbstractConfiguration
public static final Character COMMENT = '#';
public static final Character CONTINUATION = '\\';
- public static final String GROUP = "group";
public static final String ACL = "acl";
public static final String CONFIG = "config";
public static final String UNRECOGNISED_INITIAL_MSG = "Unrecognised initial token '%s' at line %d";
public static final String NOT_ENOUGH_TOKENS_MSG = "Not enough tokens at line %d";
- public static final String NUMBER_NOT_ALLOWED_MSG = "Number not allowed before '%s' at line %d";
+ public static final String NUMBER_NOT_ALLOWED_MSG = "Number not allowed before '%s' at line %d";
public static final String CANNOT_LOAD_MSG = "Cannot load config file %s";
public static final String PREMATURE_CONTINUATION_MSG = "Premature continuation character at line %d";
public static final String PREMATURE_EOF_MSG = "Premature end of file reached at line %d";
public static final String PARSE_TOKEN_FAILED_MSG = "Failed to parse token at line %d";
public static final String CONFIG_NOT_FOUND_MSG = "Cannot find config file %s";
- public static final String NOT_ENOUGH_GROUP_MSG = "Not enough data for a group at line %d";
public static final String NOT_ENOUGH_ACL_MSG = "Not enough data for an acl at line %d";
public static final String NOT_ENOUGH_CONFIG_MSG = "Not enough data for config at line %d";
public static final String BAD_ACL_RULE_NUMBER_MSG = "Invalid rule number at line %d";
public static final String PROPERTY_KEY_ONLY_MSG = "Incomplete property (key only) at line %d";
public static final String PROPERTY_NO_EQUALS_MSG = "Incomplete property (no equals) at line %d";
public static final String PROPERTY_NO_VALUE_MSG = "Incomplete property (no value) at line %d";
-
+
private StreamTokenizer _st;
public PlainConfiguration(File file)
{
super(file);
}
-
+
@Override
public RuleSet load() throws ConfigurationException
{
RuleSet ruleSet = super.load();
-
+
try
{
_st = new StreamTokenizer(new BufferedReader(new FileReader(getFile())));
_st.resetSyntax(); // setup the tokenizer
-
+
_st.commentChar(COMMENT); // single line comments
_st.eolIsSignificant(true); // return EOL as a token
_st.ordinaryChar('='); // equals is a token
@@ -97,7 +95,7 @@ public class PlainConfiguration extends AbstractConfiguration
_st.wordChars('*', '*'); // star
_st.wordChars('@', '@'); // at
_st.wordChars(':', ':'); // colon
-
+
// parse the acl file lines
Stack<String> stack = new Stack<String>();
int current;
@@ -111,7 +109,7 @@ public class PlainConfiguration extends AbstractConfiguration
{
break; // blank line
}
-
+
// pull out the first token from the bottom of the stack and check arguments exist
String first = stack.firstElement();
stack.removeElementAt(0);
@@ -119,13 +117,13 @@ public class PlainConfiguration extends AbstractConfiguration
{
throw new ConfigurationException(String.format(NOT_ENOUGH_TOKENS_MSG, getLine()));
}
-
+
// check for and parse optional initial number for ACL lines
Integer number = null;
if (StringUtils.isNumeric(first))
{
// set the acl number and get the next element
- number = Integer.valueOf(first);
+ number = Integer.valueOf(first);
first = stack.firstElement();
stack.removeElementAt(0);
}
@@ -136,9 +134,9 @@ public class PlainConfiguration extends AbstractConfiguration
}
else if (number == null)
{
- if (StringUtils.equalsIgnoreCase(GROUP, first))
+ if(StringUtils.equalsIgnoreCase("GROUP", first))
{
- parseGroup(stack);
+ throw new ConfigurationException(String.format("GROUP keyword not supported. Groups should defined via a Group Provider, not in the ACL file.", getLine()));
}
else if (StringUtils.equalsIgnoreCase(CONFIG, first))
{
@@ -153,7 +151,7 @@ public class PlainConfiguration extends AbstractConfiguration
{
throw new ConfigurationException(String.format(NUMBER_NOT_ALLOWED_MSG, first, getLine()));
}
-
+
// reset stack, start next line
stack.clear();
break;
@@ -171,7 +169,7 @@ public class PlainConfiguration extends AbstractConfiguration
{
break; // continue reading next line
}
-
+
// invalid location for continuation character (add one to line beacuse we ate the EOL)
throw new ConfigurationException(String.format(PREMATURE_CONTINUATION_MSG, getLine() + 1));
}
@@ -185,7 +183,7 @@ public class PlainConfiguration extends AbstractConfiguration
}
}
} while (current != StreamTokenizer.TT_EOF);
-
+
if (!stack.isEmpty())
{
throw new ConfigurationException(String.format(PREMATURE_EOF_MSG, getLine()));
@@ -203,20 +201,10 @@ public class PlainConfiguration extends AbstractConfiguration
{
throw new ConfigurationException(String.format(CANNOT_LOAD_MSG, getFile().getName()), ioe);
}
-
+
return ruleSet;
}
-
- private void parseGroup(List<String> args) throws ConfigurationException
- {
- if (args.size() < 2)
- {
- throw new ConfigurationException(String.format(NOT_ENOUGH_GROUP_MSG, getLine()));
- }
-
- getConfiguration().addGroup(args.get(0), args.subList(1, args.size()));
- }
-
+
private void parseAcl(Integer number, List<String> args) throws ConfigurationException
{
if (args.size() < 3)
@@ -227,12 +215,12 @@ public class PlainConfiguration extends AbstractConfiguration
Permission permission = Permission.parse(args.get(0));
String identity = args.get(1);
Operation operation = Operation.parse(args.get(2));
-
+
if (number != null && !getConfiguration().isValidNumber(number))
{
throw new ConfigurationException(String.format(BAD_ACL_RULE_NUMBER_MSG, getLine()));
}
-
+
if (args.size() == 3)
{
getConfiguration().grant(number, identity, permission, operation);
@@ -245,7 +233,7 @@ public class PlainConfiguration extends AbstractConfiguration
getConfiguration().grant(number, identity, permission, operation, object, properties);
}
}
-
+
private void parseConfig(List<String> args) throws ConfigurationException
{
if (args.size() < 3)
@@ -254,10 +242,10 @@ public class PlainConfiguration extends AbstractConfiguration
}
Map<String, Boolean> properties = toPluginProperties(args);
-
+
getConfiguration().configure(properties);
}
-
+
/** Converts a {@link List} of "name", "=", "value" tokens into a {@link Map}. */
protected ObjectProperties toObjectProperties(List<String> args) throws ConfigurationException
{
@@ -279,14 +267,14 @@ public class PlainConfiguration extends AbstractConfiguration
throw new ConfigurationException(String.format(PROPERTY_NO_VALUE_MSG, getLine()));
}
String value = i.next();
-
+
// parse property key
ObjectProperties.Property property = ObjectProperties.Property.parse(key);
properties.put(property, value);
}
return properties;
}
-
+
/** Converts a {@link List} of "name", "=", "value" tokens into a {@link Map}. */
protected Map<String, Boolean> toPluginProperties(List<String> args) throws ConfigurationException
{
@@ -307,14 +295,14 @@ public class PlainConfiguration extends AbstractConfiguration
{
throw new ConfigurationException(String.format(PROPERTY_NO_VALUE_MSG, getLine()));
}
-
+
// parse property value and save
Boolean value = Boolean.valueOf(i.next());
properties.put(key, value);
}
return properties;
}
-
+
protected int getLine()
{
return _st.lineno() - 1;
diff --git a/qpid/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/Rule.java b/qpid/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/Rule.java
index 15d6b67192..5e98e0bd1b 100644
--- a/qpid/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/Rule.java
+++ b/qpid/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/Rule.java
@@ -29,7 +29,7 @@ import org.apache.qpid.server.security.access.Permission;
/**
* An access control v2 rule.
- *
+ *
* A rule consists of {@link Permission} for a particular identity to perform an {@link Action}. The identity
* may be either a user or a group.
*/
@@ -37,13 +37,13 @@ public class Rule implements Comparable<Rule>
{
/** String indicating all identitied. */
public static final String ALL = "all";
-
+
private Integer _number;
private Boolean _enabled = Boolean.TRUE;
private String _identity;
private Action _action;
private Permission _permission;
-
+
public Rule(Integer number, String identity, Action action, Permission permission)
{
setNumber(number);
@@ -51,27 +51,27 @@ public class Rule implements Comparable<Rule>
setAction(action);
setPermission(permission);
}
-
+
public Rule(String identity, Action action, Permission permission)
{
this(null, identity, action, permission);
}
-
+
public boolean isEnabled()
{
return _enabled;
}
-
+
public void setEnabled(boolean enabled)
{
_enabled = enabled;
}
-
+
public void enable()
{
_enabled = Boolean.TRUE;
}
-
+
public void disable()
{
_enabled = Boolean.FALSE;
@@ -96,7 +96,7 @@ public class Rule implements Comparable<Rule>
{
_identity = identity;
}
-
+
public Action getAction()
{
return _action;
@@ -136,7 +136,7 @@ public class Rule implements Comparable<Rule>
return false;
}
Rule r = (Rule) o;
-
+
return new EqualsBuilder()
.append(getIdentity(), r.getIdentity())
.append(getAction(), r.getAction())
diff --git a/qpid/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/RuleSet.java b/qpid/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/RuleSet.java
index 815df99f80..2477455de4 100644
--- a/qpid/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/RuleSet.java
+++ b/qpid/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/RuleSet.java
@@ -19,7 +19,6 @@
package org.apache.qpid.server.security.access.config;
import java.security.Principal;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumMap;
@@ -66,7 +65,6 @@ public class RuleSet
private static final Integer _increment = 10;
- private final Map<String, List<String>> _aclGroups = new HashMap<String, List<String>>();
private final SortedMap<Integer, Rule> _rules = new TreeMap<Integer, Rule>();
private final Map<Subject, Map<Operation, Map<ObjectType, List<Rule>>>> _cache =
new WeakHashMap<Subject, Map<Operation, Map<ObjectType, List<Rule>>>>();
@@ -79,14 +77,13 @@ public class RuleSet
}
/**
- * Clear the contents, including acl groups, rules and configuration.
+ * Clear the contents, including acl rules and configuration.
*/
public void clear()
{
_rules.clear();
_cache.clear();
_config.clear();
- _aclGroups.clear();
}
public int getRuleCount()
@@ -222,53 +219,6 @@ public class RuleSet
_rules.get(Integer.valueOf(ruleNumber)).disable();
}
- public boolean addGroup(String group, List<String> constituents)
- {
- _cache.clear();
-
- if (_aclGroups.containsKey(group))
- {
- // cannot redefine
- return false;
- }
- else
- {
- _aclGroups.put(group, new ArrayList<String>());
- }
-
- for (String name : constituents)
- {
- if (name.equalsIgnoreCase(group))
- {
- // recursive definition
- return false;
- }
-
- if (!checkName(name))
- {
- // invalid name
- return false;
- }
-
- if (_aclGroups.containsKey(name))
- {
- // is a group
- _aclGroups.get(group).addAll(_aclGroups.get(name));
- }
- else
- {
- // is a user
- if (!isvalidUserName(name))
- {
- // invalid username
- return false;
- }
- _aclGroups.get(group).add(name);
- }
- }
- return true;
- }
-
/** Return true if the name is well-formed (contains legal characters). */
protected boolean checkName(String name)
{
@@ -312,12 +262,6 @@ public class RuleSet
return true;
}
- // CPP broker authorise function prototype
- // virtual bool authorise(const std::string& id, const Action& action, const ObjectType& objType,
- // const std::string& name, std::map<Property, std::string>* params=0)
-
- // Possibly add a String name paramater?
-
/**
* Check the authorisation granted to a particular identity for an operation on an object type with
* specific properties.
@@ -446,8 +390,7 @@ public class RuleSet
{
final Principal principal = iterator.next();
- if (rule.getIdentity().equalsIgnoreCase(principal.getName())
- || (_aclGroups.containsKey(rule.getIdentity()) && _aclGroups.get(rule.getIdentity()).contains(principal.getName())))
+ if (rule.getIdentity().equalsIgnoreCase(principal.getName()))
{
return true;
}
diff --git a/qpid/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/AccessControl.java b/qpid/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/AccessControl.java
index d8a5bd4085..d36ae810c6 100644
--- a/qpid/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/AccessControl.java
+++ b/qpid/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/AccessControl.java
@@ -40,9 +40,9 @@ import org.apache.qpid.server.security.access.config.RuleSet;
public class AccessControl extends AbstractPlugin
{
public static final Logger _logger = Logger.getLogger(AccessControl.class);
-
+
private RuleSet _ruleSet;
-
+
public static final SecurityPluginFactory<AccessControl> FACTORY = new SecurityPluginFactory<AccessControl>()
{
public Class<AccessControl> getPluginClass()
@@ -86,7 +86,7 @@ public class AccessControl extends AbstractPlugin
{
return authorise(Operation.ACCESS, objectType, ObjectProperties.EMPTY);
}
-
+
/**
* Check if an operation is authorised by asking the configuration object about the access
* control rules granted to the current thread's {@link Subject}. If there is no current
@@ -100,7 +100,7 @@ public class AccessControl extends AbstractPlugin
{
return Result.ABSTAIN;
}
-
+
_logger.debug("Checking " + operation + " " + objectType);
return _ruleSet.check(subject, operation, objectType, properties);
}
diff --git a/qpid/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/AccessControlConfiguration.java b/qpid/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/AccessControlConfiguration.java
index c4db6db820..63f7e254ae 100644
--- a/qpid/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/AccessControlConfiguration.java
+++ b/qpid/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/AccessControlConfiguration.java
@@ -34,7 +34,7 @@ import org.apache.qpid.server.security.access.config.RuleSet;
public class AccessControlConfiguration extends ConfigurationPlugin
{
- public static final ConfigurationPluginFactory FACTORY = new ConfigurationPluginFactory()
+ public static final ConfigurationPluginFactory FACTORY = new ConfigurationPluginFactory()
{
public ConfigurationPlugin newInstance(String path, Configuration config) throws ConfigurationException
{
@@ -70,7 +70,7 @@ public class AccessControlConfiguration extends ConfigurationPlugin
}
File aclFile = new File(filename);
-
+
ConfigurationFile configFile = new PlainConfiguration(aclFile);
_ruleSet = configFile.load();
}
diff --git a/qpid/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/AccessControlTest.java b/qpid/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/AccessControlTest.java
index 5db02d10ce..2385bcc3dd 100644
--- a/qpid/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/AccessControlTest.java
+++ b/qpid/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/AccessControlTest.java
@@ -20,8 +20,6 @@
*/
package org.apache.qpid.server.security.access.plugins;
-import java.util.Arrays;
-
import junit.framework.TestCase;
import org.apache.commons.configuration.ConfigurationException;
@@ -37,19 +35,22 @@ 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.sasl.TestPrincipalUtils;
+import org.apache.qpid.server.security.auth.TestPrincipalUtils;
/**
- * Unit test for ACL V2 plugin.
- *
+ * Unit test for ACL V2 plugin.
+ *
* This unit test tests the AccessControl class and it collaboration with {@link RuleSet},
* {@link SecurityManager} and {@link CurrentActor}. The ruleset is configured programmatically,
* rather than from an external file.
- *
+ *
* @see RuleSetTest
*/
public class AccessControlTest extends TestCase
{
+ private static final String ALLOWED_GROUP = "allowed_group";
+ private static final String DENIED_GROUP = "denied_group";
+
private AccessControl _plugin = null; // Class under test
private final UnitTestMessageLogger messageLogger = new UnitTestMessageLogger();
@@ -68,14 +69,12 @@ public class AccessControlTest extends TestCase
private RuleSet createGroupRuleSet()
{
final RuleSet rs = new RuleSet();
- rs.addGroup("aclGroup1", Arrays.asList(new String[] {"member1", "Member2"}));
// Rule expressed with username
rs.grant(0, "user1", Permission.ALLOW, Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY);
- // Rule expressed with a acl group
- rs.grant(1, "aclGroup1", Permission.ALLOW, Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY);
- // Rule expressed with an external group
- rs.grant(2, "extGroup1", Permission.DENY, Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY);
+ // Rules expressed with groups
+ rs.grant(1, ALLOWED_GROUP, Permission.ALLOW, Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY);
+ rs.grant(2, DENIED_GROUP, Permission.DENY, Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY);
// Catch all rule
rs.grant(3, Rule.ALL, Permission.DENY_LOG, Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY);
@@ -117,31 +116,23 @@ public class AccessControlTest extends TestCase
* Tests that an allow rule expressed with an <b>ACL groupname</b> allows an operation performed by a thread running
* by a user who belongs to the same group..
*/
- public void testAclGroupMembershipAllowsOperation() throws ConfigurationException
+ public void testGroupMembershipAllowsOperation() throws ConfigurationException
{
setUpGroupAccessControl();
- SecurityManager.setThreadSubject(TestPrincipalUtils.createTestSubject("member1"));
- Result result = _plugin.authorise(Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY);
- assertEquals(Result.ALLOWED, result);
-
- SecurityManager.setThreadSubject(TestPrincipalUtils.createTestSubject("Member2"));
-
- result = _plugin.authorise(Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY);
- assertEquals(Result.ALLOWED, result);
+ authoriseAndAssertResult(Result.ALLOWED, "member of allowed group", ALLOWED_GROUP);
+ authoriseAndAssertResult(Result.DENIED, "member of denied group", DENIED_GROUP);
+ authoriseAndAssertResult(Result.ALLOWED, "another member of allowed group", ALLOWED_GROUP);
}
/**
- * Tests that a deny rule expressed with an <b>External groupname</b> denies an operation performed by a thread running
+ * Tests that a deny rule expressed with a <b>groupname</b> denies an operation performed by a thread running
* by a user who belongs to the same group.
*/
- public void testExternalGroupMembershipDeniesOperation() throws ConfigurationException
+ public void testGroupMembershipDeniesOperation() throws ConfigurationException
{
setUpGroupAccessControl();
- SecurityManager.setThreadSubject(TestPrincipalUtils.createTestSubject("user3", "extGroup1"));
-
- final Result result = _plugin.authorise(Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY);
- assertEquals(Result.DENIED, result);
+ authoriseAndAssertResult(Result.DENIED, "user3", DENIED_GROUP);
}
/**
@@ -325,6 +316,14 @@ public class AccessControlTest extends TestCase
assertEquals(Result.DEFER, result);
}
+ private void authoriseAndAssertResult(Result expectedResult, String userName, String... groups)
+ {
+ SecurityManager.setThreadSubject(TestPrincipalUtils.createTestSubject(userName, groups));
+
+ Result result = _plugin.authorise(Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY);
+ assertEquals(expectedResult, result);
+ }
+
/**
* Creates a configuration plugin for the {@link AccessControl} plugin.
*/
diff --git a/qpid/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/PlainConfigurationTest.java b/qpid/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/PlainConfigurationTest.java
index c2282694fb..be4962615c 100644
--- a/qpid/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/PlainConfigurationTest.java
+++ b/qpid/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/PlainConfigurationTest.java
@@ -108,19 +108,6 @@ public class PlainConfigurationTest extends TestCase
}
}
- public void testACLFileSyntaxNotEnoughGroup() throws Exception
- {
- try
- {
- writeACLConfig("GROUP blah");
- fail("fail");
- }
- catch (ConfigurationException ce)
- {
- assertEquals(String.format(PlainConfiguration.NOT_ENOUGH_GROUP_MSG, 1), ce.getMessage());
- }
- }
-
public void testACLFileSyntaxNotEnoughACL() throws Exception
{
try
@@ -391,4 +378,77 @@ public class PlainConfigurationTest extends TestCase
assertEquals("Rule has unexpected object properties", ObjectProperties.EMPTY, rule.getAction().getProperties());
}
+ public void testUserRuleParsing() throws Exception
+ {
+ validateRule(writeACLConfig("ACL ALLOW user1 CREATE USER"),
+ "user1", Operation.CREATE, ObjectType.USER, ObjectProperties.EMPTY);
+ validateRule(writeACLConfig("ACL ALLOW user1 CREATE USER name=\"otherUser\""),
+ "user1", Operation.CREATE, ObjectType.USER, new ObjectProperties("otherUser"));
+
+ validateRule(writeACLConfig("ACL ALLOW user1 DELETE USER"),
+ "user1", Operation.DELETE, ObjectType.USER, ObjectProperties.EMPTY);
+ validateRule(writeACLConfig("ACL ALLOW user1 DELETE USER name=\"otherUser\""),
+ "user1", Operation.DELETE, ObjectType.USER, new ObjectProperties("otherUser"));
+
+ validateRule(writeACLConfig("ACL ALLOW user1 UPDATE USER"),
+ "user1", Operation.UPDATE, ObjectType.USER, ObjectProperties.EMPTY);
+ validateRule(writeACLConfig("ACL ALLOW user1 UPDATE USER name=\"otherUser\""),
+ "user1", Operation.UPDATE, ObjectType.USER, new ObjectProperties("otherUser"));
+
+ validateRule(writeACLConfig("ACL ALLOW user1 ALL USER"),
+ "user1", Operation.ALL, ObjectType.USER, ObjectProperties.EMPTY);
+ validateRule(writeACLConfig("ACL ALLOW user1 ALL USER name=\"otherUser\""),
+ "user1", Operation.ALL, ObjectType.USER, new ObjectProperties("otherUser"));
+ }
+
+ public void testGroupRuleParsing() throws Exception
+ {
+ validateRule(writeACLConfig("ACL ALLOW user1 CREATE GROUP"),
+ "user1", Operation.CREATE, ObjectType.GROUP, ObjectProperties.EMPTY);
+ validateRule(writeACLConfig("ACL ALLOW user1 CREATE GROUP name=\"groupName\""),
+ "user1", Operation.CREATE, ObjectType.GROUP, new ObjectProperties("groupName"));
+
+ validateRule(writeACLConfig("ACL ALLOW user1 DELETE GROUP"),
+ "user1", Operation.DELETE, ObjectType.GROUP, ObjectProperties.EMPTY);
+ validateRule(writeACLConfig("ACL ALLOW user1 DELETE GROUP name=\"groupName\""),
+ "user1", Operation.DELETE, ObjectType.GROUP, new ObjectProperties("groupName"));
+
+ validateRule(writeACLConfig("ACL ALLOW user1 UPDATE GROUP"),
+ "user1", Operation.UPDATE, ObjectType.GROUP, ObjectProperties.EMPTY);
+ validateRule(writeACLConfig("ACL ALLOW user1 UPDATE GROUP name=\"groupName\""),
+ "user1", Operation.UPDATE, ObjectType.GROUP, new ObjectProperties("groupName"));
+
+ validateRule(writeACLConfig("ACL ALLOW user1 ALL GROUP"),
+ "user1", Operation.ALL, ObjectType.GROUP, ObjectProperties.EMPTY);
+ validateRule(writeACLConfig("ACL ALLOW user1 ALL GROUP name=\"groupName\""),
+ "user1", Operation.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(ConfigurationException e)
+ {
+ assertTrue(e.getMessage().contains("GROUP keyword not supported"));
+ }
+ }
+
+ private void validateRule(final PlainConfiguration config, String username, Operation operation, ObjectType objectType, ObjectProperties objectProperties)
+ {
+ final RuleSet rs = config.getConfiguration();
+ assertEquals(1, rs.getRuleCount());
+
+ final Map<Integer, 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());
+ }
}
diff --git a/qpid/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/RuleSetTest.java b/qpid/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/RuleSetTest.java
index f7cc60543d..181d693614 100644
--- a/qpid/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/RuleSetTest.java
+++ b/qpid/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/RuleSetTest.java
@@ -22,7 +22,6 @@
package org.apache.qpid.server.security.access.plugins;
import java.security.Principal;
-import java.util.Arrays;
import javax.security.auth.Subject;
@@ -34,8 +33,7 @@ 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.sasl.TestPrincipalUtils;
-import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal;
+import org.apache.qpid.server.security.auth.TestPrincipalUtils;
import org.apache.qpid.test.utils.QpidTestCase;
/**
@@ -46,10 +44,7 @@ import org.apache.qpid.test.utils.QpidTestCase;
* 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, ACL groups (that is those
- * groups declared directly in the ACL itself), and External groups (that is a group from an External
- * Authentication Provider, such as an LDAP).
-
+ * It ensure that permissions can be granted correctly on users directly and on groups.
*/
public class RuleSetTest extends QpidTestCase
{
@@ -316,63 +311,36 @@ public class RuleSetTest extends QpidTestCase
assertEquals(Result.ALLOWED, _ruleSet.check(TestPrincipalUtils.createTestSubject("userb"),Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY));
}
- /**
- * Tests support for ACL groups (i.e. inline groups declared in the ACL file itself).
- */
- public void testAclGroupsSupported()
+ public void testGroupsSupported()
{
- assertTrue(_ruleSet.addGroup("aclgroup", Arrays.asList(new String[] {"usera", "userb"})));
-
- _ruleSet.grant(1, "aclgroup", 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));
- assertEquals(Result.DEFER, _ruleSet.check(TestPrincipalUtils.createTestSubject("userc"),Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY));
- }
-
- /**
- * Tests support for nested ACL groups.
- */
- public void testNestedAclGroupsSupported()
- {
- assertTrue(_ruleSet.addGroup("aclgroup1", Arrays.asList(new String[] {"userb"})));
- assertTrue(_ruleSet.addGroup("aclgroup2", Arrays.asList(new String[] {"usera", "aclgroup1"})));
-
- _ruleSet.grant(1, "aclgroup2", Permission.ALLOW, Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY);
- assertEquals(1, _ruleSet.getRuleCount());
+ String allowGroup = "allowGroup";
+ String deniedGroup = "deniedGroup";
- 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));
- }
+ _ruleSet.grant(1, allowGroup, Permission.ALLOW, Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY);
+ _ruleSet.grant(2, deniedGroup, Permission.DENY, Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY);
- /**
- * Tests support for nested External groups (i.e. those groups coming from an external source such as an LDAP).
- */
- public void testExternalGroupsSupported()
- {
- _ruleSet.grant(1, "extgroup1", Permission.ALLOW, Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY);
- _ruleSet.grant(2, "extgroup2", Permission.DENY, Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY);
assertEquals(2, _ruleSet.getRuleCount());
- assertEquals(Result.ALLOWED, _ruleSet.check(TestPrincipalUtils.createTestSubject("usera", "extgroup1"),Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY));
- assertEquals(Result.DENIED, _ruleSet.check(TestPrincipalUtils.createTestSubject("userb", "extgroup2"),Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY));
+ 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 although late a group
+ * 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()
{
- assertTrue(_ruleSet.addGroup("aclgroup", Arrays.asList(new String[] {"usera"})));
+ String group = "group";
+ String user = "user";
- _ruleSet.grant(1, "usera", Permission.ALLOW, Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY);
- _ruleSet.grant(2, "aclgroup", Permission.DENY, Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY);
+ _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("usera"),Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY));
+ assertEquals(Result.ALLOWED, _ruleSet.check(TestPrincipalUtils.createTestSubject(user, group),Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY));
}
/**
@@ -381,13 +349,33 @@ public class RuleSetTest extends QpidTestCase
*/
public void testDenyDeterminedByRuleOrder()
{
- assertTrue(_ruleSet.addGroup("aclgroup", Arrays.asList(new String[] {"usera"})));
+ String group = "aclgroup";
+ String user = "usera";
- _ruleSet.grant(1, "aclgroup", Permission.DENY, Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY);
- _ruleSet.grant(2, "usera", Permission.ALLOW, Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY);
+ _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("usera"),Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY));
+ 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));
}
}
diff --git a/qpid/java/broker-plugins/management-http/MANIFEST.MF b/qpid/java/broker-plugins/management-http/MANIFEST.MF
index cca10d3f89..525801f65f 100644
--- a/qpid/java/broker-plugins/management-http/MANIFEST.MF
+++ b/qpid/java/broker-plugins/management-http/MANIFEST.MF
@@ -20,6 +20,7 @@ Import-Package: org.apache.qpid,
org.apache.qpid.server.binding,
org.apache.qpid.server.exchange,
org.apache.qpid.server.logging,
+ org.apache.qpid.server.logging.actors,
org.apache.qpid.server.message,
org.apache.qpid.server.model,
org.apache.qpid.server.model.adapter,
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/Management.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/Management.java
index c2f9b73b54..38a8722852 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/Management.java
+++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/Management.java
@@ -44,6 +44,9 @@ import org.apache.qpid.server.model.Broker;
import org.apache.qpid.server.model.ConfiguredObject;
import org.apache.qpid.server.model.Connection;
import org.apache.qpid.server.model.Exchange;
+import org.apache.qpid.server.model.Group;
+import org.apache.qpid.server.model.GroupMember;
+import org.apache.qpid.server.model.GroupProvider;
import org.apache.qpid.server.model.Port;
import org.apache.qpid.server.model.Protocol;
import org.apache.qpid.server.model.Queue;
@@ -158,6 +161,9 @@ public class Management
addRestServlet(root, "virtualhost", VirtualHost.class);
addRestServlet(root, "authenticationprovider", AuthenticationProvider.class);
addRestServlet(root, "user", AuthenticationProvider.class, User.class);
+ addRestServlet(root, "groupprovider", GroupProvider.class);
+ addRestServlet(root, "group", GroupProvider.class, Group.class);
+ addRestServlet(root, "groupmember", GroupProvider.class, Group.class, GroupMember.class);
addRestServlet(root, "exchange", VirtualHost.class, Exchange.class);
addRestServlet(root, "queue", VirtualHost.class, Queue.class);
addRestServlet(root, "connection", VirtualHost.class, Connection.class);
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/AbstractServlet.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/AbstractServlet.java
index a76bd98179..1469808565 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/AbstractServlet.java
+++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/AbstractServlet.java
@@ -24,8 +24,10 @@ package org.apache.qpid.server.management.plugin.servlet.rest;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
-import java.security.Principal;
-import java.util.Collections;
+import java.security.AccessControlException;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+
import javax.security.auth.Subject;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
@@ -33,168 +35,293 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.commons.codec.binary.Base64;
+import org.apache.log4j.Logger;
+import org.apache.qpid.server.logging.LogActor;
+import org.apache.qpid.server.logging.RootMessageLogger;
+import org.apache.qpid.server.logging.actors.CurrentActor;
+import org.apache.qpid.server.logging.actors.HttpManagementActor;
import org.apache.qpid.server.model.Broker;
import org.apache.qpid.server.registry.ApplicationRegistry;
-import org.apache.qpid.server.security.auth.AuthenticationResult;
+import org.apache.qpid.server.security.SubjectCreator;
+import org.apache.qpid.server.security.auth.AuthenticationResult.AuthenticationStatus;
+import org.apache.qpid.server.security.auth.SubjectAuthenticationResult;
import org.apache.qpid.server.security.auth.manager.AnonymousAuthenticationManager;
-import org.apache.qpid.server.security.auth.manager.AuthenticationManager;
public abstract class AbstractServlet extends HttpServlet
{
+ private static final Logger LOGGER = Logger.getLogger(AbstractServlet.class);
+
+ protected static final String ATTR_SUBJECT = "subject";
+ private static final String ATTR_LOG_ACTOR = "AbstractServlet.logActor";
+
private final Broker _broker;
+ private RootMessageLogger _rootLogger;
+
protected AbstractServlet()
{
super();
_broker = ApplicationRegistry.getInstance().getBroker();
+ _rootLogger = ApplicationRegistry.getInstance().getRootMessageLogger();
}
protected AbstractServlet(Broker broker)
{
_broker = broker;
+ _rootLogger = ApplicationRegistry.getInstance().getRootMessageLogger();
}
@Override
- protected final void doGet(HttpServletRequest request, HttpServletResponse resp) throws ServletException, IOException
+ protected final void doGet(final HttpServletRequest request, final HttpServletResponse resp)
{
- setAuthorizedSubject(request);
- try
- {
- onGet(request, resp);
- }
- finally
- {
- clearAuthorizedSubject();
- }
+ doWithSubjectAndActor(
+ new PrivilegedExceptionAction<Void>()
+ {
+ @Override
+ public Void run() throws Exception
+ {
+ doGetWithSubjectAndActor(request, resp);
+ return null;
+ }
+ },
+ request,
+ resp
+ );
}
- protected void onGet(HttpServletRequest request, HttpServletResponse resp) throws IOException, ServletException
+ /**
+ * Performs the GET action as the logged-in {@link Subject}.
+ * The {@link LogActor} is set before this method is called.
+ * Subclasses commonly override this method
+ */
+ protected void doGetWithSubjectAndActor(HttpServletRequest request, HttpServletResponse resp) throws ServletException, IOException
{
- super.doGet(request, resp);
+ throw new UnsupportedOperationException("GET not supported by this servlet");
}
- private void clearAuthorizedSubject()
+
+ @Override
+ protected final void doPost(final HttpServletRequest request, final HttpServletResponse resp)
{
- org.apache.qpid.server.security.SecurityManager.setThreadSubject(null);
+ doWithSubjectAndActor(
+ new PrivilegedExceptionAction<Void>()
+ {
+ @Override
+ public Void run() throws Exception
+ {
+ doPostWithSubjectAndActor(request, resp);
+ return null;
+ }
+ },
+ request,
+ resp
+ );
}
-
- private void setAuthorizedSubject(HttpServletRequest request)
+ /**
+ * Performs the POST action as the logged-in {@link Subject}.
+ * The {@link LogActor} is set before this method is called.
+ * Subclasses commonly override this method
+ */
+ protected void doPostWithSubjectAndActor(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
{
- HttpSession session = request.getSession(true);
- Subject subject = (Subject) session.getAttribute("subject");
+ throw new UnsupportedOperationException("POST not supported by this servlet");
+ }
- if(subject == null)
- {
- Principal principal = request.getUserPrincipal();
- if(principal != null)
- {
- subject = new Subject(false, Collections.singleton(principal),Collections.emptySet(),
- Collections.emptySet());
- }
- else
+ @Override
+ protected final void doPut(final HttpServletRequest request, final HttpServletResponse resp)
+ {
+ doWithSubjectAndActor(
+ new PrivilegedExceptionAction<Void>()
{
- String header = request.getHeader("Authorization");
+ @Override
+ public Void run() throws Exception
+ {
+ doPutWithSubjectAndActor(request, resp);
+ return null;
+ }
+ },
+ request,
+ resp
+ );
+ }
- /*
- * TODO - Should configure whether basic authentication is allowed... and in particular whether it
- * should be allowed over non-ssl connections
- * */
+ /**
+ * Performs the PUT action as the logged-in {@link Subject}.
+ * The {@link LogActor} is set before this method is called.
+ * Subclasses commonly override this method
+ */
+ protected void doPutWithSubjectAndActor(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
+ {
+ throw new UnsupportedOperationException("PUT not supported by this servlet");
+ }
- if (header != null)
+ @Override
+ protected final void doDelete(final HttpServletRequest request, final HttpServletResponse resp)
+ throws ServletException, IOException
+ {
+ doWithSubjectAndActor(
+ new PrivilegedExceptionAction<Void>()
+ {
+ @Override
+ public Void run() throws Exception
{
- String[] tokens = header.split("\\s");
- if(tokens.length >= 2
- && "BASIC".equalsIgnoreCase(tokens[0]))
- {
- String[] credentials = (new String(Base64.decodeBase64(tokens[1].getBytes()))).split(":",2);
- if(credentials.length == 2)
- {
- SocketAddress address = getSocketAddress(request);
- AuthenticationManager authenticationManager =
- ApplicationRegistry.getInstance().getAuthenticationManager(address);
- AuthenticationResult authResult =
- authenticationManager.authenticate(credentials[0], credentials[1]);
- subject = authResult.getSubject();
-
- }
- }
+ doDeleteWithSubjectAndActor(request, resp);
+ return null;
}
- }
- }
- if (subject == null)
- {
- subject = AnonymousAuthenticationManager.ANONYMOUS_SUBJECT;
- }
- org.apache.qpid.server.security.SecurityManager.setThreadSubject(subject);
-
+ },
+ request,
+ resp
+ );
}
- protected Subject getSubject(HttpSession session)
+ /**
+ * Performs the PUT action as the logged-in {@link Subject}.
+ * The {@link LogActor} is set before this method is called.
+ * Subclasses commonly override this method
+ */
+ protected void doDeleteWithSubjectAndActor(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
{
- return (Subject)session.getAttribute("subject");
+ throw new UnsupportedOperationException("DELETE not supported by this servlet");
}
- @Override
- protected final void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
+ private void doWithSubjectAndActor(
+ PrivilegedExceptionAction<Void> privilegedExceptionAction,
+ final HttpServletRequest request,
+ final HttpServletResponse resp)
{
- setAuthorizedSubject(req);
+ Subject subject = getAndCacheAuthorizedSubject(request);
+ org.apache.qpid.server.security.SecurityManager.setThreadSubject(subject);
+
try
{
- onPost(req, resp);
+ HttpManagementActor logActor = getLogActorAndCacheInSession(request);
+ CurrentActor.set(logActor);
+ try
+ {
+ Subject.doAs(subject, privilegedExceptionAction);
+ }
+ catch(RuntimeException e)
+ {
+ LOGGER.error("Unable to perform action", e);
+ throw e;
+ }
+ catch (PrivilegedActionException e)
+ {
+ LOGGER.error("Unable to perform action", e);
+ throw new RuntimeException(e.getCause());
+ }
+ finally
+ {
+ CurrentActor.remove();
+ }
}
finally
{
- clearAuthorizedSubject();
+ org.apache.qpid.server.security.SecurityManager.setThreadSubject(null);
}
-
}
- protected void onPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
+ /**
+ * Gets the logged-in {@link Subject} by trying the following:
+ *
+ * <ul>
+ * <li>Get it from the session</li>
+ * <li>Get it from the request</li>
+ * <li>Log in using the username and password in the Authorization HTTP header</li>
+ * <li>Create a Subject representing the anonymous user.</li>
+ * </ul>
+ *
+ * If an authenticated subject is found it is cached in the http session.
+ */
+ private Subject getAndCacheAuthorizedSubject(HttpServletRequest request)
{
- super.doPost(req, resp);
- }
+ HttpSession session = request.getSession();
+ Subject subject = getSubjectFromSession(session);
- @Override
- protected final void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
- {
- setAuthorizedSubject(req);
- try
+ if(subject != null)
{
- onPut(req, resp);
+ return subject;
+ }
+ SubjectCreator subjectCreator = ApplicationRegistry.getInstance().getSubjectCreator(getSocketAddress(request));
+
+ String remoteUser = request.getRemoteUser();
+ if(remoteUser != null)
+ {
+ subject = subjectCreator.createSubjectWithGroups(remoteUser);
}
- finally
+ else
{
- clearAuthorizedSubject();
+ String header = request.getHeader("Authorization");
+
+ /*
+ * TODO - Should configure whether basic authentication is allowed... and in particular whether it
+ * should be allowed over non-ssl connections
+ * */
+
+ if (header != null)
+ {
+ String[] tokens = header.split("\\s");
+ if(tokens.length >= 2
+ && "BASIC".equalsIgnoreCase(tokens[0]))
+ {
+ String[] credentials = (new String(Base64.decodeBase64(tokens[1].getBytes()))).split(":",2);
+ if(credentials.length == 2)
+ {
+ SubjectAuthenticationResult authResult = subjectCreator.authenticate(credentials[0], credentials[1]);
+ if( authResult.getStatus() != AuthenticationStatus.SUCCESS)
+ {
+ //TODO: write a return response indicating failure?
+ throw new AccessControlException("Incorrect username or password");
+ }
+ subject = authResult.getSubject();
+ }
+ else
+ {
+ //TODO: write a return response indicating failure?
+ throw new AccessControlException("Invalid number of credentials supplied: "
+ + credentials.length);
+ }
+ }
+ }
}
- }
- protected void onPut(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException
- {
- super.doPut(req,resp);
+ if (subject != null)
+ {
+ setSubjectInSession(subject, session);
+ }
+ else
+ {
+ subject = subjectCreator.createSubjectWithGroups(AnonymousAuthenticationManager.ANONYMOUS_USERNAME);
+ }
+
+ return subject;
}
- @Override
- protected final void doDelete(HttpServletRequest req, HttpServletResponse resp)
- throws ServletException, IOException
+ private HttpManagementActor getLogActorAndCacheInSession(HttpServletRequest req)
{
- setAuthorizedSubject(req);
- try
- {
- onDelete(req, resp);
- }
- finally
+ HttpSession session = req.getSession();
+
+ HttpManagementActor actor = (HttpManagementActor) session.getAttribute(ATTR_LOG_ACTOR);
+ if(actor == null)
{
- clearAuthorizedSubject();
+ actor = new HttpManagementActor(_rootLogger, req.getRemoteAddr(), req.getRemotePort());
+ session.setAttribute(ATTR_LOG_ACTOR, actor);
}
+
+ return actor;
}
- protected void onDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
+ protected Subject getSubjectFromSession(HttpSession session)
{
- super.doDelete(req, resp);
+ return (Subject)session.getAttribute(ATTR_SUBJECT);
}
+ protected void setSubjectInSession(Subject subject, final HttpSession session)
+ {
+ session.setAttribute(ATTR_SUBJECT, subject);
+ }
protected Broker getBroker()
{
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/LogRecordsServlet.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/LogRecordsServlet.java
index 404793b592..04eda2a787 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/LogRecordsServlet.java
+++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/LogRecordsServlet.java
@@ -44,7 +44,7 @@ public class LogRecordsServlet extends AbstractServlet
}
@Override
- protected void onGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
+ protected void doGetWithSubjectAndActor(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
response.setContentType("application/json");
response.setStatus(HttpServletResponse.SC_OK);
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageContentServlet.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageContentServlet.java
index bc87f0bcc5..ae794472bf 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageContentServlet.java
+++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageContentServlet.java
@@ -48,7 +48,7 @@ public class MessageContentServlet extends AbstractServlet
}
@Override
- protected void onGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
+ protected void doGetWithSubjectAndActor(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
if(request.getPathInfo() != null && request.getPathInfo().length()>0 && request.getPathInfo().substring(1).split("/").length > 2)
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageServlet.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageServlet.java
index 6e7bc1d935..3920443b07 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageServlet.java
+++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageServlet.java
@@ -62,7 +62,7 @@ public class MessageServlet extends AbstractServlet
}
@Override
- protected void onGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
+ protected void doGetWithSubjectAndActor(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
if(request.getPathInfo() != null && request.getPathInfo().length()>0 && request.getPathInfo().substring(1).split("/").length > 2)
@@ -400,7 +400,7 @@ public class MessageServlet extends AbstractServlet
* POST moves or copies messages to the given queue from a queue specified in the posted JSON data
*/
@Override
- protected void onPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+ protected void doPostWithSubjectAndActor(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
try
@@ -450,7 +450,7 @@ public class MessageServlet extends AbstractServlet
* DELETE removes messages from the queue
*/
@Override
- protected void onDelete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+ protected void doDeleteWithSubjectAndActor(HttpServletRequest request, HttpServletResponse response)
{
final Queue sourceQueue = getQueueFromRequest(request);
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/RestServlet.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/RestServlet.java
index 6a79916d07..f2ca25d664 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/RestServlet.java
+++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/RestServlet.java
@@ -31,7 +31,6 @@ import org.apache.qpid.server.model.*;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.SerializationConfig;
-
public class RestServlet extends AbstractServlet
{
private static final Logger LOGGER = Logger.getLogger(RestServlet.class);
@@ -285,7 +284,7 @@ public class RestServlet extends AbstractServlet
}
@Override
- protected void onGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+ protected void doGetWithSubjectAndActor(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
response.setContentType("application/json");
response.setStatus(HttpServletResponse.SC_OK);
@@ -319,7 +318,7 @@ public class RestServlet extends AbstractServlet
}
@Override
- protected void onPut(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+ protected void doPutWithSubjectAndActor(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
response.setContentType("application/json");
@@ -336,7 +335,8 @@ public class RestServlet extends AbstractServlet
if(names.size() != _hierarchy.length)
{
- throw new IllegalArgumentException("Path to object to create must be fully specified");
+ throw new IllegalArgumentException("Path to object to create must be fully specified. "
+ + "Found " + names.size() + " expecting " + _hierarchy.length);
}
}
@@ -428,8 +428,11 @@ public class RestServlet extends AbstractServlet
|| (obj.getName().equals(providedObject.get("name")) && equalParents(obj, otherParents)))
{
doUpdate(obj, providedObject);
+ response.setStatus(HttpServletResponse.SC_OK);
+ return;
}
}
+
theParent.createChild(objClass, providedObject, otherParents);
}
catch (RuntimeException e)
@@ -464,11 +467,12 @@ public class RestServlet extends AbstractServlet
{
if (e.getCause() instanceof AMQSecurityException)
{
+ LOGGER.debug("Caught AMQSecurityException", e);
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
}
else
{
- LOGGER.warn("Unexpected exception is caught", e);
+ LOGGER.warn("Caught exception", e);
// TODO
response.setStatus(HttpServletResponse.SC_CONFLICT);
@@ -476,7 +480,7 @@ public class RestServlet extends AbstractServlet
}
@Override
- protected void onDelete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
+ protected void doDeleteWithSubjectAndActor(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
response.setContentType("application/json");
response.setStatus(HttpServletResponse.SC_OK);
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/SaslServlet.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/SaslServlet.java
index 1b78611a50..b5929875ff 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/SaslServlet.java
+++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/SaslServlet.java
@@ -27,8 +27,8 @@ import org.codehaus.jackson.map.SerializationConfig;
import org.apache.log4j.Logger;
import org.apache.qpid.server.model.Broker;
import org.apache.qpid.server.registry.ApplicationRegistry;
-import org.apache.qpid.server.security.auth.manager.AuthenticationManager;
-import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal;
+import org.apache.qpid.server.security.SubjectCreator;
+import org.apache.qpid.server.security.auth.AuthenticatedPrincipal;
import javax.security.auth.Subject;
import javax.security.sasl.SaslException;
@@ -67,7 +67,7 @@ public class SaslServlet extends AbstractServlet
super(broker);
}
- protected void onGet(HttpServletRequest request, HttpServletResponse response) throws
+ protected void doGetWithSubjectAndActor(HttpServletRequest request, HttpServletResponse response) throws
ServletException,
IOException
{
@@ -79,15 +79,16 @@ public class SaslServlet extends AbstractServlet
response.setDateHeader ("Expires", 0);
HttpSession session = request.getSession();
- Random rand = getRandom(session);
+ getRandom(session);
- AuthenticationManager authManager = ApplicationRegistry.getInstance().getAuthenticationManager(getSocketAddress(request));
- String[] mechanisms = authManager.getMechanisms().split(" ");
+ SubjectCreator subjectCreator = ApplicationRegistry.getInstance().getSubjectCreator(getSocketAddress(request));
+ String[] mechanisms = subjectCreator.getMechanisms().split(" ");
Map<String, Object> outputObject = new LinkedHashMap<String, Object>();
- final Subject subject = (Subject) session.getAttribute("subject");
+
+ final Subject subject = getSubjectFromSession(session);
if(subject != null)
{
- final Principal principal = subject.getPrincipals().iterator().next();
+ Principal principal = AuthenticatedPrincipal.getAuthenticatedPrincipalFromSubject(subject);
outputObject.put("user", principal.getName());
}
else if (request.getRemoteUser() != null)
@@ -121,8 +122,7 @@ public class SaslServlet extends AbstractServlet
@Override
- protected void onPost(final HttpServletRequest request, final HttpServletResponse response)
- throws ServletException, IOException
+ protected void doPostWithSubjectAndActor(final HttpServletRequest request, final HttpServletResponse response) throws IOException
{
try
{
@@ -137,14 +137,14 @@ public class SaslServlet extends AbstractServlet
String id = request.getParameter("id");
String saslResponse = request.getParameter("response");
- AuthenticationManager authManager = ApplicationRegistry.getInstance().getAuthenticationManager(getSocketAddress(request));
+ SubjectCreator subjectCreator = ApplicationRegistry.getInstance().getSubjectCreator(getSocketAddress(request));
if(mechanism != null)
{
if(id == null)
{
- SaslServer saslServer = authManager.createSaslServer(mechanism, request.getServerName(), null/*TODO*/);
- evaluateSaslResponse(response, session, saslResponse, saslServer);
+ SaslServer saslServer = subjectCreator.createSaslServer(mechanism, request.getServerName(), null/*TODO*/);
+ evaluateSaslResponse(response, session, saslResponse, saslServer, subjectCreator);
}
else
{
@@ -152,9 +152,7 @@ public class SaslServlet extends AbstractServlet
session.removeAttribute(ATTR_ID);
session.removeAttribute(ATTR_SASL_SERVER);
session.removeAttribute(ATTR_EXPIRY);
-
}
-
}
else
{
@@ -163,8 +161,7 @@ public class SaslServlet extends AbstractServlet
if(id.equals(session.getAttribute(ATTR_ID)) && System.currentTimeMillis() < (Long) session.getAttribute(ATTR_EXPIRY))
{
SaslServer saslServer = (SaslServer) session.getAttribute(ATTR_SASL_SERVER);
- evaluateSaslResponse(response, session, saslResponse, saslServer);
-
+ evaluateSaslResponse(response, session, saslResponse, saslServer, subjectCreator);
}
else
{
@@ -180,7 +177,6 @@ public class SaslServlet extends AbstractServlet
session.removeAttribute(ATTR_ID);
session.removeAttribute(ATTR_SASL_SERVER);
session.removeAttribute(ATTR_EXPIRY);
-
}
}
}
@@ -199,7 +195,7 @@ public class SaslServlet extends AbstractServlet
private void evaluateSaslResponse(final HttpServletResponse response,
final HttpSession session,
- final String saslResponse, final SaslServer saslServer) throws IOException
+ final String saslResponse, final SaslServer saslServer, SubjectCreator subjectCreator) throws IOException
{
final String id;
byte[] challenge;
@@ -209,7 +205,6 @@ public class SaslServlet extends AbstractServlet
}
catch(SaslException e)
{
-
session.removeAttribute(ATTR_ID);
session.removeAttribute(ATTR_SASL_SERVER);
session.removeAttribute(ATTR_EXPIRY);
@@ -220,16 +215,14 @@ public class SaslServlet extends AbstractServlet
if(saslServer.isComplete())
{
- final Subject subject = new Subject();
- subject.getPrincipals().add(new UsernamePrincipal(saslServer.getAuthorizationID()));
- session.setAttribute("subject", subject);
+ Subject subject = subjectCreator.createSubjectWithGroups(saslServer.getAuthorizationID());
+
+ setSubjectInSession(subject, session);
session.removeAttribute(ATTR_ID);
session.removeAttribute(ATTR_SASL_SERVER);
session.removeAttribute(ATTR_EXPIRY);
response.setStatus(HttpServletResponse.SC_OK);
-
-
}
else
{
@@ -250,7 +243,6 @@ public class SaslServlet extends AbstractServlet
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, true);
mapper.writeValue(writer, outputObject);
-
}
}
}
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/StructureServlet.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/StructureServlet.java
index 60f977ca66..5f553beb26 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/StructureServlet.java
+++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/StructureServlet.java
@@ -47,7 +47,7 @@ public class StructureServlet extends AbstractServlet
}
@Override
- protected void onGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
+ protected void doGetWithSubjectAndActor(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
response.setContentType("application/json");
response.setStatus(HttpServletResponse.SC_OK);
@@ -56,6 +56,8 @@ public class StructureServlet extends AbstractServlet
response.setHeader("Pragma","no-cache");
response.setDateHeader ("Expires", 0);
+ // TODO filtering??? request.getParameter("filter"); // filter=1,2,3 /groups/*/*
+
Map<String,Object> structure = generateStructure(getBroker(), Broker.class);
final PrintWriter writer = response.getWriter();
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/authenticationprovider/showPrincipalDatabaseAuthenticationManager.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/authenticationprovider/showPrincipalDatabaseAuthenticationManager.html
index baadc8c35f..e6c067fddf 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/resources/authenticationprovider/showPrincipalDatabaseAuthenticationManager.html
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/authenticationprovider/showPrincipalDatabaseAuthenticationManager.html
@@ -23,7 +23,5 @@
<div class="users"></div>
<button data-dojo-type="dijit.form.Button" class="addUserButton">Add User</button>
<button data-dojo-type="dijit.form.Button" class="deleteUserButton">Delete Users</button>
-
</div>
-
</div>
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/group/addGroupMember.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/group/addGroupMember.html
new file mode 100644
index 0000000000..0372468f91
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/group/addGroupMember.html
@@ -0,0 +1,37 @@
+<!--
+ -
+ - 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.
+ -
+ -->
+<div class="dijitHidden">
+ <div data-dojo-type="dijit.Dialog" style="width:600px;" data-dojo-props="title:'Add Group Member'" id="addGroupMember">
+ <form id="formAddGroupMember" method="post" dojoType="dijit.form.Form">
+ <table cellpadding="0" cellspacing="2">
+ <tr>
+ <td valign="top"><strong>Name*: </strong></td>
+ <td><input type="text" required="true" name="name" id="formAddGroupMember.name" placeholder="Name"
+ dojoType="dijit.form.ValidationTextBox" missingMessage="A name must be supplied" /></td>
+ </tr>
+ </table>
+ <br/>
+
+ <!-- submit buttons -->
+ <input type="submit" value="Add Group Member" label="Add Group Member" dojoType="dijit.form.Button" />
+ </form>
+ </div>
+</div>
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/group/showGroup.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/group/showGroup.html
new file mode 100644
index 0000000000..4fddf727d0
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/group/showGroup.html
@@ -0,0 +1,30 @@
+<!--
+ -
+ - 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.
+ -
+ -->
+<div class="group">
+ <span style="">Name:</span><span class="name" style="position:absolute; left:6em"></span>
+ <br/>
+ <div data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Group Members'">
+ <div class="groupMembers"></div>
+ <button data-dojo-type="dijit.form.Button" class="addGroupMemberButton" type="button">Add Group Member</button>
+ <button data-dojo-type="dijit.form.Button" class="removeGroupMemberButton" type="button">Remove Group Members</button>
+ </div>
+</div>
+
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/groupprovider/addGroup.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/groupprovider/addGroup.html
new file mode 100644
index 0000000000..8d3431808a
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/groupprovider/addGroup.html
@@ -0,0 +1,38 @@
+<!--
+ -
+ - 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.
+ -
+ -->
+<div class="dijitHidden">
+ <div data-dojo-type="dijit.Dialog" style="width:600px;" data-dojo-props="title:'Add Group'" id="addGroup">
+ <form id="formAddGroup" method="post" dojoType="dijit.form.Form">
+ <table cellpadding="0" cellspacing="2">
+ <tr>
+ <td valign="top"><strong>Group Name*: </strong></td>
+ <td><input type="text" required="true" name="name" id="formAddGroup.name" placeholder="Group Name"
+ dojoType="dijit.form.ValidationTextBox" missingMessage="A name must be supplied" /></td>
+ </tr>
+ </table>
+ <br/>
+
+ <!-- submit buttons -->
+ <input type="submit" value="Create Group" label="Create Group" dojoType="dijit.form.Button" />
+
+ </form>
+ </div>
+</div>
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/groupprovider/showFileGroupManager.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/groupprovider/showFileGroupManager.html
new file mode 100644
index 0000000000..734e8b5419
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/groupprovider/showFileGroupManager.html
@@ -0,0 +1,28 @@
+<!--
+ -
+ - 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.
+ -
+ -->
+<div class="FileGroupManager">
+ <div data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Groups'">
+ <div class="groups"></div>
+ <button data-dojo-type="dijit.form.Button" class="addGroupButton">Add Group</button>
+ <button data-dojo-type="dijit.form.Button" class="deleteGroupButton">Delete Groups</button>
+ </div>
+
+</div>
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/util.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/util.js
index 08fdf5c99b..5557c37a2c 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/util.js
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/util.js
@@ -58,10 +58,10 @@ define(["dojo/_base/xhr"],
return exchangeName == null || exchangeName == "" || "<<default>>" == exchangeName || exchangeName.indexOf("amq.") == 0 || exchangeName.indexOf("qpid.") == 0;
};
- util.deleteGridSelections = function(updater, gridName, url, confirmationMessageStart)
+ util.deleteGridSelections = function(updater, grid, url, confirmationMessageStart)
{
- var grid = updater[gridName].grid;
var data = grid.selection.getSelected();
+
if(data.length)
{
var confirmationMessage = null;
@@ -103,7 +103,8 @@ define(["dojo/_base/xhr"],
xhr.del({url: query, sync: true, handleAs: "json"}).then(
function(data)
{
- grid.setQuery({id: "*"});
+ // TODO why query *??
+ //grid.setQuery({id: "*"});
grid.selection.deselectAll();
updater.update();
},
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Exchange.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Exchange.js
index 37bae1ef8e..5a5a6515ef 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Exchange.js
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Exchange.js
@@ -115,7 +115,7 @@ define(["dojo/_base/xhr",
{
util.deleteGridSelections(
this.exchangeUpdater,
- "bindingsGrid",
+ that.exchangeUpdater.bindingsGrid.grid,
"rest/binding/"+ encodeURIComponent(this.getVirtualHostName()) + "/" + encodeURIComponent(this.name),
"Are you sure you want to delete binding for queue");
}
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/GroupProvider.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/GroupProvider.js
new file mode 100644
index 0000000000..4e05f4b0ea
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/GroupProvider.js
@@ -0,0 +1,109 @@
+/*
+ *
+ * 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.
+ *
+ */
+define(["dojo/_base/xhr",
+ "dojo/parser",
+ "dojo/query",
+ "dojo/_base/connect",
+ "qpid/common/properties",
+ "qpid/common/updater",
+ "qpid/common/util",
+ "qpid/common/UpdatableStore",
+ "dojox/grid/EnhancedGrid",
+ "dojox/grid/enhanced/plugins/Pagination",
+ "dojox/grid/enhanced/plugins/IndirectSelection",
+ "dojo/domReady!"],
+ function (xhr, parser, query, connect, properties, updater, util, UpdatableStore, EnhancedGrid) {
+
+ function GroupProvider(name, parent, controller) {
+ this.name = name;
+ this.controller = controller;
+ this.modelObj = { type: "groupprovider", name: name };
+ if(parent) {
+ this.modelObj.parent = {};
+ this.modelObj.parent[ parent.type] = parent;
+ }
+ }
+
+ GroupProvider.prototype.getTitle = function() {
+ return "GroupProvider";
+ };
+
+ GroupProvider.prototype.open = function(contentPane) {
+ var that = this;
+ this.contentPane = contentPane;
+ xhr.get({url: "showGroupProvider.html",
+ sync: true,
+ load: function(data) {
+ contentPane.containerNode.innerHTML = data;
+ parser.parse(contentPane.containerNode);
+
+ that.groupProviderAdapter = new GroupProviderUpdater(contentPane.containerNode, that.modelObj, that.controller);
+
+ updater.add( that.groupProviderAdapter );
+
+ that.groupProviderAdapter.update();
+
+ }});
+ };
+
+ GroupProvider.prototype.close = function() {
+ updater.remove( this.groupProviderAdapter );
+ };
+
+ function GroupProviderUpdater(node, groupProviderObj, controller)
+ {
+ this.controller = controller;
+ this.name = query(".name", node)[0];
+ this.query = "rest/groupprovider/"+encodeURIComponent(groupProviderObj.name);
+
+ var that = this;
+
+ xhr.get({url: this.query, sync: properties.useSyncGet, handleAs: "json"})
+ .then(function(data)
+ {
+ that.groupProviderData = data[0];
+
+ util.flattenStatistics( that.groupProviderData );
+
+ that.updateHeader();
+
+ require(["qpid/management/groupprovider/"+that.groupProviderData.type],
+ function(SpecificProvider) {
+ that.details = new SpecificProvider(node, groupProviderObj, controller);
+ that.details.update();
+ });
+
+ });
+
+ }
+
+ GroupProviderUpdater.prototype.updateHeader = function()
+ {
+ this.name.innerHTML = this.groupProviderData[ "name" ];
+ };
+
+ GroupProviderUpdater.prototype.update = function()
+ {
+ var that = this;
+ };
+
+ return GroupProvider;
+ });
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/VirtualHost.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/VirtualHost.js
index 957f2381cf..2efc46476d 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/VirtualHost.js
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/VirtualHost.js
@@ -72,7 +72,7 @@ define(["dojo/_base/xhr",
function(evt){
util.deleteGridSelections(
that.vhostUpdater,
- "queuesGrid",
+ that.vhostUpdater.queuesGrid.grid,
"rest/queue/"+ encodeURIComponent(that.name),
"Are you sure you want to delete queue");
}
@@ -87,7 +87,7 @@ define(["dojo/_base/xhr",
{
util.deleteGridSelections(
that.vhostUpdater,
- "exchangesGrid",
+ that.vhostUpdater.exchangesGrid.grid,
"rest/exchange/"+ encodeURIComponent(that.name),
"Are you sure you want to delete exchange");
}
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/controller.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/controller.js
index 1aa05a5a3c..5d3a666760 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/controller.js
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/controller.js
@@ -27,13 +27,17 @@ define(["dojo/dom",
"qpid/management/Queue",
"qpid/management/Connection",
"qpid/management/AuthenticationProvider",
+ "qpid/management/GroupProvider",
+ "qpid/management/group/Group",
"dojo/ready",
"dojo/domReady!"],
- function (dom, registry, ContentPane, Broker, VirtualHost, Exchange, Queue, Connection, AuthProvider, ready) {
+ function (dom, registry, ContentPane, Broker, VirtualHost, Exchange, Queue, Connection, AuthProvider, GroupProvider, Group, ready) {
var controller = {};
var constructors = { broker: Broker, virtualhost: VirtualHost, exchange: Exchange,
- queue: Queue, connection: Connection, authenticationprovider: AuthProvider };
+ queue: Queue, connection: Connection,
+ authenticationprovider: AuthProvider, groupprovider: GroupProvider,
+ group: Group };
var tabDiv = dom.byId("managedViews");
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/group/Group.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/group/Group.js
new file mode 100644
index 0000000000..801f35c7aa
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/group/Group.js
@@ -0,0 +1,215 @@
+/*
+ *
+ * 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.
+ *
+ */
+define(["dojo/_base/xhr",
+ "dojo/parser",
+ "dojo/query",
+ "dijit/registry",
+ "dojo/_base/connect",
+ "dojo/_base/event",
+ "dojo/json",
+ "qpid/common/properties",
+ "qpid/common/updater",
+ "qpid/common/util",
+ "qpid/common/formatter",
+ "qpid/common/UpdatableStore",
+ "dojo/store/JsonRest",
+ "dojox/grid/EnhancedGrid",
+ "dojo/data/ObjectStore",
+ "qpid/management/group/addGroupMember",
+ "dojox/grid/enhanced/plugins/Pagination",
+ "dojox/grid/enhanced/plugins/IndirectSelection",
+ "dojo/domReady!"],
+ function (xhr, parser, query, registry, connect, event, json, properties, updater, util, formatter,
+ UpdatableStore, JsonRest, EnhancedGrid, ObjectStore, addGroupMember) {
+
+ function Group(name, parent, controller) {
+ this.name = name;
+ this.controller = controller;
+ this.modelObj = { type: "group", name: name };
+
+ if(parent) {
+ this.modelObj.parent = {};
+ this.modelObj.parent[ parent.type] = parent;
+ }
+ }
+
+ Group.prototype.getGroupName = function()
+ {
+ return this.name;
+ };
+
+
+ Group.prototype.getGroupProviderName = function()
+ {
+ return this.modelObj.parent.groupprovider.name;
+ };
+
+ Group.prototype.getTitle = function()
+ {
+ return "Group: " + this.name;
+ };
+
+ Group.prototype.open = function(contentPane) {
+ var that = this;
+ this.contentPane = contentPane;
+
+ xhr.get({url: "group/showGroup.html",
+ sync: true,
+ load: function(data) {
+ contentPane.containerNode.innerHTML = data;
+ parser.parse(contentPane.containerNode);
+
+ that.groupUpdater = new GroupUpdater(contentPane.containerNode, that, that.controller);
+
+ updater.add( that.groupUpdater );
+
+ that.groupUpdater.update();
+
+ var addGroupMemberButton = query(".addGroupMemberButton", contentPane.containerNode)[0];
+ connect.connect(registry.byNode(addGroupMemberButton), "onClick",
+ function(evt){
+ addGroupMember.show(that.getGroupProviderName(), that.getGroupName())
+ }
+ );
+
+ var removeGroupMemberButton = query(".removeGroupMemberButton", contentPane.containerNode)[0];
+ connect.connect(registry.byNode(removeGroupMemberButton), "onClick",
+ function(evt){
+ util.deleteGridSelections(
+ that.groupUpdater,
+ that.groupUpdater.groupMembersUpdatableStore.grid,
+ "rest/groupmember/"+ encodeURIComponent(that.getGroupProviderName()) +
+ "/" + encodeURIComponent(that.getGroupName()),
+ "Are you sure you want to remove group member");
+ }
+ );
+ }});
+ };
+
+ Group.prototype.close = function() {
+ updater.remove( this.groupUpdater );
+ };
+
+ function GroupUpdater(containerNode, groupObj, controller)
+ {
+ var that = this;
+
+ function findNode(name) {
+ return query("." + name, containerNode)[0];
+ }
+
+ function storeNodes(names)
+ {
+ for(var i = 0; i < names.length; i++) {
+ that[names[i]] = findNode(names[i]);
+ }
+ }
+
+ storeNodes(["name",
+ "state",
+ "durable",
+ "lifetimePolicy",
+ "type"]);
+
+ this.query = "rest/groupmember/"+ encodeURIComponent(groupObj.getGroupProviderName()) + "/" + encodeURIComponent(groupObj.getGroupName());
+
+ xhr.get({url: this.query, sync: properties.useSyncGet, handleAs: "json"}).then(function(data)
+ {
+ that.groupMemberData = data;
+
+ util.flattenStatistics( that.groupMemberData );
+
+ var gridProperties = {
+ keepSelection: true,
+ plugins: {
+ pagination: {
+ pageSizes: ["10", "25", "50", "100"],
+ description: true,
+ sizeSwitch: true,
+ pageStepper: true,
+ gotoButton: true,
+ maxPageStep: 4,
+ position: "bottom"
+ },
+ indirectSelection: true
+
+ }};
+
+ that.groupMembersUpdatableStore = new UpdatableStore(that.groupMemberData, findNode("groupMembers"),
+ [ { name: "Group Member Name", field: "name", width: "100%" }],
+ function(obj)
+ {
+ connect.connect(obj.grid, "onRowDblClick", obj.grid,
+ function(evt){
+
+ });
+ } , gridProperties, EnhancedGrid);
+
+ });
+
+ }
+
+ GroupUpdater.prototype.update = function()
+ {
+
+ var that = this;
+
+ console.log("updater called ");
+ console.dir(that);
+
+
+ xhr.get({url: this.query, sync: properties.useSyncGet, handleAs: "json"})
+ .then(function(data) {
+ that.groupMemberData = data;
+
+ console.log("updater data ");
+ console.dir(that.groupMemberData);
+
+
+ util.flattenStatistics( that.groupMemberData );
+
+ that.groupMembersUpdatableStore.update(that.groupMemberData);
+
+ console.log("updated grid");
+ console.dir(that.groupMembersUpdatableStore.grid);
+ });
+ };
+
+ Group.prototype.deleteGroupMember = function() {
+ if(confirm("Are you sure you want to delete group member'" +this.name+"'?")) {
+ var query = "rest/groupmember/"+ encodeURIComponent(this.getGroupProviderName()) + "/" + encodeURIComponent(this.name);
+ this.success = true
+ var that = this;
+ xhr.del({url: query, sync: true, handleAs: "json"}).then(
+ function(data) {
+ that.contentPane.onClose()
+ that.controller.tabContainer.removeChild(that.contentPane);
+ that.contentPane.destroyRecursive();
+ },
+ function(error) {that.success = false; that.failureReason = error;});
+ if(!this.success ) {
+ alert("Error:" + this.failureReason);
+ }
+ }
+ }
+
+ return Group;
+ });
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/group/addGroupMember.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/group/addGroupMember.js
new file mode 100644
index 0000000000..1861cc6ffe
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/group/addGroupMember.js
@@ -0,0 +1,108 @@
+/*
+ *
+ * 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.
+ *
+ */
+define(["dojo/_base/xhr",
+ "dojo/dom",
+ "dojo/dom-construct",
+ "dojo/_base/window",
+ "dijit/registry",
+ "dojo/parser",
+ "dojo/_base/array",
+ "dojo/_base/event",
+ 'dojo/_base/json',
+ "dijit/form/NumberSpinner", // required by the form
+ /* dojox/ validate resources */
+ "dojox/validate/us", "dojox/validate/web",
+ /* basic dijit classes */
+ "dijit/Dialog",
+ "dijit/form/CheckBox", "dijit/form/Textarea",
+ "dijit/form/FilteringSelect", "dijit/form/TextBox",
+ "dijit/form/ValidationTextBox", "dijit/form/DateTextBox",
+ "dijit/form/TimeTextBox", "dijit/form/Button",
+ "dijit/form/RadioButton", "dijit/form/Form",
+ "dijit/form/DateTextBox",
+ /* basic dojox classes */
+ "dojox/form/BusyButton", "dojox/form/CheckedMultiSelect",
+ "dojo/domReady!"],
+ function (xhr, dom, construct, win, registry, parser, array, event, json) {
+
+ var addGroupMember = {};
+
+ var node = construct.create("div", null, win.body(), "last");
+
+ var convertToGroupMember = function convertToGroupMember(formValues)
+ {
+ var newGroupMember = {};
+ newGroupMember.name = formValues.name;
+ return newGroupMember;
+ };
+
+ xhr.get({url: "group/addGroupMember.html",
+ sync: true,
+ load: function(data) {
+ var theForm;
+ node.innerHTML = data;
+ addGroupMember.dialogNode = dom.byId("addGroupMember");
+ parser.instantiate([addGroupMember.dialogNode]);
+
+ theForm = registry.byId("formAddGroupMember");
+ theForm.on("submit", function(e) {
+
+ event.stop(e);
+ if(theForm.validate()){
+
+ var newGroupMember = convertToGroupMember(theForm.getValues());
+ var that = this;
+ xhr.put({url: "rest/groupmember/"+encodeURIComponent(addGroupMember.groupProvider) +
+ "/" + encodeURIComponent(addGroupMember.group) + "/" + encodeURIComponent(newGroupMember.name), sync: true, handleAs: "json",
+ headers: { "Content-Type": "application/json"},
+ putData: json.toJson(newGroupMember),
+ load: function(x) {that.success = true; },
+ error: function(error) {that.success = false; that.failureReason = error;}});
+
+ if(this.success === true)
+ {
+ registry.byId("addGroupMember").hide();
+ }
+ else
+ {
+ alert("Error:" + this.failureReason);
+ }
+
+ return false;
+
+
+ }else{
+ alert('Form contains invalid data. Please correct first');
+ return false;
+ }
+
+ });
+ }});
+
+ addGroupMember.show = function(groupProvider, group) {
+ addGroupMember.groupProvider = groupProvider;
+ addGroupMember.group = group;
+ registry.byId("formAddGroupMember").reset();
+ registry.byId("addGroupMember").show();
+ };
+
+ return addGroupMember;
+ }); \ No newline at end of file
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/groupprovider/FileGroupManager.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/groupprovider/FileGroupManager.js
new file mode 100644
index 0000000000..44fc9702e2
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/groupprovider/FileGroupManager.js
@@ -0,0 +1,251 @@
+/*
+ *
+ * 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.
+ *
+ */
+define(["dojo/_base/xhr",
+ "dojo/dom",
+ "dojo/parser",
+ "dojo/query",
+ "dojo/dom-construct",
+ "dojo/_base/connect",
+ "dojo/_base/window",
+ "dojo/_base/event",
+ "dojo/_base/json",
+ "dijit/registry",
+ "qpid/common/util",
+ "qpid/common/properties",
+ "qpid/common/updater",
+ "qpid/common/UpdatableStore",
+ "dojox/grid/EnhancedGrid",
+ "dojox/grid/enhanced/plugins/Pagination",
+ "dojox/grid/enhanced/plugins/IndirectSelection",
+ "dojox/validate/us", "dojox/validate/web",
+ "dijit/Dialog",
+ "dijit/form/TextBox",
+ "dijit/form/ValidationTextBox",
+ "dijit/form/TimeTextBox", "dijit/form/Button",
+ "dijit/form/Form",
+ "dijit/form/DateTextBox",
+ "dojo/domReady!"],
+ function (xhr, dom, parser, query, construct, connect, win, event, json, registry, util, properties, updater, UpdatableStore, EnhancedGrid) {
+ function DatabaseGroupManager(containerNode, groupProviderObj, controller) {
+ var node = construct.create("div", null, containerNode, "last");
+ var that = this;
+ this.name = groupProviderObj.name;
+ xhr.get({url: "groupprovider/showFileGroupManager.html",
+ sync: true,
+ load: function(data) {
+ node.innerHTML = data;
+ parser.parse(node);
+
+
+ that.groupDatabaseUpdater= new GroupProviderUpdater(node, groupProviderObj, controller);
+
+ updater.add( that.groupDatabaseUpdater);
+
+ that.groupDatabaseUpdater.update();
+
+
+ }});
+ }
+
+ DatabaseGroupManager.prototype.update = function() {
+ this.groupDatabaseUpdater.update();
+ };
+
+ DatabaseGroupManager.prototype.close = function() {
+ updater.remove( this.groupDatabaseUpdater );
+ };
+
+ function GroupProviderUpdater(node, groupProviderObj, controller)
+ {
+ this.controller = controller;
+ this.query = "rest/groupprovider/"+encodeURIComponent(groupProviderObj.name);
+ this.name = groupProviderObj.name;
+ var that = this;
+
+ xhr.get({url: this.query, sync: properties.useSyncGet, handleAs: "json"})
+ .then(function(data) {
+ that.groupProviderData = data[0];
+
+ util.flattenStatistics( that.groupProviderData );
+
+ var groupDiv = query(".groups")[0];
+
+ var gridProperties = {
+ height: 400,
+ keepSelection: true,
+ plugins: {
+ pagination: {
+ pageSizes: ["10", "25", "50", "100"],
+ description: true,
+ sizeSwitch: true,
+ pageStepper: true,
+ gotoButton: true,
+ maxPageStep: 4,
+ position: "bottom"
+ },
+ indirectSelection: true
+
+ }};
+
+
+ that.groupsGrid =
+ new UpdatableStore(that.groupProviderData.groups, groupDiv,
+ [ { name: "Group Name", field: "name", width: "100%" }
+ ], null, gridProperties, EnhancedGrid);
+
+
+ var addGroupButton = query(".addGroupButton", node)[0];
+ connect.connect(registry.byNode(addGroupButton), "onClick", function(evt){ addGroup.show(groupProviderObj.name) });
+
+ var deleteMessagesButton = query(".deleteGroupButton", node)[0];
+ var deleteWidget = registry.byNode(deleteMessagesButton);
+ connect.connect(deleteWidget, "onClick",
+ function(evt){
+ event.stop(evt);
+ that.deleteGroups();
+ });
+ });
+ }
+
+ GroupProviderUpdater.prototype.deleteGroups = function()
+ {
+ var grid = this.groupsGrid.grid;
+ var data = grid.selection.getSelected();
+ if(data.length) {
+ var that = this;
+ if(confirm("Delete " + data.length + " groups?")) {
+ var i, queryParam;
+ for(i = 0; i<data.length; i++) {
+ if(queryParam) {
+ queryParam += "&";
+ } else {
+ queryParam = "?";
+ }
+
+ queryParam += "id=" + data[i].id;
+ }
+ var query = "rest/group/"+ encodeURIComponent(that.name)
+ + queryParam;
+ that.success = true
+ xhr.del({url: query, sync: true, handleAs: "json"}).then(
+ function(data) {
+ grid.setQuery({id: "*"});
+ grid.selection.deselectAll();
+ that.update();
+ },
+ function(error) {that.success = false; that.failureReason = error;});
+ if(!that.success ) {
+ alert("Error:" + this.failureReason);
+ }
+ }
+}
+ };
+
+ GroupProviderUpdater.prototype.update = function()
+ {
+
+ var that = this;
+
+ xhr.get({url: this.query, sync: properties.useSyncGet, handleAs: "json"})
+ .then(function(data) {
+ that.groupProviderData = data[0];
+ util.flattenStatistics( that.groupProviderData );
+
+ that.groupsGrid.update(that.groupProviderData.groups);
+
+ });
+
+
+ };
+
+ var addGroup = {};
+
+ var node = construct.create("div", null, win.body(), "last");
+
+ var convertToGroup = function convertToGroup(formValues) {
+ var newGroup = {};
+ newGroup.name = formValues.name;
+ for(var propName in formValues)
+ {
+ if(formValues.hasOwnProperty(propName)) {
+ if(formValues[ propName ] !== "") {
+ newGroup[ propName ] = formValues[propName];
+ }
+ }
+ }
+
+ return newGroup;
+ };
+
+
+ xhr.get({url: "groupprovider/addGroup.html",
+ sync: true,
+ load: function(data) {
+ var theForm;
+ node.innerHTML = data;
+ addGroup.dialogNode = dom.byId("addGroup");
+ parser.instantiate([addGroup.dialogNode]);
+
+ var that = this;
+
+ theForm = registry.byId("formAddGroup");
+ theForm.on("submit", function(e) {
+
+ event.stop(e);
+ if(theForm.validate()){
+
+ var newGroup = convertToGroup(theForm.getValues());
+
+
+ var url = "rest/group/"+encodeURIComponent(addGroup.groupProvider) +
+ "/"+encodeURIComponent(newGroup.name);
+
+ xhr.put({url: url, sync: true, handleAs: "json",
+ headers: { "Content-Type": "application/json"},
+ putData: json.toJson(newGroup),
+ load: function(x) {that.success = true; },
+ error: function(error) {that.success = false; that.failureReason = error;}});
+
+ if(that.success === true) {
+ registry.byId("addGroup").hide();
+ } else {
+ alert("Error:" + that.failureReason);
+ }
+
+ return false;
+
+
+ }else{
+ alert('Form contains invalid data. Please correct first');
+ return false;
+ }
+
+ });
+ }});
+
+ addGroup.show = function(groupProvider) {
+ addGroup.groupProvider = groupProvider;
+ registry.byId("formAddGroup").reset();
+ registry.byId("addGroup").show();
+ };
+
+ return DatabaseGroupManager;
+ });
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/treeView.js b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/treeView.js
index b1d4abf8c1..59356cfce1 100644
--- a/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/treeView.js
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/treeView.js
@@ -273,10 +273,12 @@ define(["dojo/_base/xhr",
controller.show("port", details.port, { type: "virtualhost", name: details.virtualhost, parent: {broker: {type:"broker", name:""}}});
} else if (details.type == 'authenticationprovider') {
controller.show("authenticationprovider", details.authenticationprovider, {broker: {type:"broker", name:""}});
+ } else if (details.type == 'groupprovider') {
+ controller.show("groupprovider", details.groupprovider, {broker: {type:"broker", name:""}});
+ } else if (details.type == 'group') {
+ controller.show("group", details.group, { type: "groupprovider", name: details.groupprovider, parent: {broker: {type:"broker", name:""}}});
}
-
-
};
TreeViewModel.prototype.update = function () {
diff --git a/qpid/java/broker-plugins/management-http/src/main/java/resources/showGroupProvider.html b/qpid/java/broker-plugins/management-http/src/main/java/resources/showGroupProvider.html
new file mode 100644
index 0000000000..914857db5c
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/main/java/resources/showGroupProvider.html
@@ -0,0 +1,25 @@
+<!--
+ -
+ - 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.
+ -
+ -->
+<div class="groupProvider">
+ <span style="">Name:</span><span class="name" style="position:absolute; left:6em"></span>
+ <br/>
+ <span style="">Type:</span><span class="type" style="position:absolute; left:6em"></span>
+</div> \ No newline at end of file
diff --git a/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/AuthenticationProviderRestTest.java b/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/AuthenticationProviderRestTest.java
index 5e6d9a998a..86533b76b4 100644
--- a/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/AuthenticationProviderRestTest.java
+++ b/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/AuthenticationProviderRestTest.java
@@ -33,13 +33,13 @@ public class AuthenticationProviderRestTest extends QpidRestTestCase
public void testGet() throws Exception
{
- List<Map<String, Object>> providerDetails = getJsonAsList("/rest/authenticationprovider");
+ List<Map<String, Object>> providerDetails = getRestTestHelper().getJsonAsList("/rest/authenticationprovider");
assertNotNull("Providers details cannot be null", providerDetails);
assertEquals("Unexpected number of providers", 1, providerDetails.size());
for (Map<String, Object> provider : providerDetails)
{
assertProvider("PrincipalDatabaseAuthenticationManager", provider);
- Map<String, Object> data = getJsonAsSingletonList("/rest/authenticationprovider/"
+ Map<String, Object> data = getRestTestHelper().getJsonAsSingletonList("/rest/authenticationprovider/"
+ provider.get(AuthenticationProvider.NAME));
assertNotNull("Cannot load data for " + provider.get(AuthenticationProvider.NAME), data);
assertProvider("PrincipalDatabaseAuthenticationManager", data);
diff --git a/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/BindingRestTest.java b/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/BindingRestTest.java
index 1ed0d97185..c2f11ed237 100644
--- a/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/BindingRestTest.java
+++ b/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/BindingRestTest.java
@@ -32,7 +32,7 @@ public class BindingRestTest extends QpidRestTestCase
public void testGetAllBindings() throws Exception
{
- List<Map<String, Object>> bindings = getJsonAsList("/rest/binding");
+ List<Map<String, Object>> bindings = getRestTestHelper().getJsonAsList("/rest/binding");
assertNotNull("Bindings cannot be null", bindings);
assertTrue("Unexpected number of bindings", bindings.size() >= EXPECTED_HOSTS.length * EXPECTED_QUEUES.length);
for (Map<String, Object> binding : bindings)
@@ -43,7 +43,7 @@ public class BindingRestTest extends QpidRestTestCase
public void testGetVirtualHostBindings() throws Exception
{
- List<Map<String, Object>> bindings = getJsonAsList("/rest/binding/test");
+ List<Map<String, Object>> bindings = getRestTestHelper().getJsonAsList("/rest/binding/test");
assertNotNull("Bindings cannot be null", bindings);
assertEquals("Unexpected number of bindings", EXPECTED_QUEUES.length * 2, bindings.size());
for (String queueName : EXPECTED_QUEUES)
@@ -52,31 +52,31 @@ public class BindingRestTest extends QpidRestTestCase
searchAttributes.put(Binding.NAME, queueName);
searchAttributes.put(Binding.EXCHANGE, "amq.direct");
- Map<String, Object> binding = find(searchAttributes, bindings);
+ Map<String, Object> binding = getRestTestHelper().find(searchAttributes, bindings);
Asserts.assertBinding(queueName, "amq.direct", binding);
searchAttributes.put(Binding.EXCHANGE, "<<default>>");
- binding = find(searchAttributes, bindings);
+ binding = getRestTestHelper().find(searchAttributes, bindings);
Asserts.assertBinding(queueName, "<<default>>", binding);
}
}
public void testGetVirtualHostExchangeBindings() throws Exception
{
- List<Map<String, Object>> bindings = getJsonAsList("/rest/binding/test/amq.direct");
+ List<Map<String, Object>> bindings = getRestTestHelper().getJsonAsList("/rest/binding/test/amq.direct");
assertNotNull("Bindings cannot be null", bindings);
assertEquals("Unexpected number of bindings", EXPECTED_QUEUES.length, bindings.size());
for (String queueName : EXPECTED_QUEUES)
{
- Map<String, Object> binding = find(Binding.NAME, queueName, bindings);
+ Map<String, Object> binding = getRestTestHelper().find(Binding.NAME, queueName, bindings);
Asserts.assertBinding(queueName, "amq.direct", binding);
}
}
public void testGetVirtualHostExchangeQueueBindings() throws Exception
{
- List<Map<String, Object>> bindings = getJsonAsList("/rest/binding/test/amq.direct/queue");
+ List<Map<String, Object>> bindings = getRestTestHelper().getJsonAsList("/rest/binding/test/amq.direct/queue");
assertNotNull("Bindings cannot be null", bindings);
assertEquals("Unexpected number of bindings", 1, bindings.size());
Asserts.assertBinding("queue", "amq.direct", bindings.get(0));
@@ -85,25 +85,25 @@ public class BindingRestTest extends QpidRestTestCase
public void testDeleteBinding() throws Exception
{
- List<Map<String, Object>> bindings = getJsonAsList("/rest/binding/test/amq.direct/queue/queue");
+ List<Map<String, Object>> bindings = getRestTestHelper().getJsonAsList("/rest/binding/test/amq.direct/queue/queue");
assertEquals("Unexpected number of bindings", 1, bindings.size());
Asserts.assertBinding("queue", "amq.direct", bindings.get(0));
- HttpURLConnection connection = openManagementConection("/rest/binding/test/amq.direct/queue/queue", "DELETE");
+ HttpURLConnection connection = getRestTestHelper().openManagementConnection("/rest/binding/test/amq.direct/queue/queue", "DELETE");
connection.connect();
assertEquals("Unexpected response code", 200, connection.getResponseCode());
- bindings = getJsonAsList("/rest/binding/test/amq.direct/queue/queue");
+ bindings = getRestTestHelper().getJsonAsList("/rest/binding/test/amq.direct/queue/queue");
assertEquals("Binding should be deleted", 0, bindings.size());
}
public void testDeleteBindingById() throws Exception
{
- Map<String, Object> binding = getJsonAsSingletonList("/rest/binding/test/amq.direct/queue");
- HttpURLConnection connection = openManagementConection("/rest/binding/test/amq.direct?id=" + binding.get(Binding.ID), "DELETE");
+ Map<String, Object> binding = getRestTestHelper().getJsonAsSingletonList("/rest/binding/test/amq.direct/queue");
+ HttpURLConnection connection = getRestTestHelper().openManagementConnection("/rest/binding/test/amq.direct?id=" + binding.get(Binding.ID), "DELETE");
connection.connect();
assertEquals("Unexpected response code", 200, connection.getResponseCode());
- List<Map<String, Object>> bindings = getJsonAsList("/rest/binding/test/amq.direct/queue");
+ List<Map<String, Object>> bindings = getRestTestHelper().getJsonAsList("/rest/binding/test/amq.direct/queue");
assertEquals("Binding should be deleted", 0, bindings.size());
}
@@ -115,13 +115,13 @@ public class BindingRestTest extends QpidRestTestCase
bindingData.put(Binding.QUEUE, "queue");
bindingData.put(Binding.EXCHANGE, "amq.direct");
- HttpURLConnection connection = openManagementConection("/rest/binding/test/amq.direct/queue/" + bindingName, "PUT");
+ HttpURLConnection connection = getRestTestHelper().openManagementConnection("/rest/binding/test/amq.direct/queue/" + bindingName, "PUT");
connection.connect();
- writeJsonRequest(connection, bindingData);
+ getRestTestHelper().writeJsonRequest(connection, bindingData);
int responseCode = connection.getResponseCode();
connection.disconnect();
assertEquals("Unexpected response code", 201, responseCode);
- Map<String, Object> binding = getJsonAsSingletonList("/rest/binding/test/amq.direct/queue/" + bindingName);
+ Map<String, Object> binding = getRestTestHelper().getJsonAsSingletonList("/rest/binding/test/amq.direct/queue/" + bindingName);
Asserts.assertBinding(bindingName, "queue", "amq.direct", binding);
}
diff --git a/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/BrokerRestHttpsTest.java b/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/BrokerRestHttpsTest.java
index 4bbe9155cd..08b5863004 100644
--- a/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/BrokerRestHttpsTest.java
+++ b/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/BrokerRestHttpsTest.java
@@ -21,13 +21,8 @@
package org.apache.qpid.server.management.plugin.servlet.rest;
import java.io.IOException;
-import java.net.HttpURLConnection;
-import java.net.URL;
import java.util.Map;
-import javax.net.ssl.HttpsURLConnection;
-import javax.net.ssl.SSLSocketFactory;
-
import org.apache.commons.configuration.ConfigurationException;
import org.apache.qpid.server.model.Broker;
@@ -48,37 +43,16 @@ public class BrokerRestHttpsTest extends QpidRestTestCase
@Override
protected void customizeConfiguration() throws ConfigurationException, IOException
{
+ getRestTestHelper().setUseSsl(true);
setConfigurationProperty("management.enabled", "true");
setConfigurationProperty("management.http.enabled", "false");
setConfigurationProperty("management.https.enabled", "true");
- setConfigurationProperty("management.https.port", Integer.toString(getHttpPort()));
- }
-
- @Override
- protected String getHostName()
- {
- return "localhost";
- }
-
- @Override
- protected String getProtocol()
- {
- return "https";
- }
-
- @Override
- protected HttpURLConnection openManagementConection(String path) throws IOException
- {
- URL url = getManagementURL(path);
- HttpURLConnection httpCon = (HttpURLConnection) url.openConnection();
- ((HttpsURLConnection) httpCon).setSSLSocketFactory((SSLSocketFactory) SSLSocketFactory.getDefault());
- httpCon.setDoOutput(true);
- return httpCon;
+ setConfigurationProperty("management.https.port", Integer.toString(getRestTestHelper().getHttpPort()));
}
public void testGetWithHttps() throws Exception
{
- Map<String, Object> brokerDetails = getJsonAsSingletonList("/rest/broker");
+ Map<String, Object> brokerDetails = getRestTestHelper().getJsonAsSingletonList("/rest/broker");
Asserts.assertAttributesPresent(brokerDetails, Broker.AVAILABLE_ATTRIBUTES, Broker.BYTES_RETAINED,
Broker.PROCESS_PID, Broker.SUPPORTED_STORE_TYPES, Broker.CREATED, Broker.TIME_TO_LIVE, Broker.UPDATED);
diff --git a/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/BrokerRestTest.java b/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/BrokerRestTest.java
index f2970e2ba9..c4cd00416b 100644
--- a/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/BrokerRestTest.java
+++ b/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/BrokerRestTest.java
@@ -43,7 +43,7 @@ public class BrokerRestTest extends QpidRestTestCase
public void testGet() throws Exception
{
- Map<String, Object> brokerDetails = getJsonAsSingletonList("/rest/broker");
+ Map<String, Object> brokerDetails = getRestTestHelper().getJsonAsSingletonList("/rest/broker");
assertBrokerAttributes(brokerDetails);
@@ -55,9 +55,9 @@ public class BrokerRestTest extends QpidRestTestCase
List<Map<String, Object>> virtualhosts = (List<Map<String, Object>>) brokerDetails.get(BROKER_VIRTUALHOSTS_ATTRIBUTE);
assertEquals("Unexpected number of virtual hosts", 3, virtualhosts.size());
- Asserts.assertVirtualHost("development", find(VirtualHost.NAME, "development", virtualhosts));
- Asserts.assertVirtualHost("localhost", find(VirtualHost.NAME, "localhost", virtualhosts));
- Asserts.assertVirtualHost("test", find(VirtualHost.NAME, "test", virtualhosts));
+ Asserts.assertVirtualHost("development", getRestTestHelper().find(VirtualHost.NAME, "development", virtualhosts));
+ Asserts.assertVirtualHost("localhost", getRestTestHelper().find(VirtualHost.NAME, "localhost", virtualhosts));
+ Asserts.assertVirtualHost("test", getRestTestHelper().find(VirtualHost.NAME, "test", virtualhosts));
@SuppressWarnings("unchecked")
List<Map<String, Object>> ports = (List<Map<String, Object>>) brokerDetails.get(BROKER_PORTS_ATTRIBUTE);
@@ -70,8 +70,8 @@ public class BrokerRestTest extends QpidRestTestCase
String bindingAddress = (String)ports.get(0).get(Port.BINDING_ADDRESS);
- Map<String, Object> amqpPort = find(Port.NAME, bindingAddress + ":" + getPort(), ports);
- Map<String, Object> httpPort = find(Port.NAME, bindingAddress + ":" + getHttpPort(), ports);
+ Map<String, Object> amqpPort = getRestTestHelper().find(Port.NAME, bindingAddress + ":" + getPort(), ports);
+ Map<String, Object> httpPort = getRestTestHelper().find(Port.NAME, bindingAddress + ":" + getRestTestHelper().getHttpPort(), ports);
assertNotNull("Cannot find AMQP port", amqpPort);
assertNotNull("Cannot find HTTP port", httpPort);
diff --git a/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/ConnectionRestTest.java b/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/ConnectionRestTest.java
index 3661b94a7c..500a5770fb 100644
--- a/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/ConnectionRestTest.java
+++ b/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/ConnectionRestTest.java
@@ -90,14 +90,14 @@ public class ConnectionRestTest extends QpidRestTestCase
public void testGetAllConnections() throws Exception
{
- List<Map<String, Object>> connections = getJsonAsList("/rest/connection");
+ List<Map<String, Object>> connections = getRestTestHelper().getJsonAsList("/rest/connection");
assertEquals("Unexpected number of connections", 1, connections.size());
Asserts.assertConnection(connections.get(0), (AMQConnection) _connection);
}
public void testGetVirtualHostConnections() throws Exception
{
- List<Map<String, Object>> connections = getJsonAsList("/rest/connection/test");
+ List<Map<String, Object>> connections = getRestTestHelper().getJsonAsList("/rest/connection/test");
assertEquals("Unexpected number of connections", 1, connections.size());
Asserts.assertConnection(connections.get(0), (AMQConnection) _connection);
}
@@ -107,21 +107,21 @@ public class ConnectionRestTest extends QpidRestTestCase
// get connection name
String connectionName = getConnectionName();
- Map<String, Object> connectionDetails = getJsonAsSingletonList("/rest/connection/test/"
+ Map<String, Object> connectionDetails = getRestTestHelper().getJsonAsSingletonList("/rest/connection/test/"
+ URLDecoder.decode(connectionName, "UTF-8"));
assertConnection(connectionDetails);
}
public void testGetAllSessions() throws Exception
{
- List<Map<String, Object>> sessions = getJsonAsList("/rest/session");
+ List<Map<String, Object>> sessions = getRestTestHelper().getJsonAsList("/rest/session");
assertEquals("Unexpected number of sessions", 1, sessions.size());
assertSession(sessions.get(0), (AMQSession<?, ?>) _session);
}
public void testGetVirtualHostSessions() throws Exception
{
- List<Map<String, Object>> sessions = getJsonAsList("/rest/session/test");
+ List<Map<String, Object>> sessions = getRestTestHelper().getJsonAsList("/rest/session/test");
assertEquals("Unexpected number of sessions", 1, sessions.size());
assertSession(sessions.get(0), (AMQSession<?, ?>) _session);
}
@@ -131,7 +131,7 @@ public class ConnectionRestTest extends QpidRestTestCase
// get connection name
String connectionName = getConnectionName();
- List<Map<String, Object>> sessions = getJsonAsList("/rest/session/test/"
+ List<Map<String, Object>> sessions = getRestTestHelper().getJsonAsList("/rest/session/test/"
+ URLDecoder.decode(connectionName, "UTF-8"));
assertEquals("Unexpected number of sessions", 1, sessions.size());
assertSession(sessions.get(0), (AMQSession<?, ?>) _session);
@@ -142,7 +142,7 @@ public class ConnectionRestTest extends QpidRestTestCase
// get connection name
String connectionName = getConnectionName();
- List<Map<String, Object>> sessions = getJsonAsList("/rest/session/test/"
+ List<Map<String, Object>> sessions = getRestTestHelper().getJsonAsList("/rest/session/test/"
+ URLDecoder.decode(connectionName, "UTF-8") + "/" + ((AMQSession<?, ?>) _session).getChannelId());
assertEquals("Unexpected number of sessions", 1, sessions.size());
assertSession(sessions.get(0), (AMQSession<?, ?>) _session);
@@ -201,7 +201,7 @@ public class ConnectionRestTest extends QpidRestTestCase
private String getConnectionName() throws IOException
{
- Map<String, Object> hostDetails = getJsonAsSingletonList("/rest/virtualhost/test");
+ Map<String, Object> hostDetails = getRestTestHelper().getJsonAsSingletonList("/rest/virtualhost/test");
@SuppressWarnings("unchecked")
List<Map<String, Object>> connections = (List<Map<String, Object>>) hostDetails
.get(VirtualHostRestTest.VIRTUALHOST_CONNECTIONS_ATTRIBUTE);
diff --git a/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/ExchangeRestTest.java b/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/ExchangeRestTest.java
index 4904d2adf3..363652d37c 100644
--- a/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/ExchangeRestTest.java
+++ b/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/ExchangeRestTest.java
@@ -31,7 +31,7 @@ public class ExchangeRestTest extends QpidRestTestCase
{
public void testGet() throws Exception
{
- List<Map<String, Object>> exchanges = getJsonAsList("/rest/exchange");
+ List<Map<String, Object>> exchanges = getRestTestHelper().getJsonAsList("/rest/exchange");
assertNotNull("Exchanges cannot be null", exchanges);
assertTrue("Unexpected number of exchanges", exchanges.size() >= EXPECTED_HOSTS.length * EXPECTED_EXCHANGES.length);
for (Map<String, Object> exchange : exchanges)
@@ -42,12 +42,12 @@ public class ExchangeRestTest extends QpidRestTestCase
public void testGetHostExchanges() throws Exception
{
- List<Map<String, Object>> exchanges = getJsonAsList("/rest/exchange/test");
+ List<Map<String, Object>> exchanges = getRestTestHelper().getJsonAsList("/rest/exchange/test");
assertNotNull("Users cannot be null", exchanges);
assertEquals("Unexpected number of exchanges", 6, EXPECTED_EXCHANGES.length);
for (String exchangeName : EXPECTED_EXCHANGES)
{
- Map<String, Object> exchange = find(Exchange.NAME, exchangeName, exchanges);
+ Map<String, Object> exchange = getRestTestHelper().find(Exchange.NAME, exchangeName, exchanges);
assertExchange(exchangeName, exchange);
}
}
@@ -56,7 +56,7 @@ public class ExchangeRestTest extends QpidRestTestCase
{
for (String exchangeName : EXPECTED_EXCHANGES)
{
- Map<String, Object> exchange = getJsonAsSingletonList("/rest/exchange/test/"
+ Map<String, Object> exchange = getRestTestHelper().getJsonAsSingletonList("/rest/exchange/test/"
+ URLDecoder.decode(exchangeName, "UTF-8"));
assertExchange(exchangeName, exchange);
}
@@ -79,7 +79,7 @@ public class ExchangeRestTest extends QpidRestTestCase
List<Map<String, Object>> bindings = (List<Map<String, Object>>) exchange.get("bindings");
for (String queueName : EXPECTED_QUEUES)
{
- Map<String, Object> binding = find(Binding.NAME, queueName, bindings);
+ Map<String, Object> binding = getRestTestHelper().find(Binding.NAME, queueName, bindings);
Asserts.assertBinding(queueName, (String) exchange.get(Exchange.NAME), binding);
}
}
diff --git a/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/GroupProviderRestTest.java b/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/GroupProviderRestTest.java
new file mode 100644
index 0000000000..c2eefec395
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/GroupProviderRestTest.java
@@ -0,0 +1,160 @@
+/*
+ *
+ * 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.management.plugin.servlet.rest;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.qpid.server.model.Group;
+import org.apache.qpid.server.model.GroupProvider;
+import org.apache.qpid.server.model.LifetimePolicy;
+import org.apache.qpid.server.model.State;
+import org.apache.qpid.server.model.UUIDGenerator;
+
+public class GroupProviderRestTest extends QpidRestTestCase
+{
+ private static final String FILE_GROUP_MANAGER = "FileGroupManager";
+ private File _groupFile;
+
+ @Override
+ public void setUp() throws Exception
+ {
+ _groupFile = createTemporaryGroupFile();
+
+ setConfigurationProperty("security.file-group-manager.attributes.attribute.name", "groupFile");
+ setConfigurationProperty("security.file-group-manager.attributes.attribute.value", _groupFile.getAbsolutePath());
+
+ super.setUp();
+ }
+
+ @Override
+ public void tearDown() throws Exception
+ {
+ super.tearDown();
+
+ if (_groupFile != null)
+ {
+ if (_groupFile.exists())
+ {
+ _groupFile.delete();
+ }
+ }
+ }
+
+ public void testGet() throws Exception
+ {
+ List<Map<String, Object>> providerDetails = getRestTestHelper().getJsonAsList("/rest/groupprovider");
+ assertNotNull("Providers details cannot be null", providerDetails);
+ assertEquals("Unexpected number of providers", 1, providerDetails.size());
+ for (Map<String, Object> provider : providerDetails)
+ {
+ assertProvider(FILE_GROUP_MANAGER, provider);
+ Map<String, Object> data = getRestTestHelper().getJsonAsSingletonList("/rest/groupprovider/"
+ + provider.get(GroupProvider.NAME));
+ assertNotNull("Cannot load data for " + provider.get(GroupProvider.NAME), data);
+ assertProvider(FILE_GROUP_MANAGER, data);
+ }
+ }
+
+ public void testCreateNewGroup() throws Exception
+ {
+ String groupName = "newGroup";
+
+ Map<String, Object> data = getRestTestHelper().getJsonAsSingletonList("/rest/groupprovider/" + FILE_GROUP_MANAGER);
+ assertNotNull("Cannot load data for provider", data);
+
+ getRestTestHelper().assertNumberOfGroups(data, 1);
+
+ getRestTestHelper().createGroup(groupName, FILE_GROUP_MANAGER);
+
+ data = getRestTestHelper().getJsonAsSingletonList("/rest/groupprovider/" + FILE_GROUP_MANAGER);
+ assertNotNull("Cannot load data for provider", data);
+
+ getRestTestHelper().assertNumberOfGroups(data, 2);
+ }
+
+ public void testRemoveGroup() throws Exception
+ {
+ String groupName = "myGroup";
+
+ Map<String, Object> data = getRestTestHelper().getJsonAsSingletonList("/rest/groupprovider/" + FILE_GROUP_MANAGER);
+ assertNotNull("Cannot load data for provider", data);
+
+ getRestTestHelper().assertNumberOfGroups(data, 1);
+
+ getRestTestHelper().removeGroup(groupName, FILE_GROUP_MANAGER);
+
+ data = getRestTestHelper().getJsonAsSingletonList("/rest/groupprovider/" + FILE_GROUP_MANAGER);
+ assertNotNull("Cannot load data for provider", data);
+
+ getRestTestHelper().assertNumberOfGroups(data, 0);
+ }
+
+
+ private void assertProvider(String type, Map<String, Object> provider)
+ {
+ Asserts.assertAttributesPresent(provider, GroupProvider.AVAILABLE_ATTRIBUTES,
+ GroupProvider.CREATED, GroupProvider.UPDATED, GroupProvider.DESCRIPTION,
+ GroupProvider.TIME_TO_LIVE);
+ assertEquals("Unexpected value of provider attribute " + GroupProvider.STATE, State.ACTIVE.name(),
+ provider.get(GroupProvider.STATE));
+ assertEquals("Unexpected value of provider attribute " + GroupProvider.LIFETIME_POLICY,
+ LifetimePolicy.PERMANENT.name(), provider.get(GroupProvider.LIFETIME_POLICY));
+ assertEquals("Unexpected value of provider attribute " + GroupProvider.DURABLE, Boolean.TRUE,
+ provider.get(GroupProvider.DURABLE));
+ assertEquals("Unexpected value of provider attribute " + GroupProvider.TYPE, type,
+ provider.get(GroupProvider.TYPE));
+
+ final String name = (String) provider.get(GroupProvider.NAME);
+ assertEquals("Unexpected value of provider attribute " + GroupProvider.NAME, type,
+ name);
+
+ @SuppressWarnings("unchecked")
+ List<Map<String, Object>> groups = (List<Map<String, Object>>) provider.get("groups");
+ assertNotNull("Groups were not found", groups);
+ assertEquals("Unexpected number of groups", 1, groups.size());
+ for (Map<String, Object> group : groups)
+ {
+
+ final String groupName = (String) group.get(Group.NAME);
+ assertNotNull("Attribute " + Group.NAME, groupName);
+
+ assertNotNull("Attribute " + Group.ID, group.get(Group.ID));
+ assertEquals("Attribute " + Group.ID, UUIDGenerator.generateGroupUUID(name, groupName).toString(), group.get(Group.ID));
+ }
+ }
+
+ private File createTemporaryGroupFile() throws Exception
+ {
+ File groupFile = File.createTempFile("group", "grp");
+ groupFile.deleteOnExit();
+
+ Properties props = new Properties();
+ props.put("myGroup.users", "guest");
+
+ props.store(new FileOutputStream(groupFile), "test group file");
+
+ return groupFile;
+ }
+}
diff --git a/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/GroupRestTest.java b/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/GroupRestTest.java
new file mode 100644
index 0000000000..5430cce6dc
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/GroupRestTest.java
@@ -0,0 +1,109 @@
+/*
+ *
+ * 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.management.plugin.servlet.rest;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.qpid.server.model.GroupMember;
+
+public class GroupRestTest extends QpidRestTestCase
+{
+ private static final String GROUP_NAME = "myGroup";
+ private static final String FILE_GROUP_MANAGER = "FileGroupManager";
+ private static final String EXISTING_MEMBER = "user1";
+ private static final String NEW_MEMBER = "user2";
+
+ private File _groupFile;
+
+ @Override
+ public void setUp() throws Exception
+ {
+ _groupFile = createTemporaryGroupFile();
+
+ setConfigurationProperty("security.file-group-manager.attributes.attribute.name", "groupFile");
+ setConfigurationProperty("security.file-group-manager.attributes.attribute.value", _groupFile.getAbsolutePath());
+
+ super.setUp();
+ }
+
+ @Override
+ public void tearDown() throws Exception
+ {
+ super.tearDown();
+
+ if (_groupFile != null)
+ {
+ if (_groupFile.exists())
+ {
+ _groupFile.delete();
+ }
+ }
+ }
+
+ public void testGet() throws Exception
+ {
+ Map<String, Object> group = getRestTestHelper().getJsonAsSingletonList("/rest/group/FileGroupManager/myGroup");
+ List<Map<String, Object>> groupmembers = (List<Map<String, Object>>) group.get("groupmembers");
+ assertEquals(1, groupmembers.size());
+
+ Map<String, Object> member1 = groupmembers.get(0);
+ assertEquals(EXISTING_MEMBER, (String)member1.get(GroupMember.NAME));
+ }
+
+ public void testCreateNewMemberOfGroup() throws Exception
+ {
+ Map<String, Object> group = getRestTestHelper().getJsonAsSingletonList("/rest/group/FileGroupManager/myGroup");
+ getRestTestHelper().assertNumberOfGroupMembers(group, 1);
+
+ getRestTestHelper().createNewGroupMember(FILE_GROUP_MANAGER, GROUP_NAME, NEW_MEMBER);
+
+ group = getRestTestHelper().getJsonAsSingletonList("/rest/group/FileGroupManager/myGroup");
+ getRestTestHelper().assertNumberOfGroupMembers(group, 2);
+ }
+
+ public void testRemoveMemberFromGroup() throws Exception
+ {
+ Map<String, Object> group = getRestTestHelper().getJsonAsSingletonList("/rest/group/FileGroupManager/myGroup");
+ getRestTestHelper().assertNumberOfGroupMembers(group, 1);
+
+ getRestTestHelper().removeMemberFromGroup(FILE_GROUP_MANAGER, GROUP_NAME, EXISTING_MEMBER);
+
+ group = getRestTestHelper().getJsonAsSingletonList("/rest/group/FileGroupManager/myGroup");
+ getRestTestHelper().assertNumberOfGroupMembers(group, 0);
+ }
+
+ private File createTemporaryGroupFile() throws Exception
+ {
+ File groupFile = File.createTempFile("group", "grp");
+ groupFile.deleteOnExit();
+
+ Properties props = new Properties();
+ props.put(GROUP_NAME + ".users", EXISTING_MEMBER);
+
+ props.store(new FileOutputStream(groupFile), "test group file");
+
+ return groupFile;
+ }
+}
diff --git a/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/LogRecordsRestTest.java b/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/LogRecordsRestTest.java
index c64fd6e1da..34b25e2e40 100644
--- a/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/LogRecordsRestTest.java
+++ b/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/LogRecordsRestTest.java
@@ -27,10 +27,10 @@ public class LogRecordsRestTest extends QpidRestTestCase
{
public void testGet() throws Exception
{
- List<Map<String, Object>> logs = getJsonAsList("/rest/logrecords");
+ List<Map<String, Object>> logs = getRestTestHelper().getJsonAsList("/rest/logrecords");
assertNotNull("Logs data cannot be null", logs);
assertTrue("Logs are not found", logs.size() > 0);
- Map<String, Object> record = find("message", "[Broker] BRK-1004 : Qpid Broker Ready", logs);
+ Map<String, Object> record = getRestTestHelper().find("message", "[Broker] BRK-1004 : Qpid Broker Ready", logs);
assertNotNull("BRK-1004 message is not found", record);
assertNotNull("Message id cannot be null", record.get("id"));
diff --git a/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/MessagesRestTest.java b/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/MessagesRestTest.java
index 492df43957..a4efcc9456 100644
--- a/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/MessagesRestTest.java
+++ b/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/MessagesRestTest.java
@@ -85,7 +85,7 @@ public class MessagesRestTest extends QpidRestTestCase
public void testGet() throws Exception
{
String queueName = getTestQueueName();
- List<Map<String, Object>> messages = getJsonAsList("/rest/message/test/" + queueName);
+ List<Map<String, Object>> messages = getRestTestHelper().getJsonAsList("/rest/message/test/" + queueName);
assertNotNull("Messages are not found", messages);
assertEquals("Unexpected number of messages", MESSAGE_NUMBER, messages.size());
int position = 0;
@@ -111,7 +111,7 @@ public class MessagesRestTest extends QpidRestTestCase
// get message IDs
List<Long> ids = getMesssageIds(queueName);
- Map<String, Object> message = getJsonAsMap("/rest/message/test/" + queueName + "/" + ids.get(0));
+ Map<String, Object> message = getRestTestHelper().getJsonAsMap("/rest/message/test/" + queueName + "/" + ids.get(0));
assertMessageAttributes(message);
assertMessageAttributeValues(message, true);
@@ -121,7 +121,7 @@ public class MessagesRestTest extends QpidRestTestCase
assertEquals("Unexpected message header", 0, headers.get("index"));
Long lastMessageId = ids.get(ids.size() - 1);
- message = getJsonAsMap("/rest/message/test/" + queueName + "/" + lastMessageId);
+ message = getRestTestHelper().getJsonAsMap("/rest/message/test/" + queueName + "/" + lastMessageId);
assertMessageAttributes(message);
assertEquals("Unexpected message attribute mimeType", "application/octet-stream", message.get("mimeType"));
assertEquals("Unexpected message attribute size", 4, message.get("size"));
@@ -132,10 +132,10 @@ public class MessagesRestTest extends QpidRestTestCase
assertEquals("Unexpected message header", "value", bytesMessageHeader.get("test"));
// get content
- HttpURLConnection connection = openManagementConection("/rest/message-content/test/" + queueName + "/"
+ HttpURLConnection connection = getRestTestHelper().openManagementConnection("/rest/message-content/test/" + queueName + "/"
+ lastMessageId, "GET");
connection.connect();
- byte[] data = readConnectionInputStream(connection);
+ byte[] data = getRestTestHelper().readConnectionInputStream(connection);
assertTrue("Unexpected message", Arrays.equals(messageBytes, data));
}
@@ -159,38 +159,38 @@ public class MessagesRestTest extends QpidRestTestCase
}
// move messages
- HttpURLConnection connection = openManagementConection("/rest/message/test/" + queueName, "POST");
+ HttpURLConnection connection = getRestTestHelper().openManagementConnection("/rest/message/test/" + queueName, "POST");
Map<String, Object> messagesData = new HashMap<String, Object>();
messagesData.put("messages", movedMessageIds);
messagesData.put("destinationQueue", queueName2);
messagesData.put("move", Boolean.TRUE);
- writeJsonRequest(connection, messagesData);
+ getRestTestHelper().writeJsonRequest(connection, messagesData);
assertEquals("Unexpected response code", 200, connection.getResponseCode());
// check messages on target queue
- List<Map<String, Object>> messages = getJsonAsList("/rest/message/test/" + queueName2);
+ List<Map<String, Object>> messages = getRestTestHelper().getJsonAsList("/rest/message/test/" + queueName2);
assertNotNull("Messages are not found", messages);
assertEquals("Unexpected number of messages", movedMessageIds.size(), messages.size());
for (Long id : movedMessageIds)
{
- Map<String, Object> message = find("id", id.intValue(), messages);
+ Map<String, Object> message = getRestTestHelper().find("id", id.intValue(), messages);
assertMessageAttributes(message);
}
// check messages on original queue
- messages = getJsonAsList("/rest/message/test/" + queueName);
+ messages = getRestTestHelper().getJsonAsList("/rest/message/test/" + queueName);
assertNotNull("Messages are not found", messages);
assertEquals("Unexpected number of messages", ids.size(), messages.size());
for (Long id : ids)
{
- Map<String, Object> message = find("id", id.intValue(), messages);
+ Map<String, Object> message = getRestTestHelper().find("id", id.intValue(), messages);
assertMessageAttributes(message);
}
for (Long id : movedMessageIds)
{
- Map<String, Object> message = find("id", id.intValue(), messages);
+ Map<String, Object> message = getRestTestHelper().find("id", id.intValue(), messages);
assertNull("Moved message " + id + " is found on original queue", message);
}
}
@@ -214,37 +214,37 @@ public class MessagesRestTest extends QpidRestTestCase
}
// copy messages
- HttpURLConnection connection = openManagementConection("/rest/message/test/" + queueName, "POST");
+ HttpURLConnection connection = getRestTestHelper().openManagementConnection("/rest/message/test/" + queueName, "POST");
Map<String, Object> messagesData = new HashMap<String, Object>();
messagesData.put("messages", copyMessageIds);
messagesData.put("destinationQueue", queueName2);
- writeJsonRequest(connection, messagesData);
+ getRestTestHelper().writeJsonRequest(connection, messagesData);
assertEquals("Unexpected response code", 200, connection.getResponseCode());
// check messages on target queue
- List<Map<String, Object>> messages = getJsonAsList("/rest/message/test/" + queueName2);
+ List<Map<String, Object>> messages = getRestTestHelper().getJsonAsList("/rest/message/test/" + queueName2);
assertNotNull("Messages are not found", messages);
assertEquals("Unexpected number of messages", copyMessageIds.size(), messages.size());
for (Long id : copyMessageIds)
{
- Map<String, Object> message = find("id", id.intValue(), messages);
+ Map<String, Object> message = getRestTestHelper().find("id", id.intValue(), messages);
assertMessageAttributes(message);
}
// check messages on original queue
- messages = getJsonAsList("/rest/message/test/" + queueName);
+ messages = getRestTestHelper().getJsonAsList("/rest/message/test/" + queueName);
assertNotNull("Messages are not found", messages);
assertEquals("Unexpected number of messages", MESSAGE_NUMBER, messages.size());
for (Long id : ids)
{
- Map<String, Object> message = find("id", id.intValue(), messages);
+ Map<String, Object> message = getRestTestHelper().find("id", id.intValue(), messages);
assertMessageAttributes(message);
}
for (Long id : copyMessageIds)
{
- Map<String, Object> message = find("id", id.intValue(), messages);
+ Map<String, Object> message = getRestTestHelper().find("id", id.intValue(), messages);
assertMessageAttributes(message);
}
}
@@ -272,30 +272,30 @@ public class MessagesRestTest extends QpidRestTestCase
}
// delete messages
- HttpURLConnection connection = openManagementConection(
+ HttpURLConnection connection = getRestTestHelper().openManagementConnection(
"/rest/message/test/" + queueName + "?" + queryString.toString(), "DELETE");
connection.connect();
assertEquals("Unexpected response code", 200, connection.getResponseCode());
// check messages on queue
- List<Map<String, Object>> messages = getJsonAsList("/rest/message/test/" + queueName);
+ List<Map<String, Object>> messages = getRestTestHelper().getJsonAsList("/rest/message/test/" + queueName);
assertNotNull("Messages are not found", messages);
assertEquals("Unexpected number of messages", ids.size(), messages.size());
for (Long id : ids)
{
- Map<String, Object> message = find("id", id.intValue(), messages);
+ Map<String, Object> message = getRestTestHelper().find("id", id.intValue(), messages);
assertMessageAttributes(message);
}
for (Long id : deleteMessageIds)
{
- Map<String, Object> message = find("id", id.intValue(), messages);
+ Map<String, Object> message = getRestTestHelper().find("id", id.intValue(), messages);
assertNull("Message with id " + id + " was not deleted", message);
}
}
private List<Long> getMesssageIds(String queueName) throws IOException, JsonParseException, JsonMappingException
{
- List<Map<String, Object>> messages = getJsonAsList("/rest/message/test/" + queueName);
+ List<Map<String, Object>> messages = getRestTestHelper().getJsonAsList("/rest/message/test/" + queueName);
List<Long> ids = new ArrayList<Long>();
for (Map<String, Object> message : messages)
{
diff --git a/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/PortRestTest.java b/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/PortRestTest.java
index 739ef5c737..ea897881a9 100644
--- a/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/PortRestTest.java
+++ b/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/PortRestTest.java
@@ -30,14 +30,14 @@ public class PortRestTest extends QpidRestTestCase
{
public void testGet() throws Exception
{
- List<Map<String, Object>> ports = getJsonAsList("/rest/port/");
+ List<Map<String, Object>> ports = getRestTestHelper().getJsonAsList("/rest/port/");
assertNotNull("Port data cannot be null", ports);
assertEquals("Unexpected number of ports", 2, ports.size());
- int[] expectedPorts = { getPort(), getHttpPort() };
+ int[] expectedPorts = { getPort(), getRestTestHelper().getHttpPort() };
for (int port : expectedPorts)
{
String portName = "0.0.0.0:" + port;
- Map<String, Object> portData = find(Port.NAME, portName, ports);
+ Map<String, Object> portData = getRestTestHelper().find(Port.NAME, portName, ports);
assertNotNull("Port " + portName + " is not found", portData);
Asserts.assertPortAttributes(portData);
}
@@ -45,14 +45,14 @@ public class PortRestTest extends QpidRestTestCase
public void testGetPort() throws Exception
{
- List<Map<String, Object>> ports = getJsonAsList("/rest/port/");
+ List<Map<String, Object>> ports = getRestTestHelper().getJsonAsList("/rest/port/");
assertNotNull("Ports data cannot be null", ports);
assertEquals("Unexpected number of ports", 2, ports.size());
for (Map<String, Object> portMap : ports)
{
String portName = (String) portMap.get(Port.NAME);
assertNotNull("Port name attribute is not found", portName);
- Map<String, Object> portData = getJsonAsSingletonList("/rest/port/" + URLDecoder.decode(portName, "UTF-8"));
+ Map<String, Object> portData = getRestTestHelper().getJsonAsSingletonList("/rest/port/" + URLDecoder.decode(portName, "UTF-8"));
assertNotNull("Port " + portName + " is not found", portData);
Asserts.assertPortAttributes(portData);
}
diff --git a/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/QpidRestTestCase.java b/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/QpidRestTestCase.java
index e83341de80..958e68ab70 100644
--- a/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/QpidRestTestCase.java
+++ b/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/QpidRestTestCase.java
@@ -20,226 +20,50 @@
*/
package org.apache.qpid.server.management.plugin.servlet.rest;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
import java.io.IOException;
-import java.io.InputStream;
-import java.net.HttpURLConnection;
-import java.net.InetAddress;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
import org.apache.commons.configuration.ConfigurationException;
-import org.apache.log4j.Logger;
import org.apache.qpid.test.utils.QpidBrokerTestCase;
-import org.codehaus.jackson.JsonGenerationException;
-import org.codehaus.jackson.JsonParseException;
-import org.codehaus.jackson.map.JsonMappingException;
-import org.codehaus.jackson.map.ObjectMapper;
-import org.codehaus.jackson.type.TypeReference;
public class QpidRestTestCase extends QpidBrokerTestCase
{
- private static final Logger LOGGER = Logger.getLogger(QpidRestTestCase.class);
-
public static final String[] EXPECTED_HOSTS = { "development", "test", "localhost" };
public static final String[] EXPECTED_QUEUES = { "queue", "ping" };
public static final String[] EXPECTED_EXCHANGES = { "amq.fanout", "amq.match", "amq.direct", "amq.topic",
"qpid.management", "<<default>>" };
- private int _httpPort;
- private String _hostName;
- private List<HttpURLConnection> _httpConnections;
+ private RestTestHelper _restTestHelper = new RestTestHelper(findFreePort());
@Override
public void setUp() throws Exception
{
- _httpConnections = new ArrayList<HttpURLConnection>();
- _hostName = InetAddress.getLocalHost().getHostName();
- _httpPort = findFreePort();
customizeConfiguration();
super.setUp();
-
- }
-
- protected void customizeConfiguration() throws ConfigurationException, IOException
- {
- setConfigurationProperty("management.enabled", "false");
- setConfigurationProperty("management.http.enabled", "true");
- setConfigurationProperty("management.https.enabled", "false");
- setConfigurationProperty("management.http.port", Integer.toString(_httpPort));
- }
-
- public void teearDown() throws Exception
- {
- for (HttpURLConnection connection : _httpConnections)
- {
- try
- {
- connection.disconnect();
- }
- catch (Exception e)
- {
- // ignore
- }
- }
- super.tearDown();
- }
-
- protected int getHttpPort()
- {
- return _httpPort;
- }
-
- protected String getHostName()
- {
- return _hostName;
- }
-
- protected String getProtocol()
- {
- return "http";
- }
-
- protected String getManagementURL()
- {
- return getProtocol() + "://" + getHostName() + ":" + getHttpPort();
- }
-
- protected URL getManagementURL(String path) throws MalformedURLException
- {
- return new URL(getManagementURL() + path);
- }
-
- protected HttpURLConnection openManagementConection(String path) throws IOException
- {
- URL url = getManagementURL(path);
- HttpURLConnection httpCon = (HttpURLConnection) url.openConnection();
- httpCon.setDoOutput(true);
- return httpCon;
- }
-
- protected HttpURLConnection openManagementConection(String path, String method) throws IOException
- {
- HttpURLConnection httpCon = openManagementConection(path);
- httpCon.setRequestMethod(method);
- return httpCon;
}
- protected List<Map<String, Object>> readJsonResponseAsList(HttpURLConnection connection) throws IOException,
- JsonParseException, JsonMappingException
- {
- byte[] data = readConnectionInputStream(connection);
-
- ObjectMapper mapper = new ObjectMapper();
-
- TypeReference<List<LinkedHashMap<String, Object>>> typeReference = new TypeReference<List<LinkedHashMap<String, Object>>>()
- {
- };
- List<Map<String, Object>> providedObject = mapper.readValue(new ByteArrayInputStream(data), typeReference);
- return providedObject;
- }
-
- protected Map<String, Object> readJsonResponseAsMap(HttpURLConnection connection) throws IOException,
- JsonParseException, JsonMappingException
- {
- byte[] data = readConnectionInputStream(connection);
-
- ObjectMapper mapper = new ObjectMapper();
-
- TypeReference<LinkedHashMap<String, Object>> typeReference = new TypeReference<LinkedHashMap<String, Object>>()
- {
- };
- Map<String, Object> providedObject = mapper.readValue(new ByteArrayInputStream(data), typeReference);
- return providedObject;
- }
-
- protected byte[] readConnectionInputStream(HttpURLConnection connection) throws IOException
- {
- InputStream is = connection.getInputStream();
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- byte[] buffer = new byte[1024];
- int len = -1;
- while ((len = is.read(buffer)) != -1)
- {
- baos.write(buffer, 0, len);
- }
- if (LOGGER.isTraceEnabled())
- {
- LOGGER.trace("RESPONSE:" + new String(baos.toByteArray()));
- }
- return baos.toByteArray();
- }
-
- protected void writeJsonRequest(HttpURLConnection connection, Map<String, Object> data) throws JsonGenerationException,
- JsonMappingException, IOException
- {
- ObjectMapper mapper = new ObjectMapper();
- mapper.writeValue(connection.getOutputStream(), data);
- }
-
- protected Map<String, Object> find(String name, Object value, List<Map<String, Object>> data)
+ @Override
+ protected void tearDown() throws Exception
{
- for (Map<String, Object> map : data)
+ try
{
- Object mapValue = map.get(name);
- if (value.equals(mapValue))
- {
- return map;
- }
+ super.tearDown();
}
- return null;
- }
-
- protected Map<String, Object> find(Map<String, Object> searchAttributes, List<Map<String, Object>> data)
- {
- for (Map<String, Object> map : data)
+ finally
{
- boolean equals = true;
- for (Map.Entry<String, Object> entry : searchAttributes.entrySet())
- {
- Object mapValue = map.get(entry.getKey());
- if (!entry.getValue().equals(mapValue))
- {
- equals = false;
- break;
- }
- }
- if (equals)
- {
- return map;
- }
+ getRestTestHelper().tearDown();
}
- return null;
}
- protected Map<String, Object> getJsonAsSingletonList(String path) throws IOException
- {
- List<Map<String, Object>> response = getJsonAsList(path);
-
- assertNotNull("Response cannot be null", response);
- assertEquals("Unexpected response", 1, response.size());
- return response.get(0);
- }
-
- protected List<Map<String, Object>> getJsonAsList(String path) throws IOException, JsonParseException,
- JsonMappingException
+ protected void customizeConfiguration() throws ConfigurationException, IOException
{
- HttpURLConnection connection = openManagementConection(path, "GET");
- connection.connect();
- List<Map<String, Object>> response = readJsonResponseAsList(connection);
- return response;
+ setConfigurationProperty("management.enabled", "false");
+ setConfigurationProperty("management.http.enabled", "true");
+ setConfigurationProperty("management.https.enabled", "false");
+ setConfigurationProperty("management.http.port", Integer.toString(_restTestHelper.getHttpPort()));
}
- protected Map<String, Object> getJsonAsMap(String path) throws IOException
+ public RestTestHelper getRestTestHelper()
{
- HttpURLConnection connection = openManagementConection(path, "GET");
- connection.connect();
- Map<String, Object> response = readJsonResponseAsMap(connection);
- return response;
+ return _restTestHelper;
}
}
diff --git a/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/QueueRestTest.java b/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/QueueRestTest.java
index 5f11b3fb1d..d7732af688 100644
--- a/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/QueueRestTest.java
+++ b/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/QueueRestTest.java
@@ -80,7 +80,7 @@ public class QueueRestTest extends QpidRestTestCase
public void testGetVirtualHostQueues() throws Exception
{
String queueName = getTestQueueName();
- List<Map<String, Object>> queues = getJsonAsList("/rest/queue/test");
+ List<Map<String, Object>> queues = getRestTestHelper().getJsonAsList("/rest/queue/test");
assertEquals("Unexpected number of queues", EXPECTED_QUEUES.length + 1, queues.size());
String[] expectedQueues = new String[EXPECTED_QUEUES.length + 1];
System.arraycopy(EXPECTED_QUEUES, 0, expectedQueues, 0, EXPECTED_QUEUES.length);
@@ -88,7 +88,7 @@ public class QueueRestTest extends QpidRestTestCase
for (String name : expectedQueues)
{
- Map<String, Object> queueDetails = find(Queue.NAME, name, queues);
+ Map<String, Object> queueDetails = getRestTestHelper().find(Queue.NAME, name, queues);
Asserts.assertQueue(name, "standard", queueDetails);
@SuppressWarnings("unchecked")
@@ -96,8 +96,8 @@ public class QueueRestTest extends QpidRestTestCase
assertNotNull("Queue bindings are not found", bindings);
assertEquals("Unexpected number of bindings", 2, bindings.size());
- Map<String, Object> defaultExchangeBinding = find(Binding.EXCHANGE, "<<default>>", bindings);
- Map<String, Object> directExchangeBinding = find(Binding.EXCHANGE, "amq.direct", bindings);
+ Map<String, Object> defaultExchangeBinding = getRestTestHelper().find(Binding.EXCHANGE, "<<default>>", bindings);
+ Map<String, Object> directExchangeBinding = getRestTestHelper().find(Binding.EXCHANGE, "amq.direct", bindings);
Asserts.assertBinding(name, "<<default>>", defaultExchangeBinding);
Asserts.assertBinding(name, "amq.direct", directExchangeBinding);
}
@@ -106,7 +106,7 @@ public class QueueRestTest extends QpidRestTestCase
public void testGetByName() throws Exception
{
String queueName = getTestQueueName();
- Map<String, Object> queueDetails = getJsonAsSingletonList("/rest/queue/test/" + queueName);
+ Map<String, Object> queueDetails = getRestTestHelper().getJsonAsSingletonList("/rest/queue/test/" + queueName);
Asserts.assertQueue(queueName, "standard", queueDetails);
assertStatistics(queueDetails);
@@ -115,8 +115,8 @@ public class QueueRestTest extends QpidRestTestCase
assertNotNull("Queue bindings are not found", bindings);
assertEquals("Unexpected number of bindings", 2, bindings.size());
- Map<String, Object> defaultExchangeBinding = find(Binding.EXCHANGE, "<<default>>", bindings);
- Map<String, Object> directExchangeBinding = find(Binding.EXCHANGE, "amq.direct", bindings);
+ Map<String, Object> defaultExchangeBinding = getRestTestHelper().find(Binding.EXCHANGE, "<<default>>", bindings);
+ Map<String, Object> directExchangeBinding = getRestTestHelper().find(Binding.EXCHANGE, "amq.direct", bindings);
Asserts.assertBinding(queueName, "<<default>>", defaultExchangeBinding);
Asserts.assertBinding(queueName, "amq.direct", directExchangeBinding);
@@ -138,7 +138,7 @@ public class QueueRestTest extends QpidRestTestCase
createBinding(bindingName, exchanges[i], queueName);
}
- Map<String, Object> queueDetails = getJsonAsSingletonList("/rest/queue/test/" + queueName);
+ Map<String, Object> queueDetails = getRestTestHelper().getJsonAsSingletonList("/rest/queue/test/" + queueName);
Asserts.assertQueue(queueName, "standard", queueDetails);
@SuppressWarnings("unchecked")
@@ -152,14 +152,14 @@ public class QueueRestTest extends QpidRestTestCase
for (int i = 0; i < exchanges.length; i++)
{
searchAttributes.put(Binding.EXCHANGE, exchanges[i]);
- Map<String, Object> binding = find(searchAttributes, bindings);
+ Map<String, Object> binding = getRestTestHelper().find(searchAttributes, bindings);
Asserts.assertBinding(bindingName, queueName, exchanges[i], binding);
}
}
private void createBinding(String bindingName, String exchangeName, String queueName) throws IOException
{
- HttpURLConnection connection = openManagementConection(
+ HttpURLConnection connection = getRestTestHelper().openManagementConnection(
"/rest/binding/test/" + URLDecoder.decode(exchangeName, "UTF-8") + "/" + queueName + "/" + bindingName,
"PUT");
@@ -168,7 +168,7 @@ public class QueueRestTest extends QpidRestTestCase
bindingData.put(Binding.EXCHANGE, exchangeName);
bindingData.put(Binding.QUEUE, queueName);
- writeJsonRequest(connection, bindingData);
+ getRestTestHelper().writeJsonRequest(connection, bindingData);
assertEquals("Unexpected response code", 201, connection.getResponseCode());
connection.disconnect();
diff --git a/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/RestTestHelper.java b/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/RestTestHelper.java
new file mode 100644
index 0000000000..8a323c0639
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/RestTestHelper.java
@@ -0,0 +1,417 @@
+/*
+ * 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.management.plugin.servlet.rest;
+
+import java.io.BufferedWriter;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLDecoder;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLSocketFactory;
+import javax.servlet.http.HttpServletResponse;
+
+import junit.framework.Assert;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.log4j.Logger;
+import org.apache.qpid.test.utils.QpidBrokerTestCase;
+import org.codehaus.jackson.JsonGenerationException;
+import org.codehaus.jackson.JsonParseException;
+import org.codehaus.jackson.map.JsonMappingException;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.type.TypeReference;
+
+public class RestTestHelper
+{
+ private static final Logger LOGGER = Logger.getLogger(RestTestHelper.class);
+
+ private int _httpPort;
+
+ private boolean _useSsl;
+
+ private String _username;
+
+ private String _password;
+
+ private File _passwdFile;
+
+ public RestTestHelper(int httpPort)
+ {
+ _httpPort = httpPort;
+ }
+
+ public int getHttpPort()
+ {
+ return _httpPort;
+ }
+
+ private String getHostName()
+ {
+ return "localhost";
+ }
+
+ private String getProtocol()
+ {
+ return _useSsl ? "https" : "http";
+ }
+
+ public String getManagementURL()
+ {
+ return getProtocol() + "://" + getHostName() + ":" + getHttpPort();
+ }
+
+ public URL getManagementURL(String path) throws MalformedURLException
+ {
+ return new URL(getManagementURL() + path);
+ }
+
+ public HttpURLConnection openManagementConnection(String path, String method) throws IOException
+ {
+ URL url = getManagementURL(path);
+ HttpURLConnection httpCon = (HttpURLConnection) url.openConnection();
+ if(_useSsl)
+ {
+ ((HttpsURLConnection) httpCon).setSSLSocketFactory((SSLSocketFactory) SSLSocketFactory.getDefault());
+ }
+ if(_username != null)
+ {
+ String encoded = new String(new Base64().encode((_username + ":" + _password).getBytes()));
+ httpCon.setRequestProperty("Authorization", "Basic " + encoded);
+ }
+ httpCon.setDoOutput(true);
+ httpCon.setRequestMethod(method);
+ return httpCon;
+ }
+
+ public List<Map<String, Object>> readJsonResponseAsList(HttpURLConnection connection) throws IOException,
+ JsonParseException, JsonMappingException
+ {
+ byte[] data = readConnectionInputStream(connection);
+
+ ObjectMapper mapper = new ObjectMapper();
+
+ TypeReference<List<LinkedHashMap<String, Object>>> typeReference = new TypeReference<List<LinkedHashMap<String, Object>>>()
+ {
+ };
+ List<Map<String, Object>> providedObject = mapper.readValue(new ByteArrayInputStream(data), typeReference);
+ return providedObject;
+ }
+
+ public Map<String, Object> readJsonResponseAsMap(HttpURLConnection connection) throws IOException,
+ JsonParseException, JsonMappingException
+ {
+ byte[] data = readConnectionInputStream(connection);
+
+ ObjectMapper mapper = new ObjectMapper();
+
+ TypeReference<LinkedHashMap<String, Object>> typeReference = new TypeReference<LinkedHashMap<String, Object>>()
+ {
+ };
+ Map<String, Object> providedObject = mapper.readValue(new ByteArrayInputStream(data), typeReference);
+ return providedObject;
+ }
+
+ public byte[] readConnectionInputStream(HttpURLConnection connection) throws IOException
+ {
+ InputStream is = connection.getInputStream();
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ byte[] buffer = new byte[1024];
+ int len = -1;
+ while ((len = is.read(buffer)) != -1)
+ {
+ baos.write(buffer, 0, len);
+ }
+ if (LOGGER.isTraceEnabled())
+ {
+ LOGGER.trace("RESPONSE:" + new String(baos.toByteArray()));
+ }
+ return baos.toByteArray();
+ }
+
+ public void writeJsonRequest(HttpURLConnection connection, Map<String, Object> data) throws JsonGenerationException,
+ JsonMappingException, IOException
+ {
+ ObjectMapper mapper = new ObjectMapper();
+ mapper.writeValue(connection.getOutputStream(), data);
+ }
+
+ public Map<String, Object> find(String name, Object value, List<Map<String, Object>> data)
+ {
+ for (Map<String, Object> map : data)
+ {
+ Object mapValue = map.get(name);
+ if (value.equals(mapValue))
+ {
+ return map;
+ }
+ }
+ return null;
+ }
+
+ public Map<String, Object> find(Map<String, Object> searchAttributes, List<Map<String, Object>> data)
+ {
+ for (Map<String, Object> map : data)
+ {
+ boolean equals = true;
+ for (Map.Entry<String, Object> entry : searchAttributes.entrySet())
+ {
+ Object mapValue = map.get(entry.getKey());
+ if (!entry.getValue().equals(mapValue))
+ {
+ equals = false;
+ break;
+ }
+ }
+ if (equals)
+ {
+ return map;
+ }
+ }
+ return null;
+ }
+
+ public Map<String, Object> getJsonAsSingletonList(String path) throws IOException
+ {
+ List<Map<String, Object>> response = getJsonAsList(path);
+
+ Assert.assertNotNull("Response cannot be null", response);
+ Assert.assertEquals("Unexpected response", 1, response.size());
+ return response.get(0);
+ }
+
+ public List<Map<String, Object>> getJsonAsList(String path) throws IOException, JsonParseException,
+ JsonMappingException
+ {
+ HttpURLConnection connection = openManagementConnection(path, "GET");
+ connection.connect();
+ List<Map<String, Object>> response = readJsonResponseAsList(connection);
+ return response;
+ }
+
+ public Map<String, Object> getJsonAsMap(String path) throws IOException
+ {
+ HttpURLConnection connection = openManagementConnection(path, "GET");
+ connection.connect();
+ Map<String, Object> response = readJsonResponseAsMap(connection);
+ return response;
+ }
+
+ public void createNewGroupMember(String groupProviderName, String groupName, String memberName, int responseCode) throws IOException
+ {
+ HttpURLConnection connection = openManagementConnection(
+ "/rest/groupmember/" + URLDecoder.decode(groupProviderName, "UTF-8") + "/"+ URLDecoder.decode(groupName, "UTF-8") + "/" + URLDecoder.decode(memberName, "UTF-8"),
+ "PUT");
+
+ Map<String, Object> groupMemberData = new HashMap<String, Object>();
+ // TODO add type
+ writeJsonRequest(connection, groupMemberData);
+
+ Assert.assertEquals("Unexpected response code", responseCode, connection.getResponseCode());
+
+ connection.disconnect();
+ }
+
+ public void createNewGroupMember(String groupProviderName, String groupName, String memberName) throws IOException
+ {
+ createNewGroupMember(groupProviderName, groupName, memberName, HttpServletResponse.SC_CREATED);
+ }
+
+ public void removeMemberFromGroup(String groupProviderName, String groupName, String memberName, int responseCode) throws IOException
+ {
+ HttpURLConnection connection = openManagementConnection(
+ "/rest/groupmember/" + URLDecoder.decode(groupProviderName, "UTF-8") + "/"+ URLDecoder.decode(groupName, "UTF-8") + "/" + URLDecoder.decode(memberName, "UTF-8"),
+ "DELETE");
+
+ Assert.assertEquals("Unexpected response code", responseCode, connection.getResponseCode());
+
+ connection.disconnect();
+ }
+
+ public void removeMemberFromGroup(String groupProviderName, String groupName, String memberName) throws IOException
+ {
+ removeMemberFromGroup(groupProviderName, groupName, memberName, HttpServletResponse.SC_OK);
+ }
+
+ public void assertNumberOfGroupMembers(Map<String, Object> data, int expectedNumberOfGroupMembers)
+ {
+ List<Map<String, Object>> groups = (List<Map<String, Object>>) data.get("groupmembers");
+ if (groups == null)
+ {
+ groups = Collections.emptyList();
+ }
+
+ Assert.assertEquals("Unexpected number of group members", expectedNumberOfGroupMembers, groups.size());
+ }
+
+ public void createGroup(String groupName, String groupProviderName) throws IOException
+ {
+ createGroup(groupName, groupProviderName, HttpServletResponse.SC_CREATED);
+ }
+
+ public void createGroup(String groupName, String groupProviderName, int responseCode) throws IOException
+ {
+ HttpURLConnection connection = openManagementConnection(
+ "/rest/group/" + URLDecoder.decode(groupProviderName, "UTF-8") + "/"+ URLDecoder.decode(groupName, "UTF-8"),
+ "PUT");
+
+ Map<String, Object> groupData = new HashMap<String, Object>();
+ writeJsonRequest(connection, groupData);
+
+ Assert.assertEquals("Unexpected response code", responseCode, connection.getResponseCode());
+
+ connection.disconnect();
+ }
+
+ public void createOrUpdateUser(String username, String password) throws IOException
+ {
+ createOrUpdateUser(username, password, HttpServletResponse.SC_CREATED);
+ }
+
+ public void createOrUpdateUser(String username, String password, int responseCode) throws IOException
+ {
+ HttpURLConnection connection = openManagementConnection("/rest/user/PrincipalDatabaseAuthenticationManager/" + username, "PUT");
+
+ Map<String, Object> data = new HashMap<String, Object>();
+ data.put("password", password);
+ writeJsonRequest(connection, data);
+
+ Assert.assertEquals("Unexpected response code", responseCode, connection.getResponseCode());
+
+ connection.disconnect();
+ }
+
+ public void removeGroup(String groupName, String groupProviderName, int responseCode) throws IOException
+ {
+ HttpURLConnection connection = openManagementConnection(
+ "/rest/group/" + URLDecoder.decode(groupProviderName, "UTF-8") + "/"+ URLDecoder.decode(groupName, "UTF-8"),
+ "DELETE");
+
+ Assert.assertEquals("Unexpected response code", responseCode, connection.getResponseCode());
+ connection.disconnect();
+ }
+
+ public void removeGroup(String groupName, String groupProviderName) throws IOException
+ {
+ removeGroup(groupName, groupProviderName, HttpServletResponse.SC_OK);
+ }
+
+ public void removeUserById(String id) throws IOException
+ {
+ HttpURLConnection connection = openManagementConnection("/rest/user/PrincipalDatabaseAuthenticationManager?id=" + id, "DELETE");
+ Assert.assertEquals("Unexpected response code", HttpServletResponse.SC_OK, connection.getResponseCode());
+ connection.disconnect();
+ }
+
+ public void removeUser(String username, int responseCode) throws IOException
+ {
+ HttpURLConnection connection = openManagementConnection("/rest/user/PrincipalDatabaseAuthenticationManager/" + username, "DELETE");
+ Assert.assertEquals("Unexpected response code", responseCode, connection.getResponseCode());
+ connection.disconnect();
+ }
+
+ public void removeUser(String username) throws IOException
+ {
+ removeUser(username, HttpServletResponse.SC_OK);
+ }
+
+ public void assertNumberOfGroups(Map<String, Object> data, int expectedNumberOfGroups)
+ {
+ List<Map<String, Object>> groups = (List<Map<String, Object>>) data.get("groups");
+ if (groups == null)
+ {
+ groups = Collections.emptyList();
+ }
+ Assert.assertEquals("Unexpected number of groups", expectedNumberOfGroups, groups.size());
+ }
+
+ public void setUseSsl(boolean useSsl)
+ {
+ _useSsl = useSsl;
+ }
+
+ public void setUsernameAndPassword(String username, String password)
+ {
+ _username = username;
+ _password = password;
+ }
+
+ /**
+ * Create password file that follows the convention username=password, which is deleted by {@link #tearDown()}
+ */
+ public void configureTemporaryPasswordFile(QpidBrokerTestCase testCase, String... users) throws ConfigurationException, IOException
+ {
+ _passwdFile = createTemporaryPasswdFile(users);
+
+ testCase.setConfigurationProperty("security.pd-auth-manager.principal-database.attributes.attribute.name", "passwordFile");
+ testCase.setConfigurationProperty("security.pd-auth-manager.principal-database.attributes.attribute.value", _passwdFile.getAbsolutePath());
+ }
+
+ public void tearDown()
+ {
+ if (_passwdFile != null)
+ {
+ if (_passwdFile.exists())
+ {
+ _passwdFile.delete();
+ }
+ }
+ }
+
+ private File createTemporaryPasswdFile(String[] users) throws IOException
+ {
+ BufferedWriter writer = null;
+ try
+ {
+ File testFile = File.createTempFile(this.getClass().getName(),"tmp");
+ testFile.deleteOnExit();
+
+ writer = new BufferedWriter(new FileWriter(testFile));
+ for (int i = 0; i < users.length; i++)
+ {
+ String username = users[i];
+ writer.write(username + ":" + username);
+ writer.newLine();
+ }
+
+ return testFile;
+
+ }
+ finally
+ {
+ if (writer != null)
+ {
+ writer.close();
+ }
+ }
+ }
+}
diff --git a/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/SaslRestTest.java b/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/SaslRestTest.java
index b504c9fa60..d65b06e6a6 100644
--- a/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/SaslRestTest.java
+++ b/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/SaslRestTest.java
@@ -27,7 +27,7 @@ public class SaslRestTest extends QpidRestTestCase
{
public void testGet() throws Exception
{
- Map<String, Object> saslData = getJsonAsMap("/rest/sasl");
+ Map<String, Object> saslData = getRestTestHelper().getJsonAsMap("/rest/sasl");
assertNotNull("mechanisms attribute is not found", saslData.get("mechanisms"));
@SuppressWarnings("unchecked")
diff --git a/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/StructureRestTest.java b/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/StructureRestTest.java
index b01e1d44b8..c72dcfc8ab 100644
--- a/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/StructureRestTest.java
+++ b/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/StructureRestTest.java
@@ -28,7 +28,7 @@ public class StructureRestTest extends QpidRestTestCase
public void testGet() throws Exception
{
- Map<String, Object> structure = getJsonAsMap("/rest/structure");
+ Map<String, Object> structure = getRestTestHelper().getJsonAsMap("/rest/structure");
assertNotNull("Structure data cannot be null", structure);
assertNode(structure, "Broker");
@@ -46,7 +46,7 @@ public class StructureRestTest extends QpidRestTestCase
for (String hostName : EXPECTED_HOSTS)
{
- Map<String, Object> host = find("name", hostName, virtualhosts);
+ Map<String, Object> host = getRestTestHelper().find("name", hostName, virtualhosts);
assertNotNull("Host " + hostName + " is not found ", host);
assertNode(host, hostName);
@@ -55,7 +55,7 @@ public class StructureRestTest extends QpidRestTestCase
assertNotNull("Host " + hostName + " queues are not found ", queues);
for (String queueName : EXPECTED_QUEUES)
{
- Map<String, Object> queue = find("name", queueName, queues);
+ Map<String, Object> queue = getRestTestHelper().find("name", queueName, queues);
assertNotNull(hostName + " queue " + queueName + " is not found ", queue);
assertNode(queue, queueName);
@@ -73,7 +73,7 @@ public class StructureRestTest extends QpidRestTestCase
assertNotNull("Host " + hostName + " exchanges are not found ", exchanges);
for (String exchangeName : EXPECTED_EXCHANGES)
{
- Map<String, Object> exchange = find("name", exchangeName, exchanges);
+ Map<String, Object> exchange = getRestTestHelper().find("name", exchangeName, exchanges);
assertNotNull("Exchange " + exchangeName + " is not found ", exchange);
assertNode(exchange, exchangeName);
if ("amq.direct".equalsIgnoreCase(exchangeName) || "<<default>>".equalsIgnoreCase(exchangeName))
@@ -83,7 +83,7 @@ public class StructureRestTest extends QpidRestTestCase
assertNotNull(hostName + " exchange " + exchangeName + " bindings are not found ", bindings);
for (String queueName : EXPECTED_QUEUES)
{
- Map<String, Object> binding = find("name", queueName, bindings);
+ Map<String, Object> binding = getRestTestHelper().find("name", queueName, bindings);
assertNotNull(hostName + " exchange " + exchangeName + " binding " + queueName + " is not found", binding);
assertNode(binding, queueName);
}
@@ -97,11 +97,11 @@ public class StructureRestTest extends QpidRestTestCase
assertNode(aliases.get(0), hostName);
}
- int[] expectedPorts = { getPort(), getHttpPort() };
+ int[] expectedPorts = { getPort(), getRestTestHelper().getHttpPort() };
for (int port : expectedPorts)
{
String portName = "0.0.0.0:" + port;
- Map<String, Object> portData = find("name", portName, ports);
+ Map<String, Object> portData = getRestTestHelper().find("name", portName, ports);
assertNotNull("Port " + portName + " is not found ", portData);
assertNode(portData, portName);
}
diff --git a/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/UserRestTest.java b/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/UserRestTest.java
index e56fa27e21..037d26a7bd 100644
--- a/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/UserRestTest.java
+++ b/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/UserRestTest.java
@@ -20,8 +20,6 @@
*/
package org.apache.qpid.server.management.plugin.servlet.rest;
-import java.net.HttpURLConnection;
-import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -29,9 +27,17 @@ import org.apache.qpid.server.model.User;
public class UserRestTest extends QpidRestTestCase
{
+ @Override
+ public void setUp() throws Exception
+ {
+ getRestTestHelper().configureTemporaryPasswordFile(this, "user1", "user2");
+
+ super.setUp(); // do this last because it starts the broker, using the modified config
+ }
+
public void testGet() throws Exception
{
- List<Map<String, Object>> users = getJsonAsList("/rest/user");
+ List<Map<String, Object>> users = getRestTestHelper().getJsonAsList("/rest/user");
assertNotNull("Users cannot be null", users);
assertTrue("Unexpected number of users", users.size() > 1);
for (Map<String, Object> user : users)
@@ -42,7 +48,7 @@ public class UserRestTest extends QpidRestTestCase
public void testGetUserByName() throws Exception
{
- List<Map<String, Object>> users = getJsonAsList("/rest/user");
+ List<Map<String, Object>> users = getRestTestHelper().getJsonAsList("/rest/user");
assertNotNull("Users cannot be null", users);
assertTrue("Unexpected number of users", users.size() > 1);
for (Map<String, Object> user : users)
@@ -50,7 +56,7 @@ public class UserRestTest extends QpidRestTestCase
assertNotNull("Attribute " + User.ID, user.get(User.ID));
String userName = (String) user.get(User.NAME);
assertNotNull("Attribute " + User.NAME, userName);
- Map<String, Object> userDetails = getJsonAsSingletonList("/rest/user/PrincipalDatabaseAuthenticationManager/"
+ Map<String, Object> userDetails = getRestTestHelper().getJsonAsSingletonList("/rest/user/PrincipalDatabaseAuthenticationManager/"
+ userName);
assertUser(userDetails);
assertEquals("Unexpected user name", userName, userDetails.get(User.NAME));
@@ -60,19 +66,9 @@ public class UserRestTest extends QpidRestTestCase
public void testPut() throws Exception
{
String userName = getTestName();
- HttpURLConnection connection = openManagementConection("/rest/user/PrincipalDatabaseAuthenticationManager/"
- + userName, "PUT");
-
- Map<String, Object> userData = new HashMap<String, Object>();
- userData.put(User.NAME, userName);
- userData.put(User.PASSWORD, userName);
+ getRestTestHelper().createOrUpdateUser(userName, "newPassword");
- writeJsonRequest(connection, userData);
- assertEquals("Unexpected response code", 201, connection.getResponseCode());
-
- connection.disconnect();
-
- Map<String, Object> userDetails = getJsonAsSingletonList("/rest/user/PrincipalDatabaseAuthenticationManager/"
+ Map<String, Object> userDetails = getRestTestHelper().getJsonAsSingletonList("/rest/user/PrincipalDatabaseAuthenticationManager/"
+ userName);
assertUser(userDetails);
assertEquals("Unexpected user name", userName, userDetails.get(User.NAME));
@@ -80,27 +76,16 @@ public class UserRestTest extends QpidRestTestCase
public void testDelete() throws Exception
{
- // add user
String userName = getTestName();
- HttpURLConnection connection = openManagementConection("/rest/user/PrincipalDatabaseAuthenticationManager/"
- + userName, "PUT");
-
- Map<String, Object> userData = new HashMap<String, Object>();
- userData.put(User.NAME, userName);
- userData.put(User.PASSWORD, userName);
+ getRestTestHelper().createOrUpdateUser(userName, "newPassword");
- writeJsonRequest(connection, userData);
- assertEquals("Unexpected response code", 201, connection.getResponseCode());
- connection.disconnect();
-
- Map<String, Object> userDetails = getJsonAsSingletonList("/rest/user/PrincipalDatabaseAuthenticationManager/"
+ Map<String, Object> userDetails = getRestTestHelper().getJsonAsSingletonList("/rest/user/PrincipalDatabaseAuthenticationManager/"
+ userName);
String id = (String) userDetails.get(User.ID);
- connection = openManagementConection("/rest/user/PrincipalDatabaseAuthenticationManager?id=" + id, "DELETE");
- connection.connect();
- assertEquals("Unexpected response code", 200, connection.getResponseCode());
- List<Map<String, Object>> users = getJsonAsList("/rest/user/PrincipalDatabaseAuthenticationManager/" + userName);
+ getRestTestHelper().removeUserById(id);
+
+ List<Map<String, Object>> users = getRestTestHelper().getJsonAsList("/rest/user/PrincipalDatabaseAuthenticationManager/" + userName);
assertEquals("User should be deleted", 0, users.size());
}
diff --git a/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/VirtualHostRestTest.java b/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/VirtualHostRestTest.java
index 17f1aaaf7b..4bd936a948 100644
--- a/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/VirtualHostRestTest.java
+++ b/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/VirtualHostRestTest.java
@@ -46,12 +46,12 @@ public class VirtualHostRestTest extends QpidRestTestCase
public void testGet() throws Exception
{
- List<Map<String, Object>> hosts = getJsonAsList("/rest/virtualhost/");
+ List<Map<String, Object>> hosts = getRestTestHelper().getJsonAsList("/rest/virtualhost/");
assertNotNull("Hosts data cannot be null", hosts);
assertEquals("Unexpected number of hosts", 3, hosts.size());
for (String hostName : EXPECTED_HOSTS)
{
- Map<String, Object> host = find("name", hostName, hosts);
+ Map<String, Object> host = getRestTestHelper().find("name", hostName, hosts);
Asserts.assertVirtualHost(hostName, host);
}
}
@@ -62,7 +62,7 @@ public class VirtualHostRestTest extends QpidRestTestCase
_connection = (AMQConnection) getConnection();
_connection.createSession(true, Session.SESSION_TRANSACTED);
- Map<String, Object> hostDetails = getJsonAsSingletonList("/rest/virtualhost/test");
+ Map<String, Object> hostDetails = getRestTestHelper().getJsonAsSingletonList("/rest/virtualhost/test");
Asserts.assertVirtualHost("test", hostDetails);
@SuppressWarnings("unchecked")
@@ -74,18 +74,18 @@ public class VirtualHostRestTest extends QpidRestTestCase
@SuppressWarnings("unchecked")
List<Map<String, Object>> exchanges = (List<Map<String, Object>>) hostDetails.get(VIRTUALHOST_EXCHANGES_ATTRIBUTE);
assertEquals("Unexpected number of exchanges", 6, exchanges.size());
- Asserts.assertDurableExchange("amq.fanout", "fanout", find(Exchange.NAME, "amq.fanout", exchanges));
- Asserts.assertDurableExchange("qpid.management", "management", find(Exchange.NAME, "qpid.management", exchanges));
- Asserts.assertDurableExchange("amq.topic", "topic", find(Exchange.NAME, "amq.topic", exchanges));
- Asserts.assertDurableExchange("amq.direct", "direct", find(Exchange.NAME, "amq.direct", exchanges));
- Asserts.assertDurableExchange("amq.match", "headers", find(Exchange.NAME, "amq.match", exchanges));
- Asserts.assertDurableExchange("<<default>>", "direct", find(Exchange.NAME, "<<default>>", exchanges));
+ Asserts.assertDurableExchange("amq.fanout", "fanout", getRestTestHelper().find(Exchange.NAME, "amq.fanout", exchanges));
+ Asserts.assertDurableExchange("qpid.management", "management", getRestTestHelper().find(Exchange.NAME, "qpid.management", exchanges));
+ Asserts.assertDurableExchange("amq.topic", "topic", getRestTestHelper().find(Exchange.NAME, "amq.topic", exchanges));
+ Asserts.assertDurableExchange("amq.direct", "direct", getRestTestHelper().find(Exchange.NAME, "amq.direct", exchanges));
+ Asserts.assertDurableExchange("amq.match", "headers", getRestTestHelper().find(Exchange.NAME, "amq.match", exchanges));
+ Asserts.assertDurableExchange("<<default>>", "direct", getRestTestHelper().find(Exchange.NAME, "<<default>>", exchanges));
@SuppressWarnings("unchecked")
List<Map<String, Object>> queues = (List<Map<String, Object>>) hostDetails.get(VIRTUALHOST_QUEUES_ATTRIBUTE);
assertEquals("Unexpected number of queues", 2, queues.size());
- Map<String, Object> queue = find(Queue.NAME, "queue", queues);
- Map<String, Object> ping = find(Queue.NAME, "ping", queues);
+ Map<String, Object> queue = getRestTestHelper().find(Queue.NAME, "queue", queues);
+ Map<String, Object> ping = getRestTestHelper().find(Queue.NAME, "ping", queues);
Asserts.assertQueue("queue", "standard", queue);
Asserts.assertQueue("ping", "standard", ping);
assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.FALSE, queue.get(Queue.DURABLE));
@@ -116,14 +116,14 @@ public class VirtualHostRestTest extends QpidRestTestCase
lvqQueueAttributes.put(Queue.LVQ_KEY, "LVQ");
createQueue(queueName + "-lvq", "lvq", lvqQueueAttributes);
- Map<String, Object> hostDetails = getJsonAsSingletonList("/rest/virtualhost/test");
+ Map<String, Object> hostDetails = getRestTestHelper().getJsonAsSingletonList("/rest/virtualhost/test");
@SuppressWarnings("unchecked")
List<Map<String, Object>> queues = (List<Map<String, Object>>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_QUEUES_ATTRIBUTE);
- Map<String, Object> standardQueue = find(Queue.NAME, queueName + "-standard" , queues);
- Map<String, Object> sortedQueue = find(Queue.NAME, queueName + "-sorted" , queues);
- Map<String, Object> priorityQueue = find(Queue.NAME, queueName + "-priority" , queues);
- Map<String, Object> lvqQueue = find(Queue.NAME, queueName + "-lvq" , queues);
+ Map<String, Object> standardQueue = getRestTestHelper().find(Queue.NAME, queueName + "-standard" , queues);
+ Map<String, Object> sortedQueue = getRestTestHelper().find(Queue.NAME, queueName + "-sorted" , queues);
+ Map<String, Object> priorityQueue = getRestTestHelper().find(Queue.NAME, queueName + "-priority" , queues);
+ Map<String, Object> lvqQueue = getRestTestHelper().find(Queue.NAME, queueName + "-lvq" , queues);
Asserts.assertQueue(queueName + "-standard", "standard", standardQueue);
Asserts.assertQueue(queueName + "-sorted", "sorted", sortedQueue);
@@ -149,14 +149,14 @@ public class VirtualHostRestTest extends QpidRestTestCase
createExchange(exchangeName + "-headers", "headers");
createExchange(exchangeName + "-fanout", "fanout");
- Map<String, Object> hostDetails = getJsonAsSingletonList("/rest/virtualhost/test");
+ Map<String, Object> hostDetails = getRestTestHelper().getJsonAsSingletonList("/rest/virtualhost/test");
@SuppressWarnings("unchecked")
List<Map<String, Object>> exchanges = (List<Map<String, Object>>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_EXCHANGES_ATTRIBUTE);
- Map<String, Object> directExchange = find(Queue.NAME, exchangeName + "-direct" , exchanges);
- Map<String, Object> topicExchange = find(Queue.NAME, exchangeName + "-topic" , exchanges);
- Map<String, Object> headersExchange = find(Queue.NAME, exchangeName + "-headers" , exchanges);
- Map<String, Object> fanoutExchange = find(Queue.NAME, exchangeName + "-fanout" , exchanges);
+ Map<String, Object> directExchange = getRestTestHelper().find(Queue.NAME, exchangeName + "-direct" , exchanges);
+ Map<String, Object> topicExchange = getRestTestHelper().find(Queue.NAME, exchangeName + "-topic" , exchanges);
+ Map<String, Object> headersExchange = getRestTestHelper().find(Queue.NAME, exchangeName + "-headers" , exchanges);
+ Map<String, Object> fanoutExchange = getRestTestHelper().find(Queue.NAME, exchangeName + "-fanout" , exchanges);
Asserts.assertDurableExchange(exchangeName + "-direct", "direct", directExchange);
Asserts.assertDurableExchange(exchangeName + "-topic", "topic", topicExchange);
@@ -175,11 +175,11 @@ public class VirtualHostRestTest extends QpidRestTestCase
String queueName = getTestQueueName()+ "-lvq";
createQueue(queueName, "lvq", null);
- Map<String, Object> hostDetails = getJsonAsSingletonList("/rest/virtualhost/test");
+ Map<String, Object> hostDetails = getRestTestHelper().getJsonAsSingletonList("/rest/virtualhost/test");
@SuppressWarnings("unchecked")
List<Map<String, Object>> queues = (List<Map<String, Object>>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_QUEUES_ATTRIBUTE);
- Map<String, Object> lvqQueue = find(Queue.NAME, queueName , queues);
+ Map<String, Object> lvqQueue = getRestTestHelper().find(Queue.NAME, queueName , queues);
Asserts.assertQueue(queueName , "lvq", lvqQueue);
assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, lvqQueue.get(Queue.DURABLE));
@@ -192,11 +192,11 @@ public class VirtualHostRestTest extends QpidRestTestCase
int responseCode = tryCreateQueue(queueName, "sorted", null);
assertEquals("Unexpected response code", 409, responseCode);
- Map<String, Object> hostDetails = getJsonAsSingletonList("/rest/virtualhost/test");
+ Map<String, Object> hostDetails = getRestTestHelper().getJsonAsSingletonList("/rest/virtualhost/test");
@SuppressWarnings("unchecked")
List<Map<String, Object>> queues = (List<Map<String, Object>>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_QUEUES_ATTRIBUTE);
- Map<String, Object> testQueue = find(Queue.NAME, queueName , queues);
+ Map<String, Object> testQueue = getRestTestHelper().find(Queue.NAME, queueName , queues);
assertNull("Sorted queue without a key was created ", testQueue);
}
@@ -206,11 +206,11 @@ public class VirtualHostRestTest extends QpidRestTestCase
String queueName = getTestQueueName()+ "-priority";
createQueue(queueName, "priority", null);
- Map<String, Object> hostDetails = getJsonAsSingletonList("/rest/virtualhost/test");
+ Map<String, Object> hostDetails = getRestTestHelper().getJsonAsSingletonList("/rest/virtualhost/test");
@SuppressWarnings("unchecked")
List<Map<String, Object>> queues = (List<Map<String, Object>>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_QUEUES_ATTRIBUTE);
- Map<String, Object> priorityQueue = find(Queue.NAME, queueName , queues);
+ Map<String, Object> priorityQueue = getRestTestHelper().find(Queue.NAME, queueName , queues);
Asserts.assertQueue(queueName , "priority", priorityQueue);
assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, priorityQueue.get(Queue.DURABLE));
@@ -222,11 +222,11 @@ public class VirtualHostRestTest extends QpidRestTestCase
String queueName = getTestQueueName();
createQueue(queueName, null, null);
- Map<String, Object> hostDetails = getJsonAsSingletonList("/rest/virtualhost/test");
+ Map<String, Object> hostDetails = getRestTestHelper().getJsonAsSingletonList("/rest/virtualhost/test");
@SuppressWarnings("unchecked")
List<Map<String, Object>> queues = (List<Map<String, Object>>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_QUEUES_ATTRIBUTE);
- Map<String, Object> queue = find(Queue.NAME, queueName , queues);
+ Map<String, Object> queue = getRestTestHelper().find(Queue.NAME, queueName , queues);
Asserts.assertQueue(queueName , "standard", queue);
}
@@ -237,11 +237,11 @@ public class VirtualHostRestTest extends QpidRestTestCase
int responseCode = tryCreateQueue(queueName, "unsupported", null);
assertEquals("Unexpected response code", 409, responseCode);
- Map<String, Object> hostDetails = getJsonAsSingletonList("/rest/virtualhost/test");
+ Map<String, Object> hostDetails = getRestTestHelper().getJsonAsSingletonList("/rest/virtualhost/test");
@SuppressWarnings("unchecked")
List<Map<String, Object>> queues = (List<Map<String, Object>>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_QUEUES_ATTRIBUTE);
- Map<String, Object> queue = find(Queue.NAME, queueName , queues);
+ Map<String, Object> queue = getRestTestHelper().find(Queue.NAME, queueName , queues);
assertNull("Queue of unsupported type was created", queue);
}
@@ -251,10 +251,10 @@ public class VirtualHostRestTest extends QpidRestTestCase
String queueName = getTestQueueName();
createQueue(queueName, null, null);
- HttpURLConnection connection = openManagementConection("/rest/queue/test/" + queueName, "DELETE");
+ HttpURLConnection connection = getRestTestHelper().openManagementConnection("/rest/queue/test/" + queueName, "DELETE");
connection.connect();
assertEquals("Unexpected response code", 200, connection.getResponseCode());
- List<Map<String, Object>> queues = getJsonAsList("/rest/queue/test/" + queueName);
+ List<Map<String, Object>> queues = getRestTestHelper().getJsonAsList("/rest/queue/test/" + queueName);
assertEquals("Queue should be deleted", 0, queues.size());
}
@@ -262,12 +262,12 @@ public class VirtualHostRestTest extends QpidRestTestCase
{
String queueName = getTestQueueName();
createQueue(queueName, null, null);
- Map<String, Object> queueDetails = getJsonAsSingletonList("/rest/queue/test/" + queueName);
+ Map<String, Object> queueDetails = getRestTestHelper().getJsonAsSingletonList("/rest/queue/test/" + queueName);
- HttpURLConnection connection = openManagementConection("/rest/queue/test?id=" + queueDetails.get(Queue.ID), "DELETE");
+ HttpURLConnection connection = getRestTestHelper().openManagementConnection("/rest/queue/test?id=" + queueDetails.get(Queue.ID), "DELETE");
connection.connect();
assertEquals("Unexpected response code", 200, connection.getResponseCode());
- List<Map<String, Object>> queues = getJsonAsList("/rest/queue/test/" + queueName);
+ List<Map<String, Object>> queues = getRestTestHelper().getJsonAsList("/rest/queue/test/" + queueName);
assertEquals("Queue should be deleted", 0, queues.size());
}
@@ -276,10 +276,10 @@ public class VirtualHostRestTest extends QpidRestTestCase
String exchangeName = getTestName();
createExchange(exchangeName, "direct");
- HttpURLConnection connection = openManagementConection("/rest/exchange/test/" + exchangeName, "DELETE");
+ HttpURLConnection connection = getRestTestHelper().openManagementConnection("/rest/exchange/test/" + exchangeName, "DELETE");
connection.connect();
assertEquals("Unexpected response code", 200, connection.getResponseCode());
- List<Map<String, Object>> queues = getJsonAsList("/rest/exchange/test/" + exchangeName);
+ List<Map<String, Object>> queues = getRestTestHelper().getJsonAsList("/rest/exchange/test/" + exchangeName);
assertEquals("Exchange should be deleted", 0, queues.size());
}
@@ -287,12 +287,12 @@ public class VirtualHostRestTest extends QpidRestTestCase
{
String exchangeName = getTestName();
createExchange(exchangeName, "direct");
- Map<String, Object> echangeDetails = getJsonAsSingletonList("/rest/exchange/test/" + exchangeName);
+ Map<String, Object> echangeDetails = getRestTestHelper().getJsonAsSingletonList("/rest/exchange/test/" + exchangeName);
- HttpURLConnection connection = openManagementConection("/rest/exchange/test?id=" + echangeDetails.get(Exchange.ID), "DELETE");
+ HttpURLConnection connection = getRestTestHelper().openManagementConnection("/rest/exchange/test?id=" + echangeDetails.get(Exchange.ID), "DELETE");
connection.connect();
assertEquals("Unexpected response code", 200, connection.getResponseCode());
- List<Map<String, Object>> queues = getJsonAsList("/rest/exchange/test/" + exchangeName);
+ List<Map<String, Object>> queues = getRestTestHelper().getJsonAsList("/rest/exchange/test/" + exchangeName);
assertEquals("Exchange should be deleted", 0, queues.size());
}
@@ -326,14 +326,14 @@ public class VirtualHostRestTest extends QpidRestTestCase
lvqQueueAttributes.put(Queue.LVQ_KEY, "LVQ");
createQueue(queueName + "-lvq", "lvq", lvqQueueAttributes);
- Map<String, Object> hostDetails = getJsonAsSingletonList("/rest/virtualhost/test");
+ Map<String, Object> hostDetails = getRestTestHelper().getJsonAsSingletonList("/rest/virtualhost/test");
@SuppressWarnings("unchecked")
List<Map<String, Object>> queues = (List<Map<String, Object>>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_QUEUES_ATTRIBUTE);
- Map<String, Object> standardQueue = find(Queue.NAME, queueName + "-standard" , queues);
- Map<String, Object> sortedQueue = find(Queue.NAME, queueName + "-sorted" , queues);
- Map<String, Object> priorityQueue = find(Queue.NAME, queueName + "-priority" , queues);
- Map<String, Object> lvqQueue = find(Queue.NAME, queueName + "-lvq" , queues);
+ Map<String, Object> standardQueue = getRestTestHelper().find(Queue.NAME, queueName + "-standard" , queues);
+ Map<String, Object> sortedQueue = getRestTestHelper().find(Queue.NAME, queueName + "-sorted" , queues);
+ Map<String, Object> priorityQueue = getRestTestHelper().find(Queue.NAME, queueName + "-priority" , queues);
+ Map<String, Object> lvqQueue = getRestTestHelper().find(Queue.NAME, queueName + "-lvq" , queues);
attributes.put(Queue.DURABLE, Boolean.TRUE);
Asserts.assertQueue(queueName + "-standard", "standard", standardQueue, attributes);
@@ -355,25 +355,25 @@ public class VirtualHostRestTest extends QpidRestTestCase
attributes.put(AMQQueueFactory.X_QPID_DLQ_ENABLED, true);
//verify the starting state
- Map<String, Object> hostDetails = getJsonAsSingletonList("/rest/virtualhost/test");
+ Map<String, Object> hostDetails = getRestTestHelper().getJsonAsSingletonList("/rest/virtualhost/test");
List<Map<String, Object>> queues = (List<Map<String, Object>>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_QUEUES_ATTRIBUTE);
List<Map<String, Object>> exchanges = (List<Map<String, Object>>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_EXCHANGES_ATTRIBUTE);
- assertNull("queue should not have already been present", find(Queue.NAME, queueName , queues));
- assertNull("queue should not have already been present", find(Queue.NAME, queueName + "_DLQ" , queues));
- assertNull("exchange should not have already been present", find(Exchange.NAME, queueName + "_DLE" , exchanges));
+ assertNull("queue should not have already been present", getRestTestHelper().find(Queue.NAME, queueName , queues));
+ assertNull("queue should not have already been present", getRestTestHelper().find(Queue.NAME, queueName + "_DLQ" , queues));
+ assertNull("exchange should not have already been present", getRestTestHelper().find(Exchange.NAME, queueName + "_DLE" , exchanges));
//create the queue
createQueue(queueName, "standard", attributes);
//verify the new queue, as well as the DLQueue and DLExchange have been created
- hostDetails = getJsonAsSingletonList("/rest/virtualhost/test");
+ hostDetails = getRestTestHelper().getJsonAsSingletonList("/rest/virtualhost/test");
queues = (List<Map<String, Object>>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_QUEUES_ATTRIBUTE);
exchanges = (List<Map<String, Object>>) hostDetails.get(VirtualHostRestTest.VIRTUALHOST_EXCHANGES_ATTRIBUTE);
- Map<String, Object> queue = find(Queue.NAME, queueName , queues);
- Map<String, Object> dlqQueue = find(Queue.NAME, queueName + "_DLQ" , queues);
- Map<String, Object> dlExchange = find(Exchange.NAME, queueName + "_DLE" , exchanges);
+ Map<String, Object> queue = getRestTestHelper().find(Queue.NAME, queueName , queues);
+ Map<String, Object> dlqQueue = getRestTestHelper().find(Queue.NAME, queueName + "_DLQ" , queues);
+ Map<String, Object> dlExchange = getRestTestHelper().find(Exchange.NAME, queueName + "_DLE" , exchanges);
assertNotNull("queue should not have been present", queue);
assertNotNull("queue should not have been present", dlqQueue);
assertNotNull("exchange should not have been present", dlExchange);
@@ -388,14 +388,14 @@ public class VirtualHostRestTest extends QpidRestTestCase
private void createExchange(String exchangeName, String exchangeType) throws IOException
{
- HttpURLConnection connection = openManagementConection("/rest/exchange/test/" + exchangeName, "PUT");
+ HttpURLConnection connection = getRestTestHelper().openManagementConnection("/rest/exchange/test/" + exchangeName, "PUT");
Map<String, Object> queueData = new HashMap<String, Object>();
queueData.put(Exchange.NAME, exchangeName);
queueData.put(Exchange.DURABLE, Boolean.TRUE);
queueData.put(Exchange.TYPE, exchangeType);
- writeJsonRequest(connection, queueData);
+ getRestTestHelper().writeJsonRequest(connection, queueData);
assertEquals("Unexpected response code", 201, connection.getResponseCode());
connection.disconnect();
@@ -411,7 +411,7 @@ public class VirtualHostRestTest extends QpidRestTestCase
private int tryCreateQueue(String queueName, String queueType, Map<String, Object> attributes) throws IOException,
JsonGenerationException, JsonMappingException
{
- HttpURLConnection connection = openManagementConection("/rest/queue/test/" + queueName, "PUT");
+ HttpURLConnection connection = getRestTestHelper().openManagementConnection("/rest/queue/test/" + queueName, "PUT");
Map<String, Object> queueData = new HashMap<String, Object>();
queueData.put(Queue.NAME, queueName);
@@ -425,7 +425,7 @@ public class VirtualHostRestTest extends QpidRestTestCase
queueData.putAll(attributes);
}
- writeJsonRequest(connection, queueData);
+ getRestTestHelper().writeJsonRequest(connection, queueData);
int responseCode = connection.getResponseCode();
connection.disconnect();
return responseCode;
diff --git a/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/systest/rest/acl/GroupRestACLTest.java b/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/systest/rest/acl/GroupRestACLTest.java
new file mode 100644
index 0000000000..f9f9fbfef0
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/systest/rest/acl/GroupRestACLTest.java
@@ -0,0 +1,187 @@
+/*
+ *
+ * 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.systest.rest.acl;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.qpid.server.management.plugin.servlet.rest.QpidRestTestCase;
+import org.apache.qpid.server.security.acl.AbstractACLTestCase;
+
+public class GroupRestACLTest extends QpidRestTestCase
+{
+ private static final String FILE_GROUP_MANAGER = "FileGroupManager";
+
+ private static final String ALLOWED_GROUP = "allowedGroup";
+ private static final String DENIED_GROUP = "deniedGroup";
+ private static final String OTHER_GROUP = "otherGroup";
+
+ private static final String ALLOWED_USER = "webadmin";
+ private static final String DENIED_USER = "admin";
+ private static final String OTHER_USER = "admin";
+
+ private File _groupFile;
+
+ @Override
+ public void setUp() throws Exception
+ {
+ _groupFile = createTemporaryGroupFile();
+
+ setConfigurationProperty("security.file-group-manager.attributes.attribute.name", "groupFile");
+ setConfigurationProperty("security.file-group-manager.attributes.attribute.value", _groupFile.getAbsolutePath());
+
+ //DONT call super.setUp(), the tests will start the broker after configuring it
+ }
+
+ @Override
+ public void tearDown() throws Exception
+ {
+ super.tearDown();
+
+ if (_groupFile != null)
+ {
+ if (_groupFile.exists())
+ {
+ _groupFile.delete();
+ }
+ }
+ }
+
+ private File createTemporaryGroupFile() throws Exception
+ {
+ File groupFile = File.createTempFile("group", "grp");
+ groupFile.deleteOnExit();
+
+ Properties props = new Properties();
+ props.put(ALLOWED_GROUP + ".users", ALLOWED_USER);
+ props.put(DENIED_GROUP + ".users", DENIED_USER);
+ props.put(OTHER_GROUP + ".users", OTHER_USER);
+
+ props.store(new FileOutputStream(groupFile), "test group file");
+
+ return groupFile;
+ }
+
+ public void testCreateGroup() throws Exception
+ {
+ AbstractACLTestCase.writeACLFileUtil(this, null,
+ "ACL ALLOW-LOG " + ALLOWED_GROUP + " CREATE GROUP",
+ "ACL DENY-LOG " + DENIED_GROUP + " CREATE GROUP");
+
+ //Start the broker with the custom config
+ super.setUp();
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ Map<String, Object> data = getRestTestHelper().getJsonAsSingletonList("/rest/groupprovider/" + FILE_GROUP_MANAGER);
+ getRestTestHelper().assertNumberOfGroups(data, 3);
+
+ getRestTestHelper().createGroup("newGroup", FILE_GROUP_MANAGER);
+
+ data = getRestTestHelper().getJsonAsSingletonList("/rest/groupprovider/" + FILE_GROUP_MANAGER);
+ getRestTestHelper().assertNumberOfGroups(data, 4);
+
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+
+ //TODO: the expected response code needs changed when we overhaul the brokers error handling
+ getRestTestHelper().createGroup("anotherNewGroup", FILE_GROUP_MANAGER, HttpServletResponse.SC_CONFLICT);
+
+ data = getRestTestHelper().getJsonAsSingletonList("/rest/groupprovider/" + FILE_GROUP_MANAGER);
+ getRestTestHelper().assertNumberOfGroups(data, 4);
+ }
+
+ public void testDeleteGroup() throws Exception
+ {
+ AbstractACLTestCase.writeACLFileUtil(this, null,
+ "ACL ALLOW-LOG " + ALLOWED_GROUP + " DELETE GROUP",
+ "ACL DENY-LOG " + DENIED_GROUP + " DELETE GROUP");
+
+ //Start the broker with the custom config
+ super.setUp();
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+
+ Map<String, Object> data = getRestTestHelper().getJsonAsSingletonList("/rest/groupprovider/" + FILE_GROUP_MANAGER);
+ getRestTestHelper().assertNumberOfGroups(data, 3);
+
+ //TODO: the expected response code needs changed when we overhaul the brokers error handling
+ getRestTestHelper().removeGroup(OTHER_GROUP, FILE_GROUP_MANAGER, HttpServletResponse.SC_CONFLICT);
+
+ data = getRestTestHelper().getJsonAsSingletonList("/rest/groupprovider/" + FILE_GROUP_MANAGER);
+ getRestTestHelper().assertNumberOfGroups(data, 3);
+
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+
+ getRestTestHelper().removeGroup(OTHER_GROUP, FILE_GROUP_MANAGER);
+
+ data = getRestTestHelper().getJsonAsSingletonList("/rest/groupprovider/" + FILE_GROUP_MANAGER);
+ getRestTestHelper().assertNumberOfGroups(data, 2);
+ }
+
+ public void testUpdateGroupAddMember() throws Exception
+ {
+ AbstractACLTestCase.writeACLFileUtil(this, null,
+ "ACL ALLOW-LOG " + ALLOWED_GROUP + " UPDATE GROUP",
+ "ACL DENY-LOG " + DENIED_GROUP + " UPDATE GROUP");
+
+ //Start the broker with the custom config
+ super.setUp();
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+
+ assertNumberOfGroupMembers(OTHER_GROUP, 1);
+
+ getRestTestHelper().createNewGroupMember(FILE_GROUP_MANAGER, OTHER_GROUP, "newGroupMember", HttpServletResponse.SC_CONFLICT);
+ assertNumberOfGroupMembers(OTHER_GROUP, 1);
+
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+ getRestTestHelper().createNewGroupMember(FILE_GROUP_MANAGER, OTHER_GROUP, "newGroupMember");
+ assertNumberOfGroupMembers(OTHER_GROUP, 2);
+ }
+
+ public void testUpdateGroupDeleteMember() throws Exception
+ {
+ AbstractACLTestCase.writeACLFileUtil(this, null,
+ "ACL ALLOW-LOG " + ALLOWED_GROUP + " UPDATE GROUP",
+ "ACL DENY-LOG " + DENIED_GROUP + " UPDATE GROUP");
+
+ //Start the broker with the custom config
+ super.setUp();
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+
+ assertNumberOfGroupMembers(OTHER_GROUP, 1);
+
+ getRestTestHelper().removeMemberFromGroup(FILE_GROUP_MANAGER, OTHER_GROUP, OTHER_USER, HttpServletResponse.SC_CONFLICT);
+ assertNumberOfGroupMembers(OTHER_GROUP, 1);
+
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+ getRestTestHelper().removeMemberFromGroup(FILE_GROUP_MANAGER, OTHER_GROUP, OTHER_USER);
+ assertNumberOfGroupMembers(OTHER_GROUP, 0);
+ }
+
+ private void assertNumberOfGroupMembers(String groupName, int expectedNumberOfMembers) throws IOException
+ {
+ Map<String, Object> group = getRestTestHelper().getJsonAsSingletonList("/rest/group/FileGroupManager/" + groupName);
+ getRestTestHelper().assertNumberOfGroupMembers(group, expectedNumberOfMembers);
+ }
+}
diff --git a/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/systest/rest/acl/UserRestACLTest.java b/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/systest/rest/acl/UserRestACLTest.java
new file mode 100644
index 0000000000..514d1bd781
--- /dev/null
+++ b/qpid/java/broker-plugins/management-http/src/test/java/org/apache/qpid/systest/rest/acl/UserRestACLTest.java
@@ -0,0 +1,188 @@
+/*
+ * 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.systest.rest.acl;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.qpid.server.management.plugin.servlet.rest.QpidRestTestCase;
+import org.apache.qpid.server.security.acl.AbstractACLTestCase;
+import org.codehaus.jackson.JsonParseException;
+import org.codehaus.jackson.map.JsonMappingException;
+
+public class UserRestACLTest extends QpidRestTestCase
+{
+ private static final String ALLOWED_GROUP = "allowedGroup";
+ private static final String DENIED_GROUP = "deniedGroup";
+ private static final String OTHER_GROUP = "otherGroup";
+
+ private static final String ALLOWED_USER = "webadmin";
+ private static final String DENIED_USER = "admin";
+ private static final String OTHER_USER = "other";
+
+ private File _groupFile;
+
+ @Override
+ public void setUp() throws Exception
+ {
+ _groupFile = createTemporaryGroupFile();
+
+ setConfigurationProperty("security.file-group-manager.attributes.attribute.name", "groupFile");
+ setConfigurationProperty("security.file-group-manager.attributes.attribute.value", _groupFile.getAbsolutePath());
+
+ getRestTestHelper().configureTemporaryPasswordFile(this, ALLOWED_USER, DENIED_USER, OTHER_USER);
+
+ //DONT call super.setUp(), the tests will start the broker after configuring it
+ }
+
+ @Override
+ public void tearDown() throws Exception
+ {
+ super.tearDown();
+
+ if (_groupFile != null)
+ {
+ if (_groupFile.exists())
+ {
+ _groupFile.delete();
+ }
+ }
+ }
+
+ private File createTemporaryGroupFile() throws Exception
+ {
+ File groupFile = File.createTempFile("group", "grp");
+ groupFile.deleteOnExit();
+
+ Properties props = new Properties();
+ props.put(ALLOWED_GROUP + ".users", ALLOWED_USER);
+ props.put(DENIED_GROUP + ".users", DENIED_USER);
+ props.put(OTHER_GROUP + ".users", OTHER_USER);
+
+ props.store(new FileOutputStream(groupFile), "test group file");
+
+ return groupFile;
+ }
+
+ public void testAddUser() throws Exception
+ {
+ AbstractACLTestCase.writeACLFileUtil(this, null,
+ "ACL ALLOW-LOG " + ALLOWED_GROUP + " CREATE USER",
+ "ACL DENY-LOG " + DENIED_GROUP + " CREATE USER");
+
+ //Start the broker with the custom config
+ super.setUp();
+
+ String newUser = "newUser";
+ String password = "password";
+
+ assertUserDoesNotExist(newUser);
+
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+
+ getRestTestHelper().createOrUpdateUser(newUser, password, HttpServletResponse.SC_CONFLICT);
+ assertUserDoesNotExist(newUser);
+
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+ getRestTestHelper().createOrUpdateUser(newUser, password);
+ assertUserExists(newUser);
+ }
+
+ public void testDeleteUser() throws Exception
+ {
+ AbstractACLTestCase.writeACLFileUtil(this, null,
+ "ACL ALLOW-LOG " + ALLOWED_GROUP + " DELETE USER",
+ "ACL DENY-LOG " + DENIED_GROUP + " DELETE USER");
+
+ //Start the broker with the custom config
+ super.setUp();
+
+ assertUserExists(OTHER_USER);
+
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+ getRestTestHelper().removeUser(OTHER_USER, HttpServletResponse.SC_CONFLICT);
+ assertUserExists(OTHER_USER);
+
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+ getRestTestHelper().removeUser(OTHER_USER);
+ assertUserDoesNotExist(OTHER_USER);
+ }
+
+ public void testUpdateUser() throws Exception
+ {
+ AbstractACLTestCase.writeACLFileUtil(this, null,
+ "ACL ALLOW-LOG " + ALLOWED_GROUP + " UPDATE USER",
+ "ACL DENY-LOG " + DENIED_GROUP + " UPDATE USER");
+
+ //Start the broker with the custom config
+ super.setUp();
+
+ String newPassword = "newPassword";
+
+ checkPassword(OTHER_USER, OTHER_USER, true);
+
+ getRestTestHelper().setUsernameAndPassword(DENIED_USER, DENIED_USER);
+ getRestTestHelper().createOrUpdateUser(OTHER_USER, newPassword, HttpServletResponse.SC_CONFLICT);
+
+ checkPassword(OTHER_USER, newPassword, false);
+
+ getRestTestHelper().setUsernameAndPassword(ALLOWED_USER, ALLOWED_USER);
+ getRestTestHelper().createOrUpdateUser(OTHER_USER, newPassword, HttpServletResponse.SC_OK); // expect SC_OK rather than the default SC_CREATED
+
+ checkPassword(OTHER_USER, newPassword, true);
+ checkPassword(OTHER_USER, OTHER_USER, false);
+ }
+
+ private void checkPassword(String username, String password, boolean passwordExpectedToBeCorrect) throws IOException
+ {
+ getRestTestHelper().setUsernameAndPassword(username, password);
+ HttpURLConnection connection = getRestTestHelper().openManagementConnection("/rest/user/PrincipalDatabaseAuthenticationManager/", "GET");
+
+ boolean passwordIsCorrect = connection.getResponseCode() == HttpServletResponse.SC_OK;
+
+ connection.disconnect();
+
+ assertEquals(passwordExpectedToBeCorrect, passwordIsCorrect);
+ }
+
+ private void assertUserDoesNotExist(String newUser) throws JsonParseException, JsonMappingException, IOException
+ {
+ String path = "/rest/user/PrincipalDatabaseAuthenticationManager/" + newUser;
+ List<Map<String, Object>> userDetailsList = getRestTestHelper().getJsonAsList(path);
+ assertTrue(userDetailsList.isEmpty());
+ }
+
+ private void assertUserExists(String username) throws IOException
+ {
+ String path = "/rest/user/PrincipalDatabaseAuthenticationManager/" + username;
+ Map<String, Object> userDetails = getRestTestHelper().getJsonAsSingletonList(path);
+
+ assertEquals(
+ "User returned by " + path + " should have name=" + username + ". The returned JSON was: " + userDetails,
+ username,
+ userDetails.get("name"));
+ }
+}
diff --git a/qpid/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXManagedObjectRegistry.java b/qpid/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXManagedObjectRegistry.java
index 0648235077..e68c0d650b 100644
--- a/qpid/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXManagedObjectRegistry.java
+++ b/qpid/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXManagedObjectRegistry.java
@@ -29,9 +29,8 @@ import org.apache.qpid.server.logging.messages.ManagementConsoleMessages;
import org.apache.qpid.server.registry.ApplicationRegistry;
import org.apache.qpid.server.registry.IApplicationRegistry;
+import org.apache.qpid.server.security.auth.AuthenticatedPrincipal;
import org.apache.qpid.server.security.auth.rmi.RMIPasswordAuthenticator;
-import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal;
-
import javax.management.JMException;
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
@@ -73,7 +72,7 @@ import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
- * This class starts up an MBeanserver. If out of the box agent has been enabled then there are no
+ * This class starts up an MBeanserver. If out of the box agent has been enabled then there are no
* security features implemented like user authentication and authorisation.
*/
public class JMXManagedObjectRegistry implements ManagedObjectRegistry
@@ -244,8 +243,8 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry
protected RMIConnection makeClient(String connectionId, Subject subject) throws IOException
{
final RMIConnection makeClient = super.makeClient(connectionId, subject);
- final UsernamePrincipal usernamePrincipalFromSubject = UsernamePrincipal.getUsernamePrincipalFromSubject(subject);
- connectionIdUsernameMap.put(connectionId, usernamePrincipalFromSubject.getName());
+ final AuthenticatedPrincipal authenticatedPrincipalFromSubject = AuthenticatedPrincipal.getAuthenticatedPrincipalFromSubject(subject);
+ connectionIdUsernameMap.put(connectionId, authenticatedPrincipalFromSubject.getName());
return makeClient;
}
};
@@ -451,7 +450,7 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry
_log.error("Exception while closing the JMX ConnectorServer: ", e);
}
}
-
+
if (_rmiRegistry != null)
{
// Stopping the RMI registry
@@ -469,7 +468,7 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry
_log.error("Exception while closing the RMI Registry: ", e);
}
}
-
+
//ObjectName query to gather all Qpid related MBeans
ObjectName mbeanNameQuery = null;
try
diff --git a/qpid/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/MBeanInvocationHandlerImpl.java b/qpid/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/MBeanInvocationHandlerImpl.java
index a2a0d2d093..694b0b2913 100644
--- a/qpid/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/MBeanInvocationHandlerImpl.java
+++ b/qpid/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/MBeanInvocationHandlerImpl.java
@@ -30,6 +30,7 @@ import org.apache.qpid.server.registry.ApplicationRegistry;
import org.apache.qpid.server.registry.IApplicationRegistry;
import org.apache.qpid.server.security.SecurityManager;
import org.apache.qpid.server.security.access.Operation;
+import org.apache.qpid.server.security.auth.AuthenticatedPrincipal;
import javax.management.Attribute;
import javax.management.JMException;
@@ -41,7 +42,6 @@ import javax.management.NotificationListener;
import javax.management.ObjectName;
import javax.management.RuntimeErrorException;
import javax.management.remote.JMXConnectionNotification;
-import javax.management.remote.JMXPrincipal;
import javax.management.remote.MBeanServerForwarder;
import javax.security.auth.Subject;
import java.lang.reflect.InvocationHandler;
@@ -52,7 +52,6 @@ import java.security.AccessControlContext;
import java.security.AccessController;
import java.util.Arrays;
import java.util.Map;
-import java.util.Set;
/**
* This class can be used by the JMXConnectorServer as an InvocationHandler for the mbean operations. It delegates
@@ -101,7 +100,7 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler, Notificati
{
ObjectName mbean = (ObjectName) args[0];
- if(!DefaultManagedObject.DOMAIN.equalsIgnoreCase(mbean.getDomain()))
+ if(!ManagedObject.DOMAIN.equalsIgnoreCase(mbean.getDomain()))
{
return true;
}
@@ -151,11 +150,13 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler, Notificati
return method.invoke(_mbs, args);
}
- // Retrieve JMXPrincipal from Subject
- Set<JMXPrincipal> principals = subject.getPrincipals(JMXPrincipal.class);
- if (principals == null || principals.isEmpty())
+ try
+ {
+ AuthenticatedPrincipal.getAuthenticatedPrincipalFromSubject(subject);
+ }
+ catch(Exception e)
{
- throw new SecurityException("Access denied: no JMX principal");
+ throw new SecurityException("Access denied: no authenticated principal", e);
}
// Save the subject
@@ -381,6 +382,7 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler, Notificati
String user = null;
if (handback instanceof Map)
{
+ @SuppressWarnings("unchecked")
final Map<String, String> connectionIdUsernameMap = (Map<String, String>) handback;
user = connectionIdUsernameMap.get(connectionId);
}
diff --git a/qpid/java/broker/etc/broker_example.acl b/qpid/java/broker/etc/broker_example.acl
index 45a48bda09..a5e01fb895 100644
--- a/qpid/java/broker/etc/broker_example.acl
+++ b/qpid/java/broker/etc/broker_example.acl
@@ -19,14 +19,7 @@
### EXAMPLE ACL V2 FILE
### NOTE: Rules are considered from top to bottom, and the first matching rule governs the decision.
-
-### DEFINE GROUPS ###
-
-#Define a 'messaging-users' group with users 'client' and 'server' in it
-GROUP messaging-users client server
-
-#Define a group for management web console users
-GROUP webadmins webadmin
+### Rules may refer to users or groups. Groups are currently defined in the etc/groups file.
### JMX MANAGEMENT ####
@@ -34,9 +27,9 @@ GROUP webadmins webadmin
# This is used for items such as querying the management API and broker release versions.
ACL ALLOW ALL ACCESS METHOD component="ServerInformation"
-# Allow 'admin' all management operations. To reduce log file noise, only non-read-only operations are logged.
-ACL ALLOW admin ACCESS METHOD
-ACL ALLOW-LOG admin ALL METHOD
+# Allow 'administrators' all management operations. To reduce log file noise, only non-read-only operations are logged.
+ACL ALLOW administrators ACCESS METHOD
+ACL ALLOW-LOG administrators ALL METHOD
# Allow 'guest' to view logger levels, and use getter methods on LoggingManagement
ACL ALLOW guest ACCESS METHOD component="LoggingManagement" name="viewEffectiveRuntimeLoggerLevels"
@@ -87,6 +80,13 @@ ACL ALLOW-LOG webadmins CREATE EXCHANGE
ACL ALLOW-LOG webadmins DELETE EXCHANGE
ACL ALLOW-LOG webadmins BIND EXCHANGE
ACL ALLOW-LOG webadmins UNBIND EXCHANGE
+ACL ALLOW-LOG webadmins CREATE GROUP
+ACL ALLOW-LOG webadmins DELETE GROUP
+ACL ALLOW-LOG webadmins UPDATE GROUP
+ACL ALLOW-LOG webadmins CREATE USER
+ACL ALLOW-LOG webadmins DELETE USER
+ACL ALLOW-LOG webadmins UPDATE USER
+
ACL ALLOW-LOG webadmins UPDATE METHOD
# at the moment only the following UPDATE METHOD rules are supported by web management console
@@ -96,5 +96,5 @@ ACL ALLOW-LOG webadmins UPDATE METHOD
### DEFAULT ###
-#Deny all users from performing all operations
+# Deny all users from performing all operations
ACL DENY-LOG all all
diff --git a/qpid/java/broker/etc/config.xml b/qpid/java/broker/etc/config.xml
index 08c7c23d13..7bd4ceb128 100644
--- a/qpid/java/broker/etc/config.xml
+++ b/qpid/java/broker/etc/config.xml
@@ -79,13 +79,24 @@
</principal-database>
</pd-auth-manager>
- <!-- By default, all authenticated users have permissions to perform all actions -->
+ <!--
+ <file-group-manager>
+ <attributes>
+ <attribute>
+ <name>groupFile</name>
+ <value>${conf}/groups</value>
+ </attribute>
+ </attributes>
+ </file-group-manager>
+ -->
+
+ <!--
+ ACL Example. This example illustrates securing both management and messaging.
+ By default, all authenticated users have permissions to perform all actions
- <!-- ACL Example
- This example illustrates securing the both Management (JMX) and Messaging.
<acl>${conf}/broker_example.acl</acl>
-->
-
+
<msg-auth>false</msg-auth>
</security>
diff --git a/qpid/java/broker/etc/groups b/qpid/java/broker/etc/groups
new file mode 100644
index 0000000000..e3912ece99
--- /dev/null
+++ b/qpid/java/broker/etc/groups
@@ -0,0 +1,29 @@
+#
+# 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.
+#
+
+#
+# To define a group, use the format:
+#
+# <groupname>.users=<user1>,<user2>,...,<usern>
+#
+
+messaging-users.users=guest,client,server
+administrators.users=admin
+webadmins.users=webadmin
+
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java
index b8c8411c5d..e65fe10eb5 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionSecureOkMethodHandler.java
@@ -32,9 +32,8 @@ import org.apache.qpid.framing.MethodRegistry;
import org.apache.qpid.protocol.AMQConstant;
import org.apache.qpid.server.protocol.AMQProtocolSession;
import org.apache.qpid.server.registry.ApplicationRegistry;
-import org.apache.qpid.server.security.auth.AuthenticationResult;
-import org.apache.qpid.server.security.auth.manager.AuthenticationManager;
-import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal;
+import org.apache.qpid.server.security.SubjectCreator;
+import org.apache.qpid.server.security.auth.SubjectAuthenticationResult;
import org.apache.qpid.server.state.AMQState;
import org.apache.qpid.server.state.AMQStateManager;
import org.apache.qpid.server.state.StateAwareMethodListener;
@@ -61,7 +60,7 @@ public class ConnectionSecureOkMethodHandler implements StateAwareMethodListener
{
AMQProtocolSession session = stateManager.getProtocolSession();
- AuthenticationManager authMgr = stateManager.getAuthenticationManager();
+ SubjectCreator subjectCreator = stateManager.getSubjectCreator();
SaslServer ss = session.getSaslServer();
if (ss == null)
@@ -69,7 +68,7 @@ public class ConnectionSecureOkMethodHandler implements StateAwareMethodListener
throw new AMQException("No SASL context set up in session");
}
MethodRegistry methodRegistry = session.getMethodRegistry();
- AuthenticationResult authResult = authMgr.authenticate(ss, body.getResponse());
+ SubjectAuthenticationResult authResult = subjectCreator.authenticate(ss, body.getResponse());
switch (authResult.getStatus())
{
case ERROR:
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java
index a522b9f60f..9f596a4637 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/handler/ConnectionStartOkMethodHandler.java
@@ -32,9 +32,8 @@ import org.apache.qpid.protocol.AMQConstant;
import org.apache.qpid.server.configuration.ServerConfiguration;
import org.apache.qpid.server.protocol.AMQProtocolSession;
import org.apache.qpid.server.registry.ApplicationRegistry;
-import org.apache.qpid.server.security.auth.AuthenticationResult;
-import org.apache.qpid.server.security.auth.manager.AuthenticationManager;
-import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal;
+import org.apache.qpid.server.security.SubjectCreator;
+import org.apache.qpid.server.security.auth.SubjectAuthenticationResult;
import org.apache.qpid.server.state.AMQState;
import org.apache.qpid.server.state.AMQStateManager;
import org.apache.qpid.server.state.StateAwareMethodListener;
@@ -65,11 +64,11 @@ public class ConnectionStartOkMethodHandler implements StateAwareMethodListener<
_logger.info("SASL Mechanism selected: " + body.getMechanism());
_logger.info("Locale selected: " + body.getLocale());
- AuthenticationManager authMgr = stateManager.getAuthenticationManager();
+ SubjectCreator subjectCreator = stateManager.getSubjectCreator();
SaslServer ss = null;
try
{
- ss = authMgr.createSaslServer(String.valueOf(body.getMechanism()), session.getLocalFQDN(), session.getPeerPrincipal());
+ ss = subjectCreator.createSaslServer(String.valueOf(body.getMechanism()), session.getLocalFQDN(), session.getPeerPrincipal());
if (ss == null)
{
@@ -78,7 +77,7 @@ public class ConnectionStartOkMethodHandler implements StateAwareMethodListener<
session.setSaslServer(ss);
- final AuthenticationResult authResult = authMgr.authenticate(ss, body.getResponse());
+ final SubjectAuthenticationResult authResult = subjectCreator.authenticate(ss, body.getResponse());
//save clientProperties
session.setClientProperties(body.getClientProperties());
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AbstractManagementActor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AbstractManagementActor.java
new file mode 100644
index 0000000000..f67c7a1c6a
--- /dev/null
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/AbstractManagementActor.java
@@ -0,0 +1,48 @@
+package org.apache.qpid.server.logging.actors;
+
+import java.security.AccessController;
+
+import javax.security.auth.Subject;
+
+import org.apache.qpid.server.logging.RootMessageLogger;
+import org.apache.qpid.server.security.auth.AuthenticatedPrincipal;
+
+public abstract class AbstractManagementActor extends AbstractActor
+{
+ /**
+ * Holds the principal name to display when principal subject is not available.
+ * <p>
+ * This is useful for cases when users invoke JMX operation over JConsole
+ * attached to the local JVM.
+ */
+ protected static final String UNKNOWN_PRINCIPAL = "N/A";
+
+ /** used when the principal name cannot be discovered from the Subject */
+ private final String _fallbackPrincipalName;
+
+ public AbstractManagementActor(RootMessageLogger rootLogger, String fallbackPrincipalName)
+ {
+ super(rootLogger);
+ _fallbackPrincipalName = fallbackPrincipalName;
+ }
+
+ /**
+ * Returns current {@link AuthenticatedPrincipal} name or {@link #_fallbackPrincipalName}
+ * if it can't be found.
+ */
+ protected String getPrincipalName()
+ {
+ String identity = _fallbackPrincipalName;
+
+ final Subject subject = Subject.getSubject(AccessController.getContext());
+ if (subject != null)
+ {
+ AuthenticatedPrincipal authenticatedPrincipal = AuthenticatedPrincipal.getOptionalAuthenticatedPrincipalFromSubject(subject);
+ if(authenticatedPrincipal != null)
+ {
+ identity = authenticatedPrincipal.getName();
+ }
+ }
+ return identity;
+ }
+} \ No newline at end of file
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/HttpManagementActor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/HttpManagementActor.java
new file mode 100644
index 0000000000..9b445c2bd9
--- /dev/null
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/HttpManagementActor.java
@@ -0,0 +1,62 @@
+/*
+ *
+ * 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.logging.actors;
+
+import java.text.MessageFormat;
+
+import org.apache.qpid.server.logging.RootMessageLogger;
+import org.apache.qpid.server.logging.subjects.LogSubjectFormat;
+
+/**
+ * HttpManagement actor to use in {@link AbstractServlet} to log all http management operational logging.
+ *
+ * An instance is required per http Session.
+ */
+public class HttpManagementActor extends AbstractManagementActor
+{
+ private String _cachedLogString;
+ private String _lastPrincipalName;
+ private String _address;
+
+ public HttpManagementActor(RootMessageLogger rootLogger, String ip, int port)
+ {
+ super(rootLogger, UNKNOWN_PRINCIPAL);
+ _address = ip + ":" + port;
+ }
+
+ private synchronized String getAndCacheLogString()
+ {
+ String principalName = getPrincipalName();
+
+ if(!principalName.equals(_lastPrincipalName))
+ {
+ _lastPrincipalName = principalName;
+ _cachedLogString = "[" + MessageFormat.format(LogSubjectFormat.MANAGEMENT_FORMAT, principalName, _address) + "] ";
+ }
+
+ return _cachedLogString;
+ }
+
+ public String getLogMessage()
+ {
+ return getAndCacheLogString();
+ }
+}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/ManagementActor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/ManagementActor.java
index a2f3506502..ba5ea47fc1 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/ManagementActor.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/actors/ManagementActor.java
@@ -21,58 +21,31 @@
package org.apache.qpid.server.logging.actors;
import org.apache.qpid.server.logging.RootMessageLogger;
+import org.apache.qpid.server.logging.subjects.LogSubjectFormat;
-import javax.management.remote.JMXPrincipal;
-import javax.security.auth.Subject;
-import java.security.AccessController;
-import java.security.Principal;
import java.text.MessageFormat;
-import java.util.Set;
/**
* Management actor to use in {@link MBeanInvocationHandlerImpl} to log all management operational logging.
*/
-public class ManagementActor extends AbstractActor
+public class ManagementActor extends AbstractManagementActor
{
- /**
- * Holds the principal name to display when principal subject is not available.
- * <p>
- * This is useful for cases when users invoke JMX operation over JConsole
- * attached to the local JVM.
- */
- private static final String UNKNOWN_PRINCIPAL = "N/A";
-
private String _lastThreadName = null;
/**
- * LOG FORMAT for the ManagementActor,
- * Uses a MessageFormat call to insert the required values according to
- * these indices:
- *
- * 0 - User ID
- * 1 - IP
- */
- public static final String MANAGEMENT_FORMAT = "mng:{0}({1})";
-
- /**
* The logString to be used for logging
*/
private String _logStringContainingPrincipal;
- /** used when the principal name cannot be discovered from the Subject */
- private final String _fallbackPrincipalName;
-
/** @param rootLogger The RootLogger to use for this Actor */
public ManagementActor(RootMessageLogger rootLogger)
{
- super(rootLogger);
- _fallbackPrincipalName = UNKNOWN_PRINCIPAL;
+ super(rootLogger, UNKNOWN_PRINCIPAL);
}
public ManagementActor(RootMessageLogger rootLogger, String principalName)
{
- super(rootLogger);
- _fallbackPrincipalName = principalName;
+ super(rootLogger, principalName);
}
private synchronized String getAndCacheLogString()
@@ -96,7 +69,7 @@ public class ManagementActor extends AbstractActor
if (split.length == 2)
{
String ip = currentName.split("-")[1];
- actor = MessageFormat.format(MANAGEMENT_FORMAT, principalName, ip);
+ actor = MessageFormat.format(LogSubjectFormat.MANAGEMENT_FORMAT, principalName, ip);
}
else
{
@@ -119,33 +92,8 @@ public class ManagementActor extends AbstractActor
return logString;
}
- /**
- * Returns current JMX principal name.
- *
- * @return principal name or null if principal can not be found
- */
- private String getPrincipalName()
- {
- String identity = _fallbackPrincipalName;
-
- // retrieve Subject from current AccessControlContext
- final Subject subject = Subject.getSubject(AccessController.getContext());
- if (subject != null)
- {
- // retrieve JMXPrincipal from Subject
- final Set<JMXPrincipal> principals = subject.getPrincipals(JMXPrincipal.class);
- if (principals != null && !principals.isEmpty())
- {
- final Principal principal = principals.iterator().next();
- identity = principal.getName();
- }
- }
- return identity;
- }
-
public String getLogMessage()
{
return getAndCacheLogString();
}
-
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/LogSubjectFormat.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/LogSubjectFormat.java
index 28c4f0d52a..7611ee1a88 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/LogSubjectFormat.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/logging/subjects/LogSubjectFormat.java
@@ -32,11 +32,19 @@ package org.apache.qpid.server.logging.subjects;
public class LogSubjectFormat
{
+
private LogSubjectFormat()
{
}
/**
+ * LOG FORMAT for the ManagementActors,
+ * 0 - User ID
+ * 1 - IP[:Port]
+ */
+ public static final String MANAGEMENT_FORMAT = "mng:{0}({1})";
+
+ /**
* LOG FORMAT for the Subscription Log Subject
* 0 - Subscription ID
*/
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Group.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Group.java
new file mode 100644
index 0000000000..aacd515107
--- /dev/null
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Group.java
@@ -0,0 +1,52 @@
+/*
+ * 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.model;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+
+public interface Group extends ConfiguredObject
+{
+ String CREATED = "created";
+ String DURABLE = "durable";
+ String ID = "id";
+ String LIFETIME_POLICY = "lifetimePolicy";
+ String NAME = "name";
+ String STATE = "state";
+ String TIME_TO_LIVE = "timeToLive";
+ String UPDATED = "updated";
+
+ // Attributes
+ public static final Collection<String> AVAILABLE_ATTRIBUTES =
+ Collections.unmodifiableList(
+ Arrays.asList(
+ ID,
+ NAME,
+ STATE,
+ DURABLE,
+ LIFETIME_POLICY,
+ TIME_TO_LIVE,
+ CREATED,
+ UPDATED
+ ));
+
+
+}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/GroupMember.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/GroupMember.java
new file mode 100644
index 0000000000..6832cc6fa6
--- /dev/null
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/GroupMember.java
@@ -0,0 +1,52 @@
+/*
+ * 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.model;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+
+public interface GroupMember extends ConfiguredObject
+{
+ String CREATED = "created";
+ String DURABLE = "durable";
+ String ID = "id";
+ String LIFETIME_POLICY = "lifetimePolicy";
+ String NAME = "name";
+ String STATE = "state";
+ String TIME_TO_LIVE = "timeToLive";
+ String UPDATED = "updated";
+
+ // Attributes
+ public static final Collection<String> AVAILABLE_ATTRIBUTES =
+ Collections.unmodifiableList(
+ Arrays.asList(
+ ID,
+ NAME,
+ STATE,
+ DURABLE,
+ LIFETIME_POLICY,
+ TIME_TO_LIVE,
+ CREATED,
+ UPDATED
+ ));
+
+
+}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/GroupProvider.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/GroupProvider.java
new file mode 100644
index 0000000000..76fa379c1b
--- /dev/null
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/GroupProvider.java
@@ -0,0 +1,51 @@
+/*
+ * 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.model;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+
+public interface GroupProvider extends ConfiguredObject
+{
+ public static final String ID = "id";
+ public static final String DESCRIPTION = "description";
+ public static final String NAME = "name";
+ public static final String STATE = "state";
+ public static final String DURABLE = "durable";
+ public static final String LIFETIME_POLICY = "lifetimePolicy";
+ public static final String TIME_TO_LIVE = "timeToLive";
+ public static final String CREATED = "created";
+ public static final String UPDATED = "updated";
+ public static final String TYPE = "type";
+
+ public static final Collection<String> AVAILABLE_ATTRIBUTES =
+ Collections.unmodifiableList(
+ Arrays.asList(ID,
+ NAME,
+ DESCRIPTION,
+ STATE,
+ DURABLE,
+ LIFETIME_POLICY,
+ TIME_TO_LIVE,
+ CREATED,
+ UPDATED,
+ TYPE));
+}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Model.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Model.java
index 36179fc105..329574f017 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Model.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/Model.java
@@ -47,6 +47,7 @@ public class Model
addRelationship(Broker.class, VirtualHost.class);
addRelationship(Broker.class, Port.class);
addRelationship(Broker.class, AuthenticationProvider.class);
+ addRelationship(Broker.class, GroupProvider.class);
addRelationship(VirtualHost.class, Exchange.class);
addRelationship(VirtualHost.class, Queue.class);
@@ -54,6 +55,10 @@ public class Model
addRelationship(VirtualHost.class, VirtualHostAlias.class);
addRelationship(AuthenticationProvider.class, User.class);
+ addRelationship(User.class, GroupMember.class);
+
+ addRelationship(GroupProvider.class, Group.class);
+ addRelationship(Group.class, GroupMember.class);
addRelationship(Connection.class, Session.class);
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/UUIDGenerator.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/UUIDGenerator.java
index 36b6a454dc..6606944dc5 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/UUIDGenerator.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/UUIDGenerator.java
@@ -63,6 +63,11 @@ public class UUIDGenerator
return createUUID(User.class.getName(), authenticationProviderName, userName);
}
+ public static UUID generateGroupUUID(String groupProviderName, String groupName)
+ {
+ return createUUID(Group.class.getName(), groupProviderName, groupName);
+ }
+
public static UUID generateVhostUUID(String virtualHostName)
{
return createUUID(VirtualHost.class.getName(), virtualHostName);
@@ -77,4 +82,9 @@ public class UUIDGenerator
{
return createUUID(Consumer.class.getName(), virtualHostName, queueName, connectionRemoteAddress, channelNumber, consumerName);
}
+
+ public static UUID generateGroupMemberUUID(String groupProviderName, String groupName, String groupMemberName)
+ {
+ return createUUID(GroupMember.class.getName(), groupProviderName, groupName, groupMemberName);
+ }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/User.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/User.java
index d97bf46d31..675dc8f0d3 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/User.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/User.java
@@ -52,8 +52,6 @@ public interface User extends ConfiguredObject
PASSWORD
));
- public String getPassword();
-
public void setPassword(String password);
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AuthenticationProviderAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AuthenticationProviderAdapter.java
index 8c2bc98ba7..adad2a355c 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AuthenticationProviderAdapter.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/AuthenticationProviderAdapter.java
@@ -38,7 +38,7 @@ import org.apache.qpid.server.security.access.Operation;
import org.apache.qpid.server.security.auth.database.PrincipalDatabase;
import org.apache.qpid.server.security.auth.manager.AuthenticationManager;
import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager;
-import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal;
+import org.apache.qpid.server.security.auth.UsernamePrincipal;
public abstract class AuthenticationProviderAdapter<T extends AuthenticationManager> extends AbstractAdapter implements AuthenticationProvider
{
@@ -147,7 +147,7 @@ public abstract class AuthenticationProviderAdapter<T extends AuthenticationMana
{
if(TYPE.equals(name))
{
- return _authManager.getClass().getSimpleName();
+ return getName();
}
else if(CREATED.equals(name))
{
@@ -195,7 +195,8 @@ public abstract class AuthenticationProviderAdapter<T extends AuthenticationMana
Map<String, Object> attributes,
ConfiguredObject... otherParents)
{
- return null;
+ throw new IllegalArgumentException("This authentication provider does not support" +
+ " creating children of type: " + childClass);
}
private static class SimpleAuthenticationProviderAdapter extends AuthenticationProviderAdapter<AuthenticationManager>
@@ -220,15 +221,20 @@ public abstract class AuthenticationProviderAdapter<T extends AuthenticationMana
@Override
public boolean createUser(String username, String password, Map<String, String> attributes)
{
- return getPrincipalDatabase().createPrincipal(new UsernamePrincipal(username), password.toCharArray());
+ if(getSecurityManager().authoriseUserOperation(Operation.CREATE, username))
+ {
+ return getPrincipalDatabase().createPrincipal(new UsernamePrincipal(username), password.toCharArray());
+ }
+ else
+ {
+ throw new AccessControlException("Do not have permission to create new user");
+ }
}
@Override
public void deleteUser(String username) throws AccountNotFoundException
{
- if(getSecurityManager().authoriseMethod(Operation.DELETE,
- "UserManagement",
- "deleteUser"))
+ if(getSecurityManager().authoriseUserOperation(Operation.DELETE, username))
{
getPrincipalDatabase().deletePrincipal(new UsernamePrincipal(username));
@@ -252,18 +258,13 @@ public abstract class AuthenticationProviderAdapter<T extends AuthenticationMana
@Override
public void setPassword(String username, String password) throws AccountNotFoundException
{
- getPrincipalDatabase().updatePassword(new UsernamePrincipal(username), password.toCharArray());
- }
-
- public void reload() throws IOException
- {
- if(getSecurityManager().authoriseMethod(Operation.UPDATE, "UserManagement", "reload"))
+ if(getSecurityManager().authoriseUserOperation(Operation.UPDATE, username))
{
- getPrincipalDatabase().reload();
+ getPrincipalDatabase().updatePassword(new UsernamePrincipal(username), password.toCharArray());
}
else
{
- throw new AccessControlException("Do not have permission to reload principal database");
+ throw new AccessControlException("Do not have permission to set password");
}
}
@@ -279,6 +280,11 @@ public abstract class AuthenticationProviderAdapter<T extends AuthenticationMana
return users;
}
+ public void reload() throws IOException
+ {
+ getPrincipalDatabase().reload();
+ }
+
@Override
public <C extends ConfiguredObject> C createChild(Class<C> childClass,
Map<String, Object> attributes,
@@ -286,19 +292,19 @@ public abstract class AuthenticationProviderAdapter<T extends AuthenticationMana
{
if(childClass == User.class)
{
- Principal p = new UsernamePrincipal((String) attributes.get("name"));
- if(getSecurityManager().authoriseMethod(Operation.UPDATE, "UserManagement", "createUser"))
+ String username = (String) attributes.get("name");
+ String password = (String) attributes.get("password");
+ Principal p = new UsernamePrincipal(username);
+
+ if(createUser(username, password,null))
{
- if(getPrincipalDatabase().createPrincipal(p, ((String)attributes.get("password")).toCharArray()))
- {
- return (C) new PrincipalAdapter(p);
- }
+ return (C) new PrincipalAdapter(p);
}
else
{
- throw new AccessControlException("Do not have permission to create a new user");
+ //TODO? Silly interface on the PrincipalDatabase at fault
+ throw new RuntimeException("Failed to create user");
}
-
}
return super.createChild(childClass, attributes, otherParents);
@@ -336,12 +342,6 @@ public abstract class AuthenticationProviderAdapter<T extends AuthenticationMana
}
@Override
- public String getPassword()
- {
- return null;
- }
-
- @Override
public void setPassword(String password)
{
try
@@ -445,6 +445,10 @@ public abstract class AuthenticationProviderAdapter<T extends AuthenticationMana
{
return getId();
}
+ else if(PASSWORD.equals(name))
+ {
+ return null; // for security reasons we don't expose the password
+ }
else if(NAME.equals(name))
{
return getName();
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapter.java
index f1cce2d45c..276dc83540 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapter.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapter.java
@@ -32,6 +32,7 @@ import org.apache.qpid.common.QpidProperties;
import org.apache.qpid.server.model.AuthenticationProvider;
import org.apache.qpid.server.model.Broker;
import org.apache.qpid.server.model.ConfiguredObject;
+import org.apache.qpid.server.model.GroupProvider;
import org.apache.qpid.server.model.LifetimePolicy;
import org.apache.qpid.server.model.Port;
import org.apache.qpid.server.model.Protocol;
@@ -43,12 +44,14 @@ import org.apache.qpid.server.model.VirtualHost;
import org.apache.qpid.server.registry.IApplicationRegistry;
import org.apache.qpid.server.security.auth.manager.AuthenticationManager;
import org.apache.qpid.server.security.auth.manager.IAuthenticationManagerRegistry;
+import org.apache.qpid.server.security.group.GroupManager;
import org.apache.qpid.server.transport.QpidAcceptor;
import org.apache.qpid.server.virtualhost.VirtualHostRegistry;
public class BrokerAdapter extends AbstractAdapter implements Broker, VirtualHostRegistry.RegistryChangeListener,
IApplicationRegistry.PortBindingListener,
- IAuthenticationManagerRegistry.RegistryChangeListener
+ IAuthenticationManagerRegistry.RegistryChangeListener,
+ IApplicationRegistry.GroupManagerChangeListener
{
@@ -62,6 +65,8 @@ public class BrokerAdapter extends AbstractAdapter implements Broker, VirtualHos
private final Map<AuthenticationManager, AuthenticationProviderAdapter> _authManagerAdapters =
new HashMap<AuthenticationManager, AuthenticationProviderAdapter>();
+ private final Map<GroupManager, GroupProviderAdapter> _groupManagerAdapters =
+ new HashMap<GroupManager, GroupProviderAdapter>();
public BrokerAdapter(final IApplicationRegistry instance)
@@ -75,8 +80,10 @@ public class BrokerAdapter extends AbstractAdapter implements Broker, VirtualHos
populateVhosts();
instance.addPortBindingListener(this);
populatePorts();
- instance.addRegistryChangeListener(this);
+ instance.addAuthenticationManagerRegistryChangeListener(this);
populateAuthenticationManagers();
+ instance.addGroupManagerChangeListener(this);
+ populateGroupManagers();
}
private void populateVhosts()
@@ -171,6 +178,25 @@ public class BrokerAdapter extends AbstractAdapter implements Broker, VirtualHos
}
}
+ private void populateGroupManagers()
+ {
+ synchronized (_groupManagerAdapters)
+ {
+ List<GroupManager> groupManagers = _applicationRegistry.getGroupManagers();
+ if(groupManagers != null)
+ {
+ for (GroupManager groupManager : groupManagers)
+ {
+ if(!_groupManagerAdapters.containsKey(groupManager))
+ {
+ _groupManagerAdapters.put(groupManager,
+ GroupProviderAdapter.createGroupProviderAdapter(this, groupManager));
+ }
+ }
+ }
+ }
+ }
+
public Collection<AuthenticationProvider> getAuthenticationProviders()
{
synchronized (_authManagerAdapters)
@@ -179,7 +205,16 @@ public class BrokerAdapter extends AbstractAdapter implements Broker, VirtualHos
new ArrayList<AuthenticationProvider>(_authManagerAdapters.values());
return authManagers;
}
+ }
+ public Collection<GroupProvider> getGroupProviders()
+ {
+ synchronized (_groupManagerAdapters)
+ {
+ final ArrayList<GroupProvider> groupManagers =
+ new ArrayList<GroupProvider>(_groupManagerAdapters.values());
+ return groupManagers;
+ }
}
public VirtualHost createVirtualHost(final String name,
@@ -277,6 +312,10 @@ public class BrokerAdapter extends AbstractAdapter implements Broker, VirtualHos
{
return (Collection<C>) getAuthenticationProviders();
}
+ else if(clazz == GroupProvider.class)
+ {
+ return (Collection<C>) getGroupProviders();
+ }
return Collections.emptySet();
}
@@ -491,4 +530,36 @@ public class BrokerAdapter extends AbstractAdapter implements Broker, VirtualHos
{
return super.setAttribute(name, expected, desired); //TODO - Implement.
}
+
+ @Override
+ public void groupManagerRegistered(GroupManager groupManager)
+ {
+ GroupProviderAdapter adapter = null;
+ synchronized (_groupManagerAdapters)
+ {
+ if(!_groupManagerAdapters.containsKey(groupManager))
+ {
+ adapter = GroupProviderAdapter.createGroupProviderAdapter(this, groupManager);
+ _groupManagerAdapters.put(groupManager, adapter);
+ }
+ }
+ if(adapter != null)
+ {
+ childAdded(adapter);
+ }
+ }
+
+ @Override
+ public void groupManagerUnregistered(GroupManager groupManager)
+ {
+ GroupProviderAdapter adapter;
+ synchronized (_groupManagerAdapters)
+ {
+ adapter = _groupManagerAdapters.remove(groupManager);
+ }
+ if(adapter != null)
+ {
+ childRemoved(adapter);
+ }
+ }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/GroupProviderAdapter.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/GroupProviderAdapter.java
new file mode 100644
index 0000000000..adc98919d5
--- /dev/null
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/model/adapter/GroupProviderAdapter.java
@@ -0,0 +1,548 @@
+/*
+ * 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.model.adapter;
+
+import java.security.AccessControlException;
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.qpid.server.model.Broker;
+import org.apache.qpid.server.model.ConfiguredObject;
+import org.apache.qpid.server.model.Group;
+import org.apache.qpid.server.model.GroupMember;
+import org.apache.qpid.server.model.GroupProvider;
+import org.apache.qpid.server.model.IllegalStateTransitionException;
+import org.apache.qpid.server.model.LifetimePolicy;
+import org.apache.qpid.server.model.State;
+import org.apache.qpid.server.model.Statistics;
+import org.apache.qpid.server.model.UUIDGenerator;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.security.access.Operation;
+import org.apache.qpid.server.security.group.GroupManager;
+
+public class GroupProviderAdapter extends AbstractAdapter implements
+ GroupProvider
+{
+ private final GroupManager _groupManager;
+
+ protected GroupProviderAdapter(GroupManager groupManager)
+ {
+ super(UUIDGenerator.generateRandomUUID());
+
+ if (groupManager == null)
+ {
+ throw new IllegalArgumentException("GroupManager must not be null");
+ }
+ _groupManager = groupManager;
+ }
+
+ public static GroupProviderAdapter createGroupProviderAdapter(
+ BrokerAdapter brokerAdapter, GroupManager groupManager)
+ {
+ final GroupProviderAdapter groupProviderAdapter = new GroupProviderAdapter(
+ groupManager);
+ groupProviderAdapter.addParent(Broker.class, brokerAdapter);
+ return groupProviderAdapter;
+ }
+
+ @Override
+ public String getName()
+ {
+ return _groupManager.getClass().getSimpleName();
+ }
+
+ @Override
+ public String setName(String currentName, String desiredName)
+ throws IllegalStateException, AccessControlException
+ {
+ return null;
+ }
+
+ @Override
+ public State getActualState()
+ {
+ return null;
+ }
+
+ @Override
+ public boolean isDurable()
+ {
+ return true;
+ }
+
+ @Override
+ public void setDurable(boolean durable) throws IllegalStateException,
+ AccessControlException, IllegalArgumentException
+ {
+ }
+
+ @Override
+ public LifetimePolicy getLifetimePolicy()
+ {
+ return LifetimePolicy.PERMANENT;
+ }
+
+ @Override
+ public LifetimePolicy setLifetimePolicy(LifetimePolicy expected,
+ LifetimePolicy desired) throws IllegalStateException,
+ AccessControlException, IllegalArgumentException
+ {
+ return null;
+ }
+
+ @Override
+ public long getTimeToLive()
+ {
+ return 0;
+ }
+
+ @Override
+ public long setTimeToLive(long expected, long desired)
+ throws IllegalStateException, AccessControlException,
+ IllegalArgumentException
+ {
+ return 0;
+ }
+
+ @Override
+ public Statistics getStatistics()
+ {
+ return NoStatistics.getInstance();
+ }
+
+ @Override
+ public Collection<String> getAttributeNames()
+ {
+ return GroupProvider.AVAILABLE_ATTRIBUTES;
+ }
+
+ @Override
+ public Object getAttribute(String name)
+ {
+ if (TYPE.equals(name))
+ {
+ return getName();
+ }
+ else if (CREATED.equals(name))
+ {
+ // TODO
+ }
+ else if (DURABLE.equals(name))
+ {
+ return true;
+ }
+ else if (ID.equals(name))
+ {
+ return getId();
+ }
+ else if (LIFETIME_POLICY.equals(name))
+ {
+ return LifetimePolicy.PERMANENT;
+ }
+ else if (NAME.equals(name))
+ {
+ return getName();
+ }
+ else if (STATE.equals(name))
+ {
+ return State.ACTIVE; // TODO
+ }
+ else if (TIME_TO_LIVE.equals(name))
+ {
+ // TODO
+ }
+ else if (UPDATED.equals(name))
+ {
+ // TODO
+ }
+ return super.getAttribute(name);
+ }
+
+ @Override
+ public <C extends ConfiguredObject> C createChild(Class<C> childClass,
+ Map<String, Object> attributes, ConfiguredObject... otherParents)
+ {
+ if (childClass == Group.class)
+ {
+ String groupName = (String) attributes.get(Group.NAME);
+
+ if (getSecurityManager().authoriseGroupOperation(Operation.CREATE, groupName))
+ {
+ _groupManager.createGroup(groupName);
+ return (C) new GroupAdapter(groupName);
+ }
+ else
+ {
+ throw new AccessControlException("Do not have permission" +
+ " to create new group");
+ }
+ }
+
+ throw new IllegalArgumentException(
+ "This group provider does not support creating children of type: "
+ + childClass);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public <C extends ConfiguredObject> Collection<C> getChildren(Class<C> clazz)
+ {
+ if (clazz == Group.class)
+ {
+ Set<Principal> groups = _groupManager.getGroupPrincipals();
+ Collection<Group> principals = new ArrayList<Group>(groups.size());
+ for (Principal group : groups)
+ {
+ principals.add(new GroupAdapter(group.getName()));
+ }
+ return (Collection<C>) Collections
+ .unmodifiableCollection(principals);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ private org.apache.qpid.server.security.SecurityManager getSecurityManager()
+ {
+ return ApplicationRegistry.getInstance().getSecurityManager();
+ }
+
+ private class GroupAdapter extends AbstractAdapter implements Group
+ {
+ private final String _group;
+
+ public GroupAdapter(String group)
+ {
+ super(UUIDGenerator.generateGroupUUID(
+ GroupProviderAdapter.this.getName(), group));
+ _group = group;
+
+ }
+
+ @Override
+ public String getName()
+ {
+ return _group;
+ }
+
+ @Override
+ public String setName(String currentName, String desiredName)
+ throws IllegalStateException, AccessControlException
+ {
+ throw new IllegalStateException("Names cannot be updated");
+ }
+
+ @Override
+ public State getActualState()
+ {
+ return State.ACTIVE;
+ }
+
+ @Override
+ public boolean isDurable()
+ {
+ return true;
+ }
+
+ @Override
+ public void setDurable(boolean durable) throws IllegalStateException,
+ AccessControlException, IllegalArgumentException
+ {
+ throw new IllegalStateException("Durability cannot be updated");
+ }
+
+ @Override
+ public LifetimePolicy getLifetimePolicy()
+ {
+ return LifetimePolicy.PERMANENT;
+ }
+
+ @Override
+ public LifetimePolicy setLifetimePolicy(LifetimePolicy expected,
+ LifetimePolicy desired) throws IllegalStateException,
+ AccessControlException, IllegalArgumentException
+ {
+ throw new IllegalStateException("LifetimePolicy cannot be updated");
+ }
+
+ @Override
+ public long getTimeToLive()
+ {
+ return 0;
+ }
+
+ @Override
+ public long setTimeToLive(long expected, long desired)
+ throws IllegalStateException, AccessControlException,
+ IllegalArgumentException
+ {
+ throw new IllegalStateException("ttl cannot be updated");
+ }
+
+ @Override
+ public Statistics getStatistics()
+ {
+ return NoStatistics.getInstance();
+ }
+
+ @Override
+ public <C extends ConfiguredObject> Collection<C> getChildren(
+ Class<C> clazz)
+ {
+ if (clazz == GroupMember.class)
+ {
+ Set<Principal> usersInGroup = _groupManager
+ .getUserPrincipalsForGroup(_group);
+ Collection<GroupMember> members = new ArrayList<GroupMember>();
+ for (Principal principal : usersInGroup)
+ {
+ members.add(new GroupMemberAdapter(principal.getName()));
+ }
+ return (Collection<C>) Collections
+ .unmodifiableCollection(members);
+ }
+ else
+ {
+ return null;
+ }
+
+ }
+
+ @Override
+ public <C extends ConfiguredObject> C createChild(Class<C> childClass,
+ Map<String, Object> attributes,
+ ConfiguredObject... otherParents)
+ {
+ if (childClass == GroupMember.class)
+ {
+ String memberName = (String) attributes.get(GroupMember.NAME);
+
+ if (getSecurityManager().authoriseGroupOperation(Operation.UPDATE, _group))
+ {
+ _groupManager.addUserToGroup(memberName, _group);
+ return (C) new GroupMemberAdapter(memberName);
+ }
+ else
+ {
+ throw new AccessControlException("Do not have permission" +
+ " to add new group member");
+ }
+ }
+
+ throw new IllegalArgumentException(
+ "This group provider does not support creating children of type: "
+ + childClass);
+ }
+
+ @Override
+ public Collection<String> getAttributeNames()
+ {
+ return Group.AVAILABLE_ATTRIBUTES;
+ }
+
+ @Override
+ public Object getAttribute(String name)
+ {
+ if (ID.equals(name))
+ {
+ return getId();
+ }
+ else if (NAME.equals(name))
+ {
+ return getName();
+ }
+ return super.getAttribute(name);
+ }
+
+ @Override
+ public Object setAttribute(String name, Object expected, Object desired)
+ throws IllegalStateException, AccessControlException,
+ IllegalArgumentException
+ {
+ return super.setAttribute(name, expected, desired);
+ }
+
+ @Override
+ public State setDesiredState(State currentState, State desiredState)
+ throws IllegalStateTransitionException, AccessControlException
+ {
+ if (desiredState == State.DELETED)
+ {
+ if (getSecurityManager().authoriseGroupOperation(Operation.DELETE, _group))
+ {
+ _groupManager.removeGroup(_group);
+ return State.DELETED;
+ }
+ else
+ {
+ throw new AccessControlException("Do not have permission" +
+ " to delete group");
+ }
+ }
+
+ return super.setDesiredState(currentState, desiredState);
+ }
+
+ private class GroupMemberAdapter extends AbstractAdapter implements
+ GroupMember
+ {
+ private String _memberName;
+
+ public GroupMemberAdapter(String memberName)
+ {
+ super(UUIDGenerator
+ .generateGroupMemberUUID(
+ GroupProviderAdapter.this.getName(), _group,
+ memberName));
+ _memberName = memberName;
+ }
+
+ @Override
+ public Collection<String> getAttributeNames()
+ {
+ return GroupMember.AVAILABLE_ATTRIBUTES;
+ }
+
+ @Override
+ public Object getAttribute(String name)
+ {
+ if (ID.equals(name))
+ {
+ return getId();
+ }
+ else if (NAME.equals(name))
+ {
+ return getName();
+ }
+ return super.getAttribute(name);
+ }
+
+ @Override
+ public String getName()
+ {
+ return _memberName;
+ }
+
+ @Override
+ public String setName(String currentName, String desiredName)
+ throws IllegalStateException, AccessControlException
+ {
+ return null;
+ }
+
+ @Override
+ public State getActualState()
+ {
+ return null;
+ }
+
+ @Override
+ public boolean isDurable()
+ {
+ return false;
+ }
+
+ @Override
+ public void setDurable(boolean durable)
+ throws IllegalStateException, AccessControlException,
+ IllegalArgumentException
+ {
+ }
+
+ @Override
+ public LifetimePolicy getLifetimePolicy()
+ {
+ return null;
+ }
+
+ @Override
+ public LifetimePolicy setLifetimePolicy(LifetimePolicy expected,
+ LifetimePolicy desired) throws IllegalStateException,
+ AccessControlException, IllegalArgumentException
+ {
+ return null;
+ }
+
+ @Override
+ public long getTimeToLive()
+ {
+ return 0;
+ }
+
+ @Override
+ public long setTimeToLive(long expected, long desired)
+ throws IllegalStateException, AccessControlException,
+ IllegalArgumentException
+ {
+ return 0;
+ }
+
+ @Override
+ public Statistics getStatistics()
+ {
+ return NoStatistics.getInstance();
+ }
+
+ @Override
+ public <C extends ConfiguredObject> Collection<C> getChildren(
+ Class<C> clazz)
+ {
+ return null;
+ }
+
+ @Override
+ public <C extends ConfiguredObject> C createChild(
+ Class<C> childClass, Map<String, Object> attributes,
+ ConfiguredObject... otherParents)
+ {
+ return null;
+ }
+
+ @Override
+ public State setDesiredState(State currentState, State desiredState)
+ throws IllegalStateTransitionException,
+ AccessControlException
+ {
+ if (desiredState == State.DELETED)
+ {
+ if (getSecurityManager().authoriseGroupOperation(Operation.UPDATE, _group))
+ {
+ _groupManager.removeUserFromGroup(_memberName, _group);
+ return State.DELETED;
+ }
+ else
+ {
+ throw new AccessControlException("Do not have permission" +
+ " to remove group member");
+ }
+ }
+
+ return super.setDesiredState(currentState, desiredState);
+ }
+
+ }
+ }
+}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java
index 74abbccd2b..ff38d5ec58 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/plugins/PluginManager.java
@@ -49,6 +49,8 @@ import org.apache.qpid.server.security.auth.manager.ExternalAuthenticationManage
import org.apache.qpid.server.security.auth.manager.KerberosAuthenticationManager;
import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager;
import org.apache.qpid.server.security.auth.manager.SimpleLDAPAuthenticationManager;
+import org.apache.qpid.server.security.group.FileGroupManager;
+import org.apache.qpid.server.security.group.GroupManagerPluginFactory;
import org.apache.qpid.server.virtualhost.plugins.SlowConsumerDetection;
import org.apache.qpid.server.virtualhost.plugins.VirtualHostPluginFactory;
import org.apache.qpid.server.virtualhost.plugins.policies.TopicDeletePolicy;
@@ -90,6 +92,7 @@ public class PluginManager implements Closeable
private ServiceTracker _virtualHostTracker = null;
private ServiceTracker _policyTracker = null;
private ServiceTracker _authenticationManagerTracker = null;
+ private ServiceTracker _groupManagerTracker = null;
private Activator _activator;
@@ -99,6 +102,7 @@ public class PluginManager implements Closeable
private Map<String, VirtualHostPluginFactory> _vhostPlugins = new HashMap<String, VirtualHostPluginFactory>();
private Map<String, SlowConsumerPolicyPluginFactory> _policyPlugins = new HashMap<String, SlowConsumerPolicyPluginFactory>();
private Map<String, AuthenticationManagerPluginFactory<? extends Plugin>> _authenticationManagerPlugins = new HashMap<String, AuthenticationManagerPluginFactory<? extends Plugin>>();
+ private Map<String, GroupManagerPluginFactory<? extends Plugin>> _groupManagerPlugins = new HashMap<String, GroupManagerPluginFactory<? extends Plugin>>();
/** The default name of the OSGI system package list. */
private static final String DEFAULT_RESOURCE_NAME = "org/apache/qpid/server/plugins/OsgiSystemPackages.properties";
@@ -162,7 +166,8 @@ public class PluginManager implements Closeable
AnonymousAuthenticationManager.AnonymousAuthenticationManagerConfiguration.FACTORY,
KerberosAuthenticationManager.KerberosAuthenticationManagerConfiguration.FACTORY,
SimpleLDAPAuthenticationManager.SimpleLDAPAuthenticationManagerConfiguration.FACTORY,
- ExternalAuthenticationManager.ExternalAuthenticationManagerConfiguration.FACTORY
+ ExternalAuthenticationManager.ExternalAuthenticationManagerConfiguration.FACTORY,
+ FileGroupManager.FileGroupManagerConfiguration.FACTORY
))
{
_configPlugins.put(configFactory.getParentPaths(), configFactory);
@@ -186,6 +191,12 @@ public class PluginManager implements Closeable
_authenticationManagerPlugins.put(pluginFactory.getPluginName(), pluginFactory);
}
+ for (GroupManagerPluginFactory<? extends Plugin> pluginFactory : Arrays.asList(
+ FileGroupManager.FACTORY))
+ {
+ _groupManagerPlugins.put(pluginFactory.getPluginName(), pluginFactory);
+ }
+
if(bundleContext == null)
{
// Check the plugin directory path is set and exist
@@ -283,6 +294,11 @@ public class PluginManager implements Closeable
_authenticationManagerTracker.open();
_trackers.add(_authenticationManagerTracker);
+ _groupManagerTracker = new ServiceTracker(bundleContext, GroupManagerPluginFactory.class.getName(), null);
+ _groupManagerTracker.open();
+ _trackers.add(_groupManagerTracker);
+
+
_logger.info("Opened service trackers");
}
@@ -358,6 +374,11 @@ public class PluginManager implements Closeable
return getServices(_authenticationManagerTracker, _authenticationManagerPlugins);
}
+ public Map<String, GroupManagerPluginFactory<? extends Plugin>> getGroupManagerPlugins()
+ {
+ return getServices(_groupManagerTracker, _groupManagerPlugins);
+ }
+
public void close()
{
try
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java
index 1e649c3cb7..aac7562be2 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolEngine.java
@@ -68,6 +68,7 @@ import org.apache.qpid.server.output.ProtocolOutputConverter;
import org.apache.qpid.server.output.ProtocolOutputConverterRegistry;
import org.apache.qpid.server.queue.QueueEntry;
import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.security.auth.AuthenticatedPrincipal;
import org.apache.qpid.server.state.AMQState;
import org.apache.qpid.server.state.AMQStateManager;
import org.apache.qpid.server.stats.StatisticsCounter;
@@ -367,7 +368,7 @@ public class AMQProtocolEngine implements ServerProtocolEngine, AMQProtocolSessi
// This sets the protocol version (and hence framing classes) for this session.
setProtocolVersion(pv);
- String mechanisms = ApplicationRegistry.getInstance().getAuthenticationManager(getLocalAddress()).getMechanisms();
+ String mechanisms = ApplicationRegistry.getInstance().getSubjectCreator(getLocalAddress()).getMechanisms();
String locales = "en_US";
@@ -1017,7 +1018,7 @@ public class AMQProtocolEngine implements ServerProtocolEngine, AMQProtocolSessi
public Principal getAuthorizedPrincipal()
{
- return _authorizedSubject == null ? null : _authorizedSubject.getPrincipals().iterator().next();
+ return _authorizedSubject == null ? null : _authorizedSubject.getPrincipals(AuthenticatedPrincipal.class).iterator().next();
}
public SocketAddress getRemoteAddress()
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/MultiVersionProtocolEngine.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/MultiVersionProtocolEngine.java
index 5c92aa95b6..152f591e66 100755
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/MultiVersionProtocolEngine.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/MultiVersionProtocolEngine.java
@@ -302,7 +302,7 @@ public class MultiVersionProtocolEngine implements ServerProtocolEngine
public ServerProtocolEngine getProtocolEngine()
{
final ConnectionDelegate connDelegate =
- new org.apache.qpid.server.transport.ServerConnectionDelegate(_appRegistry, _fqdn, _appRegistry.getAuthenticationManager(getLocalAddress()));
+ new org.apache.qpid.server.transport.ServerConnectionDelegate(_appRegistry, _fqdn, _appRegistry.getSubjectCreator(getLocalAddress()));
ServerConnection conn = new ServerConnection(_id);
conn.setConnectionDelegate(connDelegate);
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngine_1_0_0.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngine_1_0_0.java
index e6282315c6..ba5348c0ed 100755
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngine_1_0_0.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngine_1_0_0.java
@@ -43,6 +43,7 @@ import org.apache.qpid.server.configuration.ConfigStore;
import org.apache.qpid.server.configuration.ConnectionConfigType;
import org.apache.qpid.server.protocol.v1_0.Connection_1_0;
import org.apache.qpid.server.registry.IApplicationRegistry;
+import org.apache.qpid.server.security.SubjectCreator;
import org.apache.qpid.server.security.auth.manager.AuthenticationManager;
import org.apache.qpid.transport.Sender;
import org.apache.qpid.transport.network.NetworkConnection;
@@ -144,7 +145,7 @@ public class ProtocolEngine_1_0_0 implements ServerProtocolEngine, FrameOutputHa
Container container = new Container(_appRegistry.getBrokerId().toString());
- _conn = new ConnectionEndpoint(container, asSaslServerProvider(_appRegistry.getAuthenticationManager(
+ _conn = new ConnectionEndpoint(container, asSaslServerProvider(_appRegistry.getSubjectCreator(
getLocalAddress())));
_conn.setConnectionEventListener(new Connection_1_0(_appRegistry, _conn, _connectionId));
_conn.setFrameOutputHandler(this);
@@ -157,14 +158,14 @@ public class ProtocolEngine_1_0_0 implements ServerProtocolEngine, FrameOutputHa
_sender.flush();
}
- private SaslServerProvider asSaslServerProvider(final AuthenticationManager authenticationManager)
+ private SaslServerProvider asSaslServerProvider(final SubjectCreator subjectCreator)
{
return new SaslServerProvider()
{
@Override
public SaslServer getSaslServer(String mechanism, String fqdn) throws SaslException
{
- return authenticationManager.createSaslServer(mechanism, fqdn, null);
+ return subjectCreator.createSaslServer(mechanism, fqdn, null);
}
};
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngine_1_0_0_SASL.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngine_1_0_0_SASL.java
index a48441bf30..b80080b991 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngine_1_0_0_SASL.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/protocol/ProtocolEngine_1_0_0_SASL.java
@@ -45,7 +45,7 @@ import org.apache.qpid.server.configuration.ConnectionConfigType;
import org.apache.qpid.server.protocol.v1_0.Connection_1_0;
import org.apache.qpid.server.registry.ApplicationRegistry;
import org.apache.qpid.server.registry.IApplicationRegistry;
-import org.apache.qpid.server.security.auth.manager.AuthenticationManager;
+import org.apache.qpid.server.security.SubjectCreator;
import org.apache.qpid.transport.Sender;
import org.apache.qpid.transport.network.NetworkConnection;
@@ -165,7 +165,7 @@ public class ProtocolEngine_1_0_0_SASL implements ServerProtocolEngine, FrameOut
Container container = new Container(_appRegistry.getBrokerId().toString());
_conn = new ConnectionEndpoint(container, asSaslServerProvider(ApplicationRegistry.getInstance()
- .getAuthenticationManager(getLocalAddress())));
+ .getSubjectCreator(getLocalAddress())));
_conn.setConnectionEventListener(new Connection_1_0(_appRegistry, _conn, _connectionId));
_conn.setRemoteAddress(getRemoteAddress());
@@ -175,8 +175,6 @@ public class ProtocolEngine_1_0_0_SASL implements ServerProtocolEngine, FrameOut
_conn.setOnSaslComplete(new Runnable()
{
-
-
public void run()
{
if(_conn.isAuthenticated())
@@ -201,14 +199,14 @@ public class ProtocolEngine_1_0_0_SASL implements ServerProtocolEngine, FrameOut
}
- private SaslServerProvider asSaslServerProvider(final AuthenticationManager authenticationManager)
+ private SaslServerProvider asSaslServerProvider(final SubjectCreator subjectCreator)
{
return new SaslServerProvider()
{
@Override
public SaslServer getSaslServer(String mechanism, String fqdn) throws SaslException
{
- return authenticationManager.createSaslServer(mechanism, fqdn, null);
+ return subjectCreator.createSaslServer(mechanism, fqdn, null);
}
};
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java
index e0e317f75d..f31275fa36 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java
@@ -42,11 +42,17 @@ import org.apache.qpid.server.logging.messages.BrokerMessages;
import org.apache.qpid.server.logging.messages.VirtualHostMessages;
import org.apache.qpid.server.model.Broker;
import org.apache.qpid.server.model.adapter.BrokerAdapter;
+import org.apache.qpid.server.plugins.Plugin;
import org.apache.qpid.server.plugins.PluginManager;
import org.apache.qpid.server.security.SecurityManager;
+import org.apache.qpid.server.security.SubjectCreator;
+import org.apache.qpid.server.security.SecurityManager.SecurityConfiguration;
import org.apache.qpid.server.security.auth.manager.AuthenticationManager;
import org.apache.qpid.server.security.auth.manager.AuthenticationManagerRegistry;
import org.apache.qpid.server.security.auth.manager.IAuthenticationManagerRegistry;
+import org.apache.qpid.server.security.group.GroupManager;
+import org.apache.qpid.server.security.group.GroupManagerPluginFactory;
+import org.apache.qpid.server.security.group.GroupPrincipalAccessor;
import org.apache.qpid.server.stats.StatisticsCounter;
import org.apache.qpid.server.transport.QpidAcceptor;
import org.apache.qpid.server.virtualhost.VirtualHost;
@@ -87,7 +93,7 @@ public abstract class ApplicationRegistry implements IApplicationRegistry
private ConfigurationManager _configurationManager;
- private RootMessageLogger _rootMessageLogger;
+ private volatile RootMessageLogger _rootMessageLogger;
private CompositeStartupMessageLogger _startupMessageLogger;
@@ -115,6 +121,11 @@ public abstract class ApplicationRegistry implements IApplicationRegistry
private List<IAuthenticationManagerRegistry.RegistryChangeListener> _authManagerChangeListeners =
new ArrayList<IAuthenticationManagerRegistry.RegistryChangeListener>();
+ private List<GroupManagerChangeListener> _groupManagerChangeListeners =
+ new ArrayList<GroupManagerChangeListener>();
+
+ private List<GroupManager> _groupManagerList = new ArrayList<GroupManager>();
+
public Map<InetSocketAddress, QpidAcceptor> getAcceptors()
{
synchronized (_acceptors)
@@ -314,7 +325,25 @@ public abstract class ApplicationRegistry implements IApplicationRegistry
_securityManager = new SecurityManager(_configuration, _pluginManager);
- _authenticationManagerRegistry = createAuthenticationManagerRegistry(_configuration, _pluginManager);
+ final Collection<GroupManagerPluginFactory<? extends Plugin>> factories = _pluginManager.getGroupManagerPlugins().values();
+ final SecurityConfiguration securityConfiguration = _configuration.getConfiguration(SecurityConfiguration.class.getName());
+
+ for(GroupManagerPluginFactory<? extends Plugin> factory : factories)
+ {
+ final GroupManager groupManager = factory.newInstance(securityConfiguration);
+ if(groupManager != null)
+ {
+ _groupManagerList.add(groupManager);
+
+ for(GroupManagerChangeListener listener : _groupManagerChangeListeners)
+ {
+ listener.groupManagerRegistered(groupManager);
+ }
+ }
+ }
+ _logger.debug("Created " + _groupManagerList.size() + " group manager(s)");
+
+ _authenticationManagerRegistry = createAuthenticationManagerRegistry(_configuration, _pluginManager, new GroupPrincipalAccessor(_groupManagerList));
if(!_authManagerChangeListeners.isEmpty())
{
@@ -348,10 +377,10 @@ public abstract class ApplicationRegistry implements IApplicationRegistry
}
}
- protected IAuthenticationManagerRegistry createAuthenticationManagerRegistry(ServerConfiguration _configuration, PluginManager _pluginManager)
+ protected IAuthenticationManagerRegistry createAuthenticationManagerRegistry(ServerConfiguration configuration, PluginManager pluginManager, GroupPrincipalAccessor groupManagerList)
throws ConfigurationException
{
- return new AuthenticationManagerRegistry(_configuration, _pluginManager);
+ return new AuthenticationManagerRegistry(configuration, pluginManager, groupManagerList);
}
protected void initialiseVirtualHosts() throws Exception
@@ -588,9 +617,9 @@ public abstract class ApplicationRegistry implements IApplicationRegistry
}
@Override
- public AuthenticationManager getAuthenticationManager(SocketAddress address)
+ public SubjectCreator getSubjectCreator(SocketAddress localAddress)
{
- return _authenticationManagerRegistry.getAuthenticationManager(address);
+ return _authenticationManagerRegistry.getSubjectCreator(localAddress);
}
@Override
@@ -599,6 +628,12 @@ public abstract class ApplicationRegistry implements IApplicationRegistry
return _authenticationManagerRegistry;
}
+ @Override
+ public List<GroupManager> getGroupManagers()
+ {
+ return _groupManagerList;
+ }
+
public PluginManager getPluginManager()
{
return _pluginManager;
@@ -758,7 +793,7 @@ public abstract class ApplicationRegistry implements IApplicationRegistry
}
@Override
- public void addRegistryChangeListener(IAuthenticationManagerRegistry.RegistryChangeListener registryChangeListener)
+ public void addAuthenticationManagerRegistryChangeListener(IAuthenticationManagerRegistry.RegistryChangeListener registryChangeListener)
{
if(_authenticationManagerRegistry == null)
{
@@ -769,4 +804,10 @@ public abstract class ApplicationRegistry implements IApplicationRegistry
_authenticationManagerRegistry.addRegistryChangeListener(registryChangeListener);
}
}
+
+ @Override
+ public void addGroupManagerChangeListener(GroupManagerChangeListener groupManagerChangeListener)
+ {
+ _groupManagerChangeListeners.add(groupManagerChangeListener);
+ }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java
index 88c3c93156..5959b6fbe2 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/registry/IApplicationRegistry.java
@@ -30,8 +30,10 @@ import org.apache.qpid.server.logging.RootMessageLogger;
import org.apache.qpid.server.model.Broker;
import org.apache.qpid.server.plugins.PluginManager;
import org.apache.qpid.server.security.SecurityManager;
+import org.apache.qpid.server.security.SubjectCreator;
import org.apache.qpid.server.security.auth.manager.AuthenticationManager;
import org.apache.qpid.server.security.auth.manager.IAuthenticationManagerRegistry;
+import org.apache.qpid.server.security.group.GroupManager;
import org.apache.qpid.server.stats.StatisticsGatherer;
import org.apache.qpid.server.transport.QpidAcceptor;
import org.apache.qpid.server.virtualhost.VirtualHost;
@@ -39,6 +41,7 @@ import org.apache.qpid.server.virtualhost.VirtualHostRegistry;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
+import java.util.List;
import java.util.Map;
import java.util.UUID;
@@ -64,18 +67,16 @@ public interface IApplicationRegistry extends StatisticsGatherer
ServerConfiguration getConfiguration();
/**
- * Get the AuthenticationManager for the given socket address
- *
- * If no AuthenticationManager has been specifically set for the given address, then use the default
- * AuthenticationManager
+ * Get the SubjectCreator for the given socket address.
*
* @param address The (listening) socket address for which the AuthenticationManager is required
- * @return the AuthenticationManager
*/
- AuthenticationManager getAuthenticationManager(SocketAddress address);
+ SubjectCreator getSubjectCreator(SocketAddress localAddress);
IAuthenticationManagerRegistry getAuthenticationManagerRegistry();
+ List<GroupManager> getGroupManagers();
+
VirtualHostRegistry getVirtualHostRegistry();
SecurityManager getSecurityManager();
@@ -123,7 +124,7 @@ public interface IApplicationRegistry extends StatisticsGatherer
int getHTTPSManagementPort();
- void addRegistryChangeListener(IAuthenticationManagerRegistry.RegistryChangeListener registryChangeListener);
+ void addAuthenticationManagerRegistryChangeListener(IAuthenticationManagerRegistry.RegistryChangeListener registryChangeListener);
public interface PortBindingListener
{
@@ -132,4 +133,11 @@ public interface IApplicationRegistry extends StatisticsGatherer
}
+ void addGroupManagerChangeListener(GroupManagerChangeListener groupManagerChangeListener);
+
+ public static interface GroupManagerChangeListener
+ {
+ void groupManagerRegistered(GroupManager groupManager);
+ void groupManagerUnregistered(GroupManager groupManager);
+ }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/AuthorizationHolder.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/AuthorizationHolder.java
index 8f3bdf7738..8243fc3f75 100755
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/AuthorizationHolder.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/AuthorizationHolder.java
@@ -24,14 +24,14 @@ import javax.security.auth.Subject;
import java.security.Principal;
/**
- * Represents the authorization of the logged on user.
- *
+ * Represents the authorization of the logged on user.
+ *
*/
public interface AuthorizationHolder
{
- /**
+ /**
* Returns the {@link Subject} of the authorized user. This is guaranteed to
- * contain at least one {@link org.apache.qpid.server.security.auth.sasl.UsernamePrincipal}, representing the the identity
+ * contain at least one {@link org.apache.qpid.server.security.auth.UsernamePrincipal}, representing the the identity
* used when the user logged on to the application, and zero or more {@link org.apache.qpid.server.security.auth.sasl.GroupPrincipal}
* representing the group(s) to which the user belongs.
*
@@ -39,10 +39,10 @@ public interface AuthorizationHolder
*/
Subject getAuthorizedSubject();
- /**
+ /**
* Returns the {@link Principal} representing the the identity
* used when the user logged on to the application.
- *
+ *
* @return a Principal
*/
Principal getAuthorizedPrincipal();
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java
index 436660cfaf..088d120821 100755
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SecurityManager.java
@@ -32,8 +32,10 @@ import org.apache.qpid.server.security.access.ObjectProperties;
import org.apache.qpid.server.security.access.Operation;
import static org.apache.qpid.server.security.access.ObjectType.EXCHANGE;
+import static org.apache.qpid.server.security.access.ObjectType.GROUP;
import static org.apache.qpid.server.security.access.ObjectType.METHOD;
import static org.apache.qpid.server.security.access.ObjectType.QUEUE;
+import static org.apache.qpid.server.security.access.ObjectType.USER;
import static org.apache.qpid.server.security.access.ObjectType.VIRTUALHOST;
import static org.apache.qpid.server.security.access.Operation.BIND;
import static org.apache.qpid.server.security.access.Operation.CONSUME;
@@ -387,6 +389,27 @@ public class SecurityManager
});
}
+ public boolean authoriseGroupOperation(final Operation operation, final String groupName)
+ {
+ return checkAllPlugins(new AccessCheck()
+ {
+ Result allowed(SecurityPlugin plugin)
+ {
+ return plugin.authorise(operation, GROUP, new ObjectProperties(groupName));
+ }
+ });
+ }
+
+ public boolean authoriseUserOperation(final Operation operation, final String userName)
+ {
+ return checkAllPlugins(new AccessCheck()
+ {
+ Result allowed(SecurityPlugin plugin)
+ {
+ return plugin.authorise(operation, USER, new ObjectProperties(userName));
+ }
+ });
+ }
private ConcurrentHashMap<String, ConcurrentHashMap<String, PublishAccessCheck>> _immediatePublishPropsCache
= new ConcurrentHashMap<String, ConcurrentHashMap<String, PublishAccessCheck>>();
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SubjectCreator.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SubjectCreator.java
new file mode 100644
index 0000000000..8138745486
--- /dev/null
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/SubjectCreator.java
@@ -0,0 +1,137 @@
+/*
+ *
+ * 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;
+
+import java.security.Principal;
+
+import javax.security.auth.Subject;
+import javax.security.sasl.SaslException;
+import javax.security.sasl.SaslServer;
+
+import org.apache.qpid.server.security.auth.AuthenticatedPrincipal;
+import org.apache.qpid.server.security.auth.AuthenticationResult;
+import org.apache.qpid.server.security.auth.AuthenticationResult.AuthenticationStatus;
+import org.apache.qpid.server.security.auth.SubjectAuthenticationResult;
+import org.apache.qpid.server.security.auth.manager.AuthenticationManager;
+import org.apache.qpid.server.security.group.GroupPrincipalAccessor;
+
+/**
+ * Creates a {@link Subject} formed by the {@link Principal}'s returned from:
+ * <ol>
+ * <li>Authenticating using an {@link AuthenticationManager}</li>
+ * <li>A {@link GroupPrincipalAccessor}</li>
+ * </ol>
+ *
+ * <p>
+ * SubjectCreator is a facade to the {@link AuthenticationManager}, and is intended to be
+ * the single place that {@link Subject}'s are created in the broker.
+ * </p>
+ */
+public class SubjectCreator
+{
+ private AuthenticationManager _authenticationManager;
+ private GroupPrincipalAccessor _groupAccessor;
+
+ public SubjectCreator(AuthenticationManager authenticationManager, GroupPrincipalAccessor groupAccessor)
+ {
+ _authenticationManager = authenticationManager;
+ _groupAccessor = groupAccessor;
+ }
+
+ /**
+ * Gets the known SASL mechanisms
+ *
+ * @return SASL mechanism names, space separated.
+ */
+ public String getMechanisms()
+ {
+ return _authenticationManager.getMechanisms();
+ }
+
+ /**
+ * @see AuthenticationManager#createSaslServer(String, String, Principal)
+ */
+ public SaslServer createSaslServer(String mechanism, String localFQDN, Principal externalPrincipal) throws SaslException
+ {
+ return _authenticationManager.createSaslServer(mechanism, localFQDN, externalPrincipal);
+ }
+
+ /**
+ * Authenticates a user using SASL negotiation.
+ *
+ * @param server SASL server
+ * @param response SASL response to process
+ */
+ public SubjectAuthenticationResult authenticate(SaslServer server, byte[] response)
+ {
+ AuthenticationResult authenticationResult = _authenticationManager.authenticate(server, response);
+ if(server.isComplete())
+ {
+ String username = server.getAuthorizationID();
+
+ return createResultWithGroups(username, authenticationResult);
+ }
+ else
+ {
+ return new SubjectAuthenticationResult(authenticationResult);
+ }
+ }
+
+ /**
+ * Authenticates a user using their username and password.
+ */
+ public SubjectAuthenticationResult authenticate(String username, String password)
+ {
+ final AuthenticationResult authenticationResult = _authenticationManager.authenticate(username, password);
+
+ return createResultWithGroups(username, authenticationResult);
+ }
+
+ private SubjectAuthenticationResult createResultWithGroups(String username, final AuthenticationResult authenticationResult)
+ {
+ if(authenticationResult.getStatus() == AuthenticationStatus.SUCCESS)
+ {
+ final Subject authenticationSubject = new Subject();
+
+ authenticationSubject.getPrincipals().addAll(authenticationResult.getPrincipals());
+ authenticationSubject.getPrincipals().addAll(_groupAccessor.getGroupPrincipals(username));
+
+ authenticationSubject.setReadOnly();
+
+ return new SubjectAuthenticationResult(authenticationResult, authenticationSubject);
+ }
+ else
+ {
+ return new SubjectAuthenticationResult(authenticationResult);
+ }
+ }
+
+ public Subject createSubjectWithGroups(String username)
+ {
+ Subject authenticationSubject = new Subject();
+
+ authenticationSubject.getPrincipals().add(new AuthenticatedPrincipal(username));
+ authenticationSubject.getPrincipals().addAll(_groupAccessor.getGroupPrincipals(username));
+ authenticationSubject.setReadOnly();
+
+ return authenticationSubject;
+ }
+}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectType.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectType.java
index 90ecd1dd17..043d4909d5 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectType.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/access/ObjectType.java
@@ -45,8 +45,10 @@ public enum ObjectType
EXCHANGE(Operation.ALL, ACCESS, CREATE, DELETE, BIND, UNBIND, PUBLISH),
LINK, // Not allowed in the Java broker
ROUTE, // Not allowed in the Java broker
- METHOD(Operation.ALL, ACCESS, UPDATE);
-
+ METHOD(Operation.ALL, ACCESS, UPDATE),
+ USER(Operation.ALL, CREATE, DELETE, UPDATE),
+ GROUP(Operation.ALL, CREATE, DELETE, UPDATE);
+
private EnumSet<Operation> _actions;
private ObjectType()
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticatedPrincipal.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticatedPrincipal.java
new file mode 100644
index 0000000000..96360e83e4
--- /dev/null
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticatedPrincipal.java
@@ -0,0 +1,126 @@
+/*
+ * 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.auth;
+
+import java.security.Principal;
+import java.util.Set;
+
+import javax.security.auth.Subject;
+
+import org.apache.qpid.server.security.auth.UsernamePrincipal;
+
+/**
+ * A simple Principal wrapper. Exists to allow us to identify the "primary" principal
+ * by calling {@link Subject#getPrincipals(Class)}, passing in {@link AuthenticatedPrincipal}.class,
+ * e.g. when logging.
+ */
+public final class AuthenticatedPrincipal implements Principal
+{
+ private final Principal _wrappedPrincipal;
+
+ /** convenience constructor for the common case where we're wrapping a {@link UsernamePrincipal} */
+ public AuthenticatedPrincipal(String userPrincipalName)
+ {
+ this(new UsernamePrincipal(userPrincipalName));
+ }
+
+ public AuthenticatedPrincipal(Principal wrappedPrincipal)
+ {
+ if(wrappedPrincipal == null)
+ {
+ throw new IllegalArgumentException("Wrapped principal is null");
+ }
+
+ _wrappedPrincipal = wrappedPrincipal;
+ }
+
+ @Override
+ public String getName()
+ {
+ return _wrappedPrincipal.getName();
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return _wrappedPrincipal.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ {
+ return true;
+ }
+
+ if (!(obj instanceof AuthenticatedPrincipal))
+ {
+ return false;
+ }
+
+ AuthenticatedPrincipal other = (AuthenticatedPrincipal) obj;
+
+ return _wrappedPrincipal.equals(other._wrappedPrincipal);
+ }
+
+ public static AuthenticatedPrincipal getOptionalAuthenticatedPrincipalFromSubject(final Subject authSubject)
+ {
+ return getAuthenticatedPrincipalFromSubject(authSubject, true);
+ }
+
+ public static AuthenticatedPrincipal getAuthenticatedPrincipalFromSubject(final Subject authSubject)
+ {
+ return getAuthenticatedPrincipalFromSubject(authSubject, false);
+ }
+
+ private static AuthenticatedPrincipal getAuthenticatedPrincipalFromSubject(final Subject authSubject, boolean isPrincipalOptional)
+ {
+ if (authSubject == null)
+ {
+ throw new IllegalArgumentException("No authenticated subject.");
+ }
+
+ final Set<AuthenticatedPrincipal> principals = authSubject.getPrincipals(AuthenticatedPrincipal.class);
+ int numberOfAuthenticatedPrincipals = principals.size();
+
+ if(numberOfAuthenticatedPrincipals == 0 && isPrincipalOptional)
+ {
+ return null;
+ }
+ else
+ {
+ if (numberOfAuthenticatedPrincipals != 1)
+ {
+ throw new IllegalArgumentException(
+ "Can't find single AuthenticatedPrincipal in authenticated subject. There were "
+ + numberOfAuthenticatedPrincipals
+ + " authenticated principals out of a total number of principals of: " + authSubject.getPrincipals());
+ }
+ return principals.iterator().next();
+ }
+ }
+
+ @Override
+ public String toString()
+ {
+ return getName();
+ }
+
+}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationResult.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationResult.java
index 949c0f2b89..a49dd6793f 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationResult.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/AuthenticationResult.java
@@ -7,9 +7,9 @@
* 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
@@ -20,15 +20,20 @@
*/
package org.apache.qpid.server.security.auth;
-import javax.security.auth.Subject;
+import java.security.Principal;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.qpid.server.security.auth.manager.AuthenticationManager;
/**
- * Encapsulates the result of an attempt to authenticate.
+ * Encapsulates the result of an attempt to authenticate using an {@link AuthenticationManager}.
* <p>
* The authentication status describes the overall outcome.
* <p>
* <ol>
- * <li>If authentication status is SUCCESS, the subject will be populated.
+ * <li>If authentication status is SUCCESS, at least one {@link Principal} will be populated.
* </li>
* <li>If authentication status is CONTINUE, the authentication has failed because the user
* supplied incorrect credentials (etc). If the authentication requires it, the next challenge
@@ -40,6 +45,8 @@ import javax.security.auth.Subject;
* </li>
* </ol>
*
+ * The main principal provided to the constructor is wrapped in an {@link AuthenticatedPrincipal}
+ * to make it easier for the rest of the application to identify it among the set of other principals.
*/
public class AuthenticationResult
{
@@ -56,37 +63,54 @@ public class AuthenticationResult
private final AuthenticationStatus _status;
private final byte[] _challenge;
private final Exception _cause;
- private final Subject _subject;
+ private final Set<Principal> _principals = new HashSet<Principal>();
public AuthenticationResult(final AuthenticationStatus status)
{
this(null, status, null);
}
+ public AuthenticationResult(Principal mainPrincipal)
+ {
+ this(mainPrincipal, Collections.<Principal>emptySet());
+ }
+
+ public AuthenticationResult(Principal mainPrincipal, Set<Principal> otherPrincipals)
+ {
+ AuthenticatedPrincipal specialQpidAuthenticatedPrincipal = new AuthenticatedPrincipal(mainPrincipal);
+ _principals.addAll(otherPrincipals);
+ _principals.remove(mainPrincipal);
+ _principals.add(specialQpidAuthenticatedPrincipal);
+
+ _status = AuthenticationStatus.SUCCESS;
+ _challenge = null;
+ _cause = null;
+ }
+
public AuthenticationResult(final byte[] challenge, final AuthenticationStatus status)
{
- this(challenge, status, null);
+ _challenge = challenge;
+ _status = status;
+ _cause = null;
}
public AuthenticationResult(final AuthenticationStatus error, final Exception cause)
{
- this(null, error, cause);
+ _status = error;
+ _challenge = null;
+ _cause = cause;
}
public AuthenticationResult(final byte[] challenge, final AuthenticationStatus status, final Exception cause)
{
+ if(status == AuthenticationStatus.SUCCESS)
+ {
+ throw new IllegalArgumentException("Successful authentication requires at least one principal");
+ }
+
this._status = status;
this._challenge = challenge;
this._cause = cause;
- this._subject = null;
- }
-
- public AuthenticationResult(final Subject subject)
- {
- this._status = AuthenticationStatus.SUCCESS;
- this._challenge = null;
- this._cause = null;
- this._subject = subject;
}
public Exception getCause()
@@ -104,9 +128,8 @@ public class AuthenticationResult
return _challenge;
}
- public Subject getSubject()
+ public Set<Principal> getPrincipals()
{
- return _subject;
+ return _principals;
}
-
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/SubjectAuthenticationResult.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/SubjectAuthenticationResult.java
new file mode 100644
index 0000000000..3be96b87eb
--- /dev/null
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/SubjectAuthenticationResult.java
@@ -0,0 +1,76 @@
+/*
+ *
+ * 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.auth;
+
+import java.security.Principal;
+
+import javax.security.auth.Subject;
+
+import org.apache.qpid.server.security.SubjectCreator;
+
+/**
+ * Encapsulates the result of an attempt to authenticate using a {@link SubjectCreator}.
+ *
+ * <p>
+ * iff authentication was successful, {@link #getSubject()} will return a non-null value and
+ * {@link #getStatus()} will return {@link AuthenticationResult.AuthenticationStatus#SUCCESS}.
+ *
+ * In this case, the {@link Subject} will contain the user {@link Principal} and zero or more other principals
+ * representing groups.
+ * </p>
+ * @see SubjectCreator
+ */
+public class SubjectAuthenticationResult
+{
+ private final AuthenticationResult _authenticationResult;
+ private final Subject _subject;
+
+ public SubjectAuthenticationResult(AuthenticationResult authenticationResult, Subject subject)
+ {
+ _authenticationResult = authenticationResult;
+ _subject = subject;
+ }
+
+ public SubjectAuthenticationResult(AuthenticationResult unsuccessfulAuthenticationResult)
+ {
+ this(unsuccessfulAuthenticationResult, null);
+ }
+
+ public Exception getCause()
+ {
+ return _authenticationResult.getCause();
+ }
+
+ public AuthenticationResult.AuthenticationStatus getStatus()
+ {
+ return _authenticationResult.getStatus();
+ }
+
+ public byte[] getChallenge()
+ {
+ return _authenticationResult.getChallenge();
+ }
+
+ public Subject getSubject()
+ {
+ return _subject;
+ }
+}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePrincipal.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/UsernamePrincipal.java
index 9e7db94216..cc414f801a 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePrincipal.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/UsernamePrincipal.java
@@ -7,9 +7,9 @@
* 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
@@ -18,11 +18,9 @@
* under the License.
*
*/
-package org.apache.qpid.server.security.auth.sasl;
+package org.apache.qpid.server.security.auth;
-import javax.security.auth.Subject;
import java.security.Principal;
-import java.util.Set;
/** A principal that is just a wrapper for a simple username. */
public class UsernamePrincipal implements Principal
@@ -48,9 +46,6 @@ public class UsernamePrincipal implements Principal
return _name;
}
- /**
- * @see java.lang.Object#hashCode()
- */
@Override
public int hashCode()
{
@@ -58,9 +53,6 @@ public class UsernamePrincipal implements Principal
return prime * _name.hashCode();
}
- /**
- * @see java.lang.Object#equals(java.lang.Object)
- */
@Override
public boolean equals(Object obj)
{
@@ -81,19 +73,4 @@ public class UsernamePrincipal implements Principal
}
}
}
-
- public static UsernamePrincipal getUsernamePrincipalFromSubject(final Subject authSubject)
- {
- if (authSubject == null)
- {
- throw new IllegalArgumentException("No authenticated subject.");
- }
-
- final Set<UsernamePrincipal> principals = authSubject.getPrincipals(UsernamePrincipal.class);
- if (principals.size() != 1)
- {
- throw new IllegalArgumentException("Can't find single UsernamePrincipal in authenticated subject");
- }
- return principals.iterator().next();
- }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/AbstractPasswordFilePrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/AbstractPasswordFilePrincipalDatabase.java
index cac60a5283..578bb96efa 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/AbstractPasswordFilePrincipalDatabase.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/AbstractPasswordFilePrincipalDatabase.java
@@ -21,9 +21,9 @@
package org.apache.qpid.server.security.auth.database;
import org.apache.log4j.Logger;
+import org.apache.qpid.server.security.auth.UsernamePrincipal;
import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser;
import org.apache.qpid.server.security.auth.sasl.UsernamePasswordInitialiser;
-import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.login.AccountNotFoundException;
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java
index 4203cb0e07..ecf08de72e 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java
@@ -21,7 +21,7 @@
package org.apache.qpid.server.security.auth.database;
import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser;
-import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal;
+import org.apache.qpid.server.security.auth.UsernamePrincipal;
import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5Initialiser;
import org.apache.qpid.server.security.auth.sasl.plain.PlainInitialiser;
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AnonymousAuthenticationManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AnonymousAuthenticationManager.java
index 5676c43754..9ac7a8b11a 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AnonymousAuthenticationManager.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AnonymousAuthenticationManager.java
@@ -24,7 +24,6 @@ import java.security.Principal;
import java.util.Arrays;
import java.util.List;
import javax.security.auth.Subject;
-import javax.security.auth.callback.CallbackHandler;
import javax.security.sasl.SaslException;
import javax.security.sasl.SaslServer;
import org.apache.commons.configuration.Configuration;
@@ -33,7 +32,7 @@ import org.apache.log4j.Logger;
import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin;
import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory;
import org.apache.qpid.server.security.auth.AuthenticationResult;
-import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal;
+import org.apache.qpid.server.security.auth.UsernamePrincipal;
import org.apache.qpid.server.security.auth.sasl.anonymous.AnonymousInitialiser;
import org.apache.qpid.server.security.auth.sasl.anonymous.AnonymousSaslServer;
@@ -45,7 +44,9 @@ public class AnonymousAuthenticationManager implements AuthenticationManager
private static final String ANONYMOUS = SASL_INITIALISER.getMechanismName();
- private static final Principal ANONYMOUS_PRINCIPAL = new UsernamePrincipal("ANONYMOUS");
+ public static final String ANONYMOUS_USERNAME = "ANONYMOUS";
+
+ public static final Principal ANONYMOUS_PRINCIPAL = new UsernamePrincipal(ANONYMOUS_USERNAME);
public static final Subject ANONYMOUS_SUBJECT = new Subject();
static
@@ -53,10 +54,7 @@ public class AnonymousAuthenticationManager implements AuthenticationManager
ANONYMOUS_SUBJECT.getPrincipals().add(ANONYMOUS_PRINCIPAL);
}
- private static final AuthenticationResult ANONYMOUS_AUTHENTICATION = new AuthenticationResult(ANONYMOUS_SUBJECT);
-
-
- private static CallbackHandler _callbackHandler = SASL_INITIALISER.getCallbackHandler();
+ private static final AuthenticationResult ANONYMOUS_AUTHENTICATION = new AuthenticationResult(ANONYMOUS_PRINCIPAL);
static final AnonymousAuthenticationManager INSTANCE = new AnonymousAuthenticationManager();
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java
index ccddcb7669..ba635cd023 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManager.java
@@ -30,14 +30,15 @@ import org.apache.qpid.server.security.auth.AuthenticationResult;
/**
* Implementations of the AuthenticationManager are responsible for determining
* the authenticity of a user's credentials.
- *
- * If the authentication is successful, the manager is responsible for producing a populated
- * {@link javax.security.auth.Subject} containing the user's identity and zero or more principals representing
- * groups to which the user belongs.
+ * <p>
+ * If the authentication is successful, the manager is responsible for producing an
+ * {@link AuthenticationResult} containing the user's main {@link Principal} and zero or
+ * more other implementation-specific principals.
+ * </p>
* <p>
* The {@link #initialise()} method is responsible for registering SASL mechanisms required by
* the manager. The {@link #close()} method must reverse this registration.
- *
+ * </p>
*/
public interface AuthenticationManager extends Closeable, Plugin
{
@@ -88,5 +89,4 @@ public interface AuthenticationManager extends Closeable, Plugin
* @return authentication result
*/
AuthenticationResult authenticate(String username, String password);
-
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManagerRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManagerRegistry.java
index 89a4d8ae66..323ee15dd9 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManagerRegistry.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/AuthenticationManagerRegistry.java
@@ -25,7 +25,6 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
-import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -35,6 +34,8 @@ import org.apache.qpid.server.configuration.ServerConfiguration;
import org.apache.qpid.server.plugins.Plugin;
import org.apache.qpid.server.plugins.PluginManager;
import org.apache.qpid.server.security.SecurityManager.SecurityConfiguration;
+import org.apache.qpid.server.security.SubjectCreator;
+import org.apache.qpid.server.security.group.GroupPrincipalAccessor;
/**
* A concrete implementation of {@link IAuthenticationManagerRegistry} that registers all {@link AuthenticationManager}
@@ -50,12 +51,12 @@ import org.apache.qpid.server.security.SecurityManager.SecurityConfiguration;
public class AuthenticationManagerRegistry implements Closeable, IAuthenticationManagerRegistry
{
private final Map<String,AuthenticationManager> _classToAuthManagerMap = new HashMap<String,AuthenticationManager>();
- private final AuthenticationManager _defaultAuthenticationManager;
- private final Map<Integer,AuthenticationManager> _portToAuthenticationManagerMap;
+ private final SubjectCreator _defaultSubjectCreator;
+ private final Map<Integer, SubjectCreator> _portToSubjectCreatorMap;
private final List<RegistryChangeListener> _listeners =
Collections.synchronizedList(new ArrayList<RegistryChangeListener>());
- public AuthenticationManagerRegistry(ServerConfiguration serverConfiguration, PluginManager _pluginManager)
+ public AuthenticationManagerRegistry(ServerConfiguration serverConfiguration, PluginManager _pluginManager, GroupPrincipalAccessor groupPrincipalAccessor)
throws ConfigurationException
{
final Collection<AuthenticationManagerPluginFactory<? extends Plugin>> factories = _pluginManager.getAuthenticationManagerPlugins().values();
@@ -78,9 +79,9 @@ public class AuthenticationManagerRegistry implements Closeable, IAuthentication
throw new ConfigurationException("No authentication managers configured within the configuration file.");
}
- _defaultAuthenticationManager = getDefaultAuthenticationManager(serverConfiguration);
+ _defaultSubjectCreator = createDefaultSubectCreator(serverConfiguration, groupPrincipalAccessor);
- _portToAuthenticationManagerMap = getPortToAuthenticationManagerMap(serverConfiguration);
+ _portToSubjectCreatorMap = createPortToSubjectCreatorMap(serverConfiguration, groupPrincipalAccessor);
willClose = false;
}
finally
@@ -95,14 +96,14 @@ public class AuthenticationManagerRegistry implements Closeable, IAuthentication
}
@Override
- public AuthenticationManager getAuthenticationManager(SocketAddress address)
+ public SubjectCreator getSubjectCreator(SocketAddress address)
{
- AuthenticationManager authManager =
+ SubjectCreator subjectCreator =
address instanceof InetSocketAddress
- ? _portToAuthenticationManagerMap.get(((InetSocketAddress)address).getPort())
+ ? _portToSubjectCreatorMap.get(((InetSocketAddress)address).getPort())
: null;
- return authManager == null ? _defaultAuthenticationManager : authManager;
+ return subjectCreator == null ? _defaultSubjectCreator : subjectCreator;
}
@Override
@@ -140,8 +141,8 @@ public class AuthenticationManagerRegistry implements Closeable, IAuthentication
}
}
- private AuthenticationManager getDefaultAuthenticationManager(
- ServerConfiguration serverConfiguration)
+ private SubjectCreator createDefaultSubectCreator(
+ ServerConfiguration serverConfiguration, GroupPrincipalAccessor groupAccessor)
throws ConfigurationException
{
final AuthenticationManager defaultAuthenticationManager;
@@ -164,14 +165,14 @@ public class AuthenticationManagerRegistry implements Closeable, IAuthentication
{
throw new ConfigurationException("If more than one authentication manager is configured a default MUST be specified.");
}
- return defaultAuthenticationManager;
+ return new SubjectCreator(defaultAuthenticationManager, groupAccessor);
}
- private Map<Integer,AuthenticationManager> getPortToAuthenticationManagerMap(
- ServerConfiguration serverConfiguration)
+ private Map<Integer, SubjectCreator> createPortToSubjectCreatorMap(
+ ServerConfiguration serverConfiguration, GroupPrincipalAccessor groupPrincipalAccessor)
throws ConfigurationException
{
- Map<Integer,AuthenticationManager> portToAuthenticationManagerMap = new HashMap<Integer, AuthenticationManager>();
+ Map<Integer,SubjectCreator> portToSubjectCreatorMap = new HashMap<Integer, SubjectCreator>();
for(Map.Entry<Integer,String> portMapping : serverConfiguration.getPortAuthenticationMappings().entrySet())
{
@@ -182,10 +183,12 @@ public class AuthenticationManagerRegistry implements Closeable, IAuthentication
throw new ConfigurationException("Unknown authentication manager class " + portMapping.getValue() +
" configured for port " + portMapping.getKey());
}
- portToAuthenticationManagerMap.put(portMapping.getKey(), authenticationManager);
+
+ SubjectCreator subjectCreator = new SubjectCreator(authenticationManager, groupPrincipalAccessor);
+ portToSubjectCreatorMap.put(portMapping.getKey(), subjectCreator);
}
- return portToAuthenticationManagerMap;
+ return portToSubjectCreatorMap;
}
@Override
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationManager.java
index 2d6866b657..a1328ca0de 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationManager.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationManager.java
@@ -21,7 +21,6 @@ package org.apache.qpid.server.security.auth.manager;
import java.security.Principal;
import java.util.Arrays;
import java.util.List;
-import javax.security.auth.Subject;
import javax.security.sasl.SaslException;
import javax.security.sasl.SaslServer;
import org.apache.commons.configuration.Configuration;
@@ -137,15 +136,13 @@ public class ExternalAuthenticationManager implements AuthenticationManager
// Process response from the client
try
{
- byte[] challenge = server.evaluateResponse(response != null ? response : new byte[0]);
+ server.evaluateResponse(response != null ? response : new byte[0]);
Principal principal = ((ExternalSaslServer)server).getAuthenticatedPrincipal();
if(principal != null)
{
- final Subject subject = new Subject();
- subject.getPrincipals().add(principal);
- return new AuthenticationResult(subject);
+ return new AuthenticationResult(principal);
}
else
{
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/IAuthenticationManagerRegistry.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/IAuthenticationManagerRegistry.java
index 485ca2e1e9..6ed8f95512 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/IAuthenticationManagerRegistry.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/IAuthenticationManagerRegistry.java
@@ -23,13 +23,11 @@ import java.net.SocketAddress;
import java.util.Map;
import org.apache.qpid.common.Closeable;
-import org.apache.qpid.server.virtualhost.VirtualHost;
+import org.apache.qpid.server.security.SubjectCreator;
/**
- * Registry for {@link AuthenticationManager} instances.
- *
- * <p>A lookup method {@link #getAuthenticationManager(SocketAddress)} allows a caller to determine
- * the AuthenticationManager associated with a particular port number.</p>
+ * Registry for {@link AuthenticationManager} instances, also exposing them wrapped in {@link SubjectCreator}'s
+ * as a convenience.
*
* <p>It is important to {@link #close()} the registry after use and this allows the AuthenticationManagers
* to reverse any security registrations they have performed.</p>
@@ -37,14 +35,11 @@ import org.apache.qpid.server.virtualhost.VirtualHost;
public interface IAuthenticationManagerRegistry extends Closeable
{
/**
- * Returns the {@link AuthenticationManager} associated with a particular {@link SocketAddress}.
- * If no authentication manager is associated with this address, a default authentication manager will be
+ * Returns the {@link SubjectCreator} associated with a particular {@link SocketAddress}.
+ * If no subject creator is associated with this address, a default will be
* returned. Null is never returned.
- *
- * @param address
- * @return authentication manager.
*/
- public AuthenticationManager getAuthenticationManager(SocketAddress address);
+ public SubjectCreator getSubjectCreator(SocketAddress address);
Map<String, AuthenticationManager> getAvailableAuthenticationManagers();
@@ -55,5 +50,4 @@ public interface IAuthenticationManagerRegistry extends Closeable
}
public void addRegistryChangeListener(RegistryChangeListener listener);
-
} \ No newline at end of file
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/KerberosAuthenticationManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/KerberosAuthenticationManager.java
index d735ecb1d4..ed15d244eb 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/KerberosAuthenticationManager.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/KerberosAuthenticationManager.java
@@ -23,7 +23,6 @@ import java.security.Principal;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
-import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
@@ -37,7 +36,7 @@ import org.apache.log4j.Logger;
import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin;
import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory;
import org.apache.qpid.server.security.auth.AuthenticationResult;
-import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal;
+import org.apache.qpid.server.security.auth.UsernamePrincipal;
public class KerberosAuthenticationManager implements AuthenticationManager
{
@@ -158,10 +157,7 @@ public class KerberosAuthenticationManager implements AuthenticationManager
if (server.isComplete())
{
- final Subject subject = new Subject();
- _logger.debug("Authenticated as " + server.getAuthorizationID());
- subject.getPrincipals().add(new UsernamePrincipal(server.getAuthorizationID()));
- return new AuthenticationResult(subject);
+ return new AuthenticationResult(new UsernamePrincipal(server.getAuthorizationID()));
}
else
{
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java
index e6498919a1..529f2bf6a8 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java
@@ -34,9 +34,8 @@ import org.apache.qpid.server.security.auth.AuthenticationResult.AuthenticationS
import org.apache.qpid.server.security.auth.database.PrincipalDatabase;
import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser;
import org.apache.qpid.server.security.auth.sasl.JCAProvider;
-import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal;
+import org.apache.qpid.server.security.auth.UsernamePrincipal;
-import javax.security.auth.Subject;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.login.AccountNotFoundException;
import javax.security.sasl.Sasl;
@@ -164,6 +163,7 @@ public class PrincipalDatabaseAuthenticationManager implements AuthenticationMan
return getConfig().getString("principal-database.class");
}
+ @SuppressWarnings({ "unchecked", "rawtypes" })
public Map<String,String> getPdClassAttributeMap() throws ConfigurationException
{
final List<String> argumentNames = (List) getConfig().getList("principal-database.attributes.attribute.name");
@@ -284,9 +284,8 @@ public class PrincipalDatabaseAuthenticationManager implements AuthenticationMan
if (server.isComplete())
{
- final Subject subject = new Subject();
- subject.getPrincipals().add(new UsernamePrincipal(server.getAuthorizationID()));
- return new AuthenticationResult(subject);
+ final String userId = server.getAuthorizationID();
+ return new AuthenticationResult(new UsernamePrincipal(userId));
}
else
{
@@ -308,9 +307,7 @@ public class PrincipalDatabaseAuthenticationManager implements AuthenticationMan
{
if (_principalDatabase.verifyPassword(username, password.toCharArray()))
{
- final Subject subject = new Subject();
- subject.getPrincipals().add(new UsernamePrincipal(username));
- return new AuthenticationResult(subject);
+ return new AuthenticationResult(new UsernamePrincipal(username));
}
else
{
@@ -353,6 +350,16 @@ public class PrincipalDatabaseAuthenticationManager implements AuthenticationMan
}
}
+ public PrincipalDatabase getPrincipalDatabase()
+ {
+ return _principalDatabase;
+ }
+
+ protected void setPrincipalDatabase(final PrincipalDatabase principalDatabase)
+ {
+ _principalDatabase = principalDatabase;
+ }
+
private void configPrincipalDatabase(final PrincipalDatabase principalDatabase, final PrincipalDatabaseAuthenticationManagerConfiguration config)
throws ConfigurationException
{
@@ -400,11 +407,6 @@ public class PrincipalDatabaseAuthenticationManager implements AuthenticationMan
}
}
- public PrincipalDatabase getPrincipalDatabase()
- {
- return _principalDatabase;
- }
-
private String generateSetterName(String argName) throws ConfigurationException
{
if ((argName == null) || (argName.length() == 0))
@@ -421,8 +423,4 @@ public class PrincipalDatabaseAuthenticationManager implements AuthenticationMan
return methodName;
}
- protected void setPrincipalDatabase(final PrincipalDatabase principalDatabase)
- {
- _principalDatabase = principalDatabase;
- }
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManager.java
index 64b24e28bc..8490a1c373 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManager.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManager.java
@@ -32,7 +32,6 @@ import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
-import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
@@ -47,7 +46,7 @@ import org.apache.log4j.Logger;
import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin;
import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory;
import org.apache.qpid.server.security.auth.AuthenticationResult;
-import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal;
+import org.apache.qpid.server.security.auth.UsernamePrincipal;
import org.apache.qpid.server.security.auth.sasl.plain.PlainPasswordCallback;
public class SimpleLDAPAuthenticationManager implements AuthenticationManager
@@ -205,10 +204,10 @@ public class SimpleLDAPAuthenticationManager implements AuthenticationManager
if (server.isComplete())
{
- final Subject subject = new Subject();
- _logger.debug("Authenticated as " + server.getAuthorizationID());
- subject.getPrincipals().add(new UsernamePrincipal(server.getAuthorizationID()));
- return new AuthenticationResult(subject);
+ String authorizationID = server.getAuthorizationID();
+ _logger.debug("Authenticated as " + authorizationID);
+
+ return new AuthenticationResult(new UsernamePrincipal(authorizationID));
}
else
{
@@ -249,9 +248,8 @@ public class SimpleLDAPAuthenticationManager implements AuthenticationManager
env.put(Context.SECURITY_CREDENTIALS, password);
DirContext ctx = new InitialDirContext(env);
ctx.close();
- final Subject subject = new Subject();
- subject.getPrincipals().add(new UsernamePrincipal(username));
- return new AuthenticationResult(subject);
+
+ return new AuthenticationResult(new UsernamePrincipal(username));
}
@Override
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticator.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticator.java
index 2e21cfbb07..808447b7ff 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticator.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticator.java
@@ -23,12 +23,11 @@ package org.apache.qpid.server.security.auth.rmi;
import java.net.SocketAddress;
import org.apache.qpid.server.registry.ApplicationRegistry;
-import org.apache.qpid.server.security.auth.AuthenticationResult;
+import org.apache.qpid.server.security.SubjectCreator;
import org.apache.qpid.server.security.auth.AuthenticationResult.AuthenticationStatus;
-import org.apache.qpid.server.security.auth.manager.AuthenticationManager;
+import org.apache.qpid.server.security.auth.SubjectAuthenticationResult;
import javax.management.remote.JMXAuthenticator;
-import javax.management.remote.JMXPrincipal;
import javax.security.auth.Subject;
public class RMIPasswordAuthenticator implements JMXAuthenticator
@@ -41,7 +40,7 @@ public class RMIPasswordAuthenticator implements JMXAuthenticator
static final String CREDENTIALS_REQUIRED = "User details are required. " +
"Please ensure you are using an up to date management console to connect.";
- private AuthenticationManager _authenticationManager = null;
+ private SubjectCreator _subjectCreator = null;
private SocketAddress _socketAddress;
public RMIPasswordAuthenticator(SocketAddress socketAddress)
@@ -49,9 +48,9 @@ public class RMIPasswordAuthenticator implements JMXAuthenticator
_socketAddress = socketAddress;
}
- public void setAuthenticationManager(final AuthenticationManager authenticationManager)
+ public void setSubjectCreator(final SubjectCreator subjectCreator)
{
- _authenticationManager = authenticationManager;
+ _subjectCreator = subjectCreator;
}
public Subject authenticate(Object credentials) throws SecurityException
@@ -85,14 +84,14 @@ public class RMIPasswordAuthenticator implements JMXAuthenticator
throw new SecurityException(SHOULD_BE_NON_NULL);
}
- // Verify that an AuthenticationManager has been set.
- if (_authenticationManager == null)
+ // Verify that an SubjectCreator has been set.
+ if (_subjectCreator == null)
{
try
{
- if(ApplicationRegistry.getInstance().getAuthenticationManager(_socketAddress) != null)
+ if(ApplicationRegistry.getInstance().getSubjectCreator(_socketAddress) != null)
{
- _authenticationManager = ApplicationRegistry.getInstance().getAuthenticationManager(_socketAddress);
+ _subjectCreator = ApplicationRegistry.getInstance().getSubjectCreator(_socketAddress);
}
else
{
@@ -104,7 +103,7 @@ public class RMIPasswordAuthenticator implements JMXAuthenticator
throw new SecurityException(UNABLE_TO_LOOKUP);
}
}
- final AuthenticationResult result = _authenticationManager.authenticate(username, password);
+ final SubjectAuthenticationResult result = _subjectCreator.authenticate(username, password);
if (AuthenticationStatus.ERROR.equals(result.getStatus()))
{
@@ -112,10 +111,7 @@ public class RMIPasswordAuthenticator implements JMXAuthenticator
}
else if (AuthenticationStatus.SUCCESS.equals(result.getStatus()))
{
- final Subject subject = result.getSubject();
- subject.getPrincipals().add(new JMXPrincipal(username));
- subject.setReadOnly();
- return subject;
+ return result.getSubject();
}
else
{
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePasswordInitialiser.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePasswordInitialiser.java
index f4e8f800c6..b70a987107 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePasswordInitialiser.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/UsernamePasswordInitialiser.java
@@ -23,6 +23,7 @@ package org.apache.qpid.server.security.auth.sasl;
import org.apache.commons.configuration.Configuration;
import org.apache.log4j.Logger;
+import org.apache.qpid.server.security.auth.UsernamePrincipal;
import org.apache.qpid.server.security.auth.database.PrincipalDatabase;
import javax.security.auth.callback.Callback;
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/anonymous/AnonymousSaslServer.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/anonymous/AnonymousSaslServer.java
index 52d36023c2..d10193e743 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/anonymous/AnonymousSaslServer.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/anonymous/AnonymousSaslServer.java
@@ -23,6 +23,8 @@ package org.apache.qpid.server.security.auth.sasl.anonymous;
import javax.security.sasl.SaslException;
import javax.security.sasl.SaslServer;
+import org.apache.qpid.server.security.auth.manager.AnonymousAuthenticationManager;
+
public class AnonymousSaslServer implements SaslServer
{
@@ -52,7 +54,7 @@ public class AnonymousSaslServer implements SaslServer
public String getAuthorizationID()
{
- return null;
+ return AnonymousAuthenticationManager.ANONYMOUS_PRINCIPAL.getName();
}
public byte[] unwrap(byte[] incoming, int offset, int len) throws SaslException
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/group/FileGroupDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/group/FileGroupDatabase.java
new file mode 100644
index 0000000000..2e4fc9e3a3
--- /dev/null
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/group/FileGroupDatabase.java
@@ -0,0 +1,265 @@
+/*
+ * 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.group;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentSkipListSet;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.log4j.Logger;
+
+/**
+ * A group database that reads/writes the following file format:
+ *
+ * group1.users=user1,user2
+ * group2.users=user2,user3
+ */
+public class FileGroupDatabase implements GroupDatabase
+{
+ private static final Logger LOGGER = Logger.getLogger(FileGroupDatabase.class);
+
+ private Map<String, Set<String>> _groupToUserMap = new ConcurrentHashMap<String, Set<String>>();
+ private Map<String, Set<String>> _userToGroupMap = new ConcurrentHashMap<String, Set<String>>();
+ private String _groupFile;
+
+ @Override
+ public Set<String> getAllGroups()
+ {
+ return Collections.unmodifiableSet(_groupToUserMap.keySet());
+ }
+
+ public synchronized void setGroupFile(String groupFile) throws IOException
+ {
+ File file = new File(groupFile);
+
+ if (!file.canRead())
+ {
+ throw new FileNotFoundException(groupFile
+ + " cannot be found or is not readable");
+ }
+
+ readGroupFile(groupFile);
+ }
+
+ @Override
+ public Set<String> getUsersInGroup(String group)
+ {
+ if (group == null)
+ {
+ LOGGER.warn("Requested user set for null group. Returning empty set.");
+ return Collections.emptySet();
+ }
+
+ Set<String> set = _groupToUserMap.get(group);
+ if (set == null)
+ {
+ return Collections.emptySet();
+ }
+ else
+ {
+ return Collections.unmodifiableSet(set);
+ }
+ }
+
+ @Override
+ public synchronized void addUserToGroup(String user, String group)
+ {
+ Set<String> users = _groupToUserMap.get(group);
+ if (users == null)
+ {
+ throw new IllegalArgumentException("Group " + group + " does not exist so could not add " + user + " to it");
+ }
+
+ users.add(user);
+
+ Set<String> groups = _userToGroupMap.get(user);
+ if (groups == null)
+ {
+ groups = new ConcurrentSkipListSet<String>();
+ _userToGroupMap.put(user, groups);
+ }
+ groups.add(group);
+
+ update();
+ }
+
+ @Override
+ public synchronized void removeUserFromGroup(String user, String group)
+ {
+ Set<String> users = _groupToUserMap.get(group);
+ if (users == null)
+ {
+ throw new IllegalArgumentException("Group " + group + " does not exist so could not remove " + user + " from it");
+ }
+
+ users.remove(user);
+
+ Set<String> groups = _userToGroupMap.get(user);
+ if (groups != null)
+ {
+ groups.remove(group);
+ }
+
+ update();
+ }
+
+ @Override
+ public Set<String> getGroupsForUser(String user)
+ {
+ if(user == null)
+ {
+ LOGGER.warn("Requested group set for null user. Returning empty set.");
+ return Collections.emptySet();
+ }
+
+ Set<String> groups = _userToGroupMap.get(user);
+ if (groups == null)
+ {
+ return Collections.emptySet();
+ }
+ else
+ {
+ return Collections.unmodifiableSet(groups);
+ }
+ }
+
+ @Override
+ public synchronized void createGroup(String group)
+ {
+ Set<String> users = new ConcurrentSkipListSet<String>();
+ _groupToUserMap.put(group, users);
+
+ update();
+ }
+
+ @Override
+ public synchronized void removeGroup(String group)
+ {
+ _groupToUserMap.remove(group);
+ for (Set<String> groupsForUser : _userToGroupMap.values())
+ {
+ groupsForUser.remove(group);
+ }
+
+ update();
+ }
+
+ private synchronized void update()
+ {
+ if (_groupFile != null)
+ {
+ try
+ {
+ writeGroupFile(_groupFile);
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("Unable to persist change to file " + _groupFile);
+ }
+ }
+ }
+
+ private synchronized void readGroupFile(String groupFile) throws IOException
+ {
+ _groupFile = groupFile;
+ _groupToUserMap.clear();
+ _userToGroupMap.clear();
+ Properties propertiesFile = new Properties();
+ propertiesFile.load(new FileInputStream(groupFile));
+
+ for (String propertyName : propertiesFile.stringPropertyNames())
+ {
+ validatePropertyNameIsGroupName(propertyName);
+
+ String groupName = propertyName.replaceAll("\\.users$", "");
+ String userString = propertiesFile.getProperty(propertyName);
+
+ final Set<String> userSet = buildUserSetFromCommaSeparateValue(userString);
+
+ _groupToUserMap.put(groupName, userSet);
+
+ for (String userName : userSet)
+ {
+ Set<String> groupsForThisUser = _userToGroupMap.get(userName);
+
+ if (groupsForThisUser == null)
+ {
+ groupsForThisUser = new ConcurrentSkipListSet<String>();
+ _userToGroupMap.put(userName, groupsForThisUser);
+ }
+
+ groupsForThisUser.add(groupName);
+ }
+ }
+ }
+
+ private synchronized void writeGroupFile(String groupFile) throws IOException
+ {
+ Properties propertiesFile = new Properties();
+
+ for (String group : _groupToUserMap.keySet())
+ {
+ Set<String> users = _groupToUserMap.get(group);
+ String userList = StringUtils.join(users, ",");
+
+ propertiesFile.setProperty(group + ".users", userList);
+ }
+
+ String comment = "Written " + new Date();
+ propertiesFile.store(new FileOutputStream(groupFile), comment);
+ }
+
+ private void validatePropertyNameIsGroupName(String propertyName)
+ {
+ if (!propertyName.endsWith(".users"))
+ {
+ throw new IllegalArgumentException(
+ "Invalid definition with name '"
+ + propertyName
+ + "'. Group definitions must end with suffix '.users'");
+ }
+ }
+
+ private ConcurrentSkipListSet<String> buildUserSetFromCommaSeparateValue(String userString)
+ {
+ String[] users = userString.split(",");
+ final ConcurrentSkipListSet<String> userSet = new ConcurrentSkipListSet<String>();
+ for (String user : users)
+ {
+ final String trimmed = user.trim();
+ if (!trimmed.isEmpty())
+ {
+ userSet.add(trimmed);
+ }
+ }
+ return userSet;
+ }
+
+}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/group/FileGroupManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/group/FileGroupManager.java
new file mode 100644
index 0000000000..1b393c3ecf
--- /dev/null
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/group/FileGroupManager.java
@@ -0,0 +1,251 @@
+/*
+ * 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.group;
+
+import java.io.IOException;
+import java.security.Principal;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.configuration.Configuration;
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.log4j.Logger;
+import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin;
+import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory;
+import org.apache.qpid.server.security.auth.UsernamePrincipal;
+
+/**
+ * Implementation of a group manager whose implementation is backed by a flat group file.
+ * <p>
+ * This plugin is configured in the following manner:
+ * </p>
+ * <pre>
+ * &lt;file-group-manager&gt;
+ * &lt;attributes&gt;
+ * &lt;attribute&gt;
+ * &lt;name>groupFile&lt;/name&gt;
+ * &lt;value>${conf}/groups&lt;/value&gt;
+ * &lt;/attribute&gt;
+ * &lt;/attributes&gt;
+ * &lt;/file-group-manager&gt;
+ * </pre>
+ */
+public class FileGroupManager implements GroupManager
+{
+ private static final Logger LOGGER = Logger.getLogger(FileGroupManager.class);
+
+ public static final GroupManagerPluginFactory<FileGroupManager> FACTORY = new GroupManagerPluginFactory<FileGroupManager>()
+ {
+ public FileGroupManager newInstance(final ConfigurationPlugin config) throws ConfigurationException
+ {
+ final FileGroupManagerConfiguration configuration =
+ config == null
+ ? null
+ : (FileGroupManagerConfiguration) config.getConfiguration(FileGroupManagerConfiguration.class.getName());
+
+ // If there is no configuration for this plugin then don't load it.
+ if (configuration == null)
+ {
+ LOGGER.info("No file-group-manager configuration found for FileGroupManager");
+ return null;
+ }
+
+ final FileGroupManager fgm = new FileGroupManager();
+ fgm.configure(configuration);
+ return fgm;
+ }
+
+ public Class<FileGroupManager> getPluginClass()
+ {
+ return FileGroupManager.class;
+ }
+
+ public String getPluginName()
+ {
+ return FileGroupManager.class.getName();
+ }
+ };
+
+ private FileGroupDatabase _groupDatabase;
+
+ public static class FileGroupManagerConfiguration extends ConfigurationPlugin {
+
+ public static final ConfigurationPluginFactory FACTORY = new ConfigurationPluginFactory()
+ {
+ public List<String> getParentPaths()
+ {
+ return Arrays.asList("security.file-group-manager");
+ }
+
+ public ConfigurationPlugin newInstance(final String path, final Configuration config) throws ConfigurationException
+ {
+ final ConfigurationPlugin instance = new FileGroupManagerConfiguration();
+
+ instance.setConfiguration(path, config);
+ return instance;
+ }
+ };
+
+ public String[] getElementsProcessed()
+ {
+ return new String[] {"attributes.attribute.name",
+ "attributes.attribute.value"};
+ }
+
+ public void validateConfiguration() throws ConfigurationException
+ {
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ public Map<String,String> getAttributeMap() throws ConfigurationException
+ {
+ final List<String> argumentNames = (List) getConfig().getList("attributes.attribute.name");
+ final List<String> argumentValues = (List) getConfig().getList("attributes.attribute.value");
+ final Map<String,String> attributes = new HashMap<String,String>(argumentNames.size());
+
+ for (int i = 0; i < argumentNames.size(); i++)
+ {
+ final String argName = argumentNames.get(i);
+ final String argValue = argumentValues.get(i);
+
+ attributes.put(argName, argValue);
+ }
+
+ return Collections.unmodifiableMap(attributes);
+ }
+ }
+
+ @Override
+ public void configure(ConfigurationPlugin config)
+ throws ConfigurationException
+ {
+ if (LOGGER.isDebugEnabled())
+ {
+ LOGGER.debug("configuring file group plugin");
+ }
+
+ FileGroupManagerConfiguration fileGroupMangerConfig = (FileGroupManagerConfiguration) config;
+ Map<String,String> attribMap = fileGroupMangerConfig.getAttributeMap();
+ String groupFile = attribMap.get("groupFile");
+
+ if (LOGGER.isDebugEnabled())
+ {
+ LOGGER.debug("Group file : " + groupFile);
+ }
+
+ _groupDatabase = new FileGroupDatabase();
+ try
+ {
+ _groupDatabase.setGroupFile(groupFile);
+ }
+ catch (IOException e)
+ {
+ throw new ConfigurationException("Unable to set group file " + groupFile, e);
+ }
+ }
+
+ @Override
+ public Set<Principal> getGroupPrincipalsForUser(String userId)
+ {
+ Set<String> groups = _groupDatabase.getGroupsForUser(userId);
+ if (groups.isEmpty())
+ {
+ return Collections.emptySet();
+ }
+ else
+ {
+ Set<Principal> principals = new HashSet<Principal>();
+ for (String groupName : groups)
+ {
+ principals.add(new GroupPrincipal(groupName));
+ }
+ return principals;
+ }
+ }
+
+ @Override
+ public Set<Principal> getUserPrincipalsForGroup(String group)
+ {
+ Set<String> users = _groupDatabase.getUsersInGroup(group);
+ if (users.isEmpty())
+ {
+ return Collections.emptySet();
+ }
+ else
+ {
+ Set<Principal> principals = new HashSet<Principal>();
+ for (String user : users)
+ {
+ principals.add(new UsernamePrincipal(user));
+ }
+ return principals;
+ }
+ }
+
+ @Override
+ public Set<Principal> getGroupPrincipals()
+ {
+ Set<String> groups = _groupDatabase.getAllGroups();
+ if (groups.isEmpty())
+ {
+ return Collections.emptySet();
+ }
+ else
+ {
+ Set<Principal> principals = new HashSet<Principal>();
+ for (String groupName : groups)
+ {
+ principals.add(new GroupPrincipal(groupName));
+ }
+ return principals;
+ }
+ }
+
+ @Override
+ public void createGroup(String group)
+ {
+ _groupDatabase.createGroup(group);
+ }
+
+ @Override
+ public void removeGroup(String group)
+ {
+ _groupDatabase.removeGroup(group);
+ }
+
+ @Override
+ public void addUserToGroup(String user, String group)
+ {
+ _groupDatabase.addUserToGroup(user, group);
+ }
+
+ @Override
+ public void removeUserFromGroup(String user, String group)
+ {
+ _groupDatabase.removeUserFromGroup(user, group);
+
+ }
+
+}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/group/GroupDatabase.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/group/GroupDatabase.java
new file mode 100644
index 0000000000..98c12782d8
--- /dev/null
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/group/GroupDatabase.java
@@ -0,0 +1,34 @@
+/*
+ * 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.group;
+
+import java.util.Set;
+
+public interface GroupDatabase
+{
+ Set<String> getAllGroups();
+ Set<String> getUsersInGroup(String group);
+
+ void addUserToGroup(String user, String group);
+ void removeUserFromGroup(String user, String group);
+ Set<String> getGroupsForUser(String user);
+ void createGroup(String group);
+ void removeGroup(String group);
+}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/group/GroupManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/group/GroupManager.java
new file mode 100644
index 0000000000..30510eaad5
--- /dev/null
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/group/GroupManager.java
@@ -0,0 +1,42 @@
+/*
+ * 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.group;
+
+import java.security.Principal;
+import java.util.Set;
+
+import org.apache.qpid.server.plugins.Plugin;
+
+public interface GroupManager extends Plugin
+{
+ Set<Principal> getGroupPrincipalsForUser(String user);
+
+ Set<Principal> getGroupPrincipals();
+
+ Set<Principal> getUserPrincipalsForGroup(String group);
+
+ void createGroup(String group);
+
+ void removeGroup(String group);
+
+ void addUserToGroup(String user, String group);
+
+ void removeUserFromGroup(String user, String group);
+}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/group/GroupManagerPluginFactory.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/group/GroupManagerPluginFactory.java
new file mode 100644
index 0000000000..dc5ab33668
--- /dev/null
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/group/GroupManagerPluginFactory.java
@@ -0,0 +1,27 @@
+/*
+ * 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.group;
+
+import org.apache.qpid.server.plugins.PluginFactory;
+
+public interface GroupManagerPluginFactory<S extends GroupManager> extends PluginFactory<S>
+{
+
+}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/GroupPrincipal.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/group/GroupPrincipal.java
index 30a503c769..ccb446b719 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/auth/sasl/GroupPrincipal.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/group/GroupPrincipal.java
@@ -7,9 +7,9 @@
* 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
@@ -18,7 +18,7 @@
* under the License.
*
*/
-package org.apache.qpid.server.security.auth.sasl;
+package org.apache.qpid.server.security.group;
import java.security.Principal;
import java.security.acl.Group;
@@ -34,7 +34,7 @@ public class GroupPrincipal implements Group
{
/** Name of the group */
private final String _groupName;
-
+
public GroupPrincipal(final String groupName)
{
_groupName = groupName;
@@ -83,7 +83,7 @@ public class GroupPrincipal implements Group
{
return true;
}
- else
+ else
{
if (obj instanceof GroupPrincipal)
{
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/security/group/GroupPrincipalAccessor.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/group/GroupPrincipalAccessor.java
new file mode 100644
index 0000000000..9ab8ee586c
--- /dev/null
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/security/group/GroupPrincipalAccessor.java
@@ -0,0 +1,51 @@
+/*
+ * 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.group;
+
+import java.security.Principal;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+
+public class GroupPrincipalAccessor
+{
+ private final List<GroupManager> _groupManagerList;
+
+ public GroupPrincipalAccessor(List<GroupManager> groupManagerList)
+ {
+ _groupManagerList = groupManagerList;
+ }
+
+ public Set<Principal> getGroupPrincipals(String username)
+ {
+ Set<Principal> principals = new HashSet<Principal>();
+ for (GroupManager groupManager : _groupManagerList)
+ {
+ Set<Principal> groups = groupManager.getGroupPrincipalsForUser(username);
+ if (groups != null)
+ {
+ principals.addAll(groups);
+ }
+ }
+
+ return Collections.unmodifiableSet(principals);
+ }
+}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java
index f352bbdd2c..f8b8d14abf 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/state/AMQStateManager.java
@@ -34,6 +34,7 @@ import org.apache.qpid.protocol.AMQMethodListener;
import org.apache.qpid.server.protocol.AMQProtocolSession;
import org.apache.qpid.server.registry.IApplicationRegistry;
import org.apache.qpid.server.security.SecurityManager;
+import org.apache.qpid.server.security.SubjectCreator;
import org.apache.qpid.server.security.auth.manager.AuthenticationManager;
import org.apache.qpid.server.virtualhost.VirtualHostRegistry;
@@ -157,13 +158,9 @@ public class AMQStateManager implements AMQMethodListener
return _protocolSession;
}
- /**
- * Get the AuthenticationManager associated with the ProtocolSession of the AMQStateManager
- *
- * @return the AuthenticationManager
- */
- public AuthenticationManager getAuthenticationManager()
+
+ public SubjectCreator getSubjectCreator()
{
- return getApplicationRegistry().getAuthenticationManager(getProtocolSession().getLocalAddress());
+ return getApplicationRegistry().getSubjectCreator(getProtocolSession().getLocalAddress());
}
}
diff --git a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java
index c13f63b44d..615fce2909 100644
--- a/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java
+++ b/qpid/java/broker/src/main/java/org/apache/qpid/server/transport/ServerConnectionDelegate.java
@@ -37,9 +37,9 @@ import org.apache.qpid.server.configuration.BrokerConfig;
import org.apache.qpid.server.protocol.AMQConnectionModel;
import org.apache.qpid.server.registry.IApplicationRegistry;
import org.apache.qpid.server.security.SecurityManager;
-import org.apache.qpid.server.security.auth.AuthenticationResult;
+import org.apache.qpid.server.security.SubjectCreator;
import org.apache.qpid.server.security.auth.AuthenticationResult.AuthenticationStatus;
-import org.apache.qpid.server.security.auth.manager.AuthenticationManager;
+import org.apache.qpid.server.security.auth.SubjectAuthenticationResult;
import org.apache.qpid.server.subscription.Subscription_0_10;
import org.apache.qpid.server.virtualhost.State;
import org.apache.qpid.server.virtualhost.VirtualHost;
@@ -57,25 +57,25 @@ public class ServerConnectionDelegate extends ServerDelegate
private final IApplicationRegistry _appRegistry;
private int _maxNoOfChannels;
private Map<String,Object> _clientProperties;
- private final AuthenticationManager _authManager;
+ private final SubjectCreator _subjectCreator;
- public ServerConnectionDelegate(IApplicationRegistry appRegistry, String localFQDN, AuthenticationManager authManager)
+ public ServerConnectionDelegate(IApplicationRegistry appRegistry, String localFQDN, SubjectCreator subjectCreator)
{
- this(createConnectionProperties(appRegistry.getBrokerConfig()), Collections.singletonList((Object)"en_US"), appRegistry, localFQDN, authManager);
+ this(createConnectionProperties(appRegistry.getBrokerConfig()), Collections.singletonList((Object)"en_US"), appRegistry, localFQDN, subjectCreator);
}
private ServerConnectionDelegate(Map<String, Object> properties,
List<Object> locales,
IApplicationRegistry appRegistry,
String localFQDN,
- AuthenticationManager authManager)
+ SubjectCreator subjectCreator)
{
- super(properties, parseToList(authManager.getMechanisms()), locales);
+ super(properties, parseToList(subjectCreator.getMechanisms()), locales);
_appRegistry = appRegistry;
_localFQDN = localFQDN;
_maxNoOfChannels = appRegistry.getConfiguration().getMaxChannelCount();
- _authManager = authManager;
+ _subjectCreator = subjectCreator;
}
private static Map<String, Object> createConnectionProperties(final BrokerConfig brokerConfig)
@@ -112,14 +112,14 @@ public class ServerConnectionDelegate extends ServerDelegate
protected SaslServer createSaslServer(Connection conn, String mechanism) throws SaslException
{
- return _authManager.createSaslServer(mechanism, _localFQDN, ((ServerConnection) conn).getPeerPrincipal());
+ return _subjectCreator.createSaslServer(mechanism, _localFQDN, ((ServerConnection) conn).getPeerPrincipal());
}
protected void secure(final SaslServer ss, final Connection conn, final byte[] response)
{
final ServerConnection sconn = (ServerConnection) conn;
- final AuthenticationResult authResult = _authManager.authenticate(ss, response);
+ final SubjectAuthenticationResult authResult = _subjectCreator.authenticate(ss, response);
if (AuthenticationStatus.SUCCESS.equals(authResult.getStatus()))
{
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/logging/actors/AbstractManagementActorTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/logging/actors/AbstractManagementActorTest.java
new file mode 100644
index 0000000000..bf38bb64bf
--- /dev/null
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/logging/actors/AbstractManagementActorTest.java
@@ -0,0 +1,86 @@
+/*
+ *
+ * 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.logging.actors;
+
+import java.security.Principal;
+import java.security.PrivilegedAction;
+import java.util.Collections;
+
+import javax.security.auth.Subject;
+
+import org.apache.qpid.server.logging.NullRootMessageLogger;
+import org.apache.qpid.server.security.auth.TestPrincipalUtils;
+import org.apache.qpid.test.utils.QpidTestCase;
+
+public class AbstractManagementActorTest extends QpidTestCase
+{
+ private AbstractManagementActor _logActor;
+
+ @Override
+ public void setUp()
+ {
+ _logActor = new AbstractManagementActor(new NullRootMessageLogger(), AbstractManagementActor.UNKNOWN_PRINCIPAL)
+ {
+ @Override
+ public String getLogMessage()
+ {
+ return null;
+ }
+ };
+ }
+
+ public void testGetPrincipalName()
+ {
+ Subject subject = TestPrincipalUtils.createTestSubject("guest");
+
+ final String principalName = Subject.doAs(subject,
+ new PrivilegedAction<String>()
+ {
+ public String run()
+ {
+ return _logActor.getPrincipalName();
+ }
+ });
+
+ assertEquals("guest", principalName);
+ }
+
+ public void testGetPrincipalNameUsingSubjectWithoutAuthenticatedPrincipal()
+ {
+ Subject subject = new Subject(true, Collections.<Principal>emptySet(), Collections.emptySet(), Collections.emptySet());
+
+ final String principalName = Subject.doAs(subject,
+ new PrivilegedAction<String>()
+ {
+ public String run()
+ {
+ return _logActor.getPrincipalName();
+ }
+ });
+
+ assertEquals(AbstractManagementActor.UNKNOWN_PRINCIPAL, principalName);
+ }
+
+ public void testGetPrincipalWithoutSubject()
+ {
+ assertEquals(AbstractManagementActor.UNKNOWN_PRINCIPAL, _logActor.getPrincipalName());
+ }
+}
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/logging/actors/HttpManagementActorTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/logging/actors/HttpManagementActorTest.java
new file mode 100644
index 0000000000..b40405e1f4
--- /dev/null
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/logging/actors/HttpManagementActorTest.java
@@ -0,0 +1,94 @@
+/*
+ *
+ * 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.logging.actors;
+
+import javax.security.auth.Subject;
+
+import org.apache.qpid.server.security.auth.TestPrincipalUtils;
+
+import java.security.PrivilegedAction;
+import java.util.List;
+
+public class HttpManagementActorTest extends BaseActorTestCase
+{
+ private static final String IP = "127.0.0.1";
+ private static final int PORT = 1;
+ private static final String SUFFIX = "(" + IP + ":" + PORT + ")] ";
+
+ @Override
+ public void createBroker() throws Exception
+ {
+ super.createBroker();
+ _amqpActor = new HttpManagementActor(_rootLogger, IP, PORT);
+ }
+
+ public void testSubjectPrincipalNameAppearance()
+ {
+ Subject subject = TestPrincipalUtils.createTestSubject("guest");
+
+ final String message = Subject.doAs(subject, new PrivilegedAction<String>()
+ {
+ public String run()
+ {
+ return sendTestLogMessage(_amqpActor);
+ }
+ });
+
+ assertNotNull("Test log message is not created!", message);
+
+ List<Object> logs = _rawLogger.getLogMessages();
+ assertEquals("Message log size not as expected.", 1, logs.size());
+
+ String logMessage = logs.get(0).toString();
+ assertTrue("Message was not found in log message", logMessage.contains(message));
+ assertTrue("Message does not contain expected value: " + logMessage, logMessage.contains("[mng:guest" + SUFFIX));
+ }
+
+ /** It's necessary to test successive calls because HttpManagementActor caches
+ * its log message based on principal name */
+ public void testGetLogMessageCaching()
+ {
+ assertLogMessageWithoutPrincipal();
+ assertLogMessageWithPrincipal("my_principal");
+ assertLogMessageWithPrincipal("my_principal2");
+ assertLogMessageWithoutPrincipal();
+ }
+
+ private void assertLogMessageWithoutPrincipal()
+ {
+ String message = _amqpActor.getLogMessage();
+ assertEquals("Unexpected log message", "[mng:" + AbstractManagementActor.UNKNOWN_PRINCIPAL + SUFFIX, message);
+ }
+
+ private void assertLogMessageWithPrincipal(String principalName)
+ {
+ Subject subject = TestPrincipalUtils.createTestSubject(principalName);
+ final String message = Subject.doAs(subject, new PrivilegedAction<String>()
+ {
+ public String run()
+ {
+ return _amqpActor.getLogMessage();
+ }
+ });
+
+ assertEquals("Unexpected log message", "[mng:" + principalName + SUFFIX, message);
+ }
+}
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/logging/actors/ManagementActorTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/logging/actors/ManagementActorTest.java
index cb866245f0..20cc321aab 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/logging/actors/ManagementActorTest.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/logging/actors/ManagementActorTest.java
@@ -20,10 +20,11 @@
*/
package org.apache.qpid.server.logging.actors;
-import javax.management.remote.JMXPrincipal;
import javax.security.auth.Subject;
+
+import org.apache.qpid.server.security.auth.TestPrincipalUtils;
+
import java.security.PrivilegedAction;
-import java.util.Collections;
import java.util.List;
public class ManagementActorTest extends BaseActorTestCase
@@ -94,8 +95,7 @@ public class ManagementActorTest extends BaseActorTestCase
*/
public void testSubjectPrincipalNameAppearance()
{
- Subject subject = new Subject(true, Collections.singleton(new JMXPrincipal("guest")), Collections.EMPTY_SET,
- Collections.EMPTY_SET);
+ Subject subject = TestPrincipalUtils.createTestSubject("guest");
final String message = Subject.doAs(subject, new PrivilegedAction<String>()
{
@@ -172,9 +172,7 @@ public class ManagementActorTest extends BaseActorTestCase
private void assertLogMessageInRMIThreadWithPrincipal(String threadName, String principalName)
{
Thread.currentThread().setName(threadName);
- Subject subject = new Subject(true, Collections.singleton(new JMXPrincipal(principalName)), Collections.EMPTY_SET,
- Collections.EMPTY_SET);
-
+ Subject subject = TestPrincipalUtils.createTestSubject(principalName);
final String message = Subject.doAs(subject, new PrivilegedAction<String>()
{
public String run()
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/model/UUIDGeneratorTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/model/UUIDGeneratorTest.java
index 643132d371..c686a24e99 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/model/UUIDGeneratorTest.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/model/UUIDGeneratorTest.java
@@ -70,8 +70,12 @@ public class UUIDGeneratorTest extends QpidTestCase
idSet.add(id6);
UUID id7 = UUIDGenerator.generateVhostAliasUUID(value, value);
idSet.add(id7);
+ UUID id8 = UUIDGenerator.generateGroupUUID(value, value);
+ idSet.add(id8);
+ UUID id9 = UUIDGenerator.generateGroupMemberUUID(value, value, value);
+ idSet.add(id9);
- assertEquals("The produced UUIDs were not all unique", 7, idSet.size());
+ assertEquals("The produced UUIDs were not all unique", 9, idSet.size());
}
public void testQueueIdGeneration() throws Exception
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/protocol/InternalTestProtocolSession.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/protocol/InternalTestProtocolSession.java
index 96c67941f9..0016e31236 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/protocol/InternalTestProtocolSession.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/protocol/InternalTestProtocolSession.java
@@ -31,7 +31,8 @@ import org.apache.qpid.server.message.MessageContentSource;
import org.apache.qpid.server.output.ProtocolOutputConverter;
import org.apache.qpid.server.queue.QueueEntry;
import org.apache.qpid.server.registry.ApplicationRegistry;
-import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal;
+import org.apache.qpid.server.security.auth.AuthenticatedPrincipal;
+import org.apache.qpid.server.security.auth.UsernamePrincipal;
import org.apache.qpid.server.subscription.ClientDeliveryMethod;
import org.apache.qpid.server.subscription.Subscription;
import org.apache.qpid.server.subscription.SubscriptionImpl;
@@ -39,6 +40,8 @@ import org.apache.qpid.server.virtualhost.VirtualHost;
import org.apache.qpid.transport.TestNetworkConnection;
import javax.security.auth.Subject;
+
+import java.security.Principal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@@ -61,13 +64,22 @@ public class InternalTestProtocolSession extends AMQProtocolEngine implements Pr
_channelDelivers = new HashMap<Integer, Map<AMQShortString, LinkedList<DeliveryPair>>>();
- // Need to authenticate session for it to be representative testing.
- setAuthorizedSubject(new Subject(true, Collections.singleton(new UsernamePrincipal("InternalTestProtocolSession")),
- Collections.EMPTY_SET, Collections.EMPTY_SET));
-
+ setTestAuthorizedSubject();
setVirtualHost(virtualHost);
}
+ private void setTestAuthorizedSubject()
+ {
+ Principal principal = new AuthenticatedPrincipal(new UsernamePrincipal("InternalTestProtocolSession"));
+ Subject authorizedSubject = new Subject(
+ true,
+ Collections.singleton(principal),
+ Collections.emptySet(),
+ Collections.emptySet());
+
+ setAuthorizedSubject(authorizedSubject);
+ }
+
public ProtocolOutputConverter getProtocolOutputConverter()
{
return this;
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/SubjectCreatorTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/SubjectCreatorTest.java
new file mode 100644
index 0000000000..b1bc9bea68
--- /dev/null
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/SubjectCreatorTest.java
@@ -0,0 +1,138 @@
+/*
+ * 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;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.security.Principal;
+import java.util.Arrays;
+import java.util.HashSet;
+
+import javax.security.auth.Subject;
+import javax.security.sasl.SaslServer;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.server.security.auth.AuthenticatedPrincipal;
+import org.apache.qpid.server.security.auth.AuthenticationResult;
+import org.apache.qpid.server.security.auth.AuthenticationResult.AuthenticationStatus;
+import org.apache.qpid.server.security.auth.SubjectAuthenticationResult;
+import org.apache.qpid.server.security.auth.manager.AuthenticationManager;
+import org.apache.qpid.server.security.group.GroupPrincipalAccessor;
+
+public class SubjectCreatorTest extends TestCase
+{
+ private static final String USERNAME = "username";
+ private static final String PASSWORD = "password";
+
+ private AuthenticationManager _authenticationManager = mock(AuthenticationManager.class);
+ private GroupPrincipalAccessor _groupPrincipalAccessor = mock(GroupPrincipalAccessor.class);
+ private SubjectCreator _subjectCreator = new SubjectCreator(_authenticationManager, _groupPrincipalAccessor);
+
+ private Principal _userPrincipal = mock(Principal.class);
+ private Principal _group1 = mock(Principal.class);
+ private Principal _group2 = mock(Principal.class);
+
+ private AuthenticationResult _authenticationResult;
+ private SaslServer _testSaslServer = mock(SaslServer.class);
+ private byte[] _saslResponseBytes = PASSWORD.getBytes();
+
+ @Override
+ public void setUp()
+ {
+ _authenticationResult = new AuthenticationResult(_userPrincipal);
+ when(_authenticationManager.authenticate(USERNAME, PASSWORD)).thenReturn(_authenticationResult);
+
+ when(_groupPrincipalAccessor.getGroupPrincipals(USERNAME))
+ .thenReturn(new HashSet<Principal>(Arrays.asList(_group1, _group2)));
+ }
+
+ public void testAuthenticateUsernameAndPasswordReturnsSubjectWithUserAndGroupPrincipals()
+ {
+ final SubjectAuthenticationResult actualResult = _subjectCreator.authenticate(USERNAME, PASSWORD);
+
+ assertEquals(AuthenticationStatus.SUCCESS, actualResult.getStatus());
+
+ final Subject actualSubject = actualResult.getSubject();
+
+ assertEquals("Should contain one user principal and two groups ", 3, actualSubject.getPrincipals().size());
+
+ assertTrue(actualSubject.getPrincipals().contains(new AuthenticatedPrincipal(_userPrincipal)));
+ assertTrue(actualSubject.getPrincipals().contains(_group1));
+ assertTrue(actualSubject.getPrincipals().contains(_group2));
+
+ assertTrue(actualSubject.isReadOnly());
+ }
+
+ public void testSaslAuthenticationSuccessReturnsSubjectWithUserAndGroupPrincipals() throws Exception
+ {
+ when(_authenticationManager.authenticate(_testSaslServer, _saslResponseBytes)).thenReturn(_authenticationResult);
+ when(_testSaslServer.isComplete()).thenReturn(true);
+ when(_testSaslServer.getAuthorizationID()).thenReturn(USERNAME);
+
+ SubjectAuthenticationResult result = _subjectCreator.authenticate(_testSaslServer, _saslResponseBytes);
+
+ final Subject actualSubject = result.getSubject();
+ assertEquals("Should contain one user principal and two groups ", 3, actualSubject.getPrincipals().size());
+
+ assertTrue(actualSubject.getPrincipals().contains(new AuthenticatedPrincipal(_userPrincipal)));
+ assertTrue(actualSubject.getPrincipals().contains(_group1));
+ assertTrue(actualSubject.getPrincipals().contains(_group2));
+
+ assertTrue(actualSubject.isReadOnly());
+ }
+
+ public void testAuthenticateUnsuccessfulWithUsernameReturnsNullSubjectAndCorrectStatus()
+ {
+ testUnsuccessfulAuthentication(AuthenticationResult.AuthenticationStatus.CONTINUE);
+ testUnsuccessfulAuthentication(AuthenticationResult.AuthenticationStatus.ERROR);
+ }
+
+ private void testUnsuccessfulAuthentication(AuthenticationStatus expectedStatus)
+ {
+ AuthenticationResult failedAuthenticationResult = new AuthenticationResult(expectedStatus);
+
+ when(_authenticationManager.authenticate(USERNAME, PASSWORD)).thenReturn(failedAuthenticationResult);
+
+ SubjectAuthenticationResult subjectAuthenticationResult = _subjectCreator.authenticate(USERNAME, PASSWORD);
+
+ assertSame(expectedStatus, subjectAuthenticationResult.getStatus());
+ assertNull(subjectAuthenticationResult.getSubject());
+ }
+
+ public void testAuthenticateUnsuccessfulWithSaslServerReturnsNullSubjectAndCorrectStatus()
+ {
+ testUnsuccessfulAuthenticationWithSaslServer(AuthenticationResult.AuthenticationStatus.CONTINUE);
+ testUnsuccessfulAuthenticationWithSaslServer(AuthenticationResult.AuthenticationStatus.ERROR);
+ }
+
+ private void testUnsuccessfulAuthenticationWithSaslServer(AuthenticationStatus expectedStatus)
+ {
+ AuthenticationResult failedAuthenticationResult = new AuthenticationResult(expectedStatus);
+
+ when(_authenticationManager.authenticate(_testSaslServer, _saslResponseBytes)).thenReturn(failedAuthenticationResult);
+ when(_testSaslServer.isComplete()).thenReturn(false);
+
+ SubjectAuthenticationResult subjectAuthenticationResult = _subjectCreator.authenticate(_testSaslServer, _saslResponseBytes);
+
+ assertSame(expectedStatus, subjectAuthenticationResult.getStatus());
+ assertNull(subjectAuthenticationResult.getSubject());
+ }
+}
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/AuthenticatedPrincipalTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/AuthenticatedPrincipalTest.java
new file mode 100644
index 0000000000..cd5791952f
--- /dev/null
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/AuthenticatedPrincipalTest.java
@@ -0,0 +1,147 @@
+/*
+ * 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.auth;
+
+import java.security.Principal;
+
+import javax.security.auth.Subject;
+
+import org.apache.qpid.server.security.auth.UsernamePrincipal;
+
+import junit.framework.TestCase;
+
+public class AuthenticatedPrincipalTest extends TestCase
+{
+
+ private AuthenticatedPrincipal _authenticatedPrincipal = new AuthenticatedPrincipal(new UsernamePrincipal("name"));
+
+ public void testGetAuthenticatedPrincipalFromSubject()
+ {
+ final Subject subject = createSubjectContainingAuthenticatedPrincipal();
+ final AuthenticatedPrincipal actual = AuthenticatedPrincipal.getAuthenticatedPrincipalFromSubject(subject);
+ assertSame(_authenticatedPrincipal, actual);
+ }
+
+ public void testAuthenticatedPrincipalNotInSubject()
+ {
+ try
+ {
+ AuthenticatedPrincipal.getAuthenticatedPrincipalFromSubject(new Subject());
+ fail("Exception not thrown");
+ }
+ catch (IllegalArgumentException iae)
+ {
+ // PASS
+ }
+ }
+
+ public void testGetOptionalAuthenticatedPrincipalFromSubject()
+ {
+ final Subject subject = createSubjectContainingAuthenticatedPrincipal();
+ final AuthenticatedPrincipal actual = AuthenticatedPrincipal.getOptionalAuthenticatedPrincipalFromSubject(subject);
+ assertSame(_authenticatedPrincipal, actual);
+ }
+
+ public void testGetOptionalAuthenticatedPrincipalFromSubjectReturnsNullIfMissing()
+ {
+ Subject subjectWithNoPrincipals = new Subject();
+ assertNull(AuthenticatedPrincipal.getOptionalAuthenticatedPrincipalFromSubject(subjectWithNoPrincipals));
+
+ Subject subjectWithoutAuthenticatedPrincipal = new Subject();
+ subjectWithoutAuthenticatedPrincipal.getPrincipals().add(new UsernamePrincipal("name1"));
+ assertNull("Should return null for a subject containing a principal that isn't an AuthenticatedPrincipal",
+ AuthenticatedPrincipal.getOptionalAuthenticatedPrincipalFromSubject(subjectWithoutAuthenticatedPrincipal));
+ }
+
+ public void testTooManyAuthenticatedPrincipalsInSubject()
+ {
+ final Subject subject = new Subject();
+ subject.getPrincipals().add(new AuthenticatedPrincipal(new UsernamePrincipal("name1")));
+ subject.getPrincipals().add(new AuthenticatedPrincipal(new UsernamePrincipal("name2")));
+
+ try
+ {
+ AuthenticatedPrincipal.getAuthenticatedPrincipalFromSubject(subject);
+ fail("Exception not thrown");
+ }
+ catch (IllegalArgumentException iae)
+ {
+ // PASS
+ }
+ }
+
+ private Subject createSubjectContainingAuthenticatedPrincipal()
+ {
+ final Principal other = new Principal()
+ {
+ public String getName()
+ {
+ return "otherprincipal";
+ }
+ };
+
+ final Subject subject = new Subject();
+ subject.getPrincipals().add(_authenticatedPrincipal);
+ subject.getPrincipals().add(other);
+ return subject;
+ }
+
+ public void testEqualsAndHashcode()
+ {
+ AuthenticatedPrincipal user1principal1 = new AuthenticatedPrincipal(new UsernamePrincipal("user1"));
+ AuthenticatedPrincipal user1principal2 = new AuthenticatedPrincipal(new UsernamePrincipal("user1"));
+
+ assertTrue(user1principal1.equals(user1principal1));
+ assertTrue(user1principal1.equals(user1principal2));
+ assertTrue(user1principal2.equals(user1principal1));
+
+ assertEquals(user1principal1.hashCode(), user1principal2.hashCode());
+ }
+
+ public void testEqualsAndHashcodeWithSameWrappedObject()
+ {
+ UsernamePrincipal wrappedPrincipal = new UsernamePrincipal("user1");
+ AuthenticatedPrincipal user1principal1 = new AuthenticatedPrincipal(wrappedPrincipal);
+ AuthenticatedPrincipal user1principal2 = new AuthenticatedPrincipal(wrappedPrincipal);
+
+ assertTrue(user1principal1.equals(user1principal1));
+ assertTrue(user1principal1.equals(user1principal2));
+ assertTrue(user1principal2.equals(user1principal1));
+
+ assertEquals(user1principal1.hashCode(), user1principal2.hashCode());
+ }
+
+ public void testEqualsWithDifferentUsernames()
+ {
+ AuthenticatedPrincipal user1principal1 = new AuthenticatedPrincipal(new UsernamePrincipal("user1"));
+ AuthenticatedPrincipal user1principal2 = new AuthenticatedPrincipal(new UsernamePrincipal("user2"));
+
+ assertFalse(user1principal1.equals(user1principal2));
+ assertFalse(user1principal2.equals(user1principal1));
+ }
+
+ public void testEqualsWithDisimilarObjects()
+ {
+ UsernamePrincipal wrappedPrincipal = new UsernamePrincipal("user1");
+ AuthenticatedPrincipal authenticatedPrincipal = new AuthenticatedPrincipal(wrappedPrincipal);
+
+ assertFalse(authenticatedPrincipal.equals(wrappedPrincipal));
+ assertFalse(wrappedPrincipal.equals(authenticatedPrincipal));
+ }
+}
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/AuthenticatedPrincipalTestHelper.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/AuthenticatedPrincipalTestHelper.java
new file mode 100644
index 0000000000..e9d8d16fce
--- /dev/null
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/AuthenticatedPrincipalTestHelper.java
@@ -0,0 +1,54 @@
+/*
+ * 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.auth;
+
+import java.security.Principal;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import junit.framework.Assert;
+
+/**
+ * Helper class for testing that sets of principals contain {@link AuthenticatedPrincipal}'s that wrap
+ * expected {@link Principal}'s.
+ */
+public class AuthenticatedPrincipalTestHelper
+{
+ public static void assertOnlyContainsWrapped(Principal wrappedPrincipal, Set<Principal> principals)
+ {
+ assertOnlyContainsWrappedAndSecondaryPrincipals(wrappedPrincipal, Collections.<Principal>emptySet(), principals);
+ }
+
+
+ public static void assertOnlyContainsWrappedAndSecondaryPrincipals(
+ Principal expectedWrappedPrincipal,
+ Set<Principal> expectedSecondaryPrincipals,
+ Set<Principal> actualPrincipals)
+ {
+ Assert.assertEquals("Principal set should contain one principal " + "but the principal set is: " + actualPrincipals,
+ 1 + expectedSecondaryPrincipals.size(),
+ actualPrincipals.size());
+
+ Set<Principal> expectedSet = new HashSet<Principal>(expectedSecondaryPrincipals);
+ expectedSet.add(new AuthenticatedPrincipal(expectedWrappedPrincipal));
+
+ Assert.assertEquals(expectedSet, actualPrincipals);
+ }
+}
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/AuthenticationResultTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/AuthenticationResultTest.java
new file mode 100644
index 0000000000..a023cbdbb2
--- /dev/null
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/AuthenticationResultTest.java
@@ -0,0 +1,112 @@
+/*
+ * 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.auth;
+
+import static org.apache.qpid.server.security.auth.AuthenticatedPrincipalTestHelper.assertOnlyContainsWrapped;
+import static org.apache.qpid.server.security.auth.AuthenticatedPrincipalTestHelper.assertOnlyContainsWrappedAndSecondaryPrincipals;
+import static org.mockito.Mockito.mock;
+
+import java.security.Principal;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import junit.framework.TestCase;
+
+public class AuthenticationResultTest extends TestCase
+{
+ public void testConstructWithAuthenticationStatusContinue()
+ {
+ AuthenticationResult authenticationResult = new AuthenticationResult(AuthenticationResult.AuthenticationStatus.CONTINUE);
+ assertSame(AuthenticationResult.AuthenticationStatus.CONTINUE, authenticationResult.getStatus());
+ assertTrue(authenticationResult.getPrincipals().isEmpty());
+ }
+
+ public void testConstructWithAuthenticationStatusError()
+ {
+ AuthenticationResult authenticationResult = new AuthenticationResult(AuthenticationResult.AuthenticationStatus.ERROR);
+ assertSame(AuthenticationResult.AuthenticationStatus.ERROR, authenticationResult.getStatus());
+ assertTrue(authenticationResult.getPrincipals().isEmpty());
+ }
+
+ public void testConstructWithAuthenticationStatusSuccessThrowsException()
+ {
+ try
+ {
+ new AuthenticationResult(AuthenticationResult.AuthenticationStatus.SUCCESS);
+ fail("Exception not thrown");
+ }
+ catch(IllegalArgumentException e)
+ {
+ // PASS
+ }
+ }
+
+ public void testConstructWithPrincipal()
+ {
+ Principal mainPrincipal = mock(Principal.class);
+ AuthenticationResult authenticationResult = new AuthenticationResult(mainPrincipal);
+
+ assertOnlyContainsWrapped(mainPrincipal, authenticationResult.getPrincipals());
+ assertSame(AuthenticationResult.AuthenticationStatus.SUCCESS, authenticationResult.getStatus());
+ }
+
+ public void testConstructWithNullPrincipalThrowsException()
+ {
+ try
+ {
+ new AuthenticationResult((Principal)null);
+ fail("Exception not thrown");
+ }
+ catch(IllegalArgumentException e)
+ {
+ // pass
+ }
+ }
+
+ public void testConstructWithSetOfPrincipals()
+ {
+ Principal mainPrincipal = mock(Principal.class);
+ Principal secondaryPrincipal = mock(Principal.class);
+ Set<Principal> secondaryPrincipals = Collections.singleton(secondaryPrincipal);
+
+ AuthenticationResult authenticationResult = new AuthenticationResult(mainPrincipal, secondaryPrincipals);
+
+ assertOnlyContainsWrappedAndSecondaryPrincipals(mainPrincipal, secondaryPrincipals, authenticationResult.getPrincipals());
+ assertSame(AuthenticationResult.AuthenticationStatus.SUCCESS, authenticationResult.getStatus());
+ }
+
+ public void testConstructWithSetOfPrincipalsDeDuplicatesMainPrincipal()
+ {
+ Principal mainPrincipal = mock(Principal.class);
+ Principal secondaryPrincipal = mock(Principal.class);
+
+ Set<Principal> secondaryPrincipalsContainingDuplicateOfMainPrincipal = new HashSet<Principal>(
+ Arrays.asList(secondaryPrincipal, mainPrincipal));
+ Set<Principal> deDuplicatedSecondaryPrincipals = Collections.singleton(secondaryPrincipal);
+
+ AuthenticationResult authenticationResult = new AuthenticationResult(
+ mainPrincipal, secondaryPrincipalsContainingDuplicateOfMainPrincipal);
+
+ assertOnlyContainsWrappedAndSecondaryPrincipals(mainPrincipal, deDuplicatedSecondaryPrincipals, authenticationResult.getPrincipals());
+
+ assertSame(AuthenticationResult.AuthenticationStatus.SUCCESS, authenticationResult.getStatus());
+ }
+}
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/sasl/TestPrincipalUtils.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/TestPrincipalUtils.java
index 7ce03eaa79..ea6b40e3de 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/sasl/TestPrincipalUtils.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/TestPrincipalUtils.java
@@ -18,9 +18,12 @@
* under the License.
*
*/
-package org.apache.qpid.server.security.auth.sasl;
+package org.apache.qpid.server.security.auth;
import javax.security.auth.Subject;
+
+import org.apache.qpid.server.security.group.GroupPrincipal;
+
import java.security.Principal;
import java.util.Collections;
import java.util.HashSet;
@@ -28,21 +31,19 @@ import java.util.Set;
public class TestPrincipalUtils
{
-
/**
- * Creates a test subject, with exactly one UsernamePrincipal and zero or more GroupPrincipals.
+ * Creates a test subject, with exactly one {@link AuthenticatedPrincipal} and zero or more GroupPrincipals.
*/
public static Subject createTestSubject(final String username, final String... groups)
{
final Set<Principal> principals = new HashSet<Principal>(1 + groups.length);
- principals.add(new UsernamePrincipal(username));
+ principals.add(new AuthenticatedPrincipal(username));
for (String group : groups)
{
principals.add(new GroupPrincipal(group));
}
-
- final Subject subject = new Subject(true, principals, Collections.EMPTY_SET, Collections.EMPTY_SET);
- return subject;
+
+ return new Subject(true, principals, Collections.EMPTY_SET, Collections.EMPTY_SET);
}
}
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/sasl/UsernamePrincipalTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/UsernamePrincipalTest.java
index 75bc76c688..5e025d3ca8 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/sasl/UsernamePrincipalTest.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/UsernamePrincipalTest.java
@@ -18,13 +18,10 @@
* under the License.
*
*/
-package org.apache.qpid.server.security.auth.sasl;
+package org.apache.qpid.server.security.auth;
import junit.framework.TestCase;
-import javax.security.auth.Subject;
-import java.security.Principal;
-
/**
* Tests the UsernamePrincipal.
*
@@ -70,54 +67,4 @@ public class UsernamePrincipalTest extends TestCase
UsernamePrincipal principal = new UsernamePrincipal("string");
assertFalse(principal.equals(null));
}
-
- public void testGetUsernamePrincipalFromSubject()
- {
- final UsernamePrincipal expected = new UsernamePrincipal("name");
- final Principal other = new Principal()
- {
- public String getName()
- {
- return "otherprincipal";
- }
- };
-
- final Subject subject = new Subject();
- subject.getPrincipals().add(expected);
- subject.getPrincipals().add(other);
-
- final UsernamePrincipal actual = UsernamePrincipal.getUsernamePrincipalFromSubject(subject);
- assertSame(expected, actual);
- }
-
- public void testUsernamePrincipalNotInSubject()
- {
- try
- {
- UsernamePrincipal.getUsernamePrincipalFromSubject(new Subject());
- fail("Exception not thrown");
- }
- catch (IllegalArgumentException iae)
- {
- // PASS
- }
- }
-
- public void testTooManyUsernamePrincipalInSubject()
- {
- final Subject subject = new Subject();
- subject.getPrincipals().add(new UsernamePrincipal("name1"));
- subject.getPrincipals().add(new UsernamePrincipal("name2"));
- try
- {
-
- UsernamePrincipal.getUsernamePrincipalFromSubject(subject);
- fail("Exception not thrown");
- }
- catch (IllegalArgumentException iae)
- {
- // PASS
- }
- }
-
}
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabaseTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabaseTest.java
index 33740af1e7..7b244e219e 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabaseTest.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabaseTest.java
@@ -23,7 +23,7 @@ package org.apache.qpid.server.security.auth.database;
import junit.framework.TestCase;
import org.apache.commons.codec.binary.Base64;
-import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal;
+import org.apache.qpid.server.security.auth.UsernamePrincipal;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.login.AccountNotFoundException;
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabaseTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabaseTest.java
index b8601f0e5c..8e62324f7d 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabaseTest.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabaseTest.java
@@ -22,7 +22,7 @@ package org.apache.qpid.server.security.auth.database;
import junit.framework.TestCase;
-import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal;
+import org.apache.qpid.server.security.auth.UsernamePrincipal;
import javax.security.auth.login.AccountNotFoundException;
import java.io.BufferedReader;
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/manager/AnonymousAuthenticationManagerTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/manager/AnonymousAuthenticationManagerTest.java
index 9dcd22c088..a36e97199f 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/manager/AnonymousAuthenticationManagerTest.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/manager/AnonymousAuthenticationManagerTest.java
@@ -20,6 +20,8 @@
*/
package org.apache.qpid.server.security.auth.manager;
+import static org.apache.qpid.server.security.auth.AuthenticatedPrincipalTestHelper.assertOnlyContainsWrapped;
+
import javax.security.sasl.SaslException;
import javax.security.sasl.SaslServer;
import org.apache.commons.configuration.CompositeConfiguration;
@@ -102,7 +104,8 @@ public class AnonymousAuthenticationManagerTest extends InternalBrokerBaseCase
assertEquals("Expected authentication to be successful",
AuthenticationResult.AuthenticationStatus.SUCCESS,
result.getStatus());
- assertNotNull("Subject should not be null", result.getSubject());
+
+ assertOnlyContainsWrapped(AnonymousAuthenticationManager.ANONYMOUS_PRINCIPAL, result.getPrincipals());
}
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/manager/AuthenticationManagerRegistryTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/manager/AuthenticationManagerRegistryTest.java
index efb8df3a38..9b7131c71a 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/manager/AuthenticationManagerRegistryTest.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/manager/AuthenticationManagerRegistryTest.java
@@ -35,6 +35,8 @@ import org.apache.qpid.server.configuration.ServerConfiguration;
import org.apache.qpid.server.plugins.Plugin;
import org.apache.qpid.server.plugins.PluginManager;
import org.apache.qpid.server.security.SecurityManager.SecurityConfiguration;
+import org.apache.qpid.server.security.SubjectCreator;
+import org.apache.qpid.server.security.group.GroupPrincipalAccessor;
import org.mockito.Mockito;
import junit.framework.TestCase;
@@ -49,6 +51,8 @@ public class AuthenticationManagerRegistryTest extends TestCase
private List<AuthenticationManager> _allCreatedAuthManagers = new ArrayList<AuthenticationManager>();
+ private GroupPrincipalAccessor _groupPrincipalAccessor = mock(GroupPrincipalAccessor.class);;
+
@Override
protected void setUp() throws Exception
{
@@ -76,7 +80,7 @@ public class AuthenticationManagerRegistryTest extends TestCase
when(_pluginManager.getAuthenticationManagerPlugins()).thenReturn(EMPTY_PLUGINMAP);
try
{
- new AuthenticationManagerRegistry(_serverConfiguration, _pluginManager);
+ new AuthenticationManagerRegistry(_serverConfiguration, _pluginManager, _groupPrincipalAccessor);
fail("Exception not thrown");
}
catch (ConfigurationException ce)
@@ -97,7 +101,7 @@ public class AuthenticationManagerRegistryTest extends TestCase
try
{
- new AuthenticationManagerRegistry(_serverConfiguration, _pluginManager);
+ new AuthenticationManagerRegistry(_serverConfiguration, _pluginManager, _groupPrincipalAccessor);
fail("Exception not thrown");
}
catch (ConfigurationException ce)
@@ -120,7 +124,7 @@ public class AuthenticationManagerRegistryTest extends TestCase
try
{
- new AuthenticationManagerRegistry(_serverConfiguration, _pluginManager);
+ new AuthenticationManagerRegistry(_serverConfiguration, _pluginManager, _groupPrincipalAccessor);
fail("Exception not thrown");
}
catch (ConfigurationException ce)
@@ -145,7 +149,7 @@ public class AuthenticationManagerRegistryTest extends TestCase
try
{
- new AuthenticationManagerRegistry(_serverConfiguration, _pluginManager);
+ new AuthenticationManagerRegistry(_serverConfiguration, _pluginManager, _groupPrincipalAccessor);
fail("Exception not thrown");
}
catch (ConfigurationException ce)
@@ -170,7 +174,7 @@ public class AuthenticationManagerRegistryTest extends TestCase
try
{
- new AuthenticationManagerRegistry(_serverConfiguration, _pluginManager);
+ new AuthenticationManagerRegistry(_serverConfiguration, _pluginManager, _groupPrincipalAccessor);
fail("Exception not thrown");
}
catch (ConfigurationException ce)
@@ -187,10 +191,10 @@ public class AuthenticationManagerRegistryTest extends TestCase
when(_pluginManager.getAuthenticationManagerPlugins()).thenReturn(pluginMap);
- AuthenticationManagerRegistry registry = new AuthenticationManagerRegistry(_serverConfiguration, _pluginManager);
+ AuthenticationManagerRegistry registry = new AuthenticationManagerRegistry(_serverConfiguration, _pluginManager, _groupPrincipalAccessor);
- AuthenticationManager authenticationManager = registry.getAuthenticationManager(new InetSocketAddress(1234));
- assertEquals("TestAuthenticationManager1", authenticationManager.getMechanisms());
+ SubjectCreator subjectCreator = registry.getSubjectCreator(new InetSocketAddress(1234));
+ assertEquals("TestAuthenticationManager1", subjectCreator.getMechanisms());
registry.close();
}
@@ -202,10 +206,10 @@ public class AuthenticationManagerRegistryTest extends TestCase
when(_pluginManager.getAuthenticationManagerPlugins()).thenReturn(pluginMap);
- AuthenticationManagerRegistry registry = new AuthenticationManagerRegistry(_serverConfiguration, _pluginManager);
+ AuthenticationManagerRegistry registry = new AuthenticationManagerRegistry(_serverConfiguration, _pluginManager, _groupPrincipalAccessor);
- AuthenticationManager authenticationManager = registry.getAuthenticationManager(mock(SocketAddress.class));
- assertEquals("TestAuthenticationManager1", authenticationManager.getMechanisms());
+ SubjectCreator subjectCreator = registry.getSubjectCreator(mock(SocketAddress.class));
+ assertEquals("TestAuthenticationManager1", subjectCreator.getMechanisms());
registry.close();
}
@@ -225,13 +229,13 @@ public class AuthenticationManagerRegistryTest extends TestCase
when(_serverConfiguration.getDefaultAuthenticationManager()).thenReturn(defaultAuthManger);
when(_serverConfiguration.getPortAuthenticationMappings()).thenReturn(Collections.singletonMap(mappedPortNumber, mappedAuthManager));
- AuthenticationManagerRegistry registry = new AuthenticationManagerRegistry(_serverConfiguration, _pluginManager);
+ AuthenticationManagerRegistry registry = new AuthenticationManagerRegistry(_serverConfiguration, _pluginManager, _groupPrincipalAccessor);
- AuthenticationManager authenticationManager1 = registry.getAuthenticationManager(new InetSocketAddress(unmappedPortNumber));
- assertEquals("TestAuthenticationManager1", authenticationManager1.getMechanisms());
+ SubjectCreator subjectCreator = registry.getSubjectCreator(new InetSocketAddress(unmappedPortNumber));
+ assertEquals("TestAuthenticationManager1", subjectCreator.getMechanisms());
- AuthenticationManager authenticationManager2 = registry.getAuthenticationManager(new InetSocketAddress(mappedPortNumber));
- assertEquals("TestAuthenticationManager2", authenticationManager2.getMechanisms());
+ SubjectCreator subjectCreator2 = registry.getSubjectCreator(new InetSocketAddress(mappedPortNumber));
+ assertEquals("TestAuthenticationManager2", subjectCreator2.getMechanisms());
registry.close();
}
@@ -246,7 +250,7 @@ public class AuthenticationManagerRegistryTest extends TestCase
when(_pluginManager.getAuthenticationManagerPlugins()).thenReturn(pluginMap);
when(_serverConfiguration.getDefaultAuthenticationManager()).thenReturn(defaultAuthManger);
- AuthenticationManagerRegistry registry = new AuthenticationManagerRegistry(_serverConfiguration, _pluginManager);
+ AuthenticationManagerRegistry registry = new AuthenticationManagerRegistry(_serverConfiguration, _pluginManager, _groupPrincipalAccessor);
registry.close();
}
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationManagerTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationManagerTest.java
index c1a55ef2ad..4e0643e229 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationManagerTest.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationManagerTest.java
@@ -18,6 +18,8 @@
*/
package org.apache.qpid.server.security.auth.manager;
+import static org.apache.qpid.server.security.auth.AuthenticatedPrincipalTestHelper.assertOnlyContainsWrapped;
+
import javax.security.auth.x500.X500Principal;
import javax.security.sasl.SaslException;
import javax.security.sasl.SaslServer;
@@ -25,6 +27,7 @@ import org.apache.commons.configuration.CompositeConfiguration;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.XMLConfiguration;
import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin;
+
import org.apache.qpid.server.security.auth.AuthenticationResult;
import org.apache.qpid.server.security.auth.database.PlainPasswordFilePrincipalDatabase;
import org.apache.qpid.server.util.InternalBrokerBaseCase;
@@ -103,12 +106,12 @@ public class ExternalAuthenticationManagerTest extends InternalBrokerBaseCase
assertEquals("Expected authentication to be successful",
AuthenticationResult.AuthenticationStatus.SUCCESS,
result.getStatus());
- assertEquals("Expected principal to be unchanged",
- principal,
- result.getSubject().getPrincipals().iterator().next());
+
+ assertOnlyContainsWrapped(principal, result.getPrincipals());
saslServer = _manager.createSaslServer("EXTERNAL", "example.example.com", null);
result = _manager.authenticate(saslServer, new byte[0]);
+
assertNotNull(result);
assertEquals("Expected authentication to be unsuccessful",
AuthenticationResult.AuthenticationStatus.ERROR,
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManagerTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManagerTest.java
index 47c189e4fa..391eb4e665 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManagerTest.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManagerTest.java
@@ -20,6 +20,8 @@
*/
package org.apache.qpid.server.security.auth.manager;
+import static org.apache.qpid.server.security.auth.AuthenticatedPrincipalTestHelper.assertOnlyContainsWrapped;
+
import org.apache.commons.configuration.CompositeConfiguration;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.XMLConfiguration;
@@ -28,10 +30,9 @@ import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin;
import org.apache.qpid.server.security.auth.AuthenticationResult;
import org.apache.qpid.server.security.auth.AuthenticationResult.AuthenticationStatus;
import org.apache.qpid.server.security.auth.database.PlainPasswordFilePrincipalDatabase;
-import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal;
+import org.apache.qpid.server.security.auth.UsernamePrincipal;
import org.apache.qpid.server.util.InternalBrokerBaseCase;
-import javax.security.auth.Subject;
import javax.security.sasl.SaslException;
import javax.security.sasl.SaslServer;
import java.io.BufferedWriter;
@@ -48,6 +49,7 @@ import java.security.Security;
*/
public class PrincipalDatabaseAuthenticationManagerTest extends InternalBrokerBaseCase
{
+ private static final UsernamePrincipal PRINCIPAL = new UsernamePrincipal("guest");
private AuthenticationManager _manager = null; // Class under test
private String TEST_USERNAME = "guest";
private String TEST_PASSWORD = "guest";
@@ -72,7 +74,7 @@ public class PrincipalDatabaseAuthenticationManagerTest extends InternalBrokerBa
public void setUp() throws Exception
{
super.setUp();
-
+
final String passwdFilename = createPasswordFile().getCanonicalPath();
final ConfigurationPlugin config = getConfig(PlainPasswordFilePrincipalDatabase.class.getName(),
"passwordFile", passwdFilename);
@@ -121,7 +123,7 @@ public class PrincipalDatabaseAuthenticationManagerTest extends InternalBrokerBa
{
try
{
- _manager = PrincipalDatabaseAuthenticationManager.FACTORY.newInstance(getConfig(PlainPasswordFilePrincipalDatabase.class.getName(), "noMethod", "test"));
+ _manager = PrincipalDatabaseAuthenticationManager.FACTORY.newInstance(getConfig(PlainPasswordFilePrincipalDatabase.class.getName(), "noMethod", "test"));
fail("Exception not thrown");
}
catch (ConfigurationException ce)
@@ -137,7 +139,7 @@ public class PrincipalDatabaseAuthenticationManagerTest extends InternalBrokerBa
{
try
{
- _manager = PrincipalDatabaseAuthenticationManager.FACTORY.newInstance(getConfig(PlainPasswordFilePrincipalDatabase.class.getName(), "passwordFile", "/not/found"));
+ _manager = PrincipalDatabaseAuthenticationManager.FACTORY.newInstance(getConfig(PlainPasswordFilePrincipalDatabase.class.getName(), "passwordFile", "/not/found"));
fail("Exception not thrown");
}
catch (ConfigurationException ce)
@@ -157,7 +159,7 @@ public class PrincipalDatabaseAuthenticationManagerTest extends InternalBrokerBa
// relies on those mechanisms attached to PropertiesPrincipalDatabaseManager
assertEquals("AMQPLAIN PLAIN CRAM-MD5", _manager.getMechanisms());
- Provider qpidProvider = Security.getProvider(PrincipalDatabaseAuthenticationManager.PROVIDER_NAME);
+ Provider qpidProvider = Security.getProvider(AuthenticationManager.PROVIDER_NAME);
assertNotNull(qpidProvider);
}
@@ -172,49 +174,51 @@ public class PrincipalDatabaseAuthenticationManagerTest extends InternalBrokerBa
// Merely tests the creation of the mechanism. Mechanisms themselves are tested
// by their own tests.
}
-
+
/**
* Tests that the authenticate method correctly interprets an
* authentication success.
- *
+ *
*/
public void testSaslAuthenticationSuccess() throws Exception
{
+
SaslServer testServer = createTestSaslServer(true, false);
-
+
AuthenticationResult result = _manager.authenticate(testServer, "12345".getBytes());
- final Subject subject = result.getSubject();
- assertTrue(subject.getPrincipals().contains(new UsernamePrincipal("guest")));
+
+ assertOnlyContainsWrapped(PRINCIPAL, result.getPrincipals());
assertEquals(AuthenticationStatus.SUCCESS, result.getStatus());
}
/**
- *
+ *
* Tests that the authenticate method correctly interprets an
* authentication not complete.
- *
+ *
*/
public void testSaslAuthenticationNotCompleted() throws Exception
{
SaslServer testServer = createTestSaslServer(false, false);
-
+
AuthenticationResult result = _manager.authenticate(testServer, "12345".getBytes());
- assertNull(result.getSubject());
+ assertEquals("Principals was not expected size", 0, result.getPrincipals().size());
+
assertEquals(AuthenticationStatus.CONTINUE, result.getStatus());
}
/**
- *
+ *
* Tests that the authenticate method correctly interprets an
* authentication error.
- *
+ *
*/
public void testSaslAuthenticationError() throws Exception
{
SaslServer testServer = createTestSaslServer(false, true);
-
+
AuthenticationResult result = _manager.authenticate(testServer, "12345".getBytes());
- assertNull(result.getSubject());
+ assertEquals("Principals was not expected size", 0, result.getPrincipals().size());
assertEquals(AuthenticationStatus.ERROR, result.getStatus());
}
@@ -226,9 +230,7 @@ public class PrincipalDatabaseAuthenticationManagerTest extends InternalBrokerBa
public void testNonSaslAuthenticationSuccess() throws Exception
{
AuthenticationResult result = _manager.authenticate("guest", "guest");
- final Subject subject = result.getSubject();
- assertFalse("Subject should not be set read-only", subject.isReadOnly());
- assertTrue(subject.getPrincipals().contains(new UsernamePrincipal("guest")));
+ assertOnlyContainsWrapped(PRINCIPAL, result.getPrincipals());
assertEquals(AuthenticationStatus.SUCCESS, result.getStatus());
}
@@ -240,23 +242,23 @@ public class PrincipalDatabaseAuthenticationManagerTest extends InternalBrokerBa
public void testNonSaslAuthenticationNotCompleted() throws Exception
{
AuthenticationResult result = _manager.authenticate("guest", "wrongpassword");
- assertNull(result.getSubject());
+ assertEquals("Principals was not expected size", 0, result.getPrincipals().size());
assertEquals(AuthenticationStatus.CONTINUE, result.getStatus());
}
-
+
/**
* Tests the ability to de-register the provider.
*/
public void testClose() throws Exception
{
assertEquals("AMQPLAIN PLAIN CRAM-MD5", _manager.getMechanisms());
- assertNotNull(Security.getProvider(PrincipalDatabaseAuthenticationManager.PROVIDER_NAME));
+ assertNotNull(Security.getProvider(AuthenticationManager.PROVIDER_NAME));
_manager.close();
// Check provider has been removed.
assertNull(_manager.getMechanisms());
- assertNull(Security.getProvider(PrincipalDatabaseAuthenticationManager.PROVIDER_NAME));
+ assertNull(Security.getProvider(AuthenticationManager.PROVIDER_NAME));
_manager = null;
}
@@ -343,7 +345,7 @@ public class PrincipalDatabaseAuthenticationManagerTest extends InternalBrokerBa
writer = new BufferedWriter(new FileWriter(testFile));
writer.write(TEST_USERNAME + ":" + TEST_PASSWORD);
writer.newLine();
-
+
return testFile;
}
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticatorTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticatorTest.java
index c0c55de92a..efdb286866 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticatorTest.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/rmi/RMIPasswordAuthenticatorTest.java
@@ -20,20 +20,21 @@
*/
package org.apache.qpid.server.security.auth.rmi;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.net.InetSocketAddress;
import java.security.Principal;
+
+import javax.security.auth.Subject;
+
import junit.framework.TestCase;
-import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin;
+import org.apache.qpid.server.security.SubjectCreator;
import org.apache.qpid.server.security.auth.AuthenticationResult;
import org.apache.qpid.server.security.auth.AuthenticationResult.AuthenticationStatus;
-import org.apache.qpid.server.security.auth.manager.AuthenticationManager;
-
-import javax.management.remote.JMXPrincipal;
-import javax.security.auth.Subject;
-import javax.security.sasl.SaslException;
-import javax.security.sasl.SaslServer;
-import java.net.InetSocketAddress;
-import java.util.Collections;
+import org.apache.qpid.server.security.auth.SubjectAuthenticationResult;
/**
* Tests the RMIPasswordAuthenticator and its collaboration with the AuthenticationManager.
@@ -41,6 +42,7 @@ import java.util.Collections;
*/
public class RMIPasswordAuthenticatorTest extends TestCase
{
+ private static final Subject SUBJECT = new Subject();
private final String USERNAME = "guest";
private final String PASSWORD = "guest";
private RMIPasswordAuthenticator _rmipa;
@@ -54,23 +56,14 @@ public class RMIPasswordAuthenticatorTest extends TestCase
}
/**
- * Tests a successful authentication. Ensures that a populated read-only subject it returned.
+ * Tests a successful authentication. Ensures that the expected subject is returned.
*/
public void testAuthenticationSuccess()
{
- final Subject expectedSubject = new Subject(true,
- Collections.singleton(new JMXPrincipal(USERNAME)),
- Collections.EMPTY_SET,
- Collections.EMPTY_SET);
-
- _rmipa.setAuthenticationManager(createTestAuthenticationManager(true, null));
-
+ _rmipa.setSubjectCreator(createMockSubjectCreator(true, null));
Subject newSubject = _rmipa.authenticate(_credentials);
- assertTrue("Subject must be readonly", newSubject.isReadOnly());
- assertTrue("Returned subject does not equal expected value",
- newSubject.equals(expectedSubject));
-
+ assertSame("Subject must be unchanged", SUBJECT, newSubject);
}
/**
@@ -78,7 +71,7 @@ public class RMIPasswordAuthenticatorTest extends TestCase
*/
public void testUsernameOrPasswordInvalid()
{
- _rmipa.setAuthenticationManager(createTestAuthenticationManager(false, null));
+ _rmipa.setSubjectCreator(createMockSubjectCreator(false, null));
try
{
@@ -99,7 +92,7 @@ public class RMIPasswordAuthenticatorTest extends TestCase
public void testAuthenticationFailure()
{
final Exception mockAuthException = new Exception("Mock Auth system failure");
- _rmipa.setAuthenticationManager(createTestAuthenticationManager(false, mockAuthException));
+ _rmipa.setSubjectCreator(createMockSubjectCreator(false, mockAuthException));
try
{
@@ -118,7 +111,7 @@ public class RMIPasswordAuthenticatorTest extends TestCase
*/
public void testNullAuthenticationManager() throws Exception
{
- _rmipa.setAuthenticationManager(null);
+ _rmipa.setSubjectCreator(null);
try
{
_rmipa.authenticate(_credentials);
@@ -209,55 +202,30 @@ public class RMIPasswordAuthenticatorTest extends TestCase
}
}
- private AuthenticationManager createTestAuthenticationManager(final boolean successfulAuth, final Exception exception)
+ private SubjectCreator createMockSubjectCreator(final boolean successfulAuth, final Exception exception)
{
- return new AuthenticationManager()
- {
- public void configure(ConfigurationPlugin config)
- {
- throw new UnsupportedOperationException();
- }
+ SubjectCreator subjectCreator = mock(SubjectCreator.class);
- public void initialise()
- {
- throw new UnsupportedOperationException();
- }
+ SubjectAuthenticationResult subjectAuthenticationResult;
- public void close()
- {
- throw new UnsupportedOperationException();
- }
+ if (exception != null) {
- public String getMechanisms()
- {
- throw new UnsupportedOperationException();
- }
-
- public SaslServer createSaslServer(String mechanism, String localFQDN, Principal externalPrincipal) throws SaslException
- {
- throw new UnsupportedOperationException();
- }
+ subjectAuthenticationResult = new SubjectAuthenticationResult(
+ new AuthenticationResult(AuthenticationStatus.ERROR, exception));
+ }
+ else if (successfulAuth)
+ {
- public AuthenticationResult authenticate(SaslServer server, byte[] response)
- {
- throw new UnsupportedOperationException();
- }
+ subjectAuthenticationResult = new SubjectAuthenticationResult(
+ new AuthenticationResult(mock(Principal.class)), SUBJECT);
+ }
+ else
+ {
+ subjectAuthenticationResult = new SubjectAuthenticationResult(new AuthenticationResult(AuthenticationStatus.CONTINUE));
+ }
- public AuthenticationResult authenticate(String username, String password)
- {
- if (exception != null) {
- return new AuthenticationResult(AuthenticationStatus.ERROR, exception);
- }
- else if (successfulAuth)
- {
- return new AuthenticationResult(new Subject());
- }
- else
- {
- return new AuthenticationResult(AuthenticationStatus.CONTINUE);
- }
- }
+ when(subjectCreator.authenticate(anyString(), anyString())).thenReturn(subjectAuthenticationResult);
- };
+ return subjectCreator;
}
}
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/group/FileGroupDatabaseTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/group/FileGroupDatabaseTest.java
new file mode 100644
index 0000000000..b020c1655a
--- /dev/null
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/group/FileGroupDatabaseTest.java
@@ -0,0 +1,456 @@
+/*
+ * 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.group;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Properties;
+import java.util.Set;
+
+import org.apache.qpid.server.security.group.FileGroupDatabase;
+
+import junit.framework.TestCase;
+
+public class FileGroupDatabaseTest extends TestCase
+{
+ private static final String USER1 = "user1";
+ private static final String USER2 = "user2";
+ private static final String USER3 = "user3";
+
+ private static final String MY_GROUP = "myGroup";
+ private static final String MY_GROUP2 = "myGroup2";
+ private static final String MY_GROUP1 = "myGroup1";
+
+ private FileGroupDatabase _groupDatabase = new FileGroupDatabase();
+ private String _groupFile;
+
+ public void testGetAllGroups() throws Exception
+ {
+ writeAndSetGroupFile("myGroup.users", USER1);
+
+ Set<String> groups = _groupDatabase.getAllGroups();
+ assertEquals(1, groups.size());
+ assertTrue(groups.contains(MY_GROUP));
+ }
+
+ public void testGetAllGroupsWhenGroupFileEmpty() throws Exception
+ {
+ _groupDatabase.setGroupFile(_groupFile);
+
+ Set<String> groups = _groupDatabase.getAllGroups();
+ assertEquals(0, groups.size());
+ }
+
+ public void testMissingGroupFile() throws Exception
+ {
+ try
+ {
+ _groupDatabase.setGroupFile("/not/a/file");
+ fail("Exception not thrown");
+ }
+ catch (FileNotFoundException fnfe)
+ {
+ // PASS
+ }
+ }
+
+ public void testInvalidFormat() throws Exception
+ {
+ writeGroupFile("name.notvalid", USER1);
+
+ try
+ {
+ _groupDatabase.setGroupFile(_groupFile);
+ fail("Exception not thrown");
+ }
+ catch (IllegalArgumentException gde)
+ {
+ // PASS
+ }
+ }
+
+ public void testGetUsersInGroup() throws Exception
+ {
+ writeGroupFile("myGroup.users", "user1,user2,user3");
+
+ _groupDatabase.setGroupFile(_groupFile);
+
+ Set<String> users = _groupDatabase.getUsersInGroup(MY_GROUP);
+ assertNotNull(users);
+ assertEquals(3, users.size());
+ }
+
+ public void testDuplicateUsersInGroupAreConflated() throws Exception
+ {
+ writeAndSetGroupFile("myGroup.users", "user1,user1,user3,user1");
+
+ Set<String> users = _groupDatabase.getUsersInGroup(MY_GROUP);
+ assertNotNull(users);
+ assertEquals(2, users.size());
+ }
+
+ public void testGetUsersWithEmptyGroup() throws Exception
+ {
+ writeAndSetGroupFile("myGroup.users", "");
+
+ Set<String> users = _groupDatabase.getUsersInGroup(MY_GROUP);
+ assertNotNull(users);
+ assertTrue(users.isEmpty());
+ }
+
+ public void testGetUsersInNonExistentGroup() throws Exception
+ {
+ writeAndSetGroupFile("myGroup.users", "user1,user2,user3");
+
+ Set<String> users = _groupDatabase.getUsersInGroup("groupDoesntExist");
+ assertNotNull(users);
+ assertTrue(users.isEmpty());
+ }
+
+ public void testGetUsersInNullGroup() throws Exception
+ {
+ writeAndSetGroupFile();
+ assertTrue(_groupDatabase.getUsersInGroup(null).isEmpty());
+ }
+
+ public void testGetGroupPrincipalsForUserWhenUserBelongsToOneGroup() throws Exception
+ {
+ writeAndSetGroupFile("myGroup.users", "user1,user2");
+ Set<String> groups = _groupDatabase.getGroupsForUser(USER1);
+ assertEquals(1, groups.size());
+ assertTrue(groups.contains(MY_GROUP));
+ }
+
+ public void testGetGroupPrincipalsForUserWhenUserBelongsToTwoGroup() throws Exception
+ {
+ writeAndSetGroupFile("myGroup1.users", "user1,user2",
+ "myGroup2.users", "user1,user3");
+ Set<String> groups = _groupDatabase.getGroupsForUser(USER1);
+ assertEquals(2, groups.size());
+ assertTrue(groups.contains(MY_GROUP1));
+ assertTrue(groups.contains(MY_GROUP2));
+ }
+
+ public void testGetGroupPrincipalsForUserWhenUserAddedToGroup() throws Exception
+ {
+ writeAndSetGroupFile("myGroup1.users", "user1,user2",
+ "myGroup2.users", USER2);
+ Set<String> groups = _groupDatabase.getGroupsForUser(USER1);
+ assertEquals(1, groups.size());
+ assertTrue(groups.contains(MY_GROUP1));
+
+ _groupDatabase.addUserToGroup(USER1, MY_GROUP2);
+
+ groups = _groupDatabase.getGroupsForUser(USER1);
+ assertEquals(2, groups.size());
+ assertTrue(groups.contains(MY_GROUP1));
+ assertTrue(groups.contains(MY_GROUP2));
+
+ Set<String> users = _groupDatabase.getUsersInGroup(MY_GROUP2);
+ assertEquals(2, users.size());
+ assertTrue(users.contains(USER1));
+ assertTrue(users.contains(USER2));
+ }
+
+ public void testGetGroupPrincipalsForUserWhenUserRemovedFromGroup() throws Exception
+ {
+ writeAndSetGroupFile("myGroup1.users", "user1,user2",
+ "myGroup2.users", "user1,user2");
+ Set<String> groups = _groupDatabase.getGroupsForUser(USER1);
+ assertEquals(2, groups.size());
+ assertTrue(groups.contains(MY_GROUP1));
+ assertTrue(groups.contains(MY_GROUP2));
+
+ _groupDatabase.removeUserFromGroup(USER1, MY_GROUP2);
+
+ groups = _groupDatabase.getGroupsForUser(USER1);
+ assertEquals(1, groups.size());
+ assertTrue(groups.contains(MY_GROUP1));
+ }
+
+ public void testGetGroupPrincipalsForUserWhenUserAdddedToGroupTheyAreAlreadyIn() throws Exception
+ {
+ writeAndSetGroupFile("myGroup.users", USER1);
+ _groupDatabase.addUserToGroup(USER1, MY_GROUP);
+
+ Set<String> groups = _groupDatabase.getGroupsForUser(USER1);
+
+ assertEquals(1, groups.size());
+ assertTrue(groups.contains(MY_GROUP));
+
+ Set<String> users = _groupDatabase.getUsersInGroup(MY_GROUP);
+ assertEquals(1, users.size());
+ assertTrue(users.contains(USER1));
+ }
+
+ public void testGetGroupPrincipalsForUserWhenUserNotKnown() throws Exception
+ {
+ writeAndSetGroupFile("myGroup.users", "user1,user2");
+ Set<String> groups = _groupDatabase.getGroupsForUser(USER3);
+ assertEquals(0, groups.size());
+ }
+
+ public void testGetGroupPrincipalsForNullUser() throws Exception
+ {
+ writeAndSetGroupFile();
+ assertTrue(_groupDatabase.getGroupsForUser(null).isEmpty());
+ }
+
+ public void testAddUserToExistingGroup() throws Exception
+ {
+ writeAndSetGroupFile("myGroup.users", "user1,user2");
+
+ Set<String> users = _groupDatabase.getUsersInGroup(MY_GROUP);
+ assertNotNull(users);
+ assertEquals(2, users.size());
+
+ _groupDatabase.addUserToGroup(USER3, MY_GROUP);
+
+ users = _groupDatabase.getUsersInGroup(MY_GROUP);
+ assertNotNull(users);
+ assertEquals(3, users.size());
+ }
+
+ public void testAddUserToEmptyGroup() throws Exception
+ {
+ writeAndSetGroupFile("myGroup.users", "");
+
+ Set<String> users = _groupDatabase.getUsersInGroup(MY_GROUP);
+ assertNotNull(users);
+ assertEquals(0, users.size());
+
+ _groupDatabase.addUserToGroup(USER3, MY_GROUP);
+
+ users = _groupDatabase.getUsersInGroup(MY_GROUP);
+ assertNotNull(users);
+ assertEquals(1, users.size());
+ }
+
+ public void testAddUserToNonExistentGroup() throws Exception
+ {
+ writeAndSetGroupFile();
+
+ Set<String> users = _groupDatabase.getUsersInGroup(MY_GROUP);
+ assertNotNull(users);
+ assertEquals(0, users.size());
+
+ try
+ {
+ _groupDatabase.addUserToGroup(USER3, MY_GROUP);
+ fail("Expected exception not thrown");
+ }
+ catch(IllegalArgumentException e)
+ {
+ // pass
+ }
+
+ users = _groupDatabase.getUsersInGroup(MY_GROUP);
+ assertNotNull(users);
+ assertEquals(0, users.size());
+ }
+
+ public void testRemoveUserFromExistingGroup() throws Exception
+ {
+ writeAndSetGroupFile("myGroup.users", "user1,user2");
+
+ Set<String> users = _groupDatabase.getUsersInGroup(MY_GROUP);
+ assertNotNull(users);
+ assertEquals(2, users.size());
+
+ _groupDatabase.removeUserFromGroup(USER2, MY_GROUP);
+
+ users = _groupDatabase.getUsersInGroup(MY_GROUP);
+ assertNotNull(users);
+ assertEquals(1, users.size());
+ }
+
+ public void testRemoveUserFromNonexistentGroup() throws Exception
+ {
+ writeAndSetGroupFile();
+
+ try
+ {
+ _groupDatabase.removeUserFromGroup(USER1, MY_GROUP);
+ fail("Expected exception not thrown");
+ }
+ catch(IllegalArgumentException e)
+ {
+ // pass
+ }
+
+ assertTrue(_groupDatabase.getUsersInGroup(MY_GROUP).isEmpty());
+ }
+
+ public void testRemoveUserFromGroupTwice() throws Exception
+ {
+ writeAndSetGroupFile("myGroup.users", USER1);
+ assertTrue(_groupDatabase.getUsersInGroup(MY_GROUP).contains(USER1));
+
+ _groupDatabase.removeUserFromGroup(USER1, MY_GROUP);
+ assertTrue(_groupDatabase.getUsersInGroup(MY_GROUP).isEmpty());
+
+ _groupDatabase.removeUserFromGroup(USER1, MY_GROUP);
+ assertTrue(_groupDatabase.getUsersInGroup(MY_GROUP).isEmpty());
+ }
+
+ public void testAddUserPersistedToFile() throws Exception
+ {
+ writeAndSetGroupFile("myGroup.users", "user1,user2");
+
+ Set<String> users = _groupDatabase.getUsersInGroup(MY_GROUP);
+ assertEquals(2, users.size());
+
+ _groupDatabase.addUserToGroup(USER3, MY_GROUP);
+ assertEquals(3, users.size());
+
+ FileGroupDatabase newGroupDatabase = new FileGroupDatabase();
+ newGroupDatabase.setGroupFile(_groupFile);
+
+ Set<String> newUsers = newGroupDatabase.getUsersInGroup(MY_GROUP);
+ assertEquals(users.size(), newUsers.size());
+ }
+
+ public void testRemoveUserPersistedToFile() throws Exception
+ {
+ writeAndSetGroupFile("myGroup.users", "user1,user2");
+
+ Set<String> users = _groupDatabase.getUsersInGroup(MY_GROUP);
+ assertEquals(2, users.size());
+
+ _groupDatabase.removeUserFromGroup(USER2, MY_GROUP);
+ assertEquals(1, users.size());
+
+ FileGroupDatabase newGroupDatabase = new FileGroupDatabase();
+ newGroupDatabase.setGroupFile(_groupFile);
+
+ Set<String> newUsers = newGroupDatabase.getUsersInGroup(MY_GROUP);
+ assertEquals(users.size(), newUsers.size());
+ }
+
+ public void testCreateGroupPersistedToFile() throws Exception
+ {
+ writeAndSetGroupFile();
+
+ Set<String> groups = _groupDatabase.getAllGroups();
+ assertEquals(0, groups.size());
+
+ _groupDatabase.createGroup(MY_GROUP);
+
+ groups = _groupDatabase.getAllGroups();
+ assertEquals(1, groups.size());
+ assertTrue(groups.contains(MY_GROUP));
+
+ FileGroupDatabase newGroupDatabase = new FileGroupDatabase();
+ newGroupDatabase.setGroupFile(_groupFile);
+
+ Set<String> newGroups = newGroupDatabase.getAllGroups();
+ assertEquals(1, newGroups.size());
+ assertTrue(newGroups.contains(MY_GROUP));
+ }
+
+ public void testRemoveGroupPersistedToFile() throws Exception
+ {
+ writeAndSetGroupFile("myGroup1.users", "user1,user2",
+ "myGroup2.users", "user1,user2");
+
+ Set<String> groups = _groupDatabase.getAllGroups();
+ assertEquals(2, groups.size());
+
+ Set<String> groupsForUser1 = _groupDatabase.getGroupsForUser(USER1);
+ assertEquals(2, groupsForUser1.size());
+
+ _groupDatabase.removeGroup(MY_GROUP1);
+
+ groups = _groupDatabase.getAllGroups();
+ assertEquals(1, groups.size());
+ assertTrue(groups.contains(MY_GROUP2));
+
+ groupsForUser1 = _groupDatabase.getGroupsForUser(USER1);
+ assertEquals(1, groupsForUser1.size());
+
+ FileGroupDatabase newGroupDatabase = new FileGroupDatabase();
+ newGroupDatabase.setGroupFile(_groupFile);
+
+ Set<String> newGroups = newGroupDatabase.getAllGroups();
+ assertEquals(1, newGroups.size());
+ assertTrue(newGroups.contains(MY_GROUP2));
+
+ Set<String> newGroupsForUser1 = newGroupDatabase.getGroupsForUser(USER1);
+ assertEquals(1, newGroupsForUser1.size());
+ assertTrue(newGroupsForUser1.contains(MY_GROUP2));
+}
+
+ @Override
+ protected void setUp() throws Exception
+ {
+ super.setUp();
+ _groupFile = createEmptyTestGroupFile();
+ }
+
+ private void writeAndSetGroupFile(String... groupAndUsers) throws Exception
+ {
+ writeGroupFile(groupAndUsers);
+ _groupDatabase.setGroupFile(_groupFile);
+ }
+
+ private void writeGroupFile(String... groupAndUsers) throws Exception
+ {
+ if (groupAndUsers.length % 2 != 0)
+ {
+ throw new IllegalArgumentException("Number of groupAndUsers must be even");
+ }
+
+ Properties props = new Properties();
+ for (int i = 0 ; i < groupAndUsers.length; i=i+2)
+ {
+ String group = groupAndUsers[i];
+ String users = groupAndUsers[i+1];
+ props.put(group, users);
+ }
+
+ props.store(new FileOutputStream(_groupFile), "test group file");
+ }
+
+ private String createEmptyTestGroupFile() throws IOException
+ {
+ File tmpGroupFile = File.createTempFile("groups", "grp");
+ tmpGroupFile.deleteOnExit();
+
+ return tmpGroupFile.getAbsolutePath();
+ }
+
+ @Override
+ protected void tearDown() throws Exception
+ {
+ super.tearDown();
+
+ if (_groupFile != null)
+ {
+ File groupFile = new File(_groupFile);
+ if (groupFile.exists())
+ {
+ groupFile.delete();
+ }
+ }
+ }
+
+}
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/group/FileGroupManagerTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/group/FileGroupManagerTest.java
new file mode 100644
index 0000000000..165ecb098f
--- /dev/null
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/group/FileGroupManagerTest.java
@@ -0,0 +1,236 @@
+/*
+ * 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.group;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.security.Principal;
+import java.util.Properties;
+import java.util.Set;
+
+import org.apache.commons.configuration.CompositeConfiguration;
+import org.apache.commons.configuration.ConfigurationException;
+import org.apache.commons.configuration.XMLConfiguration;
+import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin;
+import org.apache.qpid.server.security.auth.UsernamePrincipal;
+import org.apache.qpid.server.util.InternalBrokerBaseCase;
+
+public class FileGroupManagerTest extends InternalBrokerBaseCase
+{
+ private static final String MYGROUP_USERS = "user1";
+ private static final String MY_GROUP = "myGroup.users";
+ private static final String MY_GROUP2 = "myGroup2.users";
+ private File _tmpGroupFile;
+ private FileGroupManager _manager;
+
+ @Override
+ public void tearDown() throws Exception
+ {
+ super.tearDown();
+//TODO: implement closable
+// if (_manager != null)
+// {
+// _manager.close();
+// }
+
+ if (_tmpGroupFile != null)
+ {
+ if (_tmpGroupFile.exists())
+ {
+ _tmpGroupFile.delete();
+ }
+ }
+ }
+
+ public void testValidGroupFile() throws Exception
+ {
+ final String groupFileName = writeGroupFile();
+ final ConfigurationPlugin config = getConfig("groupFile", groupFileName);
+
+ _manager = FileGroupManager.FACTORY.newInstance(config);
+ assertNotNull(_manager);
+ }
+
+ public void testNonExistentGroupFile() throws Exception
+ {
+ final String filePath = "/does.not.exist/";
+ final File fileFile = new File(filePath);
+
+ assertFalse("File already exists", fileFile.exists());
+ final ConfigurationPlugin config = getConfig("groupFile", filePath);
+
+ try
+ {
+ _manager = FileGroupManager.FACTORY.newInstance(config);
+ fail("expected exception was not thrown");
+ }
+ catch(ConfigurationException ce)
+ {
+ assertNotNull(ce.getCause());
+ assertTrue(ce.getCause() instanceof FileNotFoundException);
+ }
+ }
+
+ public void testGetGroupPrincipalsForUser() throws Exception
+ {
+ final String groupFileName = writeGroupFile();
+ final ConfigurationPlugin config = getConfig("groupFile", groupFileName);
+ _manager = FileGroupManager.FACTORY.newInstance(config);
+
+ Set<Principal> principals = _manager.getGroupPrincipalsForUser("user1");
+ assertEquals(1, principals.size());
+ assertTrue(principals.contains(new GroupPrincipal("myGroup")));
+ }
+
+ public void testGetUserPrincipalsForGroup() throws Exception
+ {
+ final String groupFileName = writeGroupFile();
+ final ConfigurationPlugin config = getConfig("groupFile", groupFileName);
+ _manager = FileGroupManager.FACTORY.newInstance(config);
+
+ Set<Principal> principals = _manager.getUserPrincipalsForGroup("myGroup");
+ assertEquals(1, principals.size());
+ assertTrue(principals.contains(new UsernamePrincipal("user1")));
+ }
+
+ public void testGetGroupPrincipals() throws Exception
+ {
+ final String groupFileName = writeGroupFile(MY_GROUP, MYGROUP_USERS, MY_GROUP2, MYGROUP_USERS);
+ final ConfigurationPlugin config = getConfig("groupFile", groupFileName);
+ _manager = FileGroupManager.FACTORY.newInstance(config);
+
+ Set<Principal> principals = _manager.getGroupPrincipals();
+ assertEquals(2, principals.size());
+ assertTrue(principals.contains(new GroupPrincipal("myGroup")));
+ assertTrue(principals.contains(new GroupPrincipal("myGroup2")));
+ }
+
+ public void testCreateGroup() throws Exception
+ {
+ final String groupFileName = writeGroupFile();
+ final ConfigurationPlugin config = getConfig("groupFile", groupFileName);
+ _manager = FileGroupManager.FACTORY.newInstance(config);
+
+ Set<Principal> principals = _manager.getGroupPrincipals();
+ assertEquals(1, principals.size());
+
+ _manager.createGroup("myGroup2");
+
+ principals = _manager.getGroupPrincipals();
+ assertEquals(2, principals.size());
+ assertTrue(principals.contains(new GroupPrincipal("myGroup2")));
+ }
+
+ public void testRemoveGroup() throws Exception
+ {
+ final String groupFileName = writeGroupFile(MY_GROUP, MYGROUP_USERS);
+ final ConfigurationPlugin config = getConfig("groupFile", groupFileName);
+ _manager = FileGroupManager.FACTORY.newInstance(config);
+
+ Set<Principal> principals = _manager.getGroupPrincipals();
+ assertEquals(1, principals.size());
+
+ _manager.removeGroup("myGroup");
+
+ principals = _manager.getGroupPrincipals();
+ assertEquals(0, principals.size());
+ }
+
+ public void testAddUserToGroup() throws Exception
+ {
+ final String groupFileName = writeGroupFile(MY_GROUP, MYGROUP_USERS);
+ final ConfigurationPlugin config = getConfig("groupFile", groupFileName);
+ _manager = FileGroupManager.FACTORY.newInstance(config);
+
+ Set<Principal> principals = _manager.getUserPrincipalsForGroup("myGroup");
+ assertEquals(1, principals.size());
+ assertFalse(principals.contains(new UsernamePrincipal("user2")));
+
+ _manager.addUserToGroup("user2", "myGroup");
+
+ principals = _manager.getUserPrincipalsForGroup("myGroup");
+ assertEquals(2, principals.size());
+ assertTrue(principals.contains(new UsernamePrincipal("user2")));
+ }
+
+ public void testRemoveUserInGroup() throws Exception
+ {
+ final String groupFileName = writeGroupFile(MY_GROUP, MYGROUP_USERS);
+ final ConfigurationPlugin config = getConfig("groupFile", groupFileName);
+ _manager = FileGroupManager.FACTORY.newInstance(config);
+
+ Set<Principal> principals = _manager.getUserPrincipalsForGroup("myGroup");
+ assertEquals(1, principals.size());
+ assertTrue(principals.contains(new UsernamePrincipal("user1")));
+
+ _manager.removeUserFromGroup("user1", "myGroup");
+
+ principals = _manager.getUserPrincipalsForGroup("myGroup");
+ assertEquals(0, principals.size());
+ }
+
+ private ConfigurationPlugin getConfig(final String argName, final String argValue) throws Exception
+ {
+ final ConfigurationPlugin config = new FileGroupManager.FileGroupManagerConfiguration();
+
+ XMLConfiguration xmlconfig = new XMLConfiguration();
+
+ if (argName != null)
+ {
+ xmlconfig.addProperty("file-group-manager.attributes.attribute.name", argName);
+ xmlconfig.addProperty("file-group-manager.attributes.attribute.value", argValue);
+ }
+
+ // Create a CompositeConfiguration as this is what the broker uses
+ CompositeConfiguration composite = new CompositeConfiguration();
+ composite.addConfiguration(xmlconfig);
+ config.setConfiguration("security", xmlconfig);
+ return config;
+ }
+
+ private String writeGroupFile() throws Exception
+ {
+ return writeGroupFile(MY_GROUP, MYGROUP_USERS);
+ }
+
+ private String writeGroupFile(String... groupAndUsers) throws Exception
+ {
+ if (groupAndUsers.length % 2 != 0)
+ {
+ throw new IllegalArgumentException("Number of groupAndUsers must be even");
+ }
+
+ _tmpGroupFile = File.createTempFile("groups", "grp");
+ _tmpGroupFile.deleteOnExit();
+
+ Properties props = new Properties();
+ for (int i = 0 ; i < groupAndUsers.length; i=i+2)
+ {
+ String group = groupAndUsers[i];
+ String users = groupAndUsers[i+1];
+ props.put(group, users);
+ }
+
+ props.store(new FileOutputStream(_tmpGroupFile), "test group file");
+
+ return _tmpGroupFile.getCanonicalPath();
+ }
+}
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/group/GroupPrincipalAccessorTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/group/GroupPrincipalAccessorTest.java
new file mode 100644
index 0000000000..6f9b73845d
--- /dev/null
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/group/GroupPrincipalAccessorTest.java
@@ -0,0 +1,81 @@
+/*
+ * 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.group;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.security.Principal;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.server.security.group.GroupManager;
+import org.apache.qpid.server.security.group.GroupPrincipalAccessor;
+
+public class GroupPrincipalAccessorTest extends TestCase
+{
+ private static final String USERNAME = "username";
+
+ private GroupManager _groupManager1 = mock(GroupManager.class);
+ private GroupManager _groupManager2 = mock(GroupManager.class);
+
+ private Principal _group1 = mock(Principal.class);
+ private Principal _group2 = mock(Principal.class);
+
+ @Override
+ public void setUp()
+ {
+ when(_groupManager1.getGroupPrincipalsForUser(USERNAME)).thenReturn(Collections.singleton(_group1));
+ when(_groupManager2.getGroupPrincipalsForUser(USERNAME)).thenReturn(Collections.singleton(_group2));
+ }
+
+ public void testGetGroupPrincipals()
+ {
+ getAndAssertGroupPrincipals(_group1, _group2);
+ }
+
+ public void testGetGroupPrincipalsWhenAGroupManagerReturnsNull()
+ {
+ when(_groupManager1.getGroupPrincipalsForUser(USERNAME)).thenReturn(null);
+
+ getAndAssertGroupPrincipals(_group2);
+ }
+
+ public void testGetGroupPrincipalsWhenAGroupManagerReturnsEmptySet()
+ {
+ when(_groupManager2.getGroupPrincipalsForUser(USERNAME)).thenReturn(new HashSet<Principal>());
+
+ getAndAssertGroupPrincipals(_group1);
+ }
+
+ private void getAndAssertGroupPrincipals(Principal... expectedGroups)
+ {
+ GroupPrincipalAccessor groupPrincipalAccessor = new GroupPrincipalAccessor(Arrays.asList(_groupManager1, _groupManager2));
+
+ Set<Principal> actualGroupPrincipals = groupPrincipalAccessor.getGroupPrincipals(USERNAME);
+
+ Set<Principal> expectedGroupPrincipals = new HashSet<Principal>(Arrays.asList(expectedGroups));
+
+ assertEquals(expectedGroupPrincipals, actualGroupPrincipals);
+ }
+}
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/sasl/GroupPrincipalTest.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/group/GroupPrincipalTest.java
index 076b7c9248..d285a0797a 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/security/auth/sasl/GroupPrincipalTest.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/security/group/GroupPrincipalTest.java
@@ -7,9 +7,9 @@
* 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
@@ -18,7 +18,9 @@
* under the License.
*
*/
-package org.apache.qpid.server.security.auth.sasl;
+package org.apache.qpid.server.security.group;
+
+import org.apache.qpid.server.security.auth.UsernamePrincipal;
import junit.framework.TestCase;
@@ -34,7 +36,7 @@ public class GroupPrincipalTest extends TestCase
{
final GroupPrincipal principal = new GroupPrincipal("group");
final UsernamePrincipal user = new UsernamePrincipal("name");
-
+
try
{
principal.addMember(user);
@@ -45,7 +47,7 @@ public class GroupPrincipalTest extends TestCase
// PASS
}
}
-
+
public void testEqualitySameName()
{
final String string = "string";
@@ -80,7 +82,7 @@ public class GroupPrincipalTest extends TestCase
assertFalse(principal.equals(null));
}
-
+
}
diff --git a/qpid/java/broker/src/test/java/org/apache/qpid/server/util/TestApplicationRegistry.java b/qpid/java/broker/src/test/java/org/apache/qpid/server/util/TestApplicationRegistry.java
index a64ab620ab..411ed81d2a 100644
--- a/qpid/java/broker/src/test/java/org/apache/qpid/server/util/TestApplicationRegistry.java
+++ b/qpid/java/broker/src/test/java/org/apache/qpid/server/util/TestApplicationRegistry.java
@@ -33,10 +33,12 @@ import org.apache.qpid.server.logging.actors.CurrentActor;
import org.apache.qpid.server.logging.actors.GenericActor;
import org.apache.qpid.server.plugins.PluginManager;
import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.server.security.SubjectCreator;
import org.apache.qpid.server.security.auth.database.PropertiesPrincipalDatabase;
import org.apache.qpid.server.security.auth.manager.AuthenticationManager;
import org.apache.qpid.server.security.auth.manager.IAuthenticationManagerRegistry;
import org.apache.qpid.server.security.auth.manager.PrincipalDatabaseAuthenticationManager;
+import org.apache.qpid.server.security.group.GroupPrincipalAccessor;
import java.util.Properties;
@@ -58,7 +60,7 @@ public class TestApplicationRegistry extends ApplicationRegistry
@Override
protected IAuthenticationManagerRegistry createAuthenticationManagerRegistry(
- ServerConfiguration _configuration, PluginManager _pluginManager)
+ ServerConfiguration configuration, PluginManager pluginManager, final GroupPrincipalAccessor groupPrincipalAccessor)
throws ConfigurationException
{
final Properties users = new Properties();
@@ -98,10 +100,9 @@ public class TestApplicationRegistry extends ApplicationRegistry
}
@Override
- public AuthenticationManager getAuthenticationManager(
- SocketAddress address)
+ public SubjectCreator getSubjectCreator(SocketAddress address)
{
- return pdam;
+ return new SubjectCreator(pdam, groupPrincipalAccessor);
}
@Override
diff --git a/qpid/java/systests/etc/config-systests-settings.xml b/qpid/java/systests/etc/config-systests-settings.xml
index 0b65ad83c3..4dfa0a01ee 100644
--- a/qpid/java/systests/etc/config-systests-settings.xml
+++ b/qpid/java/systests/etc/config-systests-settings.xml
@@ -78,12 +78,14 @@
</principal-database>
</pd-auth-manager>
- <!-- By default, all authenticated users have permissions to perform all actions -->
-
- <!-- ACL Example
- This example illustrates securing the both Management (JMX) and Messaging.
- <acl>${conf}/broker_example.acl</acl>
- -->
+ <file-group-manager>
+ <attributes>
+ <attribute>
+ <name>groupFile</name>
+ <value>${conf}/groups-systests</value>
+ </attribute>
+ </attributes>
+ </file-group-manager>
<msg-auth>false</msg-auth>
</security>
diff --git a/qpid/java/systests/etc/groups-systests b/qpid/java/systests/etc/groups-systests
new file mode 100644
index 0000000000..e3912ece99
--- /dev/null
+++ b/qpid/java/systests/etc/groups-systests
@@ -0,0 +1,29 @@
+#
+# 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.
+#
+
+#
+# To define a group, use the format:
+#
+# <groupname>.users=<user1>,<user2>,...,<usern>
+#
+
+messaging-users.users=guest,client,server
+administrators.users=admin
+webadmins.users=webadmin
+
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/AccessControlLoggingTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/AccessControlLoggingTest.java
index 4b7b3f0cf0..37f960a65a 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/AccessControlLoggingTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/logging/AccessControlLoggingTest.java
@@ -31,10 +31,10 @@ import java.util.List;
/**
* ACL version 2/3 file testing to verify that ACL actor logging works correctly.
- *
+ *
* This suite of tests validate that the AccessControl messages occur correctly
* and according to the following format:
- *
+ *
* <pre>
* ACL-1001 : Allowed Operation Object {PROPERTIES}
* ACL-1002 : Denied Operation Object {PROPERTIES}
@@ -83,12 +83,12 @@ public class AccessControlLoggingTest extends AbstractTestLogging
Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
conn.start();
((AMQSession<?, ?>) sess).createQueue(new AMQShortString("allow"), false, false, false);
-
+
List<String> matches = findMatches(ACL_LOG_PREFIX);
-
+
assertTrue("Should be no ACL log messages", matches.isEmpty());
}
-
+
/**
* Test that {@code allow-log} ACL entries log correctly.
*/
@@ -98,25 +98,25 @@ public class AccessControlLoggingTest extends AbstractTestLogging
Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
conn.start();
((AMQSession<?, ?>) sess).createQueue(new AMQShortString("allow-log"), false, false, false);
-
+
List<String> matches = findMatches(ACL_LOG_PREFIX);
-
+
assertEquals("Should only be one ACL log message", 1, matches.size());
-
+
String log = getLogMessage(matches, 0);
String actor = fromActor(log);
String subject = fromSubject(log);
String message = getMessageString(fromMessage(log));
-
+
validateMessageID(ACL_LOG_PREFIX + 1001, log);
-
- assertTrue("Actor should contain the user identity", actor.contains(USER));
+
+ assertTrue("Actor " + actor + " should contain the user identity: " + USER, actor.contains(USER));
assertTrue("Subject should be empty", subject.length() == 0);
assertTrue("Message should start with 'Allowed'", message.startsWith("Allowed"));
assertTrue("Message should contain 'Create Queue'", message.contains("Create Queue"));
assertTrue("Message should have contained the queue name", message.contains("allow-log"));
}
-
+
/**
* Test that {@code deny-log} ACL entries log correctly.
*/
@@ -134,25 +134,25 @@ public class AccessControlLoggingTest extends AbstractTestLogging
// Denied, so exception thrown
assertEquals("Expected ACCESS_REFUSED error code", AMQConstant.ACCESS_REFUSED, amqe.getErrorCode());
}
-
+
List<String> matches = findMatches(ACL_LOG_PREFIX);
-
+
assertEquals("Should only be one ACL log message", 1, matches.size());
-
+
String log = getLogMessage(matches, 0);
String actor = fromActor(log);
String subject = fromSubject(log);
String message = getMessageString(fromMessage(log));
-
+
validateMessageID(ACL_LOG_PREFIX + 1002, log);
-
- assertTrue("Actor should contain the user identity", actor.contains(USER));
+
+ assertTrue("Actor " + actor + " should contain the user identity: " + USER, actor.contains(USER));
assertTrue("Subject should be empty", subject.length() == 0);
assertTrue("Message should start with 'Denied'", message.startsWith("Denied"));
assertTrue("Message should contain 'Create Queue'", message.contains("Create Queue"));
assertTrue("Message should have contained the queue name", message.contains("deny-log"));
}
-
+
/**
* Test that {@code deny} ACL entries do not log anything.
*/
@@ -170,9 +170,9 @@ public class AccessControlLoggingTest extends AbstractTestLogging
// Denied, so exception thrown
assertEquals("Expected ACCESS_REFUSED error code", AMQConstant.ACCESS_REFUSED, amqe.getErrorCode());
}
-
+
List<String> matches = findMatches(ACL_LOG_PREFIX);
-
+
assertTrue("Should be no ACL log messages", matches.isEmpty());
}
}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/AbstractACLTestCase.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/AbstractACLTestCase.java
index 8ccf74a22b..7b50749f5f 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/AbstractACLTestCase.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/AbstractACLTestCase.java
@@ -45,7 +45,7 @@ import java.util.concurrent.TimeUnit;
/**
* Abstract test case for ACLs.
*
- * This base class contains convenience methods to mange ACL files and implements a mechanism that allows each
+ * This base class contains convenience methods to manage ACL files and implements a mechanism that allows each
* test method to run its own setup code before the broker starts.
*
* TODO move the pre broker-startup setup method invocation code to {@link QpidBrokerTestCase}
diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/ExternalACLTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/ExternalACLTest.java
index 0e45ca9493..400464b4eb 100644
--- a/qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/ExternalACLTest.java
+++ b/qpid/java/systests/src/main/java/org/apache/qpid/server/security/acl/ExternalACLTest.java
@@ -319,8 +319,12 @@ public class ExternalACLTest extends AbstractACLTestCase
public void setUpRequestResponseSuccess() throws Exception
{
- writeACLFile("test", "GROUP messaging-users client server",
- "ACL ALLOW-LOG messaging-users ACCESS VIRTUALHOST",
+ // The group "messaging-users", referenced in the ACL below, is currently defined
+ // in broker/etc/groups-systests.
+ // We tolerate a dependency from this test to that file because its
+ // contents are expected to change rarely.
+
+ writeACLFile("test", "ACL ALLOW-LOG messaging-users ACCESS VIRTUALHOST",
"# Server side",
"ACL ALLOW-LOG server CREATE QUEUE name=\"example.RequestQueue\"" ,
"ACL ALLOW-LOG server BIND EXCHANGE",
@@ -389,11 +393,12 @@ public class ExternalACLTest extends AbstractACLTestCase
conn.start();
// create kipper
- Topic kipper = sess.createTopic("kipper");
- TopicSubscriber subscriber = sess.createDurableSubscriber(kipper, "kipper");
+ String topicName = "kipper";
+ Topic topic = sess.createTopic(topicName);
+ TopicSubscriber subscriber = sess.createDurableSubscriber(topic, topicName);
subscriber.close();
- sess.unsubscribe("kipper");
+ sess.unsubscribe(topicName);
//Do something to show connection is active.
sess.rollback();