diff options
Diffstat (limited to 'java/broker-plugins')
126 files changed, 5226 insertions, 8855 deletions
diff --git a/java/broker-plugins/access-control/MANIFEST.MF b/java/broker-plugins/access-control/MANIFEST.MF deleted file mode 100644 index a8fb99995e..0000000000 --- a/java/broker-plugins/access-control/MANIFEST.MF +++ /dev/null @@ -1,41 +0,0 @@ -Manifest-Version: 1.0 -Bundle-ManifestVersion: 2 -Bundle-Name: Qpid Broker-Plugins Access Control -Bundle-SymbolicName: broker-plugins-access-control -Bundle-Description: Access control plugin for Qpid. -Bundle-License: http://www.apache.org/licenses/LICENSE-2.0.txt -Bundle-DocURL: http://qpid.apache.org/acl.html -Bundle-Version: 1.0.0 -Bundle-Activator: org.apache.qpid.server.security.access.plugins.AccessControlActivator -Bundle-RequiredExecutionEnvironment: JavaSE-1.5 -Bundle-ClassPath: . -Bundle-ActivationPolicy: lazy -Import-Package: org.apache.qpid, - org.apache.qpid.exchange, - org.apache.qpid.framing, - org.apache.qpid.protocol, - org.apache.qpid.server.configuration, - org.apache.qpid.server.configuration.plugins, - org.apache.qpid.server.exchange, - org.apache.qpid.server.logging, - org.apache.qpid.server.logging.actors, - org.apache.qpid.server.logging.subjects, - org.apache.qpid.server.plugins, - org.apache.qpid.server.queue, - org.apache.qpid.server.registry, - org.apache.qpid.server.security, - org.apache.qpid.server.security.access, - org.apache.qpid.server.virtualhost, - org.apache.qpid.util, - org.apache.commons.configuration;version=1.0.0, - org.apache.commons.lang;version=1.0.0, - org.apache.commons.lang.builder;version=1.0.0, - org.apache.log4j;version=1.0.0, - javax.management;version=1.0.0, - javax.management.openmbean;version=1.0.0, - javax.security.auth;version=1.0.0, - org.osgi.util.tracker;version=1.0.0, - org.osgi.framework;version=1.3 -Private-Package: org.apache.qpid.server.security.access.config, - org.apache.qpid.server.security.access.logging -Export-Package: org.apache.qpid.server.security.access.plugins diff --git a/java/broker-plugins/access-control/build.xml b/java/broker-plugins/access-control/build.xml index df3346788c..4debdcb95a 100644 --- a/java/broker-plugins/access-control/build.xml +++ b/java/broker-plugins/access-control/build.xml @@ -18,13 +18,13 @@ --> <project name="Qpid Broker-Plugins Access Control" default="build"> <property name="module.depends" value="common broker" /> - <property name="module.test.depends" value="test common/test broker/test management/common systests" /> + <property name="module.test.depends" value="common/tests broker/tests management/common" /> - <property name="module.manifest" value="MANIFEST.MF" /> - <property name="module.plugin" value="true" /> <property name="module.genpom" value="true"/> <property name="module.genpom.args" value="-Sqpid-common=provided -Sqpid-broker=provided"/> + <property name="broker.plugin" value="true"/> + <property name="broker-plugins-access-control.libs" value=""/> <import file="../../module.xml" /> diff --git a/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/AbstractConfiguration.java b/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/AbstractConfiguration.java index f04dd38aca..f87374ac80 100644 --- a/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/AbstractConfiguration.java +++ b/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/AbstractConfiguration.java @@ -22,13 +22,8 @@ package org.apache.qpid.server.security.access.config; import java.io.File; -import org.apache.commons.configuration.ConfigurationException; -import org.apache.log4j.Logger; - public abstract class AbstractConfiguration implements ConfigurationFile { - private static final Logger _logger = Logger.getLogger(ConfigurationFile.class); - private File _file; private RuleSet _config; @@ -42,7 +37,7 @@ public abstract class AbstractConfiguration implements ConfigurationFile return _file; } - public RuleSet load() throws ConfigurationException + public RuleSet load() { _config = new RuleSet(); return _config; diff --git a/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/AclAction.java b/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/AclAction.java new file mode 100644 index 0000000000..e4bf21a082 --- /dev/null +++ b/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/AclAction.java @@ -0,0 +1,102 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.security.access.config; + +import org.apache.commons.lang.builder.EqualsBuilder; +import org.apache.commons.lang.builder.HashCodeBuilder; +import org.apache.commons.lang.builder.ToStringBuilder; +import org.apache.commons.lang.builder.ToStringStyle; +import org.apache.qpid.server.security.access.ObjectProperties; +import org.apache.qpid.server.security.access.ObjectType; +import org.apache.qpid.server.security.access.Operation; +import org.apache.qpid.server.security.access.firewall.FirewallRule; + +public class AclAction +{ + private Action _action; + private FirewallRule _firewallRule; + + public AclAction(Operation operation, ObjectType object, AclRulePredicates predicates) + { + _action = new Action(operation, object, predicates.getObjectProperties()); + _firewallRule = predicates.getFirewallRule(); + } + + public AclAction(Operation operation) + { + _action = new Action(operation); + } + + public AclAction(Operation operation, ObjectType object, ObjectProperties properties) + { + _action = new Action(operation, object, properties); + } + + public FirewallRule getFirewallRule() + { + return _firewallRule; + } + + public Action getAction() + { + return _action; + } + + public boolean isAllowed() + { + return _action.isAllowed(); + } + + @Override + public int hashCode() + { + return new HashCodeBuilder() + .append(_action) + .append(_firewallRule).toHashCode(); + } + + @Override + public boolean equals(Object obj) + { + if (obj == null) + { + return false; + } + if (obj == this) + { + return true; + } + if (obj.getClass() != getClass()) + { + return false; + } + AclAction rhs = (AclAction) obj; + return new EqualsBuilder() + .append(_action, rhs._action) + .append(_firewallRule, rhs._firewallRule).isEquals(); + } + + @Override + public String toString() + { + return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) + .append(_action) + .append(_firewallRule).toString(); + } +} diff --git a/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/AclRulePredicates.java b/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/AclRulePredicates.java new file mode 100644 index 0000000000..45af85be6c --- /dev/null +++ b/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/AclRulePredicates.java @@ -0,0 +1,102 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.security.access.config; + +import org.apache.commons.lang.builder.ToStringBuilder; +import org.apache.commons.lang.builder.ToStringStyle; +import org.apache.log4j.Logger; +import org.apache.qpid.server.security.access.ObjectProperties; +import org.apache.qpid.server.security.access.ObjectProperties.Property; +import org.apache.qpid.server.security.access.firewall.FirewallRule; +import org.apache.qpid.server.security.access.firewall.FirewallRuleFactory; + +/** + * Represents the predicates on an ACL rule by combining predicates relating to the object being operated on + * (e.g. name=foo) with firewall rules. + */ +public class AclRulePredicates +{ + private static final Logger _logger = Logger.getLogger(AclRulePredicates.class); + + private static final String SEPARATOR = ","; + + private ObjectProperties _properties = new ObjectProperties(); + + private FirewallRule _firewallRule; + + private FirewallRuleFactory _firewallRuleFactory = new FirewallRuleFactory(); + + public void parse(String key, String value) + { + ObjectProperties.Property property = ObjectProperties.Property.parse(key); + + if(property == Property.FROM_HOSTNAME) + { + checkFirewallRuleNotAlreadyDefined(key, value); + _firewallRule = _firewallRuleFactory.createForHostname(value.split(SEPARATOR)); + } + else if(property == Property.FROM_NETWORK) + { + checkFirewallRuleNotAlreadyDefined(key, value); + _firewallRule = _firewallRuleFactory.createForNetwork(value.split(SEPARATOR)); + } + else + { + _properties.put(property, value); + } + + if (_logger.isDebugEnabled()) + { + _logger.debug("Parsed " + property + " with value " + value); + } + } + + private void checkFirewallRuleNotAlreadyDefined(String key, String value) + { + if(_firewallRule != null) + { + throw new IllegalStateException( + "Cannot parse " + key + "=" + value + + " because firewall rule " + _firewallRule + " has already been defined"); + } + } + + @Override + public String toString() + { + return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) + .append(_properties) + .append(_firewallRule).toString(); + } + + public FirewallRule getFirewallRule() + { + return _firewallRule; + } + + public ObjectProperties getObjectProperties() + { + return _properties; + } + + void setFirewallRuleFactory(FirewallRuleFactory firewallRuleFactory) + { + _firewallRuleFactory = firewallRuleFactory; + } +} diff --git a/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/Action.java b/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/Action.java index b887d1e079..4fff0bebf5 100644 --- a/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/Action.java +++ b/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/Action.java @@ -20,8 +20,6 @@ */ package org.apache.qpid.server.security.access.config; -import java.util.Comparator; - import org.apache.commons.lang.builder.EqualsBuilder; import org.apache.commons.lang.builder.HashCodeBuilder; import org.apache.commons.lang.builder.ToStringBuilder; @@ -32,7 +30,7 @@ import org.apache.qpid.server.security.access.Operation; /** * An access control v2 rule action. - * + * * An action consists of an {@link Operation} on an {@link ObjectType} with certain properties, stored in a {@link java.util.Map}. * The operation and object should be an allowable combination, based on the {@link ObjectType#isAllowed(Operation)} * method of the object, which is exposed as the {@link #isAllowed()} method here. The internal {@link #propertiesMatch(Map)} @@ -45,104 +43,96 @@ import org.apache.qpid.server.security.access.Operation; */ public class Action { - private Operation _operation; - private ObjectType _object; - private ObjectProperties _properties; - + private final Operation _operation; + private final ObjectType _object; + private final ObjectProperties _properties; + public Action(Operation operation) { this(operation, ObjectType.ALL); } - + public Action(Operation operation, ObjectType object, String name) { this(operation, object, new ObjectProperties(name)); } - + public Action(Operation operation, ObjectType object) { this(operation, object, ObjectProperties.EMPTY); } - + public Action(Operation operation, ObjectType object, ObjectProperties properties) { - setOperation(operation); - setObjectType(object); - setProperties(properties); + _operation = operation; + _object = object; + _properties = properties; } - + public Operation getOperation() { return _operation; } - public void setOperation(Operation operation) - { - _operation = operation; - } - public ObjectType getObjectType() { return _object; } - public void setObjectType(ObjectType object) - { - _object = object; - } - public ObjectProperties getProperties() { return _properties; } - - public void setProperties(ObjectProperties properties) - { - _properties = properties; - } - + public boolean isAllowed() { return _object.isAllowed(_operation); } - /** @see Comparable#compareTo(Object) */ public boolean matches(Action a) { - return ((Operation.ALL == a.getOperation() || getOperation() == a.getOperation()) - && (ObjectType.ALL == a.getObjectType() || getObjectType() == a.getObjectType()) - && _properties.matches(a.getProperties())); + if (!operationsMatch(a)) + { + return false; + } + + if (!objectTypesMatch(a)) + { + return false; + } + + if (!propertiesMatch(a)) + { + return false; + } + + return true; + } + + private boolean operationsMatch(Action a) + { + return Operation.ALL == a.getOperation() || getOperation() == a.getOperation(); } - /** - * An ordering based on specificity - * - * @see Comparator#compare(Object, Object) - */ - public class Specificity implements Comparator<Action> + private boolean objectTypesMatch(Action a) { - public int compare(Action a, Action b) + return ObjectType.ALL == a.getObjectType() || getObjectType() == a.getObjectType(); + } + + private boolean propertiesMatch(Action a) + { + boolean propertiesMatch = false; + if (_properties != null) + { + propertiesMatch = _properties.matches(a.getProperties()); + } + else if (a.getProperties() == null) { - if (a.getOperation() == Operation.ALL && b.getOperation() != Operation.ALL) - { - return 1; // B is more specific - } - else if (b.getOperation() == Operation.ALL && a.getOperation() != Operation.ALL) - { - return 1; // A is more specific - } - else if (a.getOperation() == b.getOperation()) - { - return 1; // b is more specific - } - else // Different operations - { - return a.getOperation().compareTo(b.getOperation()); // Arbitrary - } + propertiesMatch = true; } + return propertiesMatch; } - /** @see Object#equals(Object) */ @Override public boolean equals(Object o) { @@ -151,26 +141,24 @@ public class Action return false; } Action a = (Action) o; - + return new EqualsBuilder() .append(_operation, a.getOperation()) .append(_object, a.getObjectType()) - .appendSuper(_properties.equals(a.getProperties())) + .append(_properties, a.getProperties()) .isEquals(); } - /** @see Object#hashCode() */ @Override public int hashCode() { return new HashCodeBuilder() .append(_operation) - .append(_operation) + .append(_object) .append(_properties) .toHashCode(); } - /** @see Object#toString() */ @Override public String toString() { diff --git a/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/ClientAction.java b/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/ClientAction.java new file mode 100644 index 0000000000..fed20a56c8 --- /dev/null +++ b/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/ClientAction.java @@ -0,0 +1,88 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.security.access.config; + +import java.net.InetAddress; + +import org.apache.commons.lang.builder.ToStringBuilder; +import org.apache.commons.lang.builder.ToStringStyle; +import org.apache.qpid.server.security.access.ObjectProperties; +import org.apache.qpid.server.security.access.ObjectType; +import org.apache.qpid.server.security.access.Operation; +import org.apache.qpid.server.security.access.firewall.FirewallRule; + +/** + * I represent an {@link Action} taken by a client from a known address. The address is used to + * determine if I match an {@link AclAction}, which may contain firewall rules. + */ +public class ClientAction +{ + private Action _clientAction; + + public ClientAction(Action clientAction) + { + _clientAction = clientAction; + } + + public ClientAction(Operation operation, ObjectType objectType, ObjectProperties properties) + { + _clientAction = new Action(operation, objectType, properties); + } + + public boolean matches(AclAction ruleAction, InetAddress addressOfClient) + { + return _clientAction.matches(ruleAction.getAction()) + && addressOfClientMatches(ruleAction, addressOfClient); + } + + private boolean addressOfClientMatches(AclAction ruleAction, InetAddress addressOfClient) + { + FirewallRule firewallRule = ruleAction.getFirewallRule(); + if(firewallRule == null || addressOfClient == null) + { + return true; + } + else + { + return firewallRule.matches(addressOfClient); + } + } + + public Operation getOperation() + { + return _clientAction.getOperation(); + } + + public ObjectType getObjectType() + { + return _clientAction.getObjectType(); + } + + public ObjectProperties getProperties() + { + return _clientAction.getProperties(); + } + + @Override + public String toString() + { + return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) + .append(_clientAction).toString(); + } +} diff --git a/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/ConfigurationFile.java b/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/ConfigurationFile.java index 8b1a00259b..966c32e24e 100644 --- a/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/ConfigurationFile.java +++ b/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/ConfigurationFile.java @@ -22,7 +22,7 @@ package org.apache.qpid.server.security.access.config; import java.io.File; -import org.apache.commons.configuration.ConfigurationException; +import org.apache.qpid.server.configuration.IllegalConfigurationException; public interface ConfigurationFile { @@ -33,19 +33,17 @@ public interface ConfigurationFile /** * Load this configuration file's contents into a {@link RuleSet}. - * - * @throws ConfigurationException if the configuration file has errors. + * @throws IllegalConfigurationException if the configuration file has errors. * @throws IllegalArgumentException if individual tokens cannot be parsed. */ - RuleSet load() throws ConfigurationException; + RuleSet load() throws IllegalConfigurationException; /** * Reload this configuration file's contents. - * - * @throws ConfigurationException if the configuration file has errors. + * @throws IllegalConfigurationException if the configuration file has errors. * @throws IllegalArgumentException if individual tokens cannot be parsed. */ - RuleSet reload() throws ConfigurationException; + RuleSet reload() throws IllegalConfigurationException; RuleSet getConfiguration(); diff --git a/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/PlainConfiguration.java b/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/PlainConfiguration.java index 9a08eb6499..ab309c54ce 100644 --- a/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/PlainConfiguration.java +++ b/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; @@ -32,55 +32,65 @@ import java.util.List; import java.util.Map; import java.util.Stack; -import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.lang.StringUtils; -import org.apache.qpid.server.security.access.ObjectProperties; +import org.apache.log4j.Logger; +import org.apache.qpid.server.configuration.IllegalConfigurationException; import org.apache.qpid.server.security.access.ObjectType; import org.apache.qpid.server.security.access.Operation; import org.apache.qpid.server.security.access.Permission; public class PlainConfiguration extends AbstractConfiguration { + private static final Logger _logger = Logger.getLogger(PlainConfiguration.class); + 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 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"; - + static final String UNRECOGNISED_INITIAL_MSG = "Unrecognised initial token '%s' at line %d"; + static final String NOT_ENOUGH_TOKENS_MSG = "Not enough tokens at line %d"; + static final String NUMBER_NOT_ALLOWED_MSG = "Number not allowed before '%s' at line %d"; + static final String CANNOT_LOAD_MSG = "Cannot load config file %s"; + static final String CANNOT_CLOSE_MSG = "Cannot close config file %s"; + static final String PREMATURE_CONTINUATION_MSG = "Premature continuation character at line %d"; + static final String PREMATURE_EOF_MSG = "Premature end of file reached at line %d"; + static final String PARSE_TOKEN_FAILED_MSG = "Failed to parse token at line %d"; + static final String CONFIG_NOT_FOUND_MSG = "Cannot find config file %s"; + static final String NOT_ENOUGH_ACL_MSG = "Not enough data for an acl at line %d"; + static final String NOT_ENOUGH_CONFIG_MSG = "Not enough data for config at line %d"; + static final String BAD_ACL_RULE_NUMBER_MSG = "Invalid rule number at line %d"; + static final String PROPERTY_KEY_ONLY_MSG = "Incomplete property (key only) at line %d"; + static final String PROPERTY_NO_EQUALS_MSG = "Incomplete property (no equals) at line %d"; + 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 + public RuleSet load() { RuleSet ruleSet = super.load(); - + + File file = getFile(); + FileReader fileReader = null; + try { - _st = new StreamTokenizer(new BufferedReader(new FileReader(getFile()))); + if(_logger.isDebugEnabled()) + { + _logger.debug("About to load ACL file " + file); + } + + fileReader = new FileReader(file); + _st = new StreamTokenizer(new BufferedReader(fileReader)); _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 +107,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,21 +121,21 @@ 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); if (stack.isEmpty()) { - throw new ConfigurationException(String.format(NOT_ENOUGH_TOKENS_MSG, getLine())); + throw new IllegalConfigurationException(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 +146,9 @@ public class PlainConfiguration extends AbstractConfiguration } else if (number == null) { - if (StringUtils.equalsIgnoreCase(GROUP, first)) + if(StringUtils.equalsIgnoreCase("GROUP", first)) { - parseGroup(stack); + throw new IllegalConfigurationException(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)) { @@ -146,14 +156,14 @@ public class PlainConfiguration extends AbstractConfiguration } else { - throw new ConfigurationException(String.format(UNRECOGNISED_INITIAL_MSG, first, getLine())); + throw new IllegalConfigurationException(String.format(UNRECOGNISED_INITIAL_MSG, first, getLine())); } } else { - throw new ConfigurationException(String.format(NUMBER_NOT_ALLOWED_MSG, first, getLine())); + throw new IllegalConfigurationException(String.format(NUMBER_NOT_ALLOWED_MSG, first, getLine())); } - + // reset stack, start next line stack.clear(); break; @@ -171,9 +181,9 @@ 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)); + throw new IllegalConfigurationException(String.format(PREMATURE_CONTINUATION_MSG, getLine() + 1)); } else if (_st.ttype == '\'' || _st.ttype == '"') { @@ -185,54 +195,59 @@ public class PlainConfiguration extends AbstractConfiguration } } } while (current != StreamTokenizer.TT_EOF); - + if (!stack.isEmpty()) { - throw new ConfigurationException(String.format(PREMATURE_EOF_MSG, getLine())); + throw new IllegalConfigurationException(String.format(PREMATURE_EOF_MSG, getLine())); } } catch (IllegalArgumentException iae) { - throw new ConfigurationException(String.format(PARSE_TOKEN_FAILED_MSG, getLine()), iae); + throw new IllegalConfigurationException(String.format(PARSE_TOKEN_FAILED_MSG, getLine()), iae); } catch (FileNotFoundException fnfe) { - throw new ConfigurationException(String.format(CONFIG_NOT_FOUND_MSG, getFile().getName()), fnfe); + throw new IllegalConfigurationException(String.format(CONFIG_NOT_FOUND_MSG, file.getName()), fnfe); } catch (IOException ioe) { - throw new ConfigurationException(String.format(CANNOT_LOAD_MSG, getFile().getName()), ioe); + throw new IllegalConfigurationException(String.format(CANNOT_LOAD_MSG, file.getName()), ioe); } - - return ruleSet; - } - - private void parseGroup(List<String> args) throws ConfigurationException - { - if (args.size() < 2) + finally { - throw new ConfigurationException(String.format(NOT_ENOUGH_GROUP_MSG, getLine())); + if(fileReader != null) + { + try + { + fileReader.close(); + } + catch (IOException e) + { + throw new IllegalConfigurationException(String.format(CANNOT_CLOSE_MSG, file.getName()), e); + } + } } - - getConfiguration().addGroup(args.get(0), args.subList(1, args.size())); + + + return ruleSet; } - - private void parseAcl(Integer number, List<String> args) throws ConfigurationException + + private void parseAcl(Integer number, List<String> args) { if (args.size() < 3) { - throw new ConfigurationException(String.format(NOT_ENOUGH_ACL_MSG, getLine())); + throw new IllegalConfigurationException(String.format(NOT_ENOUGH_ACL_MSG, getLine())); } 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())); + throw new IllegalConfigurationException(String.format(BAD_ACL_RULE_NUMBER_MSG, getLine())); } - + if (args.size() == 3) { getConfiguration().grant(number, identity, permission, operation); @@ -240,55 +255,52 @@ public class PlainConfiguration extends AbstractConfiguration else { ObjectType object = ObjectType.parse(args.get(3)); - ObjectProperties properties = toObjectProperties(args.subList(4, args.size())); + AclRulePredicates predicates = toRulePredicates(args.subList(4, args.size())); - getConfiguration().grant(number, identity, permission, operation, object, properties); + getConfiguration().grant(number, identity, permission, operation, object, predicates); } } - - private void parseConfig(List<String> args) throws ConfigurationException + + private void parseConfig(List<String> args) { if (args.size() < 3) { - throw new ConfigurationException(String.format(NOT_ENOUGH_CONFIG_MSG, getLine())); + throw new IllegalConfigurationException(String.format(NOT_ENOUGH_CONFIG_MSG, getLine())); } 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 + + private AclRulePredicates toRulePredicates(List<String> args) { - ObjectProperties properties = new ObjectProperties(); + AclRulePredicates predicates = new AclRulePredicates(); Iterator<String> i = args.iterator(); while (i.hasNext()) { String key = i.next(); if (!i.hasNext()) { - throw new ConfigurationException(String.format(PROPERTY_KEY_ONLY_MSG, getLine())); + throw new IllegalConfigurationException(String.format(PROPERTY_KEY_ONLY_MSG, getLine())); } if (!"=".equals(i.next())) { - throw new ConfigurationException(String.format(PROPERTY_NO_EQUALS_MSG, getLine())); + throw new IllegalConfigurationException(String.format(PROPERTY_NO_EQUALS_MSG, getLine())); } if (!i.hasNext()) { - throw new ConfigurationException(String.format(PROPERTY_NO_VALUE_MSG, getLine())); + throw new IllegalConfigurationException(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); + + predicates.parse(key, value); } - return properties; + return predicates; } - + /** Converts a {@link List} of "name", "=", "value" tokens into a {@link Map}. */ - protected Map<String, Boolean> toPluginProperties(List<String> args) throws ConfigurationException + protected Map<String, Boolean> toPluginProperties(List<String> args) { Map<String, Boolean> properties = new HashMap<String, Boolean>(); Iterator<String> i = args.iterator(); @@ -297,24 +309,24 @@ public class PlainConfiguration extends AbstractConfiguration String key = i.next().toLowerCase(); if (!i.hasNext()) { - throw new ConfigurationException(String.format(PROPERTY_KEY_ONLY_MSG, getLine())); + throw new IllegalConfigurationException(String.format(PROPERTY_KEY_ONLY_MSG, getLine())); } if (!"=".equals(i.next())) { - throw new ConfigurationException(String.format(PROPERTY_NO_EQUALS_MSG, getLine())); + throw new IllegalConfigurationException(String.format(PROPERTY_NO_EQUALS_MSG, getLine())); } if (!i.hasNext()) { - throw new ConfigurationException(String.format(PROPERTY_NO_VALUE_MSG, getLine())); + throw new IllegalConfigurationException(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/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/Rule.java b/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/Rule.java index 15d6b67192..cef9a8696b 100644 --- a/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/Rule.java +++ b/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,41 +37,41 @@ 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 AclAction _action; private Permission _permission; - - public Rule(Integer number, String identity, Action action, Permission permission) + + public Rule(Integer number, String identity, AclAction action, Permission permission) { setNumber(number); setIdentity(identity); setAction(action); setPermission(permission); } - - public Rule(String identity, Action action, Permission permission) + + public Rule(String identity, AclAction 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,13 +96,18 @@ public class Rule implements Comparable<Rule> { _identity = identity; } - + public Action getAction() { + return _action.getAction(); + } + + public AclAction getAclAction() + { return _action; } - public void setAction(Action action) + public void setAction(AclAction action) { _action = action; } @@ -117,7 +122,7 @@ public class Rule implements Comparable<Rule> _permission = permission; } - /** @see Comparable#compareTo(Object) */ + @Override public int compareTo(Rule r) { return new CompareToBuilder() @@ -127,7 +132,6 @@ public class Rule implements Comparable<Rule> .toComparison(); } - /** @see Object#equals(Object) */ @Override public boolean equals(Object o) { @@ -136,33 +140,31 @@ public class Rule implements Comparable<Rule> return false; } Rule r = (Rule) o; - + return new EqualsBuilder() .append(getIdentity(), r.getIdentity()) - .append(getAction(), r.getAction()) + .append(getAclAction(), r.getAclAction()) .append(getPermission(), r.getPermission()) .isEquals(); } - /** @see Object#hashCode() */ @Override public int hashCode() { return new HashCodeBuilder() .append(getIdentity()) - .append(getAction()) + .append(getAclAction()) .append(getPermission()) .toHashCode(); } - /** @see Object#toString() */ @Override public String toString() { return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) .append("#", getNumber()) .append("identity", getIdentity()) - .append("action", getAction()) + .append("action", getAclAction()) .append("permission", getPermission()) .append("enabled", isEnabled()) .toString(); diff --git a/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/RuleSet.java b/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/RuleSet.java index 815df99f80..e61370fced 100644 --- a/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/RuleSet.java +++ b/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/config/RuleSet.java @@ -18,8 +18,8 @@ */ package org.apache.qpid.server.security.access.config; +import java.net.InetAddress; import java.security.Principal; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.EnumMap; @@ -54,7 +54,7 @@ import org.apache.qpid.server.security.access.logging.AccessControlMessages; */ public class RuleSet { - public static final Logger _logger = Logger.getLogger(RuleSet.class); + private static final Logger _logger = Logger.getLogger(RuleSet.class); private static final String AT = "@"; private static final String SLASH = "/"; @@ -66,7 +66,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 +78,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() @@ -157,21 +155,27 @@ public class RuleSet public void grant(Integer number, String identity, Permission permission, Operation operation) { - Action action = new Action(operation); + AclAction action = new AclAction(operation); addRule(number, identity, permission, action); } public void grant(Integer number, String identity, Permission permission, Operation operation, ObjectType object, ObjectProperties properties) { - Action action = new Action(operation, object, properties); + AclAction action = new AclAction(operation, object, properties); addRule(number, identity, permission, action); } - public boolean ruleExists(String identity, Action action) + public void grant(Integer number, String identity, Permission permission, Operation operation, ObjectType object, AclRulePredicates predicates) + { + AclAction aclAction = new AclAction(operation, object, predicates); + addRule(number, identity, permission, aclAction); + } + + public boolean ruleExists(String identity, AclAction action) { for (Rule rule : _rules.values()) { - if (rule.getIdentity().equals(identity) && rule.getAction().equals(action)) + if (rule.getIdentity().equals(identity) && rule.getAclAction().equals(action)) { return true; } @@ -179,8 +183,7 @@ public class RuleSet return false; } - // TODO make this work when group membership is not known at file parse time - public void addRule(Integer number, String identity, Permission permission, Action action) + public void addRule(Integer number, String identity, Permission permission, AclAction action) { _cache.clear(); @@ -222,53 +225,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,11 +268,15 @@ 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? + /** + * Checks for the case when the client's address is not known. + * + * @see #check(Subject, Operation, ObjectType, ObjectProperties, InetAddress) + */ + public Result check(Subject subject, Operation operation, ObjectType objectType, ObjectProperties properties) + { + return check(subject, operation, objectType, properties, null); + } /** * Check the authorisation granted to a particular identity for an operation on an object type with @@ -327,10 +287,9 @@ public class RuleSet * the first match found, or denies access if there are no matching rules. Normally, it would be expected * to have a default deny or allow rule at the end of an access configuration however. */ - public Result check(Subject subject, Operation operation, ObjectType objectType, ObjectProperties properties) + public Result check(Subject subject, Operation operation, ObjectType objectType, ObjectProperties properties, InetAddress addressOfClient) { - // Create the action to check - Action action = new Action(operation, objectType, properties); + ClientAction action = new ClientAction(operation, objectType, properties); if(_logger.isDebugEnabled()) { @@ -349,27 +308,31 @@ public class RuleSet } // Iterate through a filtered set of rules dealing with this identity and operation - for (Rule current : rules) + for (Rule rule : rules) { if(_logger.isDebugEnabled()) { - _logger.debug("Checking against rule: " + current); + _logger.debug("Checking against rule: " + rule); } - // Check if action matches - if (action.matches(current.getAction())) + + if (action.matches(rule.getAclAction(), addressOfClient)) { - Permission permission = current.getPermission(); + Permission permission = rule.getPermission(); switch (permission) { case ALLOW_LOG: CurrentActor.get().message(AccessControlMessages.ALLOWED( - action.getOperation().toString(), action.getObjectType().toString(), action.getProperties().toString())); + action.getOperation().toString(), + action.getObjectType().toString(), + action.getProperties().toString())); case ALLOW: return Result.ALLOWED; case DENY_LOG: CurrentActor.get().message(AccessControlMessages.DENIED( - action.getOperation().toString(), action.getObjectType().toString(), action.getProperties().toString())); + action.getOperation().toString(), + action.getObjectType().toString(), + action.getProperties().toString())); case DENY: return Result.DENIED; } @@ -446,8 +409,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; } @@ -476,5 +438,4 @@ public class RuleSet } return objects; } - } diff --git a/java/broker-plugins/firewall/src/main/java/org/apache/qpid/server/security/access/config/FirewallException.java b/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/firewall/AccessControlFirewallException.java index a9e3fdc242..d08a052efd 100644 --- a/java/broker-plugins/firewall/src/main/java/org/apache/qpid/server/security/access/config/FirewallException.java +++ b/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/firewall/AccessControlFirewallException.java @@ -18,29 +18,30 @@ * under the License. * */ -package org.apache.qpid.server.security.access.config; +package org.apache.qpid.server.security.access.firewall; -/** - * Firewall plugin exception. - */ -public class FirewallException extends Exception +public class AccessControlFirewallException extends RuntimeException { /** serialVersionUID */ private static final long serialVersionUID = 4526157149690917805L; - - public FirewallException() { - super(); + + public AccessControlFirewallException() + { + super(); } - public FirewallException(String message) { - super(message); + public AccessControlFirewallException(String message) + { + super(message); } - public FirewallException(String message, Throwable cause) { + public AccessControlFirewallException(String message, Throwable cause) + { super(message, cause); } - public FirewallException(Throwable cause) { + public AccessControlFirewallException(Throwable cause) + { super(cause); } }
\ No newline at end of file diff --git a/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/AccessControlActivator.java b/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/firewall/FirewallRule.java index 7c83446cf1..482a795693 100644 --- a/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/AccessControlActivator.java +++ b/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/firewall/FirewallRule.java @@ -1,5 +1,4 @@ /* - * * 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,35 +6,21 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. - * */ -package org.apache.qpid.server.security.access.plugins; +package org.apache.qpid.server.security.access.firewall; -import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory; -import org.apache.qpid.server.security.SecurityPluginActivator; -import org.apache.qpid.server.security.SecurityPluginFactory; +import java.net.InetAddress; -/** - * The OSGi {@link org.osgi.framework.BundleActivator} for {@link AccessControl}. - */ -public class AccessControlActivator extends SecurityPluginActivator +public interface FirewallRule { - public SecurityPluginFactory getFactory() - { - return AccessControl.FACTORY; - } - - public ConfigurationPluginFactory getConfigurationFactory() - { - return AccessControlConfiguration.FACTORY; - } + boolean matches(InetAddress addressOfClient); } diff --git a/java/broker-plugins/firewall/src/main/java/org/apache/qpid/server/security/access/plugins/FirewallActivator.java b/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/firewall/FirewallRuleFactory.java index 1669352085..64be26c209 100644 --- a/java/broker-plugins/firewall/src/main/java/org/apache/qpid/server/security/access/plugins/FirewallActivator.java +++ b/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/firewall/FirewallRuleFactory.java @@ -1,5 +1,4 @@ /* - * * 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,35 +6,28 @@ * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. - * */ -package org.apache.qpid.server.security.access.plugins; +package org.apache.qpid.server.security.access.firewall; -import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory; -import org.apache.qpid.server.security.SecurityPluginActivator; -import org.apache.qpid.server.security.SecurityPluginFactory; - -/** - * The OSGi {@link org.osgi.framework.BundleActivator} for {@link Firewall}. - */ -public class FirewallActivator extends SecurityPluginActivator +public class FirewallRuleFactory { - public SecurityPluginFactory getFactory() + public FirewallRule createForHostname(String[] hostnames) { - return Firewall.FACTORY; + return new HostnameFirewallRule(hostnames); } - public ConfigurationPluginFactory getConfigurationFactory() + public FirewallRule createForNetwork(String[] networks) { - return FirewallConfiguration.FACTORY; + return new NetworkFirewallRule(networks); } + } diff --git a/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/firewall/HostnameFirewallRule.java b/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/firewall/HostnameFirewallRule.java new file mode 100644 index 0000000000..fb13426fbb --- /dev/null +++ b/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/firewall/HostnameFirewallRule.java @@ -0,0 +1,156 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.security.access.firewall; + +import java.net.InetAddress; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.FutureTask; +import java.util.concurrent.TimeUnit; +import java.util.regex.Pattern; + +import org.apache.commons.lang.builder.EqualsBuilder; +import org.apache.commons.lang.builder.HashCodeBuilder; +import org.apache.commons.lang.builder.ToStringBuilder; +import org.apache.commons.lang.builder.ToStringStyle; +import org.apache.log4j.Logger; + +public class HostnameFirewallRule implements FirewallRule +{ + private static final Logger _logger = Logger.getLogger(HostnameFirewallRule.class); + + private static final long DNS_TIMEOUT = 30000; + private static final ExecutorService DNS_LOOKUP = Executors.newCachedThreadPool(); + + private Pattern[] _hostnamePatterns; + private String[] _hostnames; + + public HostnameFirewallRule(String... hostnames) + { + _hostnames = hostnames; + + int i = 0; + _hostnamePatterns = new Pattern[hostnames.length]; + for (String hostname : hostnames) + { + _hostnamePatterns[i++] = Pattern.compile(hostname); + } + + if(_logger.isDebugEnabled()) + { + _logger.debug("Created " + this); + } + } + + @Override + public boolean matches(InetAddress remote) + { + String hostname = getHostname(remote); + if (hostname == null) + { + throw new AccessControlFirewallException("DNS lookup failed for address " + remote); + } + for (Pattern pattern : _hostnamePatterns) + { + boolean hostnameMatches = pattern.matcher(hostname).matches(); + + if (hostnameMatches) + { + if(_logger.isDebugEnabled()) + { + _logger.debug("Hostname " + hostname + " matches rule " + pattern.toString()); + } + return true; + } + } + + if(_logger.isDebugEnabled()) + { + _logger.debug("Hostname " + hostname + " matches no configured hostname patterns"); + } + + return false; + } + + + /** + * @param remote + * the InetAddress to look up + * @return the hostname, null if not found, takes longer than + * {@value #DNS_LOOKUP} to find or otherwise fails + */ + private String getHostname(final InetAddress remote) throws AccessControlFirewallException + { + FutureTask<String> lookup = new FutureTask<String>(new Callable<String>() + { + public String call() + { + return remote.getCanonicalHostName(); + } + }); + DNS_LOOKUP.execute(lookup); + + try + { + return lookup.get(DNS_TIMEOUT, TimeUnit.MILLISECONDS); + } + catch (Exception e) + { + _logger.warn("Unable to look up hostname from address " + remote, e); + return null; + } + finally + { + lookup.cancel(true); + } + } + + @Override + public int hashCode() + { + return new HashCodeBuilder().append(_hostnames).toHashCode(); + } + + @Override + public boolean equals(Object obj) + { + if (obj == null) + { + return false; + } + if (obj == this) + { + return true; + } + if (obj.getClass() != getClass()) + { + return false; + } + HostnameFirewallRule rhs = (HostnameFirewallRule) obj; + return new EqualsBuilder().append(_hostnames, rhs._hostnames).isEquals(); + } + + @Override + public String toString() + { + return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) + .append(_hostnames).toString(); + } +} diff --git a/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/firewall/InetNetwork.java b/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/firewall/InetNetwork.java new file mode 100644 index 0000000000..2e979b38f1 --- /dev/null +++ b/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/firewall/InetNetwork.java @@ -0,0 +1,177 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.security.access.firewall; + +import java.net.InetAddress; + +class InetNetwork +{ + /* + * Implements network masking, and is compatible with RFC 1518 and + * RFC 1519, which describe CIDR: Classless Inter-Domain Routing. + */ + + private InetAddress network; + private InetAddress netmask; + + public InetNetwork(InetAddress ip, InetAddress netmask) + { + this.network = maskIP(ip, netmask); + this.netmask = netmask; + } + + public boolean contains(final String name) throws java.net.UnknownHostException + { + return network.equals(maskIP(InetAddress.getByName(name), netmask)); + } + + public boolean contains(final InetAddress ip) + { + return network.equals(maskIP(ip, netmask)); + } + + @Override + public String toString() + { + return network.getHostAddress() + "/" + netmask.getHostAddress(); + } + + @Override + public int hashCode() + { + return maskIP(network, netmask).hashCode(); + } + + @Override + public boolean equals(Object obj) + { + return (obj != null) && + (obj instanceof InetNetwork) && + ((InetNetwork)obj).network.equals(network) && + ((InetNetwork)obj).netmask.equals(netmask); + } + + public static InetNetwork getFromString(String netspec) throws java.net.UnknownHostException + { + if (netspec.endsWith("*")) + { + netspec = normalizeFromAsterisk(netspec); + } + else + { + int iSlash = netspec.indexOf('/'); + if (iSlash == -1) + { + netspec += "/255.255.255.255"; + } + else if (netspec.indexOf('.', iSlash) == -1) + { + netspec = normalizeFromCIDR(netspec); + } + } + + return new InetNetwork( + InetAddress.getByName(netspec.substring(0, netspec.indexOf('/'))), + InetAddress.getByName(netspec.substring(netspec.indexOf('/') + 1))); + } + + public static InetAddress maskIP(final byte[] ip, final byte[] mask) + { + try + { + return getByAddress( + new byte[] + { + (byte) (mask[0] & ip[0]), + (byte) (mask[1] & ip[1]), + (byte) (mask[2] & ip[2]), + (byte) (mask[3] & ip[3]) + } + ); + } + catch (Exception _) + { + return null; + } + } + + public static InetAddress maskIP(final InetAddress ip, final InetAddress mask) + { + return maskIP(ip.getAddress(), mask.getAddress()); + } + + /* + * This converts from an uncommon "wildcard" CIDR format + * to "address + mask" format: + * + * * => 000.000.000.0/000.000.000.0 + * xxx.* => xxx.000.000.0/255.000.000.0 + * xxx.xxx.* => xxx.xxx.000.0/255.255.000.0 + * xxx.xxx.xxx.* => xxx.xxx.xxx.0/255.255.255.0 + */ + static private String normalizeFromAsterisk(final String netspec) + { + String[] masks = { "0.0.0.0/0.0.0.0", "0.0.0/255.0.0.0", "0.0/255.255.0.0", "0/255.255.255.0" }; + char[] srcb = netspec.toCharArray(); + int octets = 0; + for (int i = 1; i < netspec.length(); i++) + { + if (srcb[i] == '.') + { + octets++; + } + } + return (octets == 0) ? masks[0] : netspec.substring(0, netspec.length() -1 ).concat(masks[octets]); + } + + /* + * RFC 1518, 1519 - Classless Inter-Domain Routing (CIDR) + * This converts from "prefix + prefix-length" format to + * "address + mask" format, e.g. from xxx.xxx.xxx.xxx/yy + * to xxx.xxx.xxx.xxx/yyy.yyy.yyy.yyy. + */ + static private String normalizeFromCIDR(final String netspec) + { + final int bits = 32 - Integer.parseInt(netspec.substring(netspec.indexOf('/')+1)); + final int mask = (bits == 32) ? 0 : 0xFFFFFFFF - ((1 << bits)-1); + + return netspec.substring(0, netspec.indexOf('/') + 1) + + Integer.toString(mask >> 24 & 0xFF, 10) + "." + + Integer.toString(mask >> 16 & 0xFF, 10) + "." + + Integer.toString(mask >> 8 & 0xFF, 10) + "." + + Integer.toString(mask >> 0 & 0xFF, 10); + } + + private static InetAddress getByAddress(byte[] ip) throws java.net.UnknownHostException + { + InetAddress addr = InetAddress.getByAddress(ip); + + if (addr == null) { + addr = InetAddress.getByName + ( + Integer.toString(ip[0] & 0xFF, 10) + "." + + Integer.toString(ip[1] & 0xFF, 10) + "." + + Integer.toString(ip[2] & 0xFF, 10) + "." + + Integer.toString(ip[3] & 0xFF, 10) + ); + } + + return addr; + } +}
\ No newline at end of file diff --git a/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/firewall/NetworkFirewallRule.java b/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/firewall/NetworkFirewallRule.java new file mode 100644 index 0000000000..ad619a0e0b --- /dev/null +++ b/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/firewall/NetworkFirewallRule.java @@ -0,0 +1,117 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.security.access.firewall; + +import java.net.InetAddress; +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.lang.builder.EqualsBuilder; +import org.apache.commons.lang.builder.HashCodeBuilder; +import org.apache.commons.lang.builder.ToStringBuilder; +import org.apache.commons.lang.builder.ToStringStyle; +import org.apache.log4j.Logger; + +public class NetworkFirewallRule implements FirewallRule +{ + private static final Logger _logger = Logger.getLogger(NetworkFirewallRule.class); + + private List<InetNetwork> _networks; + + public NetworkFirewallRule(String... networks) + { + _networks = new ArrayList<InetNetwork>(); + for (int i = 0; i < networks.length; i++) + { + String network = networks[i]; + try + { + InetNetwork inetNetwork = InetNetwork.getFromString(network); + if (!_networks.contains(inetNetwork)) + { + _networks.add(inetNetwork); + } + } + catch (java.net.UnknownHostException uhe) + { + _logger.error("Cannot resolve address: " + network, uhe); + } + } + + if(_logger.isDebugEnabled()) + { + _logger.debug("Created " + this); + } + } + + @Override + public boolean matches(InetAddress ip) + { + for (InetNetwork network : _networks) + { + if (network.contains(ip)) + { + if(_logger.isDebugEnabled()) + { + _logger.debug("Client address " + ip + " matches configured network " + network); + } + return true; + } + } + + if(_logger.isDebugEnabled()) + { + _logger.debug("Client address " + ip + " does not match any configured networks"); + } + + return false; + } + + @Override + public int hashCode() + { + return new HashCodeBuilder().append(_networks).toHashCode(); + } + + @Override + public boolean equals(Object obj) + { + if (obj == null) + { + return false; + } + if (obj == this) + { + return true; + } + if (obj.getClass() != getClass()) + { + return false; + } + NetworkFirewallRule rhs = (NetworkFirewallRule) obj; + return new EqualsBuilder().append(_networks, rhs._networks).isEquals(); + } + + @Override + public String toString() + { + return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) + .append(_networks).toString(); + } +} diff --git a/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/logging/AccessControl_logmessages.properties b/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/logging/AccessControl_logmessages.properties index bf80df3722..2a5eb7b3be 100644 --- a/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/logging/AccessControl_logmessages.properties +++ b/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/logging/AccessControl_logmessages.properties @@ -25,4 +25,4 @@ ALLOWED = ACL-1001 : Allowed : {0} {1} {2} # 'deny-log' rule message -DENIED = ACL-1002 : Denied : {0} {1} {2}
\ No newline at end of file +DENIED = ACL-1002 : Denied : {0} {1} {2} diff --git a/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/AccessControlConfiguration.java b/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/AccessControlConfiguration.java deleted file mode 100644 index c4db6db820..0000000000 --- a/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/AccessControlConfiguration.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.access.plugins; - -import java.io.File; -import java.util.Arrays; -import java.util.List; - -import org.apache.commons.configuration.Configuration; -import org.apache.commons.configuration.ConfigurationException; -import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; -import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory; -import org.apache.qpid.server.security.access.config.ConfigurationFile; -import org.apache.qpid.server.security.access.config.PlainConfiguration; -import org.apache.qpid.server.security.access.config.RuleSet; - -public class AccessControlConfiguration extends ConfigurationPlugin -{ - public static final ConfigurationPluginFactory FACTORY = new ConfigurationPluginFactory() - { - public ConfigurationPlugin newInstance(String path, Configuration config) throws ConfigurationException - { - ConfigurationPlugin instance = new AccessControlConfiguration(); - instance.setConfiguration(path, config); - return instance; - } - - public List<String> getParentPaths() - { - return Arrays.asList("security.acl", "virtualhosts.virtualhost.security.acl"); - } - }; - - private RuleSet _ruleSet; - - public String[] getElementsProcessed() - { - return new String[] { "" }; - } - - public String getFileName() - { - return getConfig().getString(""); - } - - public void validateConfiguration() throws ConfigurationException - { - String filename = getFileName(); - if (filename == null) - { - throw new ConfigurationException("No ACL file name specified"); - } - - File aclFile = new File(filename); - - ConfigurationFile configFile = new PlainConfiguration(aclFile); - _ruleSet = configFile.load(); - } - - public RuleSet getRuleSet() - { - return _ruleSet; - } - -} diff --git a/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/AccessControl.java b/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/DefaultAccessControl.java index d8a5bd4085..6f7885da94 100644 --- a/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/AccessControl.java +++ b/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/DefaultAccessControl.java @@ -20,56 +20,47 @@ */ package org.apache.qpid.server.security.access.plugins; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.io.File; + import javax.security.auth.Subject; import org.apache.commons.configuration.ConfigurationException; +import org.apache.commons.lang.ObjectUtils; import org.apache.log4j.Logger; -import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; -import org.apache.qpid.server.security.AbstractPlugin; import org.apache.qpid.server.security.Result; import org.apache.qpid.server.security.SecurityManager; -import org.apache.qpid.server.security.SecurityPluginFactory; +import org.apache.qpid.server.security.AccessControl; import org.apache.qpid.server.security.access.ObjectProperties; import org.apache.qpid.server.security.access.ObjectType; import org.apache.qpid.server.security.access.Operation; +import org.apache.qpid.server.security.access.config.ConfigurationFile; +import org.apache.qpid.server.security.access.config.PlainConfiguration; import org.apache.qpid.server.security.access.config.RuleSet; -/** - * This access control plugin implements version two plain text access control. - */ -public class AccessControl extends AbstractPlugin +public class DefaultAccessControl implements AccessControl { - public static final Logger _logger = Logger.getLogger(AccessControl.class); - + private static final Logger _logger = Logger.getLogger(DefaultAccessControl.class); + private RuleSet _ruleSet; - - public static final SecurityPluginFactory<AccessControl> FACTORY = new SecurityPluginFactory<AccessControl>() - { - public Class<AccessControl> getPluginClass() - { - return AccessControl.class; - } - public String getPluginName() + public DefaultAccessControl(String fileName) + { + if (_logger.isDebugEnabled()) { - return AccessControl.class.getName(); + _logger.debug("Creating AccessControl instance using file: " + fileName); } + File aclFile = new File(fileName); - public AccessControl newInstance(ConfigurationPlugin config) throws ConfigurationException - { - AccessControlConfiguration configuration = config.getConfiguration(AccessControlConfiguration.class.getName()); - - // If there is no configuration for this plugin then don't load it. - if (configuration == null) - { - return null; - } + ConfigurationFile configFile = new PlainConfiguration(aclFile); + _ruleSet = configFile.load(); + } - AccessControl plugin = new AccessControl(); - plugin.configure(configuration); - return plugin; - } - }; + DefaultAccessControl(RuleSet rs) throws ConfigurationException + { + _ruleSet = rs; + } public Result getDefault() { @@ -82,11 +73,18 @@ public class AccessControl extends AbstractPlugin * Delegate to the {@link #authorise(Operation, ObjectType, ObjectProperties)} method, with * the operation set to ACCESS and no object properties. */ - public Result access(ObjectType objectType, Object instance) + public Result access(ObjectType objectType, Object inetSocketAddress) { - return authorise(Operation.ACCESS, objectType, ObjectProperties.EMPTY); + InetAddress addressOfClient = null; + + if(inetSocketAddress != null) + { + addressOfClient = ((InetSocketAddress) inetSocketAddress).getAddress(); + } + + return authoriseFromAddress(Operation.ACCESS, objectType, ObjectProperties.EMPTY, addressOfClient); } - + /** * 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 @@ -94,23 +92,31 @@ public class AccessControl extends AbstractPlugin */ public Result authorise(Operation operation, ObjectType objectType, ObjectProperties properties) { + return authoriseFromAddress(operation, objectType, properties, null); + } + + public Result authoriseFromAddress(Operation operation, ObjectType objectType, ObjectProperties properties, InetAddress addressOfClient) + { final Subject subject = SecurityManager.getThreadSubject(); // Abstain if there is no subject/principal associated with this thread if (subject == null || subject.getPrincipals().size() == 0) { return Result.ABSTAIN; } - - _logger.debug("Checking " + operation + " " + objectType); - return _ruleSet.check(subject, operation, objectType, properties); - } - public void configure(ConfigurationPlugin config) - { - super.configure(config); - - AccessControlConfiguration accessConfig = (AccessControlConfiguration) getConfig(); + if(_logger.isDebugEnabled()) + { + _logger.debug("Checking " + operation + " " + objectType + " " + ObjectUtils.defaultIfNull(addressOfClient, "")); + } - _ruleSet = accessConfig.getRuleSet(); + try + { + return _ruleSet.check(subject, operation, objectType, properties, addressOfClient); + } + catch(Exception e) + { + _logger.error("Unable to check " + operation + " " + objectType + " " + ObjectUtils.defaultIfNull(addressOfClient, ""), e); + return Result.DENIED; + } } } diff --git a/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/DefaultAccessControlFactory.java b/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/DefaultAccessControlFactory.java new file mode 100644 index 0000000000..a3d7823caf --- /dev/null +++ b/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/DefaultAccessControlFactory.java @@ -0,0 +1,59 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.access.plugins; + +import java.io.File; +import java.util.Map; + +import org.apache.qpid.server.configuration.IllegalConfigurationException; +import org.apache.qpid.server.plugin.AccessControlFactory; +import org.apache.qpid.server.security.AccessControl; + +public class DefaultAccessControlFactory implements AccessControlFactory +{ + public static final String ATTRIBUTE_ACL_FILE = "aclFile"; + + public AccessControl createInstance(Map<String, Object> aclConfiguration) + { + if (aclConfiguration != null) + { + Object aclFile = aclConfiguration.get(ATTRIBUTE_ACL_FILE); + if (aclFile != null) + { + if (aclFile instanceof String) + { + String aclPath = (String) aclFile; + if (!new File(aclPath).exists()) + { + throw new IllegalConfigurationException("ACL file '" + aclPath + "' is not found"); + } + return new DefaultAccessControl(aclPath); + } + else + { + throw new IllegalConfigurationException("Expected '" + ATTRIBUTE_ACL_FILE + "' attribute value of type String but was " + aclFile.getClass() + + ": " + aclFile); + } + } + } + return null; + } +} diff --git a/java/broker-plugins/access-control/src/main/resources/META-INF/services/org.apache.qpid.server.plugin.AccessControlFactory b/java/broker-plugins/access-control/src/main/resources/META-INF/services/org.apache.qpid.server.plugin.AccessControlFactory new file mode 100644 index 0000000000..b6c429baab --- /dev/null +++ b/java/broker-plugins/access-control/src/main/resources/META-INF/services/org.apache.qpid.server.plugin.AccessControlFactory @@ -0,0 +1,19 @@ +# +# 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. +# +org.apache.qpid.server.security.access.plugins.DefaultAccessControlFactory diff --git a/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/AclActionTest.java b/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/AclActionTest.java new file mode 100644 index 0000000000..14620cff70 --- /dev/null +++ b/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/AclActionTest.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.security.access.config; + +import static org.mockito.Mockito.*; + +import org.apache.qpid.server.security.access.ObjectProperties; +import org.apache.qpid.server.security.access.ObjectType; +import org.apache.qpid.server.security.access.Operation; +import org.apache.qpid.server.security.access.firewall.FirewallRule; + +import junit.framework.TestCase; + +public class AclActionTest extends TestCase +{ + public void testEqualsAndHashCode() + { + AclRulePredicates predicates = createAclRulePredicates(); + ObjectType objectType = ObjectType.EXCHANGE; + Operation operation = Operation.ACCESS; + + AclAction aclAction = new AclAction(operation, objectType, predicates); + AclAction equalAclAction = new AclAction(operation, objectType, predicates); + + assertTrue(aclAction.equals(aclAction)); + assertTrue(aclAction.equals(equalAclAction)); + assertTrue(equalAclAction.equals(aclAction)); + + assertTrue(aclAction.hashCode() == equalAclAction.hashCode()); + + assertFalse("Different operation should cause aclActions to be unequal", + aclAction.equals(new AclAction(Operation.BIND, objectType, predicates))); + + assertFalse("Different operation type should cause aclActions to be unequal", + aclAction.equals(new AclAction(operation, ObjectType.GROUP, predicates))); + + assertFalse("Different predicates should cause aclActions to be unequal", + aclAction.equals(new AclAction(operation, objectType, createAclRulePredicates()))); + + } + + private AclRulePredicates createAclRulePredicates() + { + AclRulePredicates predicates = mock(AclRulePredicates.class); + when(predicates.getFirewallRule()).thenReturn(mock(FirewallRule.class)); + when(predicates.getObjectProperties()).thenReturn(mock(ObjectProperties.class)); + return predicates; + } + +} diff --git a/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/AclRulePredicatesTest.java b/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/AclRulePredicatesTest.java new file mode 100644 index 0000000000..93b765d0fb --- /dev/null +++ b/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/AclRulePredicatesTest.java @@ -0,0 +1,87 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.security.access.config; + +import static org.apache.qpid.server.security.access.ObjectProperties.Property.*; + +import org.apache.qpid.server.security.access.firewall.FirewallRule; +import org.apache.qpid.server.security.access.firewall.FirewallRuleFactory; + +import static org.mockito.Mockito.*; + +import junit.framework.TestCase; + +public class AclRulePredicatesTest extends TestCase +{ + private AclRulePredicates _aclRulePredicates = new AclRulePredicates(); + private FirewallRuleFactory _firewallRuleFactory = mock(FirewallRuleFactory.class); + + @Override + protected void setUp() throws Exception + { + _aclRulePredicates.setFirewallRuleFactory(_firewallRuleFactory); + + when(_firewallRuleFactory.createForHostname((String[]) any())).thenReturn(mock(FirewallRule.class)); + when(_firewallRuleFactory.createForNetwork((String[]) any())).thenReturn(mock(FirewallRule.class)); + } + + public void testParse() + { + String name = "name"; + String className = "class"; + + _aclRulePredicates.parse(NAME.name(), name); + _aclRulePredicates.parse(CLASS.name(), className); + + assertEquals(name, _aclRulePredicates.getObjectProperties().get(NAME)); + assertEquals(className, _aclRulePredicates.getObjectProperties().get(CLASS)); + } + + public void testParseHostnameFirewallRule() + { + String hostname = "hostname1,hostname2"; + _aclRulePredicates.parse(FROM_HOSTNAME.name(), hostname); + + verify(_firewallRuleFactory).createForHostname(new String[] {"hostname1", "hostname2"}); + } + + public void testParseNetworkFirewallRule() + { + _aclRulePredicates.setFirewallRuleFactory(_firewallRuleFactory); + + String networks = "network1,network2"; + _aclRulePredicates.parse(FROM_NETWORK.name(), networks); + + verify(_firewallRuleFactory).createForNetwork(new String[] {"network1", "network2"}); + } + + public void testParseThrowsExceptionIfBothHostnameAndNetworkSpecified() + { + _aclRulePredicates.parse(FROM_NETWORK.name(), "network1,network2"); + try + { + _aclRulePredicates.parse(FROM_HOSTNAME.name(), "hostname1,hostname2"); + fail("Exception not thrown"); + } + catch(IllegalStateException e) + { + // pass + } + } +} diff --git a/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/ActionTest.java b/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/ActionTest.java new file mode 100644 index 0000000000..00e06106bf --- /dev/null +++ b/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/ActionTest.java @@ -0,0 +1,95 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.security.access.config; + +import static org.mockito.Mockito.*; + +import org.apache.qpid.server.security.access.ObjectProperties; +import org.apache.qpid.server.security.access.ObjectType; +import org.apache.qpid.server.security.access.Operation; + +import junit.framework.TestCase; + +public class ActionTest extends TestCase +{ + private ObjectProperties _properties1 = mock(ObjectProperties.class); + private ObjectProperties _properties2 = mock(ObjectProperties.class); + + public void testMatchesReturnsTrueForMatchingActions() + { + when(_properties1.matches(_properties2)).thenReturn(true); + + assertMatches( + new Action(Operation.CONSUME, ObjectType.QUEUE, _properties1), + new Action(Operation.CONSUME, ObjectType.QUEUE, _properties2)); + } + + public void testMatchesReturnsFalseWhenOperationsDiffer() + { + assertDoesntMatch( + new Action(Operation.CONSUME, ObjectType.QUEUE, _properties1), + new Action(Operation.CREATE, ObjectType.QUEUE, _properties1)); + } + + public void testMatchesReturnsFalseWhenOperationTypesDiffer() + { + assertDoesntMatch( + new Action(Operation.CREATE, ObjectType.QUEUE, _properties1), + new Action(Operation.CREATE, ObjectType.EXCHANGE, _properties1)); + } + + public void testMatchesReturnsFalseWhenOperationPropertiesDiffer() + { + assertDoesntMatch( + new Action(Operation.CREATE, ObjectType.QUEUE, _properties1), + new Action(Operation.CREATE, ObjectType.QUEUE, _properties2)); + } + + public void testMatchesReturnsFalseWhenMyOperationPropertiesIsNull() + { + assertDoesntMatch( + new Action(Operation.CREATE, ObjectType.QUEUE, (ObjectProperties)null), + new Action(Operation.CREATE, ObjectType.QUEUE, _properties1)); + } + + public void testMatchesReturnsFalseWhenOtherOperationPropertiesIsNull() + { + assertDoesntMatch( + new Action(Operation.CREATE, ObjectType.QUEUE, _properties1), + new Action(Operation.CREATE, ObjectType.QUEUE, (ObjectProperties)null)); + } + + public void testMatchesReturnsTrueWhenBothOperationPropertiesAreNull() + { + assertMatches( + new Action(Operation.CREATE, ObjectType.QUEUE, (ObjectProperties)null), + new Action(Operation.CREATE, ObjectType.QUEUE, (ObjectProperties)null)); + } + + private void assertMatches(Action action1, Action action2) + { + assertTrue(action1 + " should match " + action2, action1.matches(action2)); + } + + private void assertDoesntMatch(Action action1, Action action2) + { + assertFalse(action1 + " should not match " + action2, action1.matches(action2)); + } + +} diff --git a/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/ClientActionTest.java b/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/ClientActionTest.java new file mode 100644 index 0000000000..ae5d3fda74 --- /dev/null +++ b/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/ClientActionTest.java @@ -0,0 +1,79 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.security.access.config; + +import static org.mockito.Mockito.*; + +import java.net.InetAddress; + +import org.apache.qpid.server.security.access.firewall.FirewallRule; + +import junit.framework.TestCase; + +public class ClientActionTest extends TestCase +{ + private Action _action = mock(Action.class); + private AclAction _ruleAction = mock(AclAction.class); + private InetAddress _addressOfClient = mock(InetAddress.class); + + private ClientAction _clientAction = new ClientAction(_action); + + public void testMatches_returnsTrueWhenActionsMatchAndNoFirewallRule() + { + when(_action.matches(any(Action.class))).thenReturn(true); + when(_ruleAction.getFirewallRule()).thenReturn(null); + + assertTrue(_clientAction.matches(_ruleAction, _addressOfClient)); + } + + public void testMatches_returnsFalseWhenActionsDontMatch() + { + FirewallRule firewallRule = mock(FirewallRule.class); + when(firewallRule.matches(_addressOfClient)).thenReturn(true); + + when(_action.matches(any(Action.class))).thenReturn(false); + when(_ruleAction.getFirewallRule()).thenReturn(firewallRule); + + assertFalse(_clientAction.matches(_ruleAction, _addressOfClient)); + } + + public void testMatches_returnsTrueWhenActionsAndFirewallRuleMatch() + { + FirewallRule firewallRule = mock(FirewallRule.class); + when(firewallRule.matches(_addressOfClient)).thenReturn(true); + + when(_action.matches(any(Action.class))).thenReturn(true); + when(_ruleAction.getFirewallRule()).thenReturn(firewallRule); + + assertTrue(_clientAction.matches(_ruleAction, _addressOfClient)); + } + + public void testMatches_ignoresFirewallRuleIfClientAddressIsNull() + { + FirewallRule firewallRule = mock(FirewallRule.class); + + when(_action.matches(any(Action.class))).thenReturn(true); + when(_ruleAction.getFirewallRule()).thenReturn(firewallRule); + + assertTrue(_clientAction.matches(_ruleAction, null)); + + verifyZeroInteractions(firewallRule); + } + +} diff --git a/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/PlainConfigurationTest.java b/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/PlainConfigurationTest.java index c2282694fb..cbfc9003c8 100644 --- a/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/PlainConfigurationTest.java +++ b/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/PlainConfigurationTest.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.qpid.server.security.access.plugins; +package org.apache.qpid.server.security.access.config; import java.io.File; import java.io.FileNotFoundException; @@ -26,7 +26,7 @@ import java.util.Map; import junit.framework.TestCase; -import org.apache.commons.configuration.ConfigurationException; +import org.apache.qpid.server.configuration.IllegalConfigurationException; import org.apache.qpid.server.security.access.ObjectProperties; import org.apache.qpid.server.security.access.ObjectProperties.Property; import org.apache.qpid.server.security.access.ObjectType; @@ -73,7 +73,7 @@ public class PlainConfigurationTest extends TestCase fail("fail"); } - catch (ConfigurationException ce) + catch (IllegalConfigurationException ce) { assertEquals(String.format(PlainConfiguration.CONFIG_NOT_FOUND_MSG, "doesnotexist"), ce.getMessage()); assertTrue(ce.getCause() instanceof FileNotFoundException); @@ -87,7 +87,7 @@ public class PlainConfigurationTest extends TestCase writeACLConfig("ACL ALLOW ALL \\ ALL"); fail("fail"); } - catch (ConfigurationException ce) + catch (IllegalConfigurationException ce) { assertEquals(String.format(PlainConfiguration.PREMATURE_CONTINUATION_MSG, 1), ce.getMessage()); } @@ -100,7 +100,7 @@ public class PlainConfigurationTest extends TestCase writeACLConfig("ACL unparsed ALL ALL"); fail("fail"); } - catch (ConfigurationException ce) + catch (IllegalConfigurationException ce) { assertEquals(String.format(PlainConfiguration.PARSE_TOKEN_FAILED_MSG, 1), ce.getMessage()); assertTrue(ce.getCause() instanceof IllegalArgumentException); @@ -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 @@ -128,7 +115,7 @@ public class PlainConfigurationTest extends TestCase writeACLConfig("ACL ALLOW"); fail("fail"); } - catch (ConfigurationException ce) + catch (IllegalConfigurationException ce) { assertEquals(String.format(PlainConfiguration.NOT_ENOUGH_ACL_MSG, 1), ce.getMessage()); } @@ -141,7 +128,7 @@ public class PlainConfigurationTest extends TestCase writeACLConfig("CONFIG"); fail("fail"); } - catch (ConfigurationException ce) + catch (IllegalConfigurationException ce) { assertEquals(String.format(PlainConfiguration.NOT_ENOUGH_TOKENS_MSG, 1), ce.getMessage()); } @@ -154,7 +141,7 @@ public class PlainConfigurationTest extends TestCase writeACLConfig("INVALID"); fail("fail"); } - catch (ConfigurationException ce) + catch (IllegalConfigurationException ce) { assertEquals(String.format(PlainConfiguration.NOT_ENOUGH_TOKENS_MSG, 1), ce.getMessage()); } @@ -167,7 +154,7 @@ public class PlainConfigurationTest extends TestCase writeACLConfig("ACL ALLOW adk CREATE QUEUE name"); fail("fail"); } - catch (ConfigurationException ce) + catch (IllegalConfigurationException ce) { assertEquals(String.format(PlainConfiguration.PROPERTY_KEY_ONLY_MSG, 1), ce.getMessage()); } @@ -180,7 +167,7 @@ public class PlainConfigurationTest extends TestCase writeACLConfig("ACL ALLOW adk CREATE QUEUE name test"); fail("fail"); } - catch (ConfigurationException ce) + catch (IllegalConfigurationException ce) { assertEquals(String.format(PlainConfiguration.PROPERTY_NO_EQUALS_MSG, 1), ce.getMessage()); } @@ -193,7 +180,7 @@ public class PlainConfigurationTest extends TestCase writeACLConfig("ACL ALLOW adk CREATE QUEUE name ="); fail("fail"); } - catch (ConfigurationException ce) + catch (IllegalConfigurationException ce) { assertEquals(String.format(PlainConfiguration.PROPERTY_NO_VALUE_MSG, 1), ce.getMessage()); } @@ -391,4 +378,86 @@ 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(IllegalConfigurationException e) + { + assertTrue(e.getMessage().contains("GROUP keyword not supported")); + } + } + + public void testManagementRuleParsing() throws Exception + { + validateRule(writeACLConfig("ACL ALLOW user1 ALL MANAGEMENT"), + "user1", Operation.ALL, ObjectType.MANAGEMENT, ObjectProperties.EMPTY); + + validateRule(writeACLConfig("ACL ALLOW user1 ACCESS MANAGEMENT"), + "user1", Operation.ACCESS, ObjectType.MANAGEMENT, ObjectProperties.EMPTY); + } + + 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/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/RuleTest.java b/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/RuleTest.java new file mode 100644 index 0000000000..2ae7759679 --- /dev/null +++ b/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/config/RuleTest.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.security.access.config; + +import static org.mockito.Mockito.*; + +import org.apache.qpid.server.security.access.Permission; + +import junit.framework.TestCase; + +public class RuleTest extends TestCase +{ + public void testEqualsAndHashCode() + { + AclAction aclAction = mock(AclAction.class); + String identity = "identity"; + Permission allow = Permission.ALLOW; + + Rule rule = new Rule(identity, aclAction, allow); + Rule equalRule = new Rule(identity, aclAction, allow); + + assertTrue(rule.equals(rule)); + assertTrue(rule.equals(equalRule)); + assertTrue(equalRule.equals(rule)); + + assertTrue(rule.hashCode() == equalRule.hashCode()); + + assertFalse("Different identity should cause rules to be unequal", + rule.equals(new Rule("identity2", aclAction, allow))); + + assertFalse("Different action should cause rules to be unequal", + rule.equals(new Rule(identity, mock(AclAction.class), allow))); + + assertFalse("Different permission should cause rules to be unequal", + rule.equals(new Rule(identity, aclAction, Permission.DENY))); + } +} diff --git a/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/firewall/HostnameFirewallRuleTest.java b/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/firewall/HostnameFirewallRuleTest.java new file mode 100644 index 0000000000..be82cb294a --- /dev/null +++ b/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/firewall/HostnameFirewallRuleTest.java @@ -0,0 +1,99 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.security.access.firewall; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.net.InetAddress; + +import org.apache.qpid.server.security.access.firewall.HostnameFirewallRule; + +import junit.framework.TestCase; + +public class HostnameFirewallRuleTest extends TestCase +{ + private InetAddress _addressNotInRule; + + private HostnameFirewallRule _HostnameFirewallRule; + + @Override + protected void setUp() throws Exception + { + _addressNotInRule = InetAddress.getByName("127.0.0.1"); + } + + public void testSingleHostname() throws Exception + { + String hostnameInRule = "hostnameInRule"; + InetAddress addressWithMatchingHostname = mock(InetAddress.class); + when(addressWithMatchingHostname.getCanonicalHostName()).thenReturn(hostnameInRule); + + _HostnameFirewallRule = new HostnameFirewallRule(hostnameInRule); + + assertFalse(_HostnameFirewallRule.matches(_addressNotInRule)); + assertTrue(_HostnameFirewallRule.matches(addressWithMatchingHostname)); + } + + public void testSingleHostnameWilcard() throws Exception + { + String hostnameInRule = ".*FOO.*"; + InetAddress addressWithMatchingHostname = mock(InetAddress.class); + when(addressWithMatchingHostname.getCanonicalHostName()).thenReturn("xxFOOxx"); + + _HostnameFirewallRule = new HostnameFirewallRule(hostnameInRule); + + assertFalse(_HostnameFirewallRule.matches(_addressNotInRule)); + assertTrue(_HostnameFirewallRule.matches(addressWithMatchingHostname)); + } + + public void testMultipleHostnames() throws Exception + { + String[] hostnamesInRule = new String[] {"hostnameInRule1", "hostnameInRule2"}; + + _HostnameFirewallRule = new HostnameFirewallRule(hostnamesInRule); + + assertFalse(_HostnameFirewallRule.matches(_addressNotInRule)); + for (String hostnameInRule : hostnamesInRule) + { + InetAddress addressWithMatchingHostname = mock(InetAddress.class); + when(addressWithMatchingHostname.getCanonicalHostName()).thenReturn(hostnameInRule); + + assertTrue(_HostnameFirewallRule.matches(addressWithMatchingHostname)); + } + } + + public void testEqualsAndHashCode() + { + String hostname1 = "hostname1"; + String hostname2 = "hostname2"; + + HostnameFirewallRule rule = new HostnameFirewallRule(hostname1, hostname2); + HostnameFirewallRule equalRule = new HostnameFirewallRule(hostname1, hostname2); + + assertTrue(rule.equals(rule)); + assertTrue(rule.equals(equalRule)); + assertTrue(equalRule.equals(rule)); + + assertTrue(rule.hashCode() == equalRule.hashCode()); + + assertFalse("Different hostnames should cause rules to be unequal", + rule.equals(new HostnameFirewallRule(hostname1, "different-hostname"))); + } +} diff --git a/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/firewall/NetworkFirewallRuleTest.java b/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/firewall/NetworkFirewallRuleTest.java new file mode 100644 index 0000000000..e521039db2 --- /dev/null +++ b/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/firewall/NetworkFirewallRuleTest.java @@ -0,0 +1,115 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.security.access.firewall; + +import java.net.InetAddress; + +import org.apache.qpid.server.security.access.firewall.NetworkFirewallRule; + +import junit.framework.TestCase; + +public class NetworkFirewallRuleTest extends TestCase +{ + private static final String LOCALHOST_IP = "127.0.0.1"; + private static final String OTHER_IP_1 = "192.168.23.1"; + private static final String OTHER_IP_2 = "192.168.23.2"; + + private InetAddress _addressNotInRule; + + private NetworkFirewallRule _networkFirewallRule; + + @Override + protected void setUp() throws Exception + { + _addressNotInRule = InetAddress.getByName(LOCALHOST_IP); + } + + public void testIpRule() throws Exception + { + String ipAddressInRule = OTHER_IP_1; + + _networkFirewallRule = new NetworkFirewallRule(ipAddressInRule); + + assertFalse(_networkFirewallRule.matches(_addressNotInRule)); + assertTrue(_networkFirewallRule.matches(InetAddress.getByName(ipAddressInRule))); + } + + public void testNetMask() throws Exception + { + String ipAddressInRule = "192.168.23.0/24"; + _networkFirewallRule = new NetworkFirewallRule(ipAddressInRule); + + assertFalse(_networkFirewallRule.matches(InetAddress.getByName("192.168.24.1"))); + assertTrue(_networkFirewallRule.matches(InetAddress.getByName("192.168.23.0"))); + assertTrue(_networkFirewallRule.matches(InetAddress.getByName("192.168.23.255"))); + } + + public void testWildcard() throws Exception + { + // Test xxx.xxx.* + + assertFalse(new NetworkFirewallRule("192.168.*") + .matches(InetAddress.getByName("192.169.1.0"))); + + assertTrue(new NetworkFirewallRule("192.168.*") + .matches(InetAddress.getByName("192.168.1.0"))); + + assertTrue(new NetworkFirewallRule("192.168.*") + .matches(InetAddress.getByName("192.168.255.255"))); + + // Test xxx.xxx.xxx.* + + assertFalse(new NetworkFirewallRule("192.168.1.*") + .matches(InetAddress.getByName("192.169.2.0"))); + + assertTrue(new NetworkFirewallRule("192.168.1.*") + .matches(InetAddress.getByName("192.168.1.0"))); + + assertTrue(new NetworkFirewallRule("192.168.1.*") + .matches(InetAddress.getByName("192.168.1.255"))); + } + + public void testMultipleNetworks() throws Exception + { + String[] ipAddressesInRule = new String[] {OTHER_IP_1, OTHER_IP_2}; + + _networkFirewallRule = new NetworkFirewallRule(ipAddressesInRule); + + assertFalse(_networkFirewallRule.matches(_addressNotInRule)); + for (String ipAddressInRule : ipAddressesInRule) + { + assertTrue(_networkFirewallRule.matches(InetAddress.getByName(ipAddressInRule))); + } + } + + public void testEqualsAndHashCode() + { + NetworkFirewallRule rule = new NetworkFirewallRule(LOCALHOST_IP, OTHER_IP_1); + NetworkFirewallRule equalRule = new NetworkFirewallRule(LOCALHOST_IP, OTHER_IP_1); + + assertTrue(rule.equals(rule)); + assertTrue(rule.equals(equalRule)); + assertTrue(equalRule.equals(rule)); + + assertTrue(rule.hashCode() == equalRule.hashCode()); + + assertFalse("Different networks should cause rules to be unequal", + rule.equals(new NetworkFirewallRule(LOCALHOST_IP, OTHER_IP_2))); + } +} diff --git a/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/DefaultAccessControlFactoryTest.java b/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/DefaultAccessControlFactoryTest.java new file mode 100644 index 0000000000..ca1f19098f --- /dev/null +++ b/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/DefaultAccessControlFactoryTest.java @@ -0,0 +1,69 @@ +package org.apache.qpid.server.security.access.plugins; + +import java.io.File; +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Pattern; + +import org.apache.qpid.server.configuration.IllegalConfigurationException; +import org.apache.qpid.server.security.AccessControl; +import org.apache.qpid.test.utils.QpidTestCase; +import org.apache.qpid.test.utils.TestFileUtils; + +public class DefaultAccessControlFactoryTest extends QpidTestCase +{ + public void testCreateInstanceWhenAclFileIsNotPresent() + { + DefaultAccessControlFactory factory = new DefaultAccessControlFactory(); + Map<String, Object> attributes = new HashMap<String, Object>(); + AccessControl acl = factory.createInstance(attributes); + assertNull("ACL was created without a configuration file", acl); + } + + public void testCreateInstanceWhenAclFileIsSpecified() + { + File aclFile = TestFileUtils.createTempFile(this, ".acl", "ACL ALLOW all all"); + DefaultAccessControlFactory factory = new DefaultAccessControlFactory(); + Map<String, Object> attributes = new HashMap<String, Object>(); + attributes.put(DefaultAccessControlFactory.ATTRIBUTE_ACL_FILE, aclFile.getAbsolutePath()); + AccessControl acl = factory.createInstance(attributes); + + assertNotNull("ACL was not created from acl file: " + aclFile.getAbsolutePath(), acl); + } + + public void testCreateInstanceWhenAclFileIsSpecifiedButDoesNotExist() + { + File aclFile = new File(TMP_FOLDER, "my-non-existing-acl-" + System.currentTimeMillis()); + assertFalse("ACL file " + aclFile.getAbsolutePath() + " actually exists but should not", aclFile.exists()); + DefaultAccessControlFactory factory = new DefaultAccessControlFactory(); + Map<String, Object> attributes = new HashMap<String, Object>(); + attributes.put(DefaultAccessControlFactory.ATTRIBUTE_ACL_FILE, aclFile.getAbsolutePath()); + try + { + factory.createInstance(attributes); + fail("It should not be possible to create ACL from non existing file"); + } + catch (IllegalConfigurationException e) + { + assertTrue("Unexpected exception message", Pattern.matches("ACL file '.*' is not found", e.getMessage())); + } + } + + public void testCreateInstanceWhenAclFileIsSpecifiedAsNonString() + { + DefaultAccessControlFactory factory = new DefaultAccessControlFactory(); + Map<String, Object> attributes = new HashMap<String, Object>(); + Integer aclFile = new Integer(0); + attributes.put(DefaultAccessControlFactory.ATTRIBUTE_ACL_FILE, aclFile); + try + { + factory.createInstance(attributes); + fail("It should not be possible to create ACL from Integer"); + } + catch (IllegalConfigurationException e) + { + assertEquals("Unexpected exception message", "Expected '" + DefaultAccessControlFactory.ATTRIBUTE_ACL_FILE + + "' attribute value of type String but was " + Integer.class + ": " + aclFile, e.getMessage()); + } + } +} diff --git a/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/AccessControlTest.java b/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/DefaultAccessControlTest.java index 5db02d10ce..a8406308c0 100644 --- a/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/AccessControlTest.java +++ b/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/DefaultAccessControlTest.java @@ -20,12 +20,16 @@ */ package org.apache.qpid.server.security.access.plugins; -import java.util.Arrays; +import static org.mockito.Mockito.*; + +import java.net.InetAddress; +import java.net.InetSocketAddress; + +import javax.security.auth.Subject; import junit.framework.TestCase; import org.apache.commons.configuration.ConfigurationException; -import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; import org.apache.qpid.server.logging.UnitTestMessageLogger; import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.actors.TestLogActor; @@ -37,20 +41,19 @@ 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. - * - * 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. - * + * In these tests, the ruleset is configured programmatically rather than from an external file. + * * @see RuleSetTest */ -public class AccessControlTest extends TestCase +public class DefaultAccessControlTest extends TestCase { - private AccessControl _plugin = null; // Class under test + private static final String ALLOWED_GROUP = "allowed_group"; + private static final String DENIED_GROUP = "denied_group"; + + private DefaultAccessControl _plugin = null; // Class under test private final UnitTestMessageLogger messageLogger = new UnitTestMessageLogger(); private void setUpGroupAccessControl() throws ConfigurationException @@ -60,7 +63,7 @@ public class AccessControlTest extends TestCase private void configureAccessControl(final RuleSet rs) throws ConfigurationException { - _plugin = (AccessControl) AccessControl.FACTORY.newInstance(createConfiguration(rs)); + _plugin = new DefaultAccessControl(rs); SecurityManager.setThreadSubject(null); CurrentActor.set(new TestLogActor(messageLogger)); } @@ -68,14 +71,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 +118,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); } /** @@ -203,6 +196,46 @@ public class AccessControlTest extends TestCase assertEquals(Result.DEFER, result); } + public void testAccess() throws Exception + { + Subject subject = TestPrincipalUtils.createTestSubject("user1"); + SecurityManager.setThreadSubject(subject); + + RuleSet mockRuleSet = mock(RuleSet.class); + + InetAddress inetAddress = InetAddress.getLocalHost(); + InetSocketAddress inetSocketAddress = new InetSocketAddress(inetAddress, 1); + + DefaultAccessControl accessControl = new DefaultAccessControl(mockRuleSet); + + accessControl.access(ObjectType.VIRTUALHOST, inetSocketAddress); + + verify(mockRuleSet).check(subject, Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY, inetAddress); + } + + public void testAccessIsDeniedIfRuleThrowsException() throws Exception + { + Subject subject = TestPrincipalUtils.createTestSubject("user1"); + SecurityManager.setThreadSubject(subject); + + InetAddress inetAddress = InetAddress.getLocalHost(); + InetSocketAddress inetSocketAddress = new InetSocketAddress(inetAddress, 1); + + RuleSet mockRuleSet = mock(RuleSet.class); + when(mockRuleSet.check( + subject, + Operation.ACCESS, + ObjectType.VIRTUALHOST, + ObjectProperties.EMPTY, + inetAddress)).thenThrow(new RuntimeException()); + + DefaultAccessControl accessControl = new DefaultAccessControl(mockRuleSet); + Result result = accessControl.access(ObjectType.VIRTUALHOST, inetSocketAddress); + + assertEquals(Result.DENIED, result); + } + + /** * Tests that a grant access method rule allows any access operation to be performed on a specified component */ @@ -325,31 +358,11 @@ public class AccessControlTest extends TestCase assertEquals(Result.DEFER, result); } - /** - * Creates a configuration plugin for the {@link AccessControl} plugin. - */ - private ConfigurationPlugin createConfiguration(final RuleSet rs) + private void authoriseAndAssertResult(Result expectedResult, String userName, String... groups) { - final ConfigurationPlugin cp = new ConfigurationPlugin() - { - @SuppressWarnings("unchecked") - public AccessControlConfiguration getConfiguration(final String plugin) - { - return new AccessControlConfiguration() - { - public RuleSet getRuleSet() - { - return rs; - } - }; - } - - public String[] getElementsProcessed() - { - throw new UnsupportedOperationException(); - } - }; - - return cp; + SecurityManager.setThreadSubject(TestPrincipalUtils.createTestSubject(userName, groups)); + + Result result = _plugin.authorise(Operation.ACCESS, ObjectType.VIRTUALHOST, ObjectProperties.EMPTY); + assertEquals(expectedResult, result); } } diff --git a/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/RuleSetTest.java b/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/RuleSetTest.java index f7cc60543d..181d693614 100644 --- a/java/broker-plugins/access-control/src/test/java/org/apache/qpid/server/security/access/plugins/RuleSetTest.java +++ b/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/java/broker-plugins/firewall/MANIFEST.MF b/java/broker-plugins/firewall/MANIFEST.MF deleted file mode 100644 index a302921d03..0000000000 --- a/java/broker-plugins/firewall/MANIFEST.MF +++ /dev/null @@ -1,34 +0,0 @@ -Manifest-Version: 1.0 -Bundle-ManifestVersion: 2 -Bundle-Name: Qpid Broker-Plugins Firewall -Bundle-SymbolicName: broker-plugins-firewall -Bundle-Description: Firewall plugin for Qpid. -Bundle-License: http://www.apache.org/licenses/LICENSE-2.0.txt -Bundle-DocURL: http://www.apache.org/ -Bundle-Version: 1.0.0 -Bundle-Activator: org.apache.qpid.server.security.access.plugins.FirewallActivator -Bundle-RequiredExecutionEnvironment: JavaSE-1.6 -Bundle-ClassPath: . -Bundle-ActivationPolicy: lazy -Import-Package: org.apache.qpid, - org.apache.qpid.framing, - org.apache.qpid.protocol, - org.apache.qpid.server.configuration, - org.apache.qpid.server.configuration.plugins, - org.apache.qpid.server.exchange, - org.apache.qpid.server.plugins, - org.apache.qpid.server.queue, - org.apache.qpid.server.security, - org.apache.qpid.server.security.access, - org.apache.qpid.server.virtualhost, - org.apache.qpid.util, - org.apache.commons.configuration;version=1.0.0, - org.apache.commons.lang;version=1.0.0, - org.apache.commons.lang.builder;version=1.0.0, - org.apache.log4j;version=1.0.0, - javax.management;version=1.0.0, - javax.management.openmbean;version=1.0.0, - org.osgi.util.tracker;version=1.0.0, - org.osgi.framework;version=1.3 -Private-Package: org.apache.qpid.server.security.access.config -Export-Package: org.apache.qpid.server.security.access.plugins;uses:="org.osgi.framework" diff --git a/java/broker-plugins/firewall/src/main/java/org/apache/qpid/server/security/access/config/FirewallRule.java b/java/broker-plugins/firewall/src/main/java/org/apache/qpid/server/security/access/config/FirewallRule.java deleted file mode 100644 index ecec4b0cec..0000000000 --- a/java/broker-plugins/firewall/src/main/java/org/apache/qpid/server/security/access/config/FirewallRule.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.access.config; - -import org.apache.qpid.server.security.Result; -import org.apache.qpid.util.NetMatcher; - -import java.net.InetAddress; -import java.util.List; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.FutureTask; -import java.util.concurrent.TimeUnit; -import java.util.regex.Pattern; - -public class FirewallRule -{ - public static final String ALLOW = "ALLOW"; - public static final String DENY = "DENY"; - - private static final long DNS_TIMEOUT = 30000; - private static final ExecutorService DNS_LOOKUP = Executors.newCachedThreadPool(); - - private Result _access; - private NetMatcher _network; - private Pattern[] _hostnamePatterns; - - public FirewallRule(String access, List networks, List hostnames) - { - _access = (access.equalsIgnoreCase(ALLOW)) ? Result.ALLOWED : Result.DENIED; - - if (networks != null && networks.size() > 0) - { - String[] networkStrings = objListToStringArray(networks); - _network = new NetMatcher(networkStrings); - } - - if (hostnames != null && hostnames.size() > 0) - { - int i = 0; - _hostnamePatterns = new Pattern[hostnames.size()]; - for (String hostname : objListToStringArray(hostnames)) - { - _hostnamePatterns[i++] = Pattern.compile(hostname); - } - } - } - - private String[] objListToStringArray(List objList) - { - String[] networkStrings = new String[objList.size()]; - int i = 0; - for (Object network : objList) - { - networkStrings[i++] = (String) network; - } - return networkStrings; - } - - public boolean match(InetAddress remote) throws FirewallException - { - if (_hostnamePatterns != null) - { - String hostname = getHostname(remote); - if (hostname == null) - { - throw new FirewallException("DNS lookup failed"); - } - for (Pattern pattern : _hostnamePatterns) - { - if (pattern.matcher(hostname).matches()) - { - return true; - } - } - return false; - } - else - { - return _network.matchInetNetwork(remote); - } - } - - /** - * @param remote the InetAddress to look up - * @return the hostname, null if not found, takes longer than 30s to find or otherwise fails - */ - private String getHostname(final InetAddress remote) throws FirewallException - { - FutureTask<String> lookup = new FutureTask<String>(new Callable<String>() - { - public String call() - { - return remote.getCanonicalHostName(); - } - }); - DNS_LOOKUP.execute(lookup); - - try - { - return lookup.get(DNS_TIMEOUT, TimeUnit.MILLISECONDS); - } - catch (Exception e) - { - return null; - } - finally - { - lookup.cancel(true); - } - } - - public Result getAccess() - { - return _access; - } -}
\ No newline at end of file diff --git a/java/broker-plugins/firewall/src/main/java/org/apache/qpid/server/security/access/plugins/Firewall.java b/java/broker-plugins/firewall/src/main/java/org/apache/qpid/server/security/access/plugins/Firewall.java deleted file mode 100644 index 40a65fddba..0000000000 --- a/java/broker-plugins/firewall/src/main/java/org/apache/qpid/server/security/access/plugins/Firewall.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.access.plugins; - -import org.apache.commons.configuration.Configuration; -import org.apache.commons.configuration.ConfigurationException; - -import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; -import org.apache.qpid.server.security.AbstractPlugin; -import org.apache.qpid.server.security.Result; -import org.apache.qpid.server.security.SecurityPluginFactory; -import org.apache.qpid.server.security.access.ObjectProperties; -import org.apache.qpid.server.security.access.ObjectType; -import org.apache.qpid.server.security.access.Operation; -import org.apache.qpid.server.security.access.config.FirewallException; -import org.apache.qpid.server.security.access.config.FirewallRule; - -import java.net.InetAddress; -import java.net.InetSocketAddress; - -public class Firewall extends AbstractPlugin -{ - public static final SecurityPluginFactory<Firewall> FACTORY = new SecurityPluginFactory<Firewall>() - { - public Firewall newInstance(ConfigurationPlugin config) throws ConfigurationException - { - FirewallConfiguration configuration = config.getConfiguration(FirewallConfiguration.class.getName()); - - // If there is no configuration for this plugin then don't load it. - if (configuration == null) - { - return null; - } - - Firewall plugin = new Firewall(); - plugin.configure(configuration); - return plugin; - } - - public Class<Firewall> getPluginClass() - { - return Firewall.class; - } - - public String getPluginName() - { - return Firewall.class.getName(); - } - }; - - private Result _default = Result.ABSTAIN; - private FirewallRule[] _rules; - - public Result getDefault() - { - return _default; - } - - public Result authorise(Operation operation, ObjectType objectType, ObjectProperties properties) - { - return Result.ABSTAIN; // We only deal with access requests - } - - public Result access(ObjectType objectType, Object instance) - { - if (objectType != ObjectType.VIRTUALHOST) - { - return Result.ABSTAIN; // We are only interested in access to virtualhosts - } - - if (!(instance instanceof InetSocketAddress)) - { - return Result.ABSTAIN; // We need an internet address - } - - InetAddress address = ((InetSocketAddress) instance).getAddress(); - - try - { - for (FirewallRule rule : _rules) - { - boolean match = rule.match(address); - if (match) - { - return rule.getAccess(); - } - } - return getDefault(); - } - catch (FirewallException fe) - { - return Result.DENIED; - } - } - - - public void configure(ConfigurationPlugin config) - { - super.configure(config); - FirewallConfiguration firewallConfiguration = (FirewallConfiguration) getConfig(); - - // Get default action - _default = firewallConfiguration.getDefaultAction(); - - Configuration finalConfig = firewallConfiguration.getConfiguration(); - - // all rules must have an access attribute - int numRules = finalConfig.getList("rule[@access]").size(); - _rules = new FirewallRule[numRules]; - for (int i = 0; i < numRules; i++) - { - FirewallRule rule = new FirewallRule(finalConfig.getString("rule(" + i + ")[@access]"), - finalConfig.getList("rule(" + i + ")[@network]"), - finalConfig.getList("rule(" + i + ")[@hostname]")); - _rules[i] = rule; - } - - } -} diff --git a/java/broker-plugins/firewall/src/main/java/org/apache/qpid/server/security/access/plugins/FirewallConfiguration.java b/java/broker-plugins/firewall/src/main/java/org/apache/qpid/server/security/access/plugins/FirewallConfiguration.java deleted file mode 100644 index 010d1652f0..0000000000 --- a/java/broker-plugins/firewall/src/main/java/org/apache/qpid/server/security/access/plugins/FirewallConfiguration.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.access.plugins; - -import org.apache.commons.configuration.CompositeConfiguration; -import org.apache.commons.configuration.Configuration; -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.configuration.plugins.ConfigurationPluginFactory; -import org.apache.qpid.server.security.Result; -import org.apache.qpid.server.security.access.config.FirewallRule; - -import java.util.Arrays; -import java.util.List; - -public class FirewallConfiguration extends ConfigurationPlugin -{ - private CompositeConfiguration _finalConfig; - - public static final ConfigurationPluginFactory FACTORY = new ConfigurationPluginFactory() - { - public ConfigurationPlugin newInstance(String path, Configuration config) throws ConfigurationException - { - ConfigurationPlugin instance = new FirewallConfiguration(); - instance.setConfiguration(path, config); - return instance; - } - - public List<String> getParentPaths() - { - return Arrays.asList("security.firewall", "virtualhosts.virtualhost.security.firewall"); - } - }; - - public String[] getElementsProcessed() - { - return new String[] { "" }; - } - - public Configuration getConfiguration() - { - return _finalConfig; - } - - public Result getDefaultAction() - { - String defaultAction = getConfig().getString("[@default-action]"); - if (defaultAction == null) - { - return Result.ABSTAIN; - } - else if (defaultAction.equalsIgnoreCase(FirewallRule.ALLOW)) - { - return Result.ALLOWED; - } - else - { - return Result.DENIED; - } - } - - - - @Override - public void validateConfiguration() throws ConfigurationException - { - // Valid Configuration either has xml links to new files - _finalConfig = new CompositeConfiguration(getConfig()); - List subFiles = getConfig().getList("xml[@fileName]"); - for (Object subFile : subFiles) - { - _finalConfig.addConfiguration(new XMLConfiguration((String) subFile)); - } - - // all rules must have an access attribute or a default value - if (_finalConfig.getList("rule[@access]").size() == 0 && - getConfig().getString("[@default-action]") == null) - { - throw new ConfigurationException("No rules or default-action found in firewall configuration."); - } - } - -} diff --git a/java/broker-plugins/firewall/src/test/java/org/apache/qpid/server/security/access/FirewallConfigurationTest.java b/java/broker-plugins/firewall/src/test/java/org/apache/qpid/server/security/access/FirewallConfigurationTest.java deleted file mode 100644 index 8969363979..0000000000 --- a/java/broker-plugins/firewall/src/test/java/org/apache/qpid/server/security/access/FirewallConfigurationTest.java +++ /dev/null @@ -1,322 +0,0 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.server.security.access; - -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.registry.ConfigurationFileApplicationRegistry; -import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.server.virtualhost.VirtualHostRegistry; -import org.apache.qpid.test.utils.QpidTestCase; - -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.io.RandomAccessFile; -import java.net.InetSocketAddress; - -public class FirewallConfigurationTest extends QpidTestCase -{ - @Override - protected void tearDown() throws Exception - { - super.tearDown(); - ApplicationRegistry.remove(); - } - - public void testFirewallConfiguration() throws Exception - { - // Write out config - File mainFile = File.createTempFile(getClass().getName(), null); - mainFile.deleteOnExit(); - writeConfigFile(mainFile, false); - - // Load config - ApplicationRegistry reg = new ConfigurationFileApplicationRegistry(mainFile); - ApplicationRegistry.initialise(reg); - - // Test config - assertFalse(reg.getSecurityManager().accessVirtualhost("test", new InetSocketAddress("127.0.0.1", 65535))); - assertTrue(reg.getSecurityManager().accessVirtualhost("test", new InetSocketAddress("127.1.2.3", 65535))); - } - - public void testCombinedConfigurationFirewall() throws Exception - { - // Write out config - File mainFile = File.createTempFile(getClass().getName(), null); - File fileA = File.createTempFile(getClass().getName(), null); - File fileB = File.createTempFile(getClass().getName(), null); - - mainFile.deleteOnExit(); - fileA.deleteOnExit(); - fileB.deleteOnExit(); - - FileWriter out = new FileWriter(mainFile); - out.write("<configuration><system/>"); - out.write("<xml fileName=\"" + fileA.getAbsolutePath() + "\"/>"); - out.write("</configuration>"); - out.close(); - - out = new FileWriter(fileA); - out.write("<broker>\n"); - out.write("\t<plugin-directory>${QPID_HOME}/lib/plugins</plugin-directory>\n"); - out.write("\t<cache-directory>${QPID_WORK}/cache</cache-directory>\n"); - out.write("\t<management><enabled>false</enabled></management>\n"); - out.write("\t<security>\n"); - out.write("\t\t<pd-auth-manager>\n"); - out.write("\t\t\t<principal-database>\n"); - out.write("\t\t\t\t<class>org.apache.qpid.server.security.auth.database.PlainPasswordFilePrincipalDatabase</class>\n"); - out.write("\t\t\t\t<attributes>\n"); - out.write("\t\t\t\t\t<attribute>\n"); - out.write("\t\t\t\t\t\t<name>passwordFile</name>\n"); - out.write("\t\t\t\t\t\t<value>/dev/null</value>\n"); - out.write("\t\t\t\t\t</attribute>\n"); - out.write("\t\t\t\t</attributes>\n"); - out.write("\t\t\t</principal-database>\n"); - out.write("\t\t</pd-auth-manager>\n"); - out.write("\t\t<firewall>\n"); - out.write("\t\t\t<xml fileName=\"" + fileB.getAbsolutePath() + "\"/>"); - out.write("\t\t</firewall>\n"); - out.write("\t</security>\n"); - out.write("\t<virtualhosts>\n"); - out.write("\t\t<virtualhost>\n"); - out.write("\t\t\t<name>test</name>\n"); - out.write("\t\t</virtualhost>\n"); - out.write("\t</virtualhosts>\n"); - out.write("</broker>\n"); - out.close(); - - out = new FileWriter(fileB); - out.write("<firewall>\n"); - out.write("\t<rule access=\"deny\" network=\"127.0.0.1\"/>"); - out.write("</firewall>\n"); - out.close(); - - // Load config - ApplicationRegistry reg = new ConfigurationFileApplicationRegistry(mainFile); - ApplicationRegistry.initialise(reg); - - // Test config - assertFalse(reg.getSecurityManager().accessVirtualhost("test", new InetSocketAddress("127.0.0.1", 65535))); - } - - public void testConfigurationFirewallReload() throws Exception - { - // Write out config - File mainFile = File.createTempFile(getClass().getName(), null); - - mainFile.deleteOnExit(); - writeConfigFile(mainFile, false); - - // Load config - ApplicationRegistry reg = new ConfigurationFileApplicationRegistry(mainFile); - ApplicationRegistry.initialise(reg); - - // Test config - assertFalse(reg.getSecurityManager().accessVirtualhost("test", new InetSocketAddress("127.0.0.1", 65535))); - - // Switch to deny the connection - writeConfigFile(mainFile, true); - - reg.getConfiguration().reparseConfigFileSecuritySections(); - - assertTrue(reg.getSecurityManager().accessVirtualhost("test", new InetSocketAddress("127.0.0.1", 65535))); - } - - public void testCombinedConfigurationFirewallReload() throws Exception - { - // Write out config - File mainFile = File.createTempFile(getClass().getName(), null); - File fileA = File.createTempFile(getClass().getName(), null); - File fileB = File.createTempFile(getClass().getName(), null); - - mainFile.deleteOnExit(); - fileA.deleteOnExit(); - fileB.deleteOnExit(); - - FileWriter out = new FileWriter(mainFile); - out.write("<configuration><system/>"); - out.write("<xml fileName=\"" + fileA.getAbsolutePath() + "\"/>"); - out.write("</configuration>"); - out.close(); - - out = new FileWriter(fileA); - out.write("<broker>\n"); - out.write("\t<plugin-directory>${QPID_HOME}/lib/plugins</plugin-directory>\n"); - out.write("\t<management><enabled>false</enabled></management>\n"); - out.write("\t<security>\n"); - out.write("\t\t<pd-auth-manager>\n"); - out.write("\t\t\t<principal-database>\n"); - out.write("\t\t\t\t<class>org.apache.qpid.server.security.auth.database.PlainPasswordFilePrincipalDatabase</class>\n"); - out.write("\t\t\t\t<attributes>\n"); - out.write("\t\t\t\t\t<attribute>\n"); - out.write("\t\t\t\t\t\t<name>passwordFile</name>\n"); - out.write("\t\t\t\t\t\t<value>/dev/null</value>\n"); - out.write("\t\t\t\t\t</attribute>\n"); - out.write("\t\t\t\t</attributes>\n"); - out.write("\t\t\t</principal-database>\n"); - out.write("\t\t</pd-auth-manager>\n"); - out.write("\t\t<firewall>\n"); - out.write("\t\t\t<xml fileName=\"" + fileB.getAbsolutePath() + "\"/>"); - out.write("\t\t</firewall>\n"); - out.write("\t</security>\n"); - out.write("\t<virtualhosts>\n"); - out.write("\t\t<virtualhost>\n"); - out.write("\t\t\t<name>test</name>\n"); - out.write("\t\t</virtualhost>\n"); - out.write("\t</virtualhosts>\n"); - out.write("</broker>\n"); - out.close(); - - out = new FileWriter(fileB); - out.write("<firewall>\n"); - out.write("\t<rule access=\"deny\" network=\"127.0.0.1\"/>"); - out.write("</firewall>\n"); - out.close(); - - // Load config - ApplicationRegistry reg = new ConfigurationFileApplicationRegistry(mainFile); - ApplicationRegistry.initialise(reg); - - // Test config - assertFalse(reg.getSecurityManager().accessVirtualhost("test", new InetSocketAddress("127.0.0.1", 65535))); - - RandomAccessFile fileBRandom = new RandomAccessFile(fileB, "rw"); - fileBRandom.setLength(0); - fileBRandom.seek(0); - fileBRandom.close(); - - out = new FileWriter(fileB); - out.write("<firewall>\n"); - out.write("\t<rule access=\"allow\" network=\"127.0.0.1\"/>"); - out.write("</firewall>\n"); - out.close(); - - reg.getConfiguration().reparseConfigFileSecuritySections(); - - assertTrue(reg.getSecurityManager().accessVirtualhost("test", new InetSocketAddress("127.0.0.1", 65535))); - - fileBRandom = new RandomAccessFile(fileB, "rw"); - fileBRandom.setLength(0); - fileBRandom.seek(0); - fileBRandom.close(); - - out = new FileWriter(fileB); - out.write("<firewall>\n"); - out.write("\t<rule access=\"deny\" network=\"127.0.0.1\"/>"); - out.write("</firewall>\n"); - out.close(); - - reg.getConfiguration().reparseConfigFileSecuritySections(); - - assertFalse(reg.getSecurityManager().accessVirtualhost("test", new InetSocketAddress("127.0.0.1", 65535))); - } - - private void writeFirewallVhostsFile(File vhostsFile, boolean allow) throws IOException - { - FileWriter out = new FileWriter(vhostsFile); - String ipAddr = "127.0.0.1"; // FIXME: get this from InetAddress.getLocalHost().getAddress() ? - out.write("<virtualhosts><virtualhost>"); - out.write("<name>test</name>"); - out.write("<test>"); - out.write("<security><firewall>"); - out.write("<rule access=\""+((allow) ? "allow" : "deny")+"\" network=\""+ipAddr +"\"/>"); - out.write("</firewall></security>"); - out.write("</test>"); - out.write("</virtualhost></virtualhosts>"); - out.close(); - } - - private void writeConfigFile(File mainFile, boolean allow) throws IOException { - writeConfigFile(mainFile, allow, true, null, "test"); - } - - /* - XMLConfiguration config = new XMLConfiguration(mainFile); - PluginManager pluginManager = new MockPluginManager(""); - SecurityManager manager = new SecurityManager(config, pluginManager, Firewall.FACTORY); - - */ - private void writeConfigFile(File mainFile, boolean allow, boolean includeVhosts, File vhostsFile, String name) throws IOException { - FileWriter out = new FileWriter(mainFile); - out.write("<broker>\n"); - out.write("\t<plugin-directory>${QPID_HOME}/lib/plugins</plugin-directory>\n"); - out.write("\t<management><enabled>false</enabled></management>\n"); - out.write("\t<security>\n"); - out.write("\t\t<pd-auth-manager>\n"); - out.write("\t\t\t<principal-database>\n"); - out.write("\t\t\t\t<class>org.apache.qpid.server.security.auth.database.PlainPasswordFilePrincipalDatabase</class>\n"); - out.write("\t\t\t\t<attributes>\n"); - out.write("\t\t\t\t\t<attribute>\n"); - out.write("\t\t\t\t\t\t<name>passwordFile</name>\n"); - out.write("\t\t\t\t\t\t<value>/dev/null</value>\n"); - out.write("\t\t\t\t\t</attribute>\n"); - out.write("\t\t\t\t</attributes>\n"); - out.write("\t\t\t</principal-database>\n"); - out.write("\t\t</pd-auth-manager>\n"); - out.write("\t\t<firewall>\n"); - out.write("\t\t\t<rule access=\""+ ((allow) ? "allow" : "deny") +"\" network=\"127.0.0.1\"/>"); - out.write("\t\t</firewall>\n"); - out.write("\t</security>\n"); - if (includeVhosts) - { - out.write("\t<virtualhosts>\n"); - out.write("\t\t<default>test</default>\n"); - out.write("\t\t<virtualhost>\n"); - out.write(String.format("\t\t\t<name>%s</name>\n", name)); - out.write("\t\t</virtualhost>\n"); - out.write("\t</virtualhosts>\n"); - } - if (vhostsFile != null) - { - out.write("\t<virtualhosts>"+vhostsFile.getAbsolutePath()+"</virtualhosts>\n"); - } - out.write("</broker>\n"); - out.close(); - } - - /** - * Test that configuration loads correctly when virtual hosts are specified in an external - * configuration file only. - * <p> - * Test for QPID-2360 - */ - public void testExternalFirewallVirtualhostXMLFile() throws Exception - { - // Write out config - File mainFile = File.createTempFile(getClass().getName(), "config"); - mainFile.deleteOnExit(); - File vhostsFile = File.createTempFile(getClass().getName(), "vhosts"); - vhostsFile.deleteOnExit(); - writeConfigFile(mainFile, false, false, vhostsFile, null); - writeFirewallVhostsFile(vhostsFile, false); - - // Load config - ApplicationRegistry reg = new ConfigurationFileApplicationRegistry(mainFile); - ApplicationRegistry.initialise(reg); - - // Test config - VirtualHostRegistry virtualHostRegistry = reg.getVirtualHostRegistry(); - VirtualHost virtualHost = virtualHostRegistry.getVirtualHost("test"); - - assertEquals("Incorrect virtualhost count", 1, virtualHostRegistry.getVirtualHosts().size()); - assertEquals("Incorrect virtualhost name", "test", virtualHost.getName()); - } -} diff --git a/java/broker-plugins/firewall/src/test/java/org/apache/qpid/server/security/access/FirewallPluginTest.java b/java/broker-plugins/firewall/src/test/java/org/apache/qpid/server/security/access/FirewallPluginTest.java deleted file mode 100644 index 2004852c48..0000000000 --- a/java/broker-plugins/firewall/src/test/java/org/apache/qpid/server/security/access/FirewallPluginTest.java +++ /dev/null @@ -1,294 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.qpid.server.security.access; - -import org.apache.commons.configuration.ConfigurationException; -import org.apache.commons.configuration.XMLConfiguration; - -import org.apache.qpid.server.configuration.ServerConfiguration; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.security.Result; -import org.apache.qpid.server.security.access.plugins.Firewall; -import org.apache.qpid.server.security.access.plugins.FirewallConfiguration; -import org.apache.qpid.server.util.TestApplicationRegistry; -import org.apache.qpid.test.utils.QpidTestCase; - -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.net.InetSocketAddress; -import java.net.SocketAddress; - -public class FirewallPluginTest extends QpidTestCase -{ - public class RuleInfo - { - private String _access; - private String _network; - private String _hostname; - - public void setAccess(String _access) - { - this._access = _access; - } - - public String getAccess() - { - return _access; - } - - public void setNetwork(String _network) - { - this._network = _network; - } - - public String getNetwork() - { - return _network; - } - - public void setHostname(String _hostname) - { - this._hostname = _hostname; - } - - public String getHostname() - { - return _hostname; - } - } - - // IP address - private SocketAddress _address; - private ServerConfiguration _serverConfig; - - @Override - protected void setUp() throws Exception - { - super.setUp(); - _serverConfig = new ServerConfiguration(new XMLConfiguration()); - ApplicationRegistry.initialise(new TestApplicationRegistry(_serverConfig)); - _address = new InetSocketAddress("127.0.0.1", 65535); - } - - @Override - protected void tearDown() throws Exception - { - super.tearDown(); - ApplicationRegistry.remove(); - } - private Firewall initialisePlugin(String defaultAction, RuleInfo[] rules) throws IOException, ConfigurationException - { - // Create sample config file - File confFile = File.createTempFile(getClass().getSimpleName()+"conffile", null); - confFile.deleteOnExit(); - BufferedWriter buf = new BufferedWriter(new FileWriter(confFile)); - buf.write("<firewall default-action=\""+defaultAction+"\">\n"); - if (rules != null) - { - for (RuleInfo rule : rules) - { - buf.write("<rule"); - buf.write(" access=\""+rule.getAccess()+"\""); - if (rule.getHostname() != null) - { - buf.write(" hostname=\""+rule.getHostname()+"\""); - } - if (rule.getNetwork() != null) - { - buf.write(" network=\""+rule.getNetwork()+"\""); - } - buf.write("/>\n"); - } - } - buf.write("</firewall>"); - buf.close(); - - // Configure plugin - FirewallConfiguration config = new FirewallConfiguration(); - config.setConfiguration("", new XMLConfiguration(confFile)); - Firewall plugin = new Firewall(); - plugin.configure(config); - return plugin; - } - - private Firewall initialisePlugin(String string) throws ConfigurationException, IOException - { - return initialisePlugin(string, null); - } - - public void testDefaultAction() throws Exception - { - // Test simple deny - Firewall plugin = initialisePlugin("deny"); - assertEquals(Result.DENIED, plugin.access(ObjectType.VIRTUALHOST, _address)); - - // Test simple allow - plugin = initialisePlugin("allow"); - assertEquals(Result.ALLOWED, plugin.access(ObjectType.VIRTUALHOST, _address)); - } - - - public void testSingleIPRule() throws Exception - { - RuleInfo rule = new RuleInfo(); - rule.setAccess("allow"); - rule.setNetwork("192.168.23.23"); - - Firewall plugin = initialisePlugin("deny", new RuleInfo[]{rule}); - - assertEquals(Result.DENIED, plugin.access(ObjectType.VIRTUALHOST, _address)); - - // Set IP so that we're connected from the right address - _address = new InetSocketAddress("192.168.23.23", 65535); - assertEquals(Result.ALLOWED, plugin.access(ObjectType.VIRTUALHOST, _address)); - } - - public void testSingleNetworkRule() throws Exception - { - RuleInfo rule = new RuleInfo(); - rule.setAccess("allow"); - rule.setNetwork("192.168.23.0/24"); - - Firewall plugin = initialisePlugin("deny", new RuleInfo[]{rule}); - - assertEquals(Result.DENIED, plugin.access(ObjectType.VIRTUALHOST, _address)); - - // Set IP so that we're connected from the right address - _address = new InetSocketAddress("192.168.23.23", 65535); - assertEquals(Result.ALLOWED, plugin.access(ObjectType.VIRTUALHOST, _address)); - } - - public void testSingleHostRule() throws Exception - { - RuleInfo rule = new RuleInfo(); - rule.setAccess("allow"); - rule.setHostname(new InetSocketAddress("127.0.0.1", 5672).getHostName()); - - Firewall plugin = initialisePlugin("deny", new RuleInfo[]{rule}); - - // Set IP so that we're connected from the right address - _address = new InetSocketAddress("127.0.0.1", 65535); - assertEquals(Result.ALLOWED, plugin.access(ObjectType.VIRTUALHOST, _address)); - } - - public void testSingleHostWilcardRule() throws Exception - { - RuleInfo rule = new RuleInfo(); - rule.setAccess("allow"); - String hostname = new InetSocketAddress("127.0.0.1", 0).getHostName(); - rule.setHostname(".*"+hostname.subSequence(hostname.length() - 1, hostname.length())+"*"); - Firewall plugin = initialisePlugin("deny", new RuleInfo[]{rule}); - - // Set IP so that we're connected from the right address - _address = new InetSocketAddress("127.0.0.1", 65535); - assertEquals(Result.ALLOWED, plugin.access(ObjectType.VIRTUALHOST, _address)); - } - - public void testSeveralFirstAllowsAccess() throws Exception - { - RuleInfo firstRule = new RuleInfo(); - firstRule.setAccess("allow"); - firstRule.setNetwork("192.168.23.23"); - - RuleInfo secondRule = new RuleInfo(); - secondRule.setAccess("deny"); - secondRule.setNetwork("192.168.42.42"); - - RuleInfo thirdRule = new RuleInfo(); - thirdRule.setAccess("deny"); - thirdRule.setHostname("localhost"); - - Firewall plugin = initialisePlugin("deny", new RuleInfo[]{firstRule, secondRule, thirdRule}); - - assertEquals(Result.DENIED, plugin.access(ObjectType.VIRTUALHOST, _address)); - - // Set IP so that we're connected from the right address - _address = new InetSocketAddress("192.168.23.23", 65535); - assertEquals(Result.ALLOWED, plugin.access(ObjectType.VIRTUALHOST, _address)); - } - - public void testSeveralLastAllowsAccess() throws Exception - { - RuleInfo firstRule = new RuleInfo(); - firstRule.setAccess("deny"); - firstRule.setHostname("localhost"); - - RuleInfo secondRule = new RuleInfo(); - secondRule.setAccess("deny"); - secondRule.setNetwork("192.168.42.42"); - - RuleInfo thirdRule = new RuleInfo(); - thirdRule.setAccess("allow"); - thirdRule.setNetwork("192.168.23.23"); - - Firewall plugin = initialisePlugin("deny", new RuleInfo[]{firstRule, secondRule, thirdRule}); - - assertEquals(Result.DENIED, plugin.access(ObjectType.VIRTUALHOST, _address)); - - // Set IP so that we're connected from the right address - _address = new InetSocketAddress("192.168.23.23", 65535); - assertEquals(Result.ALLOWED, plugin.access(ObjectType.VIRTUALHOST, _address)); - } - - public void testNetmask() throws Exception - { - RuleInfo firstRule = new RuleInfo(); - firstRule.setAccess("allow"); - firstRule.setNetwork("192.168.23.0/24"); - Firewall plugin = initialisePlugin("deny", new RuleInfo[]{firstRule}); - - assertEquals(Result.DENIED, plugin.access(ObjectType.VIRTUALHOST, _address)); - - // Set IP so that we're connected from the right address - _address = new InetSocketAddress("192.168.23.23", 65535); - assertEquals(Result.ALLOWED, plugin.access(ObjectType.VIRTUALHOST, _address)); - } - - public void testCommaSeperatedNetmask() throws Exception - { - RuleInfo firstRule = new RuleInfo(); - firstRule.setAccess("allow"); - firstRule.setNetwork("10.1.1.1/8, 192.168.23.0/24"); - Firewall plugin = initialisePlugin("deny", new RuleInfo[]{firstRule}); - - assertEquals(Result.DENIED, plugin.access(ObjectType.VIRTUALHOST, _address)); - - // Set IP so that we're connected from the right address - _address = new InetSocketAddress("192.168.23.23", 65535); - assertEquals(Result.ALLOWED, plugin.access(ObjectType.VIRTUALHOST, _address)); - } - - public void testCommaSeperatedHostnames() throws Exception - { - RuleInfo firstRule = new RuleInfo(); - firstRule.setAccess("allow"); - firstRule.setHostname("foo, bar, "+new InetSocketAddress("127.0.0.1", 5672).getHostName()); - Firewall plugin = initialisePlugin("deny", new RuleInfo[]{firstRule}); - - // Set IP so that we're connected from the right address - _address = new InetSocketAddress("10.0.0.1", 65535); - assertEquals(Result.DENIED, plugin.access(ObjectType.VIRTUALHOST, _address)); - - // Set IP so that we're connected from the right address - _address = new InetSocketAddress("127.0.0.1", 65535); - assertEquals(Result.ALLOWED, plugin.access(ObjectType.VIRTUALHOST, _address)); - } -} diff --git a/java/broker-plugins/management-http/MANIFEST.MF b/java/broker-plugins/management-http/MANIFEST.MF deleted file mode 100644 index cca10d3f89..0000000000 --- a/java/broker-plugins/management-http/MANIFEST.MF +++ /dev/null @@ -1,70 +0,0 @@ -Manifest-Version: 1.0 -Bundle-ManifestVersion: 2 -Bundle-Name: Qpid Broker-Plugins Management HTTP -Bundle-SymbolicName: broker-plugins-management-http -Bundle-Description: HTTP management plugin for Qpid. -Bundle-License: http://www.apache.org/licenses/LICENSE-2.0.txt -Bundle-DocURL: http://www.apache.org/ -Bundle-Version: 1.0.0 -Bundle-Activator: org.apache.qpid.server.management.plugin.ManagementActivator -Bundle-RequiredExecutionEnvironment: JavaSE-1.6 -Bundle-ClassPath: . -Bundle-ActivationPolicy: lazy -Import-Package: org.apache.qpid, - org.apache.qpid.framing, - org.apache.qpid.protocol, - org.apache.qpid.common, - org.apache.qpid.server.security.auth, - org.apache.qpid.server.security.auth.manager, - org.apache.qpid.server.security.auth.sasl, - org.apache.qpid.server.binding, - org.apache.qpid.server.exchange, - org.apache.qpid.server.logging, - org.apache.qpid.server.message, - org.apache.qpid.server.model, - org.apache.qpid.server.model.adapter, - org.apache.qpid.server.model.impl, - org.apache.qpid.server.configuration, - org.apache.qpid.server.configuration.plugins, - org.apache.qpid.server.connection, - org.apache.qpid.server.plugins, - org.apache.qpid.server.protocol, - org.apache.qpid.server.queue, - org.apache.qpid.server.subscription, - org.apache.qpid.server.registry, - org.apache.qpid.server.security, - org.apache.qpid.server.security.access, - org.apache.qpid.server.stats, - org.apache.qpid.server.virtualhost, - org.apache.qpid.util, - org.eclipse.jetty.server;version=7.6.3, - org.eclipse.jetty.server.session;version=7.6.3, - org.eclipse.jetty.server.ssl;version=7.6.3, - org.eclipse.jetty.server.nio;version=7.6.3, - org.eclipse.jetty.security;version=7.6.3, - org.eclipse.jetty.http;version=7.6.3, - org.eclipse.jetty.io;version=7.6.3, - org.eclipse.jetty.io.nio;version=7.6.3, - org.eclipse.jetty.servlet;version=7.6.3, - org.eclipse.jetty.util.ssl;version=7.6.3, - org.apache.commons.codec;version=1.3.0, - org.apache.commons.codec.binary;version=1.3.0, - org.apache.commons.configuration;version=1.0.0, - org.apache.commons.lang;version=1.0.0, - org.apache.commons.lang.builder;version=1.0.0, - org.apache.log4j;version=1.0.0, - org.codehaus.jackson;version=1.9.0, - org.codehaus.jackson.map;version=1.9.0, - javax.crypto, - javax.crypto.spec, - javax.security.auth, - javax.security.auth.callback, - javax.security.sasl, - javax.servlet, - javax.servlet.http, - javax.management;version=1.0.0, - javax.management.openmbean;version=1.0.0, - org.osgi.util.tracker;version=1.0.0, - org.osgi.framework;version=1.3 -Private-Package: org.apache.qpid.server.management.plugin.impl -Export-Package: org.apache.qpid.server.management.plugin;uses:="org.osgi.framework" diff --git a/java/broker-plugins/management-http/build.xml b/java/broker-plugins/management-http/build.xml index b792cb292e..abf35d9c88 100644 --- a/java/broker-plugins/management-http/build.xml +++ b/java/broker-plugins/management-http/build.xml @@ -18,39 +18,36 @@ --> <project name="Qpid Broker-Plugins Management HTTP" default="build"> - <condition property="systests.optional.depends" value="bdbstore" else=""> - <or> - <and> - <contains string="${modules.opt}" substring="bdbstore"/> - <contains string="${profile}" substring="bdb"/> - </and> - <and> - <istrue value="${optional}"/> - <contains string="${profile}" substring="bdb"/> - </and> - </or> - </condition> - <property name="module.depends" value="common broker" /> - <property name="module.test.depends" value="systests test broker/test common/test management/common client ${systests.optional.depends}" /> + <property name="module.test.depends" value="broker/tests common/tests management/common client" /> + + <property name="module.genpom" value="true" /> + <property name="module.genpom.args" value="-Sqpid-common=provided -Sqpid-broker=provided" /> - <property name="module.manifest" value="MANIFEST.MF" /> - <property name="module.plugin" value="true" /> - <property name="module.genpom" value="true"/> - <property name="module.genpom.args" value="-Sqpid-common=provided -Sqpid-broker=provided"/> + <property name="broker.plugin" value="true"/> - <property name="broker-plugins-management-http.libs" value=""/> + <property name="broker-plugins-management-http.libs" value="" /> <import file="../../module.xml" /> - <target name="precompile"> - <unwar src="${project.root}/${dojo}" dest="${module.classes}/resources/dojo"> - <patternset> - <exclude name="META-INF/**"/> - <exclude name="WEB-INF/**"/> - <exclude name="**/*.uncompressed.js"/> - </patternset> - </unwar> + <!-- Flagfile used to determine if uwar needs to be done. ._ is part of Ant's defaultexcludes so wont appear bundles --> + <property name="dojo.uptodate.flagfile" value="${module.classes}/resources/dojo/._dojouptodate.timestamp" /> + + <target name="precompile" depends="unwardojo" /> + + <target name="unwardojo" depends="check-unwardojo.done" unless="unwardojo.done"> + <unwar src="${project.root}/${dojo}" dest="${module.classes}/resources/dojo"> + <patternset> + <exclude name="META-INF/**" /> + <exclude name="WEB-INF/**" /> + <exclude name="**/*.uncompressed.js" /> + </patternset> + </unwar> + <touch file="${dojo.uptodate.flagfile}" /> + </target> + + <target name="check-unwardojo.done"> + <uptodate property="unwardojo.done" targetfile="${dojo.uptodate.flagfile}" srcfile="${project.root}/${dojo}" /> </target> <target name="bundle" depends="bundle-tasks" /> diff --git a/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java b/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java new file mode 100644 index 0000000000..c2ac675e20 --- /dev/null +++ b/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java @@ -0,0 +1,416 @@ +/* + * + * 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; + +import java.io.File; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.UUID; + +import org.apache.log4j.Logger; +import org.apache.qpid.server.configuration.IllegalConfigurationException; +import org.apache.qpid.server.logging.actors.CurrentActor; +import org.apache.qpid.server.logging.messages.ManagementConsoleMessages; +import org.apache.qpid.server.management.plugin.servlet.DefinedFileServlet; +import org.apache.qpid.server.management.plugin.servlet.FileServlet; +import org.apache.qpid.server.management.plugin.servlet.rest.AbstractServlet; +import org.apache.qpid.server.management.plugin.servlet.rest.LogRecordsServlet; +import org.apache.qpid.server.management.plugin.servlet.rest.LogoutServlet; +import org.apache.qpid.server.management.plugin.servlet.rest.MessageContentServlet; +import org.apache.qpid.server.management.plugin.servlet.rest.MessageServlet; +import org.apache.qpid.server.management.plugin.servlet.rest.RestServlet; +import org.apache.qpid.server.management.plugin.servlet.rest.SaslServlet; +import org.apache.qpid.server.management.plugin.servlet.rest.StructureServlet; +import org.apache.qpid.server.model.AuthenticationProvider; +import org.apache.qpid.server.model.Binding; +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.KeyStore; +import org.apache.qpid.server.model.Plugin; +import org.apache.qpid.server.model.Port; +import org.apache.qpid.server.model.Protocol; +import org.apache.qpid.server.model.Queue; +import org.apache.qpid.server.model.Session; +import org.apache.qpid.server.model.State; +import org.apache.qpid.server.model.User; +import org.apache.qpid.server.model.VirtualHost; +import org.apache.qpid.server.model.adapter.AbstractPluginAdapter; +import org.apache.qpid.server.plugin.PluginFactory; +import org.apache.qpid.server.util.MapValueConverter; +import org.eclipse.jetty.server.Connector; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.SessionManager; +import org.eclipse.jetty.server.nio.SelectChannelConnector; +import org.eclipse.jetty.server.ssl.SslSocketConnector; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.eclipse.jetty.util.ssl.SslContextFactory; + +public class HttpManagement extends AbstractPluginAdapter +{ + private final Logger _logger = Logger.getLogger(HttpManagement.class); + + // 10 minutes by default + public static final int DEFAULT_TIMEOUT_IN_SECONDS = 60 * 10; + public static final boolean DEFAULT_HTTP_BASIC_AUTHENTICATION_ENABLED = false; + public static final boolean DEFAULT_HTTPS_BASIC_AUTHENTICATION_ENABLED = true; + public static final boolean DEFAULT_HTTP_SASL_AUTHENTICATION_ENABLED = true; + public static final boolean DEFAULT_HTTPS_SASL_AUTHENTICATION_ENABLED = true; + public static final String DEFAULT_NAME = "httpManagement"; + + public static final String TIME_OUT = "sessionTimeout"; + public static final String HTTP_BASIC_AUTHENTICATION_ENABLED = "httpBasicAuthenticationEnabled"; + public static final String HTTPS_BASIC_AUTHENTICATION_ENABLED = "httpsBasicAuthenticationEnabled"; + public static final String HTTP_SASL_AUTHENTICATION_ENABLED = "httpSaslAuthenticationEnabled"; + public static final String HTTPS_SASL_AUTHENTICATION_ENABLED = "httpsSaslAuthenticationEnabled"; + + public static final String PLUGIN_TYPE = "MANAGEMENT-HTTP"; + + @SuppressWarnings("serial") + private static final Collection<String> AVAILABLE_ATTRIBUTES = Collections.unmodifiableSet(new HashSet<String>(Plugin.AVAILABLE_ATTRIBUTES) + {{ + add(HTTP_BASIC_AUTHENTICATION_ENABLED); + add(HTTPS_BASIC_AUTHENTICATION_ENABLED); + add(HTTP_SASL_AUTHENTICATION_ENABLED); + add(HTTPS_SASL_AUTHENTICATION_ENABLED); + add(TIME_OUT); + add(PluginFactory.PLUGIN_TYPE); + }}); + + public static final String ENTRY_POINT_PATH = "/management"; + + private static final String OPERATIONAL_LOGGING_NAME = "Web"; + + + @SuppressWarnings("serial") + public static final Map<String, Object> DEFAULTS = Collections.unmodifiableMap(new HashMap<String, Object>() + {{ + put(HTTP_BASIC_AUTHENTICATION_ENABLED, DEFAULT_HTTP_BASIC_AUTHENTICATION_ENABLED); + put(HTTPS_BASIC_AUTHENTICATION_ENABLED, DEFAULT_HTTPS_BASIC_AUTHENTICATION_ENABLED); + put(HTTP_SASL_AUTHENTICATION_ENABLED, DEFAULT_HTTP_SASL_AUTHENTICATION_ENABLED); + put(HTTPS_SASL_AUTHENTICATION_ENABLED, DEFAULT_HTTPS_SASL_AUTHENTICATION_ENABLED); + put(TIME_OUT, DEFAULT_TIMEOUT_IN_SECONDS); + put(NAME, DEFAULT_NAME); + }}); + + @SuppressWarnings("serial") + private static final Map<String, Class<?>> ATTRIBUTE_TYPES = Collections.unmodifiableMap(new HashMap<String, Class<?>>(){{ + put(HTTP_BASIC_AUTHENTICATION_ENABLED, Boolean.class); + put(HTTPS_BASIC_AUTHENTICATION_ENABLED, Boolean.class); + put(HTTP_SASL_AUTHENTICATION_ENABLED, Boolean.class); + put(HTTPS_SASL_AUTHENTICATION_ENABLED, Boolean.class); + put(NAME, String.class); + put(TIME_OUT, Integer.class); + put(PluginFactory.PLUGIN_TYPE, String.class); + }}); + + private final Broker _broker; + + private Server _server; + + public HttpManagement(UUID id, Broker broker, Map<String, Object> attributes) + { + super(id, DEFAULTS, MapValueConverter.convert(attributes, ATTRIBUTE_TYPES), broker.getTaskExecutor()); + _broker = broker; + addParent(Broker.class, broker); + } + + @Override + protected boolean setState(State currentState, State desiredState) + { + if(desiredState == State.ACTIVE) + { + start(); + return true; + } + else if(desiredState == State.STOPPED) + { + stop(); + return true; + } + return false; + } + + private void start() + { + CurrentActor.get().message(ManagementConsoleMessages.STARTUP(OPERATIONAL_LOGGING_NAME)); + + Collection<Port> httpPorts = getHttpPorts(_broker.getPorts()); + _server = createServer(httpPorts); + try + { + _server.start(); + logOperationalListenMessages(_server); + } + catch (Exception e) + { + throw new RuntimeException("Failed to start http management on ports " + httpPorts); + } + + CurrentActor.get().message(ManagementConsoleMessages.READY(OPERATIONAL_LOGGING_NAME)); + } + + private void stop() + { + if (_server != null) + { + try + { + _server.stop(); + logOperationalShutdownMessage(_server); + } + catch (Exception e) + { + throw new RuntimeException("Failed to stop http management on port " + getHttpPorts(_broker.getPorts())); + } + } + + CurrentActor.get().message(ManagementConsoleMessages.STOPPED(OPERATIONAL_LOGGING_NAME)); + } + + /** Added for testing purposes */ + Broker getBroker() + { + return _broker; + } + + /** Added for testing purposes */ + int getSessionTimeout() + { + return (Integer)getAttribute(TIME_OUT); + } + + private boolean isManagementHttp(Port port) + { + return port.getProtocols().contains(Protocol.HTTP) || port.getProtocols().contains(Protocol.HTTPS); + } + + @SuppressWarnings("unchecked") + private Server createServer(Collection<Port> ports) + { + if (_logger.isInfoEnabled()) + { + _logger.info("Starting up web server on " + ports); + } + + Server server = new Server(); + for (Port port : ports) + { + if (State.QUIESCED.equals(port.getActualState())) + { + continue; + } + final Collection<Protocol> protocols = port.getProtocols(); + Connector connector = null; + + //TODO: what to do if protocol HTTP and transport SSL? + if (protocols.contains(Protocol.HTTP)) + { + connector = new SelectChannelConnector(); + } + else if (protocols.contains(Protocol.HTTPS)) + { + KeyStore keyStore = _broker.getDefaultKeyStore(); + if (keyStore == null) + { + throw new IllegalConfigurationException("Key store is not configured. Cannot start management on HTTPS port without keystore"); + } + String keyStorePath = (String)keyStore.getAttribute(KeyStore.PATH); + String keyStorePassword = keyStore.getPassword(); + validateKeystoreParameters(keyStorePath, keyStorePassword); + + SslContextFactory factory = new SslContextFactory(); + factory.setKeyStorePath(keyStorePath); + factory.setKeyStorePassword(keyStorePassword); + + connector = new SslSocketConnector(factory); + } + else + { + throw new IllegalArgumentException("Unexpected protocol " + protocols); + } + connector.setPort(port.getPort()); + server.addConnector(connector); + } + + ServletContextHandler root = new ServletContextHandler(ServletContextHandler.SESSIONS); + root.setContextPath("/"); + server.setHandler(root); + + // set servlet context attributes for broker and configuration + root.getServletContext().setAttribute(AbstractServlet.ATTR_BROKER, _broker); + root.getServletContext().setAttribute(AbstractServlet.ATTR_MANAGEMENT, this); + + addRestServlet(root, "broker"); + 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); + addRestServlet(root, "binding", VirtualHost.class, Exchange.class, Queue.class, Binding.class); + addRestServlet(root, "port", Port.class); + addRestServlet(root, "session", VirtualHost.class, Connection.class, Session.class); + + root.addServlet(new ServletHolder(new StructureServlet()), "/rest/structure"); + root.addServlet(new ServletHolder(new MessageServlet()), "/rest/message/*"); + root.addServlet(new ServletHolder(new MessageContentServlet()), "/rest/message-content/*"); + + root.addServlet(new ServletHolder(new LogRecordsServlet()), "/rest/logrecords"); + + root.addServlet(new ServletHolder(new SaslServlet()), "/rest/sasl"); + + root.addServlet(new ServletHolder(new DefinedFileServlet("index.html")), ENTRY_POINT_PATH); + root.addServlet(new ServletHolder(new LogoutServlet()), "/logout"); + + root.addServlet(new ServletHolder(FileServlet.INSTANCE), "*.js"); + root.addServlet(new ServletHolder(FileServlet.INSTANCE), "*.css"); + root.addServlet(new ServletHolder(FileServlet.INSTANCE), "*.html"); + root.addServlet(new ServletHolder(FileServlet.INSTANCE), "*.png"); + root.addServlet(new ServletHolder(FileServlet.INSTANCE), "*.gif"); + root.addServlet(new ServletHolder(FileServlet.INSTANCE), "*.jpg"); + root.addServlet(new ServletHolder(FileServlet.INSTANCE), "*.jpeg"); + root.addServlet(new ServletHolder(FileServlet.INSTANCE), "*.json"); + root.addServlet(new ServletHolder(FileServlet.INSTANCE), "*.txt"); + root.addServlet(new ServletHolder(FileServlet.INSTANCE), "*.xsl"); + + final SessionManager sessionManager = root.getSessionHandler().getSessionManager(); + + sessionManager.setMaxInactiveInterval((Integer)getAttribute(TIME_OUT)); + + return server; + } + + private void addRestServlet(ServletContextHandler root, String name, Class<? extends ConfiguredObject>... hierarchy) + { + root.addServlet(new ServletHolder(new RestServlet(hierarchy)), "/rest/" + name + "/*"); + } + + private void validateKeystoreParameters(String keyStorePath, String password) + { + if (keyStorePath == null) + { + throw new RuntimeException("Management SSL keystore path not defined, unable to start SSL protected HTTP connector"); + } + if (password == null) + { + throw new RuntimeException("Management SSL keystore password, unable to start SSL protected HTTP connector"); + } + File ksf = new File(keyStorePath); + if (!ksf.exists()) + { + throw new RuntimeException("Cannot find management SSL keystore file: " + ksf); + } + if (!ksf.canRead()) + { + throw new RuntimeException("Cannot read management SSL keystore file: " + ksf + ". Check permissions."); + } + } + + private void logOperationalListenMessages(Server server) + { + Connector[] connectors = server.getConnectors(); + for (Connector connector : connectors) + { + CurrentActor.get().message(ManagementConsoleMessages.LISTENING(stringifyConnectorScheme(connector), connector.getPort())); + if (connector instanceof SslSocketConnector) + { + SslContextFactory sslContextFactory = ((SslSocketConnector)connector).getSslContextFactory(); + if (sslContextFactory != null && sslContextFactory.getKeyStorePath() != null) + { + CurrentActor.get().message(ManagementConsoleMessages.SSL_KEYSTORE(sslContextFactory.getKeyStorePath())); + } + } + } + } + + private void logOperationalShutdownMessage(Server server) + { + Connector[] connectors = server.getConnectors(); + for (Connector connector : connectors) + { + CurrentActor.get().message(ManagementConsoleMessages.SHUTTING_DOWN(stringifyConnectorScheme(connector), connector.getPort())); + } + } + + private String stringifyConnectorScheme(Connector connector) + { + return connector instanceof SslSocketConnector ? "HTTPS" : "HTTP"; + } + + private Collection<Port> getHttpPorts(Collection<Port> ports) + { + Collection<Port> httpPorts = new HashSet<Port>(); + for (Port port : ports) + { + if (isManagementHttp(port)) + { + httpPorts.add(port); + } + } + return httpPorts; + } + + + @Override + public String getName() + { + return (String)getAttribute(NAME); + } + + @Override + public Collection<String> getAttributeNames() + { + return Collections.unmodifiableCollection(AVAILABLE_ATTRIBUTES); + } + + public boolean isHttpsSaslAuthenticationEnabled() + { + return (Boolean)getAttribute(HTTPS_SASL_AUTHENTICATION_ENABLED); + } + + public boolean isHttpSaslAuthenticationEnabled() + { + return (Boolean)getAttribute(HTTP_SASL_AUTHENTICATION_ENABLED); + } + + public boolean isHttpsBasicAuthenticationEnabled() + { + return (Boolean)getAttribute(HTTPS_BASIC_AUTHENTICATION_ENABLED); + } + + public boolean isHttpBasicAuthenticationEnabled() + { + return (Boolean)getAttribute(HTTP_BASIC_AUTHENTICATION_ENABLED); + } + +} diff --git a/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/systest/management/jmx/UserManagementWithBase64MD5PasswordsTest.java b/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagementFactory.java index 84a66232ce..ccf5373234 100644 --- a/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/systest/management/jmx/UserManagementWithBase64MD5PasswordsTest.java +++ b/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagementFactory.java @@ -16,24 +16,26 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.qpid.systest.management.jmx; +package org.apache.qpid.server.management.plugin; -import org.apache.qpid.server.security.auth.database.Base64MD5PasswordFilePrincipalDatabase; -import org.apache.qpid.server.security.auth.database.PrincipalDatabase; -import org.apache.qpid.tools.security.Passwd; +import java.util.Map; +import java.util.UUID; -public class UserManagementWithBase64MD5PasswordsTest extends UserManagementTest +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.Plugin; +import org.apache.qpid.server.plugin.PluginFactory; + +public class HttpManagementFactory implements PluginFactory { - @Override - protected Passwd createPasswordEncodingUtility() - { - return new Passwd(); - } @Override - protected Class<? extends PrincipalDatabase> getPrincipalDatabaseImplClass() + public Plugin createInstance(UUID id, Map<String, Object> attributes, Broker broker) { - return Base64MD5PasswordFilePrincipalDatabase.class; - } + if (!HttpManagement.PLUGIN_TYPE.equals(attributes.get(PLUGIN_TYPE))) + { + return null; + } + return new HttpManagement(id, broker, attributes); + } } diff --git a/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/Management.java b/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/Management.java deleted file mode 100644 index c2f9b73b54..0000000000 --- a/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/Management.java +++ /dev/null @@ -1,248 +0,0 @@ -/* - * - * 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; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; - -import org.apache.commons.configuration.ConfigurationException; -import org.apache.log4j.Logger; -import org.apache.qpid.server.management.plugin.servlet.DefinedFileServlet; -import org.apache.qpid.server.management.plugin.servlet.FileServlet; -import org.apache.qpid.server.management.plugin.servlet.api.ExchangesServlet; -import org.apache.qpid.server.management.plugin.servlet.api.VhostsServlet; -import org.apache.qpid.server.management.plugin.servlet.rest.LogRecordsServlet; -import org.apache.qpid.server.management.plugin.servlet.rest.MessageContentServlet; -import org.apache.qpid.server.management.plugin.servlet.rest.MessageServlet; -import org.apache.qpid.server.management.plugin.servlet.rest.RestServlet; -import org.apache.qpid.server.management.plugin.servlet.rest.SaslServlet; -import org.apache.qpid.server.management.plugin.servlet.rest.StructureServlet; -import org.apache.qpid.server.model.AuthenticationProvider; -import org.apache.qpid.server.model.Binding; -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.Port; -import org.apache.qpid.server.model.Protocol; -import org.apache.qpid.server.model.Queue; -import org.apache.qpid.server.model.Session; -import org.apache.qpid.server.model.Transport; -import org.apache.qpid.server.model.User; -import org.apache.qpid.server.model.VirtualHost; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.registry.IApplicationRegistry; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.SessionManager; -import org.eclipse.jetty.server.nio.SelectChannelConnector; -import org.eclipse.jetty.server.ssl.SslSocketConnector; -import org.eclipse.jetty.servlet.ServletContextHandler; -import org.eclipse.jetty.servlet.ServletHolder; -import org.eclipse.jetty.util.ssl.SslContextFactory; - -public class Management -{ - - private final Logger _logger = Logger.getLogger(Management.class); - - private Broker _broker; - - private Collection<Server> _servers = new ArrayList<Server>(); - - public Management() throws ConfigurationException, IOException - { - _broker = ApplicationRegistry.getInstance().getBroker(); - - Collection<Port> ports = _broker.getPorts(); - int httpPort = -1, httpsPort = -1; - for (Port port : ports) - { - if (port.getProtocols().contains(Protocol.HTTP)) - { - if (port.getTransports().contains(Transport.TCP)) - { - httpPort = port.getPort(); - } - } - if (port.getProtocols().contains(Protocol.HTTPS)) - { - if (port.getTransports().contains(Transport.SSL)) - { - httpsPort = port.getPort(); - } - } - } - - if (httpPort != -1 || httpsPort != -1) - { - _servers.add(createServer(httpPort, httpsPort)); - if (_logger.isDebugEnabled()) - { - _logger.debug(_servers.size() + " server(s) defined"); - } - } - else - { - if (_logger.isInfoEnabled()) - { - _logger.info("Cannot create web server as neither HTTP nor HTTPS port specified"); - } - } - } - - @SuppressWarnings("unchecked") - private Server createServer(int port, int sslPort) throws IOException, ConfigurationException - { - if (_logger.isInfoEnabled()) - { - _logger.info("Starting up web server on" + (port == -1 ? "" : " HTTP port " + port) - + (sslPort == -1 ? "" : " HTTPS port " + sslPort)); - } - - Server server = new Server(); - - if (port != -1) - { - SelectChannelConnector connector = new SelectChannelConnector(); - connector.setPort(port); - if (sslPort != -1) - { - connector.setConfidentialPort(sslPort); - } - server.addConnector(connector); - } - - if (sslPort != -1) - { - IApplicationRegistry appRegistry = ApplicationRegistry.getInstance(); - String keyStorePath = getKeyStorePath(appRegistry); - - SslContextFactory factory = new SslContextFactory(); - factory.setKeyStorePath(keyStorePath); - factory.setKeyStorePassword(appRegistry.getConfiguration().getManagementKeyStorePassword()); - - SslSocketConnector connector = new SslSocketConnector(factory); - connector.setPort(sslPort); - server.addConnector(connector); - } - - ServletContextHandler root = new ServletContextHandler(ServletContextHandler.SESSIONS); - root.setContextPath("/"); - server.setHandler(root); - - root.addServlet(new ServletHolder(new VhostsServlet(_broker)), "/api/vhosts/*"); - root.addServlet(new ServletHolder(new ExchangesServlet(_broker)), "/api/exchanges/*"); - - addRestServlet(root, "broker"); - addRestServlet(root, "virtualhost", VirtualHost.class); - addRestServlet(root, "authenticationprovider", AuthenticationProvider.class); - addRestServlet(root, "user", AuthenticationProvider.class, User.class); - addRestServlet(root, "exchange", VirtualHost.class, Exchange.class); - addRestServlet(root, "queue", VirtualHost.class, Queue.class); - addRestServlet(root, "connection", VirtualHost.class, Connection.class); - addRestServlet(root, "binding", VirtualHost.class, Exchange.class, Queue.class, Binding.class); - addRestServlet(root, "port", Port.class); - addRestServlet(root, "session", VirtualHost.class, Connection.class, Session.class); - - root.addServlet(new ServletHolder(new StructureServlet(_broker)), "/rest/structure"); - root.addServlet(new ServletHolder(new MessageServlet(_broker)), "/rest/message/*"); - root.addServlet(new ServletHolder(new MessageContentServlet(_broker)), "/rest/message-content/*"); - - root.addServlet(new ServletHolder(new LogRecordsServlet(_broker)), "/rest/logrecords"); - - root.addServlet(new ServletHolder(new SaslServlet(_broker)), "/rest/sasl"); - - root.addServlet(new ServletHolder(new DefinedFileServlet("management.html")), "/management"); - - root.addServlet(new ServletHolder(FileServlet.INSTANCE), "*.js"); - root.addServlet(new ServletHolder(FileServlet.INSTANCE), "*.css"); - root.addServlet(new ServletHolder(FileServlet.INSTANCE), "*.html"); - root.addServlet(new ServletHolder(FileServlet.INSTANCE), "*.png"); - root.addServlet(new ServletHolder(FileServlet.INSTANCE), "*.gif"); - root.addServlet(new ServletHolder(FileServlet.INSTANCE), "*.jpg"); - root.addServlet(new ServletHolder(FileServlet.INSTANCE), "*.jpeg"); - root.addServlet(new ServletHolder(FileServlet.INSTANCE), "*.json"); - root.addServlet(new ServletHolder(FileServlet.INSTANCE), "*.txt"); - root.addServlet(new ServletHolder(FileServlet.INSTANCE), "*.xsl"); - - final SessionManager sessionManager = root.getSessionHandler().getSessionManager(); - - sessionManager.setMaxInactiveInterval(60 * 15); - - return server; - } - - private void addRestServlet(ServletContextHandler root, String name, Class<? extends ConfiguredObject>... hierarchy) - { - root.addServlet(new ServletHolder(new RestServlet(_broker, hierarchy)), "/rest/" + name + "/*"); - } - - public void start() throws Exception - { - for (Server server : _servers) - { - server.start(); - } - } - - public void stop() throws Exception - { - for (Server server : _servers) - { - server.stop(); - } - } - - private String getKeyStorePath(IApplicationRegistry appRegistry) throws ConfigurationException, FileNotFoundException - { - String keyStorePath = null; - if (System.getProperty("javax.net.ssl.keyStore") != null) - { - keyStorePath = System.getProperty("javax.net.ssl.keyStore"); - } - else - { - keyStorePath = appRegistry.getConfiguration().getManagementKeyStorePath(); - } - - if (keyStorePath == null) - { - throw new ConfigurationException("Management SSL keystore path not defined, unable to start SSL protected HTTP connector"); - } - else - { - File ksf = new File(keyStorePath); - if (!ksf.exists()) - { - throw new FileNotFoundException("Cannot find management SSL keystore file: " + ksf); - } - if (!ksf.canRead()) - { - throw new FileNotFoundException("Cannot read management SSL keystore file: " + ksf + ". Check permissions."); - } - } - return keyStorePath; - } - -} diff --git a/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/ManagementActivator.java b/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/ManagementActivator.java deleted file mode 100644 index 09b7e08bfb..0000000000 --- a/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/ManagementActivator.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * - * 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; - -import org.apache.log4j.Logger; -import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.osgi.framework.BundleActivator; -import org.osgi.framework.BundleContext; - -public class ManagementActivator implements BundleActivator -{ - private static final Logger _logger = Logger.getLogger(ManagementActivator.class); - - - private BundleContext _ctx; - private String _bundleName; - private Management _managementService; - - - public void start(final BundleContext ctx) throws Exception - { - _ctx = ctx; - if (!ApplicationRegistry.getInstance().getConfiguration().getHTTPManagementEnabled() - && !ApplicationRegistry.getInstance().getConfiguration().getHTTPSManagementEnabled()) - { - _logger.info("Management plugin is disabled!"); - ctx.getBundle().uninstall(); - return; - } - _managementService = new Management(); - _managementService.start(); - _bundleName = ctx.getBundle().getSymbolicName(); - - // register the service - _logger.info("Registering management plugin: " + _bundleName); - _ctx.registerService(Management.class.getName(), _managementService, null); - _ctx.registerService(ConfigurationPluginFactory.class.getName(), ManagementConfiguration.FACTORY, null); - } - - public void stop(final BundleContext bundleContext) throws Exception - { - if (_managementService != null) - { - _logger.info("Stopping management plugin: " + _bundleName); - - _managementService.stop(); - - // null object references - _managementService = null; - } - _ctx = null; - } - -} diff --git a/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/ManagementConfiguration.java b/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/ManagementConfiguration.java deleted file mode 100644 index 3866da8f89..0000000000 --- a/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/ManagementConfiguration.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * - * 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; - -import org.apache.commons.configuration.CompositeConfiguration; -import org.apache.commons.configuration.Configuration; -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.configuration.plugins.ConfigurationPluginFactory; - -import java.util.Arrays; -import java.util.List; - -public class ManagementConfiguration extends ConfigurationPlugin -{ - CompositeConfiguration _finalConfig; - - public static final ConfigurationPluginFactory FACTORY = new ConfigurationPluginFactory() - { - public ConfigurationPlugin newInstance(String path, Configuration config) throws ConfigurationException - { - ConfigurationPlugin instance = new ManagementConfiguration(); - instance.setConfiguration(path, config); - return instance; - } - - public List<String> getParentPaths() - { - return Arrays.asList("management"); - } - }; - - public String[] getElementsProcessed() - { - return new String[] { "" }; - } - - public Configuration getConfiguration() - { - return _finalConfig; - } - - - @Override - public void validateConfiguration() throws ConfigurationException - { - // Valid Configuration either has xml links to new files - _finalConfig = new CompositeConfiguration(getConfig()); - List subFiles = getConfig().getList("xml[@fileName]"); - for (Object subFile : subFiles) - { - _finalConfig.addConfiguration(new XMLConfiguration((String) subFile)); - } - - } - -} diff --git a/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/DefinedFileServlet.java b/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/DefinedFileServlet.java index d8a8395550..e6ae47dcff 100644 --- a/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/DefinedFileServlet.java +++ b/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/DefinedFileServlet.java @@ -73,7 +73,7 @@ public class DefinedFileServlet extends HttpServlet } else { - response.sendError(404, "unknown file: "+ _filename); + response.sendError(HttpServletResponse.SC_NOT_FOUND, "unknown file: "+ _filename); } } } diff --git a/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/FileServlet.java b/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/FileServlet.java index f8ca082d79..24e5e7c049 100644 --- a/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/FileServlet.java +++ b/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/FileServlet.java @@ -20,11 +20,8 @@ */ package org.apache.qpid.server.management.plugin.servlet; -import java.io.File; import java.io.IOException; import java.io.InputStream; -import java.net.URI; -import java.net.URISyntaxException; import java.net.URL; import java.util.Collections; import java.util.HashMap; @@ -101,7 +98,7 @@ public class FileServlet extends HttpServlet } else { - response.sendError(404, "unknown file: "+ filename); + response.sendError(HttpServletResponse.SC_NOT_FOUND, "unknown file: "+ filename); } } diff --git a/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/api/ExchangesServlet.java b/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/api/ExchangesServlet.java deleted file mode 100644 index a3c5ec68a2..0000000000 --- a/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/api/ExchangesServlet.java +++ /dev/null @@ -1,208 +0,0 @@ -/* - * - * 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.api; - -import org.codehaus.jackson.map.ObjectMapper; -import org.codehaus.jackson.map.ObjectReader; - -import org.apache.qpid.server.model.Broker; -import org.apache.qpid.server.model.Exchange; -import org.apache.qpid.server.model.LifetimePolicy; -import org.apache.qpid.server.model.State; -import org.apache.qpid.server.model.VirtualHost; -import org.apache.qpid.server.registry.ApplicationRegistry; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - -public class ExchangesServlet extends HttpServlet -{ - - - private Broker _broker; - - public ExchangesServlet() - { - super(); - _broker = ApplicationRegistry.getInstance().getBroker(); - } - - public ExchangesServlet(Broker broker) - { - _broker = broker; - } - - protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException - { - response.setContentType("application/json"); - response.setStatus(HttpServletResponse.SC_OK); - - Collection<VirtualHost> vhosts = _broker.getVirtualHosts(); - Collection<Exchange> exchanges = new ArrayList<Exchange>(); - Collection<Map<String,Object>> outputObject = new ArrayList<Map<String,Object>>(); - - final PrintWriter writer = response.getWriter(); - - ObjectMapper mapper = new ObjectMapper(); - String vhostName = null; - String exchangeName = null; - - if(request.getPathInfo() != null && request.getPathInfo().length()>0) - { - String path = request.getPathInfo().substring(1); - String[] parts = path.split("/"); - vhostName = parts.length == 0 ? "" : parts[0]; - if(parts.length > 1) - { - exchangeName = parts[1]; - } - } - - for(VirtualHost vhost : vhosts) - { - if(vhostName == null || vhostName.equals(vhost.getName())) - { - for(Exchange exchange : vhost.getExchanges()) - { - if(exchangeName == null || exchangeName.equals(exchange.getName())) - { - outputObject.add(convertToObject(exchange)); - if(exchangeName != null) - { - break; - } - } - } - if(vhostName != null) - { - break; - } - } - } - - mapper.writeValue(writer, outputObject); - - } - - private Map<String,Object> convertToObject(final Exchange exchange) - { - Map<String, Object> object = new LinkedHashMap<String, Object>(); - object.put("name",exchange.getName()); - object.put("type", exchange.getExchangeType()); - object.put("durable", exchange.isDurable()); - object.put("auto-delete", exchange.getLifetimePolicy() == LifetimePolicy.AUTO_DELETE); - - Map<String,Object> arguments = new HashMap<String, Object>(); - for(String key : exchange.getAttributeNames()) - { - if(!key.equals(Exchange.TYPE)) - { - arguments.put(key, exchange.getAttribute(key)); - } - } - object.put("arguments", arguments); - return object; - } - - protected void doPut(final HttpServletRequest request, final HttpServletResponse response) - throws ServletException, IOException - { - - response.setContentType("application/json"); - - - String vhostName = null; - String exchangeName = null; - if(request.getPathInfo() != null && request.getPathInfo().length()>0) - { - String path = request.getPathInfo().substring(1); - String[] parts = path.split("/"); - vhostName = parts.length == 0 ? "" : parts[0]; - if(parts.length > 1) - { - exchangeName = parts[1]; - } - } - if(vhostName == null) - { - response.setStatus(HttpServletResponse.SC_PRECONDITION_FAILED); - } - else if (exchangeName == null) - { - response.setStatus(HttpServletResponse.SC_PRECONDITION_FAILED); - } - else - { - VirtualHost vhost = null; - for(VirtualHost host : _broker.getVirtualHosts()) - { - if(host.getName().equals(vhostName)) - { - vhost = host; - } - } - if(vhost == null) - { - response.setStatus(HttpServletResponse.SC_PRECONDITION_FAILED); - } - else - { - response.setStatus(HttpServletResponse.SC_NO_CONTENT); - ObjectMapper mapper = new ObjectMapper(); - Map<String,Object> exchangeObject = mapper.readValue(request.getInputStream(), LinkedHashMap.class); - - final boolean isDurable = exchangeObject.get("durable") instanceof Boolean - && ((Boolean)exchangeObject.get("durable")); - final boolean isAutoDelete = exchangeObject.get("auto_delete") instanceof Boolean - && ((Boolean)exchangeObject.get("auto_delete")); - - final String type = (String) exchangeObject.get("type"); - final Map<String, Object> attributes = new HashMap<String, Object>(exchangeObject); - attributes.remove("durable"); - attributes.remove("auto_delete"); - attributes.remove("type"); - - vhost.createExchange(exchangeName, State.ACTIVE, isDurable, - isAutoDelete ? LifetimePolicy.AUTO_DELETE : LifetimePolicy.PERMANENT, - 0l, - type, - attributes); - } - - - - } - - - - } -} diff --git a/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/api/VhostsServlet.java b/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/api/VhostsServlet.java deleted file mode 100644 index b2c0fcfe52..0000000000 --- a/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/api/VhostsServlet.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * - * 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.api; - -import org.codehaus.jackson.map.ObjectMapper; - -import org.apache.qpid.common.QpidProperties; -import org.apache.qpid.server.model.Broker; -import org.apache.qpid.server.model.LifetimePolicy; -import org.apache.qpid.server.model.State; -import org.apache.qpid.server.model.VirtualHost; -import org.apache.qpid.server.protocol.AMQConnectionModel; -import org.apache.qpid.server.registry.ApplicationRegistry; - - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.io.PrintWriter; -import java.util.*; - -public class VhostsServlet extends HttpServlet -{ - - - private Broker _broker; - - public VhostsServlet() - { - super(); - _broker = ApplicationRegistry.getInstance().getBroker(); - } - - public VhostsServlet(Broker broker) - { - _broker = broker; - } - - protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException - { -System.out.println("Get /api/vhosts"); - response.setContentType("application/json"); - response.setStatus(HttpServletResponse.SC_OK); - - Collection<VirtualHost> vhosts = _broker.getVirtualHosts(); - - - - final PrintWriter writer = response.getWriter(); - - ObjectMapper mapper = new ObjectMapper(); - - if(request.getPathInfo() == null || request.getPathInfo().length()==0) - { - - LinkedHashMap<String, Object> vhostObject = new LinkedHashMap<String, Object>(); - List<Map> vhostList = new ArrayList<Map>(); - - for(VirtualHost vhost : vhosts) - { - vhostList.add(Collections.singletonMap("name", vhost.getName())); - } - mapper.writeValue(writer, vhostList); - } - else - { - LinkedHashMap<String, Object> vhostObject = new LinkedHashMap<String, Object>(); - String vhostName = request.getPathInfo().substring(1); - - for(VirtualHost vhost : vhosts) - { - if(vhostName.equals(vhost.getName())) - { - vhostObject.put("name", vhost.getName()); - break; - } - } - mapper.writeValue(writer, vhostObject); - } - } - - - protected void doPut(final HttpServletRequest request, final HttpServletResponse response) - throws ServletException, IOException - { - - response.setContentType("application/json"); - response.setStatus(HttpServletResponse.SC_NO_CONTENT); - - if(request.getPathInfo() != null && request.getPathInfo().length()>0) - { - String vhostName = request.getPathInfo().substring(1); - _broker.createVirtualHost(vhostName, State.ACTIVE, true, LifetimePolicy.PERMANENT, 0L, Collections.EMPTY_MAP); - } - - - } -} diff --git a/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/AbstractServlet.java b/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/AbstractServlet.java index a76bd98179..689bdb50d8 100644 --- a/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/AbstractServlet.java +++ b/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/AbstractServlet.java @@ -18,191 +18,456 @@ * under the License. * */ - 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.ServletConfig; +import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; 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.framing.AMQShortString; +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.management.plugin.HttpManagement; +import org.apache.qpid.server.management.plugin.session.LoginLogoutReporter; 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.SecurityManager; +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 final Broker _broker; + private static final Logger LOGGER = Logger.getLogger(AbstractServlet.class); + + /** + * Servlet context attribute holding a reference to a broker instance + */ + public static final String ATTR_BROKER = "Qpid.broker"; + + /** + * Servlet context attribute holding a reference to plugin configuration + */ + public static final String ATTR_MANAGEMENT = "Qpid.management"; + + private static final String ATTR_LOGIN_LOGOUT_REPORTER = "AbstractServlet.loginLogoutReporter"; + private static final String ATTR_SUBJECT = "AbstractServlet.subject"; + private static final String ATTR_LOG_ACTOR = "AbstractServlet.logActor"; + + private Broker _broker; + private RootMessageLogger _rootLogger; + private HttpManagement _httpManagement; protected AbstractServlet() { super(); - _broker = ApplicationRegistry.getInstance().getBroker(); } - protected AbstractServlet(Broker broker) + @Override + public void init() throws ServletException { - _broker = broker; + ServletConfig servletConfig = getServletConfig(); + ServletContext servletContext = servletConfig.getServletContext(); + _broker = (Broker)servletContext.getAttribute(ATTR_BROKER); + _rootLogger = _broker.getRootMessageLogger(); + _httpManagement = (HttpManagement)servletContext.getAttribute(ATTR_MANAGEMENT); + super.init(); } @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 + ); + } + + /** + * 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 + { + throw new UnsupportedOperationException("GET not supported by this servlet"); + } + + + @Override + protected final void doPost(final HttpServletRequest request, final HttpServletResponse resp) + { + doWithSubjectAndActor( + new PrivilegedExceptionAction<Void>() + { + @Override + public Void run() throws Exception + { + doPostWithSubjectAndActor(request, resp); + return null; + } + }, + request, + resp + ); + } + + /** + * 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 + { + throw new UnsupportedOperationException("POST not supported by this servlet"); + } + + @Override + protected final void doPut(final HttpServletRequest request, final HttpServletResponse resp) + { + doWithSubjectAndActor( + new PrivilegedExceptionAction<Void>() + { + @Override + public Void run() throws Exception + { + doPutWithSubjectAndActor(request, resp); + return null; + } + }, + request, + resp + ); } - protected void onGet(HttpServletRequest request, HttpServletResponse resp) throws IOException, ServletException + /** + * 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 { - super.doGet(request, resp); + throw new UnsupportedOperationException("PUT not supported by this servlet"); } - private void clearAuthorizedSubject() + @Override + protected final void doDelete(final HttpServletRequest request, final HttpServletResponse resp) + throws ServletException, IOException { - org.apache.qpid.server.security.SecurityManager.setThreadSubject(null); + doWithSubjectAndActor( + new PrivilegedExceptionAction<Void>() + { + @Override + public Void run() throws Exception + { + doDeleteWithSubjectAndActor(request, resp); + return null; + } + }, + request, + resp + ); } + /** + * 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 + { + throw new UnsupportedOperationException("DELETE not supported by this servlet"); + } - private void setAuthorizedSubject(HttpServletRequest request) + private void doWithSubjectAndActor( + PrivilegedExceptionAction<Void> privilegedExceptionAction, + final HttpServletRequest request, + final HttpServletResponse resp) { - HttpSession session = request.getSession(true); - Subject subject = (Subject) session.getAttribute("subject"); + Subject subject; + try + { + subject = getAndCacheAuthorizedSubject(request); + } + catch (AccessControlException e) + { + sendError(resp, HttpServletResponse.SC_FORBIDDEN); + return; + } - if(subject == null) + SecurityManager.setThreadSubject(subject); + try { - Principal principal = request.getUserPrincipal(); - if(principal != null) + HttpManagementActor logActor = getLogActorAndCacheInSession(request); + CurrentActor.set(logActor); + try + { + Subject.doAs(subject, privilegedExceptionAction); + } + catch(RuntimeException e) { - subject = new Subject(false, Collections.singleton(principal),Collections.emptySet(), - Collections.emptySet()); + LOGGER.error("Unable to perform action", e); + throw e; } - else + catch (PrivilegedActionException e) { - String header = request.getHeader("Authorization"); + LOGGER.error("Unable to perform action", e); + throw new RuntimeException(e.getCause()); + } + finally + { + CurrentActor.remove(); + } + } + finally + { + try + { + SecurityManager.setThreadSubject(null); + } + finally + { + AMQShortString.clearLocalCache(); + } + } + } + + /** + * 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) + { + HttpSession session = request.getSession(); + Subject subject = getAuthorisedSubjectFromSession(session); - /* - * TODO - Should configure whether basic authentication is allowed... and in particular whether it - * should be allowed over non-ssl connections - * */ + if(subject != null) + { + return subject; + } - if (header != null) + SubjectCreator subjectCreator = getSubjectCreator(request); + subject = authenticate(request, subjectCreator); + if (subject != null) + { + authoriseManagement(request, subject); + setAuthorisedSubjectInSession(subject, request, session); + } + else + { + subject = subjectCreator.createSubjectWithGroups(AnonymousAuthenticationManager.ANONYMOUS_USERNAME); + } + + return subject; + } + + protected void authoriseManagement(HttpServletRequest request, Subject subject) + { + // TODO: We should eliminate SecurityManager.setThreadSubject in favour of Subject.doAs + SecurityManager.setThreadSubject(subject); // Required for accessManagement check + LogActor actor = createHttpManagementActor(request); + CurrentActor.set(actor); + try + { + try + { + Subject.doAs(subject, new PrivilegedExceptionAction<Void>() // Required for proper logging of Subject { - String[] tokens = header.split("\\s"); - if(tokens.length >= 2 - && "BASIC".equalsIgnoreCase(tokens[0])) + @Override + public Void run() throws Exception { - String[] credentials = (new String(Base64.decodeBase64(tokens[1].getBytes()))).split(":",2); - if(credentials.length == 2) + boolean allowed = getSecurityManager().accessManagement(); + if (!allowed) { - SocketAddress address = getSocketAddress(request); - AuthenticationManager authenticationManager = - ApplicationRegistry.getInstance().getAuthenticationManager(address); - AuthenticationResult authResult = - authenticationManager.authenticate(credentials[0], credentials[1]); - subject = authResult.getSubject(); - + throw new AccessControlException("User is not authorised for management"); } + return null; } - } + }); + } + catch (PrivilegedActionException e) + { + throw new RuntimeException("Unable to perform access check", e); } } - if (subject == null) + finally { - subject = AnonymousAuthenticationManager.ANONYMOUS_SUBJECT; + try + { + CurrentActor.remove(); + } + finally + { + SecurityManager.setThreadSubject(null); + } } - org.apache.qpid.server.security.SecurityManager.setThreadSubject(subject); - } - protected Subject getSubject(HttpSession session) + private Subject authenticate(HttpServletRequest request, SubjectCreator subjectCreator) { - return (Subject)session.getAttribute("subject"); + Subject subject = null; + + String remoteUser = request.getRemoteUser(); + if(remoteUser != null) + { + subject = authenticateUserAndGetSubject(subjectCreator, remoteUser, null); + } + else + { + String header = request.getHeader("Authorization"); + + if (header != null) + { + String[] tokens = header.split("\\s"); + if(tokens.length >= 2 && "BASIC".equalsIgnoreCase(tokens[0])) + { + if(!isBasicAuthSupported(request)) + { + //TODO: write a return response indicating failure? + throw new IllegalArgumentException("BASIC Authorization is not enabled."); + } + + subject = performBasicAuth(subject, subjectCreator, tokens[1]); + } + } + } + + return subject; } - @Override - protected final void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException + private Subject performBasicAuth(Subject subject,SubjectCreator subjectCreator, String base64UsernameAndPassword) { - setAuthorizedSubject(req); - try + String[] credentials = (new String(Base64.decodeBase64(base64UsernameAndPassword.getBytes()))).split(":",2); + if(credentials.length == 2) { - onPost(req, resp); + subject = authenticateUserAndGetSubject(subjectCreator, credentials[0], credentials[1]); } - finally + else { - clearAuthorizedSubject(); + //TODO: write a return response indicating failure? + throw new AccessControlException("Invalid number of credentials supplied: " + + credentials.length); } + return subject; + } + private Subject authenticateUserAndGetSubject(SubjectCreator subjectCreator, String username, String password) + { + SubjectAuthenticationResult authResult = subjectCreator.authenticate(username, password); + if( authResult.getStatus() != AuthenticationStatus.SUCCESS) + { + //TODO: write a return response indicating failure? + throw new AccessControlException("Incorrect username or password"); + } + Subject subject = authResult.getSubject(); + return subject; } - protected void onPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException + private boolean isBasicAuthSupported(HttpServletRequest req) { - super.doPost(req, resp); + return req.isSecure() ? _httpManagement.isHttpsBasicAuthenticationEnabled() + : _httpManagement.isHttpBasicAuthenticationEnabled(); } - @Override - protected final void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException + private HttpManagementActor getLogActorAndCacheInSession(HttpServletRequest req) { - setAuthorizedSubject(req); - try - { - onPut(req, resp); + HttpSession session = req.getSession(); - } - finally + HttpManagementActor actor = (HttpManagementActor) session.getAttribute(ATTR_LOG_ACTOR); + if(actor == null) { - clearAuthorizedSubject(); + actor = createHttpManagementActor(req); + session.setAttribute(ATTR_LOG_ACTOR, actor); } + + return actor; } - protected void onPut(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException + protected Subject getAuthorisedSubjectFromSession(HttpSession session) { - super.doPut(req,resp); + return (Subject)session.getAttribute(ATTR_SUBJECT); } - @Override - protected final void doDelete(HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException + protected void setAuthorisedSubjectInSession(Subject subject, HttpServletRequest request, final HttpSession session) + { + session.setAttribute(ATTR_SUBJECT, subject); + + LogActor logActor = createHttpManagementActor(request); + // Cause the user logon to be logged. + session.setAttribute(ATTR_LOGIN_LOGOUT_REPORTER, new LoginLogoutReporter(logActor, subject)); + } + + protected Broker getBroker() + { + return _broker; + } + + protected SocketAddress getSocketAddress(HttpServletRequest request) + { + return InetSocketAddress.createUnresolved(request.getServerName(), request.getServerPort()); + } + + protected void sendError(final HttpServletResponse resp, int errorCode) { - setAuthorizedSubject(req); try { - onDelete(req, resp); + resp.sendError(errorCode); } - finally + catch (IOException e) { - clearAuthorizedSubject(); + throw new RuntimeException("Failed to send error response code " + errorCode, e); } } - protected void onDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException + private HttpManagementActor createHttpManagementActor(HttpServletRequest request) { - super.doDelete(req, resp); + return new HttpManagementActor(_rootLogger, request.getRemoteAddr(), request.getRemotePort()); } + protected HttpManagement getManagement() + { + return _httpManagement; + } - protected Broker getBroker() + protected SecurityManager getSecurityManager() { - return _broker; + return _broker.getSecurityManager(); } - protected SocketAddress getSocketAddress(HttpServletRequest request) + protected SubjectCreator getSubjectCreator(HttpServletRequest request) { - return InetSocketAddress.createUnresolved(request.getServerName(), request.getServerPort()); + return _broker.getSubjectCreator(getSocketAddress(request)); } } diff --git a/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/LogRecordsServlet.java b/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/LogRecordsServlet.java index 404793b592..f2cf5d7734 100644 --- a/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/LogRecordsServlet.java +++ b/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/LogRecordsServlet.java @@ -26,8 +26,6 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.qpid.server.logging.LogRecorder; -import org.apache.qpid.server.model.Broker; -import org.apache.qpid.server.registry.ApplicationRegistry; import org.codehaus.jackson.map.ObjectMapper; import org.codehaus.jackson.map.SerializationConfig; @@ -35,16 +33,11 @@ public class LogRecordsServlet extends AbstractServlet { public LogRecordsServlet() { - super(ApplicationRegistry.getInstance().getBroker()); - } - - public LogRecordsServlet(Broker broker) - { - super(broker); + super(); } @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); @@ -53,10 +46,10 @@ public class LogRecordsServlet extends AbstractServlet response.setHeader("Pragma","no-cache"); response.setDateHeader ("Expires", 0); - ApplicationRegistry applicationRegistry = (ApplicationRegistry) ApplicationRegistry.getInstance(); List<Map<String,Object>> logRecords = new ArrayList<Map<String, Object>>(); - for(LogRecorder.Record record : applicationRegistry.getLogRecorder()) + LogRecorder logRecorder = getBroker().getLogRecorder(); + for(LogRecorder.Record record : logRecorder) { logRecords.add(logRecordToObject(record)); } diff --git a/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/LogoutServlet.java b/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/LogoutServlet.java new file mode 100644 index 0000000000..4188e7d60d --- /dev/null +++ b/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/LogoutServlet.java @@ -0,0 +1,65 @@ +/* + * + * 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.IOException; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import org.apache.qpid.server.management.plugin.HttpManagement; + +@SuppressWarnings("serial") +public class LogoutServlet extends HttpServlet +{ + public static final String RETURN_URL_INIT_PARAM = "qpid.webui_logout_redirect"; + private String _returnUrl = HttpManagement.ENTRY_POINT_PATH; + + @Override + public void init(ServletConfig config) throws ServletException + { + super.init(config); + + String initValue = config.getServletContext().getInitParameter(RETURN_URL_INIT_PARAM); + if(initValue != null) + { + _returnUrl = initValue; + } + } + + @Override + protected void doGet(HttpServletRequest request, HttpServletResponse resp) throws ServletException, IOException + { + HttpSession session = request.getSession(false); + if(session != null) + { + // Invalidating the session will cause LoginLogoutReporter to log the user logoff. + session.invalidate(); + } + + resp.sendRedirect(_returnUrl); + } + +} diff --git a/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageContentServlet.java b/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageContentServlet.java index bc87f0bcc5..d61c48bb2c 100644 --- a/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageContentServlet.java +++ b/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageContentServlet.java @@ -29,7 +29,6 @@ import javax.servlet.http.HttpServletResponse; import org.apache.qpid.server.message.MessageReference; import org.apache.qpid.server.message.ServerMessage; -import org.apache.qpid.server.model.Broker; import org.apache.qpid.server.model.Queue; import org.apache.qpid.server.model.VirtualHost; import org.apache.qpid.server.queue.QueueEntry; @@ -42,13 +41,8 @@ public class MessageContentServlet extends AbstractServlet super(); } - public MessageContentServlet(Broker broker) - { - super(broker); - } - @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/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageServlet.java b/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageServlet.java index 6e7bc1d935..49e0c2b1bf 100644 --- a/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageServlet.java +++ b/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/MessageServlet.java @@ -34,13 +34,10 @@ import org.apache.log4j.Logger; import org.apache.qpid.server.message.AMQMessageHeader; import org.apache.qpid.server.message.MessageReference; import org.apache.qpid.server.message.ServerMessage; -import org.apache.qpid.server.model.Broker; import org.apache.qpid.server.model.Queue; import org.apache.qpid.server.model.VirtualHost; import org.apache.qpid.server.queue.QueueEntry; import org.apache.qpid.server.queue.QueueEntryVisitor; -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.subscription.Subscription; @@ -56,13 +53,8 @@ public class MessageServlet extends AbstractServlet super(); } - public MessageServlet(Broker broker) - { - super(broker); - } - @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 +392,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 @@ -422,7 +414,7 @@ public class MessageServlet extends AbstractServlet // FIXME: added temporary authorization check until we introduce management layer // and review current ACL rules to have common rules for all management interfaces String methodName = isMoveTransaction? "moveMessages":"copyMessages"; - if (isQueueUpdateMethodAuthorized(methodName, vhost.getName())) + if (isQueueUpdateMethodAuthorized(methodName, vhost)) { final Queue destinationQueue = getQueueFromVirtualHost(destQueueName, vhost); final List messageIds = new ArrayList((List) providedObject.get("messages")); @@ -435,7 +427,7 @@ public class MessageServlet extends AbstractServlet } else { - response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + response.setStatus(HttpServletResponse.SC_FORBIDDEN); } } catch(RuntimeException e) @@ -450,7 +442,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); @@ -466,37 +458,22 @@ public class MessageServlet extends AbstractServlet // FIXME: added temporary authorization check until we introduce management layer // and review current ACL rules to have common rules for all management interfaces - if (isQueueUpdateMethodAuthorized("deleteMessages", vhost.getName())) + if (isQueueUpdateMethodAuthorized("deleteMessages", vhost)) { vhost.executeTransaction(new DeleteTransaction(sourceQueue, messageIds)); response.setStatus(HttpServletResponse.SC_OK); } else { - response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + response.setStatus(HttpServletResponse.SC_FORBIDDEN); } } - private boolean isQueueUpdateMethodAuthorized(String methodName, String virtualHost) + private boolean isQueueUpdateMethodAuthorized(String methodName, VirtualHost host) { - SecurityManager securityManager = getSecurityManager(virtualHost); + SecurityManager securityManager = host.getSecurityManager(); return securityManager.authoriseMethod(Operation.UPDATE, "VirtualHost.Queue", methodName); } - private SecurityManager getSecurityManager(String virtualHost) - { - IApplicationRegistry appRegistry = ApplicationRegistry.getInstance(); - SecurityManager security; - if (virtualHost == null) - { - security = appRegistry.getSecurityManager(); - } - else - { - security = appRegistry.getVirtualHostRegistry().getVirtualHost(virtualHost).getSecurityManager(); - } - return security; - } - } diff --git a/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/RestServlet.java b/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/RestServlet.java index 6a79916d07..3fab26cde5 100644 --- a/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/RestServlet.java +++ b/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/RestServlet.java @@ -19,6 +19,7 @@ package org.apache.qpid.server.management.plugin.servlet.rest; import java.io.BufferedWriter; import java.io.IOException; import java.io.Writer; +import java.security.AccessControlException; import java.util.*; import javax.servlet.ServletConfig; import javax.servlet.ServletException; @@ -31,7 +32,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); @@ -47,29 +47,29 @@ public class RestServlet extends AbstractServlet private Class<? extends ConfiguredObject>[] _hierarchy; - private volatile boolean initializationRequired = false; - private final ConfiguredObjectToMapConverter _objectConverter = new ConfiguredObjectToMapConverter(); + private final boolean _hierarchyInitializationRequired; public RestServlet() { super(); - initializationRequired = true; + _hierarchyInitializationRequired = true; } - public RestServlet(Broker broker, Class<? extends ConfiguredObject>... hierarchy) + public RestServlet(Class<? extends ConfiguredObject>... hierarchy) { - super(broker); + super(); _hierarchy = hierarchy; + _hierarchyInitializationRequired = false; } @Override public void init() throws ServletException { - if (initializationRequired) + super.init(); + if (_hierarchyInitializationRequired) { doInitialization(); - initializationRequired = false; } } @@ -285,7 +285,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 +319,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 +336,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 +429,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) @@ -462,13 +466,17 @@ public class RestServlet extends AbstractServlet private void setResponseStatus(HttpServletResponse response, RuntimeException e) throws IOException { - if (e.getCause() instanceof AMQSecurityException) + if (e instanceof AccessControlException || e.getCause() instanceof AMQSecurityException) { - response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + if (LOGGER.isDebugEnabled()) + { + LOGGER.debug("Caught security exception, sending " + HttpServletResponse.SC_FORBIDDEN, e); + } + response.setStatus(HttpServletResponse.SC_FORBIDDEN); } else { - LOGGER.warn("Unexpected exception is caught", e); + LOGGER.warn("Caught exception", e); // TODO response.setStatus(HttpServletResponse.SC_CONFLICT); @@ -476,7 +484,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/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/SaslServlet.java b/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/SaslServlet.java index 1b78611a50..069132af1e 100644 --- a/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/SaslServlet.java +++ b/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/SaslServlet.java @@ -25,10 +25,9 @@ import org.codehaus.jackson.map.ObjectMapper; 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.management.plugin.HttpManagement; +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; @@ -39,6 +38,7 @@ import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.io.IOException; import java.io.PrintWriter; +import java.security.AccessControlException; import java.security.Principal; import java.security.SecureRandom; import java.util.LinkedHashMap; @@ -47,6 +47,7 @@ import java.util.Random; public class SaslServlet extends AbstractServlet { + private static final Logger LOGGER = Logger.getLogger(SaslServlet.class); private static final SecureRandom SECURE_RANDOM = new SecureRandom(); @@ -56,18 +57,12 @@ public class SaslServlet extends AbstractServlet private static final String ATTR_EXPIRY = "SaslServlet.Expiry"; private static final long SASL_EXCHANGE_EXPIRY = 1000L; - public SaslServlet() { super(); } - public SaslServlet(Broker broker) - { - super(broker); - } - - protected void onGet(HttpServletRequest request, HttpServletResponse response) throws + protected void doGetWithSubjectAndActor(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { @@ -79,15 +74,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 = getSubjectCreator(request); + String[] mechanisms = subjectCreator.getMechanisms().split(" "); Map<String, Object> outputObject = new LinkedHashMap<String, Object>(); - final Subject subject = (Subject) session.getAttribute("subject"); + + final Subject subject = getAuthorisedSubjectFromSession(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,9 +117,10 @@ 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 { + checkSaslAuthEnabled(request); + try { response.setContentType("application/json"); @@ -137,14 +134,18 @@ public class SaslServlet extends AbstractServlet String id = request.getParameter("id"); String saslResponse = request.getParameter("response"); - AuthenticationManager authManager = ApplicationRegistry.getInstance().getAuthenticationManager(getSocketAddress(request)); + SubjectCreator subjectCreator = getSubjectCreator(request); if(mechanism != null) { if(id == null) { - SaslServer saslServer = authManager.createSaslServer(mechanism, request.getServerName(), null/*TODO*/); - evaluateSaslResponse(response, session, saslResponse, saslServer); + if(LOGGER.isDebugEnabled()) + { + LOGGER.debug("Creating SaslServer for mechanism: " + mechanism); + } + SaslServer saslServer = subjectCreator.createSaslServer(mechanism, request.getServerName(), null/*TODO*/); + evaluateSaslResponse(request, response, session, saslResponse, saslServer, subjectCreator); } else { @@ -152,9 +153,7 @@ public class SaslServlet extends AbstractServlet session.removeAttribute(ATTR_ID); session.removeAttribute(ATTR_SASL_SERVER); session.removeAttribute(ATTR_EXPIRY); - } - } else { @@ -163,8 +162,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(request, response, session, saslResponse, saslServer, subjectCreator); } else { @@ -180,7 +178,6 @@ public class SaslServlet extends AbstractServlet session.removeAttribute(ATTR_ID); session.removeAttribute(ATTR_SASL_SERVER); session.removeAttribute(ATTR_EXPIRY); - } } } @@ -194,12 +191,30 @@ public class SaslServlet extends AbstractServlet LOGGER.error("Error processing SASL request", e); throw e; } + } + private void checkSaslAuthEnabled(HttpServletRequest request) + { + boolean saslAuthEnabled; + HttpManagement management = getManagement(); + if (request.isSecure()) + { + saslAuthEnabled = management.isHttpsSaslAuthenticationEnabled(); + } + else + { + saslAuthEnabled = management.isHttpSaslAuthenticationEnabled(); + } + + if (!saslAuthEnabled) + { + throw new RuntimeException("Sasl authentication disabled."); + } } - private void evaluateSaslResponse(final HttpServletResponse response, - final HttpSession session, - final String saslResponse, final SaslServer saslServer) throws IOException + private void evaluateSaslResponse(final HttpServletRequest request, + final HttpServletResponse response, + final HttpSession session, final String saslResponse, final SaslServer saslServer, SubjectCreator subjectCreator) throws IOException { final String id; byte[] challenge; @@ -209,27 +224,34 @@ public class SaslServlet extends AbstractServlet } catch(SaslException e) { - session.removeAttribute(ATTR_ID); session.removeAttribute(ATTR_SASL_SERVER); session.removeAttribute(ATTR_EXPIRY); - response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + response.setStatus(HttpServletResponse.SC_FORBIDDEN); return; } 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()); + + try + { + authoriseManagement(request, subject); + } + catch (AccessControlException ace) + { + sendError(response, HttpServletResponse.SC_FORBIDDEN); + return; + } + + setAuthorisedSubjectInSession(subject, request, session); session.removeAttribute(ATTR_ID); session.removeAttribute(ATTR_SASL_SERVER); session.removeAttribute(ATTR_EXPIRY); response.setStatus(HttpServletResponse.SC_OK); - - } else { @@ -250,7 +272,6 @@ public class SaslServlet extends AbstractServlet ObjectMapper mapper = new ObjectMapper(); mapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, true); mapper.writeValue(writer, outputObject); - } } } diff --git a/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/StructureServlet.java b/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/StructureServlet.java index 60f977ca66..40d3c02768 100644 --- a/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/StructureServlet.java +++ b/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/servlet/rest/StructureServlet.java @@ -41,13 +41,8 @@ public class StructureServlet extends AbstractServlet super(); } - public StructureServlet(Broker broker) - { - super(broker); - } - @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 +51,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/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/session/LoginLogoutReporter.java b/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/session/LoginLogoutReporter.java new file mode 100644 index 0000000000..238f1b4719 --- /dev/null +++ b/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/session/LoginLogoutReporter.java @@ -0,0 +1,103 @@ +/* + * 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.session; + +import java.security.Principal; +import java.security.PrivilegedAction; + +import javax.security.auth.Subject; +import javax.servlet.http.HttpSession; +import javax.servlet.http.HttpSessionBindingEvent; +import javax.servlet.http.HttpSessionBindingListener; + +import org.apache.log4j.Logger; +import org.apache.qpid.server.logging.LogActor; +import org.apache.qpid.server.logging.messages.ManagementConsoleMessages; +import org.apache.qpid.server.security.auth.AuthenticatedPrincipal; + +/** + * Logs {@link ManagementConsoleMessages#OPEN(String)} and {@link ManagementConsoleMessages#CLOSE(String)} + * messages. A single instance of this class must be placed in the {@link HttpSession} immediately after + * the user has successfully logged-in, and removed (or the whole session invalidated) as the user logs out. + */ +public class LoginLogoutReporter implements HttpSessionBindingListener +{ + private static final Logger LOGGER = Logger.getLogger(LoginLogoutReporter.class); + private final LogActor _logActor; + private final Subject _subject; + private final Principal _principal; + + public LoginLogoutReporter(LogActor logActor, Subject subject) + { + super(); + _logActor = logActor; + _subject = subject; + _principal = AuthenticatedPrincipal.getAuthenticatedPrincipalFromSubject(_subject); + } + + @Override + public void valueBound(HttpSessionBindingEvent arg0) + { + reportLogin(); + } + + @Override + public void valueUnbound(HttpSessionBindingEvent arg0) + { + reportLogout(); + } + + private void reportLogin() + { + if (LOGGER.isDebugEnabled()) + { + LOGGER.debug("User logging in : " + _principal); + } + + Subject.doAs(_subject, new PrivilegedAction<Void>() + { + @Override + public Void run() + { + _logActor.message(ManagementConsoleMessages.OPEN(_principal.getName())); + return null; + } + }); + } + + private void reportLogout() + { + if (LOGGER.isDebugEnabled()) + { + LOGGER.debug("User logging out : " + _principal); + } + + Subject.doAs(_subject, new PrivilegedAction<Void>() + { + @Override + public Void run() + { + _logActor.message(ManagementConsoleMessages.CLOSE(_principal.getName())); + return null; + } + }); + } + +} diff --git a/java/broker-plugins/management-http/src/main/java/resources/authenticationprovider/showPrincipalDatabaseAuthenticationManager.html b/java/broker-plugins/management-http/src/main/java/resources/authenticationprovider/showPrincipalDatabaseAuthenticationManager.html index baadc8c35f..e6c067fddf 100644 --- a/java/broker-plugins/management-http/src/main/java/resources/authenticationprovider/showPrincipalDatabaseAuthenticationManager.html +++ b/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/java/broker-plugins/management-http/src/main/java/resources/group/addGroupMember.html b/java/broker-plugins/management-http/src/main/java/resources/group/addGroupMember.html new file mode 100644 index 0000000000..0372468f91 --- /dev/null +++ b/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/java/broker-plugins/firewall/build.xml b/java/broker-plugins/management-http/src/main/java/resources/group/showGroup.html index 6ae6a35b89..4fddf727d0 100644 --- a/java/broker-plugins/firewall/build.xml +++ b/java/broker-plugins/management-http/src/main/java/resources/group/showGroup.html @@ -1,4 +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 @@ -6,29 +7,24 @@ - 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. + - --> -<project name="Qpid Broker-Plugins Firewall" default="build"> - <property name="module.depends" value="common broker" /> - <property name="module.test.depends" value="test broker/test common/test management/common" /> - - <property name="module.manifest" value="MANIFEST.MF" /> - <property name="module.plugin" value="true" /> - <property name="module.genpom" value="true"/> - <property name="module.genpom.args" value="-Sqpid-common=provided -Sqpid-broker=provided"/> +<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> - <property name="broker-plugins-firewall.libs" value=""/> - - <import file="../../module.xml" /> - - <target name="bundle" depends="bundle-tasks" /> - -</project> diff --git a/java/broker-plugins/management-http/src/main/java/resources/groupprovider/addGroup.html b/java/broker-plugins/management-http/src/main/java/resources/groupprovider/addGroup.html new file mode 100644 index 0000000000..8d3431808a --- /dev/null +++ b/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/java/broker-plugins/management-http/src/main/java/resources/groupprovider/showFileGroupManager.html b/java/broker-plugins/management-http/src/main/java/resources/groupprovider/showFileGroupManager.html new file mode 100644 index 0000000000..734e8b5419 --- /dev/null +++ b/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/java/broker-plugins/management-http/src/main/java/resources/management.html b/java/broker-plugins/management-http/src/main/java/resources/index.html index a8345a8503..2fb9137ff8 100644 --- a/java/broker-plugins/management-http/src/main/java/resources/management.html +++ b/java/broker-plugins/management-http/src/main/java/resources/index.html @@ -73,10 +73,8 @@ <div id="pageLayout" data-dojo-type="dijit.layout.BorderContainer" data-dojo-props="design: 'headline', gutters: false"> <div data-dojo-type="dijit.layout.ContentPane" data-dojo-props="region:'top'"> - <div id="header" class="header"></div> - </div> - <div data-dojo-type="dijit.layout.ContentPane" data-dojo-props="region:'top'"> - <div id="login"></div> + <div id="header" class="header" style="float: left; width: 300px"></div> + <div id="login" style="float: right"></div> </div> <div data-dojo-type="dijit.layout.ContentPane" data-dojo-props="region:'leading', splitter: true"> <div qpid-type="treeView" qpid-props="query: 'rest/structure'" ></div> diff --git a/java/broker-plugins/management-http/src/main/java/resources/js/qpid/authorization/sasl.js b/java/broker-plugins/management-http/src/main/java/resources/js/qpid/authorization/sasl.js index 152504da86..b4f0728685 100644 --- a/java/broker-plugins/management-http/src/main/java/resources/js/qpid/authorization/sasl.js +++ b/java/broker-plugins/management-http/src/main/java/resources/js/qpid/authorization/sasl.js @@ -71,7 +71,7 @@ var saslPlain = function saslPlain(user, password) }, function(error) { - if(error.status == 401) + if(error.status == 403) { alert("Authentication Failed"); } @@ -127,7 +127,7 @@ var saslCramMD5 = function saslCramMD5(user, password) }, function(error) { - if(error.status == 401) + if(error.status == 403) { alert("Authentication Failed"); } @@ -141,7 +141,7 @@ var saslCramMD5 = function saslCramMD5(user, password) }, function(error) { - if(error.status == 401) + if(error.status == 403) { alert("Authentication Failed"); } @@ -152,10 +152,45 @@ var saslCramMD5 = function saslCramMD5(user, password) }); }; +var containsMechanism = function containsMechanism(mechanisms, mech) +{ + for (var i = 0; i < mechanisms.length; i++) { + if (mechanisms[i] == mech) { + return true; + } + } + + return false; +}; + var doAuthenticate = function doAuthenticate() { - saslCramMD5(dojo.byId("username").value, dojo.byId("pass").value); - updateAuthentication(); + dojo.xhrGet({ + // The URL of the request + url: "rest/sasl", + handleAs: "json" + }).then(function(data) + { + var mechMap = data.mechanisms; + + if (containsMechanism(mechMap, "CRAM-MD5")) + { + saslCramMD5(dojo.byId("username").value, dojo.byId("pass").value); + updateAuthentication(); + } + else if (containsMechanism(mechMap, "PLAIN")) + { + saslPlain(dojo.byId("username").value, dojo.byId("pass").value); + updateAuthentication(); + } + else + { + alert("No supported SASL mechanism offered: " + mechMap); + } + } + ); + + }; @@ -170,13 +205,13 @@ var updateAuthentication = function updateAuthentication() if(data.user) { dojo.byId("authenticatedUser").innerHTML = data.user; - dojo.style(button.domNode, {visibility: 'hidden'}); - dojo.style(usernameSpan, {visibility: 'visible'}); + dojo.style(button.domNode, {display: 'none'}); + dojo.style(usernameSpan, {display: 'block'}); } else { - dojo.style(button.domNode, {visibility: 'visible'}); - dojo.style(usernameSpan, {visibility: 'hidden'}); + dojo.style(button.domNode, {display: 'block'}); + dojo.style(usernameSpan, {display: 'none'}); } } ); @@ -198,13 +233,13 @@ require(["dijit/form/DropDownButton", "dijit/TooltipDialog", "dijit/form/TextBox dropDown: dialog }); - usernameSpan = domConstruct.create("span", { innerHTML: '<strong>User: </strong><span id="authenticatedUser"></span>', - style: { visibility: "hidden" }}); + usernameSpan = domConstruct.create("span", { innerHTML: '<strong>User: </strong> <span id="authenticatedUser"></span><a href="logout">[logout]</a>', + style: { display: "none" }}); var loginDiv = dom.byId("login"); - loginDiv.appendChild(button.domNode); loginDiv.appendChild(usernameSpan); + loginDiv.appendChild(button.domNode); diff --git a/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/util.js b/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/util.js index 08fdf5c99b..5557c37a2c 100644 --- a/java/broker-plugins/management-http/src/main/java/resources/js/qpid/common/util.js +++ b/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/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Exchange.js b/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Exchange.js index 37bae1ef8e..5a5a6515ef 100644 --- a/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/Exchange.js +++ b/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/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/GroupProvider.js b/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/GroupProvider.js new file mode 100644 index 0000000000..4e05f4b0ea --- /dev/null +++ b/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/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/VirtualHost.js b/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/VirtualHost.js index 957f2381cf..2efc46476d 100644 --- a/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/VirtualHost.js +++ b/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/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/controller.js b/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/controller.js index 1aa05a5a3c..5d3a666760 100644 --- a/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/controller.js +++ b/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/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/group/Group.js b/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/group/Group.js new file mode 100644 index 0000000000..ea918644e9 --- /dev/null +++ b/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/group/Group.js @@ -0,0 +1,204 @@ +/* + * + * 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; + + xhr.get({url: this.query, sync: properties.useSyncGet, handleAs: "json"}) + .then(function(data) { + that.groupMemberData = data; + + util.flattenStatistics( that.groupMemberData ); + + that.groupMembersUpdatableStore.update(that.groupMemberData); + }); + }; + + 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/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/group/addGroupMember.js b/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/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/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/groupprovider/FileGroupManager.js b/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/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/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/treeView.js b/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/treeView.js index b1d4abf8c1..59356cfce1 100644 --- a/java/broker-plugins/management-http/src/main/java/resources/js/qpid/management/treeView.js +++ b/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/java/broker-plugins/management-http/src/main/java/resources/showGroupProvider.html b/java/broker-plugins/management-http/src/main/java/resources/showGroupProvider.html new file mode 100644 index 0000000000..914857db5c --- /dev/null +++ b/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/java/broker-plugins/management-http/src/main/resources/META-INF/services/org.apache.qpid.server.plugin.PluginFactory b/java/broker-plugins/management-http/src/main/resources/META-INF/services/org.apache.qpid.server.plugin.PluginFactory new file mode 100644 index 0000000000..7ffb9a9013 --- /dev/null +++ b/java/broker-plugins/management-http/src/main/resources/META-INF/services/org.apache.qpid.server.plugin.PluginFactory @@ -0,0 +1,19 @@ +# +# 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. +# +org.apache.qpid.server.management.plugin.HttpManagementFactory diff --git a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/HttpManagementFactoryTest.java b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/HttpManagementFactoryTest.java new file mode 100644 index 0000000000..bb4c46826c --- /dev/null +++ b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/HttpManagementFactoryTest.java @@ -0,0 +1,61 @@ +/* + * 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; + +import static org.mockito.Mockito.mock; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.plugin.PluginFactory; +import org.apache.qpid.test.utils.QpidTestCase; + +public class HttpManagementFactoryTest extends QpidTestCase +{ + private static final int SESSION_TIMEOUT = 3600; + + private PluginFactory _pluginFactory = new HttpManagementFactory(); + private Map<String, Object> _attributes = new HashMap<String, Object>(); + private Broker _broker = mock(Broker.class); + private UUID _id = UUID.randomUUID(); + + public void testCreateInstanceReturnsNullWhenPluginTypeMissing() throws Exception + { + assertNull(_pluginFactory.createInstance(_id, _attributes, _broker)); + } + public void testCreateInstanceReturnsNullWhenPluginTypeNotHttp() + { + _attributes.put(PluginFactory.PLUGIN_TYPE, "notHttp"); + assertNull(_pluginFactory.createInstance(_id, _attributes, _broker)); + } + + public void testCreateInstance() throws Exception + { + _attributes.put(PluginFactory.PLUGIN_TYPE, HttpManagement.PLUGIN_TYPE); + _attributes.put(HttpManagement.TIME_OUT, SESSION_TIMEOUT); + + HttpManagement management = (HttpManagement) _pluginFactory.createInstance(_id, _attributes, _broker); + + assertEquals(_broker, management.getBroker()); + assertEquals(SESSION_TIMEOUT, management.getSessionTimeout()); + } + +} diff --git a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/Asserts.java b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/Asserts.java deleted file mode 100644 index 2595007574..0000000000 --- a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/Asserts.java +++ /dev/null @@ -1,249 +0,0 @@ -/* - * - * 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 static junit.framework.Assert.assertEquals; -import static junit.framework.Assert.assertNotNull; - -import java.util.Arrays; -import java.util.Collection; -import java.util.HashSet; -import java.util.Map; - -import javax.jms.JMSException; - -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.server.model.Binding; -import org.apache.qpid.server.model.Broker; -import org.apache.qpid.server.model.Connection; -import org.apache.qpid.server.model.Exchange; -import org.apache.qpid.server.model.LifetimePolicy; -import org.apache.qpid.server.model.Port; -import org.apache.qpid.server.model.Queue; -import org.apache.qpid.server.model.State; -import org.apache.qpid.server.model.VirtualHost; - -public class Asserts -{ - public static final String STATISTICS_ATTRIBUTE = "statistics"; - - public static void assertVirtualHost(String virtualHostName, Map<String, Object> virtualHost) - { - assertNotNull("Virtualhost " + virtualHostName + " data are not found", virtualHost); - assertAttributesPresent(virtualHost, VirtualHost.AVAILABLE_ATTRIBUTES, VirtualHost.TIME_TO_LIVE, - VirtualHost.CREATED, VirtualHost.UPDATED, VirtualHost.SUPPORTED_QUEUE_TYPES, VirtualHost.STORE_CONFIGURATION); - - assertEquals("Unexpected value of attribute " + VirtualHost.NAME, virtualHostName, virtualHost.get(VirtualHost.NAME)); - assertNotNull("Unexpected value of attribute " + VirtualHost.ID, virtualHost.get(VirtualHost.ID)); - assertEquals("Unexpected value of attribute " + VirtualHost.STATE, State.ACTIVE.name(), - virtualHost.get(VirtualHost.STATE)); - assertEquals("Unexpected value of attribute " + VirtualHost.DURABLE, Boolean.TRUE, - virtualHost.get(VirtualHost.DURABLE)); - assertEquals("Unexpected value of attribute " + VirtualHost.LIFETIME_POLICY, LifetimePolicy.PERMANENT.name(), - virtualHost.get(VirtualHost.LIFETIME_POLICY)); - assertEquals("Unexpected value of attribute " + VirtualHost.DEAD_LETTER_QUEUE_ENABLED, Boolean.FALSE, - virtualHost.get(VirtualHost.DEAD_LETTER_QUEUE_ENABLED)); - - @SuppressWarnings("unchecked") - Collection<String> exchangeTypes = (Collection<String>) virtualHost.get(VirtualHost.SUPPORTED_EXCHANGE_TYPES); - assertEquals("Unexpected value of attribute " + VirtualHost.SUPPORTED_EXCHANGE_TYPES, - new HashSet<String>(Arrays.asList("headers", "topic", "direct", "fanout", "management")), - new HashSet<String>(exchangeTypes)); - - @SuppressWarnings("unchecked") - Map<String, Object> statistics = (Map<String, Object>) virtualHost.get(STATISTICS_ATTRIBUTE); - Asserts.assertAttributesPresent(statistics, VirtualHost.AVAILABLE_STATISTICS, VirtualHost.BYTES_RETAINED, - VirtualHost.LOCAL_TRANSACTION_BEGINS, VirtualHost.LOCAL_TRANSACTION_ROLLBACKS, - VirtualHost.MESSAGES_RETAINED, VirtualHost.STATE_CHANGED, VirtualHost.XA_TRANSACTION_BRANCH_ENDS, - VirtualHost.XA_TRANSACTION_BRANCH_STARTS, VirtualHost.XA_TRANSACTION_BRANCH_SUSPENDS); - - } - - public static void assertQueue(String queueName, String queueType, Map<String, Object> queueData) - { - assertQueue(queueName, queueType, queueData, null); - } - - public static void assertQueue(String queueName, String queueType, Map<String, Object> queueData, Map<String, Object> expectedAttributes) - { - assertNotNull("Queue " + queueName + " is not found!", queueData); - Asserts.assertAttributesPresent(queueData, Queue.AVAILABLE_ATTRIBUTES, Queue.CREATED, Queue.UPDATED, - Queue.DESCRIPTION, Queue.TIME_TO_LIVE, Queue.ALTERNATE_EXCHANGE, Queue.OWNER, Queue.NO_LOCAL, Queue.LVQ_KEY, - Queue.SORT_KEY, Queue.MESSAGE_GROUP_KEY, Queue.MESSAGE_GROUP_DEFAULT_GROUP, - Queue.MESSAGE_GROUP_SHARED_GROUPS, Queue.PRIORITIES); - - assertEquals("Unexpected value of queue attribute " + Queue.NAME, queueName, queueData.get(Queue.NAME)); - assertNotNull("Unexpected value of queue attribute " + Queue.ID, queueData.get(Queue.ID)); - assertEquals("Unexpected value of queue attribute " + Queue.STATE, State.ACTIVE.name(), queueData.get(Queue.STATE)); - assertEquals("Unexpected value of queue attribute " + Queue.LIFETIME_POLICY, LifetimePolicy.PERMANENT.name(), - queueData.get(Queue.LIFETIME_POLICY)); - assertEquals("Unexpected value of queue attribute " + Queue.TYPE, queueType, queueData.get(Queue.TYPE)); - if (expectedAttributes == null) - { - assertEquals("Unexpected value of queue attribute " + Queue.EXCLUSIVE, Boolean.FALSE, queueData.get(Queue.EXCLUSIVE)); - assertEquals("Unexpected value of queue attribute " + Queue.MAXIMUM_DELIVERY_ATTEMPTS, 0, - queueData.get(Queue.MAXIMUM_DELIVERY_ATTEMPTS)); - assertEquals("Unexpected value of queue attribute " + Queue.QUEUE_FLOW_CONTROL_SIZE_BYTES, 0, - queueData.get(Queue.QUEUE_FLOW_CONTROL_SIZE_BYTES)); - assertEquals("Unexpected value of queue attribute " + Queue.QUEUE_FLOW_RESUME_SIZE_BYTES, 0, - queueData.get(Queue.QUEUE_FLOW_RESUME_SIZE_BYTES)); - assertEquals("Unexpected value of queue attribute " + Queue.QUEUE_FLOW_STOPPED, Boolean.FALSE, - queueData.get(Queue.QUEUE_FLOW_STOPPED)); - } - else - { - for (Map.Entry<String, Object> attribute : expectedAttributes.entrySet()) - { - assertEquals("Unexpected value of " + queueName + " queue attribute " + attribute.getKey(), - attribute.getValue(), queueData.get(attribute.getKey())); - } - } - - assertNotNull("Unexpected value of queue attribute statistics", queueData.get(Asserts.STATISTICS_ATTRIBUTE)); - @SuppressWarnings("unchecked") - Map<String, Object> statistics = (Map<String, Object>) queueData.get(Asserts.STATISTICS_ATTRIBUTE); - Asserts.assertAttributesPresent(statistics, Queue.AVAILABLE_STATISTICS, Queue.DISCARDS_TTL_BYTES, - Queue.DISCARDS_TTL_MESSAGES, Queue.STATE_CHANGED); - } - - public static void assertAttributesPresent(Map<String, Object> data, String[] attributes) - { - for (String name : attributes) - { - assertNotNull("Attribute " + name + " is not present", data.get(name)); - } - } - - public static void assertAttributesPresent(Map<String, Object> data, Collection<String> attributes, - String... unsupportedAttributes) - { - for (String name : attributes) - { - boolean unsupported = false; - for (String unsupportedAttribute : unsupportedAttributes) - { - if (unsupportedAttribute.equals(name)) - { - unsupported = true; - break; - } - } - if (unsupported) - { - continue; - } - assertNotNull("Attribute " + name + " is not present", data.get(name)); - } - } - - public static void assertConnection(Map<String, Object> connectionData, AMQConnection connection) throws JMSException - { - assertNotNull("Unexpected connection data", connectionData); - assertAttributesPresent(connectionData, Connection.AVAILABLE_ATTRIBUTES, Connection.STATE, Connection.DURABLE, - Connection.LIFETIME_POLICY, Connection.TIME_TO_LIVE, Connection.CREATED, Connection.UPDATED, - Connection.INCOMING, Connection.REMOTE_PROCESS_NAME, Connection.REMOTE_PROCESS_PID, - Connection.LOCAL_ADDRESS, Connection.PROPERTIES); - - assertEquals("Unexpected value of connection attribute " + Connection.SESSION_COUNT_LIMIT, - (int) connection.getMaximumChannelCount(), connectionData.get(Connection.SESSION_COUNT_LIMIT)); - assertEquals("Unexpected value of connection attribute " + Connection.CLIENT_ID, "clientid", - connectionData.get(Connection.CLIENT_ID)); - assertEquals("Unexpected value of connection attribute " + Connection.PRINCIPAL, "guest", - connectionData.get(Connection.PRINCIPAL)); - - @SuppressWarnings("unchecked") - Map<String, Object> statistics = (Map<String, Object>) connectionData.get(STATISTICS_ATTRIBUTE); - assertAttributesPresent(statistics, Connection.AVAILABLE_STATISTICS, Connection.LOCAL_TRANSACTION_BEGINS, - Connection.LOCAL_TRANSACTION_ROLLBACKS, Connection.STATE_CHANGED, Connection.XA_TRANSACTION_BRANCH_ENDS, - Connection.XA_TRANSACTION_BRANCH_STARTS, Connection.XA_TRANSACTION_BRANCH_SUSPENDS); - assertEquals("Unexpected value of connection statistics attribute " + Connection.SESSION_COUNT, 1, - statistics.get(Connection.SESSION_COUNT)); - } - - public static void assertPortAttributes(Map<String, Object> port) - { - assertAttributesPresent(port, Port.AVAILABLE_ATTRIBUTES, Port.CREATED, Port.UPDATED); - - assertNotNull("Unexpected value of attribute " + Port.ID, port.get(Port.ID)); - assertEquals("Unexpected value of attribute " + Port.DURABLE, Boolean.FALSE, port.get(Port.DURABLE)); - assertEquals("Unexpected value of attribute " + Port.LIFETIME_POLICY, LifetimePolicy.PERMANENT.name(), - port.get(Broker.LIFETIME_POLICY)); - assertEquals("Unexpected value of attribute " + Port.STATE, State.ACTIVE.name(), port.get(Port.STATE)); - assertEquals("Unexpected value of attribute " + Port.TIME_TO_LIVE, 0, port.get(Port.TIME_TO_LIVE)); - assertNotNull("Unexpected value of attribute " + Port.BINDING_ADDRESS, port.get(Port.BINDING_ADDRESS)); - assertNotNull("Unexpected value of attribute " + Port.PROTOCOLS, port.get(Port.PROTOCOLS)); - assertNotNull("Unexpected value of attribute " + Port.NAME, port.get(Port.NAME)); - - @SuppressWarnings("unchecked") - Collection<String> transports = (Collection<String>) port.get(Port.TRANSPORTS); - assertEquals("Unexpected value of attribute " + Port.TRANSPORTS, new HashSet<String>(Arrays.asList("TCP")), - new HashSet<String>(transports)); - } - - public static void assertDurableExchange(String exchangeName, String type, Map<String, Object> exchangeData) - { - assertExchange(exchangeName, type, exchangeData); - - assertEquals("Unexpected value of exchange attribute " + Exchange.DURABLE, Boolean.TRUE, - exchangeData.get(Exchange.DURABLE)); - } - - public static void assertExchange(String exchangeName, String type, Map<String, Object> exchangeData) - { - assertNotNull("Exchange " + exchangeName + " is not found!", exchangeData); - assertAttributesPresent(exchangeData, Exchange.AVAILABLE_ATTRIBUTES, Exchange.CREATED, Exchange.UPDATED, - Exchange.ALTERNATE_EXCHANGE, Exchange.TIME_TO_LIVE); - - assertEquals("Unexpected value of exchange attribute " + Exchange.NAME, exchangeName, - exchangeData.get(Exchange.NAME)); - assertNotNull("Unexpected value of exchange attribute " + Exchange.ID, exchangeData.get(VirtualHost.ID)); - assertEquals("Unexpected value of exchange attribute " + Exchange.STATE, State.ACTIVE.name(), - exchangeData.get(Exchange.STATE)); - - assertEquals("Unexpected value of exchange attribute " + Exchange.LIFETIME_POLICY, LifetimePolicy.PERMANENT.name(), - exchangeData.get(Exchange.LIFETIME_POLICY)); - assertEquals("Unexpected value of exchange attribute " + Exchange.TYPE, type, exchangeData.get(Exchange.TYPE)); - assertNotNull("Unexpected value of exchange attribute statistics", exchangeData.get(STATISTICS_ATTRIBUTE)); - - @SuppressWarnings("unchecked") - Map<String, Object> statistics = (Map<String, Object>) exchangeData.get(STATISTICS_ATTRIBUTE); - assertAttributesPresent(statistics, Exchange.AVAILABLE_STATISTICS, Exchange.STATE_CHANGED, Exchange.PRODUCER_COUNT); - } - - public static void assertBinding(String bindingName, String queueName, String exchange, Map<String, Object> binding) - { - assertNotNull("Binding map should not be null", binding); - assertAttributesPresent(binding, Binding.AVAILABLE_ATTRIBUTES, Binding.STATE, Binding.TIME_TO_LIVE, - Binding.CREATED, Binding.UPDATED); - - assertEquals("Unexpected binding attribute " + Binding.NAME, bindingName, binding.get(Binding.NAME)); - assertEquals("Unexpected binding attribute " + Binding.QUEUE, queueName, binding.get(Binding.QUEUE)); - assertEquals("Unexpected binding attribute " + Binding.EXCHANGE, exchange, binding.get(Binding.EXCHANGE)); - assertEquals("Unexpected binding attribute " + Binding.LIFETIME_POLICY, LifetimePolicy.PERMANENT.name(), - binding.get(Binding.LIFETIME_POLICY)); - } - - public static void assertBinding(String queueName, String exchange, Map<String, Object> binding) - { - assertBinding(queueName, queueName, exchange, binding); - } - -} diff --git a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/AuthenticationProviderRestTest.java b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/AuthenticationProviderRestTest.java deleted file mode 100644 index 5e6d9a998a..0000000000 --- a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/AuthenticationProviderRestTest.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * - * 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.util.List; -import java.util.Map; - -import org.apache.qpid.server.model.AuthenticationProvider; -import org.apache.qpid.server.model.LifetimePolicy; -import org.apache.qpid.server.model.State; -import org.apache.qpid.server.model.User; - -public class AuthenticationProviderRestTest extends QpidRestTestCase -{ - - public void testGet() throws Exception - { - List<Map<String, Object>> providerDetails = 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/" - + provider.get(AuthenticationProvider.NAME)); - assertNotNull("Cannot load data for " + provider.get(AuthenticationProvider.NAME), data); - assertProvider("PrincipalDatabaseAuthenticationManager", data); - } - } - - private void assertProvider(String type, Map<String, Object> provider) - { - Asserts.assertAttributesPresent(provider, AuthenticationProvider.AVAILABLE_ATTRIBUTES, - AuthenticationProvider.CREATED, AuthenticationProvider.UPDATED, AuthenticationProvider.DESCRIPTION, - AuthenticationProvider.TIME_TO_LIVE); - assertEquals("Unexpected value of provider attribute " + AuthenticationProvider.STATE, State.ACTIVE.name(), - provider.get(AuthenticationProvider.STATE)); - assertEquals("Unexpected value of provider attribute " + AuthenticationProvider.LIFETIME_POLICY, - LifetimePolicy.PERMANENT.name(), provider.get(AuthenticationProvider.LIFETIME_POLICY)); - assertEquals("Unexpected value of provider attribute " + AuthenticationProvider.DURABLE, Boolean.TRUE, - provider.get(AuthenticationProvider.DURABLE)); - assertEquals("Unexpected value of provider attribute " + AuthenticationProvider.TYPE, type, - provider.get(AuthenticationProvider.TYPE)); - - @SuppressWarnings("unchecked") - List<Map<String, Object>> users = (List<Map<String, Object>>) provider.get("users"); - assertNotNull("Users are not found", users); - assertTrue("Unexpected number of users", users.size() > 1); - for (Map<String, Object> user : users) - { - assertNotNull("Attribute " + User.ID, user.get(User.ID)); - assertNotNull("Attribute " + User.NAME, user.get(User.NAME)); - } - } -} diff --git a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/BindingRestTest.java b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/BindingRestTest.java deleted file mode 100644 index 1ed0d97185..0000000000 --- a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/BindingRestTest.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * - * 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.net.HttpURLConnection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.apache.qpid.server.model.Binding; - -public class BindingRestTest extends QpidRestTestCase -{ - - public void testGetAllBindings() throws Exception - { - List<Map<String, Object>> bindings = 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) - { - Asserts.assertBinding((String) binding.get(Binding.NAME), (String) binding.get(Binding.EXCHANGE), binding); - } - } - - public void testGetVirtualHostBindings() throws Exception - { - List<Map<String, Object>> bindings = 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) - { - Map<String, Object> searchAttributes = new HashMap<String, Object>(); - searchAttributes.put(Binding.NAME, queueName); - searchAttributes.put(Binding.EXCHANGE, "amq.direct"); - - Map<String, Object> binding = find(searchAttributes, bindings); - Asserts.assertBinding(queueName, "amq.direct", binding); - - searchAttributes.put(Binding.EXCHANGE, "<<default>>"); - - binding = find(searchAttributes, bindings); - Asserts.assertBinding(queueName, "<<default>>", binding); - } - } - - public void testGetVirtualHostExchangeBindings() throws Exception - { - List<Map<String, Object>> bindings = 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); - Asserts.assertBinding(queueName, "amq.direct", binding); - } - } - - public void testGetVirtualHostExchangeQueueBindings() throws Exception - { - List<Map<String, Object>> bindings = 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)); - } - - - public void testDeleteBinding() throws Exception - { - List<Map<String, Object>> bindings = 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"); - connection.connect(); - assertEquals("Unexpected response code", 200, connection.getResponseCode()); - - bindings = 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"); - connection.connect(); - assertEquals("Unexpected response code", 200, connection.getResponseCode()); - List<Map<String, Object>> bindings = getJsonAsList("/rest/binding/test/amq.direct/queue"); - assertEquals("Binding should be deleted", 0, bindings.size()); - } - - public void testCreateBinding() throws Exception - { - String bindingName = getTestName(); - Map<String, Object> bindingData = new HashMap<String, Object>(); - bindingData.put(Binding.NAME, bindingName); - bindingData.put(Binding.QUEUE, "queue"); - bindingData.put(Binding.EXCHANGE, "amq.direct"); - - HttpURLConnection connection = openManagementConection("/rest/binding/test/amq.direct/queue/" + bindingName, "PUT"); - connection.connect(); - 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); - - Asserts.assertBinding(bindingName, "queue", "amq.direct", binding); - } - -} diff --git a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/BrokerRestHttpsTest.java b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/BrokerRestHttpsTest.java deleted file mode 100644 index 4bbe9155cd..0000000000 --- a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/BrokerRestHttpsTest.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * - * 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.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; - -public class BrokerRestHttpsTest extends QpidRestTestCase -{ - private static final String TRUSTSTORE = "test-profiles/test_resources/ssl/java_client_truststore.jks"; - private static final String TRUSTSTORE_PASSWORD = "password"; - - @Override - public void setUp() throws Exception - { - setSystemProperty("javax.net.debug", "ssl"); - super.setUp(); - setSystemProperty("javax.net.ssl.trustStore", TRUSTSTORE); - setSystemProperty("javax.net.ssl.trustStorePassword", TRUSTSTORE_PASSWORD); - } - - @Override - protected void customizeConfiguration() throws ConfigurationException, IOException - { - 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; - } - - public void testGetWithHttps() throws Exception - { - Map<String, Object> brokerDetails = 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/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/BrokerRestTest.java b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/BrokerRestTest.java deleted file mode 100644 index f2970e2ba9..0000000000 --- a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/BrokerRestTest.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * - * 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.util.Arrays; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Map; - -import org.apache.qpid.common.QpidProperties; -import org.apache.qpid.server.model.Broker; -import org.apache.qpid.server.model.LifetimePolicy; -import org.apache.qpid.server.model.Port; -import org.apache.qpid.server.model.State; -import org.apache.qpid.server.model.VirtualHost; - -public class BrokerRestTest extends QpidRestTestCase -{ - - private static final String BROKER_AUTHENTICATIONPROVIDERS_ATTRIBUTE = "authenticationproviders"; - private static final String BROKER_PORTS_ATTRIBUTE = "ports"; - private static final String BROKER_VIRTUALHOSTS_ATTRIBUTE = "virtualhosts"; - private static final String BROKER_STATISTICS_ATTRIBUTE = "statistics"; - - public void testGet() throws Exception - { - Map<String, Object> brokerDetails = getJsonAsSingletonList("/rest/broker"); - - assertBrokerAttributes(brokerDetails); - - @SuppressWarnings("unchecked") - Map<String, Object> statistics = (Map<String, Object>) brokerDetails.get(BROKER_STATISTICS_ATTRIBUTE); - Asserts.assertAttributesPresent(statistics, new String[]{ "bytesIn", "messagesOut", "bytesOut", "messagesIn" }); - - @SuppressWarnings("unchecked") - 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)); - - @SuppressWarnings("unchecked") - List<Map<String, Object>> ports = (List<Map<String, Object>>) brokerDetails.get(BROKER_PORTS_ATTRIBUTE); - assertEquals("Unexpected number of ports", 2, ports.size()); - - for (Map<String, Object> port : ports) - { - Asserts.assertPortAttributes(port); - } - - 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); - - assertNotNull("Cannot find AMQP port", amqpPort); - assertNotNull("Cannot find HTTP port", httpPort); - - @SuppressWarnings("unchecked") - Collection<String> port1Protocols = (Collection<String>) amqpPort.get(Port.PROTOCOLS); - assertFalse("AMQP protocol list cannot contain HTTP", port1Protocols.contains("HTTP")); - - @SuppressWarnings("unchecked") - Collection<String> port2Protocols = (Collection<String>) httpPort.get(Port.PROTOCOLS); - assertEquals("Unexpected value of attribute " + Port.PROTOCOLS, new HashSet<String>(Arrays.asList("HTTP")), - new HashSet<String>(port2Protocols)); - } - - protected void assertBrokerAttributes(Map<String, Object> brokerDetails) - { - Asserts.assertAttributesPresent(brokerDetails, Broker.AVAILABLE_ATTRIBUTES, - Broker.BYTES_RETAINED, Broker.PROCESS_PID, Broker.SUPPORTED_STORE_TYPES, - Broker.CREATED, Broker.TIME_TO_LIVE, Broker.UPDATED); - - assertEquals("Unexpected value of attribute " + Broker.BUILD_VERSION, QpidProperties.getBuildVersion(), - brokerDetails.get(Broker.BUILD_VERSION)); - assertEquals("Unexpected value of attribute " + Broker.OPERATING_SYSTEM, System.getProperty("os.name") + " " - + System.getProperty("os.version") + " " + System.getProperty("os.arch"), - brokerDetails.get(Broker.OPERATING_SYSTEM)); - assertEquals( - "Unexpected value of attribute " + Broker.PLATFORM, - System.getProperty("java.vendor") + " " - + System.getProperty("java.runtime.version", System.getProperty("java.version")), - brokerDetails.get(Broker.PLATFORM)); - assertEquals("Unexpected value of attribute " + Broker.DURABLE, Boolean.TRUE, brokerDetails.get(Broker.DURABLE)); - assertEquals("Unexpected value of attribute " + Broker.LIFETIME_POLICY, LifetimePolicy.PERMANENT.name(), - brokerDetails.get(Broker.LIFETIME_POLICY)); - assertEquals("Unexpected value of attribute " + Broker.NAME, "Broker", brokerDetails.get(Broker.NAME)); - assertEquals("Unexpected value of attribute " + Broker.STATE, State.ACTIVE.name(), brokerDetails.get(Broker.STATE)); - - assertNotNull("Unexpected value of attribute " + Broker.ID, brokerDetails.get(Broker.ID)); - assertNotNull("Unexpected value of attribute statistics", brokerDetails.get(BROKER_STATISTICS_ATTRIBUTE)); - assertNotNull("Unexpected value of attribute virtualhosts", brokerDetails.get(BROKER_VIRTUALHOSTS_ATTRIBUTE)); - assertNotNull("Unexpected value of attribute ports", brokerDetails.get(BROKER_PORTS_ATTRIBUTE)); - assertNotNull("Unexpected value of attribute authenticationproviders", brokerDetails.get(BROKER_AUTHENTICATIONPROVIDERS_ATTRIBUTE)); - } - -} diff --git a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/ConnectionRestTest.java b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/ConnectionRestTest.java deleted file mode 100644 index 3661b94a7c..0000000000 --- a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/ConnectionRestTest.java +++ /dev/null @@ -1,213 +0,0 @@ -/* - * - * 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.IOException; -import java.net.URLDecoder; -import java.util.List; -import java.util.Map; - -import javax.jms.Destination; -import javax.jms.JMSException; -import javax.jms.Message; -import javax.jms.MessageConsumer; -import javax.jms.MessageProducer; - -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.server.model.Connection; -import org.apache.qpid.server.model.Session; - -public class ConnectionRestTest extends QpidRestTestCase -{ - /** - * Message number to publish into queue - */ - private static final int MESSAGE_NUMBER = 5; - private static final int MESSAGE_SIZE = 6; - - private static final String SESSIONS_ATTRIBUTE = "sessions"; - - private javax.jms.Connection _connection; - private javax.jms.Session _session; - - public void setUp() throws Exception - { - super.setUp(); - - _connection = getConnection(); - _session = _connection.createSession(true, javax.jms.Session.SESSION_TRANSACTED); - String queueName = getTestQueueName(); - Destination queue = _session.createQueue(queueName); - MessageConsumer consumer = _session.createConsumer(queue); - MessageProducer producer = _session.createProducer(queue); - _connection.start(); - - // send messages - for (int i = 0; i < MESSAGE_NUMBER; i++) - { - producer.send(_session.createTextMessage("Test-" + i)); - } - _session.commit(); - - Message m = consumer.receive(1000l); - assertNotNull("Message was not received", m); - _session.commit(); - - // receive the rest of messages for rollback - for (int i = 0; i < MESSAGE_NUMBER - 1; i++) - { - m = consumer.receive(1000l); - assertNotNull("Message was not received", m); - } - _session.rollback(); - - // receive them again - for (int i = 0; i < MESSAGE_NUMBER - 1; i++) - { - m = consumer.receive(1000l); - assertNotNull("Message was not received", m); - } - } - - public void testGetAllConnections() throws Exception - { - List<Map<String, Object>> connections = 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"); - assertEquals("Unexpected number of connections", 1, connections.size()); - Asserts.assertConnection(connections.get(0), (AMQConnection) _connection); - } - - public void testGetConnectionByName() throws Exception - { - // get connection name - String connectionName = getConnectionName(); - - Map<String, Object> connectionDetails = getJsonAsSingletonList("/rest/connection/test/" - + URLDecoder.decode(connectionName, "UTF-8")); - assertConnection(connectionDetails); - } - - public void testGetAllSessions() throws Exception - { - List<Map<String, Object>> sessions = 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"); - assertEquals("Unexpected number of sessions", 1, sessions.size()); - assertSession(sessions.get(0), (AMQSession<?, ?>) _session); - } - - public void testGetConnectionSessions() throws Exception - { - // get connection name - String connectionName = getConnectionName(); - - List<Map<String, Object>> sessions = getJsonAsList("/rest/session/test/" - + URLDecoder.decode(connectionName, "UTF-8")); - assertEquals("Unexpected number of sessions", 1, sessions.size()); - assertSession(sessions.get(0), (AMQSession<?, ?>) _session); - } - - public void testGetSessionByName() throws Exception - { - // get connection name - String connectionName = getConnectionName(); - - List<Map<String, Object>> sessions = 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); - } - - private void assertConnection(Map<String, Object> connectionDetails) throws JMSException - { - Asserts.assertConnection(connectionDetails, (AMQConnection) _connection); - - @SuppressWarnings("unchecked") - Map<String, Object> statistics = (Map<String, Object>) connectionDetails.get(Asserts.STATISTICS_ATTRIBUTE); - assertEquals("Unexpected value of connection statistics attribute " + Connection.BYTES_IN, MESSAGE_NUMBER - * MESSAGE_SIZE, statistics.get(Connection.BYTES_IN)); - assertEquals("Unexpected value of connection statistics attribute " + Connection.BYTES_OUT, MESSAGE_SIZE - + ((MESSAGE_NUMBER - 1) * MESSAGE_SIZE) * 2, statistics.get(Connection.BYTES_OUT)); - assertEquals("Unexpected value of connection statistics attribute " + Connection.MESSAGES_IN, MESSAGE_NUMBER, - statistics.get(Connection.MESSAGES_IN)); - assertEquals("Unexpected value of connection statistics attribute " + Connection.MESSAGES_OUT, - MESSAGE_NUMBER * 2 - 1, statistics.get(Connection.MESSAGES_OUT)); - - @SuppressWarnings("unchecked") - List<Map<String, Object>> sessions = (List<Map<String, Object>>) connectionDetails.get(SESSIONS_ATTRIBUTE); - assertNotNull("Sessions cannot be found", sessions); - assertEquals("Unexpected number of sessions", 1, sessions.size()); - assertSession(sessions.get(0), (AMQSession<?, ?>) _session); - } - - private void assertSession(Map<String, Object> sessionData, AMQSession<?, ?> session) - { - assertNotNull("Session map cannot be null", sessionData); - Asserts.assertAttributesPresent(sessionData, Session.AVAILABLE_ATTRIBUTES, Session.STATE, Session.DURABLE, - Session.LIFETIME_POLICY, Session.TIME_TO_LIVE, Session.CREATED, Session.UPDATED); - assertEquals("Unexpecte value of attribute " + Session.NAME, session.getChannelId() + "", - sessionData.get(Session.NAME)); - assertEquals("Unexpecte value of attribute " + Session.PRODUCER_FLOW_BLOCKED, Boolean.FALSE, - sessionData.get(Session.PRODUCER_FLOW_BLOCKED)); - assertEquals("Unexpecte value of attribute " + Session.CHANNEL_ID, session.getChannelId(), - sessionData.get(Session.CHANNEL_ID)); - - @SuppressWarnings("unchecked") - Map<String, Object> statistics = (Map<String, Object>) sessionData.get(Asserts.STATISTICS_ATTRIBUTE); - Asserts.assertAttributesPresent(statistics, Session.AVAILABLE_STATISTICS, Session.BYTES_IN, Session.BYTES_OUT, - Session.STATE_CHANGED, Session.UNACKNOWLEDGED_BYTES, Session.LOCAL_TRANSACTION_OPEN, - Session.XA_TRANSACTION_BRANCH_ENDS, Session.XA_TRANSACTION_BRANCH_STARTS, - Session.XA_TRANSACTION_BRANCH_SUSPENDS); - - assertEquals("Unexpecte value of statistic attribute " + Session.UNACKNOWLEDGED_MESSAGES, MESSAGE_NUMBER - 1, - statistics.get(Session.UNACKNOWLEDGED_MESSAGES)); - assertEquals("Unexpecte value of statistic attribute " + Session.LOCAL_TRANSACTION_BEGINS, 4, - statistics.get(Session.LOCAL_TRANSACTION_BEGINS)); - assertEquals("Unexpecte value of statistic attribute " + Session.LOCAL_TRANSACTION_ROLLBACKS, 1, - statistics.get(Session.LOCAL_TRANSACTION_ROLLBACKS)); - assertEquals("Unexpecte value of statistic attribute " + Session.CONSUMER_COUNT, 1, - statistics.get(Session.CONSUMER_COUNT)); - } - - private String getConnectionName() throws IOException - { - Map<String, Object> hostDetails = getJsonAsSingletonList("/rest/virtualhost/test"); - @SuppressWarnings("unchecked") - List<Map<String, Object>> connections = (List<Map<String, Object>>) hostDetails - .get(VirtualHostRestTest.VIRTUALHOST_CONNECTIONS_ATTRIBUTE); - assertEquals("Unexpected number of connections", 1, connections.size()); - Map<String, Object> connection = connections.get(0); - String connectionName = (String) connection.get(Connection.NAME); - return connectionName; - } -} diff --git a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/ExchangeRestTest.java b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/ExchangeRestTest.java deleted file mode 100644 index 4904d2adf3..0000000000 --- a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/ExchangeRestTest.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * - * 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.net.URLDecoder; -import java.util.List; -import java.util.Map; - -import org.apache.qpid.server.model.Binding; -import org.apache.qpid.server.model.Exchange; - -public class ExchangeRestTest extends QpidRestTestCase -{ - public void testGet() throws Exception - { - List<Map<String, Object>> exchanges = 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) - { - Asserts.assertExchange((String) exchange.get(Exchange.NAME), (String) exchange.get(Exchange.TYPE), exchange); - } - } - - public void testGetHostExchanges() throws Exception - { - List<Map<String, Object>> exchanges = 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); - assertExchange(exchangeName, exchange); - } - } - - public void testGetHostExchangeByName() throws Exception - { - for (String exchangeName : EXPECTED_EXCHANGES) - { - Map<String, Object> exchange = getJsonAsSingletonList("/rest/exchange/test/" - + URLDecoder.decode(exchangeName, "UTF-8")); - assertExchange(exchangeName, exchange); - } - } - - private void assertExchange(String exchangeName, Map<String, Object> exchange) - { - assertNotNull("Exchange with name " + exchangeName + " is not found", exchange); - String type = (String) exchange.get(Exchange.TYPE); - Asserts.assertExchange(exchangeName, type, exchange); - if ("direct".equals(type)) - { - assertBindings(exchange); - } - } - - private void assertBindings(Map<String, Object> exchange) - { - @SuppressWarnings("unchecked") - 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); - Asserts.assertBinding(queueName, (String) exchange.get(Exchange.NAME), binding); - } - } - -} diff --git a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/LogRecordsRestTest.java b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/LogRecordsRestTest.java deleted file mode 100644 index c64fd6e1da..0000000000 --- a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/LogRecordsRestTest.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * - * 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.util.List; -import java.util.Map; - -public class LogRecordsRestTest extends QpidRestTestCase -{ - public void testGet() throws Exception - { - List<Map<String, Object>> logs = 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); - - assertNotNull("BRK-1004 message is not found", record); - assertNotNull("Message id cannot be null", record.get("id")); - assertNotNull("Message timestamp cannot be null", record.get("timestamp")); - assertEquals("Unexpected log level", "INFO", record.get("level")); - assertEquals("Unexpected thread", "main", record.get("thread")); - assertEquals("Unexpected logger", "qpid.message.broker.ready", record.get("logger")); - } -} diff --git a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/MessagesRestTest.java b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/MessagesRestTest.java deleted file mode 100644 index 492df43957..0000000000 --- a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/MessagesRestTest.java +++ /dev/null @@ -1,354 +0,0 @@ -/* - * - * 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.IOException; -import java.net.HttpURLConnection; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.TimeUnit; - -import javax.jms.BytesMessage; -import javax.jms.Connection; -import javax.jms.DeliveryMode; -import javax.jms.Destination; -import javax.jms.Message; -import javax.jms.MessageProducer; -import javax.jms.Session; - -import org.codehaus.jackson.JsonParseException; -import org.codehaus.jackson.map.JsonMappingException; - -public class MessagesRestTest extends QpidRestTestCase -{ - - /** - * Message number to publish into queue - */ - private static final int MESSAGE_NUMBER = 12; - - private Connection _connection; - private Session _session; - private MessageProducer _producer; - private long _startTime; - private long _ttl; - - public void setUp() throws Exception - { - super.setUp(); - _startTime = System.currentTimeMillis(); - _connection = getConnection(); - _session = _connection.createSession(true, Session.SESSION_TRANSACTED); - String queueName = getTestQueueName(); - Destination queue = _session.createQueue(queueName); - _session.createConsumer(queue); - _producer = _session.createProducer(queue); - - _ttl = TimeUnit.DAYS.toMillis(1); - for (int i = 0; i < MESSAGE_NUMBER; i++) - { - Message m = _session.createTextMessage("Test-" + i); - m.setIntProperty("index", i); - if (i % 2 == 0) - { - _producer.send(m); - } - else - { - _producer.send(m, DeliveryMode.NON_PERSISTENT, 5, _ttl); - } - } - _session.commit(); - } - - public void testGet() throws Exception - { - String queueName = getTestQueueName(); - List<Map<String, Object>> messages = getJsonAsList("/rest/message/test/" + queueName); - assertNotNull("Messages are not found", messages); - assertEquals("Unexpected number of messages", MESSAGE_NUMBER, messages.size()); - int position = 0; - for (Map<String, Object> message : messages) - { - assertMessage(position, message); - position++; - } - } - - public void testGetMessageContent() throws Exception - { - String queueName = getTestQueueName(); - - // add bytes message - BytesMessage byteMessage = _session.createBytesMessage(); - byte[] messageBytes = "Test".getBytes(); - byteMessage.writeBytes(messageBytes); - byteMessage.setStringProperty("test", "value"); - _producer.send(byteMessage); - _session.commit(); - - // get message IDs - List<Long> ids = getMesssageIds(queueName); - - Map<String, Object> message = getJsonAsMap("/rest/message/test/" + queueName + "/" + ids.get(0)); - assertMessageAttributes(message); - assertMessageAttributeValues(message, true); - - @SuppressWarnings("unchecked") - Map<String, Object> headers = (Map<String, Object>) message.get("headers"); - assertNotNull("Message headers are not found", headers); - assertEquals("Unexpected message header", 0, headers.get("index")); - - Long lastMessageId = ids.get(ids.size() - 1); - message = 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")); - - @SuppressWarnings("unchecked") - Map<String, Object> bytesMessageHeader = (Map<String, Object>) message.get("headers"); - assertNotNull("Message headers are not found", bytesMessageHeader); - assertEquals("Unexpected message header", "value", bytesMessageHeader.get("test")); - - // get content - HttpURLConnection connection = openManagementConection("/rest/message-content/test/" + queueName + "/" - + lastMessageId, "GET"); - connection.connect(); - byte[] data = readConnectionInputStream(connection); - assertTrue("Unexpected message", Arrays.equals(messageBytes, data)); - - } - - public void testPostMoveMessages() throws Exception - { - String queueName = getTestQueueName(); - String queueName2 = queueName + "_2"; - Destination queue2 = _session.createQueue(queueName2); - _session.createConsumer(queue2); - - // get message IDs - List<Long> ids = getMesssageIds(queueName); - - // move half of the messages - int movedNumber = ids.size() / 2; - List<Long> movedMessageIds = new ArrayList<Long>(); - for (int i = 0; i < movedNumber; i++) - { - movedMessageIds.add(ids.remove(i)); - } - - // move messages - HttpURLConnection connection = openManagementConection("/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); - assertEquals("Unexpected response code", 200, connection.getResponseCode()); - - // check messages on target queue - List<Map<String, Object>> messages = 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); - assertMessageAttributes(message); - } - - // check messages on original queue - messages = 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); - assertMessageAttributes(message); - } - for (Long id : movedMessageIds) - { - Map<String, Object> message = find("id", id.intValue(), messages); - assertNull("Moved message " + id + " is found on original queue", message); - } - } - - public void testPostCopyMessages() throws Exception - { - String queueName = getTestQueueName(); - String queueName2 = queueName + "_2"; - Destination queue2 = _session.createQueue(queueName2); - _session.createConsumer(queue2); - - // get message IDs - List<Long> ids = getMesssageIds(queueName); - - // copy half of the messages - int copyNumber = ids.size() / 2; - List<Long> copyMessageIds = new ArrayList<Long>(); - for (int i = 0; i < copyNumber; i++) - { - copyMessageIds.add(ids.remove(i)); - } - - // copy messages - HttpURLConnection connection = openManagementConection("/rest/message/test/" + queueName, "POST"); - - Map<String, Object> messagesData = new HashMap<String, Object>(); - messagesData.put("messages", copyMessageIds); - messagesData.put("destinationQueue", queueName2); - - 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); - 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); - assertMessageAttributes(message); - } - - // check messages on original queue - messages = 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); - assertMessageAttributes(message); - } - for (Long id : copyMessageIds) - { - Map<String, Object> message = find("id", id.intValue(), messages); - assertMessageAttributes(message); - } - } - - public void testDeleteMessages() throws Exception - { - String queueName = getTestQueueName(); - - // get message IDs - List<Long> ids = getMesssageIds(queueName); - - // delete half of the messages - int deleteNumber = ids.size() / 2; - StringBuilder queryString = new StringBuilder(); - List<Long> deleteMessageIds = new ArrayList<Long>(); - for (int i = 0; i < deleteNumber; i++) - { - Long id = ids.remove(i); - deleteMessageIds.add(id); - if (queryString.length() > 0) - { - queryString.append("&"); - } - queryString.append("id=").append(id); - } - - // delete messages - HttpURLConnection connection = openManagementConection( - "/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); - 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); - assertMessageAttributes(message); - } - for (Long id : deleteMessageIds) - { - Map<String, Object> message = 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<Long> ids = new ArrayList<Long>(); - for (Map<String, Object> message : messages) - { - ids.add(((Number) message.get("id")).longValue()); - } - return ids; - } - - private void assertMessage(int position, Map<String, Object> message) - { - assertMessageAttributes(message); - - assertEquals("Unexpected message attribute position", position, message.get("position")); - assertEquals("Unexpected message attribute size", position < 10 ? 6 : 7, message.get("size")); - boolean even = position % 2 == 0; - assertMessageAttributeValues(message, even); - } - - private void assertMessageAttributeValues(Map<String, Object> message, boolean even) - { - if (even) - { - assertEquals("Unexpected message attribute expirationTime", 0, message.get("expirationTime")); - assertEquals("Unexpected message attribute priority", 4, message.get("priority")); - assertEquals("Unexpected message attribute persistent", Boolean.TRUE, message.get("persistent")); - } - else - { - assertEquals("Unexpected message attribute expirationTime", ((Number) message.get("timestamp")).longValue() - + _ttl, message.get("expirationTime")); - assertEquals("Unexpected message attribute priority", 5, message.get("priority")); - assertEquals("Unexpected message attribute persistent", Boolean.FALSE, message.get("persistent")); - } - assertEquals("Unexpected message attribute mimeType", "text/plain", message.get("mimeType")); - assertEquals("Unexpected message attribute userId", "guest", message.get("userId")); - assertEquals("Unexpected message attribute deliveryCount", 0, message.get("deliveryCount")); - assertEquals("Unexpected message attribute state", "Available", message.get("state")); - } - - private void assertMessageAttributes(Map<String, Object> message) - { - assertNotNull("Message map cannot be null", message); - assertNotNull("Unexpected message attribute deliveryCount", message.get("deliveryCount")); - assertNotNull("Unexpected message attribute state", message.get("state")); - assertNotNull("Unexpected message attribute id", message.get("id")); - assertNotNull("Message arrivalTime cannot be null", message.get("arrivalTime")); - assertNotNull("Message timestamp cannot be null", message.get("timestamp")); - assertTrue("Message arrivalTime cannot be null", ((Number) message.get("arrivalTime")).longValue() > _startTime); - assertNotNull("Message messageId cannot be null", message.get("messageId")); - assertNotNull("Unexpected message attribute mimeType", message.get("mimeType")); - assertNotNull("Unexpected message attribute userId", message.get("userId")); - assertNotNull("Message priority cannot be null", message.get("priority")); - assertNotNull("Message expirationTime cannot be null", message.get("expirationTime")); - assertNotNull("Message persistent cannot be null", message.get("persistent")); - } -} diff --git a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/PortRestTest.java b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/PortRestTest.java deleted file mode 100644 index 739ef5c737..0000000000 --- a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/PortRestTest.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * - * 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.net.URLDecoder; -import java.util.List; -import java.util.Map; - -import org.apache.qpid.server.model.Port; - -public class PortRestTest extends QpidRestTestCase -{ - public void testGet() throws Exception - { - List<Map<String, Object>> ports = getJsonAsList("/rest/port/"); - assertNotNull("Port data cannot be null", ports); - assertEquals("Unexpected number of ports", 2, ports.size()); - int[] expectedPorts = { getPort(), getHttpPort() }; - for (int port : expectedPorts) - { - String portName = "0.0.0.0:" + port; - Map<String, Object> portData = find(Port.NAME, portName, ports); - assertNotNull("Port " + portName + " is not found", portData); - Asserts.assertPortAttributes(portData); - } - } - - public void testGetPort() throws Exception - { - List<Map<String, Object>> ports = 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")); - assertNotNull("Port " + portName + " is not found", portData); - Asserts.assertPortAttributes(portData); - } - } - -} diff --git a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/QpidRestTestCase.java b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/QpidRestTestCase.java deleted file mode 100644 index e83341de80..0000000000 --- a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/QpidRestTestCase.java +++ /dev/null @@ -1,245 +0,0 @@ -/* - * - * 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.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; - - @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) - { - for (Map<String, Object> map : data) - { - Object mapValue = map.get(name); - if (value.equals(mapValue)) - { - return map; - } - } - return null; - } - - protected 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; - } - - 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 - { - HttpURLConnection connection = openManagementConection(path, "GET"); - connection.connect(); - List<Map<String, Object>> response = readJsonResponseAsList(connection); - return response; - } - - protected Map<String, Object> getJsonAsMap(String path) throws IOException - { - HttpURLConnection connection = openManagementConection(path, "GET"); - connection.connect(); - Map<String, Object> response = readJsonResponseAsMap(connection); - return response; - } -} diff --git a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/QueueRestTest.java b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/QueueRestTest.java deleted file mode 100644 index 5f11b3fb1d..0000000000 --- a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/QueueRestTest.java +++ /dev/null @@ -1,225 +0,0 @@ -/* - * - * 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.IOException; -import java.net.HttpURLConnection; -import java.net.URLDecoder; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.jms.Connection; -import javax.jms.Destination; -import javax.jms.Message; -import javax.jms.MessageConsumer; -import javax.jms.MessageProducer; -import javax.jms.Session; - -import org.apache.qpid.server.model.Binding; -import org.apache.qpid.server.model.Consumer; -import org.apache.qpid.server.model.LifetimePolicy; -import org.apache.qpid.server.model.Queue; - -public class QueueRestTest extends QpidRestTestCase -{ - private static final String QUEUE_ATTRIBUTE_CONSUMERS = "consumers"; - private static final String QUEUE_ATTRIBUTE_BINDINGS = "bindings"; - - /** - * Message number to publish into queue - */ - private static final int MESSAGE_NUMBER = 2; - private static final int MESSAGE_PAYLOAD_SIZE = 6; - private static final int ENQUEUED_MESSAGES = 1; - private static final int DEQUEUED_MESSAGES = 1; - private static final int ENQUEUED_BYTES = MESSAGE_PAYLOAD_SIZE; - private static final int DEQUEUED_BYTES = MESSAGE_PAYLOAD_SIZE; - - private Connection _connection; - - public void setUp() throws Exception - { - super.setUp(); - _connection = getConnection(); - Session session = _connection.createSession(true, Session.SESSION_TRANSACTED); - String queueName = getTestQueueName(); - Destination queue = session.createQueue(queueName); - MessageConsumer consumer = session.createConsumer(queue); - MessageProducer producer = session.createProducer(queue); - - for (int i = 0; i < MESSAGE_NUMBER; i++) - { - producer.send(session.createTextMessage("Test-" + i)); - } - session.commit(); - _connection.start(); - Message m = consumer.receive(1000l); - assertNotNull("Message is not received", m); - session.commit(); - } - - public void testGetVirtualHostQueues() throws Exception - { - String queueName = getTestQueueName(); - List<Map<String, Object>> queues = 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); - expectedQueues[EXPECTED_QUEUES.length] = queueName; - - for (String name : expectedQueues) - { - Map<String, Object> queueDetails = find(Queue.NAME, name, queues); - Asserts.assertQueue(name, "standard", queueDetails); - - @SuppressWarnings("unchecked") - List<Map<String, Object>> bindings = (List<Map<String, Object>>) queueDetails.get(QUEUE_ATTRIBUTE_BINDINGS); - 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); - Asserts.assertBinding(name, "<<default>>", defaultExchangeBinding); - Asserts.assertBinding(name, "amq.direct", directExchangeBinding); - } - } - - public void testGetByName() throws Exception - { - String queueName = getTestQueueName(); - Map<String, Object> queueDetails = getJsonAsSingletonList("/rest/queue/test/" + queueName); - Asserts.assertQueue(queueName, "standard", queueDetails); - assertStatistics(queueDetails); - - @SuppressWarnings("unchecked") - List<Map<String, Object>> bindings = (List<Map<String, Object>>) queueDetails.get(QUEUE_ATTRIBUTE_BINDINGS); - 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); - Asserts.assertBinding(queueName, "<<default>>", defaultExchangeBinding); - Asserts.assertBinding(queueName, "amq.direct", directExchangeBinding); - - @SuppressWarnings("unchecked") - List<Map<String, Object>> consumers = (List<Map<String, Object>>) queueDetails.get(QUEUE_ATTRIBUTE_CONSUMERS); - assertNotNull("Queue consumers are not found", consumers); - assertEquals("Unexpected number of consumers", 1, consumers.size()); - assertConsumer(consumers.get(0)); - } - - public void testPutCreateBinding() throws Exception - { - String queueName = getTestQueueName(); - String bindingName = queueName + 2; - String[] exchanges = { "amq.direct", "amq.fanout", "amq.topic", "amq.match", "qpid.management", "<<default>>" }; - - for (int i = 0; i < exchanges.length; i++) - { - createBinding(bindingName, exchanges[i], queueName); - } - - Map<String, Object> queueDetails = getJsonAsSingletonList("/rest/queue/test/" + queueName); - Asserts.assertQueue(queueName, "standard", queueDetails); - - @SuppressWarnings("unchecked") - List<Map<String, Object>> bindings = (List<Map<String, Object>>) queueDetails.get(QUEUE_ATTRIBUTE_BINDINGS); - assertNotNull("Queue bindings are not found", bindings); - assertEquals("Unexpected number of bindings", exchanges.length + 2, bindings.size()); - - Map<String, Object> searchAttributes = new HashMap<String, Object>(); - searchAttributes.put(Binding.NAME, bindingName); - - for (int i = 0; i < exchanges.length; i++) - { - searchAttributes.put(Binding.EXCHANGE, exchanges[i]); - Map<String, Object> binding = find(searchAttributes, bindings); - Asserts.assertBinding(bindingName, queueName, exchanges[i], binding); - } - } - - private void createBinding(String bindingName, String exchangeName, String queueName) throws IOException - { - HttpURLConnection connection = openManagementConection( - "/rest/binding/test/" + URLDecoder.decode(exchangeName, "UTF-8") + "/" + queueName + "/" + bindingName, - "PUT"); - - Map<String, Object> bindingData = new HashMap<String, Object>(); - bindingData.put(Binding.NAME, bindingName); - bindingData.put(Binding.EXCHANGE, exchangeName); - bindingData.put(Binding.QUEUE, queueName); - - writeJsonRequest(connection, bindingData); - assertEquals("Unexpected response code", 201, connection.getResponseCode()); - - connection.disconnect(); - } - - private void assertConsumer(Map<String, Object> consumer) - { - assertNotNull("Consumer map should not be null", consumer); - Asserts.assertAttributesPresent(consumer, Consumer.AVAILABLE_ATTRIBUTES, Consumer.STATE, Consumer.TIME_TO_LIVE, - Consumer.CREATED, Consumer.UPDATED, Consumer.SETTLEMENT_MODE, Consumer.EXCLUSIVE, Consumer.SELECTOR, - Consumer.NO_LOCAL); - - assertEquals("Unexpected binding attribute " + Consumer.NAME, "1", consumer.get(Consumer.NAME)); - assertEquals("Unexpected binding attribute " + Consumer.DURABLE, Boolean.FALSE, consumer.get(Consumer.DURABLE)); - assertEquals("Unexpected binding attribute " + Consumer.LIFETIME_POLICY, LifetimePolicy.AUTO_DELETE.name(), - consumer.get(Consumer.LIFETIME_POLICY)); - assertEquals("Unexpected binding attribute " + Consumer.DISTRIBUTION_MODE, "MOVE", - consumer.get(Consumer.DISTRIBUTION_MODE)); - - @SuppressWarnings("unchecked") - Map<String, Object> statistics = (Map<String, Object>) consumer.get(Asserts.STATISTICS_ATTRIBUTE); - assertNotNull("Consumer statistics is not present", statistics); - Asserts.assertAttributesPresent(statistics, Consumer.AVAILABLE_STATISTICS, Consumer.STATE_CHANGED); - } - - private void assertStatistics(Map<String, Object> queueDetails) - { - @SuppressWarnings("unchecked") - Map<String, Object> statistics = (Map<String, Object>) queueDetails.get(Asserts.STATISTICS_ATTRIBUTE); - assertEquals("Unexpected queue statistics attribute " + Queue.PERSISTENT_DEQUEUED_MESSAGES, DEQUEUED_MESSAGES, - statistics.get(Queue.PERSISTENT_DEQUEUED_MESSAGES)); - assertEquals("Unexpected queue statistics attribute " + Queue.QUEUE_DEPTH_MESSAGES, ENQUEUED_MESSAGES, - statistics.get(Queue.QUEUE_DEPTH_MESSAGES)); - assertEquals("Unexpected queue statistics attribute " + Queue.CONSUMER_COUNT, 1, - statistics.get(Queue.CONSUMER_COUNT)); - assertEquals("Unexpected queue statistics attribute " + Queue.CONSUMER_COUNT_WITH_CREDIT, 1, - statistics.get(Queue.CONSUMER_COUNT_WITH_CREDIT)); - assertEquals("Unexpected queue statistics attribute " + Queue.BINDING_COUNT, 2, statistics.get(Queue.BINDING_COUNT)); - assertEquals("Unexpected queue statistics attribute " + Queue.PERSISTENT_DEQUEUED_MESSAGES, DEQUEUED_MESSAGES, - statistics.get(Queue.PERSISTENT_DEQUEUED_MESSAGES)); - assertEquals("Unexpected queue statistics attribute " + Queue.TOTAL_DEQUEUED_MESSAGES, DEQUEUED_MESSAGES, - statistics.get(Queue.TOTAL_DEQUEUED_MESSAGES)); - assertEquals("Unexpected queue statistics attribute " + Queue.TOTAL_DEQUEUED_BYTES, DEQUEUED_BYTES, - statistics.get(Queue.TOTAL_DEQUEUED_BYTES)); - assertEquals("Unexpected queue statistics attribute " + Queue.PERSISTENT_DEQUEUED_BYTES, DEQUEUED_BYTES, - statistics.get(Queue.TOTAL_DEQUEUED_BYTES)); - assertEquals("Unexpected queue statistics attribute " + Queue.PERSISTENT_ENQUEUED_BYTES, ENQUEUED_BYTES - + DEQUEUED_BYTES, statistics.get(Queue.PERSISTENT_ENQUEUED_BYTES)); - assertEquals("Unexpected queue statistics attribute " + Queue.TOTAL_ENQUEUED_BYTES, ENQUEUED_BYTES + DEQUEUED_BYTES, - statistics.get(Queue.TOTAL_ENQUEUED_BYTES)); - assertEquals("Unexpected queue statistics attribute " + Queue.QUEUE_DEPTH_BYTES, ENQUEUED_BYTES, - statistics.get(Queue.QUEUE_DEPTH_BYTES)); - } -} diff --git a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/StructureRestTest.java b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/StructureRestTest.java deleted file mode 100644 index b01e1d44b8..0000000000 --- a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/StructureRestTest.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * - * 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.util.List; -import java.util.Map; - -public class StructureRestTest extends QpidRestTestCase -{ - - public void testGet() throws Exception - { - Map<String, Object> structure = getJsonAsMap("/rest/structure"); - assertNotNull("Structure data cannot be null", structure); - assertNode(structure, "Broker"); - - @SuppressWarnings("unchecked") - List<Map<String, Object>> virtualhosts = (List<Map<String, Object>>) structure.get("virtualhosts"); - assertEquals("Unexpected number of virtual hosts", 3, virtualhosts.size()); - - @SuppressWarnings("unchecked") - List<Map<String, Object>> ports = (List<Map<String, Object>>) structure.get("ports"); - assertEquals("Unexpected number of ports", 2, ports.size()); - - @SuppressWarnings("unchecked") - List<Map<String, Object>> providers = (List<Map<String, Object>>) structure.get("authenticationproviders"); - assertEquals("Unexpected number of authentication providers", 1, providers.size()); - - for (String hostName : EXPECTED_HOSTS) - { - Map<String, Object> host = find("name", hostName, virtualhosts); - assertNotNull("Host " + hostName + " is not found ", host); - assertNode(host, hostName); - - @SuppressWarnings("unchecked") - List<Map<String, Object>> queues = (List<Map<String, Object>>) host.get("queues"); - assertNotNull("Host " + hostName + " queues are not found ", queues); - for (String queueName : EXPECTED_QUEUES) - { - Map<String, Object> queue = find("name", queueName, queues); - assertNotNull(hostName + " queue " + queueName + " is not found ", queue); - assertNode(queue, queueName); - - @SuppressWarnings("unchecked") - List<Map<String, Object>> bindings = (List<Map<String, Object>>) queue.get("bindings"); - assertNotNull(hostName + " queue " + queueName + " bindings are not found ", queues); - for (Map<String, Object> binding : bindings) - { - assertNode(binding, queueName); - } - } - - @SuppressWarnings("unchecked") - List<Map<String, Object>> exchanges = (List<Map<String, Object>>) host.get("exchanges"); - assertNotNull("Host " + hostName + " exchanges are not found ", exchanges); - for (String exchangeName : EXPECTED_EXCHANGES) - { - Map<String, Object> exchange = find("name", exchangeName, exchanges); - assertNotNull("Exchange " + exchangeName + " is not found ", exchange); - assertNode(exchange, exchangeName); - if ("amq.direct".equalsIgnoreCase(exchangeName) || "<<default>>".equalsIgnoreCase(exchangeName)) - { - @SuppressWarnings("unchecked") - List<Map<String, Object>> bindings = (List<Map<String, Object>>) exchange.get("bindings"); - assertNotNull(hostName + " exchange " + exchangeName + " bindings are not found ", bindings); - for (String queueName : EXPECTED_QUEUES) - { - Map<String, Object> binding = find("name", queueName, bindings); - assertNotNull(hostName + " exchange " + exchangeName + " binding " + queueName + " is not found", binding); - assertNode(binding, queueName); - } - } - } - - @SuppressWarnings("unchecked") - List<Map<String, Object>> aliases = (List<Map<String, Object>>) host.get("virtualhostaliases"); - assertNotNull("Host " + hostName + " aliaces are not found ", aliases); - assertEquals("Unexpected aliaces size", 1, aliases.size()); - assertNode(aliases.get(0), hostName); - } - - int[] expectedPorts = { getPort(), getHttpPort() }; - for (int port : expectedPorts) - { - String portName = "0.0.0.0:" + port; - Map<String, Object> portData = find("name", portName, ports); - assertNotNull("Port " + portName + " is not found ", portData); - assertNode(portData, portName); - } - } - - private void assertNode(Map<String, Object> node, String name) - { - assertEquals("Unexpected name", name, node.get("name")); - assertNotNull("Unexpected id", node.get("id")); - } -} diff --git a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/UserRestTest.java b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/UserRestTest.java deleted file mode 100644 index e56fa27e21..0000000000 --- a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/UserRestTest.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * - * 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.net.HttpURLConnection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.apache.qpid.server.model.User; - -public class UserRestTest extends QpidRestTestCase -{ - public void testGet() throws Exception - { - List<Map<String, Object>> users = getJsonAsList("/rest/user"); - assertNotNull("Users cannot be null", users); - assertTrue("Unexpected number of users", users.size() > 1); - for (Map<String, Object> user : users) - { - assertUser(user); - } - } - - public void testGetUserByName() throws Exception - { - List<Map<String, Object>> users = getJsonAsList("/rest/user"); - assertNotNull("Users cannot be null", users); - assertTrue("Unexpected number of users", users.size() > 1); - for (Map<String, Object> user : users) - { - 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/" - + userName); - assertUser(userDetails); - assertEquals("Unexpected user name", userName, userDetails.get(User.NAME)); - } - } - - 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); - - writeJsonRequest(connection, userData); - assertEquals("Unexpected response code", 201, connection.getResponseCode()); - - connection.disconnect(); - - Map<String, Object> userDetails = getJsonAsSingletonList("/rest/user/PrincipalDatabaseAuthenticationManager/" - + userName); - assertUser(userDetails); - assertEquals("Unexpected user name", userName, userDetails.get(User.NAME)); - } - - 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); - - writeJsonRequest(connection, userData); - assertEquals("Unexpected response code", 201, connection.getResponseCode()); - connection.disconnect(); - - Map<String, Object> userDetails = 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); - assertEquals("User should be deleted", 0, users.size()); - } - - private void assertUser(Map<String, Object> user) - { - assertNotNull("Attribute " + User.ID, user.get(User.ID)); - assertNotNull("Attribute " + User.NAME, user.get(User.NAME)); - } -} diff --git a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/VirtualHostRestTest.java b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/VirtualHostRestTest.java deleted file mode 100644 index 17f1aaaf7b..0000000000 --- a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/VirtualHostRestTest.java +++ /dev/null @@ -1,434 +0,0 @@ -/* - * - * 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.IOException; -import java.net.HttpURLConnection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.jms.Session; - -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.server.model.Exchange; -import org.apache.qpid.server.model.Queue; -import org.apache.qpid.server.model.VirtualHost; -import org.apache.qpid.server.queue.AMQQueueFactory; -import org.codehaus.jackson.JsonGenerationException; -import org.codehaus.jackson.map.JsonMappingException; - -public class VirtualHostRestTest extends QpidRestTestCase -{ - private static final String VIRTUALHOST_EXCHANGES_ATTRIBUTE = "exchanges"; - public static final String VIRTUALHOST_QUEUES_ATTRIBUTE = "queues"; - public static final String VIRTUALHOST_CONNECTIONS_ATTRIBUTE = "connections"; - - private AMQConnection _connection; - - public void testGet() throws Exception - { - List<Map<String, Object>> hosts = 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); - Asserts.assertVirtualHost(hostName, host); - } - } - - public void testGetHost() throws Exception - { - // create AMQP connection to get connection JSON details - _connection = (AMQConnection) getConnection(); - _connection.createSession(true, Session.SESSION_TRANSACTED); - - Map<String, Object> hostDetails = getJsonAsSingletonList("/rest/virtualhost/test"); - Asserts.assertVirtualHost("test", hostDetails); - - @SuppressWarnings("unchecked") - Map<String, Object> statistics = (Map<String, Object>) hostDetails.get(Asserts.STATISTICS_ATTRIBUTE); - assertEquals("Unexpected number of exchanges in statistics", 6, statistics.get(VirtualHost.EXCHANGE_COUNT)); - assertEquals("Unexpected number of queues in statistics", 2, statistics.get(VirtualHost.QUEUE_COUNT)); - assertEquals("Unexpected number of connections in statistics", 1, statistics.get(VirtualHost.CONNECTION_COUNT)); - - @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)); - - @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); - Asserts.assertQueue("queue", "standard", queue); - Asserts.assertQueue("ping", "standard", ping); - assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.FALSE, queue.get(Queue.DURABLE)); - assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.FALSE, ping.get(Queue.DURABLE)); - - @SuppressWarnings("unchecked") - List<Map<String, Object>> connections = (List<Map<String, Object>>) hostDetails - .get(VIRTUALHOST_CONNECTIONS_ATTRIBUTE); - assertEquals("Unexpected number of connections", 1, connections.size()); - Asserts.assertConnection(connections.get(0), _connection); - } - - public void testPutCreateQueue() throws Exception - { - String queueName = getTestQueueName(); - - createQueue(queueName + "-standard", "standard", null); - - Map<String, Object> sortedQueueAttributes = new HashMap<String, Object>(); - sortedQueueAttributes.put(Queue.SORT_KEY, "sortme"); - createQueue(queueName + "-sorted", "sorted", sortedQueueAttributes); - - Map<String, Object> priorityQueueAttributes = new HashMap<String, Object>(); - priorityQueueAttributes.put(Queue.PRIORITIES, 10); - createQueue(queueName + "-priority", "priority", priorityQueueAttributes); - - Map<String, Object> lvqQueueAttributes = new HashMap<String, Object>(); - lvqQueueAttributes.put(Queue.LVQ_KEY, "LVQ"); - createQueue(queueName + "-lvq", "lvq", lvqQueueAttributes); - - Map<String, Object> hostDetails = 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); - - Asserts.assertQueue(queueName + "-standard", "standard", standardQueue); - Asserts.assertQueue(queueName + "-sorted", "sorted", sortedQueue); - Asserts.assertQueue(queueName + "-priority", "priority", priorityQueue); - Asserts.assertQueue(queueName + "-lvq", "lvq", lvqQueue); - - assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, standardQueue.get(Queue.DURABLE)); - assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, sortedQueue.get(Queue.DURABLE)); - assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, priorityQueue.get(Queue.DURABLE)); - assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, lvqQueue.get(Queue.DURABLE)); - - assertEquals("Unexpected sorted key attribute", "sortme", sortedQueue.get(Queue.SORT_KEY)); - assertEquals("Unexpected lvq key attribute", "LVQ", lvqQueue.get(Queue.LVQ_KEY)); - assertEquals("Unexpected priorities key attribute", 10, priorityQueue.get(Queue.PRIORITIES)); - } - - public void testPutCreateExchange() throws Exception - { - String exchangeName = getTestName(); - - createExchange(exchangeName + "-direct", "direct"); - createExchange(exchangeName + "-topic", "topic"); - createExchange(exchangeName + "-headers", "headers"); - createExchange(exchangeName + "-fanout", "fanout"); - - Map<String, Object> hostDetails = 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); - - Asserts.assertDurableExchange(exchangeName + "-direct", "direct", directExchange); - Asserts.assertDurableExchange(exchangeName + "-topic", "topic", topicExchange); - Asserts.assertDurableExchange(exchangeName + "-headers", "headers", headersExchange); - Asserts.assertDurableExchange(exchangeName + "-fanout", "fanout", fanoutExchange); - - assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, directExchange.get(Queue.DURABLE)); - assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, topicExchange.get(Queue.DURABLE)); - assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, headersExchange.get(Queue.DURABLE)); - assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, fanoutExchange.get(Queue.DURABLE)); - - } - - public void testPutCreateLVQWithoutKey() throws Exception - { - String queueName = getTestQueueName()+ "-lvq"; - createQueue(queueName, "lvq", null); - - Map<String, Object> hostDetails = 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); - - Asserts.assertQueue(queueName , "lvq", lvqQueue); - assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, lvqQueue.get(Queue.DURABLE)); - assertEquals("Unexpected lvq key attribute", AMQQueueFactory.QPID_LVQ_KEY, lvqQueue.get(Queue.LVQ_KEY)); - } - - public void testPutCreateSortedQueueWithoutKey() throws Exception - { - String queueName = getTestQueueName() + "-sorted"; - int responseCode = tryCreateQueue(queueName, "sorted", null); - assertEquals("Unexpected response code", 409, responseCode); - - Map<String, Object> hostDetails = 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); - - assertNull("Sorted queue without a key was created ", testQueue); - } - - public void testPutCreatePriorityQueueWithoutKey() throws Exception - { - String queueName = getTestQueueName()+ "-priority"; - createQueue(queueName, "priority", null); - - Map<String, Object> hostDetails = 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); - - Asserts.assertQueue(queueName , "priority", priorityQueue); - assertEquals("Unexpected value of queue attribute " + Queue.DURABLE, Boolean.TRUE, priorityQueue.get(Queue.DURABLE)); - assertEquals("Unexpected number of priorities", 10, priorityQueue.get(Queue.PRIORITIES)); - } - - public void testPutCreateStandardQueueWithoutType() throws Exception - { - String queueName = getTestQueueName(); - createQueue(queueName, null, null); - - Map<String, Object> hostDetails = 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); - - Asserts.assertQueue(queueName , "standard", queue); - } - - public void testPutCreateQueueOfUnsupportedType() throws Exception - { - String queueName = getTestQueueName(); - int responseCode = tryCreateQueue(queueName, "unsupported", null); - assertEquals("Unexpected response code", 409, responseCode); - - Map<String, Object> hostDetails = 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); - - assertNull("Queue of unsupported type was created", queue); - } - - public void testDeleteQueue() throws Exception - { - String queueName = getTestQueueName(); - createQueue(queueName, null, null); - - HttpURLConnection connection = openManagementConection("/rest/queue/test/" + queueName, "DELETE"); - connection.connect(); - assertEquals("Unexpected response code", 200, connection.getResponseCode()); - List<Map<String, Object>> queues = getJsonAsList("/rest/queue/test/" + queueName); - assertEquals("Queue should be deleted", 0, queues.size()); - } - - public void testDeleteQueueById() throws Exception - { - String queueName = getTestQueueName(); - createQueue(queueName, null, null); - Map<String, Object> queueDetails = getJsonAsSingletonList("/rest/queue/test/" + queueName); - - HttpURLConnection connection = openManagementConection("/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); - assertEquals("Queue should be deleted", 0, queues.size()); - } - - public void testDeleteExchange() throws Exception - { - String exchangeName = getTestName(); - createExchange(exchangeName, "direct"); - - HttpURLConnection connection = openManagementConection("/rest/exchange/test/" + exchangeName, "DELETE"); - connection.connect(); - assertEquals("Unexpected response code", 200, connection.getResponseCode()); - List<Map<String, Object>> queues = getJsonAsList("/rest/exchange/test/" + exchangeName); - assertEquals("Exchange should be deleted", 0, queues.size()); - } - - public void testDeleteExchangeById() throws Exception - { - String exchangeName = getTestName(); - createExchange(exchangeName, "direct"); - Map<String, Object> echangeDetails = getJsonAsSingletonList("/rest/exchange/test/" + exchangeName); - - HttpURLConnection connection = openManagementConection("/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); - assertEquals("Exchange should be deleted", 0, queues.size()); - } - - public void testPutCreateQueueWithAttributes() throws Exception - { - String queueName = getTestQueueName(); - - Map<String, Object> attributes = new HashMap<String, Object>(); - attributes.put(Queue.ALERT_REPEAT_GAP, 1000); - attributes.put(Queue.ALERT_THRESHOLD_MESSAGE_AGE, 3600000); - attributes.put(Queue.ALERT_THRESHOLD_MESSAGE_SIZE, 1000000000); - attributes.put(Queue.ALERT_THRESHOLD_QUEUE_DEPTH_MESSAGES, 800); - attributes.put(Queue.MAXIMUM_DELIVERY_ATTEMPTS, 15); - attributes.put(Queue.QUEUE_FLOW_CONTROL_SIZE_BYTES, 2000000000); - attributes.put(Queue.QUEUE_FLOW_RESUME_SIZE_BYTES, 1500000000); - - createQueue(queueName + "-standard", "standard", attributes); - - Map<String, Object> sortedQueueAttributes = new HashMap<String, Object>(); - sortedQueueAttributes.putAll(attributes); - sortedQueueAttributes.put(Queue.SORT_KEY, "sortme"); - createQueue(queueName + "-sorted", "sorted", sortedQueueAttributes); - - Map<String, Object> priorityQueueAttributes = new HashMap<String, Object>(); - priorityQueueAttributes.putAll(attributes); - priorityQueueAttributes.put(Queue.PRIORITIES, 10); - createQueue(queueName + "-priority", "priority", priorityQueueAttributes); - - Map<String, Object> lvqQueueAttributes = new HashMap<String, Object>(); - lvqQueueAttributes.putAll(attributes); - lvqQueueAttributes.put(Queue.LVQ_KEY, "LVQ"); - createQueue(queueName + "-lvq", "lvq", lvqQueueAttributes); - - Map<String, Object> hostDetails = 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); - - attributes.put(Queue.DURABLE, Boolean.TRUE); - Asserts.assertQueue(queueName + "-standard", "standard", standardQueue, attributes); - Asserts.assertQueue(queueName + "-sorted", "sorted", sortedQueue, attributes); - Asserts.assertQueue(queueName + "-priority", "priority", priorityQueue, attributes); - Asserts.assertQueue(queueName + "-lvq", "lvq", lvqQueue, attributes); - - assertEquals("Unexpected sorted key attribute", "sortme", sortedQueue.get(Queue.SORT_KEY)); - assertEquals("Unexpected lvq key attribute", "LVQ", lvqQueue.get(Queue.LVQ_KEY)); - assertEquals("Unexpected priorities key attribute", 10, priorityQueue.get(Queue.PRIORITIES)); - } - - @SuppressWarnings("unchecked") - public void testCreateQueueWithDLQEnabled() throws Exception - { - String queueName = getTestQueueName(); - - Map<String, Object> attributes = new HashMap<String, Object>(); - attributes.put(AMQQueueFactory.X_QPID_DLQ_ENABLED, true); - - //verify the starting state - Map<String, Object> hostDetails = 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)); - - //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"); - 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); - assertNotNull("queue should not have been present", queue); - assertNotNull("queue should not have been present", dlqQueue); - assertNotNull("exchange should not have been present", dlExchange); - - //verify that the alternate exchange is set as expected on the new queue - Map<String, Object> queueAttributes = new HashMap<String, Object>(); - queueAttributes.put(Queue.ALTERNATE_EXCHANGE, queueName + "_DLE"); - - Asserts.assertQueue(queueName, "standard", queue, queueAttributes); - Asserts.assertQueue(queueName, "standard", queue, null); - } - - private void createExchange(String exchangeName, String exchangeType) throws IOException - { - HttpURLConnection connection = openManagementConection("/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); - assertEquals("Unexpected response code", 201, connection.getResponseCode()); - - connection.disconnect(); - } - - private void createQueue(String queueName, String queueType, Map<String, Object> attributes) throws IOException, - JsonGenerationException, JsonMappingException - { - int responseCode = tryCreateQueue(queueName, queueType, attributes); - assertEquals("Unexpected response code", 201, responseCode); - } - - private int tryCreateQueue(String queueName, String queueType, Map<String, Object> attributes) throws IOException, - JsonGenerationException, JsonMappingException - { - HttpURLConnection connection = openManagementConection("/rest/queue/test/" + queueName, "PUT"); - - Map<String, Object> queueData = new HashMap<String, Object>(); - queueData.put(Queue.NAME, queueName); - queueData.put(Queue.DURABLE, Boolean.TRUE); - if (queueType != null) - { - queueData.put(Queue.TYPE, queueType); - } - if (attributes != null) - { - queueData.putAll(attributes); - } - - writeJsonRequest(connection, queueData); - int responseCode = connection.getResponseCode(); - connection.disconnect(); - return responseCode; - } - -} diff --git a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/session/LoginLogoutReporterTest.java b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/session/LoginLogoutReporterTest.java new file mode 100644 index 0000000000..1d43c44587 --- /dev/null +++ b/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/session/LoginLogoutReporterTest.java @@ -0,0 +1,74 @@ +/* + * 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.session; + +import static org.mockito.Mockito.verify; +import static org.mockito.Matchers.argThat; + +import javax.security.auth.Subject; + +import org.apache.qpid.server.logging.LogActor; +import org.apache.qpid.server.logging.LogMessage; +import org.apache.qpid.server.security.auth.AuthenticatedPrincipal; +import org.mockito.ArgumentMatcher; +import org.mockito.Mockito; + +import junit.framework.TestCase; + +public class LoginLogoutReporterTest extends TestCase +{ + private LoginLogoutReporter _loginLogoutReport; + private Subject _subject = new Subject(); + private LogActor _logActor = Mockito.mock(LogActor.class); + + @Override + protected void setUp() throws Exception + { + super.setUp(); + + _subject.getPrincipals().add(new AuthenticatedPrincipal("mockusername")); + _loginLogoutReport = new LoginLogoutReporter(_logActor, _subject); + } + + public void testLoginLogged() + { + _loginLogoutReport.valueBound(null); + verify(_logActor).message(isLogMessageWithMessage("MNG-1007 : Open : User mockusername")); + } + + public void testLogoutLogged() + { + _loginLogoutReport.valueUnbound(null); + verify(_logActor).message(isLogMessageWithMessage("MNG-1008 : Close : User mockusername")); + } + + private LogMessage isLogMessageWithMessage(final String expectedMessage) + { + return argThat( new ArgumentMatcher<LogMessage>() + { + @Override + public boolean matches(Object argument) + { + LogMessage actual = (LogMessage) argument; + return actual.toString().equals(expectedMessage); + } + }); + } +} diff --git a/java/broker-plugins/management-jmx/MANIFEST.MF b/java/broker-plugins/management-jmx/MANIFEST.MF deleted file mode 100644 index b18ec1ace7..0000000000 --- a/java/broker-plugins/management-jmx/MANIFEST.MF +++ /dev/null @@ -1,66 +0,0 @@ -Manifest-Version: 1.0 -Bundle-ManifestVersion: 2 -Bundle-Name: Qpid Broker-Plugins Management JMX -Bundle-SymbolicName: broker-plugins-management-jmx -Bundle-Description: JMX management plugin for Qpid. -Bundle-License: http://www.apache.org/licenses/LICENSE-2.0.txt -Bundle-DocURL: http://www.apache.org/ -Bundle-Version: 1.0.0 -Bundle-Activator: org.apache.qpid.server.jmx.JMXActivator -Bundle-RequiredExecutionEnvironment: JavaSE-1.6 -Bundle-ClassPath: . -Bundle-ActivationPolicy: lazy -Import-Package: org.apache.qpid, - org.apache.qpid.framing, - org.apache.qpid.protocol, - org.apache.qpid.common, - org.apache.qpid.management.common.mbeans, - org.apache.qpid.management.common.mbeans.annotations, - org.apache.qpid.server.security.auth, - org.apache.qpid.server.security.auth.manager, - org.apache.qpid.server.security.auth.rmi, - org.apache.qpid.server.security.auth.sasl, - org.apache.qpid.server.binding, - org.apache.qpid.server.exchange, - org.apache.qpid.server.logging, - org.apache.qpid.server.logging.log4j, - org.apache.qpid.server.logging.actors, - org.apache.qpid.server.logging.messages, - org.apache.qpid.server.message, - org.apache.qpid.server.model, - org.apache.qpid.server.model.adapter, - org.apache.qpid.server.model.impl, - org.apache.qpid.server.configuration, - org.apache.qpid.server.configuration.plugins, - org.apache.qpid.server.connection, - org.apache.qpid.server.plugins, - org.apache.qpid.server.protocol, - org.apache.qpid.server.queue, - org.apache.qpid.server.registry, - org.apache.qpid.server.security, - org.apache.qpid.server.security.access, - org.apache.qpid.server.stats, - org.apache.qpid.server.virtualhost, - org.apache.qpid.util, - org.apache.commons.codec;version=1.3.0, - org.apache.commons.codec.binary;version=1.3.0, - org.apache.commons.configuration;version=1.0.0, - org.apache.commons.lang;version=1.0.0, - org.apache.commons.lang.builder;version=1.0.0, - org.apache.commons.lang.time;version=1.0.0, - org.apache.log4j;version=1.2.16, - org.codehaus.jackson;version=1.9.0, - org.codehaus.jackson.map;version=1.9.0, - javax.management.remote.rmi, - javax.management.remote, - javax.servlet, - javax.servlet.http, - javax.management;version=1.0.0, - javax.management.monitor;version=1.0.0, - javax.management.openmbean;version=1.0.0, - javax.security.auth.login;version=1.0.0, - javax.security.auth;version=1.0.0, - javax.rmi.ssl;version=1.0.0, - org.osgi.util.tracker;version=1.0.0, - org.osgi.framework;version=1.3 -Export-Package: org.apache.qpid.server.jmx;uses:="org.osgi.framework" diff --git a/java/broker-plugins/management-jmx/build.xml b/java/broker-plugins/management-jmx/build.xml index fa50b8467d..9d212cf39a 100644 --- a/java/broker-plugins/management-jmx/build.xml +++ b/java/broker-plugins/management-jmx/build.xml @@ -17,28 +17,14 @@ - under the License. --> <project name="Qpid Broker-Plugins Management JMX" default="build"> - - <condition property="systests.optional.depends" value="bdbstore" else=""> - <or> - <and> - <contains string="${modules.opt}" substring="bdbstore"/> - <contains string="${profile}" substring="bdb"/> - </and> - <and> - <istrue value="${optional}"/> - <contains string="${profile}" substring="bdb"/> - </and> - </or> - </condition> - <property name="module.depends" value="common broker management/common" /> - <property name="module.test.depends" value="systests test broker/test common/test management/common client ${systests.optional.depends}" /> + <property name="module.test.depends" value="broker/tests common/tests management/common client" /> - <property name="module.manifest" value="MANIFEST.MF" /> - <property name="module.plugin" value="true" /> <property name="module.genpom" value="true"/> <property name="module.genpom.args" value="-Sqpid-common=provided -Sqpid-broker=provided -Sqpid-management-common=provided"/> + <property name="broker.plugin" value="true"/> + <property name="broker-plugins-management-jmx.libs" value=""/> <import file="../../module.xml" /> diff --git a/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/CustomRMIServerSocketFactory.java b/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/CustomRMIServerSocketFactory.java new file mode 100644 index 0000000000..b7aab78e45 --- /dev/null +++ b/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/CustomRMIServerSocketFactory.java @@ -0,0 +1,68 @@ +/* + * 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.jmx; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.rmi.server.RMIServerSocketFactory; + +/** + * Custom RMIServerSocketFactory class, used to prevent updates to the RMI registry. + * Supplied to the registry at creation, this will prevent RMI-based operations on the + * registry such as attempting to bind a new object, thereby securing it from tampering. + * This is accomplished by always returning null when attempting to determine the address + * of the caller, thus ensuring the registry will refuse the attempt. Calls to bind etc + * made using the object reference will not be affected and continue to operate normally. + */ +class CustomRMIServerSocketFactory implements RMIServerSocketFactory +{ + + public ServerSocket createServerSocket(int port) throws IOException + { + return new NoLocalAddressServerSocket(port); + } + + private static class NoLocalAddressServerSocket extends ServerSocket + { + NoLocalAddressServerSocket(int port) throws IOException + { + super(port); + } + + @Override + public Socket accept() throws IOException + { + Socket s = new NoLocalAddressSocket(); + super.implAccept(s); + return s; + } + } + + private static class NoLocalAddressSocket extends Socket + { + @Override + public InetAddress getInetAddress() + { + return null; + } + } +}
\ No newline at end of file diff --git a/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXActivator.java b/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXActivator.java deleted file mode 100644 index c588b40de7..0000000000 --- a/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXActivator.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * - * 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.jmx; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import org.apache.log4j.Logger; -import org.apache.qpid.server.configuration.plugins.ConfigurationPluginFactory; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.osgi.framework.BundleActivator; -import org.osgi.framework.BundleContext; -import org.osgi.framework.ServiceRegistration; - -public class JMXActivator implements BundleActivator -{ - private static final Logger LOGGER = Logger.getLogger(JMXActivator.class); - - private String _bundleName; - private JMXService _jmxService; - - private List<ServiceRegistration> _registeredServices; - - - public void start(final BundleContext ctx) throws Exception - { - boolean jmxManagementEnabled = ApplicationRegistry.getInstance().getConfiguration().getJMXManagementEnabled(); - - if (jmxManagementEnabled) - { - _jmxService = new JMXService(); - startJmsService(_jmxService); - - _bundleName = ctx.getBundle().getSymbolicName(); - - _registeredServices = registerServices(ctx); - } - else - { - LOGGER.debug("Skipping registration of JMX plugin as JMX Management disabled in config. "); - } - } - - public void stop(final BundleContext bundleContext) throws Exception - { - try - { - if (_jmxService != null) - { - if (LOGGER.isInfoEnabled()) - { - LOGGER.info("Stopping jmx plugin: " + _bundleName); - } - _jmxService.close(); - } - - if (_registeredServices != null) - { - unregisterServices(); - } - } - finally - { - _jmxService = null; - _registeredServices = null; - } - } - - - private List<ServiceRegistration> registerServices(BundleContext ctx) - { - if (LOGGER.isInfoEnabled()) - { - LOGGER.info("Registering jmx plugin: " + _bundleName); - } - - List<ServiceRegistration> serviceRegistrations = new ArrayList<ServiceRegistration>(); - - ServiceRegistration jmxServiceRegistration = ctx.registerService(JMXService.class.getName(), _jmxService, null); - ServiceRegistration jmxConfigFactoryRegistration = ctx.registerService(ConfigurationPluginFactory.class.getName(), JMXConfiguration.FACTORY, null); - - serviceRegistrations.add(jmxServiceRegistration); - serviceRegistrations.add(jmxConfigFactoryRegistration); - return serviceRegistrations; - } - - private void startJmsService(JMXService jmxService) throws Exception - { - if (LOGGER.isInfoEnabled()) - { - LOGGER.info("Starting JMX service"); - } - boolean startedSuccessfully = false; - try - { - jmxService.start(); - startedSuccessfully = true; - } - finally - { - if (!startedSuccessfully) - { - LOGGER.error("JMX failed to start normally, closing service"); - jmxService.close(); - } - } - } - - private void unregisterServices() - { - for (Iterator<ServiceRegistration> iterator = _registeredServices.iterator(); iterator.hasNext();) - { - ServiceRegistration service = iterator.next(); - service.unregister(); - } - } -} diff --git a/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXConfiguration.java b/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXConfiguration.java deleted file mode 100644 index dc9a712f90..0000000000 --- a/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXConfiguration.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * - * 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.jmx; - -import org.apache.commons.configuration.CompositeConfiguration; -import org.apache.commons.configuration.Configuration; -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.configuration.plugins.ConfigurationPluginFactory; - -import java.util.Arrays; -import java.util.List; - -public class JMXConfiguration extends ConfigurationPlugin -{ - CompositeConfiguration _finalConfig; - - public static final ConfigurationPluginFactory FACTORY = new ConfigurationPluginFactory() - { - public ConfigurationPlugin newInstance(String path, Configuration config) throws ConfigurationException - { - ConfigurationPlugin instance = new JMXConfiguration(); - instance.setConfiguration(path, config); - return instance; - } - - public List<String> getParentPaths() - { - return Arrays.asList("jmx"); - } - }; - - public String[] getElementsProcessed() - { - return new String[] { "" }; - } - - public Configuration getConfiguration() - { - return _finalConfig; - } - - - @Override - public void validateConfiguration() throws ConfigurationException - { - // Valid Configuration either has xml links to new files - _finalConfig = new CompositeConfiguration(getConfig()); - List subFiles = getConfig().getList("xml[@fileName]"); - for (Object subFile : subFiles) - { - _finalConfig.addConfiguration(new XMLConfiguration((String) subFile)); - } - - } - -} diff --git a/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXManagedObjectRegistry.java b/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXManagedObjectRegistry.java index 0648235077..a045683de1 100644 --- a/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXManagedObjectRegistry.java +++ b/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXManagedObjectRegistry.java @@ -20,171 +20,114 @@ */ package org.apache.qpid.server.jmx; -import org.apache.commons.configuration.ConfigurationException; import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; +import org.apache.qpid.server.configuration.BrokerProperties; +import org.apache.qpid.server.configuration.IllegalConfigurationException; import org.apache.qpid.server.logging.actors.CurrentActor; 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.model.Broker; +import org.apache.qpid.server.model.Port; +import org.apache.qpid.server.model.Transport; 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; -import javax.management.Notification; -import javax.management.NotificationFilterSupport; -import javax.management.NotificationListener; import javax.management.ObjectName; -import javax.management.remote.JMXConnectionNotification; import javax.management.remote.JMXConnectorServer; import javax.management.remote.JMXServiceURL; import javax.management.remote.MBeanServerForwarder; -import javax.management.remote.rmi.RMIConnection; import javax.management.remote.rmi.RMIConnectorServer; -import javax.management.remote.rmi.RMIJRMPServerImpl; -import javax.management.remote.rmi.RMIServerImpl; import javax.rmi.ssl.SslRMIClientSocketFactory; import javax.rmi.ssl.SslRMIServerSocketFactory; -import javax.security.auth.Subject; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.lang.management.ManagementFactory; -import java.lang.reflect.Proxy; import java.net.InetAddress; import java.net.InetSocketAddress; -import java.net.ServerSocket; -import java.net.Socket; import java.net.UnknownHostException; import java.rmi.AlreadyBoundException; import java.rmi.NoSuchObjectException; import java.rmi.NotBoundException; +import java.rmi.RemoteException; import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; import java.rmi.server.RMIClientSocketFactory; import java.rmi.server.RMIServerSocketFactory; import java.rmi.server.UnicastRemoteObject; import java.util.HashMap; -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 { private static final Logger _log = Logger.getLogger(JMXManagedObjectRegistry.class); + private static final String OPERATIONAL_LOGGING_NAME = "JMX"; + private final MBeanServer _mbeanServer; + private JMXConnectorServer _cs; private Registry _rmiRegistry; - private boolean _useCustomSocketFactory; - private final int _jmxPortRegistryServer; - private final int _jmxPortConnectorServer; + private final Broker _broker; + private final Port _registryPort; + private final Port _connectorPort; - public JMXManagedObjectRegistry() throws AMQException + public JMXManagedObjectRegistry( + Broker broker, + Port connectorPort, Port registryPort, + JMXManagement jmxManagement) { - _log.info("Initialising managed object registry using platform MBean server"); - IApplicationRegistry appRegistry = ApplicationRegistry.getInstance(); + _broker = broker; + _registryPort = registryPort; + _connectorPort = connectorPort; - // Retrieve the config parameters - _useCustomSocketFactory = appRegistry.getConfiguration().getUseCustomRMISocketFactory(); - boolean platformServer = appRegistry.getConfiguration().getPlatformMbeanserver(); + boolean usePlatformServer = (Boolean)jmxManagement.getAttribute(JMXManagement.USE_PLATFORM_MBEAN_SERVER); _mbeanServer = - platformServer ? ManagementFactory.getPlatformMBeanServer() + usePlatformServer ? ManagementFactory.getPlatformMBeanServer() : MBeanServerFactory.createMBeanServer(ManagedObject.DOMAIN); + } - _jmxPortRegistryServer = appRegistry.getConfiguration().getJMXPortRegistryServer(); - _jmxPortConnectorServer = appRegistry.getConfiguration().getJMXConnectorServerPort(); - - } - - public void start() throws IOException, ConfigurationException + @Override + public void start() throws IOException { - - CurrentActor.get().message(ManagementConsoleMessages.STARTUP()); + CurrentActor.get().message(ManagementConsoleMessages.STARTUP(OPERATIONAL_LOGGING_NAME)); //check if system properties are set to use the JVM's out-of-the-box JMXAgent if (areOutOfTheBoxJMXOptionsSet()) { - CurrentActor.get().message(ManagementConsoleMessages.READY(true)); - return; + CurrentActor.get().message(ManagementConsoleMessages.READY(OPERATIONAL_LOGGING_NAME)); } + else + { + startRegistryAndConnector(); + } + } - IApplicationRegistry appRegistry = ApplicationRegistry.getInstance(); - - - //Socket factories for the RMIConnectorServer, either default or SLL depending on configuration + private void startRegistryAndConnector() throws IOException + { + //Socket factories for the RMIConnectorServer, either default or SSL depending on configuration RMIClientSocketFactory csf; RMIServerSocketFactory ssf; - //check ssl enabled option in config, default to true if option is not set - boolean sslEnabled = appRegistry.getConfiguration().getManagementSSLEnabled(); + //check ssl enabled option on connector port (note we don't provide ssl for registry server at + //moment). + boolean connectorSslEnabled = _connectorPort.getTransports().contains(Transport.SSL); - if (sslEnabled) + if (connectorSslEnabled) { - //set the SSL related system properties used by the SSL RMI socket factories to the values - //given in the configuration file, unless command line settings have already been specified - String keyStorePath; + String keyStorePath = System.getProperty("javax.net.ssl.keyStore"); + String keyStorePassword = System.getProperty("javax.net.ssl.keyStorePassword"); - if(System.getProperty("javax.net.ssl.keyStore") != null) - { - keyStorePath = System.getProperty("javax.net.ssl.keyStore"); - } - else - { - keyStorePath = appRegistry.getConfiguration().getManagementKeyStorePath(); - } + validateKeyStoreProperties(keyStorePath, keyStorePassword); - //check the keystore path value is valid - if (keyStorePath == null) - { - throw new ConfigurationException("JMX management SSL keystore path not defined, " + - "unable to start SSL protected JMX ConnectorServer"); - } - else - { - //ensure the system property is set - System.setProperty("javax.net.ssl.keyStore", keyStorePath); - - //check the file is usable - File ksf = new File(keyStorePath); - - if (!ksf.exists()) - { - throw new FileNotFoundException("Cannot find JMX management SSL keystore file: " + ksf); - } - if (!ksf.canRead()) - { - throw new FileNotFoundException("Cannot read JMX management SSL keystore file: " - + ksf + ". Check permissions."); - } - - CurrentActor.get().message(ManagementConsoleMessages.SSL_KEYSTORE(ksf.getAbsolutePath())); - } - - //check the key store password is set - if (System.getProperty("javax.net.ssl.keyStorePassword") == null) - { - - if (appRegistry.getConfiguration().getManagementKeyStorePassword() == null) - { - throw new ConfigurationException("JMX management SSL keystore password not defined, " + - "unable to start requested SSL protected JMX server"); - } - else - { - System.setProperty("javax.net.ssl.keyStorePassword", - appRegistry.getConfiguration().getManagementKeyStorePassword()); - } - } + CurrentActor.get().message(ManagementConsoleMessages.SSL_KEYSTORE(keyStorePath)); //create the SSL RMI socket factories csf = new SslRMIClientSocketFactory(); @@ -197,27 +140,23 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry ssf = null; } + int jmxPortRegistryServer = _registryPort.getPort(); + int jmxPortConnectorServer = _connectorPort.getPort(); + //add a JMXAuthenticator implementation the env map to authenticate the RMI based JMX connector server - RMIPasswordAuthenticator rmipa = new RMIPasswordAuthenticator(new InetSocketAddress(_jmxPortRegistryServer)); - HashMap<String,Object> env = new HashMap<String,Object>(); - env.put(JMXConnectorServer.AUTHENTICATOR, rmipa); + RMIPasswordAuthenticator rmipa = new RMIPasswordAuthenticator(_broker, new InetSocketAddress(jmxPortConnectorServer)); + HashMap<String,Object> connectorEnv = new HashMap<String,Object>(); + connectorEnv.put(JMXConnectorServer.AUTHENTICATOR, rmipa); + + System.setProperty("java.rmi.server.randomIDs", "true"); + boolean useCustomSocketFactory = Boolean.parseBoolean(System.getProperty(BrokerProperties.PROPERTY_USE_CUSTOM_RMI_SOCKET_FACTORY, Boolean.TRUE.toString())); /* * Start a RMI registry on the management port, to hold the JMX RMI ConnectorServer stub. * Using custom socket factory to prevent anyone (including us unfortunately) binding to the registry using RMI. * As a result, only binds made using the object reference will succeed, thus securing it from external change. */ - System.setProperty("java.rmi.server.randomIDs", "true"); - if(_useCustomSocketFactory) - { - _rmiRegistry = LocateRegistry.createRegistry(_jmxPortRegistryServer, null, new CustomRMIServerSocketFactory()); - } - else - { - _rmiRegistry = LocateRegistry.createRegistry(_jmxPortRegistryServer, null, null); - } - - CurrentActor.get().message(ManagementConsoleMessages.LISTENING("RMI Registry", _jmxPortRegistryServer)); + _rmiRegistry = createRmiRegistry(jmxPortRegistryServer, useCustomSocketFactory); /* * We must now create the RMI ConnectorServer manually, as the JMX Factory methods use RMI calls @@ -225,57 +164,16 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry * locked it from any RMI based modifications, including our own. Instead, we will manually bind * the RMIConnectorServer stub to the registry using its object reference, which will still succeed. * - * The registry is exported on the defined management port 'port'. We will export the RMIConnectorServer - * on 'port +1'. Use of these two well-defined ports will ease any navigation through firewall's. + * The registry is exported on the defined management port 'port'. */ - final Map<String, String> connectionIdUsernameMap = new ConcurrentHashMap<String, String>(); - final RMIServerImpl rmiConnectorServerStub = new RMIJRMPServerImpl(_jmxPortConnectorServer, csf, ssf, env) - { - - /** - * Override makeClient so we can cache the username of the client in a Map keyed by connectionId. - * ConnectionId is guaranteed to be unique per client connection, according to the JMS spec. - * An instance of NotificationListener (mapCleanupListener) will be responsible for removing these Map - * entries. - * - * @see javax.management.remote.rmi.RMIJRMPServerImpl#makeClient(String, javax.security.auth.Subject) - */ - @Override - 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()); - return makeClient; - } - }; - - // Create a Listener responsible for removing the map entries add by the #makeClient entry above. - final NotificationListener mapCleanupListener = new NotificationListener() - { - - public void handleNotification(Notification notification, Object handback) - { - final String connectionId = ((JMXConnectionNotification) notification).getConnectionId(); - connectionIdUsernameMap.remove(connectionId); - } - }; + final UsernameCachingRMIJRMPServer usernameCachingRmiServer = new UsernameCachingRMIJRMPServer(jmxPortConnectorServer, csf, ssf, connectorEnv); - String localHost; - try - { - localHost = InetAddress.getLocalHost().getHostName(); - } - catch(UnknownHostException ex) - { - localHost="127.0.0.1"; - } - final String hostname = localHost; + final String localHostName = getLocalhost(); final JMXServiceURL externalUrl = new JMXServiceURL( - "service:jmx:rmi://"+hostname+":"+(_jmxPortConnectorServer)+"/jndi/rmi://"+hostname+":"+_jmxPortRegistryServer+"/jmxrmi"); + "service:jmx:rmi://"+localHostName+":"+(jmxPortConnectorServer)+"/jndi/rmi://"+localHostName+":"+jmxPortRegistryServer+"/jmxrmi"); - final JMXServiceURL internalUrl = new JMXServiceURL("rmi", hostname, _jmxPortConnectorServer); - _cs = new RMIConnectorServer(internalUrl, env, rmiConnectorServerStub, _mbeanServer) + final JMXServiceURL internalUrl = new JMXServiceURL("rmi", localHostName, jmxPortConnectorServer); + _cs = new RMIConnectorServer(internalUrl, connectorEnv, usernameCachingRmiServer, _mbeanServer) { @Override public synchronized void start() throws IOException @@ -283,7 +181,7 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry try { //manually bind the connector server to the registry at key 'jmxrmi', like the out-of-the-box agent - _rmiRegistry.bind("jmxrmi", rmiConnectorServerStub); + _rmiRegistry.bind("jmxrmi", usernameCachingRmiServer); } catch (AlreadyBoundException abe) { @@ -311,7 +209,6 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry } catch (NotBoundException nbe) { - // TODO consider if we want to keep new logging _log.error("Failed to unbind jmxrmi", nbe); //ignore } @@ -326,97 +223,100 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry //must return our pre-crafted url that includes the full details, inc JNDI details return externalUrl; } - }; - //Add the custom invoker as an MBeanServerForwarder, and start the RMIConnectorServer. - MBeanServerForwarder mbsf = MBeanInvocationHandlerImpl.newProxyInstance(); + MBeanServerForwarder mbsf = MBeanInvocationHandlerImpl.newProxyInstance(_broker); _cs.setMBeanServerForwarder(mbsf); + // Install a ManagementLogonLogoffReporter so we can report as users logon/logoff + ManagementLogonLogoffReporter jmxManagementUserLogonLogoffReporter = new ManagementLogonLogoffReporter(_broker.getRootMessageLogger(), usernameCachingRmiServer); + _cs.addNotificationListener(jmxManagementUserLogonLogoffReporter, jmxManagementUserLogonLogoffReporter, null); - // Get the handler that is used by the above MBInvocationHandler Proxy. - // which is the MBeanInvocationHandlerImpl and so also a NotificationListener. - final NotificationListener invocationHandler = (NotificationListener) Proxy.getInvocationHandler(mbsf); - - // Install a notification listener on OPENED, CLOSED, and FAILED, - // passing the map of connection-ids to usernames as hand-back data. - final NotificationFilterSupport invocationHandlerFilter = new NotificationFilterSupport(); - invocationHandlerFilter.enableType(JMXConnectionNotification.OPENED); - invocationHandlerFilter.enableType(JMXConnectionNotification.CLOSED); - invocationHandlerFilter.enableType(JMXConnectionNotification.FAILED); - _cs.addNotificationListener(invocationHandler, invocationHandlerFilter, connectionIdUsernameMap); - - // Install a second notification listener on CLOSED AND FAILED only to remove the entry from the - // Map. Here we rely on the fact that JMX will call the listeners in the order in which they are - // installed. - final NotificationFilterSupport mapCleanupHandlerFilter = new NotificationFilterSupport(); - mapCleanupHandlerFilter.enableType(JMXConnectionNotification.CLOSED); - mapCleanupHandlerFilter.enableType(JMXConnectionNotification.FAILED); - _cs.addNotificationListener(mapCleanupListener, mapCleanupHandlerFilter, null); + // Install the usernameCachingRmiServer as a listener so it may cleanup as clients disconnect + _cs.addNotificationListener(usernameCachingRmiServer, usernameCachingRmiServer, null); _cs.start(); - String connectorServer = (sslEnabled ? "SSL " : "") + "JMX RMIConnectorServer"; - CurrentActor.get().message(ManagementConsoleMessages.LISTENING(connectorServer, _jmxPortConnectorServer)); - - CurrentActor.get().message(ManagementConsoleMessages.READY(false)); + String connectorServer = (connectorSslEnabled ? "SSL " : "") + "JMX RMIConnectorServer"; + CurrentActor.get().message(ManagementConsoleMessages.LISTENING(connectorServer, jmxPortConnectorServer)); + CurrentActor.get().message(ManagementConsoleMessages.READY(OPERATIONAL_LOGGING_NAME)); } - /* - * Custom RMIServerSocketFactory class, used to prevent updates to the RMI registry. - * Supplied to the registry at creation, this will prevent RMI-based operations on the - * registry such as attempting to bind a new object, thereby securing it from tampering. - * This is accomplished by always returning null when attempting to determine the address - * of the caller, thus ensuring the registry will refuse the attempt. Calls to bind etc - * made using the object reference will not be affected and continue to operate normally. - */ - - private static class CustomRMIServerSocketFactory implements RMIServerSocketFactory + private Registry createRmiRegistry(int jmxPortRegistryServer, boolean useCustomRmiRegistry) + throws RemoteException { - - public ServerSocket createServerSocket(int port) throws IOException + Registry rmiRegistry; + if(useCustomRmiRegistry) { - return new NoLocalAddressServerSocket(port); + _log.debug("Using custom RMIServerSocketFactory"); + rmiRegistry = LocateRegistry.createRegistry(jmxPortRegistryServer, null, new CustomRMIServerSocketFactory()); } - - private static class NoLocalAddressServerSocket extends ServerSocket + else { - NoLocalAddressServerSocket(int port) throws IOException - { - super(port); - } + _log.debug("Using default RMIServerSocketFactory"); + rmiRegistry = LocateRegistry.createRegistry(jmxPortRegistryServer, null, null); + } - @Override - public Socket accept() throws IOException - { - Socket s = new NoLocalAddressSocket(); - super.implAccept(s); - return s; - } + CurrentActor.get().message(ManagementConsoleMessages.LISTENING("RMI Registry", jmxPortRegistryServer)); + return rmiRegistry; + } + + private void validateKeyStoreProperties(String keyStorePath, String keyStorePassword) throws FileNotFoundException + { + if (keyStorePath == null) + { + throw new IllegalConfigurationException("JVM system property 'javax.net.ssl.keyStore' is not set, " + + "unable to start requested SSL protected JMX connector"); + } + if (keyStorePassword == null) + { + throw new IllegalConfigurationException( "JVM system property 'javax.net.ssl.keyStorePassword' is not set, " + + "unable to start requested SSL protected JMX connector"); } - private static class NoLocalAddressSocket extends Socket + File ksf = new File(keyStorePath); + if (!ksf.exists()) { - @Override - public InetAddress getInetAddress() - { - return null; - } + throw new FileNotFoundException("Cannot find JMX management SSL keystore file: " + ksf); + } + if (!ksf.canRead()) + { + throw new FileNotFoundException("Cannot read JMX management SSL keystore file: " + + ksf + ". Check permissions."); } } - + @Override public void registerObject(ManagedObject managedObject) throws JMException { _mbeanServer.registerMBean(managedObject, managedObject.getObjectName()); } + @Override public void unregisterObject(ManagedObject managedObject) throws JMException { _mbeanServer.unregisterMBean(managedObject.getObjectName()); } + @Override + public void close() + { + _log.debug("close() called"); + + closeConnectorAndRegistryServers(); + + unregisterAllMbeans(); + + CurrentActor.get().message(ManagementConsoleMessages.STOPPED(OPERATIONAL_LOGGING_NAME)); + } + + private void closeConnectorAndRegistryServers() + { + closeConnectorServer(); + closeRegistryServer(); + } + // checks if the system properties are set which enable the JVM's out-of-the-box JMXAgent. private boolean areOutOfTheBoxJMXOptionsSet() { @@ -433,29 +333,26 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry return false; } - //Stops the JMXConnectorServer and RMIRegistry, then unregisters any remaining MBeans from the MBeanServer - public void close() + private String getLocalhost() { - _log.debug("close() called"); - - if (_cs != null) + String localHost; + try { - // Stopping the JMX ConnectorServer - try - { - CurrentActor.get().message(ManagementConsoleMessages.SHUTTING_DOWN("JMX RMIConnectorServer", _cs.getAddress().getPort())); - _cs.stop(); - } - catch (IOException e) - { - _log.error("Exception while closing the JMX ConnectorServer: ", e); - } + localHost = InetAddress.getLocalHost().getHostName(); } - + catch(UnknownHostException ex) + { + localHost="127.0.0.1"; + } + return localHost; + } + + private void closeRegistryServer() + { if (_rmiRegistry != null) { // Stopping the RMI registry - CurrentActor.get().message(ManagementConsoleMessages.SHUTTING_DOWN("RMI Registry", _jmxPortRegistryServer)); + CurrentActor.get().message(ManagementConsoleMessages.SHUTTING_DOWN("RMI Registry", _registryPort.getPort())); try { boolean success = UnicastRemoteObject.unexportObject(_rmiRegistry, false); @@ -468,8 +365,36 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry { _log.error("Exception while closing the RMI Registry: ", e); } + finally + { + _rmiRegistry = null; + } + } + } + + private void closeConnectorServer() + { + if (_cs != null) + { + // Stopping the JMX ConnectorServer + try + { + CurrentActor.get().message(ManagementConsoleMessages.SHUTTING_DOWN("JMX RMIConnectorServer", _cs.getAddress().getPort())); + _cs.stop(); + } + catch (IOException e) + { + _log.error("Exception while closing the JMX ConnectorServer: ", e); + } + finally + { + _cs = null; + } } - + } + + private void unregisterAllMbeans() + { //ObjectName query to gather all Qpid related MBeans ObjectName mbeanNameQuery = null; try @@ -492,8 +417,6 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry _log.error("Exception unregistering MBean '"+ name +"': " + e.getMessage()); } } - - CurrentActor.get().message(ManagementConsoleMessages.STOPPED()); } } diff --git a/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXManagement.java b/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXManagement.java new file mode 100644 index 0000000000..8f087ba50c --- /dev/null +++ b/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXManagement.java @@ -0,0 +1,343 @@ +/* + * + * 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.jmx; + +import java.io.IOException; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.UUID; + +import javax.management.JMException; + +import org.apache.log4j.Logger; +import org.apache.qpid.server.jmx.mbeans.LoggingManagementMBean; +import org.apache.qpid.server.jmx.mbeans.UserManagementMBean; +import org.apache.qpid.server.jmx.mbeans.ServerInformationMBean; +import org.apache.qpid.server.jmx.mbeans.Shutdown; +import org.apache.qpid.server.jmx.mbeans.VirtualHostMBean; +import org.apache.qpid.server.logging.log4j.LoggingManagementFacade; +import org.apache.qpid.server.model.AuthenticationProvider; +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.ConfigurationChangeListener; +import org.apache.qpid.server.model.ConfiguredObject; +import org.apache.qpid.server.model.PasswordCredentialManagingAuthenticationProvider; +import org.apache.qpid.server.model.Plugin; +import org.apache.qpid.server.model.Port; +import org.apache.qpid.server.model.Protocol; +import org.apache.qpid.server.model.State; +import org.apache.qpid.server.model.VirtualHost; +import org.apache.qpid.server.model.adapter.AbstractPluginAdapter; +import org.apache.qpid.server.plugin.PluginFactory; +import org.apache.qpid.server.plugin.QpidServiceLoader; +import org.apache.qpid.server.util.MapValueConverter; + +public class JMXManagement extends AbstractPluginAdapter implements ConfigurationChangeListener +{ + private static final Logger LOGGER = Logger.getLogger(JMXManagement.class); + + public static final String PLUGIN_TYPE = "MANAGEMENT-JMX"; + + // attributes + public static final String USE_PLATFORM_MBEAN_SERVER = "usePlatformMBeanServer"; + public static final String NAME = "name"; + + // default values + public static final String DEFAULT_NAME = "JMXManagement"; + public static final boolean DEFAULT_USE_PLATFORM_MBEAN_SERVER = true; + + @SuppressWarnings("serial") + private static final Collection<String> AVAILABLE_ATTRIBUTES = Collections.unmodifiableCollection(new HashSet<String>(Plugin.AVAILABLE_ATTRIBUTES){{ + add(NAME); + add(USE_PLATFORM_MBEAN_SERVER); + add(PluginFactory.PLUGIN_TYPE); + }}); + + @SuppressWarnings("serial") + private static final Map<String, Object> DEFAULTS = new HashMap<String, Object>(){{ + put(USE_PLATFORM_MBEAN_SERVER, DEFAULT_USE_PLATFORM_MBEAN_SERVER); + put(NAME, DEFAULT_NAME); + put(PluginFactory.PLUGIN_TYPE, PLUGIN_TYPE); + }}; + + @SuppressWarnings("serial") + private static final Map<String, Class<?>> ATTRIBUTE_TYPES = new HashMap<String, Class<?>>(){{ + put(USE_PLATFORM_MBEAN_SERVER, Boolean.class); + put(NAME, String.class); + put(PluginFactory.PLUGIN_TYPE, String.class); + }}; + + private final Broker _broker; + private JMXManagedObjectRegistry _objectRegistry; + + private final Map<ConfiguredObject, AMQManagedObject> _children = new HashMap<ConfiguredObject, AMQManagedObject>(); + + public JMXManagement(UUID id, Broker broker, Map<String, Object> attributes) + { + super(id, DEFAULTS, MapValueConverter.convert(attributes, ATTRIBUTE_TYPES), broker.getTaskExecutor()); + _broker = broker; + addParent(Broker.class, broker); + } + + @Override + protected boolean setState(State currentState, State desiredState) + { + if(desiredState == State.ACTIVE) + { + try + { + start(); + } + catch (JMException e) + { + throw new RuntimeException("Couldn't start JMX management", e); + } + catch (IOException e) + { + throw new RuntimeException("Couldn't start JMX management", e); + } + return true; + } + else if(desiredState == State.STOPPED) + { + stop(); + return true; + } + return false; + } + + private void start() throws JMException, IOException + { + Port connectorPort = null; + Port registryPort = null; + Collection<Port> ports = _broker.getPorts(); + for (Port port : ports) + { + if (State.QUIESCED.equals(port.getActualState())) + { + continue; + } + + if(isRegistryPort(port)) + { + registryPort = port; + } + else if(isConnectorPort(port)) + { + connectorPort = port; + } + } + if(connectorPort == null) + { + throw new IllegalStateException("No JMX connector port found supporting protocol " + Protocol.JMX_RMI); + } + if(registryPort == null) + { + throw new IllegalStateException("No JMX RMI port found supporting protocol " + Protocol.RMI); + } + + _objectRegistry = new JMXManagedObjectRegistry(_broker, connectorPort, registryPort, this); + + _broker.addChangeListener(this); + + synchronized (_children) + { + for(VirtualHost virtualHost : _broker.getVirtualHosts()) + { + if(!_children.containsKey(virtualHost)) + { + LOGGER.debug("Create MBean for virtual host:" + virtualHost.getName()); + VirtualHostMBean mbean = new VirtualHostMBean(virtualHost, _objectRegistry); + LOGGER.debug("Check for additional MBeans for virtual host:" + virtualHost.getName()); + createAdditionalMBeansFromProviders(virtualHost, mbean); + } + } + Collection<AuthenticationProvider> authenticationProviders = _broker.getAuthenticationProviders(); + for (AuthenticationProvider authenticationProvider : authenticationProviders) + { + if(authenticationProvider instanceof PasswordCredentialManagingAuthenticationProvider) + { + UserManagementMBean mbean = new UserManagementMBean( + (PasswordCredentialManagingAuthenticationProvider) authenticationProvider, + _objectRegistry); + _children.put(authenticationProvider, mbean); + } + } + } + new Shutdown(_objectRegistry); + new ServerInformationMBean(_objectRegistry, _broker); + if (LoggingManagementFacade.getCurrentInstance() != null) + { + new LoggingManagementMBean(LoggingManagementFacade.getCurrentInstance(), _objectRegistry); + } + _objectRegistry.start(); + } + + private boolean isConnectorPort(Port port) + { + return port.getProtocols().contains(Protocol.JMX_RMI); + } + + private boolean isRegistryPort(Port port) + { + return port.getProtocols().contains(Protocol.RMI); + } + + private void stop() + { + synchronized (_children) + { + for(ConfiguredObject object : _children.keySet()) + { + AMQManagedObject mbean = _children.get(object); + if (mbean instanceof ConfigurationChangeListener) + { + object.removeChangeListener((ConfigurationChangeListener)mbean); + } + try + { + mbean.unregister(); + } + catch (JMException e) + { + LOGGER.error("Error unregistering mbean", e); + } + } + _children.clear(); + } + _broker.removeChangeListener(this); + _objectRegistry.close(); + } + + @Override + public void stateChanged(ConfiguredObject object, State oldState, State newState) + { + // no-op + } + + @Override + public void childAdded(ConfiguredObject object, ConfiguredObject child) + { + synchronized (_children) + { + try + { + AMQManagedObject mbean; + if(child instanceof VirtualHost) + { + VirtualHost vhostChild = (VirtualHost)child; + mbean = new VirtualHostMBean(vhostChild, _objectRegistry); + } + else if(child instanceof PasswordCredentialManagingAuthenticationProvider) + { + mbean = new UserManagementMBean((PasswordCredentialManagingAuthenticationProvider) child, _objectRegistry); + } + else + { + mbean = null; + } + + if (mbean != null) + { + createAdditionalMBeansFromProviders(child, mbean); + } + } + catch(JMException e) + { + LOGGER.error("Error creating mbean", e); + // TODO - Implement error reporting on mbean creation + } + } + } + + @Override + public void childRemoved(ConfiguredObject object, ConfiguredObject child) + { + // TODO - implement vhost removal (possibly just removing the instanceof check below) + + synchronized (_children) + { + if(child instanceof PasswordCredentialManagingAuthenticationProvider) + { + AMQManagedObject mbean = _children.remove(child); + if(mbean != null) + { + try + { + mbean.unregister(); + } + catch(JMException e) + { + LOGGER.error("Error creating mbean", e); + //TODO - report error on removing child MBean + } + } + } + + } + } + + @Override + public void attributeSet(ConfiguredObject object, String attributeName, Object oldAttributeValue, Object newAttributeValue) + { + // no-op + } + + private void createAdditionalMBeansFromProviders(ConfiguredObject child, AMQManagedObject mbean) throws JMException + { + _children.put(child, mbean); + + QpidServiceLoader<MBeanProvider> qpidServiceLoader = new QpidServiceLoader<MBeanProvider>(); + for (MBeanProvider provider : qpidServiceLoader.instancesOf(MBeanProvider.class)) + { + LOGGER.debug("Consulting mbean provider : " + provider + " for child : " + child); + if (provider.isChildManageableByMBean(child)) + { + LOGGER.debug("Provider will create mbean "); + provider.createMBean(child, mbean); + // TODO track the mbeans that have been created on behalf of a child in a map, then + // if the child is ever removed, destroy these beans too. + } + } + } + + /** Added for testing purposes */ + Broker getBroker() + { + return _broker; + } + + @Override + public String getName() + { + return (String)getAttribute(NAME); + } + + @Override + public Collection<String> getAttributeNames() + { + return AVAILABLE_ATTRIBUTES; + } + +} diff --git a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/SaslRestTest.java b/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXManagementFactory.java index b504c9fa60..c2186c372b 100644 --- a/java/broker-plugins/management-http/src/test/java/org/apache/qpid/server/management/plugin/servlet/rest/SaslRestTest.java +++ b/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXManagementFactory.java @@ -1,5 +1,4 @@ /* - * * 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 @@ -16,27 +15,35 @@ * 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; +package org.apache.qpid.server.jmx; -import java.util.List; import java.util.Map; +import java.util.UUID; -public class SaslRestTest extends QpidRestTestCase +import org.apache.log4j.Logger; +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.Plugin; +import org.apache.qpid.server.plugin.PluginFactory; + +public class JMXManagementFactory implements PluginFactory { - public void testGet() throws Exception - { - Map<String, Object> saslData = getJsonAsMap("/rest/sasl"); - assertNotNull("mechanisms attribute is not found", saslData.get("mechanisms")); + private static final Logger LOGGER = Logger.getLogger(JMXManagementFactory.class); - @SuppressWarnings("unchecked") - List<String> mechanisms = (List<String>) saslData.get("mechanisms"); - String[] expectedMechanisms = { "AMQPLAIN", "PLAIN", "CRAM-MD5" }; - for (String mechanism : expectedMechanisms) + @Override + public Plugin createInstance(UUID id, Map<String, Object> attributes, Broker broker) + { + if (JMXManagement.PLUGIN_TYPE.equals(attributes.get(PLUGIN_TYPE))) + { + return new JMXManagement(id, broker, attributes); + } + else { - assertTrue("Mechanism " + mechanism + " is not found", mechanisms.contains(mechanism)); + if (LOGGER.isDebugEnabled()) + { + LOGGER.debug("Skipping registration of JMX plugin as JMX Management disabled in config."); + } + return null; } } - } diff --git a/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXService.java b/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXService.java deleted file mode 100644 index 7a232d2584..0000000000 --- a/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXService.java +++ /dev/null @@ -1,193 +0,0 @@ -/* - * - * 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.jmx; - -import java.io.IOException; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.ServiceLoader; - -import javax.management.JMException; -import javax.management.StandardMBean; - -import org.apache.commons.configuration.ConfigurationException; -import org.apache.log4j.Logger; -import org.apache.qpid.AMQException; -import org.apache.qpid.server.jmx.mbeans.LoggingManagementMBean; -import org.apache.qpid.server.jmx.mbeans.UserManagementMBean; -import org.apache.qpid.server.jmx.mbeans.ConfigurationManagementMBean; -import org.apache.qpid.server.jmx.mbeans.ServerInformationMBean; -import org.apache.qpid.server.jmx.mbeans.Shutdown; -import org.apache.qpid.server.jmx.mbeans.VirtualHostMBean; -import org.apache.qpid.server.logging.log4j.LoggingFacade; -import org.apache.qpid.server.model.Broker; -import org.apache.qpid.server.model.ConfigurationChangeListener; -import org.apache.qpid.server.model.ConfiguredObject; -import org.apache.qpid.server.model.PasswordCredentialManagingAuthenticationProvider; -import org.apache.qpid.server.model.State; -import org.apache.qpid.server.model.VirtualHost; -import org.apache.qpid.server.registry.ApplicationRegistry; - - -public class JMXService implements ConfigurationChangeListener -{ - private static final ClassLoader BUNDLE_CLASSLOADER = JMXService.class.getClassLoader(); - - private static final Logger LOGGER = Logger.getLogger(JMXService.class); - - private final Broker _broker; - private final JMXManagedObjectRegistry _objectRegistry; - private final Shutdown _shutdown; - private final ServerInformationMBean _serverInfo; - private final ConfigurationManagementMBean _configManagement; - private final LoggingManagementMBean _loggingManagement; - - private final Map<ConfiguredObject, AMQManagedObject> _children = new HashMap<ConfiguredObject, AMQManagedObject>(); - - public JMXService() throws AMQException, JMException - { - _broker = ApplicationRegistry.getInstance().getBroker(); - _objectRegistry = new JMXManagedObjectRegistry(); - - _broker.addChangeListener(this); - synchronized (_children) - { - for(VirtualHost virtualHost : _broker.getVirtualHosts()) - { - if(!_children.containsKey(virtualHost)) - { - _children.put(virtualHost, new VirtualHostMBean(virtualHost, _objectRegistry)); - } - } - } - _shutdown = new Shutdown(_objectRegistry); - _serverInfo = new ServerInformationMBean(_objectRegistry, _broker); - _configManagement = new ConfigurationManagementMBean(_objectRegistry); - _loggingManagement = new LoggingManagementMBean(LoggingFacade.getCurrentInstance(), _objectRegistry); - } - - public void start() throws IOException, ConfigurationException - { - _objectRegistry.start(); - } - - public void close() - { - _broker.removeChangeListener(this); - - _objectRegistry.close(); - } - - public void stateChanged(ConfiguredObject object, State oldState, State newState) - { - - } - - public void childAdded(ConfiguredObject object, ConfiguredObject child) - { - synchronized (_children) - { - try - { - AMQManagedObject mbean; - if(child instanceof VirtualHost) - { - VirtualHost vhostChild = (VirtualHost)child; - mbean = new VirtualHostMBean(vhostChild, _objectRegistry); - } - else if(child instanceof PasswordCredentialManagingAuthenticationProvider) - { - mbean = new UserManagementMBean((PasswordCredentialManagingAuthenticationProvider) child, _objectRegistry); - } - else - { - mbean = null; - } - - if (mbean != null) - { - createAdditionalMBeansFromProviders(child, mbean); - } - } - catch(JMException e) - { - LOGGER.error("Error creating mbean", e); - // TODO - Implement error reporting on mbean creation - } - } - } - - - public void childRemoved(ConfiguredObject object, ConfiguredObject child) - { - // TODO - implement vhost removal (possibly just removing the instanceof check below) - - synchronized (_children) - { - if(child instanceof PasswordCredentialManagingAuthenticationProvider) - { - AMQManagedObject mbean = _children.remove(child); - if(mbean != null) - { - try - { - mbean.unregister(); - } - catch(JMException e) - { - LOGGER.error("Error creating mbean", e); - //TODO - report error on removing child MBean - } - } - } - - } - } - - private void createAdditionalMBeansFromProviders(ConfiguredObject child, AMQManagedObject mbean) throws JMException - { - _children.put(child, mbean); - - for (Iterator<MBeanProvider> iterator = getMBeanProviderIterator(); iterator.hasNext();) - { - MBeanProvider provider = iterator.next(); - LOGGER.debug("Consulting mbean provider : " + provider + " for child : " + child); - if (provider.isChildManageableByMBean(child)) - { - LOGGER.debug("Provider will create mbean "); - StandardMBean bean = provider.createMBean(child, mbean); - // TODO track the mbeans that have been created on behalf of a child in a map, then - // if the child is ever removed, destroy these beans too. - } - } - } - - /** - * Finds all classes implementing the {@link MBeanProvider} interface. This will find - * <b>only</b> those classes which are visible to the classloader of this OSGI bundle. - */ - private Iterator<MBeanProvider> getMBeanProviderIterator() - { - return ServiceLoader.load(MBeanProvider.class, BUNDLE_CLASSLOADER).iterator(); - } -} diff --git a/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/MBeanInvocationHandlerImpl.java b/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/MBeanInvocationHandlerImpl.java index a2a0d2d093..8bc2afb176 100644 --- a/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/MBeanInvocationHandlerImpl.java +++ b/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/MBeanInvocationHandlerImpl.java @@ -22,26 +22,22 @@ package org.apache.qpid.server.jmx; import org.apache.log4j.Logger; -import org.apache.qpid.server.logging.LogActor; +import org.apache.qpid.server.configuration.BrokerProperties; import org.apache.qpid.server.logging.actors.CurrentActor; import org.apache.qpid.server.logging.actors.ManagementActor; -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.model.Broker; +import org.apache.qpid.server.model.VirtualHost; 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; import javax.management.MBeanInfo; import javax.management.MBeanOperationInfo; import javax.management.MBeanServer; -import javax.management.Notification; -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; @@ -51,27 +47,32 @@ import java.lang.reflect.Proxy; 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 * JMX access decisions to the SecurityPlugin. */ -public class MBeanInvocationHandlerImpl implements InvocationHandler, NotificationListener +public class MBeanInvocationHandlerImpl implements InvocationHandler { private static final Logger _logger = Logger.getLogger(MBeanInvocationHandlerImpl.class); - private final IApplicationRegistry _appRegistry = ApplicationRegistry.getInstance(); private final static String DELEGATE = "JMImplementation:type=MBeanServerDelegate"; private MBeanServer _mbs; - private final ManagementActor _logActor = new ManagementActor(_appRegistry.getRootMessageLogger()); - private final boolean _managementRightsInferAllAccess = - _appRegistry.getConfiguration().getManagementRightsInferAllAccess(); + private final ManagementActor _logActor; - public static MBeanServerForwarder newProxyInstance() + private final boolean _managementRightsInferAllAccess; + private final Broker _broker; + + MBeanInvocationHandlerImpl(Broker broker) + { + _managementRightsInferAllAccess = Boolean.valueOf(System.getProperty(BrokerProperties.PROPERTY_MANAGEMENT_RIGHTS_INFER_ALL_ACCESS, "true")); + _broker = broker; + _logActor = new ManagementActor(broker.getRootMessageLogger()); + } + + public static MBeanServerForwarder newProxyInstance(Broker broker) { - final InvocationHandler handler = new MBeanInvocationHandlerImpl(); + final InvocationHandler handler = new MBeanInvocationHandlerImpl(broker); final Class<?>[] interfaces = new Class[] { MBeanServerForwarder.class }; Object proxy = Proxy.newProxyInstance(MBeanServerForwarder.class.getClassLoader(), interfaces, handler); @@ -101,7 +102,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 +152,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 @@ -211,11 +214,16 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler, Notificati SecurityManager security; if (vhost == null) { - security = _appRegistry.getSecurityManager(); + security = _broker.getSecurityManager(); } else { - security = _appRegistry.getVirtualHostRegistry().getVirtualHost(vhost).getSecurityManager(); + VirtualHost virtualHost = _broker.findVirtualHostByName(vhost); + if (virtualHost == null) + { + throw new IllegalArgumentException("Virtual host with name '" + vhost + "' is not found."); + } + security = virtualHost.getSecurityManager(); } methodName = getMethodName(method, args); @@ -360,50 +368,5 @@ public class MBeanInvocationHandlerImpl implements InvocationHandler, Notificati return (methodName.startsWith("query") || methodName.startsWith("get") || methodName.startsWith("is")); } - /** - * Receives notifications from the MBeanServer. - */ - public void handleNotification(final Notification notification, final Object handback) - { - assert notification instanceof JMXConnectionNotification; - - final String connectionId = ((JMXConnectionNotification) notification).getConnectionId(); - final String type = notification.getType(); - - if (_logger.isDebugEnabled()) - { - _logger.debug("Notification connectionId : " + connectionId + " type : " + type - + " Notification handback : " + handback); - } - - // Normally JMXManagedObjectRegistry provides a Map as handback data containing a map - // between connection id and username. - String user = null; - if (handback instanceof Map) - { - final Map<String, String> connectionIdUsernameMap = (Map<String, String>) handback; - user = connectionIdUsernameMap.get(connectionId); - } - - // If user is still null, fallback to an unordered list of Principals from the connection id. - if (user == null) - { - final String[] splitConnectionId = connectionId.split(" "); - user = splitConnectionId[1]; - } - - // use a separate instance of actor as subject is not set on connect/disconnect - // we need to pass principal name explicitly into log actor - LogActor logActor = new ManagementActor(_appRegistry.getRootMessageLogger(), user); - if (JMXConnectionNotification.OPENED.equals(type)) - { - logActor.message(ManagementConsoleMessages.OPEN(user)); - } - else if (JMXConnectionNotification.CLOSED.equals(type) || - JMXConnectionNotification.FAILED.equals(type)) - { - logActor.message(ManagementConsoleMessages.CLOSE(user)); - } - } } diff --git a/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/MBeanProvider.java b/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/MBeanProvider.java index 83909dbe72..b80ddc7fac 100644 --- a/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/MBeanProvider.java +++ b/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/MBeanProvider.java @@ -21,17 +21,16 @@ package org.apache.qpid.server.jmx; -import java.util.ServiceLoader; - import javax.management.JMException; import javax.management.StandardMBean; import org.apache.qpid.server.model.ConfiguredObject; +import org.apache.qpid.server.plugin.QpidServiceLoader; /** * A provider of an mbean implementation. * - * Provider implementations are advertised as services and loaded via {@link ServiceLoader}. + * Provider implementations are advertised as services and loaded by a {@link QpidServiceLoader}. */ public interface MBeanProvider { diff --git a/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/ManagementLogonLogoffReporter.java b/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/ManagementLogonLogoffReporter.java new file mode 100644 index 0000000000..ae0574dc21 --- /dev/null +++ b/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/ManagementLogonLogoffReporter.java @@ -0,0 +1,95 @@ +/* + * 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.jmx; + +import static javax.management.remote.JMXConnectionNotification.CLOSED; +import static javax.management.remote.JMXConnectionNotification.FAILED; +import static javax.management.remote.JMXConnectionNotification.OPENED; + +import javax.management.Notification; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; +import javax.management.remote.JMXConnectionNotification; + +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.ManagementActor; +import org.apache.qpid.server.logging.messages.ManagementConsoleMessages; + +public class ManagementLogonLogoffReporter implements NotificationListener, NotificationFilter +{ + private static final Logger LOGGER = Logger.getLogger(ManagementLogonLogoffReporter.class); + private final RootMessageLogger _rootMessageLogger; + private final UsernameAccessor _usernameAccessor; + + public ManagementLogonLogoffReporter(RootMessageLogger rootMessageLogger, UsernameAccessor usernameAccessor) + { + _rootMessageLogger = rootMessageLogger; + _usernameAccessor = usernameAccessor; + } + + @Override + public void handleNotification(final Notification notification, final Object handback) + { + final String connectionId = ((JMXConnectionNotification) notification).getConnectionId(); + final String type = notification.getType(); + + if (LOGGER.isDebugEnabled()) + { + LOGGER.debug("Notification connectionId : " + connectionId + " type : " + type); + } + + String user = _usernameAccessor.getUsernameForConnectionId(connectionId); + + // If user is still null, fallback to an unordered list of Principals from the connection id. + if (user == null) + { + final String[] splitConnectionId = connectionId.split(" "); + user = splitConnectionId[1]; + } + + // use a separate instance of actor as subject is not set on connect/disconnect + // we need to pass principal name explicitly into log actor + LogActor logActor = new ManagementActor(_rootMessageLogger, user); + if (JMXConnectionNotification.OPENED.equals(type)) + { + logActor.message(ManagementConsoleMessages.OPEN(user)); + } + else if (JMXConnectionNotification.CLOSED.equals(type) || + JMXConnectionNotification.FAILED.equals(type)) + { + logActor.message(ManagementConsoleMessages.CLOSE(user)); + } + } + + @Override + public boolean isNotificationEnabled(Notification notification) + { + return notification instanceof JMXConnectionNotification && isLogonTypeEvent(notification); + } + + private boolean isLogonTypeEvent(Notification notification) + { + final String type = notification.getType(); + return CLOSED.equals(type) || FAILED.equals(type) || OPENED.equals(type); + } + +} diff --git a/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/UsernameAccessor.java b/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/UsernameAccessor.java new file mode 100644 index 0000000000..0cbb0d2687 --- /dev/null +++ b/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/UsernameAccessor.java @@ -0,0 +1,26 @@ +/* + * 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.jmx; + +public interface UsernameAccessor +{ + public String getUsernameForConnectionId(String connectionId); + +} diff --git a/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/UsernameCachingRMIJRMPServer.java b/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/UsernameCachingRMIJRMPServer.java new file mode 100644 index 0000000000..838e9e5664 --- /dev/null +++ b/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/UsernameCachingRMIJRMPServer.java @@ -0,0 +1,100 @@ +/* + * 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.jmx; + +import static javax.management.remote.JMXConnectionNotification.CLOSED; +import static javax.management.remote.JMXConnectionNotification.FAILED; + +import java.io.IOException; +import java.rmi.server.RMIClientSocketFactory; +import java.rmi.server.RMIServerSocketFactory; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import javax.management.Notification; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; +import javax.management.remote.JMXConnectionNotification; +import javax.management.remote.JMXConnectorServer; +import javax.management.remote.rmi.RMIConnection; +import javax.management.remote.rmi.RMIJRMPServerImpl; +import javax.security.auth.Subject; + +import org.apache.qpid.server.security.auth.AuthenticatedPrincipal; + +/** + * An implementation of RMIJRMPServerImpl that caches the usernames of users as they log-on + * and makes the same available via {@link UsernameAccessor#getUsernameForConnectionId(String)}. + * + * Caller is responsible for installing this object as a {@link NotificationListener} of the + * {@link JMXConnectorServer} so the cache entries are removed as the clients disconnect. + * + */ +public class UsernameCachingRMIJRMPServer extends RMIJRMPServerImpl implements NotificationListener, NotificationFilter, UsernameAccessor +{ + // ConnectionId is guaranteed to be unique per client connection, according to the JMX spec. + private final Map<String, String> _connectionIdUsernameMap = new ConcurrentHashMap<String, String>(); + + UsernameCachingRMIJRMPServer(int port, RMIClientSocketFactory csf, RMIServerSocketFactory ssf, + Map<String, ?> env) throws IOException + { + super(port, csf, ssf, env); + } + + @Override + protected RMIConnection makeClient(String connectionId, Subject subject) throws IOException + { + final RMIConnection makeClient = super.makeClient(connectionId, subject); + final AuthenticatedPrincipal authenticatedPrincipalFromSubject = AuthenticatedPrincipal.getAuthenticatedPrincipalFromSubject(subject); + _connectionIdUsernameMap.put(connectionId, authenticatedPrincipalFromSubject.getName()); + return makeClient; + } + + @Override + public String getUsernameForConnectionId(String connectionId) + { + return _connectionIdUsernameMap.get(connectionId); + } + + @Override + public void handleNotification(Notification notification, Object handback) + { + final String connectionId = ((JMXConnectionNotification) notification).getConnectionId(); + removeConnectionIdFromCache(connectionId); + } + + @Override + public boolean isNotificationEnabled(Notification notification) + { + return isClientDisconnectEvent(notification); + } + + private void removeConnectionIdFromCache(String connectionId) + { + _connectionIdUsernameMap.remove(connectionId); + } + + private boolean isClientDisconnectEvent(Notification notification) + { + final String type = notification.getType(); + return CLOSED.equals(type) || FAILED.equals(type); + } + +}
\ No newline at end of file diff --git a/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/ConfigurationManagementMBean.java b/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/ConfigurationManagementMBean.java deleted file mode 100644 index beffb4eaa9..0000000000 --- a/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/ConfigurationManagementMBean.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * - * 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.jmx.mbeans; - -import org.apache.qpid.management.common.mbeans.ConfigurationManagement; -import org.apache.qpid.server.jmx.AMQManagedObject; -import org.apache.qpid.server.jmx.ManagedObject; -import org.apache.qpid.server.jmx.ManagedObjectRegistry; -import org.apache.qpid.server.registry.ApplicationRegistry; - -import javax.management.JMException; -import javax.management.NotCompliantMBeanException; - -public class ConfigurationManagementMBean extends AMQManagedObject implements ConfigurationManagement -{ - - public ConfigurationManagementMBean(ManagedObjectRegistry registry) throws JMException - { - super(ConfigurationManagement.class, ConfigurationManagement.TYPE, registry); - register(); - } - - public String getObjectInstanceName() - { - return ConfigurationManagement.TYPE; - } - - public void reloadSecurityConfiguration() throws Exception - { - ApplicationRegistry.getInstance().getConfiguration().reparseConfigFileSecuritySections(); - } - - @Override - public ManagedObject getParentObject() - { - return null; - } -} diff --git a/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/LoggingManagementMBean.java b/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/LoggingManagementMBean.java index 0dac8ebe37..d6f4b5d8c9 100644 --- a/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/LoggingManagementMBean.java +++ b/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/LoggingManagementMBean.java @@ -26,7 +26,7 @@ import org.apache.qpid.management.common.mbeans.annotations.MBeanDescription; import org.apache.qpid.server.jmx.AMQManagedObject; import org.apache.qpid.server.jmx.ManagedObject; import org.apache.qpid.server.jmx.ManagedObjectRegistry; -import org.apache.qpid.server.logging.log4j.LoggingFacade; +import org.apache.qpid.server.logging.log4j.LoggingManagementFacade; import org.apache.qpid.server.logging.log4j.LoggingFacadeException; import javax.management.JMException; @@ -55,7 +55,8 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM private static final TabularType LOGGER_LEVEL_TABULAR_TYE; private static final CompositeType LOGGER_LEVEL_COMPOSITE_TYPE; - private final LoggingFacade _configurator; + private final LoggingManagementFacade _loggingManagementFacade; + private final String[] _allAvailableLogLevels; static { @@ -77,12 +78,13 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM throw new ExceptionInInitializerError(e); } } - - public LoggingManagementMBean(LoggingFacade configurator, ManagedObjectRegistry registry) throws JMException + + public LoggingManagementMBean(LoggingManagementFacade loggingManagementFacade, ManagedObjectRegistry registry) throws JMException { super(LoggingManagement.class, LoggingManagement.TYPE, registry); register(); - _configurator = configurator; + _loggingManagementFacade = loggingManagementFacade; + _allAvailableLogLevels = buildAllAvailableLoggerLevelsWithInheritedPsuedoLogLevel(_loggingManagementFacade); } @Override @@ -100,30 +102,26 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM @Override public Integer getLog4jLogWatchInterval() { - return _configurator.getLog4jLogWatchInterval(); + return _loggingManagementFacade.getLog4jLogWatchInterval(); } @Override public String[] getAvailableLoggerLevels() { - List<String> levels = _configurator.getAvailableLoggerLevels(); - List<String> mbeanLevels = new ArrayList<String>(levels); - mbeanLevels.add(INHERITED_PSUEDO_LOG_LEVEL); - - return mbeanLevels.toArray(new String[mbeanLevels.size()]); + return _allAvailableLogLevels; } @Override public TabularData viewEffectiveRuntimeLoggerLevels() { - Map<String, String> levels = _configurator.retrieveRuntimeLoggersLevels(); + Map<String, String> levels = _loggingManagementFacade.retrieveRuntimeLoggersLevels(); return createTabularDataFromLevelsMap(levels); } @Override public String getRuntimeRootLoggerLevel() { - return _configurator.retrieveRuntimeRootLoggerLevel(); + return _loggingManagementFacade.retrieveRuntimeRootLoggerLevel(); } @Override @@ -139,7 +137,7 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM return false; } - _configurator.setRuntimeRootLoggerLevel(level); + _loggingManagementFacade.setRuntimeRootLoggerLevel(level); return true; } @@ -159,7 +157,7 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM try { - _configurator.setRuntimeLoggerLevel(logger, validatedLevel); + _loggingManagementFacade.setRuntimeLoggerLevel(logger, validatedLevel); } catch (LoggingFacadeException e) { @@ -175,7 +173,7 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM Map<String,String> levels; try { - levels = _configurator.retrieveConfigFileLoggersLevels(); + levels = _loggingManagementFacade.retrieveConfigFileLoggersLevels(); } catch (LoggingFacadeException e) { @@ -191,7 +189,7 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM { try { - return _configurator.retrieveConfigFileRootLoggerLevel().toUpperCase(); + return _loggingManagementFacade.retrieveConfigFileRootLoggerLevel().toUpperCase(); } catch (LoggingFacadeException e) { @@ -216,7 +214,7 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM try { - _configurator.setConfigFileLoggerLevel(logger, validatedLevel); + _loggingManagementFacade.setConfigFileLoggerLevel(logger, validatedLevel); } catch (LoggingFacadeException e) { @@ -241,7 +239,7 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM try { - _configurator.setConfigFileRootLoggerLevel(level); + _loggingManagementFacade.setConfigFileRootLoggerLevel(level); return true; } catch (LoggingFacadeException e) @@ -257,7 +255,7 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM try { - _configurator.reload(); + _loggingManagementFacade.reload(); } catch (LoggingFacadeException e) { @@ -283,9 +281,8 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM private void validateLevelNotAllowingInherited(String level) { - final List<String> availableLoggerLevels = _configurator.getAvailableLoggerLevels(); - if (!availableLoggerLevels.contains(level) - && !availableLoggerLevels.contains(String.valueOf(level).toUpperCase())) + final List<String> availableLoggerLevels = _loggingManagementFacade.getAvailableLoggerLevels(); + if (level == null || !availableLoggerLevels.contains(level.toUpperCase())) { throw new IllegalArgumentException(level + " not known"); } @@ -305,7 +302,6 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM return loggerLevelList; } - private CompositeData createRow(String loggerName, String level) { Object[] itemData = {loggerName, level.toUpperCase()}; @@ -321,4 +317,13 @@ public class LoggingManagementMBean extends AMQManagedObject implements LoggingM throw new RuntimeException(ode); } } + + private String[] buildAllAvailableLoggerLevelsWithInheritedPsuedoLogLevel(LoggingManagementFacade loggingManagementFacade) + { + List<String> levels = loggingManagementFacade.getAvailableLoggerLevels(); + List<String> mbeanLevels = new ArrayList<String>(levels); + mbeanLevels.add(INHERITED_PSUEDO_LOG_LEVEL); + + return mbeanLevels.toArray(new String[mbeanLevels.size()]); + } } diff --git a/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/QueueMBean.java b/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/QueueMBean.java index 5c8b0f7194..94fac218ff 100644 --- a/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/QueueMBean.java +++ b/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/QueueMBean.java @@ -513,7 +513,6 @@ public class QueueMBean extends AMQManagedObject implements ManagedQueue, QueueN { _queue.visit(new QueueEntryVisitor() { - public boolean visit(final QueueEntry entry) { final ServerMessage message = entry.getMessage(); @@ -525,11 +524,9 @@ public class QueueMBean extends AMQManagedObject implements ManagedQueue, QueueN && (messageId <= toMessageId)) { txn.dequeue(entry); - return true; } - return false; } - return true; + return false; } }); } diff --git a/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/VirtualHostMBean.java b/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/VirtualHostMBean.java index 6990a40dee..51dea92775 100644 --- a/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/VirtualHostMBean.java +++ b/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/VirtualHostMBean.java @@ -65,7 +65,7 @@ public class VirtualHostMBean extends AMQManagedObject implements ManagedVirtual _managerMBean = new VirtualHostManagerMBean(this); } - private void initQueues() throws JMException + private void initQueues() { synchronized (_children) { @@ -73,13 +73,20 @@ public class VirtualHostMBean extends AMQManagedObject implements ManagedVirtual { if(!_children.containsKey(queue)) { - _children.put(queue, new QueueMBean(queue, this)); + try + { + _children.put(queue, new QueueMBean(queue, this)); + } + catch(Exception e) + { + LOGGER.error("Cannot create queue mbean for queue " + queue.getName(), e); + } } } } } - private void initExchanges() throws JMException + private void initExchanges() { synchronized (_children) { @@ -87,13 +94,20 @@ public class VirtualHostMBean extends AMQManagedObject implements ManagedVirtual { if(!_children.containsKey(exchange)) { - _children.put(exchange, new ExchangeMBean(exchange, this)); + try + { + _children.put(exchange, new ExchangeMBean(exchange, this)); + } + catch(Exception e) + { + LOGGER.error("Cannot create exchange mbean for exchange " + exchange.getName(), e); + } } } } } - private void initConnections() throws JMException + private void initConnections() { synchronized (_children) { @@ -101,7 +115,14 @@ public class VirtualHostMBean extends AMQManagedObject implements ManagedVirtual { if(!_children.containsKey(conn)) { - _children.put(conn, new ConnectionMBean(conn, this)); + try + { + _children.put(conn, new ConnectionMBean(conn, this)); + } + catch(Exception e) + { + LOGGER.error("Cannot create connection mbean for connection " + conn.getName(), e); + } } } } @@ -119,7 +140,7 @@ public class VirtualHostMBean extends AMQManagedObject implements ManagedVirtual public void stateChanged(ConfiguredObject object, State oldState, State newState) { - // ignore + // no-op } public void childAdded(ConfiguredObject object, ConfiguredObject child) @@ -208,4 +229,35 @@ public class VirtualHostMBean extends AMQManagedObject implements ManagedVirtual return queues; } + + @Override + public void unregister() throws JMException + { + synchronized (_children) + { + for (AMQManagedObject mbean : _children.values()) + { + if(mbean != null) + { + try + { + mbean.unregister(); + } + catch(JMException e) + { + LOGGER.error("Failed to remove mbean for child : " + mbean, e); + } + } + } + _children.clear(); + } + _managerMBean.unregister(); + } + + @Override + public void attributeSet(ConfiguredObject object, String attributeName, Object oldAttributeValue, Object newAttributeValue) + { + // no-op + } + } diff --git a/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/VirtualHostManagerMBean.java b/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/VirtualHostManagerMBean.java index b3dbbc424a..67ac1bdc7c 100644 --- a/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/VirtualHostManagerMBean.java +++ b/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/mbeans/VirtualHostManagerMBean.java @@ -229,10 +229,9 @@ public class VirtualHostManagerMBean extends AbstractStatisticsGatheringMBean<Vi return getObjectNameForSingleInstanceMBean(); } - public synchronized boolean isStatisticsEnabled() + public boolean isStatisticsEnabled() { - updateStats(); - return false; //TODO - implement isStatisticsEnabled + return true; } } diff --git a/java/broker-plugins/management-jmx/src/main/resources/META-INF/services/org.apache.qpid.server.plugin.PluginFactory b/java/broker-plugins/management-jmx/src/main/resources/META-INF/services/org.apache.qpid.server.plugin.PluginFactory new file mode 100644 index 0000000000..8fa778269e --- /dev/null +++ b/java/broker-plugins/management-jmx/src/main/resources/META-INF/services/org.apache.qpid.server.plugin.PluginFactory @@ -0,0 +1,19 @@ +# +# 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. +# +org.apache.qpid.server.jmx.JMXManagementFactory diff --git a/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/server/jmx/JMXManagementFactoryTest.java b/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/server/jmx/JMXManagementFactoryTest.java new file mode 100644 index 0000000000..5af1369239 --- /dev/null +++ b/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/server/jmx/JMXManagementFactoryTest.java @@ -0,0 +1,60 @@ +/* + * 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.jmx; + +import static org.mockito.Mockito.mock; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.plugin.PluginFactory; +import org.apache.qpid.test.utils.QpidTestCase; + +public class JMXManagementFactoryTest extends QpidTestCase +{ + private final JMXManagementFactory _jmxManagementFactory = new JMXManagementFactory(); + private final Map<String, Object> _attributes = new HashMap<String, Object>(); + private final Broker _broker = mock(Broker.class); + private UUID _id = UUID.randomUUID(); + + public void testJMXConfigured() throws Exception + { + _attributes.put(PluginFactory.PLUGIN_TYPE, JMXManagement.PLUGIN_TYPE); + + JMXManagement jmxManagement = (JMXManagement) _jmxManagementFactory.createInstance(_id, _attributes, _broker); + + assertNotNull(jmxManagement); + assertEquals("Unexpected plugin type", JMXManagement.PLUGIN_TYPE, jmxManagement.getAttribute(JMXManagementFactory.PLUGIN_TYPE)); + assertEquals("Unexpected default mbean platform", JMXManagement.DEFAULT_USE_PLATFORM_MBEAN_SERVER, jmxManagement.getAttribute(JMXManagement.USE_PLATFORM_MBEAN_SERVER)); + assertEquals("Unexpected default name", JMXManagement.DEFAULT_NAME, jmxManagement.getAttribute(JMXManagement.NAME)); + } + + public void testCreateInstanceReturnsNullWhenPluginTypeMissing() + { + assertNull(_jmxManagementFactory.createInstance(_id, _attributes, _broker)); + } + + public void testCreateInstanceReturnsNullWhenPluginTypeNotJmx() + { + _attributes.put(PluginFactory.PLUGIN_TYPE, "notJmx"); + assertNull(_jmxManagementFactory.createInstance(_id, _attributes, _broker)); + } +} diff --git a/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/server/jmx/ManagementLogActorTest.java b/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/server/jmx/ManagementLogActorTest.java deleted file mode 100644 index c1df9afc5d..0000000000 --- a/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/server/jmx/ManagementLogActorTest.java +++ /dev/null @@ -1,170 +0,0 @@ -/* - * - * 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.jmx; - -import java.util.HashMap; -import java.util.Map; - -import javax.management.JMException; -import javax.management.MBeanServerConnection; -import javax.management.ObjectName; -import javax.management.remote.JMXConnector; -import javax.management.remote.JMXConnectorFactory; -import javax.management.remote.JMXServiceURL; - -import org.apache.commons.configuration.ConfigurationException; -import org.apache.commons.configuration.XMLConfiguration; -import org.apache.qpid.server.configuration.ServerConfiguration; -import org.apache.qpid.server.configuration.plugins.ConfigurationPlugin; -import org.apache.qpid.server.logging.actors.CurrentActor; -import org.apache.qpid.server.registry.ApplicationRegistry; -import org.apache.qpid.server.security.Result; -import org.apache.qpid.server.security.SecurityPlugin; -import org.apache.qpid.server.security.access.ObjectProperties; -import org.apache.qpid.server.security.access.ObjectType; -import org.apache.qpid.server.security.access.Operation; -import org.apache.qpid.server.util.TestApplicationRegistry; -import org.apache.qpid.test.utils.QpidTestCase; - -public class ManagementLogActorTest extends QpidTestCase -{ - private ApplicationRegistry _registry; - private JMXManagedObjectRegistry _objectRegistry; - private int _registryPort; - private int _connectorPort; - private TestPlugin _plugin; - - @Override - public void setUp() throws Exception - { - super.setUp(); - - _registryPort = findFreePort(); - _connectorPort = getNextAvailable(_registryPort + 1); - XMLConfiguration config = new XMLConfiguration(); - config.addProperty(ServerConfiguration.MGMT_JMXPORT_REGISTRYSERVER, _registryPort + ""); - config.addProperty(ServerConfiguration.MGMT_JMXPORT_CONNECTORSERVER, _connectorPort + ""); - _registry = new TestApplicationRegistry(new ServerConfiguration(config)); - ApplicationRegistry.initialise(_registry); - - _plugin = new TestPlugin(); - _registry.getSecurityManager().addHostPlugin(_plugin); - - _objectRegistry = new JMXManagedObjectRegistry(); - new TestMBean(_objectRegistry); - _objectRegistry.start(); - } - - public void tearDown() throws Exception - { - _objectRegistry.close(); - ApplicationRegistry.remove(); - super.tearDown(); - } - - public void testPrincipalInLogMessage() throws Throwable - { - Map<String, Object> environment = new HashMap<String, Object>(); - environment.put(JMXConnector.CREDENTIALS, new String[] { "admin", "admin" }); - String urlString = "service:jmx:rmi:///jndi/rmi://localhost:" + _registryPort + "/jmxrmi"; - JMXServiceURL url = new JMXServiceURL(urlString); - JMXConnector jmxConnector = JMXConnectorFactory.connect(url, environment); - MBeanServerConnection mbsc = jmxConnector.getMBeanServerConnection(); - ObjectName mbeanObject = new ObjectName("org.apache.qpid:type=TestMBean,name=test"); - - String actorLogMessage = (String) mbsc.getAttribute(mbeanObject, "ActorLogMessage"); - - assertTrue("Unexpected log principal in security plugin", _plugin.getLogMessage().startsWith("[mng:admin")); - assertTrue("Unexpected log principal in MBean", actorLogMessage.startsWith("[mng:admin")); - } - - public static class TestMBean extends DefaultManagedObject implements CurrentActorRetriever - { - - public TestMBean(ManagedObjectRegistry registry) throws JMException - { - super(CurrentActorRetriever.class, "TestMBean", registry); - register(); - } - - @Override - public String getObjectInstanceName() - { - return "test"; - } - - @Override - public ManagedObject getParentObject() - { - return null; - } - - @Override - public String getActorLogMessage() - { - return CurrentActor.get().getLogMessage(); - } - - } - - public static interface CurrentActorRetriever - { - String getActorLogMessage(); - } - - public static class TestPlugin implements SecurityPlugin - { - private String _logMessage; - - @Override - public void configure(ConfigurationPlugin config) throws ConfigurationException - { - } - - @Override - public Result getDefault() - { - return Result.ALLOWED; - } - - @Override - public Result access(ObjectType objectType, Object instance) - { - return Result.ALLOWED; - } - - @Override - public Result authorise(Operation operation, ObjectType objectType, ObjectProperties properties) - { - // set thread name to work around logic in MangementActor - Thread.currentThread().setName("RMI TCP Connection(1)-" + System.currentTimeMillis()); - _logMessage = CurrentActor.get().getLogMessage(); - return Result.ALLOWED; - } - - public String getLogMessage() - { - return _logMessage; - } - - } - -} diff --git a/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/server/jmx/ManagementLogonLogoffReporterTest.java b/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/server/jmx/ManagementLogonLogoffReporterTest.java new file mode 100644 index 0000000000..ba9c2cdaa5 --- /dev/null +++ b/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/server/jmx/ManagementLogonLogoffReporterTest.java @@ -0,0 +1,101 @@ +/* + * 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.jmx; + +import static javax.management.remote.JMXConnectionNotification.OPENED; +import static javax.management.remote.JMXConnectionNotification.CLOSED; +import static javax.management.remote.JMXConnectionNotification.FAILED; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.mockito.Mockito.verify; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyString; + +import javax.management.remote.JMXConnectionNotification; + +import org.apache.qpid.server.logging.LogActor; +import org.apache.qpid.server.logging.RootMessageLogger; + +import junit.framework.TestCase; + +public class ManagementLogonLogoffReporterTest extends TestCase +{ + private static final String TEST_JMX_UNIQUE_CONNECTION_ID = "jmxconnectionid1 jmxuser,group"; + private static final String TEST_USER = "jmxuser"; + + private ManagementLogonLogoffReporter _reporter; + private UsernameAccessor _usernameAccessor; + private RootMessageLogger _rootMessageLogger; + + @Override + protected void setUp() throws Exception + { + super.setUp(); + _usernameAccessor = mock(UsernameAccessor.class); + _rootMessageLogger = mock(RootMessageLogger.class); + // Enable messaging so we can valid the generated strings + when(_rootMessageLogger.isMessageEnabled(any(LogActor.class), anyString())).thenReturn(true); + + _reporter = new ManagementLogonLogoffReporter(_rootMessageLogger, _usernameAccessor); + } + + public void testOpenedNotification() + { + when(_usernameAccessor.getUsernameForConnectionId(TEST_JMX_UNIQUE_CONNECTION_ID)).thenReturn(TEST_USER); + JMXConnectionNotification openNotification = createMockNotification(TEST_JMX_UNIQUE_CONNECTION_ID, OPENED); + + _reporter.handleNotification(openNotification, null); + + verify(_rootMessageLogger).rawMessage("[main] MNG-1007 : Open : User jmxuser", "qpid.message.managementconsole.open"); + } + + public void testClosedNotification() + { + when(_usernameAccessor.getUsernameForConnectionId(TEST_JMX_UNIQUE_CONNECTION_ID)).thenReturn(TEST_USER); + JMXConnectionNotification closeNotification = createMockNotification(TEST_JMX_UNIQUE_CONNECTION_ID, CLOSED); + + _reporter.handleNotification(closeNotification, null); + + verify(_rootMessageLogger).rawMessage("[main] MNG-1008 : Close : User jmxuser", "qpid.message.managementconsole.close"); + } + + public void tesNotifiedForLogOnTypeEvents() + { + JMXConnectionNotification openNotification = createMockNotification(TEST_JMX_UNIQUE_CONNECTION_ID, OPENED); + JMXConnectionNotification closeNotification = createMockNotification(TEST_JMX_UNIQUE_CONNECTION_ID, CLOSED); + JMXConnectionNotification failedNotification = createMockNotification(TEST_JMX_UNIQUE_CONNECTION_ID, FAILED); + + assertTrue(_reporter.isNotificationEnabled(openNotification)); + assertTrue(_reporter.isNotificationEnabled(closeNotification)); + assertTrue(_reporter.isNotificationEnabled(failedNotification)); + + JMXConnectionNotification otherNotification = createMockNotification(TEST_JMX_UNIQUE_CONNECTION_ID, "other"); + assertFalse(_reporter.isNotificationEnabled(otherNotification)); + } + + private JMXConnectionNotification createMockNotification(String connectionId, String notificationType) + { + JMXConnectionNotification notification = mock(JMXConnectionNotification.class); + when(notification.getConnectionId()).thenReturn(connectionId); + when(notification.getType()).thenReturn(notificationType); + return notification; + } +} diff --git a/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/server/jmx/mbeans/LoggingManagementMBeanTest.java b/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/server/jmx/mbeans/LoggingManagementMBeanTest.java index ae1be5db00..0f33e78d03 100644 --- a/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/server/jmx/mbeans/LoggingManagementMBeanTest.java +++ b/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/server/jmx/mbeans/LoggingManagementMBeanTest.java @@ -39,7 +39,7 @@ import junit.framework.TestCase; import org.apache.qpid.management.common.mbeans.LoggingManagement; import org.apache.qpid.server.jmx.ManagedObjectRegistry; -import org.apache.qpid.server.logging.log4j.LoggingFacade; +import org.apache.qpid.server.logging.log4j.LoggingManagementFacade; public class LoggingManagementMBeanTest extends TestCase { @@ -47,13 +47,13 @@ public class LoggingManagementMBeanTest extends TestCase private static final String TEST_LEVEL2 = "LEVEL2"; private LoggingManagementMBean _loggingMBean; - private LoggingFacade _mockLoggingFacade; + private LoggingManagementFacade _mockLoggingFacade; private ManagedObjectRegistry _mockManagedObjectRegistry; @Override protected void setUp() throws Exception { - _mockLoggingFacade = mock(LoggingFacade.class); + _mockLoggingFacade = mock(LoggingManagementFacade.class); final List<String> listOfLevels = new ArrayList<String>() {{ add(TEST_LEVEL1); diff --git a/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/systest/management/jmx/BrokerManagementTest.java b/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/systest/management/jmx/BrokerManagementTest.java deleted file mode 100644 index 7473a4d3e7..0000000000 --- a/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/systest/management/jmx/BrokerManagementTest.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * 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.management.jmx; - -import org.apache.qpid.exchange.ExchangeDefaults; -import org.apache.qpid.management.common.mbeans.ManagedBroker; -import org.apache.qpid.management.common.mbeans.ManagedExchange; -import org.apache.qpid.test.utils.JMXTestUtils; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -/** - * Tests the JMX API for the Managed Broker. - * - */ -public class BrokerManagementTest extends QpidBrokerTestCase -{ - private static final String VIRTUAL_HOST = "test"; - - /** - * JMX helper. - */ - private JMXTestUtils _jmxUtils; - private ManagedBroker _managedBroker; - - public void setUp() throws Exception - { - _jmxUtils = new JMXTestUtils(this); - _jmxUtils.setUp(); - super.setUp(); - _jmxUtils.open(); - _managedBroker = _jmxUtils.getManagedBroker(VIRTUAL_HOST); - } - - public void tearDown() throws Exception - { - if (_jmxUtils != null) - { - _jmxUtils.close(); - } - super.tearDown(); - } - - /** - * Tests queue creation/deletion also verifying the automatic binding to the default exchange. - */ - public void testCreateQueueAndDeletion() throws Exception - { - final String queueName = getTestQueueName(); - final ManagedExchange defaultExchange = _jmxUtils.getManagedExchange(ExchangeDefaults.DEFAULT_EXCHANGE_NAME.asString()); - - // Check that bind does not exist before queue creation - assertFalse("Binding to " + queueName + " should not exist in default exchange before queue creation", - defaultExchange.bindings().containsKey(new String[] {queueName})); - - _managedBroker.createNewQueue(queueName, "testowner", true); - - // Ensure the queue exists - assertNotNull("Queue object name expected to exist", _jmxUtils.getQueueObjectName(VIRTUAL_HOST, queueName)); - assertNotNull("Manager queue expected to be available", _jmxUtils.getManagedQueue(queueName)); - - // Now verify that the default exchange has been bound. - assertTrue("Binding to " + queueName + " should exist in default exchange after queue creation", - defaultExchange.bindings().containsKey(new String[] {queueName})); - - // Now delete the queue - _managedBroker.deleteQueue(queueName); - - // Finally ensure that the binding has been removed. - assertFalse("Binding to " + queueName + " should not exist in default exchange after queue deletion", - defaultExchange.bindings().containsKey(new String[] {queueName})); - } - - /** - * Tests exchange creation/deletion via JMX API. - */ - public void testCreateExchangeAndUnregister() throws Exception - { - String exchangeName = getTestName(); - _managedBroker.createNewExchange(exchangeName, "topic", true); - - ManagedExchange exchange = _jmxUtils.getManagedExchange(exchangeName); - assertNotNull("Exchange should exist", exchange); - - _managedBroker.unregisterExchange(exchangeName); - } - - /** - * Tests that it is disallowed to unregister the default exchange. - */ - public void testUnregisterOfDefaultExchangeDisallowed() throws Exception - { - String defaultExchangeName = ExchangeDefaults.DEFAULT_EXCHANGE_NAME.asString(); - - try - { - _managedBroker.unregisterExchange(defaultExchangeName); - fail("Exception not thrown"); - } - catch (UnsupportedOperationException e) - { - // PASS - assertEquals("'<<default>>' is a reserved exchange and can't be deleted", e.getMessage()); - } - final ManagedExchange defaultExchange = _jmxUtils.getManagedExchange(defaultExchangeName); - assertNotNull("Exchange should exist", defaultExchange); - } - -} diff --git a/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/systest/management/jmx/ConnectionManagementTest.java b/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/systest/management/jmx/ConnectionManagementTest.java deleted file mode 100644 index 28d7bf4aed..0000000000 --- a/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/systest/management/jmx/ConnectionManagementTest.java +++ /dev/null @@ -1,283 +0,0 @@ -/* - * 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.management.jmx; - -import java.io.IOException; -import java.util.Date; -import java.util.Iterator; -import java.util.List; - -import javax.jms.Connection; -import javax.jms.Destination; -import javax.jms.JMSException; -import javax.jms.Message; -import javax.jms.MessageConsumer; -import javax.jms.Queue; -import javax.jms.Session; -import javax.management.JMException; -import javax.management.openmbean.CompositeData; -import javax.management.openmbean.CompositeDataSupport; -import javax.management.openmbean.TabularData; - -import org.apache.commons.lang.StringUtils; -import org.apache.qpid.common.QpidProperties; -import org.apache.qpid.management.common.mbeans.ManagedConnection; -import org.apache.qpid.management.common.mbeans.ManagedQueue; -import org.apache.qpid.test.utils.JMXTestUtils; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -public class ConnectionManagementTest extends QpidBrokerTestCase -{ - private static final String VIRTUAL_HOST_NAME = "test"; - - private JMXTestUtils _jmxUtils; - private Connection _connection; - - public void setUp() throws Exception - { - _jmxUtils = new JMXTestUtils(this); - _jmxUtils.setUp(); // modifies broker config therefore must be done before super.setUp() - super.setUp(); - _jmxUtils.open(); - } - - public void tearDown() throws Exception - { - try - { - if (_jmxUtils != null) - { - _jmxUtils.close(); - } - } - finally - { - super.tearDown(); - } - } - - public void testNumberOfManagedConnectionsMatchesNumberOfClientConnections() throws Exception - { - assertEquals("Expected no managed connections", 0, getManagedConnections().size()); - - _connection = getConnection(); - assertEquals("Expected one managed connection", 1, getManagedConnections().size()); - - _connection.close(); - assertEquals("Expected no managed connections after client connection closed", 0, getManagedConnections().size()); - } - - public void testGetAttributes() throws Exception - { - _connection = getConnection(); - final ManagedConnection mBean = getConnectionMBean(); - - checkAuthorisedId(mBean); - checkClientVersion(mBean); - checkClientId(mBean); - } - - public void testNonTransactedSession() throws Exception - { - _connection = getConnection(); - - boolean transactional = false; - boolean flowBlocked = false; - - _connection.createSession(transactional, Session.AUTO_ACKNOWLEDGE); - - final ManagedConnection mBean = getConnectionMBean(); - final CompositeDataSupport row = getTheOneChannelRow(mBean); - assertChannelRowData(row, 0, transactional, flowBlocked); - } - - public void testTransactedSessionWithUnackMessages() throws Exception - { - _connection = getConnection(); - _connection.start(); - - boolean transactional = true; - int numberOfMessages = 2; - final Session session = _connection.createSession(transactional, Session.SESSION_TRANSACTED); - final Destination destination = session.createQueue(getTestQueueName()); - final MessageConsumer consumer = session.createConsumer(destination); - - sendMessage(session, destination, numberOfMessages); - receiveMessagesWithoutCommit(consumer, numberOfMessages); - - final ManagedConnection mBean = getConnectionMBean(); - final CompositeDataSupport row = getTheOneChannelRow(mBean); - boolean flowBlocked = false; - assertChannelRowData(row, numberOfMessages, transactional, flowBlocked); - - // check that commit advances the lastIoTime - final Date initialLastIOTime = mBean.getLastIoTime(); - session.commit(); - assertTrue("commit should have caused last IO time to advance", mBean.getLastIoTime().after(initialLastIOTime)); - - // check that channels() now returns one session with no unacknowledged messages - final CompositeDataSupport rowAfterCommit = getTheOneChannelRow(mBean); - final Number unackCountAfterCommit = (Number) rowAfterCommit.get(ManagedConnection.UNACKED_COUNT); - assertEquals("Unexpected number of unacknowledged messages", 0, unackCountAfterCommit); - } - - - public void testProducerFlowBlocked() throws Exception - { - _connection = getConnection(); - _connection.start(); - - String queueName = getTestQueueName(); - Session session = _connection.createSession(true, Session.SESSION_TRANSACTED); - Queue queue = session.createQueue(queueName); - createQueueOnBroker(session, queue); - - ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName); - managedQueue.setFlowResumeCapacity(DEFAULT_MESSAGE_SIZE * 2l); - managedQueue.setCapacity(DEFAULT_MESSAGE_SIZE * 3l); - - final ManagedConnection managedConnection = getConnectionMBean(); - - // Check that producer flow is not block before test - final CompositeDataSupport rowBeforeSend = getTheOneChannelRow(managedConnection); - assertFlowBlocked(rowBeforeSend, false); - - - // Check that producer flow does not become block too soon - sendMessage(session, queue, 3); - final CompositeDataSupport rowBeforeFull = getTheOneChannelRow(managedConnection); - assertFlowBlocked(rowBeforeFull, false); - - // Fourth message will over-fill the queue (but as we are not sending more messages, client thread wont't block) - sendMessage(session, queue, 1); - final CompositeDataSupport rowAfterFull = getTheOneChannelRow(managedConnection); - assertFlowBlocked(rowAfterFull, true); - - // Consume two to bring the queue down to the resume capacity - MessageConsumer consumer = session.createConsumer(queue); - assertNotNull("Could not receive first message", consumer.receive(1000)); - assertNotNull("Could not receive second message", consumer.receive(1000)); - session.commit(); - - // Check that producer flow is no longer blocked - final CompositeDataSupport rowAfterReceive = getTheOneChannelRow(managedConnection); - assertFlowBlocked(rowAfterReceive, false); - } - - private void createQueueOnBroker(Session session, Destination destination) throws JMSException - { - session.createConsumer(destination).close(); // Create a consumer only to cause queue creation - } - - private void assertChannelRowData(final CompositeData row, int unacknowledgedMessages, boolean isTransactional, boolean flowBlocked) - { - assertNotNull(row); - assertEquals("Unexpected transactional flag", isTransactional, row.get(ManagedConnection.TRANSACTIONAL)); - assertEquals("Unexpected unacknowledged message count", unacknowledgedMessages, row.get(ManagedConnection.UNACKED_COUNT)); - assertEquals("Unexpected flow blocked", flowBlocked, row.get(ManagedConnection.FLOW_BLOCKED)); - } - - private void assertFlowBlocked(final CompositeData row, boolean flowBlocked) - { - assertNotNull(row); - assertEquals("Unexpected flow blocked", flowBlocked, row.get(ManagedConnection.FLOW_BLOCKED)); - } - - private void checkAuthorisedId(ManagedConnection mBean) throws Exception - { - assertEquals("Unexpected authorized id", GUEST_USERNAME, mBean.getAuthorizedId()); - } - - private void checkClientVersion(ManagedConnection mBean) throws Exception - { - String expectedVersion = QpidProperties.getReleaseVersion(); - assertTrue(StringUtils.isNotBlank(expectedVersion)); - - assertEquals("Unexpected version", expectedVersion, mBean.getVersion()); - } - - private void checkClientId(ManagedConnection mBean) throws Exception - { - String expectedClientId = _connection.getClientID(); - assertTrue(StringUtils.isNotBlank(expectedClientId)); - - assertEquals("Unexpected ClientId", expectedClientId, mBean.getClientId()); - } - - private ManagedConnection getConnectionMBean() - { - List<ManagedConnection> connections = getManagedConnections(); - assertNotNull("Connection MBean is not found", connections); - assertEquals("Unexpected number of connection mbeans", 1, connections.size()); - final ManagedConnection mBean = connections.get(0); - assertNotNull("Connection MBean is null", mBean); - return mBean; - } - - private List<ManagedConnection> getManagedConnections() - { - return _jmxUtils.getManagedConnections(VIRTUAL_HOST_NAME); - } - - private CompositeDataSupport getTheOneChannelRow(final ManagedConnection mBean) throws Exception - { - TabularData channelsData = getChannelsDataWithRetry(mBean); - - assertEquals("Unexpected number of rows in channel table", 1, channelsData.size()); - - @SuppressWarnings("unchecked") - final Iterator<CompositeDataSupport> rowItr = (Iterator<CompositeDataSupport>) channelsData.values().iterator(); - final CompositeDataSupport row = rowItr.next(); - return row; - } - - private void receiveMessagesWithoutCommit(final MessageConsumer consumer, int numberOfMessages) throws Exception - { - for (int i = 0; i < numberOfMessages; i++) - { - final Message m = consumer.receive(1000l); - assertNotNull("Message " + i + " is not received", m); - } - } - - private TabularData getChannelsDataWithRetry(final ManagedConnection mBean) - throws IOException, JMException - { - TabularData channelsData = mBean.channels(); - int retries = 0; - while(channelsData.size() == 0 && retries < 5) - { - sleep(); - channelsData = mBean.channels(); - retries++; - } - return channelsData; - } - - private void sleep() - { - try - { - Thread.sleep(50); - } - catch (InterruptedException ie) - { - Thread.currentThread().interrupt(); - } - }} diff --git a/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/systest/management/jmx/LoggingManagementTest.java b/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/systest/management/jmx/LoggingManagementTest.java deleted file mode 100644 index ac6730638e..0000000000 --- a/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/systest/management/jmx/LoggingManagementTest.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * 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.management.jmx; - -import java.io.File; -import java.util.List; - -import javax.management.openmbean.CompositeData; -import javax.management.openmbean.TabularData; - -import org.apache.qpid.management.common.mbeans.LoggingManagement; -import org.apache.qpid.server.jmx.mbeans.LoggingManagementMBeanTest; -import org.apache.qpid.server.logging.log4j.LoggingFacadeTest; -import org.apache.qpid.test.utils.JMXTestUtils; -import org.apache.qpid.test.utils.QpidBrokerTestCase; -import org.apache.qpid.util.FileUtils; -import org.apache.qpid.util.LogMonitor; - -/** - * System test for Logging Management. <b>These tests rely on value set within - * test-profiles/log4j-test.xml</b>. - * - * @see LoggingManagementMBeanTest - * @see LoggingFacadeTest - * - */ -public class LoggingManagementTest extends QpidBrokerTestCase -{ - private JMXTestUtils _jmxUtils; - private LoggingManagement _loggingManagement; - private LogMonitor _monitor; - - public void setUp() throws Exception - { - _jmxUtils = new JMXTestUtils(this); - _jmxUtils.setUp(); - - // System test normally run with log for4j test config from beneath test-profiles. We need to - // copy it as some of our tests write to this file. - - File tmpLogFile = File.createTempFile("log4j" + "." + getName(), ".xml"); - tmpLogFile.deleteOnExit(); - FileUtils.copy(_logConfigFile, tmpLogFile); - - _logConfigFile = tmpLogFile; - - super.setUp(); - _jmxUtils.open(); - - _loggingManagement = _jmxUtils.getLoggingManagement(); - _monitor = new LogMonitor(_outputFile); - } - - public void tearDown() throws Exception - { - try - { - if (_jmxUtils != null) - { - _jmxUtils.close(); - } - } - finally - { - super.tearDown(); - } - } - - public void testViewEffectiveRuntimeLoggerLevels() throws Exception - { - final String qpidMainLogger = "org.apache.qpid"; - - TabularData table = _loggingManagement.viewEffectiveRuntimeLoggerLevels(); - final CompositeData row = table.get(new String[] {qpidMainLogger} ); - assertChannelRow(row, qpidMainLogger, "DEBUG"); - } - - public void testViewConfigFileLoggerLevels() throws Exception - { - final String operationalLoggingLogger = "qpid.message"; - - TabularData table = _loggingManagement.viewConfigFileLoggerLevels(); - final CompositeData row = table.get(new String[] {operationalLoggingLogger} ); - assertChannelRow(row, operationalLoggingLogger, "INFO"); - } - - public void testTurnOffOrgApacheQpidAtRuntime() throws Exception - { - final String logger = "org.apache.qpid"; - _monitor.markDiscardPoint(); - _loggingManagement.setRuntimeLoggerLevel(logger, "OFF"); - - List<String> matches = _monitor.findMatches("Setting level to OFF for logger 'org.apache.qpid'"); - assertEquals(1, matches.size()); - - TabularData table = _loggingManagement.viewEffectiveRuntimeLoggerLevels(); - final CompositeData row1 = table.get(new String[] {logger} ); - assertChannelRow(row1, logger, "OFF"); - } - - public void testChangesToConfigFileBecomeEffectiveAfterReload() throws Exception - { - final String operationalLoggingLogger = "qpid.message"; - assertEffectiveLoggingLevel(operationalLoggingLogger, "INFO"); - - _monitor.markDiscardPoint(); - _loggingManagement.setConfigFileLoggerLevel(operationalLoggingLogger, "OFF"); - - List<String> matches = _monitor.findMatches("Setting level to OFF for logger 'qpid.message'"); - assertEquals(1, matches.size()); - - assertEffectiveLoggingLevel(operationalLoggingLogger, "INFO"); - - _loggingManagement.reloadConfigFile(); - - assertEffectiveLoggingLevel(operationalLoggingLogger, "OFF"); - } - - private void assertEffectiveLoggingLevel(String operationalLoggingLogger, String expectedLevel) - { - TabularData table = _loggingManagement.viewEffectiveRuntimeLoggerLevels(); - final CompositeData row1 = table.get(new String[] {operationalLoggingLogger} ); - assertChannelRow(row1, operationalLoggingLogger, expectedLevel); - } - - private void assertChannelRow(final CompositeData row, String logger, String level) - { - assertNotNull("No row for " + logger, row); - assertEquals("Unexpected logger name", logger, row.get(LoggingManagement.LOGGER_NAME)); - assertEquals("Unexpected level", level, row.get(LoggingManagement.LOGGER_LEVEL)); - } - -} diff --git a/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/systest/management/jmx/ManagementActorLoggingTest.java b/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/systest/management/jmx/ManagementActorLoggingTest.java deleted file mode 100644 index 47b38381c5..0000000000 --- a/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/systest/management/jmx/ManagementActorLoggingTest.java +++ /dev/null @@ -1,480 +0,0 @@ -/* - * - * 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.management.jmx; - -import org.apache.qpid.management.common.mbeans.ManagedBroker; -import org.apache.qpid.management.common.mbeans.ManagedConnection; -import org.apache.qpid.management.common.mbeans.ManagedExchange; -import org.apache.qpid.server.logging.AbstractTestLogging; -import org.apache.qpid.server.logging.subjects.AbstractTestLogSubject; -import org.apache.qpid.test.utils.JMXTestUtils; - -import javax.jms.Connection; -import javax.jms.ExceptionListener; -import javax.jms.JMSException; -import javax.management.JMException; -import java.io.IOException; -import java.util.List; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -/** - * Test class to test if any change in the broker JMX code is affesting the management console - * There are some hardcoding of management feature names and parameter names to create a customized - * look in the console. - */ -public class ManagementActorLoggingTest extends AbstractTestLogging -{ - private JMXTestUtils _jmxUtils; - private boolean _closed = false; - - @Override - public void setUp() throws Exception - { - _jmxUtils = new JMXTestUtils(this); - _jmxUtils.setUp(); - super.setUp(); - _jmxUtils.open(); - } - - @Override - public void tearDown() throws Exception - { - if(!_closed) - { - _jmxUtils.close(); - } - super.tearDown(); - } - - /** - * Description: - * When a connected client has its connection closed via the Management Console this will be logged as a CON-1002 message. - * Input: - * - * 1. Running Broker - * 2. Connected Client - * 3. Connection is closed via Management Console - * Output: - * - * <date> CON-1002 : Close - * - * Validation Steps: - * 4. The CON ID is correct - * 5. This must be the last CON message for the Connection - * 6. It must be preceded by a CON-1001 for this Connection - * - * @throws Exception - {@see ManagedConnection.closeConnection and #getConnection} - * @throws java.io.IOException - if there is a problem reseting the log monitor - */ - public void testConnectionCloseViaManagement() throws IOException, Exception - { - //Create a connection to the broker - Connection connection = getConnection(); - - // Monitor the connection for an exception being thrown - // this should be a DisconnectionException but it is not this tests - // job to valiate that. Only use the exception as a synchronisation - // to check the log file for the Close message - final CountDownLatch exceptionReceived = new CountDownLatch(1); - connection.setExceptionListener(new ExceptionListener() - { - public void onException(JMSException e) - { - //Failover being attempted. - exceptionReceived.countDown(); - } - }); - - //Remove the connection close from any 0-10 connections - _monitor.markDiscardPoint(); - - // Get a managedConnection - ManagedConnection mangedConnection = _jmxUtils.getManagedObject(ManagedConnection.class, "org.apache.qpid:type=VirtualHost.Connection,*"); - - //Close the connection - mangedConnection.closeConnection(); - - //Wait for the connection to close - assertTrue("Timed out waiting for conneciton to report close", - exceptionReceived.await(2, TimeUnit.SECONDS)); - - //Validate results - List<String> results = waitAndFindMatches("CON-1002"); - - assertEquals("Unexpected Connection Close count", 1, results.size()); - } - - /** - * Description: - * Exchange creation is possible from the Management Console. - * When an exchanged is created in this way then a EXH-1001 create message - * is expected to be logged. - * Input: - * - * 1. Running broker - * 2. Connected Management Console - * 3. Exchange Created via Management Console - * Output: - * - * EXH-1001 : Create : [Durable] Type:<value> Name:<value> - * - * Validation Steps: - * 4. The EXH ID is correct - * 5. The correct tags are present in the message based on the create options - * - * @throws java.io.IOException - if there is a problem reseting the log monitor - * @throws javax.management.JMException - {@see #createQueue and ManagedExchange.deleteQueue} - */ - public void testCreateExchangeDirectTransientViaManagementConsole() throws IOException, JMException - { - _monitor.markDiscardPoint(); - - _jmxUtils.createExchange("test", getName(), "direct", false); - - // Validate - - //1 - ID is correct - List<String> results = waitAndFindMatches("EXH-1001"); - - assertEquals("More than one exchange creation found", 1, results.size()); - - String log = getLogMessage(results, 0); - - // Validate correct exchange name - assertTrue("Incorrect exchange name created:" + log, log.endsWith(getName())); - - // Validate it was a management actor. - String actor = fromActor(log); - assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng")); - } - - public void testCreateExchangeTopicTransientViaManagementConsole() throws IOException, JMException - { - //Remove any previous exchange declares - _monitor.markDiscardPoint(); - - _jmxUtils.createExchange("test", getName(), "topic", false); - - // Validate - - //1 - ID is correct - List<String> results = waitAndFindMatches("EXH-1001"); - - assertEquals("More than one exchange creation found", 1, results.size()); - - String log = getLogMessage(results, 0); - - // Validate correct exchange name - assertTrue("Incorrect exchange name created:" + log, log.endsWith(getName())); - - // Validate it was a management actor. - String actor = fromActor(log); - assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng")); - - } - - public void testCreateExchangeFanoutTransientViaManagementConsole() throws IOException, JMException - { - //Remove any previous exchange declares - _monitor.markDiscardPoint(); - - _jmxUtils.createExchange("test", getName(), "fanout", false); - - // Validate - - //1 - ID is correct - List<String> results = waitAndFindMatches("EXH-1001"); - - assertEquals("More than one exchange creation found", 1, results.size()); - - String log = getLogMessage(results, 0); - - // Validate correct exchange name - assertTrue("Incorrect exchange name created:" + log, log.endsWith(getName())); - - // Validate it was a management actor. - String actor = fromActor(log); - assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng")); - - } - - public void testCreateExchangeHeadersTransientViaManagementConsole() throws IOException, JMException - { - //Remove any previous exchange declares - _monitor.markDiscardPoint(); - - _jmxUtils.createExchange("test", getName(), "headers", false); - - // Validate - - //1 - ID is correct - List<String> results = waitAndFindMatches("EXH-1001"); - - assertEquals("More than one exchange creation found", 1, results.size()); - - String log = getLogMessage(results, 0); - - // Validate correct exchange name - assertTrue("Incorrect exchange name created:" + log, log.endsWith(getName())); - - // Validate it was a management actor. - String actor = fromActor(log); - assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng")); - - } - - /** - * Description: - * Queue creation is possible from the Management Console. When a queue is created in this way then a QUE-1001 create message is expected to be logged. - * Input: - * - * 1. Running broker - * 2. Connected Management Console - * 3. Queue Created via Management Console - * Output: - * - * <date> QUE-1001 : Create : Transient Owner:<name> - * - * Validation Steps: - * 4. The QUE ID is correct - * 5. The correct tags are present in the message based on the create options - * - * @throws java.io.IOException - if there is a problem reseting the log monitor - * @throws javax.management.JMException - {@see #createQueue and ManagedExchange.deleteQueue} - */ - public void testCreateQueueTransientViaManagementConsole() throws IOException, JMException - { - //Remove any previous queue declares - _monitor.markDiscardPoint(); - - _jmxUtils.createQueue("test", getName(), null, false); - - // Validate - - List<String> results = waitAndFindMatches("QUE-1001"); - - assertEquals("More than one queue creation found", 1, results.size()); - - String log = getLogMessage(results, 0); - - // Validate correct queue name - String subject = fromSubject(log); - assertEquals("Incorrect queue name created", getName(), AbstractTestLogSubject.getSlice("qu", subject)); - - // Validate it was a management actor. - String actor = fromActor(log); - assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng")); - } - - /** - * Description: - * The ManagementConsole can be used to delete a queue. When this is done a QUE-1002 Deleted message must be logged. - * Input: - * - * 1. Running Broker - * 2. Queue created on the broker with no subscribers - * 3. Management Console connected - * 4. Queue is deleted via Management Console - * Output: - * - * <date> QUE-1002 : Deleted - * - * Validation Steps: - * 5. The QUE ID is correct - * - * @throws java.io.IOException - if there is a problem reseting the log monitor - * @throws javax.management.JMException - {@see #createQueue and ManagedExchange.deleteQueue} - */ - public void testQueueDeleteViaManagementConsole() throws IOException, JMException - { - //Remove any previous queue declares - _monitor.markDiscardPoint(); - - _jmxUtils.createQueue("test", getName(), null, false); - - ManagedBroker managedBroker = _jmxUtils.getManagedBroker("test"); - - managedBroker.deleteQueue(getName()); - - List<String> results = waitAndFindMatches("QUE-1002"); - - assertEquals("More than one queue deletion found", 1, results.size()); - - String log = getLog(results.get(0)); - - // Validate correct binding - String subject = fromSubject(log); - assertEquals("Incorrect queue named in delete", getName(), AbstractTestLogSubject.getSlice("qu", subject)); - - // Validate it was a management actor. - String actor = fromActor(log); - assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng")); - - } - - /** - * Description: - * The binding of a Queue and an Exchange is done via a Binding. When this Binding is created via the Management Console a BND-1001 Create message will be logged. - * Input: - * - * 1. Running Broker - * 2. Connected Management Console - * 3. Use Management Console to perform binding - * Output: - * - * <date> BND-1001 : Create - * - * Validation Steps: - * 4. The BND ID is correct - * 5. This will be the first message for the given binding - * - * @throws java.io.IOException - if there is a problem reseting the log monitor - * @throws javax.management.JMException - {@see #createQueue and ManagedExchange.createNewBinding} - */ - public void testBindingCreateOnDirectViaManagementConsole() throws IOException, JMException - { - //Remove any previous queue declares - _monitor.markDiscardPoint(); - - _jmxUtils.createQueue("test", getName(), null, false); - - ManagedExchange managedExchange = _jmxUtils.getManagedExchange("amq.direct"); - - managedExchange.createNewBinding(getName(), getName()); - - List<String> results = waitAndFindMatches("BND-1001"); - - assertEquals("Unexpected number of bindings logged", 2, results.size()); - - String log = getLogMessage(results, 0); - - // Validate correct binding - String subject = fromSubject(log); - assertEquals("Incorrect queue named in create", getName(), AbstractTestLogSubject.getSlice("qu", subject)); - assertEquals("Incorrect routing key in create", getName(), AbstractTestLogSubject.getSlice("rk", subject)); - - // Validate it was a management actor. - String actor = fromActor(log); - assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng")); - } - - public void testBindingCreateOnTopicViaManagementConsole() throws IOException, JMException - { - //Remove any previous queue declares - _monitor.markDiscardPoint(); - - _jmxUtils.createQueue("test", getName(), null, false); - - ManagedExchange managedExchange = _jmxUtils.getManagedExchange("amq.topic"); - - managedExchange.createNewBinding(getName(), getName()); - - List<String> results = waitAndFindMatches("BND-1001"); - - assertEquals("Unexpected number of bindings logged", 2, results.size()); - - String log = getLogMessage(results, 0); - - // Validate correct binding - String subject = fromSubject(log); - assertEquals("Incorrect queue named in create", getName(), AbstractTestLogSubject.getSlice("qu", subject)); - assertEquals("Incorrect routing key in create", getName(), AbstractTestLogSubject.getSlice("rk", subject)); - - // Validate it was a management actor. - String actor = fromActor(log); - assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng")); - } - - public void testBindingCreateOnFanoutViaManagementConsole() throws IOException, JMException - { - //Remove any previous queue declares - _monitor.markDiscardPoint(); - - _jmxUtils.createQueue("test", getName(), null, false); - - ManagedExchange managedExchange = _jmxUtils.getManagedExchange("amq.fanout"); - - managedExchange.createNewBinding(getName(), getName()); - - List<String> results = waitAndFindMatches("BND-1001"); - - assertEquals("Unexpected number of bindings logged", 2, results.size()); - - String log = getLogMessage(results, 0); - - // Validate correct binding - String subject = fromSubject(log); - assertEquals("Incorrect queue named in create", getName(), AbstractTestLogSubject.getSlice("qu", subject)); - assertEquals("Incorrect routing key in create", getName(), AbstractTestLogSubject.getSlice("rk", subject)); - - // Validate it was a management actor. - String actor = fromActor(log); - assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng")); - } - - /** - * Description: - * Bindings can be deleted so that a queue can be rebound with a different set of values. This can be performed via the Management Console - * Input: - * - * 1. Running Broker - * 2. Management Console connected - * 3. Management Console is used to perform unbind. - * Output: - * - * <date> BND-1002 : Deleted - * - * Validation Steps: - * 4. The BND ID is correct - * 5. There must have been a BND-1001 Create message first. - * 6. This will be the last message for the given binding - * - * @throws java.io.IOException - if there is a problem reseting the log monitor or an issue with the JMX Connection - * @throws javax.management.JMException - {@see #createExchange and ManagedBroker.unregisterExchange} - */ - public void testUnRegisterExchangeViaManagementConsole() throws IOException, JMException - { - //Remove any previous queue declares - _monitor.markDiscardPoint(); - - _jmxUtils.createExchange("test", getName(), "direct", false); - - ManagedBroker managedBroker = _jmxUtils.getManagedBroker("test"); - - managedBroker.unregisterExchange(getName()); - - List<String> results = waitAndFindMatches("EXH-1002"); - - assertEquals("More than one exchange deletion found", 1, results.size()); - - String log = getLog(results.get(0)); - - // Validate correct binding - String subject = fromSubject(log); - assertEquals("Incorrect exchange named in delete", "direct/" + getName(), AbstractTestLogSubject.getSlice("ex", subject)); - - // Validate it was a management actor. - String actor = fromActor(log); - assertTrue("Actor is not a manangement actor:" + actor, actor.startsWith("mng")); - } - -} diff --git a/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/systest/management/jmx/ManagementLoggingTest.java b/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/systest/management/jmx/ManagementLoggingTest.java deleted file mode 100644 index 6100d5a23e..0000000000 --- a/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/systest/management/jmx/ManagementLoggingTest.java +++ /dev/null @@ -1,317 +0,0 @@ -/* - * - * 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.management.jmx; - - -import org.apache.qpid.server.configuration.ServerConfiguration; -import org.apache.qpid.server.logging.AbstractTestLogging; -import org.apache.qpid.test.utils.JMXTestUtils; -import org.apache.qpid.util.LogMonitor; - -import java.io.File; -import java.util.List; - -/** - * Management Console Test Suite - * - * The Management Console test suite validates that the follow log messages as specified in the Functional Specification. - * - * This suite of tests validate that the management console messages occur correctly and according to the following format: - * - * MNG-1001 : Startup - * MNG-1002 : Starting : <service> : Listening on port <Port> - * MNG-1003 : Shutting down : <service> : port <Port> - * MNG-1004 : Ready - * MNG-1005 : Stopped - * MNG-1006 : Using SSL Keystore : <path> - * MNG-1007 : Open : User <username> - * MNG-1008 : Close : User <username> - */ -public class ManagementLoggingTest extends AbstractTestLogging -{ - private static final String MNG_PREFIX = "MNG-"; - - public void setUp() throws Exception - { - setLogMessagePrefix(); - - // We either do this here or have a null check in tearDown. - // As when this test is run against profiles other than java it will NPE - _monitor = new LogMonitor(_outputFile); - //We explicitly do not call super.setUp as starting up the broker is - //part of the test case. - - } - - /** - * Description: - * Using the startup configuration validate that the management startup - * message is logged correctly. - * Input: - * Standard configuration with management enabled - * Output: - * - * <date> MNG-1001 : Startup - * - * Constraints: - * This is the FIRST message logged by MNG - * Validation Steps: - * - * 1. The BRK ID is correct - * 2. This is the FIRST message logged by MNG - */ - public void testManagementStartupEnabled() throws Exception - { - // This test only works on java brokers - if (isJavaBroker()) - { - startBrokerAndCreateMonitor(true, false); - - // Ensure we have received the MNG log msg. - waitForMessage("MNG-1001"); - - List<String> results = findMatches(MNG_PREFIX); - // Validation - - assertTrue("MNGer message not logged", results.size() > 0); - - String log = getLogMessage(results, 0); - - //1 - validateMessageID("MNG-1001", log); - - //2 - //There will be 2 copies of the startup message (one via SystemOut, and one via Log4J) - results = findMatches("MNG-1001"); - assertEquals("Unexpected startup message count.", - 2, results.size()); - - //3 - assertEquals("Startup log message is not 'Startup'.", "Startup", - getMessageString(log)); - } - } - - /** - * Description: - * Verify that when management is disabled in the configuration file the - * startup message is not logged. - * Input: - * Standard configuration with management disabled - * Output: - * NO MNG messages - * Validation Steps: - * - * 1. Validate that no MNG messages are produced. - */ - public void testManagementStartupDisabled() throws Exception - { - if (isJavaBroker()) - { - startBrokerAndCreateMonitor(false, false); - - List<String> results = findMatches(MNG_PREFIX); - // Validation - - assertEquals("MNGer messages logged", 0, results.size()); - } - } - - /** - * The two MNG-1002 messages are logged at the same time so lets test them - * at the same time. - * - * Description: - * Using the default configuration validate that the RMI Registry socket is - * correctly reported as being opened - * - * Input: - * The default configuration file - * Output: - * - * <date> MESSAGE MNG-1002 : Starting : RMI Registry : Listening on port 8999 - * - * Constraints: - * The RMI ConnectorServer and Registry log messages do not have a prescribed order - * Validation Steps: - * - * 1. The MNG ID is correct - * 2. The specified port is the correct '8999' - * - * Description: - * Using the default configuration validate that the RMI ConnectorServer - * socket is correctly reported as being opened - * - * Input: - * The default configuration file - * Output: - * - * <date> MESSAGE MNG-1002 : Starting : RMI ConnectorServer : Listening on port 9099 - * - * Constraints: - * The RMI ConnectorServer and Registry log messages do not have a prescribed order - * Validation Steps: - * - * 1. The MNG ID is correct - * 2. The specified port is the correct '9099' - */ - public void testManagementStartupRMIEntries() throws Exception - { - if (isJavaBroker()) - { - startBrokerAndCreateMonitor(true, false); - - List<String> results = waitAndFindMatches("MNG-1002"); - // Validation - - //There will be 4 startup messages (two via SystemOut, and two via Log4J) - assertEquals("Unexpected MNG-1002 message count", 4, results.size()); - - String log = getLogMessage(results, 0); - - //1 - validateMessageID("MNG-1002", log); - - //Check the RMI Registry port is as expected - int mPort = getManagementPort(getPort()); - assertTrue("RMI Registry port not as expected(" + mPort + ").:" + getMessageString(log), - getMessageString(log).endsWith(String.valueOf(mPort))); - - log = getLogMessage(results, 2); - - //1 - validateMessageID("MNG-1002", log); - - // We expect the RMI Registry port (the defined 'management port') to be - // 100 lower than the JMX RMIConnector Server Port (the actual JMX server) - int jmxPort = mPort + ServerConfiguration.JMXPORT_CONNECTORSERVER_OFFSET; - assertTrue("JMX RMIConnectorServer port not as expected(" + jmxPort + ").:" + getMessageString(log), - getMessageString(log).endsWith(String.valueOf(jmxPort))); - } - } - - /** - * Description: - * Using the default configuration with SSL enabled for the management port the SSL Keystore path should be reported via MNG-1006 - * Input: - * Management SSL enabled default configuration. - * Output: - * - * <date> MESSAGE MNG-1006 : Using SSL Keystore : test_resources/ssl/keystore.jks - * - * Validation Steps: - * - * 1. The MNG ID is correct - * 2. The keystore path is as specified in the configuration - */ - public void testManagementStartupSSLKeystore() throws Exception - { - if (isJavaBroker()) - { - startBrokerAndCreateMonitor(true, true); - - List<String> results = waitAndFindMatches("MNG-1006"); - - assertTrue("MNGer message not logged", results.size() > 0); - - String log = getLogMessage(results, 0); - - //1 - validateMessageID("MNG-1006", log); - - // Validate we only have two MNG-1002 (one via stdout, one via log4j) - results = findMatches("MNG-1006"); - assertEquals("Upexpected SSL Keystore message count", - 2, results.size()); - - // Validate the keystore path is as expected - assertTrue("SSL Keystore entry expected.:" + getMessageString(log), - getMessageString(log).endsWith(new File(getConfigurationStringProperty("management.ssl.keyStorePath")).getName())); - } - } - - /** - * Description: Tests the management connection open/close are logged correctly. - * - * Output: - * - * <date> MESSAGE MNG-1007 : Open : User <username> - * <date> MESSAGE MNG-1008 : Close : User <username> - * - * Validation Steps: - * - * 1. The MNG ID is correct - * 2. The message and username are correct - */ - public void testManagementUserOpenClose() throws Exception - { - if (isJavaBroker()) - { - startBrokerAndCreateMonitor(true, false); - - final JMXTestUtils jmxUtils = new JMXTestUtils(this); - List<String> openResults = null; - List<String> closeResults = null; - try - { - jmxUtils.setUp(); - jmxUtils.open(); - openResults = waitAndFindMatches("MNG-1007"); - } - finally - { - if (jmxUtils != null) - { - jmxUtils.close(); - closeResults = waitAndFindMatches("MNG-1008"); - } - } - - assertNotNull("Management Open results null", openResults.size()); - assertEquals("Management Open logged unexpected number of times", 1, openResults.size()); - - assertNotNull("Management Close results null", closeResults.size()); - assertEquals("Management Close logged unexpected number of times", 1, closeResults.size()); - - final String openMessage = getMessageString(getLogMessage(openResults, 0)); - assertTrue("Unexpected open message " + openMessage, openMessage.endsWith("Open : User admin")); - final String closeMessage = getMessageString(getLogMessage(closeResults, 0)); - assertTrue("Unexpected close message " + closeMessage, closeMessage.endsWith("Close : User admin")); - } - } - - private void startBrokerAndCreateMonitor(boolean managementEnabled, boolean useManagementSSL) throws Exception - { - //Ensure management is on - setConfigurationProperty("management.enabled", String.valueOf(managementEnabled)); - - if(useManagementSSL) - { - // This test requires we have an ssl connection - setConfigurationProperty("management.ssl.enabled", "true"); - } - - startBroker(); - - // Now we can create the monitor as _outputFile will now be defined - _monitor = new LogMonitor(_outputFile); - } -} diff --git a/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/systest/management/jmx/QueueManagementTest.java b/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/systest/management/jmx/QueueManagementTest.java deleted file mode 100644 index 79d04b239e..0000000000 --- a/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/systest/management/jmx/QueueManagementTest.java +++ /dev/null @@ -1,696 +0,0 @@ -/* - * 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.management.jmx; - -import org.apache.commons.lang.time.FastDateFormat; - -import org.apache.log4j.Logger; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.configuration.ClientProperties; -import org.apache.qpid.framing.AMQShortString; -import org.apache.qpid.management.common.mbeans.ManagedBroker; -import org.apache.qpid.management.common.mbeans.ManagedQueue; -import org.apache.qpid.server.queue.AMQQueueFactory; -import org.apache.qpid.server.queue.NotificationCheckTest; -import org.apache.qpid.server.queue.SimpleAMQQueueTest; -import org.apache.qpid.test.client.destination.AddressBasedDestinationTest; -import org.apache.qpid.test.utils.JMXTestUtils; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -import javax.jms.Connection; -import javax.jms.Destination; -import javax.jms.JMSException; -import javax.jms.Message; -import javax.jms.MessageConsumer; -import javax.jms.MessageListener; -import javax.jms.Queue; -import javax.jms.Session; -import javax.jms.TextMessage; -import javax.management.Notification; -import javax.management.NotificationListener; -import javax.management.openmbean.CompositeData; -import javax.management.openmbean.TabularData; -import javax.naming.NamingException; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.SortedSet; -import java.util.TreeSet; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; - -/** - * Tests the JMX API for the Managed Queue. - * - */ -public class QueueManagementTest extends QpidBrokerTestCase -{ - - private static final Logger LOGGER = Logger.getLogger(QueueManagementTest.class); - - private static final String VIRTUAL_HOST = "test"; - private static final String TEST_QUEUE_DESCRIPTION = "my description"; - - private JMXTestUtils _jmxUtils; - private Connection _connection; - private Session _session; - - private String _sourceQueueName; - private String _destinationQueueName; - private Destination _sourceQueue; - private Destination _destinationQueue; - private ManagedQueue _managedSourceQueue; - private ManagedQueue _managedDestinationQueue; - - public void setUp() throws Exception - { - _jmxUtils = new JMXTestUtils(this); - _jmxUtils.setUp(); - - super.setUp(); - _sourceQueueName = getTestQueueName() + "_src"; - _destinationQueueName = getTestQueueName() + "_dest"; - - createConnectionAndSession(); - - _sourceQueue = _session.createQueue(_sourceQueueName); - _destinationQueue = _session.createQueue(_destinationQueueName); - createQueueOnBroker(_sourceQueue); - createQueueOnBroker(_destinationQueue); - - _jmxUtils.open(); - - createManagementInterfacesForQueues(); - } - - public void tearDown() throws Exception - { - if (_jmxUtils != null) - { - _jmxUtils.close(); - } - super.tearDown(); - } - - public void testQueueAttributes() throws Exception - { - Queue queue = _session.createQueue(getTestQueueName()); - createQueueOnBroker(queue); - - final String queueName = queue.getQueueName(); - - final ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName); - assertEquals("Unexpected name", queueName, managedQueue.getName()); - assertEquals("Unexpected queue type", "standard", managedQueue.getQueueType()); - } - - public void testExclusiveQueueHasJmsClientIdAsOwner() throws Exception - { - Queue tmpQueue = _session.createTemporaryQueue(); - - final String queueName = tmpQueue.getQueueName(); - - final ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName); - assertNotNull(_connection.getClientID()); - assertEquals("Unexpected owner", _connection.getClientID(), managedQueue.getOwner()); - } - - public void testNonExclusiveQueueHasNoOwner() throws Exception - { - Queue nonExclusiveQueue = _session.createQueue(getTestQueueName()); - createQueueOnBroker(nonExclusiveQueue); - - final String queueName = nonExclusiveQueue.getQueueName(); - - final ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName); - assertNull("Unexpected owner", managedQueue.getOwner()); - } - - public void testSetNewQueueDescriptionOnExistingQueue() throws Exception - { - Queue queue = _session.createQueue(getTestQueueName()); - createQueueOnBroker(queue); - - final String queueName = queue.getQueueName(); - - final ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName); - assertNull("Unexpected description", managedQueue.getDescription()); - - managedQueue.setDescription(TEST_QUEUE_DESCRIPTION); - assertEquals(TEST_QUEUE_DESCRIPTION, managedQueue.getDescription()); - } - - public void testNewQueueWithDescription() throws Exception - { - String queueName = getTestQueueName(); - Map<String, Object> arguments = Collections.singletonMap(AMQQueueFactory.X_QPID_DESCRIPTION, (Object)TEST_QUEUE_DESCRIPTION); - ((AMQSession<?, ?>)_session).createQueue(AMQShortString.valueOf(queueName), false, true, false, arguments); - - final ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName); - assertEquals(TEST_QUEUE_DESCRIPTION, managedQueue.getDescription()); - } - - /** - * Requires persistent store. - */ - public void testQueueDescriptionSurvivesRestart() throws Exception - { - String queueName = getTestQueueName(); - Map<String, Object> arguments = Collections.singletonMap(AMQQueueFactory.X_QPID_DESCRIPTION, (Object)TEST_QUEUE_DESCRIPTION); - - ((AMQSession<?, ?>)_session).createQueue(AMQShortString.valueOf(queueName), false, true, false, arguments); - - ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName); - assertEquals(TEST_QUEUE_DESCRIPTION, managedQueue.getDescription()); - - restartBroker(); - - managedQueue = _jmxUtils.getManagedQueue(queueName); - assertEquals(TEST_QUEUE_DESCRIPTION, managedQueue.getDescription()); - } - - /** - * Tests queue creation with {@link AMQQueueFactory#X_QPID_MAXIMUM_DELIVERY_COUNT} argument. Also tests - * that the attribute is exposed correctly through {@link ManagedQueue#getMaximumDeliveryCount()}. - */ - public void testCreateQueueWithMaximumDeliveryCountSet() throws Exception - { - final String queueName = getName(); - final ManagedBroker managedBroker = _jmxUtils.getManagedBroker(VIRTUAL_HOST); - - final Integer deliveryCount = 1; - final Map<String, Object> arguments = Collections.singletonMap(AMQQueueFactory.X_QPID_MAXIMUM_DELIVERY_COUNT, (Object)deliveryCount); - managedBroker.createNewQueue(queueName, null, true, arguments); - - // Ensure the queue exists - assertNotNull("Queue object name expected to exist", _jmxUtils.getQueueObjectName("test", queueName)); - assertNotNull("Manager queue expected to be available", _jmxUtils.getManagedQueue(queueName)); - - final ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName); - assertEquals("Unexpected maximum delivery count", deliveryCount, managedQueue.getMaximumDeliveryCount()); - } - - /** - * Requires 0-10 as relies on ADDR addresses. - * @see AddressBasedDestinationTest for the testing of message routing to the alternate exchange - */ - public void testGetSetAlternateExchange() throws Exception - { - String queueName = getTestQueueName(); - String altExchange = "amq.fanout"; - String addrWithAltExch = String.format("ADDR:%s;{create:always,node:{type:queue,x-declare:{alternate-exchange:'%s'}}}", queueName, altExchange); - Queue queue = _session.createQueue(addrWithAltExch); - - createQueueOnBroker(queue); - - final ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName); - assertEquals("Newly created queue does not have expected alternate exchange", altExchange, managedQueue.getAlternateExchange()); - - String newAltExch = "amq.topic"; - managedQueue.setAlternateExchange(newAltExch); - assertEquals("Unexpected alternate exchange after set", newAltExch, managedQueue.getAlternateExchange()); - } - - /** - * Requires 0-10 as relies on ADDR addresses. - */ - public void testRemoveAlternateExchange() throws Exception - { - String queueName = getTestQueueName(); - String altExchange = "amq.fanout"; - String addrWithAltExch = String.format("ADDR:%s;{create:always,node:{type:queue,x-declare:{alternate-exchange:'%s'}}}", queueName, altExchange); - Queue queue = _session.createQueue(addrWithAltExch); - - createQueueOnBroker(queue); - - final ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName); - assertEquals("Newly created queue does not have expected alternate exchange", altExchange, managedQueue.getAlternateExchange()); - - managedQueue.setAlternateExchange(""); - assertNull("Unexpected alternate exchange after set", managedQueue.getAlternateExchange()); - } - - /** - * Requires persistent store - * Requires 0-10 as relies on ADDR addresses. - */ - public void testAlternateExchangeSurvivesRestart() throws Exception - { - String nonMandatoryExchangeName = "exch" + getName(); - - final ManagedBroker managedBroker = _jmxUtils.getManagedBroker(VIRTUAL_HOST); - managedBroker.createNewExchange(nonMandatoryExchangeName, "fanout", true); - - String queueName1 = getTestQueueName() + "1"; - String altExchange1 = "amq.fanout"; - String addr1WithAltExch = String.format("ADDR:%s;{create:always,node:{durable: true,type:queue,x-declare:{alternate-exchange:'%s'}}}", queueName1, altExchange1); - Queue queue1 = _session.createQueue(addr1WithAltExch); - - String queueName2 = getTestQueueName() + "2"; - String addr2WithoutAltExch = String.format("ADDR:%s;{create:always,node:{durable: true,type:queue}}", queueName2); - Queue queue2 = _session.createQueue(addr2WithoutAltExch); - - createQueueOnBroker(queue1); - createQueueOnBroker(queue2); - - ManagedQueue managedQueue1 = _jmxUtils.getManagedQueue(queueName1); - assertEquals("Newly created queue1 does not have expected alternate exchange", altExchange1, managedQueue1.getAlternateExchange()); - - ManagedQueue managedQueue2 = _jmxUtils.getManagedQueue(queueName2); - assertNull("Newly created queue2 does not have expected alternate exchange", managedQueue2.getAlternateExchange()); - - String altExchange2 = nonMandatoryExchangeName; - managedQueue2.setAlternateExchange(altExchange2); - - restartBroker(); - - managedQueue1 = _jmxUtils.getManagedQueue(queueName1); - assertEquals("Queue1 does not have expected alternate exchange after restart", altExchange1, managedQueue1.getAlternateExchange()); - - managedQueue2 = _jmxUtils.getManagedQueue(queueName2); - assertEquals("Queue2 does not have expected updated alternate exchange after restart", altExchange2, managedQueue2.getAlternateExchange()); - } - - /** - * Tests the ability to receive queue alerts as JMX notifications. - * - * @see NotificationCheckTest - * @see SimpleAMQQueueTest#testNotificationFiredAsync() - * @see SimpleAMQQueueTest#testNotificationFiredOnEnqueue() - */ - public void testQueueNotification() throws Exception - { - final String queueName = getName(); - final long maximumMessageCount = 3; - - Queue queue = _session.createQueue(queueName); - createQueueOnBroker(queue); - - ManagedQueue managedQueue = _jmxUtils.getManagedQueue(queueName); - managedQueue.setMaximumMessageCount(maximumMessageCount); - - RecordingNotificationListener listener = new RecordingNotificationListener(1); - - _jmxUtils.addNotificationListener(_jmxUtils.getQueueObjectName(VIRTUAL_HOST, queueName), listener, null, null); - - // Send two messages - this should *not* trigger the notification - sendMessage(_session, queue, 2); - - assertEquals("Premature notification received", 0, listener.getNumberOfNotificationsReceived()); - - // A further message should trigger the message count alert - sendMessage(_session, queue, 1); - - listener.awaitExpectedNotifications(5, TimeUnit.SECONDS); - - assertEquals("Unexpected number of JMX notifications received", 1, listener.getNumberOfNotificationsReceived()); - - Notification notification = listener.getLastNotification(); - assertEquals("Unexpected notification message", "MESSAGE_COUNT_ALERT 3: Maximum count on queue threshold (3) breached.", notification.getMessage()); - } - - /** - * Tests {@link ManagedQueue#viewMessages(long, long)} interface. - */ - public void testViewSingleMessage() throws Exception - { - final List<Message> sentMessages = sendMessage(_session, _sourceQueue, 1); - syncSession(_session); - final Message sentMessage = sentMessages.get(0); - - assertEquals("Unexpected queue depth", 1, _managedSourceQueue.getMessageCount().intValue()); - - // Check the contents of the message - final TabularData tab = _managedSourceQueue.viewMessages(1l, 1l); - assertEquals("Unexpected number of rows in table", 1, tab.size()); - final Iterator<CompositeData> rowItr = (Iterator<CompositeData>) tab.values().iterator(); - - final CompositeData row1 = rowItr.next(); - assertNotNull("Message should have AMQ message id", row1.get(ManagedQueue.MSG_AMQ_ID)); - assertEquals("Unexpected queue position", 1l, row1.get(ManagedQueue.MSG_QUEUE_POS)); - assertEquals("Unexpected redelivered flag", Boolean.FALSE, row1.get(ManagedQueue.MSG_REDELIVERED)); - - // Check the contents of header (encoded in a string array) - final String[] headerArray = (String[]) row1.get(ManagedQueue.MSG_HEADER); - assertNotNull("Expected message header array", headerArray); - final Map<String, String> headers = headerArrayToMap(headerArray); - - final String expectedJMSMessageID = isBroker010() ? sentMessage.getJMSMessageID().replace("ID:", "") : sentMessage.getJMSMessageID(); - final String expectedFormattedJMSTimestamp = FastDateFormat.getInstance(ManagedQueue.JMSTIMESTAMP_DATETIME_FORMAT).format(sentMessage.getJMSTimestamp()); - assertEquals("Unexpected JMSMessageID within header", expectedJMSMessageID, headers.get("JMSMessageID")); - assertEquals("Unexpected JMSPriority within header", String.valueOf(sentMessage.getJMSPriority()), headers.get("JMSPriority")); - assertEquals("Unexpected JMSTimestamp within header", expectedFormattedJMSTimestamp, headers.get("JMSTimestamp")); - } - - /** - * Tests {@link ManagedQueue#moveMessages(long, long, String)} interface. - */ - public void testMoveMessagesBetweenQueues() throws Exception - { - final int numberOfMessagesToSend = 10; - - sendMessage(_session, _sourceQueue, numberOfMessagesToSend); - syncSession(_session); - assertEquals("Unexpected queue depth after send", numberOfMessagesToSend, _managedSourceQueue.getMessageCount().intValue()); - - List<Long> amqMessagesIds = getAMQMessageIdsOn(_managedSourceQueue, 1, numberOfMessagesToSend); - - // Move first three messages to destination - long fromMessageId = amqMessagesIds.get(0); - long toMessageId = amqMessagesIds.get(2); - _managedSourceQueue.moveMessages(fromMessageId, toMessageId, _destinationQueueName); - - assertEquals("Unexpected queue depth on destination queue after first move", 3, _managedDestinationQueue.getMessageCount().intValue()); - assertEquals("Unexpected queue depth on source queue after first move", 7, _managedSourceQueue.getMessageCount().intValue()); - - // Now move a further two messages to destination - fromMessageId = amqMessagesIds.get(7); - toMessageId = amqMessagesIds.get(8); - _managedSourceQueue.moveMessages(fromMessageId, toMessageId, _destinationQueueName); - assertEquals("Unexpected queue depth on destination queue after second move", 5, _managedDestinationQueue.getMessageCount().intValue()); - assertEquals("Unexpected queue depth on source queue after second move", 5, _managedSourceQueue.getMessageCount().intValue()); - - assertMessageIndicesOn(_destinationQueue, 0, 1, 2, 7, 8); - } - - /** - * Tests {@link ManagedQueue#copyMessages(long, long, String)} interface. - */ - public void testCopyMessagesBetweenQueues() throws Exception - { - final int numberOfMessagesToSend = 10; - sendMessage(_session, _sourceQueue, numberOfMessagesToSend); - syncSession(_session); - assertEquals("Unexpected queue depth after send", numberOfMessagesToSend, _managedSourceQueue.getMessageCount().intValue()); - - List<Long> amqMessagesIds = getAMQMessageIdsOn(_managedSourceQueue, 1, numberOfMessagesToSend); - - // Copy first three messages to destination - long fromMessageId = amqMessagesIds.get(0); - long toMessageId = amqMessagesIds.get(2); - _managedSourceQueue.copyMessages(fromMessageId, toMessageId, _destinationQueueName); - - assertEquals("Unexpected queue depth on destination queue after first copy", 3, _managedDestinationQueue.getMessageCount().intValue()); - assertEquals("Unexpected queue depth on source queue after first copy", numberOfMessagesToSend, _managedSourceQueue.getMessageCount().intValue()); - - // Now copy a further two messages to destination - fromMessageId = amqMessagesIds.get(7); - toMessageId = amqMessagesIds.get(8); - _managedSourceQueue.copyMessages(fromMessageId, toMessageId, _destinationQueueName); - assertEquals("Unexpected queue depth on destination queue after second copy", 5, _managedDestinationQueue.getMessageCount().intValue()); - assertEquals("Unexpected queue depth on source queue after second copy", numberOfMessagesToSend, _managedSourceQueue.getMessageCount().intValue()); - - assertMessageIndicesOn(_destinationQueue, 0, 1, 2, 7, 8); - } - - public void testMoveMessagesBetweenQueuesWithActiveConsumerOnSourceQueue() throws Exception - { - setTestClientSystemProperty(ClientProperties.MAX_PREFETCH_PROP_NAME, new Integer(1).toString()); - Connection asyncConnection = getConnection(); - asyncConnection.start(); - - final int numberOfMessagesToSend = 50; - sendMessage(_session, _sourceQueue, numberOfMessagesToSend); - syncSession(_session); - assertEquals("Unexpected queue depth after send", numberOfMessagesToSend, _managedSourceQueue.getMessageCount().intValue()); - - List<Long> amqMessagesIds = getAMQMessageIdsOn(_managedSourceQueue, 1, numberOfMessagesToSend); - - long fromMessageId = amqMessagesIds.get(0); - long toMessageId = amqMessagesIds.get(numberOfMessagesToSend - 1); - - CountDownLatch consumerReadToHalfwayLatch = new CountDownLatch(numberOfMessagesToSend / 2); - AtomicInteger totalConsumed = new AtomicInteger(0); - startAsyncConsumerOn(_sourceQueue, asyncConnection, consumerReadToHalfwayLatch, totalConsumed); - - boolean halfwayPointReached = consumerReadToHalfwayLatch.await(5000, TimeUnit.MILLISECONDS); - assertTrue("Did not read half of messages within time allowed", halfwayPointReached); - - _managedSourceQueue.moveMessages(fromMessageId, toMessageId, _destinationQueueName); - - asyncConnection.stop(); - - // The exact number of messages moved will be non deterministic, as the number of messages processed - // by the consumer cannot be predicted. There is also the possibility that a message can remain - // on the source queue. This situation will arise if a message has been acquired by the consumer, but not - // yet delivered to the client application (i.e. MessageListener#onMessage()) when the Connection#stop() occurs. - // - // The number of messages moved + the number consumed + any messages remaining on source should - // *always* be equal to the number we originally sent. - - int numberOfMessagesReadByConsumer = totalConsumed.intValue(); - int numberOfMessagesOnDestinationQueue = _managedDestinationQueue.getMessageCount().intValue(); - int numberOfMessagesRemainingOnSourceQueue = _managedSourceQueue.getMessageCount().intValue(); - - LOGGER.debug("Async consumer read : " + numberOfMessagesReadByConsumer - + " Number of messages moved to destination : " + numberOfMessagesOnDestinationQueue - + " Number of messages remaining on source : " + numberOfMessagesRemainingOnSourceQueue); - assertEquals("Unexpected number of messages after move", numberOfMessagesToSend, numberOfMessagesReadByConsumer + numberOfMessagesOnDestinationQueue + numberOfMessagesRemainingOnSourceQueue); - } - - public void testMoveMessagesBetweenQueuesWithActiveConsumerOnDestinationQueue() throws Exception - { - setTestClientSystemProperty(ClientProperties.MAX_PREFETCH_PROP_NAME, new Integer(1).toString()); - Connection asyncConnection = getConnection(); - asyncConnection.start(); - - final int numberOfMessagesToSend = 50; - sendMessage(_session, _sourceQueue, numberOfMessagesToSend); - syncSession(_session); - assertEquals("Unexpected queue depth after send", numberOfMessagesToSend, _managedSourceQueue.getMessageCount().intValue()); - - List<Long> amqMessagesIds = getAMQMessageIdsOn(_managedSourceQueue, 1, numberOfMessagesToSend); - long fromMessageId = amqMessagesIds.get(0); - long toMessageId = amqMessagesIds.get(numberOfMessagesToSend - 1); - - AtomicInteger totalConsumed = new AtomicInteger(0); - CountDownLatch allMessagesConsumedLatch = new CountDownLatch(numberOfMessagesToSend); - startAsyncConsumerOn(_destinationQueue, asyncConnection, allMessagesConsumedLatch, totalConsumed); - - _managedSourceQueue.moveMessages(fromMessageId, toMessageId, _destinationQueueName); - - allMessagesConsumedLatch.await(5000, TimeUnit.MILLISECONDS); - assertEquals("Did not consume all messages from destination queue", numberOfMessagesToSend, totalConsumed.intValue()); - } - - /** - * Tests {@link ManagedQueue#moveMessages(long, long, String)} interface. - */ - public void testMoveMessageBetweenQueuesWithBrokerRestart() throws Exception - { - final int numberOfMessagesToSend = 1; - - sendMessage(_session, _sourceQueue, numberOfMessagesToSend); - syncSession(_session); - assertEquals("Unexpected queue depth after send", numberOfMessagesToSend, _managedSourceQueue.getMessageCount().intValue()); - - restartBroker(); - - createManagementInterfacesForQueues(); - createConnectionAndSession(); - - List<Long> amqMessagesIds = getAMQMessageIdsOn(_managedSourceQueue, 1, numberOfMessagesToSend); - - // Move messages to destination - long messageId = amqMessagesIds.get(0); - _managedSourceQueue.moveMessages(messageId, messageId, _destinationQueueName); - - assertEquals("Unexpected queue depth on destination queue after move", 1, _managedDestinationQueue.getMessageCount().intValue()); - assertEquals("Unexpected queue depth on source queue after move", 0, _managedSourceQueue.getMessageCount().intValue()); - - assertMessageIndicesOn(_destinationQueue, 0); - } - - /** - * Tests {@link ManagedQueue#copyMessages(long, long, String)} interface. - */ - public void testCopyMessageBetweenQueuesWithBrokerRestart() throws Exception - { - final int numberOfMessagesToSend = 1; - - sendMessage(_session, _sourceQueue, numberOfMessagesToSend); - syncSession(_session); - assertEquals("Unexpected queue depth after send", numberOfMessagesToSend, _managedSourceQueue.getMessageCount().intValue()); - - restartBroker(); - - createManagementInterfacesForQueues(); - createConnectionAndSession(); - - List<Long> amqMessagesIds = getAMQMessageIdsOn(_managedSourceQueue, 1, numberOfMessagesToSend); - - // Move messages to destination - long messageId = amqMessagesIds.get(0); - _managedSourceQueue.copyMessages(messageId, messageId, _destinationQueueName); - - assertEquals("Unexpected queue depth on destination queue after copy", 1, _managedDestinationQueue.getMessageCount().intValue()); - assertEquals("Unexpected queue depth on source queue after copy", 1, _managedSourceQueue.getMessageCount().intValue()); - - assertMessageIndicesOn(_destinationQueue, 0); - } - - @Override - public Message createNextMessage(Session session, int messageNumber) throws JMSException - { - Message message = session.createTextMessage(getContentForMessageNumber(messageNumber)); - message.setIntProperty(INDEX, messageNumber); - return message; - } - - private void startAsyncConsumerOn(Destination queue, Connection asyncConnection, - final CountDownLatch requiredNumberOfMessagesRead, final AtomicInteger totalConsumed) throws Exception - { - Session session = asyncConnection.createSession(false, Session.AUTO_ACKNOWLEDGE); - MessageConsumer consumer = session.createConsumer(queue); - consumer.setMessageListener(new MessageListener() - { - - @Override - public void onMessage(Message arg0) - { - totalConsumed.incrementAndGet(); - requiredNumberOfMessagesRead.countDown(); - } - }); - } - - private void assertMessageIndicesOn(Destination queue, int... expectedIndices) throws Exception - { - MessageConsumer consumer = _session.createConsumer(queue); - - for (int i : expectedIndices) - { - TextMessage message = (TextMessage)consumer.receive(1000); - assertNotNull("Expected message with index " + i, message); - assertEquals("Expected message with index " + i, i, message.getIntProperty(INDEX)); - assertEquals("Expected message content", getContentForMessageNumber(i), message.getText()); - } - - assertNull("Unexpected message encountered", consumer.receive(1000)); - } - - private List<Long> getAMQMessageIdsOn(ManagedQueue managedQueue, long startIndex, long endIndex) throws Exception - { - final SortedSet<Long> messageIds = new TreeSet<Long>(); - - final TabularData tab = managedQueue.viewMessages(startIndex, endIndex); - final Iterator<CompositeData> rowItr = (Iterator<CompositeData>) tab.values().iterator(); - while(rowItr.hasNext()) - { - final CompositeData row = rowItr.next(); - long amqMessageId = (Long)row.get(ManagedQueue.MSG_AMQ_ID); - messageIds.add(amqMessageId); - } - - return new ArrayList<Long>(messageIds); - } - - /** - * - * Utility method to convert array of Strings in the form x = y into a - * map with key/value x => y. - * - */ - private Map<String,String> headerArrayToMap(final String[] headerArray) - { - final Map<String, String> headerMap = new HashMap<String, String>(); - final List<String> headerList = Arrays.asList(headerArray); - for (Iterator<String> iterator = headerList.iterator(); iterator.hasNext();) - { - final String nameValuePair = iterator.next(); - final String[] nameValue = nameValuePair.split(" *= *", 2); - headerMap.put(nameValue[0], nameValue[1]); - } - return headerMap; - } - - private void createQueueOnBroker(Destination destination) throws JMSException - { - _session.createConsumer(destination).close(); // Create a consumer only to cause queue creation - } - - private void syncSession(Session session) throws Exception - { - ((AMQSession<?,?>)session).sync(); - } - - private void createConnectionAndSession() throws JMSException, - NamingException - { - _connection = getConnection(); - _connection.start(); - _session = _connection.createSession(true, Session.SESSION_TRANSACTED); - } - - private void createManagementInterfacesForQueues() - { - _managedSourceQueue = _jmxUtils.getManagedQueue(_sourceQueueName); - _managedDestinationQueue = _jmxUtils.getManagedQueue(_destinationQueueName); - } - - private String getContentForMessageNumber(int msgCount) - { - return "Message count " + msgCount; - } - - private final class RecordingNotificationListener implements NotificationListener - { - private final CountDownLatch _notificationReceivedLatch; - private final AtomicInteger _numberOfNotifications; - private final AtomicReference<Notification> _lastNotification; - - private RecordingNotificationListener(int expectedNumberOfNotifications) - { - _notificationReceivedLatch = new CountDownLatch(expectedNumberOfNotifications); - _numberOfNotifications = new AtomicInteger(0); - _lastNotification = new AtomicReference<Notification>(); - } - - @Override - public void handleNotification(Notification notification, Object handback) - { - _lastNotification.set(notification); - _numberOfNotifications.incrementAndGet(); - _notificationReceivedLatch.countDown(); - } - - public int getNumberOfNotificationsReceived() - { - return _numberOfNotifications.get(); - } - - public Notification getLastNotification() - { - return _lastNotification.get(); - } - - public void awaitExpectedNotifications(long timeout, TimeUnit timeunit) throws InterruptedException - { - _notificationReceivedLatch.await(timeout, timeunit); - } - } - -} diff --git a/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/systest/management/jmx/StatisticsTest.java b/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/systest/management/jmx/StatisticsTest.java deleted file mode 100644 index c3fff94923..0000000000 --- a/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/systest/management/jmx/StatisticsTest.java +++ /dev/null @@ -1,204 +0,0 @@ -/* - * 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.management.jmx; - -import java.util.List; - -import javax.jms.Connection; -import javax.jms.MessageConsumer; -import javax.jms.Queue; -import javax.jms.Session; - -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.management.common.mbeans.ManagedBroker; -import org.apache.qpid.management.common.mbeans.ManagedConnection; -import org.apache.qpid.management.common.mbeans.ServerInformation; -import org.apache.qpid.test.utils.JMXTestUtils; -import org.apache.qpid.test.utils.QpidBrokerTestCase; - -public class StatisticsTest extends QpidBrokerTestCase -{ - private static final String TEST_USER = "admin"; - private static final String TEST_PASSWORD = "admin"; - private static final int MESSAGE_COUNT_TEST = 5; - private static final int MESSAGE_COUNT_DEV = 9; - - private JMXTestUtils _jmxUtils; - private Connection _test1, _dev; - private Session _testSession, _developmentSession; - private Queue _developmentQueue, _testQueue; - protected String _brokerUrl; - - @Override - public void setUp() throws Exception - { - _jmxUtils = new JMXTestUtils(this, TEST_USER, TEST_PASSWORD); - _jmxUtils.setUp(); - - super.setUp(); - - _brokerUrl = getBroker().toString(); - _test1 = new AMQConnection(_brokerUrl, TEST_USER, TEST_PASSWORD, "clientid", "test"); - _dev = new AMQConnection(_brokerUrl, TEST_USER, TEST_PASSWORD, "clientid", "development"); - _test1.start(); - _dev.start(); - - _testSession = _test1.createSession(true, Session.SESSION_TRANSACTED); - _developmentSession = _dev.createSession(true, Session.SESSION_TRANSACTED); - - _developmentQueue = _developmentSession.createQueue(getTestQueueName()); - _testQueue = _testSession.createQueue(getTestQueueName()); - - //Create queues by opening and closing consumers - final MessageConsumer testConsumer = _testSession.createConsumer(_testQueue); - testConsumer.close(); - final MessageConsumer developmentConsumer = _developmentSession.createConsumer(_developmentQueue); - developmentConsumer.close(); - - _jmxUtils.open(); - } - - @Override - public void tearDown() throws Exception - { - _jmxUtils.close(); - - super.tearDown(); - } - - public void testInitialStatisticValues() throws Exception - { - //Check initial values - checkSingleConnectionOnVHostStatistics("test", 0, 0, 0, 0); - checkVHostStatistics("test", 0, 0, 0, 0); - checkSingleConnectionOnVHostStatistics("development", 0, 0, 0, 0); - checkVHostStatistics("development", 0, 0, 0, 0); - checkBrokerStatistics(0, 0, 0, 0); - } - - public void testSendOnSingleVHost() throws Exception - { - sendMessagesAndSync(_testSession, _testQueue, MESSAGE_COUNT_TEST); - - //Check values - checkSingleConnectionOnVHostStatistics("test", MESSAGE_COUNT_TEST, 0, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE, 0); - checkVHostStatistics("test", MESSAGE_COUNT_TEST, 0, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE, 0); - checkSingleConnectionOnVHostStatistics("development", 0, 0, 0, 0); - checkVHostStatistics("development", 0, 0, 0, 0); - checkBrokerStatistics(MESSAGE_COUNT_TEST, 0, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE, 0); - } - - public void testSendOnTwoVHosts() throws Exception - { - sendMessagesAndSync(_testSession, _testQueue, MESSAGE_COUNT_TEST); - sendMessagesAndSync(_developmentSession, _developmentQueue, MESSAGE_COUNT_DEV); - - //Check values - checkSingleConnectionOnVHostStatistics("test", MESSAGE_COUNT_TEST, 0, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE, 0); - checkVHostStatistics("test", MESSAGE_COUNT_TEST, 0, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE, 0); - checkSingleConnectionOnVHostStatistics("development", MESSAGE_COUNT_DEV, 0, MESSAGE_COUNT_DEV * DEFAULT_MESSAGE_SIZE, 0); - checkVHostStatistics("development", MESSAGE_COUNT_DEV, 0, MESSAGE_COUNT_DEV * DEFAULT_MESSAGE_SIZE, 0); - checkBrokerStatistics(MESSAGE_COUNT_TEST + MESSAGE_COUNT_DEV, 0, (MESSAGE_COUNT_TEST + MESSAGE_COUNT_DEV) * DEFAULT_MESSAGE_SIZE, 0); - } - - public void testSendAndConsumeOnSingleVHost() throws Exception - { - sendMessagesAndSync(_testSession, _testQueue, MESSAGE_COUNT_TEST); - consumeMessages(_testSession, _testQueue, MESSAGE_COUNT_TEST); - - //Check values - checkSingleConnectionOnVHostStatistics("test", MESSAGE_COUNT_TEST, MESSAGE_COUNT_TEST, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE); - checkVHostStatistics("test", MESSAGE_COUNT_TEST, MESSAGE_COUNT_TEST, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE); - checkSingleConnectionOnVHostStatistics("development", 0, 0, 0, 0); - checkVHostStatistics("development", 0, 0, 0, 0); - checkBrokerStatistics(MESSAGE_COUNT_TEST, MESSAGE_COUNT_TEST, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE); - } - - public void testSendAndConsumeOnTwoVHosts() throws Exception - { - sendMessagesAndSync(_testSession, _testQueue, MESSAGE_COUNT_TEST); - sendMessagesAndSync(_developmentSession, _developmentQueue, MESSAGE_COUNT_DEV); - consumeMessages(_testSession, _testQueue, MESSAGE_COUNT_TEST); - consumeMessages(_developmentSession, _developmentQueue, MESSAGE_COUNT_DEV); - - //Check values - checkSingleConnectionOnVHostStatistics("test", MESSAGE_COUNT_TEST, MESSAGE_COUNT_TEST, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE); - checkVHostStatistics("test", MESSAGE_COUNT_TEST, MESSAGE_COUNT_TEST, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE, MESSAGE_COUNT_TEST * DEFAULT_MESSAGE_SIZE); - checkSingleConnectionOnVHostStatistics("development", MESSAGE_COUNT_DEV, MESSAGE_COUNT_DEV, MESSAGE_COUNT_DEV * DEFAULT_MESSAGE_SIZE, MESSAGE_COUNT_DEV * DEFAULT_MESSAGE_SIZE); - checkVHostStatistics("development", MESSAGE_COUNT_DEV, MESSAGE_COUNT_DEV, MESSAGE_COUNT_DEV * DEFAULT_MESSAGE_SIZE, MESSAGE_COUNT_DEV * DEFAULT_MESSAGE_SIZE); - checkBrokerStatistics(MESSAGE_COUNT_TEST + MESSAGE_COUNT_DEV, MESSAGE_COUNT_TEST + MESSAGE_COUNT_DEV, (MESSAGE_COUNT_TEST + MESSAGE_COUNT_DEV) * DEFAULT_MESSAGE_SIZE, (MESSAGE_COUNT_TEST + MESSAGE_COUNT_DEV) * DEFAULT_MESSAGE_SIZE); - } - - private void sendMessagesAndSync(Session session, Queue queue, int numberOfMessages) throws Exception - { - //Send messages via connection on and sync - sendMessage(session, queue, numberOfMessages); - ((AMQSession<?,?>)session).sync(); - } - - private void consumeMessages(Session session, Queue queue, int numberOfMessages) throws Exception - { - //consume the messages on the virtual host - final MessageConsumer consumer = session.createConsumer(queue); - for (int i = 0 ; i < numberOfMessages ; i++) - { - assertNotNull("an expected message was not received", consumer.receive(1500)); - } - session.commit(); - consumer.close(); - } - - private void checkSingleConnectionOnVHostStatistics(String vHostName, long messagesSent, long messagesReceived, long dataSent, long dataReceived) - { - List<ManagedConnection> managedConnections = _jmxUtils.getManagedConnections(vHostName); - assertEquals(1, managedConnections.size()); - - ManagedConnection managedConnection = managedConnections.get(0); - - assertEquals(messagesSent, managedConnection.getTotalMessagesReceived()); - assertEquals(messagesReceived, managedConnection.getTotalMessagesDelivered()); - - assertEquals(dataSent, managedConnection.getTotalDataReceived()); - assertEquals(dataReceived, managedConnection.getTotalDataDelivered()); - } - - private void checkVHostStatistics(String vHostName, long messagesSent, long messagesReceived, long dataSent, long dataReceived) - { - ManagedBroker vhost = _jmxUtils.getManagedBroker(vHostName); - - assertEquals(messagesSent, vhost.getTotalMessagesReceived()); - assertEquals(messagesReceived, vhost.getTotalMessagesDelivered()); - - assertEquals(dataSent, vhost.getTotalDataReceived()); - assertEquals(dataReceived, vhost.getTotalDataDelivered()); - } - - private void checkBrokerStatistics(long messagesSent, long messagesReceived, long dataSent, long dataReceived) - { - ServerInformation broker = _jmxUtils.getServerInformation(); - - assertEquals(messagesSent, broker.getTotalMessagesReceived()); - assertEquals(messagesReceived, broker.getTotalMessagesDelivered()); - - assertEquals(dataSent, broker.getTotalDataReceived()); - assertEquals(dataReceived, broker.getTotalDataDelivered()); - } -} diff --git a/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/systest/management/jmx/UserManagementTest.java b/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/systest/management/jmx/UserManagementTest.java deleted file mode 100644 index 62b1b554a9..0000000000 --- a/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/systest/management/jmx/UserManagementTest.java +++ /dev/null @@ -1,251 +0,0 @@ -/* - * 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.management.jmx; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; - -import javax.jms.Connection; -import javax.jms.JMSException; - -import org.apache.qpid.management.common.mbeans.UserManagement; -import org.apache.qpid.server.security.auth.database.PlainPasswordFilePrincipalDatabase; -import org.apache.qpid.server.security.auth.database.PrincipalDatabase; -import org.apache.qpid.test.utils.JMXTestUtils; -import org.apache.qpid.test.utils.QpidBrokerTestCase; -import org.apache.qpid.tools.security.Passwd; - -/** - * System test for User Management. - * - */ -public class UserManagementTest extends QpidBrokerTestCase -{ - private static final String TEST_NEWPASSWORD = "newpassword"; - private static final String TEST_PASSWORD = "password"; - private JMXTestUtils _jmxUtils; - private String _testUserName; - private File _passwordFile; - private UserManagement _userManagement; - private Passwd _passwd; - - public void setUp() throws Exception - { - _passwd = createPasswordEncodingUtility(); - _passwordFile = createTemporaryPasswordFileWithJmxAdminUser(); - - setConfigurationProperty("security.pd-auth-manager.principal-database.class", getPrincipalDatabaseImplClass().getName()); - setConfigurationProperty("security.pd-auth-manager.principal-database.attributes.attribute.name", "passwordFile"); - setConfigurationProperty("security.pd-auth-manager.principal-database.attributes.attribute.value", _passwordFile.getAbsolutePath()); - - _jmxUtils = new JMXTestUtils(this); - _jmxUtils.setUp(); - - super.setUp(); - _jmxUtils.open(); - - _testUserName = getTestName() + System.currentTimeMillis(); - - _userManagement = _jmxUtils.getUserManagement(); - } - - - public void tearDown() throws Exception - { - try - { - if (_jmxUtils != null) - { - _jmxUtils.close(); - } - } - finally - { - super.tearDown(); - } - } - - public void testCreateUser() throws Exception - { - final int initialNumberOfUsers = _userManagement.viewUsers().size(); - assertFileDoesNotContainsPasswordForUser(_testUserName); - - boolean success = _userManagement.createUser(_testUserName, TEST_PASSWORD); - assertTrue("Should have been able to create new user " + _testUserName, success); - assertEquals("Unexpected number of users after add", initialNumberOfUsers + 1, _userManagement.viewUsers().size()); - - assertFileContainsPasswordForUser(_testUserName); - } - - public void testJmsLoginForNewUser() throws Exception - { - assertJmsConnectionFails(_testUserName, TEST_PASSWORD); - testCreateUser(); - - assertJmsConnectionSucceeds(_testUserName, TEST_PASSWORD); - } - - public void testDeleteUser() throws Exception - { - final int initialNumberOfUsers = _userManagement.viewUsers().size(); - - testCreateUser(); - - boolean success = _userManagement.deleteUser(_testUserName); - assertTrue("Should have been able to delete new user " + _testUserName, success); - assertEquals("Unexpected number of users after delete", initialNumberOfUsers, _userManagement.viewUsers().size()); - assertFileDoesNotContainsPasswordForUser(_testUserName); - } - - public void testJmsLoginNotPossibleForDeletedUser() throws Exception - { - testDeleteUser(); - - assertJmsConnectionFails(_testUserName, TEST_PASSWORD); - } - - public void testSetPassword() throws Exception - { - testCreateUser(); - - _userManagement.setPassword(_testUserName, TEST_NEWPASSWORD); - - assertFileContainsPasswordForUser(_testUserName); - } - - public void testJmsLoginForPasswordChangedUser() throws Exception - { - testSetPassword(); - - assertJmsConnectionSucceeds(_testUserName, TEST_NEWPASSWORD); - assertJmsConnectionFails(_testUserName, TEST_PASSWORD); - } - - public void testReload() throws Exception - { - writePasswordFile(_passwordFile, JMXTestUtils.DEFAULT_USERID, JMXTestUtils.DEFAULT_PASSWORD, _testUserName, TEST_PASSWORD); - - assertJmsConnectionFails(_testUserName, TEST_PASSWORD); - - _userManagement.reloadData(); - - assertJmsConnectionSucceeds(_testUserName, TEST_PASSWORD); - } - - protected Passwd createPasswordEncodingUtility() - { - return new Passwd() - { - @Override - public String getOutput(String username, String password) - { - return username + ":" + password; - } - }; - } - - protected Class<? extends PrincipalDatabase> getPrincipalDatabaseImplClass() - { - return PlainPasswordFilePrincipalDatabase.class; - } - - private File createTemporaryPasswordFileWithJmxAdminUser() throws Exception - { - File passwordFile = File.createTempFile("passwd", "pwd"); - passwordFile.deleteOnExit(); - writePasswordFile(passwordFile, JMXTestUtils.DEFAULT_USERID, JMXTestUtils.DEFAULT_PASSWORD); - return passwordFile; - } - - private void writePasswordFile(File passwordFile, String... userNamePasswordPairs) throws Exception - { - FileWriter writer = null; - try - { - writer = new FileWriter(passwordFile); - for (int i = 0; i < userNamePasswordPairs.length; i=i+2) - { - String username = userNamePasswordPairs[i]; - String password = userNamePasswordPairs[i+1]; - writer.append(_passwd.getOutput(username, password) + "\n"); - } - } - finally - { - writer.close(); - } - } - - - private void assertFileContainsPasswordForUser(String username) throws IOException - { - assertTrue("Could not find password for user " + username + " within " + _passwordFile, passwordFileContainsUser(username)); - } - - private void assertFileDoesNotContainsPasswordForUser(String username) throws IOException - { - assertFalse("Could not find password for user " + username + " within " + _passwordFile, passwordFileContainsUser(username)); - } - - private boolean passwordFileContainsUser(String username) throws IOException - { - BufferedReader reader = null; - try - { - reader = new BufferedReader(new FileReader(_passwordFile)); - String line = reader.readLine(); - while(line != null) - { - if (line.startsWith(username)) - { - return true; - } - line = reader.readLine(); - } - - return false; - } - finally - { - reader.close(); - } - } - - private void assertJmsConnectionSucceeds(String username, String password) throws Exception - { - Connection connection = getConnection(username, password); - assertNotNull(connection); - } - - private void assertJmsConnectionFails(String username, String password) throws Exception - { - try - { - getConnection(username, password); - fail("Exception not thrown"); - } - catch (JMSException e) - { - // PASS - } - } -} |