diff options
| author | Robert Godfrey <rgodfrey@apache.org = rgodfrey = Robert Godfrey rgodfrey@apache.org@apache.org> | 2014-04-13 23:41:53 +0000 |
|---|---|---|
| committer | Robert Godfrey <rgodfrey@apache.org = rgodfrey = Robert Godfrey rgodfrey@apache.org@apache.org> | 2014-04-13 23:41:53 +0000 |
| commit | 981b8f5357355f842a523e4b50a1d5c711095a68 (patch) | |
| tree | 8b3f05d036802077af1ae280c3c357b39dc3a4f0 /qpid/java | |
| parent | 529183e95ce802787694ec7b5b72a50f2c895821 (diff) | |
| download | qpid-python-981b8f5357355f842a523e4b50a1d5c711095a68.tar.gz | |
QPID-5690 : [Java Broker] Improve mechanisms for validating and reacting to changes in configured object attribute values
git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1587123 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'qpid/java')
70 files changed, 4118 insertions, 3435 deletions
diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/Broker.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/Broker.java index d58e906b0a..038667249e 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/Broker.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/Broker.java @@ -46,6 +46,7 @@ import org.apache.qpid.server.logging.messages.BrokerMessages; import org.apache.qpid.server.model.ConfiguredObjectFactory; import org.apache.qpid.server.model.Model; import org.apache.qpid.server.model.SystemContext; +import org.apache.qpid.server.model.SystemContextImpl; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.registry.IApplicationRegistry; import org.apache.qpid.server.security.SecurityManager; @@ -136,7 +137,7 @@ public class Broker TaskExecutor taskExecutor = new TaskExecutor(); taskExecutor.start(); ConfiguredObjectFactory configuredObjectFactory = new ConfiguredObjectFactory(Model.getInstance()); - SystemContext systemContext = new SystemContext(taskExecutor, configuredObjectFactory, _eventLogger, logRecorder, options); + SystemContext systemContext = new SystemContextImpl(taskExecutor, configuredObjectFactory, _eventLogger, logRecorder, options); BrokerConfigurationStoreCreator storeCreator = new BrokerConfigurationStoreCreator(); DurableConfigurationStore store = storeCreator.createStore(systemContext, storeType, options.getInitialConfigurationLocation(), diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java index b94f73854b..933f2700bf 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/exchange/AbstractExchange.java @@ -27,6 +27,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; @@ -913,19 +914,14 @@ public abstract class AbstractExchange<T extends AbstractExchange<T>> @Override - protected void changeAttributes(Map<String, Object> attributes) + protected void validateChange(final ConfiguredObject<?> proxyForValidation, final Set<String> changedAttributes) { + super.validateChange(proxyForValidation, changedAttributes); throw new UnsupportedOperationException("Changing attributes on exchange is not supported."); } @Override - protected void authoriseSetAttribute(String name, Object expected, Object desired) throws AccessControlException - { - _virtualHost.getSecurityManager().authoriseUpdate(this); - } - - @Override - protected void authoriseSetAttributes(Map<String, Object> attributes) throws AccessControlException + protected void authoriseSetAttributes(ConfiguredObject<?> modified, Set<String> attributes) throws AccessControlException { _virtualHost.getSecurityManager().authoriseUpdate(this); } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/AbstractConfiguredObject.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/AbstractConfiguredObject.java index 12bd2dc7f8..9359429501 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/AbstractConfiguredObject.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/AbstractConfiguredObject.java @@ -21,8 +21,11 @@ package org.apache.qpid.server.model; import java.lang.reflect.Field; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.lang.reflect.Proxy; import java.security.AccessControlException; import java.security.AccessController; import java.security.PrivilegedAction; @@ -69,8 +72,8 @@ public abstract class AbstractConfiguredObject<X extends ConfiguredObject<X>> im private static final Map<Class<? extends ConfiguredObject>, Map<String, ConfiguredObjectAttribute<?,?>>> _allAttributeTypes = Collections.synchronizedMap(new HashMap<Class<? extends ConfiguredObject>, Map<String, ConfiguredObjectAttribute<?, ?>>>()); - private static final Map<Class<? extends ConfiguredObject>, Map<String, Field>> _allAutomatedFields = - Collections.synchronizedMap(new HashMap<Class<? extends ConfiguredObject>, Map<String, Field>>()); + private static final Map<Class<? extends ConfiguredObject>, Map<String, AutomatedField>> _allAutomatedFields = + Collections.synchronizedMap(new HashMap<Class<? extends ConfiguredObject>, Map<String, AutomatedField>>()); private static final Map<Class, Object> SECURE_VALUES; public static final String SECURED_STRING_VALUE = "********"; @@ -108,6 +111,9 @@ public abstract class AbstractConfiguredObject<X extends ConfiguredObject<X>> im private final TaskExecutor _taskExecutor; + private final Class<? extends ConfiguredObject> _category; + private final Class<? extends ConfiguredObject> _bestFitInterface; + @ManagedAttributeField private long _createdTime; @@ -127,7 +133,7 @@ public abstract class AbstractConfiguredObject<X extends ConfiguredObject<X>> im private Map<String,String> _context; private final Map<String, ConfiguredObjectAttribute<?,?>> _attributeTypes; - private final Map<String, Field> _automatedFields; + private final Map<String, AutomatedField> _automatedFields; @ManagedAttributeField private String _type; @@ -173,7 +179,11 @@ public abstract class AbstractConfiguredObject<X extends ConfiguredObject<X>> im _attributeTypes = getAttributeTypes(getClass()); _automatedFields = getAutomatedFields(getClass()); + + _category = Model.getCategory(getClass()); _type = Model.getType(getClass()); + _bestFitInterface = calculateBestFitInterface(); + if(attributes.get(TYPE) != null) { if(!_type.equals(attributes.get(TYPE))) @@ -239,7 +249,61 @@ public abstract class AbstractConfiguredObject<X extends ConfiguredObject<X>> im throw new IllegalArgumentException("Mandatory attribute " + attr.getName() + " not supplied for instance of " + getClass().getName()); } } + } + + private Class<? extends ConfiguredObject> calculateBestFitInterface() + { + Set<Class<? extends ConfiguredObject>> candidates = new HashSet<Class<? extends ConfiguredObject>>(); + findBestFitInterface(getClass(), candidates); + switch(candidates.size()) + { + case 0: + throw new ServerScopedRuntimeException("The configured object class " + getClass().getSimpleName() + " does not seem to implement an interface"); + case 1: + return candidates.iterator().next(); + default: + throw new ServerScopedRuntimeException("The configured object class " + getClass().getSimpleName() + " implements no single common interface which extends ConfiguredObject"); + } + } + + private static final void findBestFitInterface(Class<? extends ConfiguredObject> clazz, Set<Class<? extends ConfiguredObject>> candidates) + { + for(Class<?> interfaceClass : clazz.getInterfaces()) + { + if(ConfiguredObject.class.isAssignableFrom(interfaceClass)) + { + checkCandidate((Class<? extends ConfiguredObject>) interfaceClass, candidates); + } + } + if(clazz.getSuperclass() != null & ConfiguredObject.class.isAssignableFrom(clazz.getSuperclass())) + { + findBestFitInterface((Class<? extends ConfiguredObject>) clazz.getSuperclass(), candidates); + } + } + + private static void checkCandidate(final Class<? extends ConfiguredObject> interfaceClass, + final Set<Class<? extends ConfiguredObject>> candidates) + { + if(!candidates.contains(interfaceClass)) + { + Iterator<Class<? extends ConfiguredObject>> candidateIterator = candidates.iterator(); + while(candidateIterator.hasNext()) + { + Class<? extends ConfiguredObject> existingCandidate = candidateIterator.next(); + if(existingCandidate.isAssignableFrom(interfaceClass)) + { + candidateIterator.remove(); + } + else if(interfaceClass.isAssignableFrom(existingCandidate)) + { + return; + } + } + + candidates.add(interfaceClass); + + } } private void automatedSetValue(final String name, Object value) @@ -251,12 +315,27 @@ public abstract class AbstractConfiguredObject<X extends ConfiguredObject<X>> im { value = attribute.getAnnotation().defaultValue(); } - _automatedFields.get(name).set(this, attribute.convert(value, this)); + AutomatedField field = _automatedFields.get(name); + + if(field.getPreSettingAction() != null) + { + field.getPreSettingAction().invoke(this); + } + field.getField().set(this, attribute.convert(value, this)); + + if(field.getPostSettingAction() != null) + { + field.getPostSettingAction().invoke(this); + } } catch (IllegalAccessException e) { throw new ServerScopedRuntimeException("Unable to set the automated attribute " + name + " on the configure object type " + getClass().getName(),e); } + catch (InvocationTargetException e) + { + throw new ServerScopedRuntimeException("Unable to set the automated attribute " + name + " on the configure object type " + getClass().getName(),e); + } } public void open() @@ -406,7 +485,7 @@ public abstract class AbstractConfiguredObject<X extends ConfiguredObject<X>> im public Class<? extends ConfiguredObject> getCategoryClass() { - return Model.getCategory(getClass()); + return _category; } public Map<String,String> getContext() @@ -602,7 +681,9 @@ public abstract class AbstractConfiguredObject<X extends ConfiguredObject<X>> im { if (_taskExecutor.isTaskExecutorThread()) { - authoriseSetAttribute(name, expected, desired); + authoriseSetAttributes(createProxyForValidation(Collections.singletonMap(name, desired)), + Collections.singleton(name)); + if (changeAttribute(name, expected, desired)) { attributeSet(name, expected, desired); @@ -803,7 +884,7 @@ public abstract class AbstractConfiguredObject<X extends ConfiguredObject<X>> im { if (getTaskExecutor().isTaskExecutorThread()) { - authoriseSetAttributes(attributes); + authoriseSetAttributes(createProxyForValidation(attributes), attributes.keySet()); changeAttributes(attributes); } else @@ -812,9 +893,15 @@ public abstract class AbstractConfiguredObject<X extends ConfiguredObject<X>> im } } + protected void authoriseSetAttributes(final ConfiguredObject<?> proxyForValidation, + final Set<String> modifiedAttributes) + { + + } + protected void changeAttributes(final Map<String, Object> attributes) { - validateChangeAttributes(attributes); + validateChange(createProxyForValidation(attributes), attributes.keySet()); Collection<String> names = getAttributeNames(); for (String name : names) { @@ -830,25 +917,21 @@ public abstract class AbstractConfiguredObject<X extends ConfiguredObject<X>> im } } - protected void validateChangeAttributes(final Map<String, Object> attributes) + protected void validateChange(final ConfiguredObject<?> proxyForValidation, final Set<String> changedAttributes) { - if (attributes.containsKey(ID)) + if(!getId().equals(proxyForValidation.getId())) { - UUID id = getId(); - Object idAttributeValue = attributes.get(ID); - if (idAttributeValue != null && !(idAttributeValue.equals(id) || idAttributeValue.equals(id.toString()))) - { - throw new IllegalConfigurationException("Cannot change existing configured object id"); - } + throw new IllegalConfigurationException("Cannot change existing configured object id"); } } - protected void authoriseSetDesiredState(State currentState, State desiredState) throws AccessControlException + private ConfiguredObject<?> createProxyForValidation(final Map<String, Object> attributes) { - // allowed by default + return (ConfiguredObject<?>) Proxy.newProxyInstance(getClass().getClassLoader(),new Class<?>[]{_bestFitInterface}, + new AttributeGettingHandler(attributes)); } - protected void authoriseSetAttribute(String name, Object expected, Object desired) throws AccessControlException + protected void authoriseSetDesiredState(State currentState, State desiredState) throws AccessControlException { // allowed by default } @@ -858,11 +941,6 @@ public abstract class AbstractConfiguredObject<X extends ConfiguredObject<X>> im // allowed by default } - protected void authoriseSetAttributes(Map<String, Object> attributes) throws AccessControlException - { - // allowed by default - } - /** * Returns a map of effective attribute values that would result * if applying the supplied changes. Does not apply the changes. @@ -1071,6 +1149,34 @@ public abstract class AbstractConfiguredObject<X extends ConfiguredObject<X>> im } } + private static class AutomatedField + { + private final Field _field; + private final Method _preSettingAction; + private final Method _postSettingAction; + + private AutomatedField(final Field field, final Method preSettingAction, final Method postSettingAction) + { + _field = field; + _preSettingAction = preSettingAction; + _postSettingAction = postSettingAction; + } + + public Field getField() + { + return _field; + } + + public Method getPreSettingAction() + { + return _preSettingAction; + } + + public Method getPostSettingAction() + { + return _postSettingAction; + } + } private static <X extends ConfiguredObject> void processAttributes(final Class<X> clazz) { @@ -1149,6 +1255,10 @@ public abstract class AbstractConfiguredObject<X extends ConfiguredObject<X>> im ManagedAttribute annotation = m.getAnnotation(ManagedAttribute.class); if(annotation != null) { + if(!clazz.isInterface() || !ConfiguredObject.class.isAssignableFrom(clazz)) + { + throw new ServerScopedRuntimeException("Can only define ManagedAttributes on interfaces which extend " + ConfiguredObject.class.getSimpleName() + ". " + clazz.getSimpleName() + " does not meet these criteria."); + } addToAttributesSet(clazz, new ConfiguredObjectAttribute(clazz, m, annotation)); } else @@ -1156,13 +1266,17 @@ public abstract class AbstractConfiguredObject<X extends ConfiguredObject<X>> im ManagedStatistic statAnnotation = m.getAnnotation(ManagedStatistic.class); if(statAnnotation != null) { + if(!clazz.isInterface() || !ConfiguredObject.class.isAssignableFrom(clazz)) + { + throw new ServerScopedRuntimeException("Can only define ManagedStatistics on interfaces which extend " + ConfiguredObject.class.getSimpleName() + ". " + clazz.getSimpleName() + " does not meet these criteria."); + } addToStatisticsSet(clazz, new ConfiguredObjectStatistic(clazz,m)); } } } Map<String,ConfiguredObjectAttribute<?,?>> attrMap = new HashMap<String, ConfiguredObjectAttribute<?, ?>>(); - Map<String,Field> fieldMap = new HashMap<String, Field>(); + Map<String,AutomatedField> fieldMap = new HashMap<String, AutomatedField>(); Collection<ConfiguredObjectAttribute<?, ?>> attrCol = _allAttributes.get(clazz); @@ -1204,17 +1318,46 @@ public abstract class AbstractConfiguredObject<X extends ConfiguredObject<X>> im } } - private static Field findField(final ConfiguredObjectAttribute<?, ?> attr, Class<?> objClass) + private static AutomatedField findField(final ConfiguredObjectAttribute<?, ?> attr, Class<?> objClass) { Class<?> clazz = objClass; while(clazz != null) { for(Field field : clazz.getDeclaredFields()) { - if(field.getAnnotation(ManagedAttributeField.class) != null && field.getName().equals("_" + attr.getName().replace('.','_'))) + if(field.isAnnotationPresent(ManagedAttributeField.class) && field.getName().equals("_" + attr.getName().replace('.','_'))) { - field.setAccessible(true); - return field; + try + { + ManagedAttributeField annotation = field.getAnnotation(ManagedAttributeField.class); + field.setAccessible(true); + Method beforeSet; + if (!"".equals(annotation.beforeSet())) + { + beforeSet = clazz.getDeclaredMethod(annotation.beforeSet()); + beforeSet.setAccessible(true); + } + else + { + beforeSet = null; + } + Method afterSet; + if (!"".equals(annotation.afterSet())) + { + afterSet = clazz.getDeclaredMethod(annotation.afterSet()); + afterSet.setAccessible(true); + } + else + { + afterSet = null; + } + return new AutomatedField(field, beforeSet, afterSet); + } + catch (NoSuchMethodException e) + { + throw new ServerScopedRuntimeException("Cannot find method referenced by annotation for pre/post setting action", e); + } + } } clazz = clazz.getSuperclass(); @@ -1298,7 +1441,7 @@ public abstract class AbstractConfiguredObject<X extends ConfiguredObject<X>> im return _allAttributeTypes.get(clazz); } - private static Map<String, Field> getAutomatedFields(Class<? extends ConfiguredObject> clazz) + private static Map<String, AutomatedField> getAutomatedFields(Class<? extends ConfiguredObject> clazz) { if(!_allAutomatedFields.containsKey(clazz)) { @@ -1426,4 +1569,66 @@ public abstract class AbstractConfiguredObject<X extends ConfiguredObject<X>> im } + private class AttributeGettingHandler implements InvocationHandler + { + private Map<String,Object> _attributes; + + AttributeGettingHandler(final Map<String, Object> modifiedAttributes) + { + Map<String,Object> combinedAttributes = new HashMap<String, Object>(getActualAttributes()); + combinedAttributes.putAll(modifiedAttributes); + _attributes = combinedAttributes; + } + + @Override + public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable + { + + if(method.isAnnotationPresent(ManagedAttribute.class)) + { + ConfiguredObjectAttribute attribute = getAttributeFromMethod(method); + return getValue(attribute); + } + else if(method.getName().equals("getAttribute") && args != null && args.length == 1 && args[0] instanceof String) + { + ConfiguredObjectAttribute attribute = _attributeTypes.get((String)args[0]); + if(attribute != null) + { + return getValue(attribute); + } + else + { + return null; + } + } + throw new UnsupportedOperationException("This class is only intended for value validation, and only getters on managed attributes are permitted."); + } + + protected Object getValue(final ConfiguredObjectAttribute attribute) + { + ManagedAttribute annotation = attribute.getAnnotation(); + if(annotation.automate()) + { + Object value = _attributes.get(attribute.getName()); + return attribute.convert(value == null && !"".equals(annotation.defaultValue()) ? annotation.defaultValue() : value , AbstractConfiguredObject.this); + } + else + { + return _attributes.get(attribute.getName()); + } + } + + private ConfiguredObjectAttribute getAttributeFromMethod(final Method method) + { + for(ConfiguredObjectAttribute attribute : _attributeTypes.values()) + { + if(attribute.getGetter().getName().equals(method.getName()) + && !Modifier.isStatic(method.getModifiers())) + { + return attribute; + } + } + throw new ServerScopedRuntimeException("Unable to find attribute definition for method " + method.getName()); + } + } } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/AuthenticationProvider.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/AuthenticationProvider.java index 8f40ca4060..4c8b5bd083 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/AuthenticationProvider.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/AuthenticationProvider.java @@ -20,9 +20,14 @@ */ package org.apache.qpid.server.model; +import java.security.Principal; import java.util.Collection; +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; + import org.apache.qpid.server.security.SubjectCreator; +import org.apache.qpid.server.security.auth.AuthenticationResult; @ManagedObject( creatable = false ) public interface AuthenticationProvider<X extends AuthenticationProvider<X>> extends ConfiguredObject<X> @@ -55,4 +60,44 @@ public interface AuthenticationProvider<X extends AuthenticationProvider<X>> ext void setPreferencesProvider(PreferencesProvider preferencesProvider); void recoverUser(User user); + + /** + * Gets the SASL mechanisms known to this manager. + * + * @return SASL mechanism names, space separated. + */ + String getMechanisms(); + + /** + * Creates a SASL server for the specified mechanism name for the given + * fully qualified domain name. + * + * @param mechanism mechanism name + * @param localFQDN domain name + * @param externalPrincipal externally authenticated Principal + * @return SASL server + * @throws javax.security.sasl.SaslException + */ + SaslServer createSaslServer(String mechanism, String localFQDN, Principal externalPrincipal) throws SaslException; + + /** + * Authenticates a user using SASL negotiation. + * + * @param server SASL server + * @param response SASL response to process + * + * @return authentication result + */ + AuthenticationResult authenticate(SaslServer server, byte[] response); + + /** + * Authenticates a user using their username and password. + * + * @param username username + * @param password password + * + * @return authentication result + */ + AuthenticationResult authenticate(String username, String password); + } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Broker.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Broker.java index 5700f20356..aabcc5844e 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Broker.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Broker.java @@ -32,7 +32,7 @@ import org.apache.qpid.server.security.SubjectCreator; import org.apache.qpid.server.stats.StatisticsGatherer; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; -@ManagedObject( defaultType = "adapter" ) +@ManagedObject( defaultType = "broker" ) public interface Broker<X extends Broker<X>> extends ConfiguredObject<X>, EventLoggerProvider, StatisticsGatherer { diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ExternalFileBasedAuthenticationManager.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ExternalFileBasedAuthenticationManager.java new file mode 100644 index 0000000000..54d69fe516 --- /dev/null +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ExternalFileBasedAuthenticationManager.java @@ -0,0 +1,27 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.model; + +public interface ExternalFileBasedAuthenticationManager<X extends ExternalFileBasedAuthenticationManager<X>> extends PasswordCredentialManagingAuthenticationProvider<X> +{ + @ManagedAttribute( automate = true , mandatory = true ) + public String getPath(); +} diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ManagedAttributeField.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ManagedAttributeField.java index c9b2f44b18..89cf32f252 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ManagedAttributeField.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/ManagedAttributeField.java @@ -27,4 +27,6 @@ import java.lang.annotation.RetentionPolicy; @Retention(RetentionPolicy.RUNTIME) public @interface ManagedAttributeField { + String beforeSet() default ""; + String afterSet() default ""; } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Model.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Model.java index 36049950e7..39f26887a6 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Model.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/Model.java @@ -74,21 +74,40 @@ public abstract class Model public static String getType(final Class<? extends ConfiguredObject> clazz) { - ManagedObject annotation = clazz.getAnnotation(ManagedObject.class); - if(annotation != null) + String type = getActualType(clazz); + + if("".equals(type)) { - if(!"".equals(annotation.type())) + Class<? extends ConfiguredObject> category = getCategory(clazz); + if (category == null) { - return annotation.type(); + throw new IllegalArgumentException("No category for " + clazz.getSimpleName()); + } + ManagedObject annotation = category.getAnnotation(ManagedObject.class); + if (annotation == null) + { + throw new NullPointerException("No definition found for category " + category.getSimpleName()); + } + if (!"".equals(annotation.defaultType())) + { + type = annotation.defaultType(); + } + else + { + type = category.getSimpleName(); } } + return type; + } - if(clazz.getSuperclass() != null && ConfiguredObject.class.isAssignableFrom(clazz.getSuperclass())) + private static String getActualType(final Class<? extends ConfiguredObject> clazz) + { + ManagedObject annotation = clazz.getAnnotation(ManagedObject.class); + if(annotation != null) { - String type = getType((Class<? extends ConfiguredObject>) clazz.getSuperclass()); - if(!"".equals(type)) + if(!"".equals(annotation.type())) { - return type; + return annotation.type(); } } @@ -96,34 +115,30 @@ public abstract class Model { if(ConfiguredObject.class.isAssignableFrom(iface)) { - String type = getType((Class<? extends ConfiguredObject>) iface); + String type = getActualType((Class<? extends ConfiguredObject>) iface); if(!"".equals(type)) { return type; } } } - Class<? extends ConfiguredObject> category = getCategory(clazz); - if(category == null) - { - return ""; - } - annotation = category.getAnnotation(ManagedObject.class); - if(annotation == null) - { - throw new NullPointerException("No definition found for category " + category.getSimpleName()); - } - if(!"".equals(annotation.defaultType())) + + if(clazz.getSuperclass() != null && ConfiguredObject.class.isAssignableFrom(clazz.getSuperclass())) { - return annotation.defaultType(); + String type = getActualType((Class<? extends ConfiguredObject>) clazz.getSuperclass()); + if(!"".equals(type)) + { + return type; + } } - return category.getSimpleName(); + + return ""; } public abstract Collection<Class<? extends ConfiguredObject>> getSupportedCategories(); public abstract Collection<Class<? extends ConfiguredObject>> getChildTypes(Class<? extends ConfiguredObject> parent); - public abstract Class<? extends ConfiguredObject<?>> getRootCategory(); + public abstract Class<? extends ConfiguredObject> getRootCategory(); public abstract Collection<Class<? extends ConfiguredObject>> getParentTypes(Class<? extends ConfiguredObject> child); public abstract int getMajorVersion(); @@ -141,11 +156,11 @@ public abstract class Model private final Set<Class<? extends ConfiguredObject>> _supportedTypes = new HashSet<Class<? extends ConfiguredObject>>(); - private final Class<? extends ConfiguredObject<?>> _rootCategory; + private Class<? extends ConfiguredObject> _rootCategory; private ModelImpl() { - _rootCategory = SystemContext.class; + setRootCategory(SystemContext.class); addRelationship(SystemContext.class, Broker.class); @@ -186,7 +201,7 @@ public abstract class Model } @Override - public Class<? extends ConfiguredObject<?>> getRootCategory() + public Class<? extends ConfiguredObject> getRootCategory() { return _rootCategory; } @@ -223,6 +238,11 @@ public abstract class Model return Collections.unmodifiableSet(_supportedTypes); } + public void setRootCategory(final Class<? extends ConfiguredObject> rootCategory) + { + _rootCategory = rootCategory; + } + private void addRelationship(Class<? extends ConfiguredObject> parent, Class<? extends ConfiguredObject> child) { Collection<Class<? extends ConfiguredObject>> parents = _parents.get(child); diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/SystemContext.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/SystemContext.java index dda65d2b3e..6e0f331d5e 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/SystemContext.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/SystemContext.java @@ -20,307 +20,34 @@ */ package org.apache.qpid.server.model; -import java.security.AccessControlException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.UUID; - import org.apache.qpid.server.BrokerOptions; -import org.apache.qpid.server.configuration.IllegalConfigurationException; import org.apache.qpid.server.configuration.updater.TaskExecutor; import org.apache.qpid.server.logging.EventLogger; import org.apache.qpid.server.logging.LogRecorder; -import org.apache.qpid.server.logging.messages.BrokerMessages; -import org.apache.qpid.server.store.ConfiguredObjectDependency; -import org.apache.qpid.server.store.ConfiguredObjectIdDependency; -import org.apache.qpid.server.store.ConfiguredObjectNameDependency; import org.apache.qpid.server.store.ConfiguredObjectRecord; -import org.apache.qpid.server.store.UnresolvedConfiguredObject; -import org.apache.qpid.server.util.ServerScopedRuntimeException; @ManagedObject (creatable = false) -public class SystemContext extends AbstractConfiguredObject<SystemContext> +public interface SystemContext<X extends SystemContext<X>> extends ConfiguredObject<X> { - private static final UUID SYSTEM_ID = new UUID(0l, 0l); - private final ConfiguredObjectFactory _objectFactory; - private final EventLogger _eventLogger; - private final LogRecorder _logRecorder; - private final BrokerOptions _brokerOptions; - - @ManagedAttributeField - private String _storePath; - - @ManagedAttributeField - private String _storeType; - - public SystemContext(final TaskExecutor taskExecutor, - final ConfiguredObjectFactory configuredObjectFactory, - final EventLogger eventLogger, - final LogRecorder logRecorder, - final BrokerOptions brokerOptions) - { - super(parentsMap(), - combineIdWithAttributes(SYSTEM_ID, createAttributes(brokerOptions)), - taskExecutor); - _eventLogger = eventLogger; - getTaskExecutor().start(); - _objectFactory = configuredObjectFactory; - _logRecorder = logRecorder; - _brokerOptions = brokerOptions; - open(); - } - - public static Map<String, Object> createAttributes(final BrokerOptions brokerOptions) - { - Map<String,Object> attributes = new HashMap<String, Object>(); - attributes.put(NAME, "System"); - attributes.put("storePath", brokerOptions.getConfigurationStoreLocation()); - attributes.put("storeTye", brokerOptions.getConfigurationStoreType()); - attributes.put(ConfiguredObject.CONTEXT, brokerOptions.getConfigProperties()); - return attributes; - } - - public void resolveObjects(ConfiguredObjectRecord... records) - { - - ConfiguredObjectFactory factory = getObjectFactory(); - - Map<UUID, ConfiguredObject<?>> resolvedObjects = new HashMap<UUID, ConfiguredObject<?>>(); - resolvedObjects.put(getId(), this); - - Collection<ConfiguredObjectRecord> recordsWithUnresolvedParents = new ArrayList<ConfiguredObjectRecord>(Arrays.asList(records)); - Collection<UnresolvedConfiguredObject<? extends ConfiguredObject>> recordsWithUnresolvedDependencies = - new ArrayList<UnresolvedConfiguredObject<? extends ConfiguredObject>>(); - - boolean updatesMade; - - do - { - updatesMade = false; - Iterator<ConfiguredObjectRecord> iter = recordsWithUnresolvedParents.iterator(); - while (iter.hasNext()) - { - ConfiguredObjectRecord record = iter.next(); - Collection<ConfiguredObject<?>> parents = new ArrayList<ConfiguredObject<?>>(); - boolean foundParents = true; - for (ConfiguredObjectRecord parent : record.getParents().values()) - { - if (!resolvedObjects.containsKey(parent.getId())) - { - foundParents = false; - break; - } - else - { - parents.add(resolvedObjects.get(parent.getId())); - } - } - if (foundParents) - { - iter.remove(); - UnresolvedConfiguredObject<? extends ConfiguredObject> recovered = - factory.recover(record, parents.toArray(new ConfiguredObject<?>[parents.size()])); - Collection<ConfiguredObjectDependency<?>> dependencies = - recovered.getUnresolvedDependencies(); - if (dependencies.isEmpty()) - { - updatesMade = true; - ConfiguredObject<?> resolved = recovered.resolve(); - resolvedObjects.put(resolved.getId(), resolved); - } - else - { - recordsWithUnresolvedDependencies.add(recovered); - } - } - - } - - Iterator<UnresolvedConfiguredObject<? extends ConfiguredObject>> unresolvedIter = - recordsWithUnresolvedDependencies.iterator(); - - while(unresolvedIter.hasNext()) - { - UnresolvedConfiguredObject<? extends ConfiguredObject> unresolvedObject = unresolvedIter.next(); - Collection<ConfiguredObjectDependency<?>> dependencies = - new ArrayList<ConfiguredObjectDependency<?>>(unresolvedObject.getUnresolvedDependencies()); - - for(ConfiguredObjectDependency dependency : dependencies) - { - if(dependency instanceof ConfiguredObjectIdDependency) - { - UUID id = ((ConfiguredObjectIdDependency)dependency).getId(); - if(resolvedObjects.containsKey(id)) - { - dependency.resolve(resolvedObjects.get(id)); - } - } - else if(dependency instanceof ConfiguredObjectNameDependency) - { - ConfiguredObject<?> dependentObject = null; - for(ConfiguredObject<?> parent : unresolvedObject.getParents()) - { - dependentObject = parent.findConfiguredObject(dependency.getCategoryClass(), ((ConfiguredObjectNameDependency)dependency).getName()); - if(dependentObject != null) - { - break; - } - } - if(dependentObject != null) - { - dependency.resolve(dependentObject); - } - } - else - { - throw new ServerScopedRuntimeException("Unknown dependency type " + dependency.getClass().getSimpleName()); - } - } - if(unresolvedObject.getUnresolvedDependencies().isEmpty()) - { - updatesMade = true; - unresolvedIter.remove(); - ConfiguredObject<?> resolved = unresolvedObject.resolve(); - resolvedObjects.put(resolved.getId(), resolved); - } - } + void resolveObjects(ConfiguredObjectRecord... records); - } while(updatesMade && !(recordsWithUnresolvedDependencies.isEmpty() && recordsWithUnresolvedParents.isEmpty())); + ConfiguredObjectFactory getObjectFactory(); - if(!recordsWithUnresolvedDependencies.isEmpty()) - { - throw new IllegalArgumentException("Cannot resolve some objects: " + recordsWithUnresolvedDependencies); - } - if(!recordsWithUnresolvedParents.isEmpty()) - { - throw new IllegalArgumentException("Cannot resolve object because their parents cannot be found" + recordsWithUnresolvedParents); - } - } + EventLogger getEventLogger(); - @Override - protected boolean setState(final State currentState, final State desiredState) - { - throw new IllegalArgumentException("Cannot change the state of the SystemContext object"); - } - - @Override - public String setName(final String currentName, final String desiredName) - throws IllegalStateException, AccessControlException - { - return null; - } - - @Override - public State getState() - { - return State.ACTIVE; - } - - @Override - public boolean isDurable() - { - return true; - } - - @Override - public void setDurable(final boolean durable) - throws IllegalStateException, AccessControlException, IllegalArgumentException - { - throw new IllegalArgumentException("Cannot change the durability of the SystemContext object"); - } - - @Override - public LifetimePolicy getLifetimePolicy() - { - return LifetimePolicy.PERMANENT; - } - - @Override - public LifetimePolicy setLifetimePolicy(final LifetimePolicy expected, final LifetimePolicy desired) - throws IllegalStateException, AccessControlException, IllegalArgumentException - { - throw new IllegalArgumentException("Cannot change the lifetime of the SystemContext object"); - } - - public ConfiguredObjectFactory getObjectFactory() - { - return _objectFactory; - } - - public EventLogger getEventLogger() - { - return _eventLogger; - } - - public LogRecorder getLogRecorder() - { - return _logRecorder; - } - - public BrokerOptions getBrokerOptions() - { - return _brokerOptions; - } + BrokerOptions getBrokerOptions(); @ManagedAttribute( automate = true ) - public String getStorePath() - { - return _storePath; - } + String getStorePath(); @ManagedAttribute( automate = true ) - public String getStoreType() - { - return _storeType; - } - - public void close() - { - try - { - - - if (getTaskExecutor() != null) - { - getTaskExecutor().stop(); - } - - _eventLogger.message(BrokerMessages.STOPPED()); - - _logRecorder.closeLogRecorder(); + String getStoreType(); - } - finally - { - if (getTaskExecutor() != null) - { - getTaskExecutor().stopImmediately(); - } - } + void close(); - } + Broker getBroker(); - @Override - public Collection<String> getAttributeNames() - { - return getAttributeNames(getClass()); - } + TaskExecutor getTaskExecutor(); - public Broker getBroker() - { - Collection<Broker> children = getChildren(Broker.class); - if(children == null || children.isEmpty()) - { - return null; - } - else if(children.size() != 1) - { - throw new IllegalConfigurationException("More than one broker has been registered in a single context"); - } - return children.iterator().next(); - } + LogRecorder getLogRecorder(); } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/SystemContextImpl.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/SystemContextImpl.java new file mode 100644 index 0000000000..b4af364634 --- /dev/null +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/SystemContextImpl.java @@ -0,0 +1,331 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.model; + +import java.security.AccessControlException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.UUID; + +import org.apache.qpid.server.BrokerOptions; +import org.apache.qpid.server.configuration.IllegalConfigurationException; +import org.apache.qpid.server.configuration.updater.TaskExecutor; +import org.apache.qpid.server.logging.EventLogger; +import org.apache.qpid.server.logging.LogRecorder; +import org.apache.qpid.server.logging.messages.BrokerMessages; +import org.apache.qpid.server.store.ConfiguredObjectDependency; +import org.apache.qpid.server.store.ConfiguredObjectIdDependency; +import org.apache.qpid.server.store.ConfiguredObjectNameDependency; +import org.apache.qpid.server.store.ConfiguredObjectRecord; +import org.apache.qpid.server.store.UnresolvedConfiguredObject; +import org.apache.qpid.server.util.ServerScopedRuntimeException; + +public class SystemContextImpl extends AbstractConfiguredObject<SystemContextImpl> implements SystemContext<SystemContextImpl> +{ + private static final UUID SYSTEM_ID = new UUID(0l, 0l); + private final ConfiguredObjectFactory _objectFactory; + private final EventLogger _eventLogger; + private final LogRecorder _logRecorder; + private final BrokerOptions _brokerOptions; + + @ManagedAttributeField + private String _storePath; + + @ManagedAttributeField + private String _storeType; + + public SystemContextImpl(final TaskExecutor taskExecutor, + final ConfiguredObjectFactory configuredObjectFactory, + final EventLogger eventLogger, + final LogRecorder logRecorder, + final BrokerOptions brokerOptions) + { + super(parentsMap(), + combineIdWithAttributes(SYSTEM_ID, createAttributes(brokerOptions)), + taskExecutor); + _eventLogger = eventLogger; + getTaskExecutor().start(); + _objectFactory = configuredObjectFactory; + _logRecorder = logRecorder; + _brokerOptions = brokerOptions; + open(); + } + + public static Map<String, Object> createAttributes(final BrokerOptions brokerOptions) + { + Map<String,Object> attributes = new HashMap<String, Object>(); + attributes.put(NAME, "System"); + attributes.put("storePath", brokerOptions.getConfigurationStoreLocation()); + attributes.put("storeTye", brokerOptions.getConfigurationStoreType()); + attributes.put(ConfiguredObject.CONTEXT, brokerOptions.getConfigProperties()); + return attributes; + } + + @Override + public void resolveObjects(ConfiguredObjectRecord... records) + { + + ConfiguredObjectFactory factory = getObjectFactory(); + + Map<UUID, ConfiguredObject<?>> resolvedObjects = new HashMap<UUID, ConfiguredObject<?>>(); + resolvedObjects.put(getId(), this); + + Collection<ConfiguredObjectRecord> recordsWithUnresolvedParents = new ArrayList<ConfiguredObjectRecord>(Arrays.asList(records)); + Collection<UnresolvedConfiguredObject<? extends ConfiguredObject>> recordsWithUnresolvedDependencies = + new ArrayList<UnresolvedConfiguredObject<? extends ConfiguredObject>>(); + + boolean updatesMade; + + do + { + updatesMade = false; + Iterator<ConfiguredObjectRecord> iter = recordsWithUnresolvedParents.iterator(); + while (iter.hasNext()) + { + ConfiguredObjectRecord record = iter.next(); + Collection<ConfiguredObject<?>> parents = new ArrayList<ConfiguredObject<?>>(); + boolean foundParents = true; + for (ConfiguredObjectRecord parent : record.getParents().values()) + { + if (!resolvedObjects.containsKey(parent.getId())) + { + foundParents = false; + break; + } + else + { + parents.add(resolvedObjects.get(parent.getId())); + } + } + if (foundParents) + { + iter.remove(); + UnresolvedConfiguredObject<? extends ConfiguredObject> recovered = + factory.recover(record, parents.toArray(new ConfiguredObject<?>[parents.size()])); + Collection<ConfiguredObjectDependency<?>> dependencies = + recovered.getUnresolvedDependencies(); + if (dependencies.isEmpty()) + { + updatesMade = true; + ConfiguredObject<?> resolved = recovered.resolve(); + resolvedObjects.put(resolved.getId(), resolved); + } + else + { + recordsWithUnresolvedDependencies.add(recovered); + } + } + + } + + Iterator<UnresolvedConfiguredObject<? extends ConfiguredObject>> unresolvedIter = + recordsWithUnresolvedDependencies.iterator(); + + while(unresolvedIter.hasNext()) + { + UnresolvedConfiguredObject<? extends ConfiguredObject> unresolvedObject = unresolvedIter.next(); + Collection<ConfiguredObjectDependency<?>> dependencies = + new ArrayList<ConfiguredObjectDependency<?>>(unresolvedObject.getUnresolvedDependencies()); + + for(ConfiguredObjectDependency dependency : dependencies) + { + if(dependency instanceof ConfiguredObjectIdDependency) + { + UUID id = ((ConfiguredObjectIdDependency)dependency).getId(); + if(resolvedObjects.containsKey(id)) + { + dependency.resolve(resolvedObjects.get(id)); + } + } + else if(dependency instanceof ConfiguredObjectNameDependency) + { + ConfiguredObject<?> dependentObject = null; + for(ConfiguredObject<?> parent : unresolvedObject.getParents()) + { + dependentObject = parent.findConfiguredObject(dependency.getCategoryClass(), ((ConfiguredObjectNameDependency)dependency).getName()); + if(dependentObject != null) + { + break; + } + } + if(dependentObject != null) + { + dependency.resolve(dependentObject); + } + } + else + { + throw new ServerScopedRuntimeException("Unknown dependency type " + dependency.getClass().getSimpleName()); + } + } + if(unresolvedObject.getUnresolvedDependencies().isEmpty()) + { + updatesMade = true; + unresolvedIter.remove(); + ConfiguredObject<?> resolved = unresolvedObject.resolve(); + resolvedObjects.put(resolved.getId(), resolved); + } + } + + } while(updatesMade && !(recordsWithUnresolvedDependencies.isEmpty() && recordsWithUnresolvedParents.isEmpty())); + + if(!recordsWithUnresolvedDependencies.isEmpty()) + { + throw new IllegalArgumentException("Cannot resolve some objects: " + recordsWithUnresolvedDependencies); + } + if(!recordsWithUnresolvedParents.isEmpty()) + { + throw new IllegalArgumentException("Cannot resolve object because their parents cannot be found" + recordsWithUnresolvedParents); + } + } + + @Override + protected boolean setState(final State currentState, final State desiredState) + { + throw new IllegalArgumentException("Cannot change the state of the SystemContext object"); + } + + @Override + public String setName(final String currentName, final String desiredName) + throws IllegalStateException, AccessControlException + { + return null; + } + + @Override + public State getState() + { + return State.ACTIVE; + } + + @Override + public boolean isDurable() + { + return true; + } + + @Override + public void setDurable(final boolean durable) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + throw new IllegalArgumentException("Cannot change the durability of the SystemContext object"); + } + + @Override + public LifetimePolicy getLifetimePolicy() + { + return LifetimePolicy.PERMANENT; + } + + @Override + public LifetimePolicy setLifetimePolicy(final LifetimePolicy expected, final LifetimePolicy desired) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + throw new IllegalArgumentException("Cannot change the lifetime of the SystemContext object"); + } + + @Override + public ConfiguredObjectFactory getObjectFactory() + { + return _objectFactory; + } + + @Override + public EventLogger getEventLogger() + { + return _eventLogger; + } + + public LogRecorder getLogRecorder() + { + return _logRecorder; + } + + @Override + public BrokerOptions getBrokerOptions() + { + return _brokerOptions; + } + + @Override + public String getStorePath() + { + return _storePath; + } + + @Override + public String getStoreType() + { + return _storeType; + } + + @Override + public void close() + { + try + { + + + if (getTaskExecutor() != null) + { + getTaskExecutor().stop(); + } + + _eventLogger.message(BrokerMessages.STOPPED()); + + _logRecorder.closeLogRecorder(); + + } + finally + { + if (getTaskExecutor() != null) + { + getTaskExecutor().stopImmediately(); + } + } + + } + + @Override + public Collection<String> getAttributeNames() + { + return getAttributeNames(getClass()); + } + + @Override + public Broker getBroker() + { + Collection<Broker> children = getChildren(Broker.class); + if(children == null || children.isEmpty()) + { + return null; + } + else if(children.size() != 1) + { + throw new IllegalConfigurationException("More than one broker has been registered in a single context"); + } + return children.iterator().next(); + } +} diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/AbstractPluginAdapter.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/AbstractPluginAdapter.java index 4502a7e53f..1143ae0a4a 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/AbstractPluginAdapter.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/AbstractPluginAdapter.java @@ -24,6 +24,7 @@ import java.security.AccessControlException; import java.util.Collection; import java.util.Collections; import java.util.Map; +import java.util.Set; import java.util.UUID; import org.apache.qpid.server.model.AbstractConfiguredObject; @@ -130,16 +131,7 @@ public abstract class AbstractPluginAdapter<X extends Plugin<X>> extends Abstrac } @Override - protected void authoriseSetAttribute(String name, Object expected, Object desired) throws AccessControlException - { - if (!_broker.getSecurityManager().authoriseConfiguringBroker(getName(), Plugin.class, Operation.UPDATE)) - { - throw new AccessControlException("Setting of plugin attribute is denied"); - } - } - - @Override - protected void authoriseSetAttributes(Map<String, Object> attributes) throws AccessControlException + protected void authoriseSetAttributes(ConfiguredObject<?> modified, Set<String> attributes) throws AccessControlException { if (!_broker.getSecurityManager().authoriseConfiguringBroker(getName(), Plugin.class, Operation.UPDATE)) { diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapter.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapter.java index d8ad780be0..fb00ee7fb3 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapter.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapter.java @@ -30,6 +30,7 @@ import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.Set; import java.util.Timer; import java.util.TimerTask; import java.util.UUID; @@ -48,8 +49,8 @@ import org.apache.qpid.server.logging.LogRecorder; import org.apache.qpid.server.logging.messages.BrokerMessages; import org.apache.qpid.server.logging.messages.VirtualHostMessages; import org.apache.qpid.server.model.*; +import org.apache.qpid.server.model.port.AbstractPortWithAuthProvider; import org.apache.qpid.server.model.port.AmqpPort; -import org.apache.qpid.server.model.port.PortWithAuthProvider; import org.apache.qpid.server.plugin.ConfiguredObjectTypeFactory; import org.apache.qpid.server.plugin.MessageStoreFactory; import org.apache.qpid.server.security.SecurityManager; @@ -63,7 +64,6 @@ import org.apache.qpid.server.virtualhost.VirtualHostImpl; import org.apache.qpid.server.virtualhost.VirtualHostRegistry; import org.apache.qpid.util.SystemUtils; -@ManagedObject(category = false, type = "adapter") public class BrokerAdapter extends AbstractConfiguredObject<BrokerAdapter> implements Broker<BrokerAdapter>, ConfigurationChangeListener, StatisticsGatherer, StatisticsGatherer.Source { private static final Logger LOGGER = Logger.getLogger(BrokerAdapter.class); @@ -1136,9 +1136,9 @@ public class BrokerAdapter extends AbstractConfiguredObject<BrokerAdapter> imple Collection<Port<?>> ports = getPorts(); for (Port<?> p : ports) { - if (p instanceof PortWithAuthProvider && inetSocketAddress.getPort() == p.getPort()) + if (p instanceof AbstractPortWithAuthProvider && inetSocketAddress.getPort() == p.getPort()) { - provider = ((PortWithAuthProvider<?>) p).getAuthenticationProvider(); + provider = ((AbstractPortWithAuthProvider<?>) p).getAuthenticationProvider(); break; } } @@ -1214,15 +1214,6 @@ public class BrokerAdapter extends AbstractConfiguredObject<BrokerAdapter> imple } @Override - protected void authoriseSetAttribute(String name, Object expected, Object desired) throws AccessControlException - { - if (!_securityManager.authoriseConfiguringBroker(getName(), Broker.class, Operation.UPDATE)) - { - throw new AccessControlException("Setting of broker attributes is denied"); - } - } - - @Override protected <C extends ConfiguredObject> void authoriseCreateChild(Class<C> childClass, Map<String, Object> attributes, ConfiguredObject... otherParents) throws AccessControlException { @@ -1233,7 +1224,7 @@ public class BrokerAdapter extends AbstractConfiguredObject<BrokerAdapter> imple } @Override - protected void authoriseSetAttributes(Map<String, Object> attributes) throws AccessControlException + protected void authoriseSetAttributes(ConfiguredObject<?> modified, Set<String> attributes) throws AccessControlException { if (!_securityManager.authoriseConfiguringBroker(getName(), Broker.class, Operation.UPDATE)) { diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapterFactory.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapterFactory.java index 8bbe446dc3..ca28aa1a68 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapterFactory.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/BrokerAdapterFactory.java @@ -20,14 +20,14 @@ */ package org.apache.qpid.server.model.adapter; -import org.apache.qpid.server.model.AbstractConfiguredObjectTypeFactory; -import org.apache.qpid.server.model.ConfiguredObject; -import org.apache.qpid.server.model.SystemContext; - import java.util.HashMap; import java.util.Map; import java.util.UUID; +import org.apache.qpid.server.model.AbstractConfiguredObjectTypeFactory; +import org.apache.qpid.server.model.ConfiguredObject; +import org.apache.qpid.server.model.SystemContext; + public class BrokerAdapterFactory extends AbstractConfiguredObjectTypeFactory<BrokerAdapter> { public BrokerAdapterFactory() diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/FileBasedGroupProvider.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/FileBasedGroupProvider.java index 3578fba7a4..5dc47f04aa 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/FileBasedGroupProvider.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/FileBasedGroupProvider.java @@ -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 @@ -19,584 +20,13 @@ */ package org.apache.qpid.server.model.adapter; -import java.io.File; -import java.io.IOException; -import java.security.AccessControlException; -import java.security.Principal; -import java.util.*; -import java.util.concurrent.atomic.AtomicReference; - -import org.apache.log4j.Logger; -import org.apache.qpid.server.configuration.IllegalConfigurationException; -import org.apache.qpid.server.model.*; -import org.apache.qpid.server.configuration.updater.TaskExecutor; -import org.apache.qpid.server.security.access.Operation; -import org.apache.qpid.server.security.group.FileGroupManager; -import org.apache.qpid.server.security.group.GroupManager; -import org.apache.qpid.server.security.SecurityManager; -import org.apache.qpid.server.util.MapValueConverter; +import org.apache.qpid.server.model.GroupProvider; +import org.apache.qpid.server.model.ManagedAttribute; +import org.apache.qpid.server.model.ManagedObject; @ManagedObject( category = false, type = "GroupFile" ) -public class FileBasedGroupProvider - extends AbstractConfiguredObject<FileBasedGroupProvider> implements GroupProvider<FileBasedGroupProvider> +public interface FileBasedGroupProvider<X extends FileBasedGroupProvider<X>> extends GroupProvider<X> { - private static Logger LOGGER = Logger.getLogger(FileBasedGroupProvider.class); - - private GroupManager _groupManager; - private final Broker<?> _broker; - private AtomicReference<State> _state; - - @ManagedAttributeField - private String _path; - - public FileBasedGroupProvider(UUID id, - Broker broker, - Map<String, Object> attributes) - { - super(parentsMap(broker), - combineIdWithAttributes(id, attributes), broker.getTaskExecutor()); - - - _broker = broker; - - State state = MapValueConverter.getEnumAttribute(State.class, STATE, attributes, State.INITIALISING); - _state = new AtomicReference<State>(state); - } - - public void validate() - { - Collection<GroupProvider<?>> groupProviders = _broker.getGroupProviders(); - for(GroupProvider<?> provider : groupProviders) - { - if(provider instanceof FileBasedGroupProvider && provider != this) - { - try - { - if(new File(getPath()).getCanonicalPath().equals(new File(((FileBasedGroupProvider)provider).getPath()).getCanonicalPath())) - { - throw new IllegalConfigurationException("Cannot have two group providers using the same file: " + getPath()); - } - } - catch (IOException e) - { - throw new IllegalArgumentException("Invalid path", e); - } - } - } - } - - protected void onOpen() - { - super.onOpen(); - if(_groupManager == null) - { - _groupManager = new FileGroupManager(getPath()); - } - } - - @Override - protected void onCreate() - { - super.onCreate(); - _groupManager = new FileGroupManager(getPath()); - _groupManager.onCreate(); - } - @ManagedAttribute( automate = true, mandatory = true) - public String getPath() - { - return _path; - } - - @Override - public String setName(String currentName, String desiredName) - throws IllegalStateException, AccessControlException - { - return null; - } - - @Override - public State getState() - { - return _state.get(); - } - - @Override - public boolean isDurable() - { - return true; - } - - @Override - public void setDurable(boolean durable) throws IllegalStateException, - AccessControlException, IllegalArgumentException - { - } - - @Override - public LifetimePolicy getLifetimePolicy() - { - return LifetimePolicy.PERMANENT; - } - - @Override - public LifetimePolicy setLifetimePolicy(LifetimePolicy expected, - LifetimePolicy desired) throws IllegalStateException, - AccessControlException, IllegalArgumentException - { - return null; - } - - @Override - public Collection<String> getAttributeNames() - { - return getAttributeNames(getClass()); - } - - @Override - public Object getAttribute(String name) - { - if (DURABLE.equals(name)) - { - return true; - } - else if (LIFETIME_POLICY.equals(name)) - { - return LifetimePolicy.PERMANENT; - } - else if (STATE.equals(name)) - { - return getState(); - } - - return super.getAttribute(name); - } - - @Override - public <C extends ConfiguredObject> C addChild(Class<C> childClass, - Map<String, Object> attributes, ConfiguredObject... otherParents) - { - if (childClass == Group.class) - { - String groupName = (String) attributes.get(Group.NAME); - - getSecurityManager().authoriseGroupOperation(Operation.CREATE, groupName); - _groupManager.createGroup(groupName); - Map<String,Object> attrMap = new HashMap<String, Object>(); - UUID id = UUIDGenerator.generateGroupUUID(getName(),groupName); - attrMap.put(Group.ID, id); - attrMap.put(Group.NAME, groupName); - return (C) new GroupAdapter(attrMap, getTaskExecutor()); - - } - - throw new IllegalArgumentException( - "This group provider does not support creating children of type: " - + childClass); - } - - @SuppressWarnings("unchecked") - @Override - public <C extends ConfiguredObject> Collection<C> getChildren(Class<C> clazz) - { - if (clazz == Group.class) - { - Set<Principal> groups = _groupManager == null ? Collections.<Principal>emptySet() : _groupManager.getGroupPrincipals(); - Collection<Group> principals = new ArrayList<Group>(groups.size()); - for (Principal group : groups) - { - Map<String,Object> attrMap = new HashMap<String, Object>(); - UUID id = UUIDGenerator.generateGroupUUID(getName(),group.getName()); - attrMap.put(Group.ID, id); - attrMap.put(Group.NAME, group.getName()); - principals.add(new GroupAdapter(attrMap, getTaskExecutor())); - } - return (Collection<C>) Collections - .unmodifiableCollection(principals); - } - else - { - return null; - } - } - - public GroupManager getGroupManager() - { - return _groupManager; - } - - private SecurityManager getSecurityManager() - { - return _broker.getSecurityManager(); - } - - @Override - protected boolean setState(State currentState, State desiredState) - { - State state = _state.get(); - if (desiredState == State.ACTIVE) - { - if ((state == State.INITIALISING || state == State.QUIESCED || state == State.STOPPED) - && _state.compareAndSet(state, State.ACTIVE)) - { - try - { - _groupManager.open(); - return true; - } - catch(RuntimeException e) - { - _state.compareAndSet(State.ACTIVE, State.ERRORED); - if (_broker.isManagementMode()) - { - LOGGER.warn("Failed to activate group provider: " + getName(), e); - } - else - { - throw e; - } - } - } - else - { - throw new IllegalStateException("Cannot activate group provider in state: " + state); - } - } - else if (desiredState == State.STOPPED) - { - if (_state.compareAndSet(state, State.STOPPED)) - { - _groupManager.close(); - return true; - } - else - { - throw new IllegalStateException("Cannot stop group provider in state: " + state); - } - } - else if (desiredState == State.DELETED) - { - if ((state == State.INITIALISING || state == State.ACTIVE || state == State.STOPPED || state == State.QUIESCED || state == State.ERRORED) - && _state.compareAndSet(state, State.DELETED)) - { - _groupManager.close(); - _groupManager.onDelete(); - deleted(); - return true; - } - else - { - throw new IllegalStateException("Cannot delete group provider in state: " + state); - } - } - else if (desiredState == State.QUIESCED) - { - if (state == State.INITIALISING && _state.compareAndSet(state, State.QUIESCED)) - { - return true; - } - } - return false; - } - - public Set<Principal> getGroupPrincipalsForUser(String username) - { - return _groupManager.getGroupPrincipalsForUser(username); - } - - @Override - protected void childAdded(ConfiguredObject child) - { - // no-op, prevent storing groups in the broker store - } - - @Override - protected void childRemoved(ConfiguredObject child) - { - // no-op, as per above, groups are not in the store - } - - @Override - protected void authoriseSetDesiredState(State currentState, State desiredState) throws AccessControlException - { - if(desiredState == State.DELETED) - { - if (!_broker.getSecurityManager().authoriseConfiguringBroker(getName(), GroupProvider.class, Operation.DELETE)) - { - throw new AccessControlException("Deletion of groups provider is denied"); - } - } - } - - @Override - protected void authoriseSetAttribute(String name, Object expected, Object desired) throws AccessControlException - { - if (!_broker.getSecurityManager().authoriseConfiguringBroker(getName(), GroupProvider.class, Operation.UPDATE)) - { - throw new AccessControlException("Setting of group provider attributes is denied"); - } - } - - @Override - protected void authoriseSetAttributes(Map<String, Object> attributes) throws AccessControlException - { - if (!_broker.getSecurityManager().authoriseConfiguringBroker(getName(), GroupProvider.class, Operation.UPDATE)) - { - throw new AccessControlException("Setting of group provider attributes is denied"); - } - } - - @Override - protected void changeAttributes(Map<String, Object> attributes) - { - throw new UnsupportedOperationException("Changing attributes on group providers is not supported."); - } - - - private class GroupAdapter extends AbstractConfiguredObject<GroupAdapter> implements Group<GroupAdapter> - { - - public GroupAdapter(Map<String,Object> attributes, TaskExecutor taskExecutor) - { - super(parentsMap(FileBasedGroupProvider.this), attributes, taskExecutor); - } - - - @Override - public String setName(String currentName, String desiredName) - throws IllegalStateException, AccessControlException - { - throw new IllegalStateException("Names cannot be updated"); - } - - @Override - public State getState() - { - return State.ACTIVE; - } - - @Override - public boolean isDurable() - { - return true; - } - - @Override - public void setDurable(boolean durable) throws IllegalStateException, - AccessControlException, IllegalArgumentException - { - throw new IllegalStateException("Durability cannot be updated"); - } - - @Override - public LifetimePolicy getLifetimePolicy() - { - return LifetimePolicy.PERMANENT; - } - - @Override - public LifetimePolicy setLifetimePolicy(LifetimePolicy expected, - LifetimePolicy desired) throws IllegalStateException, - AccessControlException, IllegalArgumentException - { - throw new IllegalStateException("LifetimePolicy cannot be updated"); - } - - @Override - public <C extends ConfiguredObject> Collection<C> getChildren( - Class<C> clazz) - { - if (clazz == GroupMember.class) - { - Set<Principal> usersInGroup = _groupManager - .getUserPrincipalsForGroup(getName()); - Collection<GroupMember> members = new ArrayList<GroupMember>(); - for (Principal principal : usersInGroup) - { - UUID id = UUIDGenerator.generateGroupMemberUUID(FileBasedGroupProvider.this.getName(), getName(), principal.getName()); - Map<String,Object> attrMap = new HashMap<String, Object>(); - attrMap.put(GroupMember.ID,id); - attrMap.put(GroupMember.NAME, principal.getName()); - members.add(new GroupMemberAdapter(attrMap, getTaskExecutor())); - } - return (Collection<C>) Collections - .unmodifiableCollection(members); - } - else - { - return null; - } - - } - - @Override - public <C extends ConfiguredObject> C addChild(Class<C> childClass, - Map<String, Object> attributes, - ConfiguredObject... otherParents) - { - if (childClass == GroupMember.class) - { - String memberName = (String) attributes.get(GroupMember.NAME); - - getSecurityManager().authoriseGroupOperation(Operation.UPDATE, getName()); - - _groupManager.addUserToGroup(memberName, getName()); - UUID id = UUIDGenerator.generateGroupMemberUUID(FileBasedGroupProvider.this.getName(), getName(), memberName); - Map<String,Object> attrMap = new HashMap<String, Object>(); - attrMap.put(GroupMember.ID,id); - attrMap.put(GroupMember.NAME, memberName); - return (C) new GroupMemberAdapter(attrMap, getTaskExecutor()); - - } - - throw new IllegalArgumentException( - "This group provider does not support creating children of type: " - + childClass); - } - - @Override - public Collection<String> getAttributeNames() - { - return getAttributeNames(Group.class); - } - - @Override - public Object getAttribute(String name) - { - if (ID.equals(name)) - { - return getId(); - } - else if (NAME.equals(name)) - { - return getName(); - } - return super.getAttribute(name); - } - - @Override - protected boolean setState(State currentState, State desiredState) - throws IllegalStateTransitionException, AccessControlException - { - if (desiredState == State.DELETED) - { - getSecurityManager().authoriseGroupOperation(Operation.DELETE, getName()); - _groupManager.removeGroup(getName()); - return true; - } - - return false; - } - - @Override - public Object setAttribute(final String name, final Object expected, final Object desired) throws IllegalStateException, - AccessControlException, IllegalArgumentException - { - throw new UnsupportedOperationException("Changing attributes on group is not supported."); - } - - @Override - public void setAttributes(final Map<String, Object> attributes) throws IllegalStateException, AccessControlException, - IllegalArgumentException - { - throw new UnsupportedOperationException("Changing attributes on group is not supported."); - } - - private class GroupMemberAdapter extends AbstractConfiguredObject<GroupMemberAdapter> implements - GroupMember<GroupMemberAdapter> - { - - public GroupMemberAdapter(Map<String,Object> attrMap, TaskExecutor taskExecutor) - { - // TODO - need to relate to the User object - super(parentsMap(GroupAdapter.this),attrMap, taskExecutor); - } - - @Override - public Collection<String> getAttributeNames() - { - return getAttributeNames(GroupMember.class); - } - - - @Override - public String setName(String currentName, String desiredName) - throws IllegalStateException, AccessControlException - { - return null; - } - - @Override - public State getState() - { - return null; - } - - @Override - public boolean isDurable() - { - return false; - } - - @Override - public void setDurable(boolean durable) - throws IllegalStateException, AccessControlException, - IllegalArgumentException - { - } - - @Override - public LifetimePolicy getLifetimePolicy() - { - return null; - } - - @Override - public LifetimePolicy setLifetimePolicy(LifetimePolicy expected, - LifetimePolicy desired) throws IllegalStateException, - AccessControlException, IllegalArgumentException - { - return null; - } - - @Override - public <C extends ConfiguredObject> Collection<C> getChildren( - Class<C> clazz) - { - return null; - } - - @Override - protected boolean setState(State currentState, State desiredState) - throws IllegalStateTransitionException, - AccessControlException - { - if (desiredState == State.DELETED) - { - getSecurityManager().authoriseGroupOperation(Operation.UPDATE, GroupAdapter.this.getName()); - - _groupManager.removeUserFromGroup(getName(), GroupAdapter.this.getName()); - return true; - - } - return false; - } - - @Override - public Object setAttribute(final String name, final Object expected, final Object desired) throws IllegalStateException, - AccessControlException, IllegalArgumentException - { - throw new UnsupportedOperationException("Changing attributes on group member is not supported."); - } - - @Override - public void setAttributes(final Map<String, Object> attributes) throws IllegalStateException, AccessControlException, - IllegalArgumentException - { - throw new UnsupportedOperationException("Changing attributes on group member is not supported."); - } - } - } - - + String getPath(); } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/FileBasedGroupProviderFactory.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/FileBasedGroupProviderFactory.java index 8d7ec4bff2..10673596a3 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/FileBasedGroupProviderFactory.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/FileBasedGroupProviderFactory.java @@ -20,29 +20,29 @@ */ package org.apache.qpid.server.model.adapter; -import org.apache.qpid.server.model.AbstractConfiguredObjectTypeFactory; -import org.apache.qpid.server.model.Broker; -import org.apache.qpid.server.model.ConfiguredObject; - import java.util.HashMap; import java.util.Map; import java.util.UUID; -public class FileBasedGroupProviderFactory extends AbstractConfiguredObjectTypeFactory<FileBasedGroupProvider> +import org.apache.qpid.server.model.AbstractConfiguredObjectTypeFactory; +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.ConfiguredObject; + +public class FileBasedGroupProviderFactory extends AbstractConfiguredObjectTypeFactory<FileBasedGroupProviderImpl> { public FileBasedGroupProviderFactory() { - super(FileBasedGroupProvider.class); + super(FileBasedGroupProviderImpl.class); } @Override - public FileBasedGroupProvider createInstance(final Map<String, Object> attributes, + public FileBasedGroupProviderImpl createInstance(final Map<String, Object> attributes, final ConfiguredObject<?>... parents) { Map<String,Object> attributesWithoutId = new HashMap<String, Object>(attributes); Object idObj = attributesWithoutId.remove(ConfiguredObject.ID); UUID id = idObj == null ? UUID.randomUUID() : idObj instanceof UUID ? (UUID) idObj : UUID.fromString(idObj.toString()); - return new FileBasedGroupProvider(id, getParent(Broker.class, parents), attributesWithoutId); + return new FileBasedGroupProviderImpl(id, getParent(Broker.class, parents), attributesWithoutId); } } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/FileBasedGroupProviderImpl.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/FileBasedGroupProviderImpl.java new file mode 100644 index 0000000000..f80d043c02 --- /dev/null +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/FileBasedGroupProviderImpl.java @@ -0,0 +1,592 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.model.adapter; + +import java.io.File; +import java.io.IOException; +import java.security.AccessControlException; +import java.security.Principal; +import java.util.*; +import java.util.concurrent.atomic.AtomicReference; + +import org.apache.log4j.Logger; +import org.apache.qpid.server.configuration.IllegalConfigurationException; +import org.apache.qpid.server.model.*; +import org.apache.qpid.server.configuration.updater.TaskExecutor; +import org.apache.qpid.server.security.access.Operation; +import org.apache.qpid.server.security.group.FileGroupManager; +import org.apache.qpid.server.security.group.GroupManager; +import org.apache.qpid.server.security.SecurityManager; +import org.apache.qpid.server.util.MapValueConverter; + +public class FileBasedGroupProviderImpl + extends AbstractConfiguredObject<FileBasedGroupProviderImpl> implements FileBasedGroupProvider<FileBasedGroupProviderImpl> +{ + private static Logger LOGGER = Logger.getLogger(FileBasedGroupProviderImpl.class); + + private GroupManager _groupManager; + private final Broker<?> _broker; + private AtomicReference<State> _state; + + @ManagedAttributeField + private String _path; + + public FileBasedGroupProviderImpl(UUID id, + Broker broker, + Map<String, Object> attributes) + { + super(parentsMap(broker), + combineIdWithAttributes(id, attributes), broker.getTaskExecutor()); + + + _broker = broker; + + State state = MapValueConverter.getEnumAttribute(State.class, STATE, attributes, State.INITIALISING); + _state = new AtomicReference<State>(state); + } + + public void validate() + { + Collection<GroupProvider<?>> groupProviders = _broker.getGroupProviders(); + for(GroupProvider<?> provider : groupProviders) + { + if(provider instanceof FileBasedGroupProvider && provider != this) + { + try + { + if(new File(getPath()).getCanonicalPath().equals(new File(((FileBasedGroupProvider)provider).getPath()).getCanonicalPath())) + { + throw new IllegalConfigurationException("Cannot have two group providers using the same file: " + getPath()); + } + } + catch (IOException e) + { + throw new IllegalArgumentException("Invalid path", e); + } + } + } + } + + protected void onOpen() + { + super.onOpen(); + if(_groupManager == null) + { + _groupManager = new FileGroupManager(getPath()); + } + } + + @Override + protected void onCreate() + { + super.onCreate(); + _groupManager = new FileGroupManager(getPath()); + _groupManager.onCreate(); + } + + @Override + public String getPath() + { + return _path; + } + + @Override + public String setName(String currentName, String desiredName) + throws IllegalStateException, AccessControlException + { + return null; + } + + @Override + public State getState() + { + return _state.get(); + } + + @Override + public boolean isDurable() + { + return true; + } + + @Override + public void setDurable(boolean durable) throws IllegalStateException, + AccessControlException, IllegalArgumentException + { + } + + @Override + public LifetimePolicy getLifetimePolicy() + { + return LifetimePolicy.PERMANENT; + } + + @Override + public LifetimePolicy setLifetimePolicy(LifetimePolicy expected, + LifetimePolicy desired) throws IllegalStateException, + AccessControlException, IllegalArgumentException + { + return null; + } + + @Override + public Collection<String> getAttributeNames() + { + return getAttributeNames(getClass()); + } + + @Override + public Object getAttribute(String name) + { + if (DURABLE.equals(name)) + { + return true; + } + else if (LIFETIME_POLICY.equals(name)) + { + return LifetimePolicy.PERMANENT; + } + else if (STATE.equals(name)) + { + return getState(); + } + + return super.getAttribute(name); + } + + @Override + public <C extends ConfiguredObject> C addChild(Class<C> childClass, + Map<String, Object> attributes, ConfiguredObject... otherParents) + { + if (childClass == Group.class) + { + String groupName = (String) attributes.get(Group.NAME); + + getSecurityManager().authoriseGroupOperation(Operation.CREATE, groupName); + _groupManager.createGroup(groupName); + Map<String,Object> attrMap = new HashMap<String, Object>(); + UUID id = UUIDGenerator.generateGroupUUID(getName(),groupName); + attrMap.put(Group.ID, id); + attrMap.put(Group.NAME, groupName); + return (C) new GroupAdapter(attrMap, getTaskExecutor()); + + } + + throw new IllegalArgumentException( + "This group provider does not support creating children of type: " + + childClass); + } + + @SuppressWarnings("unchecked") + @Override + public <C extends ConfiguredObject> Collection<C> getChildren(Class<C> clazz) + { + if (clazz == Group.class) + { + Set<Principal> groups = _groupManager == null ? Collections.<Principal>emptySet() : _groupManager.getGroupPrincipals(); + Collection<Group> principals = new ArrayList<Group>(groups.size()); + for (Principal group : groups) + { + Map<String,Object> attrMap = new HashMap<String, Object>(); + UUID id = UUIDGenerator.generateGroupUUID(getName(),group.getName()); + attrMap.put(Group.ID, id); + attrMap.put(Group.NAME, group.getName()); + principals.add(new GroupAdapter(attrMap, getTaskExecutor())); + } + return (Collection<C>) Collections + .unmodifiableCollection(principals); + } + else + { + return null; + } + } + + public GroupManager getGroupManager() + { + return _groupManager; + } + + private SecurityManager getSecurityManager() + { + return _broker.getSecurityManager(); + } + + @Override + protected boolean setState(State currentState, State desiredState) + { + State state = _state.get(); + if (desiredState == State.ACTIVE) + { + if ((state == State.INITIALISING || state == State.QUIESCED || state == State.STOPPED) + && _state.compareAndSet(state, State.ACTIVE)) + { + try + { + _groupManager.open(); + return true; + } + catch(RuntimeException e) + { + _state.compareAndSet(State.ACTIVE, State.ERRORED); + if (_broker.isManagementMode()) + { + LOGGER.warn("Failed to activate group provider: " + getName(), e); + } + else + { + throw e; + } + } + } + else + { + throw new IllegalStateException("Cannot activate group provider in state: " + state); + } + } + else if (desiredState == State.STOPPED) + { + if (_state.compareAndSet(state, State.STOPPED)) + { + _groupManager.close(); + return true; + } + else + { + throw new IllegalStateException("Cannot stop group provider in state: " + state); + } + } + else if (desiredState == State.DELETED) + { + if ((state == State.INITIALISING || state == State.ACTIVE || state == State.STOPPED || state == State.QUIESCED || state == State.ERRORED) + && _state.compareAndSet(state, State.DELETED)) + { + _groupManager.close(); + _groupManager.onDelete(); + deleted(); + return true; + } + else + { + throw new IllegalStateException("Cannot delete group provider in state: " + state); + } + } + else if (desiredState == State.QUIESCED) + { + if (state == State.INITIALISING && _state.compareAndSet(state, State.QUIESCED)) + { + return true; + } + } + return false; + } + + public Set<Principal> getGroupPrincipalsForUser(String username) + { + return _groupManager.getGroupPrincipalsForUser(username); + } + + @Override + protected void childAdded(ConfiguredObject child) + { + // no-op, prevent storing groups in the broker store + } + + @Override + protected void childRemoved(ConfiguredObject child) + { + // no-op, as per above, groups are not in the store + } + + @Override + protected void authoriseSetDesiredState(State currentState, State desiredState) throws AccessControlException + { + if(desiredState == State.DELETED) + { + if (!_broker.getSecurityManager().authoriseConfiguringBroker(getName(), GroupProvider.class, Operation.DELETE)) + { + throw new AccessControlException("Deletion of groups provider is denied"); + } + } + } + + @Override + protected void authoriseSetAttributes(ConfiguredObject<?> modified, Set<String> attributes) throws AccessControlException + { + if (!_broker.getSecurityManager().authoriseConfiguringBroker(getName(), GroupProvider.class, Operation.UPDATE)) + { + throw new AccessControlException("Setting of group provider attributes is denied"); + } + } + + @Override + protected void changeAttributes(Map<String, Object> attributes) + { + throw new UnsupportedOperationException("Changing attributes on group providers is not supported."); + } + + + private class GroupAdapter extends AbstractConfiguredObject<GroupAdapter> implements Group<GroupAdapter> + { + + public GroupAdapter(Map<String,Object> attributes, TaskExecutor taskExecutor) + { + super(parentsMap(FileBasedGroupProviderImpl.this), attributes, taskExecutor); + } + + + @Override + public String setName(String currentName, String desiredName) + throws IllegalStateException, AccessControlException + { + throw new IllegalStateException("Names cannot be updated"); + } + + @Override + public State getState() + { + return State.ACTIVE; + } + + @Override + public boolean isDurable() + { + return true; + } + + @Override + public void setDurable(boolean durable) throws IllegalStateException, + AccessControlException, IllegalArgumentException + { + throw new IllegalStateException("Durability cannot be updated"); + } + + @Override + public LifetimePolicy getLifetimePolicy() + { + return LifetimePolicy.PERMANENT; + } + + @Override + public LifetimePolicy setLifetimePolicy(LifetimePolicy expected, + LifetimePolicy desired) throws IllegalStateException, + AccessControlException, IllegalArgumentException + { + throw new IllegalStateException("LifetimePolicy cannot be updated"); + } + + @Override + public <C extends ConfiguredObject> Collection<C> getChildren( + Class<C> clazz) + { + if (clazz == GroupMember.class) + { + Set<Principal> usersInGroup = _groupManager + .getUserPrincipalsForGroup(getName()); + Collection<GroupMember> members = new ArrayList<GroupMember>(); + for (Principal principal : usersInGroup) + { + UUID id = UUIDGenerator.generateGroupMemberUUID(FileBasedGroupProviderImpl.this.getName(), getName(), principal.getName()); + Map<String,Object> attrMap = new HashMap<String, Object>(); + attrMap.put(GroupMember.ID,id); + attrMap.put(GroupMember.NAME, principal.getName()); + members.add(new GroupMemberAdapter(attrMap, getTaskExecutor())); + } + return (Collection<C>) Collections + .unmodifiableCollection(members); + } + else + { + return null; + } + + } + + @Override + public <C extends ConfiguredObject> C addChild(Class<C> childClass, + Map<String, Object> attributes, + ConfiguredObject... otherParents) + { + if (childClass == GroupMember.class) + { + String memberName = (String) attributes.get(GroupMember.NAME); + + getSecurityManager().authoriseGroupOperation(Operation.UPDATE, getName()); + + _groupManager.addUserToGroup(memberName, getName()); + UUID id = UUIDGenerator.generateGroupMemberUUID(FileBasedGroupProviderImpl.this.getName(), getName(), memberName); + Map<String,Object> attrMap = new HashMap<String, Object>(); + attrMap.put(GroupMember.ID,id); + attrMap.put(GroupMember.NAME, memberName); + return (C) new GroupMemberAdapter(attrMap, getTaskExecutor()); + + } + + throw new IllegalArgumentException( + "This group provider does not support creating children of type: " + + childClass); + } + + @Override + public Collection<String> getAttributeNames() + { + return getAttributeNames(Group.class); + } + + @Override + public Object getAttribute(String name) + { + if (ID.equals(name)) + { + return getId(); + } + else if (NAME.equals(name)) + { + return getName(); + } + return super.getAttribute(name); + } + + @Override + protected boolean setState(State currentState, State desiredState) + throws IllegalStateTransitionException, AccessControlException + { + if (desiredState == State.DELETED) + { + getSecurityManager().authoriseGroupOperation(Operation.DELETE, getName()); + _groupManager.removeGroup(getName()); + return true; + } + + return false; + } + + @Override + public Object setAttribute(final String name, final Object expected, final Object desired) throws IllegalStateException, + AccessControlException, IllegalArgumentException + { + throw new UnsupportedOperationException("Changing attributes on group is not supported."); + } + + @Override + public void setAttributes(final Map<String, Object> attributes) throws IllegalStateException, AccessControlException, + IllegalArgumentException + { + throw new UnsupportedOperationException("Changing attributes on group is not supported."); + } + + private class GroupMemberAdapter extends AbstractConfiguredObject<GroupMemberAdapter> implements + GroupMember<GroupMemberAdapter> + { + + public GroupMemberAdapter(Map<String,Object> attrMap, TaskExecutor taskExecutor) + { + // TODO - need to relate to the User object + super(parentsMap(GroupAdapter.this),attrMap, taskExecutor); + } + + @Override + public Collection<String> getAttributeNames() + { + return getAttributeNames(GroupMember.class); + } + + + @Override + public String setName(String currentName, String desiredName) + throws IllegalStateException, AccessControlException + { + return null; + } + + @Override + public State getState() + { + return null; + } + + @Override + public boolean isDurable() + { + return false; + } + + @Override + public void setDurable(boolean durable) + throws IllegalStateException, AccessControlException, + IllegalArgumentException + { + } + + @Override + public LifetimePolicy getLifetimePolicy() + { + return null; + } + + @Override + public LifetimePolicy setLifetimePolicy(LifetimePolicy expected, + LifetimePolicy desired) throws IllegalStateException, + AccessControlException, IllegalArgumentException + { + return null; + } + + @Override + public <C extends ConfiguredObject> Collection<C> getChildren( + Class<C> clazz) + { + return null; + } + + @Override + protected boolean setState(State currentState, State desiredState) + throws IllegalStateTransitionException, + AccessControlException + { + if (desiredState == State.DELETED) + { + getSecurityManager().authoriseGroupOperation(Operation.UPDATE, GroupAdapter.this.getName()); + + _groupManager.removeUserFromGroup(getName(), GroupAdapter.this.getName()); + return true; + + } + return false; + } + + @Override + public Object setAttribute(final String name, final Object expected, final Object desired) throws IllegalStateException, + AccessControlException, IllegalArgumentException + { + throw new UnsupportedOperationException("Changing attributes on group member is not supported."); + } + + @Override + public void setAttributes(final Map<String, Object> attributes) throws IllegalStateException, AccessControlException, + IllegalArgumentException + { + throw new UnsupportedOperationException("Changing attributes on group member is not supported."); + } + } + } + + +} diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/FileSystemPreferencesProvider.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/FileSystemPreferencesProvider.java index b1df475322..42b93db3e7 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/FileSystemPreferencesProvider.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/FileSystemPreferencesProvider.java @@ -18,577 +18,18 @@ * under the License. * */ - package org.apache.qpid.server.model.adapter; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.IOException; -import java.io.RandomAccessFile; -import java.lang.reflect.Type; -import java.nio.ByteBuffer; -import java.nio.channels.FileChannel; -import java.nio.channels.FileLock; -import java.nio.channels.OverlappingFileLockException; -import java.security.AccessControlException; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.TreeMap; -import java.util.UUID; -import java.util.concurrent.atomic.AtomicReference; - -import org.apache.log4j.Logger; -import org.codehaus.jackson.JsonParser; -import org.codehaus.jackson.JsonProcessingException; -import org.codehaus.jackson.map.ObjectMapper; -import org.codehaus.jackson.map.SerializationConfig; -import org.codehaus.jackson.type.TypeReference; - -import org.apache.qpid.server.configuration.IllegalConfigurationException; -import org.apache.qpid.server.model.AbstractConfiguredObject; -import org.apache.qpid.server.model.AuthenticationProvider; -import org.apache.qpid.server.model.Broker; -import org.apache.qpid.server.model.ConfiguredObject; -import org.apache.qpid.server.model.IllegalStateTransitionException; -import org.apache.qpid.server.model.LifetimePolicy; import org.apache.qpid.server.model.ManagedAttribute; import org.apache.qpid.server.model.ManagedObject; import org.apache.qpid.server.model.PreferencesProvider; -import org.apache.qpid.server.model.State; -import org.apache.qpid.server.util.MapValueConverter; @ManagedObject( category = false, type = "FileSystemPreferences" ) -public class FileSystemPreferencesProvider extends AbstractConfiguredObject<FileSystemPreferencesProvider> implements PreferencesProvider<FileSystemPreferencesProvider> +public interface FileSystemPreferencesProvider<X extends FileSystemPreferencesProvider<X>> extends PreferencesProvider<X> { - private static final Logger LOGGER = Logger.getLogger(FileSystemPreferencesProvider.class); - public static String PATH = "path"; - public static final String PROVIDER_TYPE = "FileSystemPreferences"; - - - - @SuppressWarnings("serial") - private static final Map<String, Type> ATTRIBUTE_TYPES = Collections.unmodifiableMap(new HashMap<String, Type>() - {{ - put(NAME, String.class); - put(PATH, String.class); - }}); - - private final AuthenticationProvider<? extends AuthenticationProvider> _authenticationProvider; - private AtomicReference<State> _state; - - private FileSystemPreferencesStore _store; - - public FileSystemPreferencesProvider(UUID id, Map<String, Object> attributes, - AuthenticationProvider<? extends AuthenticationProvider> authenticationProvider) - { - super(parentsMap(authenticationProvider), - combineIdWithAttributes(id,MapValueConverter.convert(attributes, ATTRIBUTE_TYPES)), - authenticationProvider.getParent(Broker.class).getTaskExecutor()); - State state = MapValueConverter.getEnumAttribute(State.class, STATE, attributes, State.INITIALISING); - _state = new AtomicReference<State>(state); - _authenticationProvider = authenticationProvider; - _store = new FileSystemPreferencesStore(new File(MapValueConverter.getStringAttribute(PATH, attributes))); - createStoreIfNotExist(); - } - - @Override - public Collection<String> getAttributeNames() - { - return getAttributeNames(FileSystemPreferencesProvider.class); - } + String PATH = "path"; + String PROVIDER_TYPE = "FileSystemPreferences"; @ManagedAttribute - public String getPath() - { - return (String) getAttribute(PATH); - } - - @Override - public String setName(String currentName, String desiredName) throws IllegalStateException, AccessControlException - { - throw new UnsupportedOperationException(); - } - - @Override - public State getState() - { - return _state.get(); - } - - @Override - public boolean isDurable() - { - return true; - } - - @Override - public void setDurable(boolean durable) throws IllegalStateException, AccessControlException, IllegalArgumentException - { - throw new UnsupportedOperationException(); - } - - @Override - public LifetimePolicy getLifetimePolicy() - { - return LifetimePolicy.PERMANENT; - } - - @Override - public LifetimePolicy setLifetimePolicy(LifetimePolicy expected, LifetimePolicy desired) throws IllegalStateException, - AccessControlException, IllegalArgumentException - { - throw new UnsupportedOperationException(); - } - - @Override - public <C extends ConfiguredObject> Collection<C> getChildren(Class<C> clazz) - { - return Collections.emptySet(); - } - - @Override - public Object getAttribute(String name) - { - if (DURABLE.equals(name)) - { - return true; - } - else if (ID.equals(name)) - { - return getId(); - } - else if (LIFETIME_POLICY.equals(name)) - { - return LifetimePolicy.PERMANENT; - } - else if (STATE.equals(name)) - { - return getState(); - } - return super.getAttribute(name); - } - - @Override - public boolean setState(State currentState, State desiredState) throws IllegalStateTransitionException, AccessControlException - { - State state = _state.get(); - if (desiredState == State.DELETED) - { - if ((state == State.INITIALISING || state == State.ACTIVE || state == State.STOPPED || state == State.QUIESCED || state == State.ERRORED) - && _state.compareAndSet(state, State.DELETED)) - { - try - { - _store.close(); - } - finally - { - _store.delete(); - deleted(); - _authenticationProvider.setPreferencesProvider(null); - } - return true; - } - else - { - throw new IllegalStateException("Cannot delete preferences provider in state: " + state); - } - } - else if (desiredState == State.ACTIVE) - { - if ((state == State.INITIALISING || state == State.QUIESCED || state == State.STOPPED) - && _state.compareAndSet(state, State.ACTIVE)) - { - try - { - _store.open(); - return true; - } - catch (RuntimeException e) - { - _state.compareAndSet(State.ACTIVE, State.ERRORED); - Broker<?> broker = getAuthenticationProvider().getParent(Broker.class); - if (broker != null && broker.isManagementMode()) - { - LOGGER.warn("Failed to activate preferences provider: " + getName(), e); - } - else - { - throw e; - } - } - } - else - { - throw new IllegalStateException("Cannot activate preferences provider in state: " + state); - } - } - else if (desiredState == State.QUIESCED) - { - if (state == State.INITIALISING && _state.compareAndSet(state, State.QUIESCED)) - { - _store.close(); - return true; - } - } - else if (desiredState == State.STOPPED) - { - if (_state.compareAndSet(state, State.STOPPED)) - { - _store.close(); - return true; - } - else - { - throw new IllegalStateException("Cannot stop preferences preferences in state: " + state); - } - } - - return false; - } - - @Override - public Map<String, Object> getPreferences(String userId) - { - return _store.getPreferences(userId); - } - - @Override - public Map<String, Object> setPreferences(String userId, Map<String, Object> preferences) - { - return _store.setPreferences(userId, preferences); - } - - @Override - public String[] deletePreferences(String... userIDs) - { - return _store.deletePreferences(userIDs); - } - - @Override - public Set<String> listUserIDs() - { - return _store.listUserIDs(); - } - - public AuthenticationProvider<? extends AuthenticationProvider> getAuthenticationProvider() - { - return _authenticationProvider; - } - - @Override - protected void changeAttributes(Map<String, Object> attributes) - { - Map<String, Object> effectiveAttributes = MapValueConverter.convert(super.generateEffectiveAttributes(attributes), - ATTRIBUTE_TYPES); - validateAttributes(effectiveAttributes); - String effectivePath = (String) effectiveAttributes.get(PATH); - String currentPath = (String) getAttribute(PATH); - - File storeFile = new File(effectivePath); - FileSystemPreferencesStore newStore = null; - if (!effectivePath.equals(currentPath)) - { - if (!storeFile.exists()) - { - throw new IllegalConfigurationException("Path to preferences file does not exist!"); - } - newStore = new FileSystemPreferencesStore(storeFile); - newStore.open(); - } - - try - { - super.changeAttributes(attributes); - - if (newStore != null) - { - _store.close(); - _store = newStore; - newStore = null; - } - } - finally - { - if (newStore != null) - { - newStore.close(); - } - } - // if provider was previously in ERRORED state then set its state to ACTIVE - _state.compareAndSet(State.ERRORED, State.ACTIVE); - } - - private void validateAttributes(Map<String, Object> attributes) - { - super.validateChangeAttributes(attributes); - - String newName = (String) attributes.get(NAME); - String currentName = getName(); - if (!currentName.equals(newName)) - { - throw new IllegalConfigurationException("Changing the name of preferences provider is not supported"); - } - String newType = (String) attributes.get(TYPE); - String currentType = (String) getAttribute(TYPE); - if (newType != null && !currentType.equals(newType)) - { - throw new IllegalConfigurationException("Changing the type of preferences provider is not supported"); - } - String path = (String) attributes.get(PATH); - if (path == null || path.equals("")) - { - throw new IllegalConfigurationException("Path to preferences file is not specified"); - } - } - - public void createStoreIfNotExist() - { - _store.createIfNotExist(); - } - - public static class FileSystemPreferencesStore - { - private final ObjectMapper _objectMapper; - private final Map<String, Map<String, Object>> _preferences; - private File _storeFile; - private FileLock _storeLock; - private RandomAccessFile _storeRAF; - - public FileSystemPreferencesStore(File preferencesFile) - { - _storeFile = preferencesFile; - _objectMapper = new ObjectMapper(); - _objectMapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, true); - _objectMapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true); - _preferences = new TreeMap<String, Map<String, Object>>(); - } - - public void createIfNotExist() - { - if (!_storeFile.exists()) - { - File parent = _storeFile.getParentFile(); - if (!parent.exists() && !parent.mkdirs()) - { - throw new IllegalConfigurationException("Cannot create preferences store folders"); - } - try - { - if (_storeFile.createNewFile() && !_storeFile.exists()) - { - throw new IllegalConfigurationException("Preferences store file was not created:" + _storeFile.getAbsolutePath()); - } - } - catch (IOException e) - { - throw new IllegalConfigurationException("Cannot create preferences store file"); - } - } - } - - public void delete() - { - if (_storeFile.exists() && !_storeFile.delete()) - { - LOGGER.warn("Failed to delete preferences provider file '" + _storeFile.getName() + "'"); - } - } - - public void open() - { - if (!_storeFile.exists()) - { - throw new IllegalConfigurationException("Preferences file does not exist"); - } - - if (_storeLock != null) - { - throw new IllegalStateException("Preferences store is already opened"); - } - try - { - _storeRAF = new RandomAccessFile(_storeFile, "rw"); - FileChannel fileChannel = _storeRAF.getChannel(); - try - { - _storeLock = fileChannel.tryLock(); - } - catch (OverlappingFileLockException e) - { - _storeLock = null; - } - if (_storeLock == null) - { - throw new IllegalConfigurationException("Cannot get lock on store file " + _storeFile.getName() - + " is another instance running?"); - } - long fileSize = fileChannel.size(); - if (fileSize > 0) - { - ByteBuffer buffer = ByteBuffer.allocate((int) fileSize); - fileChannel.read(buffer); - buffer.rewind(); - buffer.flip(); - byte[] data = buffer.array(); - try - { - Map<String, Map<String, Object>> preferencesMap = _objectMapper.readValue(data, - new TypeReference<Map<String, Map<String, Object>>>() - { - }); - _preferences.putAll(preferencesMap); - } - catch (JsonProcessingException e) - { - throw new IllegalConfigurationException("Cannot parse preferences json in " + _storeFile.getName(), e); - } - } - } - catch (IOException e) - { - throw new IllegalConfigurationException("Cannot load preferences from " + _storeFile.getName(), e); - } - } - - public void close() - { - synchronized (_preferences) - { - try - { - if (_storeLock != null) - { - _storeLock.release(); - } - } - catch (IOException e) - { - LOGGER.error("Cannot release file lock for preferences file store", e); - } - finally - { - _storeLock = null; - try - { - if (_storeRAF != null) - { - _storeRAF.close(); - } - } - catch (IOException e) - { - LOGGER.error("Cannot close preferences file", e); - } - finally - { - _storeRAF = null; - _preferences.clear(); - } - } - } - } - - public Map<String, Object> getPreferences(String userId) - { - checkStoreOpened(); - Map<String, Object> userPreferences = null; - synchronized (_preferences) - { - userPreferences = _preferences.get(userId); - } - if (userPreferences != null) - { - return new HashMap<String, Object>(userPreferences); - } - return Collections.emptyMap(); - } - - public Map<String, Object> setPreferences(String userId, Map<String, Object> preferences) - { - checkStoreOpened(); - Map<String, Object> userPreferences = null; - synchronized (_preferences) - { - userPreferences = _preferences.get(userId); - if (userPreferences == null) - { - userPreferences = new HashMap<String, Object>(preferences); - _preferences.put(userId, userPreferences); - } - else - { - userPreferences.putAll(preferences); - } - save(); - } - return userPreferences; - } - - public String[] deletePreferences(String... userIDs) - { - checkStoreOpened(); - Set<String> deletedUsers = new HashSet<String>(); - synchronized (_preferences) - { - for (String id : userIDs) - { - if (_preferences.containsKey(id)) - { - _preferences.remove(id); - deletedUsers.add(id); - } - } - if (!deletedUsers.isEmpty()) - { - save(); - } - } - return deletedUsers.toArray(new String[deletedUsers.size()]); - } - - public Set<String> listUserIDs() - { - checkStoreOpened(); - synchronized (_preferences) - { - return Collections.unmodifiableSet(_preferences.keySet()); - } - } - - private void save() - { - checkStoreOpened(); - try - { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - _objectMapper.writeValue(baos, _preferences); - FileChannel channel = _storeRAF.getChannel(); - long currentSize = channel.size(); - channel.position(0); - channel.write(ByteBuffer.wrap(baos.toByteArray())); - if (currentSize > baos.size()) - { - channel.truncate(baos.size()); - } - } - catch (IOException e) - { - throw new IllegalConfigurationException("Cannot store preferences", e); - } - } - - private void checkStoreOpened() - { - if (_storeLock == null) - { - throw new IllegalStateException("Preferences store is not opened"); - } - } - - } + String getPath(); } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/FileSystemPreferencesProviderFactory.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/FileSystemPreferencesProviderFactory.java index abf0dbb863..18f1884778 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/FileSystemPreferencesProviderFactory.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/FileSystemPreferencesProviderFactory.java @@ -21,29 +21,29 @@ package org.apache.qpid.server.model.adapter; -import org.apache.qpid.server.model.AbstractConfiguredObjectTypeFactory; -import org.apache.qpid.server.model.AuthenticationProvider; -import org.apache.qpid.server.model.ConfiguredObject; - import java.util.HashMap; import java.util.Map; import java.util.UUID; -public class FileSystemPreferencesProviderFactory extends AbstractConfiguredObjectTypeFactory<FileSystemPreferencesProvider> +import org.apache.qpid.server.model.AbstractConfiguredObjectTypeFactory; +import org.apache.qpid.server.model.AuthenticationProvider; +import org.apache.qpid.server.model.ConfiguredObject; + +public class FileSystemPreferencesProviderFactory extends AbstractConfiguredObjectTypeFactory<FileSystemPreferencesProviderImpl> { public FileSystemPreferencesProviderFactory() { - super(FileSystemPreferencesProvider.class); + super(FileSystemPreferencesProviderImpl.class); } @Override - public FileSystemPreferencesProvider createInstance(final Map<String, Object> attributes, + public FileSystemPreferencesProviderImpl createInstance(final Map<String, Object> attributes, final ConfiguredObject<?>... parents) { Map<String,Object> attributesWithoutId = new HashMap<String, Object>(attributes); Object idObj = attributesWithoutId.remove(ConfiguredObject.ID); UUID id = idObj == null ? UUID.randomUUID() : idObj instanceof UUID ? (UUID) idObj : UUID.fromString(idObj.toString()); - return new FileSystemPreferencesProvider(id, attributesWithoutId, getParent(AuthenticationProvider.class,parents)); + return new FileSystemPreferencesProviderImpl(id, attributesWithoutId, getParent(AuthenticationProvider.class,parents)); } } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/FileSystemPreferencesProviderImpl.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/FileSystemPreferencesProviderImpl.java new file mode 100644 index 0000000000..c3a2cfde61 --- /dev/null +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/adapter/FileSystemPreferencesProviderImpl.java @@ -0,0 +1,588 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ + +package org.apache.qpid.server.model.adapter; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.lang.reflect.Type; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.channels.FileLock; +import java.nio.channels.OverlappingFileLockException; +import java.security.AccessControlException; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicReference; + +import org.apache.log4j.Logger; +import org.codehaus.jackson.JsonParser; +import org.codehaus.jackson.JsonProcessingException; +import org.codehaus.jackson.map.ObjectMapper; +import org.codehaus.jackson.map.SerializationConfig; +import org.codehaus.jackson.type.TypeReference; + +import org.apache.qpid.server.configuration.IllegalConfigurationException; +import org.apache.qpid.server.model.AbstractConfiguredObject; +import org.apache.qpid.server.model.AuthenticationProvider; +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.ConfiguredObject; +import org.apache.qpid.server.model.IllegalStateTransitionException; +import org.apache.qpid.server.model.LifetimePolicy; +import org.apache.qpid.server.model.State; +import org.apache.qpid.server.util.MapValueConverter; + + +public class FileSystemPreferencesProviderImpl + extends AbstractConfiguredObject<FileSystemPreferencesProviderImpl> implements FileSystemPreferencesProvider<FileSystemPreferencesProviderImpl> +{ + private static final Logger LOGGER = Logger.getLogger(FileSystemPreferencesProviderImpl.class); + + + @SuppressWarnings("serial") + private static final Map<String, Type> ATTRIBUTE_TYPES = Collections.unmodifiableMap(new HashMap<String, Type>() + {{ + put(NAME, String.class); + put(PATH, String.class); + }}); + + private final AuthenticationProvider<? extends AuthenticationProvider> _authenticationProvider; + private AtomicReference<State> _state; + + private FileSystemPreferencesStore _store; + + public FileSystemPreferencesProviderImpl(UUID id, Map<String, Object> attributes, + AuthenticationProvider<? extends AuthenticationProvider> authenticationProvider) + { + super(parentsMap(authenticationProvider), + combineIdWithAttributes(id,MapValueConverter.convert(attributes, ATTRIBUTE_TYPES)), + authenticationProvider.getParent(Broker.class).getTaskExecutor()); + State state = MapValueConverter.getEnumAttribute(State.class, STATE, attributes, State.INITIALISING); + _state = new AtomicReference<State>(state); + _authenticationProvider = authenticationProvider; + _store = new FileSystemPreferencesStore(new File(MapValueConverter.getStringAttribute(PATH, attributes))); + createStoreIfNotExist(); + } + + @Override + public Collection<String> getAttributeNames() + { + return getAttributeNames(FileSystemPreferencesProviderImpl.class); + } + + @Override + public String getPath() + { + return (String) getAttribute(PATH); + } + + @Override + public String setName(String currentName, String desiredName) throws IllegalStateException, AccessControlException + { + throw new UnsupportedOperationException(); + } + + @Override + public State getState() + { + return _state.get(); + } + + @Override + public boolean isDurable() + { + return true; + } + + @Override + public void setDurable(boolean durable) throws IllegalStateException, AccessControlException, IllegalArgumentException + { + throw new UnsupportedOperationException(); + } + + @Override + public LifetimePolicy getLifetimePolicy() + { + return LifetimePolicy.PERMANENT; + } + + @Override + public LifetimePolicy setLifetimePolicy(LifetimePolicy expected, LifetimePolicy desired) throws IllegalStateException, + AccessControlException, IllegalArgumentException + { + throw new UnsupportedOperationException(); + } + + @Override + public <C extends ConfiguredObject> Collection<C> getChildren(Class<C> clazz) + { + return Collections.emptySet(); + } + + @Override + public Object getAttribute(String name) + { + if (DURABLE.equals(name)) + { + return true; + } + else if (ID.equals(name)) + { + return getId(); + } + else if (LIFETIME_POLICY.equals(name)) + { + return LifetimePolicy.PERMANENT; + } + else if (STATE.equals(name)) + { + return getState(); + } + return super.getAttribute(name); + } + + @Override + public boolean setState(State currentState, State desiredState) throws IllegalStateTransitionException, AccessControlException + { + State state = _state.get(); + if (desiredState == State.DELETED) + { + if ((state == State.INITIALISING || state == State.ACTIVE || state == State.STOPPED || state == State.QUIESCED || state == State.ERRORED) + && _state.compareAndSet(state, State.DELETED)) + { + try + { + _store.close(); + } + finally + { + _store.delete(); + deleted(); + _authenticationProvider.setPreferencesProvider(null); + } + return true; + } + else + { + throw new IllegalStateException("Cannot delete preferences provider in state: " + state); + } + } + else if (desiredState == State.ACTIVE) + { + if ((state == State.INITIALISING || state == State.QUIESCED || state == State.STOPPED) + && _state.compareAndSet(state, State.ACTIVE)) + { + try + { + _store.open(); + return true; + } + catch (RuntimeException e) + { + _state.compareAndSet(State.ACTIVE, State.ERRORED); + Broker<?> broker = getAuthenticationProvider().getParent(Broker.class); + if (broker != null && broker.isManagementMode()) + { + LOGGER.warn("Failed to activate preferences provider: " + getName(), e); + } + else + { + throw e; + } + } + } + else + { + throw new IllegalStateException("Cannot activate preferences provider in state: " + state); + } + } + else if (desiredState == State.QUIESCED) + { + if (state == State.INITIALISING && _state.compareAndSet(state, State.QUIESCED)) + { + _store.close(); + return true; + } + } + else if (desiredState == State.STOPPED) + { + if (_state.compareAndSet(state, State.STOPPED)) + { + _store.close(); + return true; + } + else + { + throw new IllegalStateException("Cannot stop preferences preferences in state: " + state); + } + } + + return false; + } + + @Override + public Map<String, Object> getPreferences(String userId) + { + return _store.getPreferences(userId); + } + + @Override + public Map<String, Object> setPreferences(String userId, Map<String, Object> preferences) + { + return _store.setPreferences(userId, preferences); + } + + @Override + public String[] deletePreferences(String... userIDs) + { + return _store.deletePreferences(userIDs); + } + + @Override + public Set<String> listUserIDs() + { + return _store.listUserIDs(); + } + + public AuthenticationProvider<? extends AuthenticationProvider> getAuthenticationProvider() + { + return _authenticationProvider; + } + + @Override + protected void changeAttributes(Map<String, Object> attributes) + { + Map<String, Object> effectiveAttributes = MapValueConverter.convert(super.generateEffectiveAttributes(attributes), + ATTRIBUTE_TYPES); + + String effectivePath = (String) effectiveAttributes.get(PATH); + String currentPath = (String) getAttribute(PATH); + + File storeFile = new File(effectivePath); + FileSystemPreferencesStore newStore = null; + if (!effectivePath.equals(currentPath)) + { + if (!storeFile.exists()) + { + throw new IllegalConfigurationException("Path to preferences file does not exist!"); + } + newStore = new FileSystemPreferencesStore(storeFile); + newStore.open(); + } + + try + { + super.changeAttributes(attributes); + + if (newStore != null) + { + _store.close(); + _store = newStore; + newStore = null; + } + } + finally + { + if (newStore != null) + { + newStore.close(); + } + } + // if provider was previously in ERRORED state then set its state to ACTIVE + _state.compareAndSet(State.ERRORED, State.ACTIVE); + } + + @Override + protected void validateChange(final ConfiguredObject<?> updatedObject, final Set<String> changedAttributes) + { + super.validateChange(updatedObject, changedAttributes); + FileSystemPreferencesProvider<?> updated = (FileSystemPreferencesProvider<?>) updatedObject; + + if (changedAttributes.contains(NAME) && !getName().equals(updated.getName())) + { + throw new IllegalConfigurationException("Changing the name of preferences provider is not supported"); + } + + if (changedAttributes.contains(TYPE) && getType() != null && !getType().equals(updated.getType())) + { + throw new IllegalConfigurationException("Changing the type of preferences provider is not supported"); + } + + if (changedAttributes.contains(PATH) && (updated.getPath() == null || updated.getPath().equals(""))) + { + throw new IllegalConfigurationException("Path to preferences file is not specified"); + } + } + + public void createStoreIfNotExist() + { + _store.createIfNotExist(); + } + + public static class FileSystemPreferencesStore + { + private final ObjectMapper _objectMapper; + private final Map<String, Map<String, Object>> _preferences; + private File _storeFile; + private FileLock _storeLock; + private RandomAccessFile _storeRAF; + + public FileSystemPreferencesStore(File preferencesFile) + { + _storeFile = preferencesFile; + _objectMapper = new ObjectMapper(); + _objectMapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, true); + _objectMapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true); + _preferences = new TreeMap<String, Map<String, Object>>(); + } + + public void createIfNotExist() + { + if (!_storeFile.exists()) + { + File parent = _storeFile.getParentFile(); + if (!parent.exists() && !parent.mkdirs()) + { + throw new IllegalConfigurationException("Cannot create preferences store folders"); + } + try + { + if (_storeFile.createNewFile() && !_storeFile.exists()) + { + throw new IllegalConfigurationException("Preferences store file was not created:" + _storeFile.getAbsolutePath()); + } + } + catch (IOException e) + { + throw new IllegalConfigurationException("Cannot create preferences store file"); + } + } + } + + public void delete() + { + if (_storeFile.exists() && !_storeFile.delete()) + { + LOGGER.warn("Failed to delete preferences provider file '" + _storeFile.getName() + "'"); + } + } + + public void open() + { + if (!_storeFile.exists()) + { + throw new IllegalConfigurationException("Preferences file does not exist"); + } + + if (_storeLock != null) + { + throw new IllegalStateException("Preferences store is already opened"); + } + try + { + _storeRAF = new RandomAccessFile(_storeFile, "rw"); + FileChannel fileChannel = _storeRAF.getChannel(); + try + { + _storeLock = fileChannel.tryLock(); + } + catch (OverlappingFileLockException e) + { + _storeLock = null; + } + if (_storeLock == null) + { + throw new IllegalConfigurationException("Cannot get lock on store file " + _storeFile.getName() + + " is another instance running?"); + } + long fileSize = fileChannel.size(); + if (fileSize > 0) + { + ByteBuffer buffer = ByteBuffer.allocate((int) fileSize); + fileChannel.read(buffer); + buffer.rewind(); + buffer.flip(); + byte[] data = buffer.array(); + try + { + Map<String, Map<String, Object>> preferencesMap = _objectMapper.readValue(data, + new TypeReference<Map<String, Map<String, Object>>>() + { + }); + _preferences.putAll(preferencesMap); + } + catch (JsonProcessingException e) + { + throw new IllegalConfigurationException("Cannot parse preferences json in " + _storeFile.getName(), e); + } + } + } + catch (IOException e) + { + throw new IllegalConfigurationException("Cannot load preferences from " + _storeFile.getName(), e); + } + } + + public void close() + { + synchronized (_preferences) + { + try + { + if (_storeLock != null) + { + _storeLock.release(); + } + } + catch (IOException e) + { + LOGGER.error("Cannot release file lock for preferences file store", e); + } + finally + { + _storeLock = null; + try + { + if (_storeRAF != null) + { + _storeRAF.close(); + } + } + catch (IOException e) + { + LOGGER.error("Cannot close preferences file", e); + } + finally + { + _storeRAF = null; + _preferences.clear(); + } + } + } + } + + public Map<String, Object> getPreferences(String userId) + { + checkStoreOpened(); + Map<String, Object> userPreferences = null; + synchronized (_preferences) + { + userPreferences = _preferences.get(userId); + } + if (userPreferences != null) + { + return new HashMap<String, Object>(userPreferences); + } + return Collections.emptyMap(); + } + + public Map<String, Object> setPreferences(String userId, Map<String, Object> preferences) + { + checkStoreOpened(); + Map<String, Object> userPreferences = null; + synchronized (_preferences) + { + userPreferences = _preferences.get(userId); + if (userPreferences == null) + { + userPreferences = new HashMap<String, Object>(preferences); + _preferences.put(userId, userPreferences); + } + else + { + userPreferences.putAll(preferences); + } + save(); + } + return userPreferences; + } + + public String[] deletePreferences(String... userIDs) + { + checkStoreOpened(); + Set<String> deletedUsers = new HashSet<String>(); + synchronized (_preferences) + { + for (String id : userIDs) + { + if (_preferences.containsKey(id)) + { + _preferences.remove(id); + deletedUsers.add(id); + } + } + if (!deletedUsers.isEmpty()) + { + save(); + } + } + return deletedUsers.toArray(new String[deletedUsers.size()]); + } + + public Set<String> listUserIDs() + { + checkStoreOpened(); + synchronized (_preferences) + { + return Collections.unmodifiableSet(_preferences.keySet()); + } + } + + private void save() + { + checkStoreOpened(); + try + { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + _objectMapper.writeValue(baos, _preferences); + FileChannel channel = _storeRAF.getChannel(); + long currentSize = channel.size(); + channel.position(0); + channel.write(ByteBuffer.wrap(baos.toByteArray())); + if (currentSize > baos.size()) + { + channel.truncate(baos.size()); + } + } + catch (IOException e) + { + throw new IllegalConfigurationException("Cannot store preferences", e); + } + } + + private void checkStoreOpened() + { + if (_storeLock == null) + { + throw new IllegalStateException("Preferences store is not opened"); + } + } + + } +} diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/AbstractPort.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/AbstractPort.java index 80dab3c96c..518abb692f 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/AbstractPort.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/AbstractPort.java @@ -349,6 +349,7 @@ abstract public class AbstractPort<X extends AbstractPort<X>> extends AbstractCo // no-op: expected to be overridden by subclass } + @Override protected void changeAttributes(Map<String, Object> attributes) { @@ -481,16 +482,7 @@ abstract public class AbstractPort<X extends AbstractPort<X>> extends AbstractCo } @Override - protected void authoriseSetAttribute(String name, Object expected, Object desired) throws AccessControlException - { - if (!_broker.getSecurityManager().authoriseConfiguringBroker(getName(), Port.class, Operation.UPDATE)) - { - throw new AccessControlException("Setting of port attributes is denied"); - } - } - - @Override - protected void authoriseSetAttributes(Map<String, Object> attributes) throws AccessControlException + protected void authoriseSetAttributes(ConfiguredObject<?> modified, Set<String> attributes) throws AccessControlException { if (!_broker.getSecurityManager().authoriseConfiguringBroker(getName(), Port.class, Operation.UPDATE)) { diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/PortWithAuthProvider.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/AbstractPortWithAuthProvider.java index 3aedbc9ecf..db3d9897c7 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/PortWithAuthProvider.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/AbstractPortWithAuthProvider.java @@ -27,11 +27,10 @@ import org.apache.qpid.server.configuration.IllegalConfigurationException; import org.apache.qpid.server.configuration.updater.TaskExecutor; import org.apache.qpid.server.model.AuthenticationProvider; import org.apache.qpid.server.model.Broker; -import org.apache.qpid.server.model.ManagedAttribute; import org.apache.qpid.server.model.ManagedAttributeField; import org.apache.qpid.server.model.Transport; -abstract public class PortWithAuthProvider<X extends PortWithAuthProvider<X>> extends AbstractPort<X> +abstract public class AbstractPortWithAuthProvider<X extends AbstractPortWithAuthProvider<X>> extends AbstractPort<X> { public static final String DEFAULT_AMQP_NEED_CLIENT_AUTH = "false"; public static final String DEFAULT_AMQP_WANT_CLIENT_AUTH = "false"; @@ -45,28 +44,25 @@ abstract public class PortWithAuthProvider<X extends PortWithAuthProvider<X>> ex @ManagedAttributeField private boolean _wantClientAuth; - public PortWithAuthProvider(final UUID id, - final Broker<?> broker, - final Map<String, Object> attributes, - final Map<String, Object> defaults, - final TaskExecutor taskExecutor) + public AbstractPortWithAuthProvider(final UUID id, + final Broker<?> broker, + final Map<String, Object> attributes, + final Map<String, Object> defaults, + final TaskExecutor taskExecutor) { super(id, broker, attributes, taskExecutor); } - @ManagedAttribute( automate = true, defaultValue = DEFAULT_AMQP_NEED_CLIENT_AUTH ) public boolean getNeedClientAuth() { return _needClientAuth; } - @ManagedAttribute( automate = true, defaultValue = DEFAULT_AMQP_WANT_CLIENT_AUTH ) public boolean getWantClientAuth() { return _wantClientAuth; } - @ManagedAttribute( automate = true, mandatory = true ) public AuthenticationProvider getAuthenticationProvider() { Broker<?> broker = getParent(Broker.class); diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/AmqpPort.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/AmqpPort.java index 33f6cb7ad0..a986cd8179 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/AmqpPort.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/AmqpPort.java @@ -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 @@ -19,244 +20,37 @@ */ package org.apache.qpid.server.model.port; -import java.security.GeneralSecurityException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.EnumSet; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.UUID; - -import javax.net.ssl.KeyManager; -import javax.net.ssl.SSLContext; -import javax.net.ssl.TrustManager; -import javax.net.ssl.X509TrustManager; - -import org.apache.qpid.server.configuration.BrokerProperties; -import org.apache.qpid.server.configuration.IllegalConfigurationException; -import org.apache.qpid.server.configuration.updater.TaskExecutor; -import org.apache.qpid.server.logging.messages.BrokerMessages; -import org.apache.qpid.server.model.Broker; -import org.apache.qpid.server.model.KeyStore; +import org.apache.qpid.server.model.AuthenticationProvider; import org.apache.qpid.server.model.ManagedAttribute; -import org.apache.qpid.server.model.ManagedAttributeField; import org.apache.qpid.server.model.ManagedObject; -import org.apache.qpid.server.model.Protocol; -import org.apache.qpid.server.model.Transport; -import org.apache.qpid.server.model.TrustStore; -import org.apache.qpid.server.plugin.QpidServiceLoader; -import org.apache.qpid.server.plugin.TransportProviderFactory; -import org.apache.qpid.server.transport.AcceptingTransport; -import org.apache.qpid.server.transport.TransportProvider; -import org.apache.qpid.server.util.ServerScopedRuntimeException; -import org.apache.qpid.transport.network.security.ssl.QpidMultipleTrustManager; +import org.apache.qpid.server.model.Port; @ManagedObject( category = false, type = "AMQP") -public class AmqpPort extends PortWithAuthProvider<AmqpPort> +public interface AmqpPort<X extends AmqpPort<X>> extends Port<X> { - public static final String DEFAULT_AMQP_SEND_BUFFER_SIZE = "262144"; - public static final String DEFAULT_AMQP_RECEIVE_BUFFER_SIZE = "262144"; - - public static final String DEFAULT_AMQP_TCP_NO_DELAY = "true"; - public static final String DEFAULT_BINDING_ADDRESS = "*"; - - @ManagedAttributeField - private boolean _tcpNoDelay; - - @ManagedAttributeField - private int _sendBufferSize; - - @ManagedAttributeField - private int _receiveBufferSize; - - private final Broker<?> _broker; - private AcceptingTransport _transport; - - public AmqpPort(UUID id, - Broker<?> broker, - Map<String, Object> attributes, - TaskExecutor taskExecutor) - { - super(id, broker, attributes, Collections.<String,Object>emptyMap(), taskExecutor); - _broker = broker; - } - - @ManagedAttribute( automate = true , defaultValue = DEFAULT_AMQP_TCP_NO_DELAY ) - public boolean isTcpNoDelay() - { - return _tcpNoDelay; - } - - @ManagedAttribute( automate = true , defaultValue = DEFAULT_AMQP_SEND_BUFFER_SIZE ) - public int getSendBufferSize() - { - return _sendBufferSize; - } - - @ManagedAttribute( automate = true , defaultValue = DEFAULT_AMQP_RECEIVE_BUFFER_SIZE ) - public int getReceiveBufferSize() - { - return _receiveBufferSize; - } - - protected Set<Protocol> getDefaultProtocols() - { - Set<Protocol> defaultProtocols = EnumSet.of(Protocol.AMQP_0_8, Protocol.AMQP_0_9, Protocol.AMQP_0_9_1, - Protocol.AMQP_0_10, Protocol.AMQP_1_0); - String excludedProtocols = System.getProperty(BrokerProperties.PROPERTY_BROKER_DEFAULT_AMQP_PROTOCOL_EXCLUDES); - if (excludedProtocols != null) - { - String[] excludes = excludedProtocols.split(","); - for (String exclude : excludes) - { - Protocol protocol = Protocol.valueOf(exclude); - defaultProtocols.remove(protocol); - } - } - String includedProtocols = System.getProperty(BrokerProperties.PROPERTY_BROKER_DEFAULT_AMQP_PROTOCOL_INCLUDES); - if (includedProtocols != null) - { - String[] includes = includedProtocols.split(","); - for (String include : includes) - { - Protocol protocol = Protocol.valueOf(include); - defaultProtocols.add(protocol); - } - } - return defaultProtocols; - } - - - @Override - protected void onActivate() - { - Collection<Transport> transports = getTransports(); - - TransportProvider transportProvider = null; - final HashSet<Transport> transportSet = new HashSet<Transport>(transports); - for(TransportProviderFactory tpf : (new QpidServiceLoader<TransportProviderFactory>()).instancesOf(TransportProviderFactory.class)) - { - if(tpf.getSupportedTransports().contains(transports)) - { - transportProvider = tpf.getTransportProvider(transportSet); - } - } - - if(transportProvider == null) - { - throw new IllegalConfigurationException("No transport providers found which can satisfy the requirement to support the transports: " + transports); - } - - SSLContext sslContext = null; - if (transports.contains(Transport.SSL) || transports.contains(Transport.WSS)) - { - sslContext = createSslContext(); - } - - Protocol defaultSupportedProtocolReply = getDefaultAmqpSupportedReply(); - - _transport = transportProvider.createTransport(transportSet, - sslContext, - this, - getAvailableProtocols(), - defaultSupportedProtocolReply); - - _transport.start(); - for(Transport transport : getTransports()) - { - _broker.getEventLogger().message(BrokerMessages.LISTENING(String.valueOf(transport), getPort())); - } - } - - @Override - protected void onStop() - { - if (_transport != null) - { - for(Transport transport : getTransports()) - { - _broker.getEventLogger().message(BrokerMessages.SHUTTING_DOWN(String.valueOf(transport), getPort())); - } - _transport.close(); - } - } - - private SSLContext createSslContext() - { - KeyStore keyStore = getKeyStore(); - Collection<TrustStore> trustStores = getTrustStores(); + String DEFAULT_AMQP_SEND_BUFFER_SIZE = "262144"; + String DEFAULT_AMQP_RECEIVE_BUFFER_SIZE = "262144"; + String DEFAULT_AMQP_TCP_NO_DELAY = "true"; - boolean needClientCert = (Boolean)getAttribute(NEED_CLIENT_AUTH) || (Boolean)getAttribute(WANT_CLIENT_AUTH); - if (needClientCert && trustStores.isEmpty()) - { - throw new IllegalConfigurationException("Client certificate authentication is enabled on AMQP port '" - + this.getName() + "' but no trust store defined"); - } + String DEFAULT_AMQP_NEED_CLIENT_AUTH = "false"; + String DEFAULT_AMQP_WANT_CLIENT_AUTH = "false"; - try - { - SSLContext sslContext = SSLContext.getInstance("TLS"); - KeyManager[] keyManagers = keyStore.getKeyManagers(); + @ManagedAttribute( automate = true , defaultValue = AmqpPort.DEFAULT_AMQP_TCP_NO_DELAY ) + boolean isTcpNoDelay(); - TrustManager[] trustManagers; - if(trustStores == null || trustStores.isEmpty()) - { - trustManagers = null; - } - else if(trustStores.size() == 1) - { - trustManagers = trustStores.iterator().next().getTrustManagers(); - } - else - { - Collection<TrustManager> trustManagerList = new ArrayList<TrustManager>(); - final QpidMultipleTrustManager mulTrustManager = new QpidMultipleTrustManager(); + @ManagedAttribute( automate = true , defaultValue = AmqpPort.DEFAULT_AMQP_SEND_BUFFER_SIZE ) + int getSendBufferSize(); - for(TrustStore ts : trustStores) - { - TrustManager[] managers = ts.getTrustManagers(); - if(managers != null) - { - for(TrustManager manager : managers) - { - if(manager instanceof X509TrustManager) - { - mulTrustManager.addTrustManager((X509TrustManager)manager); - } - else - { - trustManagerList.add(manager); - } - } - } - } - if(!mulTrustManager.isEmpty()) - { - trustManagerList.add(mulTrustManager); - } - trustManagers = trustManagerList.toArray(new TrustManager[trustManagerList.size()]); - } - sslContext.init(keyManagers, trustManagers, null); + @ManagedAttribute( automate = true , defaultValue = AmqpPort.DEFAULT_AMQP_RECEIVE_BUFFER_SIZE ) + int getReceiveBufferSize(); - return sslContext; - } - catch (GeneralSecurityException e) - { - throw new ServerScopedRuntimeException("Unable to create SSLContext for key or trust store", e); - } - } + @ManagedAttribute( automate = true, defaultValue = DEFAULT_AMQP_NEED_CLIENT_AUTH ) + boolean getNeedClientAuth(); - private Protocol getDefaultAmqpSupportedReply() - { - String defaultAmqpSupportedReply = System.getProperty(BrokerProperties.PROPERTY_DEFAULT_SUPPORTED_PROTOCOL_REPLY); - if (defaultAmqpSupportedReply != null && defaultAmqpSupportedReply.length() != 0) - { - return Protocol.valueOf("AMQP_" + defaultAmqpSupportedReply.substring(1)); - } - return null; - } + @ManagedAttribute( automate = true, defaultValue = DEFAULT_AMQP_WANT_CLIENT_AUTH ) + boolean getWantClientAuth(); + @ManagedAttribute( automate = true, mandatory = true ) + AuthenticationProvider getAuthenticationProvider(); } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/AmqpPortFactory.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/AmqpPortFactory.java index f2f721f572..cdb8b8c7cb 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/AmqpPortFactory.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/AmqpPortFactory.java @@ -20,31 +20,31 @@ */ package org.apache.qpid.server.model.port; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + import org.apache.qpid.server.model.AbstractConfiguredObjectTypeFactory; import org.apache.qpid.server.model.Broker; import org.apache.qpid.server.model.ConfiguredObject; import org.apache.qpid.server.model.Port; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; - -public class AmqpPortFactory extends AbstractConfiguredObjectTypeFactory<AmqpPort> +public class AmqpPortFactory extends AbstractConfiguredObjectTypeFactory<AmqpPortImpl> { public AmqpPortFactory() { - super(AmqpPort.class); + super(AmqpPortImpl.class); } @Override - public AmqpPort createInstance(final Map<String, Object> attributes, final ConfiguredObject<?>... parents) + public AmqpPortImpl createInstance(final Map<String, Object> attributes, final ConfiguredObject<?>... parents) { Broker broker = getParent(Broker.class, parents); Map<String,Object> attributesWithoutId = new HashMap<String, Object>(attributes); Object idObj = attributesWithoutId.remove(Port.ID); UUID id = idObj == null ? UUID.randomUUID() : idObj instanceof UUID ? (UUID) idObj : UUID.fromString(idObj.toString()); - return new AmqpPort(id, broker, attributesWithoutId, broker.getTaskExecutor()); + return new AmqpPortImpl(id, broker, attributesWithoutId, broker.getTaskExecutor()); } } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/AmqpPortImpl.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/AmqpPortImpl.java new file mode 100644 index 0000000000..7e496c97ed --- /dev/null +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/AmqpPortImpl.java @@ -0,0 +1,256 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.model.port; + +import java.security.GeneralSecurityException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.EnumSet; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.UUID; + +import javax.net.ssl.KeyManager; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; + +import org.apache.qpid.server.configuration.BrokerProperties; +import org.apache.qpid.server.configuration.IllegalConfigurationException; +import org.apache.qpid.server.configuration.updater.TaskExecutor; +import org.apache.qpid.server.logging.messages.BrokerMessages; +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.KeyStore; +import org.apache.qpid.server.model.ManagedAttributeField; +import org.apache.qpid.server.model.Protocol; +import org.apache.qpid.server.model.Transport; +import org.apache.qpid.server.model.TrustStore; +import org.apache.qpid.server.plugin.QpidServiceLoader; +import org.apache.qpid.server.plugin.TransportProviderFactory; +import org.apache.qpid.server.transport.AcceptingTransport; +import org.apache.qpid.server.transport.TransportProvider; +import org.apache.qpid.server.util.ServerScopedRuntimeException; +import org.apache.qpid.transport.network.security.ssl.QpidMultipleTrustManager; + +public class AmqpPortImpl extends AbstractPortWithAuthProvider<AmqpPortImpl> implements AmqpPort<AmqpPortImpl> +{ + + public static final String DEFAULT_BINDING_ADDRESS = "*"; + + @ManagedAttributeField + private boolean _tcpNoDelay; + + @ManagedAttributeField + private int _sendBufferSize; + + @ManagedAttributeField + private int _receiveBufferSize; + + private final Broker<?> _broker; + private AcceptingTransport _transport; + + public AmqpPortImpl(UUID id, + Broker<?> broker, + Map<String, Object> attributes, + TaskExecutor taskExecutor) + { + super(id, broker, attributes, Collections.<String,Object>emptyMap(), taskExecutor); + _broker = broker; + } + + @Override + public boolean isTcpNoDelay() + { + return _tcpNoDelay; + } + + @Override + public int getSendBufferSize() + { + return _sendBufferSize; + } + + @Override + public int getReceiveBufferSize() + { + return _receiveBufferSize; + } + + protected Set<Protocol> getDefaultProtocols() + { + Set<Protocol> defaultProtocols = EnumSet.of(Protocol.AMQP_0_8, Protocol.AMQP_0_9, Protocol.AMQP_0_9_1, + Protocol.AMQP_0_10, Protocol.AMQP_1_0); + String excludedProtocols = System.getProperty(BrokerProperties.PROPERTY_BROKER_DEFAULT_AMQP_PROTOCOL_EXCLUDES); + if (excludedProtocols != null) + { + String[] excludes = excludedProtocols.split(","); + for (String exclude : excludes) + { + Protocol protocol = Protocol.valueOf(exclude); + defaultProtocols.remove(protocol); + } + } + String includedProtocols = System.getProperty(BrokerProperties.PROPERTY_BROKER_DEFAULT_AMQP_PROTOCOL_INCLUDES); + if (includedProtocols != null) + { + String[] includes = includedProtocols.split(","); + for (String include : includes) + { + Protocol protocol = Protocol.valueOf(include); + defaultProtocols.add(protocol); + } + } + return defaultProtocols; + } + + + @Override + protected void onActivate() + { + Collection<Transport> transports = getTransports(); + + TransportProvider transportProvider = null; + final HashSet<Transport> transportSet = new HashSet<Transport>(transports); + for(TransportProviderFactory tpf : (new QpidServiceLoader<TransportProviderFactory>()).instancesOf(TransportProviderFactory.class)) + { + if(tpf.getSupportedTransports().contains(transports)) + { + transportProvider = tpf.getTransportProvider(transportSet); + } + } + + if(transportProvider == null) + { + throw new IllegalConfigurationException("No transport providers found which can satisfy the requirement to support the transports: " + transports); + } + + SSLContext sslContext = null; + if (transports.contains(Transport.SSL) || transports.contains(Transport.WSS)) + { + sslContext = createSslContext(); + } + + Protocol defaultSupportedProtocolReply = getDefaultAmqpSupportedReply(); + + _transport = transportProvider.createTransport(transportSet, + sslContext, + this, + getAvailableProtocols(), + defaultSupportedProtocolReply); + + _transport.start(); + for(Transport transport : getTransports()) + { + _broker.getEventLogger().message(BrokerMessages.LISTENING(String.valueOf(transport), getPort())); + } + } + + @Override + protected void onStop() + { + if (_transport != null) + { + for(Transport transport : getTransports()) + { + _broker.getEventLogger().message(BrokerMessages.SHUTTING_DOWN(String.valueOf(transport), getPort())); + } + _transport.close(); + } + } + + private SSLContext createSslContext() + { + KeyStore keyStore = getKeyStore(); + Collection<TrustStore> trustStores = getTrustStores(); + + boolean needClientCert = (Boolean)getAttribute(NEED_CLIENT_AUTH) || (Boolean)getAttribute(WANT_CLIENT_AUTH); + if (needClientCert && trustStores.isEmpty()) + { + throw new IllegalConfigurationException("Client certificate authentication is enabled on AMQP port '" + + this.getName() + "' but no trust store defined"); + } + + try + { + SSLContext sslContext = SSLContext.getInstance("TLS"); + KeyManager[] keyManagers = keyStore.getKeyManagers(); + + TrustManager[] trustManagers; + if(trustStores == null || trustStores.isEmpty()) + { + trustManagers = null; + } + else if(trustStores.size() == 1) + { + trustManagers = trustStores.iterator().next().getTrustManagers(); + } + else + { + Collection<TrustManager> trustManagerList = new ArrayList<TrustManager>(); + final QpidMultipleTrustManager mulTrustManager = new QpidMultipleTrustManager(); + + for(TrustStore ts : trustStores) + { + TrustManager[] managers = ts.getTrustManagers(); + if(managers != null) + { + for(TrustManager manager : managers) + { + if(manager instanceof X509TrustManager) + { + mulTrustManager.addTrustManager((X509TrustManager)manager); + } + else + { + trustManagerList.add(manager); + } + } + } + } + if(!mulTrustManager.isEmpty()) + { + trustManagerList.add(mulTrustManager); + } + trustManagers = trustManagerList.toArray(new TrustManager[trustManagerList.size()]); + } + sslContext.init(keyManagers, trustManagers, null); + + return sslContext; + + } + catch (GeneralSecurityException e) + { + throw new ServerScopedRuntimeException("Unable to create SSLContext for key or trust store", e); + } + } + + private Protocol getDefaultAmqpSupportedReply() + { + String defaultAmqpSupportedReply = System.getProperty(BrokerProperties.PROPERTY_DEFAULT_SUPPORTED_PROTOCOL_REPLY); + if (defaultAmqpSupportedReply != null && defaultAmqpSupportedReply.length() != 0) + { + return Protocol.valueOf("AMQP_" + defaultAmqpSupportedReply.substring(1)); + } + return null; + } + +} diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/HttpPort.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/HttpPort.java index 6813ea020c..b2a7306284 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/HttpPort.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/HttpPort.java @@ -20,30 +20,25 @@ */ package org.apache.qpid.server.model.port; -import java.util.Collections; -import java.util.Map; -import java.util.Set; -import java.util.UUID; - -import org.apache.qpid.server.configuration.updater.TaskExecutor; -import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.AuthenticationProvider; +import org.apache.qpid.server.model.ManagedAttribute; import org.apache.qpid.server.model.ManagedObject; -import org.apache.qpid.server.model.Protocol; +import org.apache.qpid.server.model.Port; @ManagedObject( category = false, type = "HTTP") -public class HttpPort extends PortWithAuthProvider<HttpPort> +public interface HttpPort<X extends HttpPort<X>> extends Port<X> { - public HttpPort(final UUID id, - final Broker<?> broker, - final Map<String, Object> attributes, - final TaskExecutor taskExecutor) - { - super(id, broker, attributes, Collections.<String,Object>emptyMap(), taskExecutor); - } - @Override - protected Set<Protocol> getDefaultProtocols() - { - return Collections.singleton(Protocol.HTTP); - } + String DEFAULT_AMQP_NEED_CLIENT_AUTH = "false"; + String DEFAULT_AMQP_WANT_CLIENT_AUTH = "false"; + + + @ManagedAttribute( automate = true, defaultValue = DEFAULT_AMQP_NEED_CLIENT_AUTH ) + boolean getNeedClientAuth(); + + @ManagedAttribute( automate = true, defaultValue = DEFAULT_AMQP_WANT_CLIENT_AUTH ) + boolean getWantClientAuth(); + + @ManagedAttribute( automate = true, mandatory = true ) + AuthenticationProvider getAuthenticationProvider(); } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/HttpPortFactory.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/HttpPortFactory.java index c8bd257114..ec849c8b48 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/HttpPortFactory.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/HttpPortFactory.java @@ -20,30 +20,30 @@ */ package org.apache.qpid.server.model.port; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + import org.apache.qpid.server.model.AbstractConfiguredObjectTypeFactory; import org.apache.qpid.server.model.Broker; import org.apache.qpid.server.model.ConfiguredObject; import org.apache.qpid.server.model.Port; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; - -public class HttpPortFactory extends AbstractConfiguredObjectTypeFactory<HttpPort> +public class HttpPortFactory extends AbstractConfiguredObjectTypeFactory<HttpPortImpl> { public HttpPortFactory() { - super(HttpPort.class); + super(HttpPortImpl.class); } @Override - public HttpPort createInstance(final Map<String, Object> attributes, final ConfiguredObject<?>... parents) + public HttpPortImpl createInstance(final Map<String, Object> attributes, final ConfiguredObject<?>... parents) { Broker broker = getParent(Broker.class, parents); Map<String,Object> attributesWithoutId = new HashMap<String, Object>(attributes); Object idObj = attributesWithoutId.remove(Port.ID); UUID id = idObj == null ? UUID.randomUUID() : idObj instanceof UUID ? (UUID) idObj : UUID.fromString(idObj.toString()); - return new HttpPort(id, broker, attributesWithoutId, broker.getTaskExecutor()); + return new HttpPortImpl(id, broker, attributesWithoutId, broker.getTaskExecutor()); } } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/HttpPortImpl.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/HttpPortImpl.java new file mode 100644 index 0000000000..654156f782 --- /dev/null +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/HttpPortImpl.java @@ -0,0 +1,47 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.model.port; + +import java.util.Collections; +import java.util.Map; +import java.util.Set; +import java.util.UUID; + +import org.apache.qpid.server.configuration.updater.TaskExecutor; +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.Protocol; + +public class HttpPortImpl extends AbstractPortWithAuthProvider<HttpPortImpl> implements HttpPort<HttpPortImpl> +{ + public HttpPortImpl(final UUID id, + final Broker<?> broker, + final Map<String, Object> attributes, + final TaskExecutor taskExecutor) + { + super(id, broker, attributes, Collections.<String,Object>emptyMap(), taskExecutor); + } + + @Override + protected Set<Protocol> getDefaultProtocols() + { + return Collections.singleton(Protocol.HTTP); + } +} diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/JmxPort.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/JmxPort.java index 73109ccb06..ca72fe962b 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/JmxPort.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/JmxPort.java @@ -20,37 +20,25 @@ */ package org.apache.qpid.server.model.port; -import java.util.Collections; -import java.util.Map; -import java.util.Set; -import java.util.UUID; - -import org.apache.qpid.server.configuration.updater.TaskExecutor; -import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.AuthenticationProvider; +import org.apache.qpid.server.model.ManagedAttribute; import org.apache.qpid.server.model.ManagedObject; -import org.apache.qpid.server.model.Protocol; +import org.apache.qpid.server.model.Port; @ManagedObject( category = false, type = "JMX") -public class JmxPort extends PortWithAuthProvider<JmxPort> +public interface JmxPort<X extends JmxPort<X>> extends Port<X> { - public JmxPort(final UUID id, - final Broker<?> broker, - final Map<String, Object> attributes, - final TaskExecutor taskExecutor) - { - super(id, broker, attributes, Collections.<String,Object>emptyMap(), taskExecutor); - } - @Override - public void validate() - { - super.validate(); - validateOnlyOneInstance(); - } + String DEFAULT_AMQP_NEED_CLIENT_AUTH = "false"; + String DEFAULT_AMQP_WANT_CLIENT_AUTH = "false"; + + + @ManagedAttribute( automate = true, defaultValue = DEFAULT_AMQP_NEED_CLIENT_AUTH ) + boolean getNeedClientAuth(); + + @ManagedAttribute( automate = true, defaultValue = DEFAULT_AMQP_WANT_CLIENT_AUTH ) + boolean getWantClientAuth(); - @Override - protected Set<Protocol> getDefaultProtocols() - { - return Collections.singleton(Protocol.JMX_RMI); - } + @ManagedAttribute( automate = true, mandatory = true ) + AuthenticationProvider getAuthenticationProvider(); } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/JmxPortFactory.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/JmxPortFactory.java index c51a9815b7..dd47965dcc 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/JmxPortFactory.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/JmxPortFactory.java @@ -20,30 +20,30 @@ */ package org.apache.qpid.server.model.port; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + import org.apache.qpid.server.model.AbstractConfiguredObjectTypeFactory; import org.apache.qpid.server.model.Broker; import org.apache.qpid.server.model.ConfiguredObject; import org.apache.qpid.server.model.Port; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; - -public class JmxPortFactory extends AbstractConfiguredObjectTypeFactory<JmxPort> +public class JmxPortFactory extends AbstractConfiguredObjectTypeFactory<JmxPortImpl> { public JmxPortFactory() { - super(JmxPort.class); + super(JmxPortImpl.class); } @Override - public JmxPort createInstance(final Map<String, Object> attributes, final ConfiguredObject<?>... parents) + public JmxPortImpl createInstance(final Map<String, Object> attributes, final ConfiguredObject<?>... parents) { Broker broker = getParent(Broker.class, parents); Map<String,Object> attributesWithoutId = new HashMap<String, Object>(attributes); Object idObj = attributesWithoutId.remove(Port.ID); UUID id = idObj == null ? UUID.randomUUID() : idObj instanceof UUID ? (UUID) idObj : UUID.fromString(idObj.toString()); - return new JmxPort(id, broker, attributesWithoutId, broker.getTaskExecutor()); + return new JmxPortImpl(id, broker, attributesWithoutId, broker.getTaskExecutor()); } } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/JmxPortImpl.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/JmxPortImpl.java new file mode 100644 index 0000000000..78a4b824cb --- /dev/null +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/port/JmxPortImpl.java @@ -0,0 +1,54 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.model.port; + +import java.util.Collections; +import java.util.Map; +import java.util.Set; +import java.util.UUID; + +import org.apache.qpid.server.configuration.updater.TaskExecutor; +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.Protocol; + +public class JmxPortImpl extends AbstractPortWithAuthProvider<JmxPortImpl> implements JmxPort<JmxPortImpl> +{ + public JmxPortImpl(final UUID id, + final Broker<?> broker, + final Map<String, Object> attributes, + final TaskExecutor taskExecutor) + { + super(id, broker, attributes, Collections.<String,Object>emptyMap(), taskExecutor); + } + + @Override + public void validate() + { + super.validate(); + validateOnlyOneInstance(); + } + + @Override + protected Set<Protocol> getDefaultProtocols() + { + return Collections.singleton(Protocol.JMX_RMI); + } +} diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/AMQQueue.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/AMQQueue.java index 6b25e20760..30c86dc732 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/AMQQueue.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/AMQQueue.java @@ -38,8 +38,8 @@ import org.apache.qpid.server.util.Deletable; import org.apache.qpid.server.virtualhost.VirtualHostImpl; public interface AMQQueue<X extends AMQQueue<X>> - extends Comparable<AMQQueue>, ExchangeReferrer, BaseQueue, MessageSource, CapacityChecker, MessageDestination, - Deletable<AMQQueue>, Queue<X> + extends Queue<X>, Comparable<AMQQueue>, ExchangeReferrer, BaseQueue, MessageSource, CapacityChecker, MessageDestination, + Deletable<AMQQueue> { boolean isExclusive(); diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/AbstractQueue.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/AbstractQueue.java index 76002970b8..78fea5a39c 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/AbstractQueue.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/queue/AbstractQueue.java @@ -24,12 +24,10 @@ import java.security.AccessController; import java.security.Principal; import java.security.PrivilegedAction; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.EnumSet; import java.util.HashMap; -import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -98,12 +96,6 @@ public abstract class AbstractQueue MessageGroupManager.ConsumerResetHelper { - private static final Set<String> ALERT_ATTRIBUTE_NAMES = - Collections.unmodifiableSet(new HashSet<String>(Arrays.asList(Queue.ALERT_THRESHOLD_MESSAGE_AGE, - Queue.ALERT_THRESHOLD_MESSAGE_SIZE, - Queue.ALERT_THRESHOLD_QUEUE_DEPTH_BYTES, - Queue.ALERT_THRESHOLD_QUEUE_DEPTH_MESSAGES))); - private static final Logger _logger = Logger.getLogger(AbstractQueue.class); public static final String SHARED_MSG_GROUP_ARG_VALUE = "1"; @@ -126,7 +118,6 @@ public abstract class AbstractQueue private final VirtualHostImpl _virtualHost; private final DeletedChildListener _deletedChildListener = new DeletedChildListener(); - /** null means shared */ private String _description; private boolean _durable; @@ -164,19 +155,19 @@ public abstract class AbstractQueue private final AtomicInteger _bindingCountHigh = new AtomicInteger(); /** max allowed size(KB) of a single message */ - @ManagedAttributeField + @ManagedAttributeField( afterSet = "updateAlertChecks" ) private long _alertThresholdMessageSize; /** max allowed number of messages on a queue. */ - @ManagedAttributeField + @ManagedAttributeField( afterSet = "updateAlertChecks" ) private long _alertThresholdQueueDepthMessages; /** max queue depth for the queue */ - @ManagedAttributeField + @ManagedAttributeField( afterSet = "updateAlertChecks" ) private long _alertThresholdQueueDepthBytes; /** maximum message age before alerts occur */ - @ManagedAttributeField + @ManagedAttributeField( afterSet = "updateAlertChecks" ) private long _alertThresholdMessageAge; /** the minimum interval between sending out consecutive alerts of the same type */ @@ -186,7 +177,7 @@ public abstract class AbstractQueue @ManagedAttributeField private long _queueFlowControlSizeBytes; - @ManagedAttributeField + @ManagedAttributeField( afterSet = "checkCapacity" ) private long _queueFlowResumeSizeBytes; @ManagedAttributeField @@ -2890,17 +2881,7 @@ public abstract class AbstractQueue return true; } - final boolean updated = super.changeAttribute(name, expected, desired); - - if(updated && ALERT_ATTRIBUTE_NAMES.contains(name)) - { - updateAlertChecks(); - } - else if(updated && QUEUE_FLOW_RESUME_SIZE_BYTES.equals(name)) - { - checkCapacity(); - } - return updated; + return super.changeAttribute(name, expected, desired); } finally { @@ -2917,14 +2898,9 @@ public abstract class AbstractQueue { return getAttributeNames(getClass()); } - @Override - protected void authoriseSetAttribute(String name, Object expected, Object desired) throws AccessControlException - { - _virtualHost.getSecurityManager().authoriseUpdate(this); - } @Override - protected void authoriseSetAttributes(Map<String, Object> attributes) throws AccessControlException + protected void authoriseSetAttributes(ConfiguredObject<?> modified, Set<String> attributes) throws AccessControlException { _virtualHost.getSecurityManager().authoriseUpdate(this); } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java index d70b32f7ca..6ddf5f83dd 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/registry/ApplicationRegistry.java @@ -21,6 +21,7 @@ package org.apache.qpid.server.registry; import org.apache.log4j.Logger; + import org.apache.qpid.common.QpidProperties; import org.apache.qpid.server.BrokerOptions; import org.apache.qpid.server.configuration.BrokerProperties; diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/FileKeyStore.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/FileKeyStore.java index b1be18dc97..cd73bec3b2 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/FileKeyStore.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/FileKeyStore.java @@ -20,63 +20,24 @@ */ package org.apache.qpid.server.security; -import java.io.IOException; -import java.lang.reflect.Type; -import java.security.AccessControlException; -import java.security.GeneralSecurityException; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.cert.Certificate; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; - -import javax.net.ssl.KeyManager; import javax.net.ssl.KeyManagerFactory; -import org.apache.qpid.server.configuration.IllegalConfigurationException; -import org.apache.qpid.server.model.AbstractConfiguredObject; -import org.apache.qpid.server.model.Broker; -import org.apache.qpid.server.model.IntegrityViolationException; import org.apache.qpid.server.model.KeyStore; -import org.apache.qpid.server.model.LifetimePolicy; import org.apache.qpid.server.model.ManagedAttribute; -import org.apache.qpid.server.model.ManagedAttributeField; import org.apache.qpid.server.model.ManagedContextDefault; import org.apache.qpid.server.model.ManagedObject; -import org.apache.qpid.server.model.Port; import org.apache.qpid.server.model.RuntimeDefault; -import org.apache.qpid.server.model.State; -import org.apache.qpid.server.security.access.Operation; -import org.apache.qpid.server.util.MapValueConverter; -import org.apache.qpid.server.util.ServerScopedRuntimeException; -import org.apache.qpid.transport.network.security.ssl.QpidClientX509KeyManager; -import org.apache.qpid.transport.network.security.ssl.SSLUtil; -@ManagedObject( category = false ) -public class FileKeyStore extends AbstractConfiguredObject<FileKeyStore> implements KeyStore<FileKeyStore> +@ManagedObject( category = false, type = "FileKeyStore" ) +public interface FileKeyStore<X extends FileKeyStore<X>> extends KeyStore<X> { - public static final String KEY_MANAGER_FACTORY_ALGORITHM = "keyManagerFactoryAlgorithm"; - public static final String CERTIFICATE_ALIAS = "certificateAlias"; - public static final String KEY_STORE_TYPE = "keyStoreType"; - public static final String PASSWORD = "password"; - public static final String PATH = "path"; - @SuppressWarnings("serial") - public static final Map<String, Type> ATTRIBUTE_TYPES = Collections.unmodifiableMap(new HashMap<String, Type>(){{ - put(NAME, String.class); - put(PATH, String.class); - put(PASSWORD, String.class); - put(KEY_STORE_TYPE, String.class); - put(CERTIFICATE_ALIAS, String.class); - put(KEY_MANAGER_FACTORY_ALGORITHM, String.class); - }}); - - + String KEY_MANAGER_FACTORY_ALGORITHM = "keyManagerFactoryAlgorithm"; + String CERTIFICATE_ALIAS = "certificateAlias"; + String KEY_STORE_TYPE = "keyStoreType"; + String PASSWORD = "password"; + String PATH = "path"; @ManagedContextDefault(name = "keyStoreFile.keyStoreType") - public static final RuntimeDefault<String> DEFAULT_KEYSTORE_TYPE = + RuntimeDefault<String> DEFAULT_KEYSTORE_TYPE = new RuntimeDefault<String>() { @Override @@ -85,9 +46,8 @@ public class FileKeyStore extends AbstractConfiguredObject<FileKeyStore> impleme return java.security.KeyStore.getDefaultType(); } }; - @ManagedContextDefault(name = "keyStoreFile.keyManagerFactoryAlgorithm") - public static final RuntimeDefault<String> DEFAULT_KEY_MANAGER_FACTORY_ALGORITHM = + RuntimeDefault<String> DEFAULT_KEY_MANAGER_FACTORY_ALGORITHM = new RuntimeDefault<String>() { @Override @@ -97,291 +57,18 @@ public class FileKeyStore extends AbstractConfiguredObject<FileKeyStore> impleme } }; - - @ManagedAttributeField - private String _type; - @ManagedAttributeField - private String _keyStoreType; - @ManagedAttributeField - private String _certificateAlias; - @ManagedAttributeField - private String _keyManagerFactoryAlgorithm; - @ManagedAttributeField - private String _path; - @ManagedAttributeField - private String _password; - - - private Broker<?> _broker; - - public FileKeyStore(UUID id, Broker<?> broker, Map<String, Object> attributes) - { - super(parentsMap(broker), - combineIdWithAttributes(id, attributes), - broker.getTaskExecutor()); - - _broker = broker; - } - - @Override - public void validate() - { - super.validate(); - validateKeyStoreAttributes(_keyStoreType, _path, getPassword(), - _certificateAlias, _keyManagerFactoryAlgorithm); - } - - @Override - public Collection<String> getAttributeNames() - { - return getAttributeNames(getClass()); - } - @Override - public String setName(String currentName, String desiredName) throws IllegalStateException, AccessControlException - { - throw new IllegalStateException(); - } - - @Override - public State getState() - { - return State.ACTIVE; - } - - @Override - public boolean isDurable() - { - return true; - } - - @Override - public void setDurable(boolean durable) throws IllegalStateException, AccessControlException, IllegalArgumentException - { - throw new IllegalStateException(); - } - - @Override - public LifetimePolicy getLifetimePolicy() - { - return LifetimePolicy.PERMANENT; - } - - @Override - public LifetimePolicy setLifetimePolicy(LifetimePolicy expected, LifetimePolicy desired) throws IllegalStateException, AccessControlException, - IllegalArgumentException - { - throw new IllegalStateException(); - } - - @Override - public Object getAttribute(String name) - { - if(KeyStore.STATE.equals(name)) - { - return getState(); - } - else if(KeyStore.DURABLE.equals(name)) - { - return isDurable(); - } - else if(KeyStore.LIFETIME_POLICY.equals(name)) - { - return getLifetimePolicy(); - } - - return super.getAttribute(name); - } - - @Override - protected boolean setState(State currentState, State desiredState) - { - if(desiredState == State.DELETED) - { - // verify that it is not in use - String storeName = getName(); - - Collection<Port> ports = new ArrayList<Port>(_broker.getPorts()); - for (Port port : ports) - { - if (port.getKeyStore() == this) - { - throw new IntegrityViolationException("Key store '" + storeName + "' can't be deleted as it is in use by a port:" + port.getName()); - } - } - deleted(); - return true; - } - - return false; - } - - @Override - protected void authoriseSetDesiredState(State currentState, State desiredState) throws AccessControlException - { - if(desiredState == State.DELETED) - { - if (!_broker.getSecurityManager().authoriseConfiguringBroker(getName(), KeyStore.class, Operation.DELETE)) - { - throw new AccessControlException("Deletion of key store is denied"); - } - } - } - - @Override - protected void authoriseSetAttribute(String name, Object expected, Object desired) throws AccessControlException - { - authoriseSetAttribute(); - } - - @Override - protected void authoriseSetAttributes(Map<String, Object> attributes) throws AccessControlException - { - authoriseSetAttribute(); - } - - private void authoriseSetAttribute() - { - if (!_broker.getSecurityManager().authoriseConfiguringBroker(getName(), KeyStore.class, Operation.UPDATE)) - { - throw new AccessControlException("Setting key store attributes is denied"); - } - } - - @Override - protected void changeAttributes(Map<String, Object> attributes) - { - Map<String, Object> changedValues = MapValueConverter.convert(attributes, ATTRIBUTE_TYPES); - if(changedValues.containsKey(KeyStore.NAME)) - { - String newName = (String) changedValues.get(KeyStore.NAME); - if(!getName().equals(newName)) - { - throw new IllegalConfigurationException("Changing the key store name is not allowed"); - } - } - - String keyStorePath = changedValues.containsKey(PATH) ? (String)changedValues.get(PATH) : getPath(); - String keyStorePassword = changedValues.containsKey(PASSWORD) ? (String) changedValues.get(PASSWORD) : getPassword(); - String keyStoreType = changedValues.containsKey(KEY_STORE_TYPE) ? (String)changedValues.get(KEY_STORE_TYPE) : getKeyStoreType(); - String keyManagerFactoryAlgorithm = changedValues.containsKey(KEY_MANAGER_FACTORY_ALGORITHM) ? - (String)changedValues.get(KEY_MANAGER_FACTORY_ALGORITHM) : getKeyManagerFactoryAlgorithm(); - String certAlias = changedValues.containsKey(CERTIFICATE_ALIAS) ? (String)changedValues.get(CERTIFICATE_ALIAS) - : getCertificateAlias(); - - validateKeyStoreAttributes(keyStoreType, keyStorePath, keyStorePassword, - certAlias, keyManagerFactoryAlgorithm); - - super.changeAttributes(changedValues); - } - - private void validateKeyStoreAttributes(String type, String keyStorePath, - String keyStorePassword, String alias, - String keyManagerFactoryAlgorithm) - { - java.security.KeyStore keyStore; - try - { - keyStore = SSLUtil.getInitializedKeyStore(keyStorePath, keyStorePassword, type); - } - catch (Exception e) - { - throw new IllegalConfigurationException("Cannot instantiate key store at " + keyStorePath, e); - } - - if (alias != null) - { - Certificate cert; - try - { - cert = keyStore.getCertificate(alias); - } - catch (KeyStoreException e) - { - // key store should be initialized above - throw new ServerScopedRuntimeException("Key store has not been initialized", e); - } - if (cert == null) - { - throw new IllegalConfigurationException("Cannot find a certificate with alias " + alias - + "in key store : " + keyStorePath); - } - } - - try - { - KeyManagerFactory.getInstance(keyManagerFactoryAlgorithm); - } - catch (NoSuchAlgorithmException e) - { - throw new IllegalConfigurationException("Unknown keyManagerFactoryAlgorithm: " - + keyManagerFactoryAlgorithm); - } - } - @ManagedAttribute( automate = true, mandatory = true) - public String getPath() - { - return _path; - } + String getPath(); @ManagedAttribute( automate = true ) - public String getCertificateAlias() - { - return _certificateAlias; - } + String getCertificateAlias(); @ManagedAttribute( automate = true, defaultValue = "${keyStoreFile.keyManagerFactoryAlgorithm}" ) - public String getKeyManagerFactoryAlgorithm() - { - return _keyManagerFactoryAlgorithm; - } + String getKeyManagerFactoryAlgorithm(); @ManagedAttribute( automate = true, defaultValue = "${keyStoreFile.keyStoreType}" ) - public String getKeyStoreType() - { - return _keyStoreType; - } + String getKeyStoreType(); @ManagedAttribute( secure = true, automate = true, mandatory = true ) - public String getPassword() - { - return _password; - } - - public void setPassword(String password) - { - _password = password; - } - - public KeyManager[] getKeyManagers() throws GeneralSecurityException - { - - try - { - if (_certificateAlias != null) - { - return new KeyManager[] { - new QpidClientX509KeyManager( _certificateAlias, _path, _keyStoreType, getPassword(), - _keyManagerFactoryAlgorithm) - }; - - } - else - { - final java.security.KeyStore ks = SSLUtil.getInitializedKeyStore(_path, getPassword(), _keyStoreType); - - char[] keyStoreCharPassword = getPassword() == null ? null : getPassword().toCharArray(); - - final KeyManagerFactory kmf = KeyManagerFactory.getInstance(_keyManagerFactoryAlgorithm); - - kmf.init(ks, keyStoreCharPassword); - - return kmf.getKeyManagers(); - } - } - catch (IOException e) - { - throw new GeneralSecurityException(e); - } - } + String getPassword(); } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/FileKeyStoreFactory.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/FileKeyStoreFactory.java index 3421bffeba..5e54d01832 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/FileKeyStoreFactory.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/FileKeyStoreFactory.java @@ -20,29 +20,29 @@ */ package org.apache.qpid.server.security; -import org.apache.qpid.server.model.AbstractConfiguredObjectTypeFactory; -import org.apache.qpid.server.model.Broker; -import org.apache.qpid.server.model.ConfiguredObject; - import java.util.HashMap; import java.util.Map; import java.util.UUID; -public class FileKeyStoreFactory extends AbstractConfiguredObjectTypeFactory<FileKeyStore> +import org.apache.qpid.server.model.AbstractConfiguredObjectTypeFactory; +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.ConfiguredObject; + +public class FileKeyStoreFactory extends AbstractConfiguredObjectTypeFactory<FileKeyStoreImpl> { public FileKeyStoreFactory() { - super(FileKeyStore.class); + super(FileKeyStoreImpl.class); } @Override - public FileKeyStore createInstance(final Map<String, Object> attributes, final ConfiguredObject<?>... parents) + public FileKeyStoreImpl createInstance(final Map<String, Object> attributes, final ConfiguredObject<?>... parents) { HashMap<String, Object> attributesWithoutId = new HashMap<String, Object>(attributes); Object idObj = attributesWithoutId.remove(ConfiguredObject.ID); UUID id = idObj == null ? UUID.randomUUID() : idObj instanceof UUID ? (UUID) idObj : UUID.fromString(idObj.toString()); - return new FileKeyStore(id, getParent(Broker.class, parents), attributesWithoutId); + return new FileKeyStoreImpl(id, getParent(Broker.class, parents), attributesWithoutId); } } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/FileKeyStoreImpl.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/FileKeyStoreImpl.java new file mode 100644 index 0000000000..cfc3987677 --- /dev/null +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/FileKeyStoreImpl.java @@ -0,0 +1,331 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security; + +import java.io.IOException; +import java.lang.reflect.Type; +import java.security.AccessControlException; +import java.security.GeneralSecurityException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.Certificate; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.UUID; + +import javax.net.ssl.KeyManager; +import javax.net.ssl.KeyManagerFactory; + +import org.apache.qpid.server.configuration.IllegalConfigurationException; +import org.apache.qpid.server.model.AbstractConfiguredObject; +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.ConfiguredObject; +import org.apache.qpid.server.model.IntegrityViolationException; +import org.apache.qpid.server.model.KeyStore; +import org.apache.qpid.server.model.LifetimePolicy; +import org.apache.qpid.server.model.ManagedAttributeField; +import org.apache.qpid.server.model.ManagedObject; +import org.apache.qpid.server.model.Port; +import org.apache.qpid.server.model.State; +import org.apache.qpid.server.security.access.Operation; +import org.apache.qpid.server.util.ServerScopedRuntimeException; +import org.apache.qpid.transport.network.security.ssl.QpidClientX509KeyManager; +import org.apache.qpid.transport.network.security.ssl.SSLUtil; + +@ManagedObject( category = false ) +public class FileKeyStoreImpl extends AbstractConfiguredObject<FileKeyStoreImpl> implements FileKeyStore<FileKeyStoreImpl> +{ + @SuppressWarnings("serial") + public static final Map<String, Type> ATTRIBUTE_TYPES = Collections.unmodifiableMap(new HashMap<String, Type>(){{ + put(NAME, String.class); + put(PATH, String.class); + put(PASSWORD, String.class); + put(KEY_STORE_TYPE, String.class); + put(CERTIFICATE_ALIAS, String.class); + put(KEY_MANAGER_FACTORY_ALGORITHM, String.class); + }}); + + + @ManagedAttributeField + private String _type; + @ManagedAttributeField + private String _keyStoreType; + @ManagedAttributeField + private String _certificateAlias; + @ManagedAttributeField + private String _keyManagerFactoryAlgorithm; + @ManagedAttributeField + private String _path; + @ManagedAttributeField + private String _password; + + + private Broker<?> _broker; + + public FileKeyStoreImpl(UUID id, Broker<?> broker, Map<String, Object> attributes) + { + super(parentsMap(broker), + combineIdWithAttributes(id, attributes), + broker.getTaskExecutor()); + + _broker = broker; + } + + @Override + public void validate() + { + super.validate(); + validateKeyStoreAttributes(this); + } + + @Override + public Collection<String> getAttributeNames() + { + return getAttributeNames(getClass()); + } + @Override + public String setName(String currentName, String desiredName) throws IllegalStateException, AccessControlException + { + throw new IllegalStateException(); + } + + @Override + public State getState() + { + return State.ACTIVE; + } + + @Override + public boolean isDurable() + { + return true; + } + + @Override + public void setDurable(boolean durable) throws IllegalStateException, AccessControlException, IllegalArgumentException + { + throw new IllegalStateException(); + } + + @Override + public LifetimePolicy getLifetimePolicy() + { + return LifetimePolicy.PERMANENT; + } + + @Override + public LifetimePolicy setLifetimePolicy(LifetimePolicy expected, LifetimePolicy desired) throws IllegalStateException, AccessControlException, + IllegalArgumentException + { + throw new IllegalStateException(); + } + + @Override + public Object getAttribute(String name) + { + if(KeyStore.STATE.equals(name)) + { + return getState(); + } + else if(KeyStore.DURABLE.equals(name)) + { + return isDurable(); + } + else if(KeyStore.LIFETIME_POLICY.equals(name)) + { + return getLifetimePolicy(); + } + + return super.getAttribute(name); + } + + @Override + protected boolean setState(State currentState, State desiredState) + { + if(desiredState == State.DELETED) + { + // verify that it is not in use + String storeName = getName(); + + Collection<Port> ports = new ArrayList<Port>(_broker.getPorts()); + for (Port port : ports) + { + if (port.getKeyStore() == this) + { + throw new IntegrityViolationException("Key store '" + storeName + "' can't be deleted as it is in use by a port:" + port.getName()); + } + } + deleted(); + return true; + } + + return false; + } + + @Override + protected void authoriseSetDesiredState(State currentState, State desiredState) throws AccessControlException + { + if(desiredState == State.DELETED) + { + if (!_broker.getSecurityManager().authoriseConfiguringBroker(getName(), KeyStore.class, Operation.DELETE)) + { + throw new AccessControlException("Deletion of key store is denied"); + } + } + } + + @Override + protected void authoriseSetAttributes(ConfiguredObject<?> modified, Set<String> attributes) throws AccessControlException + { + if (!_broker.getSecurityManager().authoriseConfiguringBroker(getName(), KeyStore.class, Operation.UPDATE)) + { + throw new AccessControlException("Setting key store attributes is denied"); + } + } + + @Override + protected void validateChange(final ConfiguredObject<?> proxyForValidation, final Set<String> changedAttributes) + { + super.validateChange(proxyForValidation, changedAttributes); + FileKeyStore changedStore = (FileKeyStore) proxyForValidation; + if(changedAttributes.contains(NAME) && !getName().equals(changedStore.getName())) + { + throw new IllegalConfigurationException("Changing the key store name is not allowed"); + } + validateKeyStoreAttributes(changedStore); + } + + private void validateKeyStoreAttributes(FileKeyStore<?> fileKeyStore) + { + java.security.KeyStore keyStore; + try + { + String path = fileKeyStore.getPath(); + String password = fileKeyStore.getPassword(); + String keyStoreType = fileKeyStore.getKeyStoreType(); + keyStore = SSLUtil.getInitializedKeyStore(path, password, keyStoreType); + } + catch (Exception e) + { + throw new IllegalConfigurationException("Cannot instantiate key store at " + fileKeyStore.getPath(), e); + } + + if (fileKeyStore.getCertificateAlias() != null) + { + Certificate cert; + try + { + cert = keyStore.getCertificate(fileKeyStore.getCertificateAlias()); + } + catch (KeyStoreException e) + { + // key store should be initialized above + throw new ServerScopedRuntimeException("Key store has not been initialized", e); + } + if (cert == null) + { + throw new IllegalConfigurationException("Cannot find a certificate with alias " + fileKeyStore.getCertificateAlias() + + "in key store : " + fileKeyStore.getPath()); + } + } + + try + { + KeyManagerFactory.getInstance(fileKeyStore.getKeyManagerFactoryAlgorithm()); + } + catch (NoSuchAlgorithmException e) + { + throw new IllegalConfigurationException("Unknown keyManagerFactoryAlgorithm: " + + fileKeyStore.getKeyManagerFactoryAlgorithm()); + } + } + + @Override + public String getPath() + { + return _path; + } + + @Override + public String getCertificateAlias() + { + return _certificateAlias; + } + + @Override + public String getKeyManagerFactoryAlgorithm() + { + return _keyManagerFactoryAlgorithm; + } + + @Override + public String getKeyStoreType() + { + return _keyStoreType; + } + + @Override + public String getPassword() + { + return _password; + } + + public void setPassword(String password) + { + _password = password; + } + + public KeyManager[] getKeyManagers() throws GeneralSecurityException + { + + try + { + if (_certificateAlias != null) + { + return new KeyManager[] { + new QpidClientX509KeyManager( _certificateAlias, _path, _keyStoreType, getPassword(), + _keyManagerFactoryAlgorithm) + }; + + } + else + { + final java.security.KeyStore ks = SSLUtil.getInitializedKeyStore(_path, getPassword(), _keyStoreType); + + char[] keyStoreCharPassword = getPassword() == null ? null : getPassword().toCharArray(); + + final KeyManagerFactory kmf = KeyManagerFactory.getInstance(_keyManagerFactoryAlgorithm); + + kmf.init(ks, keyStoreCharPassword); + + return kmf.getKeyManagers(); + } + } + catch (IOException e) + { + throw new GeneralSecurityException(e); + } + } +} diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/FileTrustStore.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/FileTrustStore.java index 8111724f0c..78de8b770f 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/FileTrustStore.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/FileTrustStore.java @@ -20,41 +20,24 @@ */ package org.apache.qpid.server.security; -import java.io.IOException; -import java.lang.reflect.Type; -import java.security.AccessControlException; -import java.security.GeneralSecurityException; -import java.security.KeyStore; -import java.security.NoSuchAlgorithmException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; - import javax.net.ssl.KeyManagerFactory; -import javax.net.ssl.TrustManager; -import javax.net.ssl.TrustManagerFactory; - -import javax.net.ssl.X509TrustManager; -import org.apache.qpid.server.configuration.IllegalConfigurationException; -import org.apache.qpid.server.model.*; -import org.apache.qpid.server.security.access.Operation; -import org.apache.qpid.server.security.auth.manager.SimpleLDAPAuthenticationManagerFactory; -import org.apache.qpid.server.util.MapValueConverter; -import org.apache.qpid.transport.network.security.ssl.QpidMultipleTrustManager; -import org.apache.qpid.transport.network.security.ssl.QpidPeersOnlyTrustManager; -import org.apache.qpid.transport.network.security.ssl.SSLUtil; +import org.apache.qpid.server.model.ManagedAttribute; +import org.apache.qpid.server.model.ManagedContextDefault; +import org.apache.qpid.server.model.ManagedObject; +import org.apache.qpid.server.model.RuntimeDefault; +import org.apache.qpid.server.model.TrustStore; -@ManagedObject( category = false ) -public class FileTrustStore extends AbstractConfiguredObject<FileTrustStore> implements TrustStore<FileTrustStore> +@ManagedObject( category = false, type = "FileTrustStore" ) +public interface FileTrustStore<X extends FileTrustStore<X>> extends TrustStore<X> { - - + String TRUST_MANAGER_FACTORY_ALGORITHM = "trustManagerFactoryAlgorithm"; + String PEERS_ONLY = "peersOnly"; + String TRUST_STORE_TYPE = "trustStoreType"; + String PASSWORD = "password"; + String PATH = "path"; @ManagedContextDefault(name = "trustStoreFile.trustStoreType") - public static final RuntimeDefault<String> DEFAULT_TRUSTSTORE_TYPE = + RuntimeDefault<String> DEFAULT_TRUSTSTORE_TYPE = new RuntimeDefault<String>() { @Override @@ -64,7 +47,7 @@ public class FileTrustStore extends AbstractConfiguredObject<FileTrustStore> imp } }; @ManagedContextDefault(name = "trustStoreFile.trustManagerFactoryAlgorithm") - public static final RuntimeDefault<String> DEFAULT_TRUST_MANAGER_FACTORY_ALGORITHM = + RuntimeDefault<String> DEFAULT_TRUST_MANAGER_FACTORY_ALGORITHM = new RuntimeDefault<String>() { @Override @@ -74,326 +57,18 @@ public class FileTrustStore extends AbstractConfiguredObject<FileTrustStore> imp } }; - public static final String TRUST_MANAGER_FACTORY_ALGORITHM = "trustManagerFactoryAlgorithm"; - public static final String PEERS_ONLY = "peersOnly"; - public static final String TRUST_STORE_TYPE = "trustStoreType"; - public static final String PASSWORD = "password"; - public static final String PATH = "path"; - @SuppressWarnings("serial") - public static final Map<String, Type> ATTRIBUTE_TYPES = Collections.unmodifiableMap(new HashMap<String, Type>(){{ - put(NAME, String.class); - put(PATH, String.class); - put(PASSWORD, String.class); - put(TRUST_STORE_TYPE, String.class); - put(PEERS_ONLY, Boolean.class); - put(TRUST_MANAGER_FACTORY_ALGORITHM, String.class); - }}); - - @ManagedAttributeField - private String _trustStoreType; - @ManagedAttributeField - private String _trustManagerFactoryAlgorithm; - @ManagedAttributeField - private String _path; - @ManagedAttributeField - private boolean _peersOnly; - @ManagedAttributeField - private String _password; - - private Broker<?> _broker; - - public FileTrustStore(UUID id, Broker<?> broker, Map<String, Object> attributes) - { - super(parentsMap(broker), - combineIdWithAttributes(id, attributes), - broker.getTaskExecutor()); - _broker = broker; - } - - @Override - public void validate() - { - super.validate(); - validateTrustStoreAttributes(_trustStoreType, _path, getPassword(), _trustManagerFactoryAlgorithm); - } - - @Override - public Collection<String> getAttributeNames() - { - return getAttributeNames(getClass()); - } - @Override - public String setName(String currentName, String desiredName) throws IllegalStateException, AccessControlException - { - throw new IllegalStateException(); - } - - @Override - public State getState() - { - return State.ACTIVE; - } - - @Override - public boolean isDurable() - { - return true; - } - - @Override - public void setDurable(boolean durable) throws IllegalStateException, AccessControlException, IllegalArgumentException - { - throw new IllegalStateException(); - } - - @Override - public LifetimePolicy getLifetimePolicy() - { - return LifetimePolicy.PERMANENT; - } - - @Override - public LifetimePolicy setLifetimePolicy(LifetimePolicy expected, LifetimePolicy desired) throws IllegalStateException, AccessControlException, - IllegalArgumentException - { - throw new IllegalStateException(); - } - - @Override - protected boolean setState(State currentState, State desiredState) - { - if(desiredState == State.DELETED) - { - // verify that it is not in use - String storeName = getName(); - - Collection<Port<?>> ports = new ArrayList<Port<?>>(_broker.getPorts()); - for (Port port : ports) - { - Collection<TrustStore> trustStores = port.getTrustStores(); - if(trustStores != null) - { - for (TrustStore store : trustStores) - { - if (storeName.equals(store.getAttribute(TrustStore.NAME))) - { - throw new IntegrityViolationException("Trust store '" - + storeName - + "' can't be deleted as it is in use by a port: " - + port.getName()); - } - } - } - } - - Collection<AuthenticationProvider> authenticationProviders = new ArrayList<AuthenticationProvider>(_broker.getAuthenticationProviders()); - for (AuthenticationProvider authProvider : authenticationProviders) - { - Object attributeType = authProvider.getAttribute(AuthenticationProvider.TYPE); - Object attributeValue = authProvider.getAttribute(SimpleLDAPAuthenticationManagerFactory.ATTRIBUTE_TRUST_STORE); - if (SimpleLDAPAuthenticationManagerFactory.PROVIDER_TYPE.equals(attributeType) - && storeName.equals(attributeValue)) - { - throw new IntegrityViolationException("Trust store '" + storeName + "' can't be deleted as it is in use by an authentication manager: " + authProvider.getName()); - } - } - deleted(); - return true; - } - return false; - } - - @Override - protected void authoriseSetDesiredState(State currentState, State desiredState) throws AccessControlException - { - if(desiredState == State.DELETED) - { - if (!_broker.getSecurityManager().authoriseConfiguringBroker(getName(), TrustStore.class, Operation.DELETE)) - { - throw new AccessControlException("Deletion of key store is denied"); - } - } - } - - @Override - protected void authoriseSetAttribute(String name, Object expected, Object desired) throws AccessControlException - { - authoriseSetAttribute(); - } - - @Override - protected void authoriseSetAttributes(Map<String, Object> attributes) throws AccessControlException - { - authoriseSetAttribute(); - } - - private void authoriseSetAttribute() - { - if (!_broker.getSecurityManager().authoriseConfiguringBroker(getName(), TrustStore.class, Operation.UPDATE)) - { - throw new AccessControlException("Setting key store attributes is denied"); - } - } - - @Override - protected void changeAttributes(Map<String, Object> attributes) - { - Map<String, Object> changedValues = MapValueConverter.convert(attributes, ATTRIBUTE_TYPES); - if(changedValues.containsKey(TrustStore.NAME)) - { - String newName = (String) changedValues.get(TrustStore.NAME); - if(!getName().equals(newName)) - { - throw new IllegalConfigurationException("Changing the trust store name is not allowed"); - } - } - - Map<String, Object> merged = generateEffectiveAttributes(changedValues); - - String trustStorePath = changedValues.containsKey(PATH) ? (String) changedValues.get(PATH) : getPath(); - String trustStorePassword = - changedValues.containsKey(PASSWORD) ? (String) changedValues.get(PASSWORD) : getPassword(); - String trustStoreType = changedValues.containsKey(TRUST_STORE_TYPE) - ? (String) changedValues.get(TRUST_STORE_TYPE) - : getTrustStoreType(); - String trustManagerFactoryAlgorithm = - changedValues.containsKey(TRUST_MANAGER_FACTORY_ALGORITHM) - ? (String) changedValues.get(TRUST_MANAGER_FACTORY_ALGORITHM) - : getTrustManagerFactoryAlgorithm(); - - validateTrustStoreAttributes(trustStoreType, trustStorePath, - trustStorePassword, trustManagerFactoryAlgorithm); - - super.changeAttributes(changedValues); - } - - private void validateTrustStoreAttributes(String type, String trustStorePath, - String password, String trustManagerFactoryAlgorithm) - { - try - { - SSLUtil.getInitializedKeyStore(trustStorePath, password, type); - } - catch (Exception e) - { - throw new IllegalConfigurationException("Cannot instantiate trust store at " + trustStorePath, e); - } - - try - { - TrustManagerFactory.getInstance(trustManagerFactoryAlgorithm); - } - catch (NoSuchAlgorithmException e) - { - throw new IllegalConfigurationException("Unknown trustManagerFactoryAlgorithm: " + trustManagerFactoryAlgorithm); - } - } - - @Override - public Object getAttribute(String name) - { - if(STATE.equals(name)) - { - return getState(); - } - else if(DURABLE.equals(name)) - { - return isDurable(); - } - else if(org.apache.qpid.server.model.KeyStore.LIFETIME_POLICY.equals(name)) - { - return getLifetimePolicy(); - } - - return super.getAttribute(name); - } @ManagedAttribute( automate = true, mandatory = true ) - public String getPath() - { - return _path; - } + String getPath(); @ManagedAttribute( automate = true, defaultValue = "${trustStoreFile.trustManagerFactoryAlgorithm}") - public String getTrustManagerFactoryAlgorithm() - { - return _trustManagerFactoryAlgorithm; - } + String getTrustManagerFactoryAlgorithm(); @ManagedAttribute( automate = true, defaultValue = "${trustStoreFile.trustStoreType}") - public String getTrustStoreType() - { - return _trustStoreType; - } + String getTrustStoreType(); @ManagedAttribute( automate = true, defaultValue = "false" ) - public boolean isPeersOnly() - { - return _peersOnly; - } + boolean isPeersOnly(); @ManagedAttribute( secure = true, automate = true, mandatory = true ) - public String getPassword() - { - return _password; - } - - public void setPassword(String password) - { - _password = password; - } - public TrustManager[] getTrustManagers() throws GeneralSecurityException - { - String trustStorePath = _path; - String trustStorePassword = getPassword(); - String trustStoreType = _trustStoreType; - String trustManagerFactoryAlgorithm = _trustManagerFactoryAlgorithm; - - try - { - KeyStore ts = SSLUtil.getInitializedKeyStore(trustStorePath, trustStorePassword, trustStoreType); - final TrustManagerFactory tmf = TrustManagerFactory - .getInstance(trustManagerFactoryAlgorithm); - tmf.init(ts); - final Collection<TrustManager> trustManagersCol = new ArrayList<TrustManager>(); - final QpidMultipleTrustManager mulTrustManager = new QpidMultipleTrustManager(); - TrustManager[] delegateManagers = tmf.getTrustManagers(); - for (TrustManager tm : delegateManagers) - { - if (tm instanceof X509TrustManager) - { - if (_peersOnly) - { - // truststore is supposed to trust only clients which peers certificates - // are directly in the store. CA signing will not be considered. - mulTrustManager.addTrustManager(new QpidPeersOnlyTrustManager(ts, (X509TrustManager) tm)); - } - else - { - mulTrustManager.addTrustManager((X509TrustManager) tm); - } - } - else - { - trustManagersCol.add(tm); - } - } - if (! mulTrustManager.isEmpty()) - { - trustManagersCol.add(mulTrustManager); - } - - if (trustManagersCol.isEmpty()) - { - return null; - } - else - { - return trustManagersCol.toArray(new TrustManager[trustManagersCol.size()]); - } - } - catch (IOException e) - { - throw new GeneralSecurityException(e); - } - } + String getPassword(); } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/FileTrustStoreFactory.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/FileTrustStoreFactory.java index 42a0c49308..6e08104444 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/FileTrustStoreFactory.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/FileTrustStoreFactory.java @@ -20,19 +20,19 @@ */ package org.apache.qpid.server.security; -import org.apache.qpid.server.model.AbstractConfiguredObjectTypeFactory; -import org.apache.qpid.server.model.Broker; -import org.apache.qpid.server.model.ConfiguredObject; - import java.util.HashMap; import java.util.Map; import java.util.UUID; -public class FileTrustStoreFactory extends AbstractConfiguredObjectTypeFactory<FileTrustStore> +import org.apache.qpid.server.model.AbstractConfiguredObjectTypeFactory; +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.ConfiguredObject; + +public class FileTrustStoreFactory extends AbstractConfiguredObjectTypeFactory<FileTrustStoreImpl> { public FileTrustStoreFactory() { - super(FileTrustStore.class); + super(FileTrustStoreImpl.class); } protected final Broker getBroker(ConfiguredObject<?>... parents) @@ -45,12 +45,12 @@ public class FileTrustStoreFactory extends AbstractConfiguredObjectTypeFactory<F } @Override - public FileTrustStore createInstance(final Map<String, Object> attributes, final ConfiguredObject<?>... parents) + public FileTrustStoreImpl createInstance(final Map<String, Object> attributes, final ConfiguredObject<?>... parents) { HashMap<String, Object> attributesWithoutId = new HashMap<String, Object>(attributes); Object idObj = attributesWithoutId.remove(ConfiguredObject.ID); UUID id = idObj == null ? UUID.randomUUID() : idObj instanceof UUID ? (UUID) idObj : UUID.fromString(idObj.toString()); - return new FileTrustStore(id, getParent(Broker.class, parents), attributesWithoutId); + return new FileTrustStoreImpl(id, getParent(Broker.class, parents), attributesWithoutId); } } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/FileTrustStoreImpl.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/FileTrustStoreImpl.java new file mode 100644 index 0000000000..efaf565364 --- /dev/null +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/FileTrustStoreImpl.java @@ -0,0 +1,369 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security; + +import java.io.IOException; +import java.lang.reflect.Type; +import java.security.AccessControlException; +import java.security.GeneralSecurityException; +import java.security.KeyStore; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.UUID; + +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509TrustManager; + +import org.apache.qpid.server.configuration.IllegalConfigurationException; +import org.apache.qpid.server.model.AbstractConfiguredObject; +import org.apache.qpid.server.model.AuthenticationProvider; +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.ConfiguredObject; +import org.apache.qpid.server.model.IntegrityViolationException; +import org.apache.qpid.server.model.LifetimePolicy; +import org.apache.qpid.server.model.ManagedAttributeField; +import org.apache.qpid.server.model.Port; +import org.apache.qpid.server.model.State; +import org.apache.qpid.server.model.TrustStore; +import org.apache.qpid.server.security.access.Operation; +import org.apache.qpid.server.security.auth.manager.SimpleLDAPAuthenticationManagerFactory; +import org.apache.qpid.server.util.MapValueConverter; +import org.apache.qpid.transport.network.security.ssl.QpidMultipleTrustManager; +import org.apache.qpid.transport.network.security.ssl.QpidPeersOnlyTrustManager; +import org.apache.qpid.transport.network.security.ssl.SSLUtil; + +public class FileTrustStoreImpl extends AbstractConfiguredObject<FileTrustStoreImpl> implements FileTrustStore<FileTrustStoreImpl> +{ + + + @SuppressWarnings("serial") + public static final Map<String, Type> ATTRIBUTE_TYPES = Collections.unmodifiableMap(new HashMap<String, Type>(){{ + put(NAME, String.class); + put(PATH, String.class); + put(PASSWORD, String.class); + put(TRUST_STORE_TYPE, String.class); + put(PEERS_ONLY, Boolean.class); + put(TRUST_MANAGER_FACTORY_ALGORITHM, String.class); + }}); + + @ManagedAttributeField + private String _trustStoreType; + @ManagedAttributeField + private String _trustManagerFactoryAlgorithm; + @ManagedAttributeField + private String _path; + @ManagedAttributeField + private boolean _peersOnly; + @ManagedAttributeField + private String _password; + + private Broker<?> _broker; + + public FileTrustStoreImpl(UUID id, Broker<?> broker, Map<String, Object> attributes) + { + super(parentsMap(broker), + combineIdWithAttributes(id, attributes), + broker.getTaskExecutor()); + _broker = broker; + } + + @Override + public void validate() + { + super.validate(); + validateTrustStoreAttributes(_trustStoreType, _path, getPassword(), _trustManagerFactoryAlgorithm); + } + + @Override + public Collection<String> getAttributeNames() + { + return getAttributeNames(getClass()); + } + @Override + public String setName(String currentName, String desiredName) throws IllegalStateException, AccessControlException + { + throw new IllegalStateException(); + } + + @Override + public State getState() + { + return State.ACTIVE; + } + + @Override + public boolean isDurable() + { + return true; + } + + @Override + public void setDurable(boolean durable) throws IllegalStateException, AccessControlException, IllegalArgumentException + { + throw new IllegalStateException(); + } + + @Override + public LifetimePolicy getLifetimePolicy() + { + return LifetimePolicy.PERMANENT; + } + + @Override + public LifetimePolicy setLifetimePolicy(LifetimePolicy expected, LifetimePolicy desired) throws IllegalStateException, AccessControlException, + IllegalArgumentException + { + throw new IllegalStateException(); + } + + @Override + protected boolean setState(State currentState, State desiredState) + { + if(desiredState == State.DELETED) + { + // verify that it is not in use + String storeName = getName(); + + Collection<Port<?>> ports = new ArrayList<Port<?>>(_broker.getPorts()); + for (Port port : ports) + { + Collection<TrustStore> trustStores = port.getTrustStores(); + if(trustStores != null) + { + for (TrustStore store : trustStores) + { + if (storeName.equals(store.getAttribute(TrustStore.NAME))) + { + throw new IntegrityViolationException("Trust store '" + + storeName + + "' can't be deleted as it is in use by a port: " + + port.getName()); + } + } + } + } + + Collection<AuthenticationProvider> authenticationProviders = new ArrayList<AuthenticationProvider>(_broker.getAuthenticationProviders()); + for (AuthenticationProvider authProvider : authenticationProviders) + { + Object attributeType = authProvider.getAttribute(AuthenticationProvider.TYPE); + Object attributeValue = authProvider.getAttribute(SimpleLDAPAuthenticationManagerFactory.ATTRIBUTE_TRUST_STORE); + if (SimpleLDAPAuthenticationManagerFactory.PROVIDER_TYPE.equals(attributeType) + && storeName.equals(attributeValue)) + { + throw new IntegrityViolationException("Trust store '" + storeName + "' can't be deleted as it is in use by an authentication manager: " + authProvider.getName()); + } + } + deleted(); + return true; + } + return false; + } + + @Override + protected void authoriseSetDesiredState(State currentState, State desiredState) throws AccessControlException + { + if(desiredState == State.DELETED) + { + if (!_broker.getSecurityManager().authoriseConfiguringBroker(getName(), TrustStore.class, Operation.DELETE)) + { + throw new AccessControlException("Deletion of key store is denied"); + } + } + } + + @Override + protected void authoriseSetAttributes(ConfiguredObject<?> modified, Set<String> attributes) throws AccessControlException + { + if (!_broker.getSecurityManager().authoriseConfiguringBroker(getName(), TrustStore.class, Operation.UPDATE)) + { + throw new AccessControlException("Setting key store attributes is denied"); + } + } + + @Override + protected void changeAttributes(Map<String, Object> attributes) + { + Map<String, Object> changedValues = MapValueConverter.convert(attributes, ATTRIBUTE_TYPES); + if(changedValues.containsKey(TrustStore.NAME)) + { + String newName = (String) changedValues.get(TrustStore.NAME); + if(!getName().equals(newName)) + { + throw new IllegalConfigurationException("Changing the trust store name is not allowed"); + } + } + + Map<String, Object> merged = generateEffectiveAttributes(changedValues); + + String trustStorePath = changedValues.containsKey(PATH) ? (String) changedValues.get(PATH) : getPath(); + String trustStorePassword = + changedValues.containsKey(PASSWORD) ? (String) changedValues.get(PASSWORD) : getPassword(); + String trustStoreType = changedValues.containsKey(TRUST_STORE_TYPE) + ? (String) changedValues.get(TRUST_STORE_TYPE) + : getTrustStoreType(); + String trustManagerFactoryAlgorithm = + changedValues.containsKey(TRUST_MANAGER_FACTORY_ALGORITHM) + ? (String) changedValues.get(TRUST_MANAGER_FACTORY_ALGORITHM) + : getTrustManagerFactoryAlgorithm(); + + validateTrustStoreAttributes(trustStoreType, trustStorePath, + trustStorePassword, trustManagerFactoryAlgorithm); + + super.changeAttributes(changedValues); + } + + private void validateTrustStoreAttributes(String type, String trustStorePath, + String password, String trustManagerFactoryAlgorithm) + { + try + { + SSLUtil.getInitializedKeyStore(trustStorePath, password, type); + } + catch (Exception e) + { + throw new IllegalConfigurationException("Cannot instantiate trust store at " + trustStorePath, e); + } + + try + { + TrustManagerFactory.getInstance(trustManagerFactoryAlgorithm); + } + catch (NoSuchAlgorithmException e) + { + throw new IllegalConfigurationException("Unknown trustManagerFactoryAlgorithm: " + trustManagerFactoryAlgorithm); + } + } + + @Override + public Object getAttribute(String name) + { + if(STATE.equals(name)) + { + return getState(); + } + else if(DURABLE.equals(name)) + { + return isDurable(); + } + else if(org.apache.qpid.server.model.KeyStore.LIFETIME_POLICY.equals(name)) + { + return getLifetimePolicy(); + } + + return super.getAttribute(name); + } + @Override + public String getPath() + { + return _path; + } + + @Override + public String getTrustManagerFactoryAlgorithm() + { + return _trustManagerFactoryAlgorithm; + } + + @Override + public String getTrustStoreType() + { + return _trustStoreType; + } + + @Override + public boolean isPeersOnly() + { + return _peersOnly; + } + + @Override + public String getPassword() + { + return _password; + } + + public void setPassword(String password) + { + _password = password; + } + public TrustManager[] getTrustManagers() throws GeneralSecurityException + { + String trustStorePath = _path; + String trustStorePassword = getPassword(); + String trustStoreType = _trustStoreType; + String trustManagerFactoryAlgorithm = _trustManagerFactoryAlgorithm; + + try + { + KeyStore ts = SSLUtil.getInitializedKeyStore(trustStorePath, trustStorePassword, trustStoreType); + final TrustManagerFactory tmf = TrustManagerFactory + .getInstance(trustManagerFactoryAlgorithm); + tmf.init(ts); + final Collection<TrustManager> trustManagersCol = new ArrayList<TrustManager>(); + final QpidMultipleTrustManager mulTrustManager = new QpidMultipleTrustManager(); + TrustManager[] delegateManagers = tmf.getTrustManagers(); + for (TrustManager tm : delegateManagers) + { + if (tm instanceof X509TrustManager) + { + if (_peersOnly) + { + // truststore is supposed to trust only clients which peers certificates + // are directly in the store. CA signing will not be considered. + mulTrustManager.addTrustManager(new QpidPeersOnlyTrustManager(ts, (X509TrustManager) tm)); + } + else + { + mulTrustManager.addTrustManager((X509TrustManager) tm); + } + } + else + { + trustManagersCol.add(tm); + } + } + if (! mulTrustManager.isEmpty()) + { + trustManagersCol.add(mulTrustManager); + } + + if (trustManagersCol.isEmpty()) + { + return null; + } + else + { + return trustManagersCol.toArray(new TrustManager[trustManagersCol.size()]); + } + } + catch (IOException e) + { + throw new GeneralSecurityException(e); + } + } +} diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/AbstractAuthenticationManager.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/AbstractAuthenticationManager.java index 52e4168cdd..cacb08ab5c 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/AbstractAuthenticationManager.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/AbstractAuthenticationManager.java @@ -25,6 +25,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Map; +import java.util.Set; import java.util.UUID; import java.util.concurrent.atomic.AtomicReference; @@ -45,7 +46,7 @@ import org.apache.qpid.server.model.PreferencesProvider; import org.apache.qpid.server.model.State; import org.apache.qpid.server.model.User; import org.apache.qpid.server.model.VirtualHostAlias; -import org.apache.qpid.server.model.port.PortWithAuthProvider; +import org.apache.qpid.server.model.port.AbstractPortWithAuthProvider; import org.apache.qpid.server.plugin.ConfiguredObjectTypeFactory; import org.apache.qpid.server.security.SubjectCreator; import org.apache.qpid.server.security.access.Operation; @@ -203,16 +204,7 @@ public abstract class AbstractAuthenticationManager<T extends AbstractAuthentica } @Override - protected void authoriseSetAttribute(String name, Object expected, Object desired) throws AccessControlException - { - if (!_broker.getSecurityManager().authoriseConfiguringBroker(getName(), AuthenticationProvider.class, Operation.UPDATE)) - { - throw new AccessControlException("Setting of authentication provider attributes is denied"); - } - } - - @Override - protected void authoriseSetAttributes(Map<String, Object> attributes) throws AccessControlException + protected void authoriseSetAttributes(ConfiguredObject<?> modified, Set<String> attributes) throws AccessControlException { if (!_broker.getSecurityManager().authoriseConfiguringBroker(getName(), AuthenticationProvider.class, Operation.UPDATE)) { @@ -233,7 +225,8 @@ public abstract class AbstractAuthenticationManager<T extends AbstractAuthentica Collection<Port> ports = new ArrayList<Port>(_broker.getPorts()); for (Port port : ports) { - if(port instanceof PortWithAuthProvider && ((PortWithAuthProvider<?>)port).getAuthenticationProvider() == this) + if(port instanceof AbstractPortWithAuthProvider + && ((AbstractPortWithAuthProvider<?>)port).getAuthenticationProvider() == this) { throw new IntegrityViolationException("Authentication provider '" + providerName + "' is set on port " + port.getName()); } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationManager.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationManager.java index e7d64d77f8..ceb6424c3d 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationManager.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationManager.java @@ -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 @@ -15,109 +16,17 @@ * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. + * */ package org.apache.qpid.server.security.auth.manager; -import java.security.Principal; -import java.util.Map; - -import javax.security.sasl.SaslException; -import javax.security.sasl.SaslServer; - -import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.AuthenticationProvider; import org.apache.qpid.server.model.ManagedAttribute; -import org.apache.qpid.server.model.ManagedAttributeField; import org.apache.qpid.server.model.ManagedObject; -import org.apache.qpid.server.security.auth.AuthenticationResult; -import org.apache.qpid.server.security.auth.UsernamePrincipal; -import org.apache.qpid.server.security.auth.sasl.external.ExternalSaslServer; @ManagedObject( category = false, type = "External" ) -public class ExternalAuthenticationManager extends AbstractAuthenticationManager<ExternalAuthenticationManager> +public interface ExternalAuthenticationManager<T extends ExternalAuthenticationManager<T>> extends AuthenticationProvider<T> { - private static final String EXTERNAL = "EXTERNAL"; - - @ManagedAttributeField - private boolean _useFullDN; - - protected ExternalAuthenticationManager(final Broker broker, - final Map<String, Object> attributes) - { - super(broker, attributes); - } - - - @Override - public void initialise() - { - - } - @ManagedAttribute( automate = true ) - public boolean getUseFullDN() - { - return _useFullDN; - } - - @Override - public String getMechanisms() - { - return EXTERNAL; - } - - @Override - public SaslServer createSaslServer(String mechanism, String localFQDN, Principal externalPrincipal) throws SaslException - { - if(EXTERNAL.equals(mechanism)) - { - return new ExternalSaslServer(externalPrincipal, _useFullDN); - } - else - { - throw new SaslException("Unknown mechanism: " + mechanism); - } - } - - @Override - public AuthenticationResult authenticate(SaslServer server, byte[] response) - { - // Process response from the client - try - { - server.evaluateResponse(response != null ? response : new byte[0]); - - Principal principal = ((ExternalSaslServer)server).getAuthenticatedPrincipal(); - - if(principal != null) - { - return new AuthenticationResult(principal); - } - else - { - return new AuthenticationResult(AuthenticationResult.AuthenticationStatus.ERROR); - } - } - catch (SaslException e) - { - return new AuthenticationResult(AuthenticationResult.AuthenticationStatus.ERROR,e); - } - - } - - @Override - public AuthenticationResult authenticate(String username, String password) - { - return new AuthenticationResult(new UsernamePrincipal(username)); - } - - @Override - public void close() - { - } - - @Override - public void delete() - { - // nothing to do, no external resource is used - } + boolean getUseFullDN(); } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationManagerFactory.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationManagerFactory.java index 1285a79211..0191b4206d 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationManagerFactory.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationManagerFactory.java @@ -19,17 +19,17 @@ */ package org.apache.qpid.server.security.auth.manager; -import org.apache.qpid.server.model.AuthenticationProvider; -import org.apache.qpid.server.model.Broker; -import org.apache.qpid.server.model.ConfiguredObject; -import org.apache.qpid.server.util.ResourceBundleLoader; - import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Map; -public class ExternalAuthenticationManagerFactory extends AbstractAuthenticationManagerFactory<ExternalAuthenticationManager> +import org.apache.qpid.server.model.AuthenticationProvider; +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.ConfiguredObject; +import org.apache.qpid.server.util.ResourceBundleLoader; + +public class ExternalAuthenticationManagerFactory extends AbstractAuthenticationManagerFactory<ExternalAuthenticationManagerImpl> { public static final String RESOURCE_BUNDLE = "org.apache.qpid.server.security.auth.manager.ExternalAuthenticationProviderAttributeDescriptions"; public static final String PROVIDER_TYPE = "External"; @@ -41,7 +41,7 @@ public class ExternalAuthenticationManagerFactory extends AbstractAuthentication public ExternalAuthenticationManagerFactory() { - super(ExternalAuthenticationManager.class); + super(ExternalAuthenticationManagerImpl.class); } @Override @@ -57,10 +57,10 @@ public class ExternalAuthenticationManagerFactory extends AbstractAuthentication } @Override - public ExternalAuthenticationManager createInstance(final Map<String, Object> attributes, + public ExternalAuthenticationManagerImpl createInstance(final Map<String, Object> attributes, final ConfiguredObject<?>... parents) { - return new ExternalAuthenticationManager(getParent(Broker.class, parents), attributes); + return new ExternalAuthenticationManagerImpl(getParent(Broker.class, parents), attributes); } } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationManagerImpl.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationManagerImpl.java new file mode 100644 index 0000000000..f5b65092b2 --- /dev/null +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationManagerImpl.java @@ -0,0 +1,121 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.qpid.server.security.auth.manager; + +import java.security.Principal; +import java.util.Map; + +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; + +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.ManagedAttributeField; +import org.apache.qpid.server.security.auth.AuthenticationResult; +import org.apache.qpid.server.security.auth.UsernamePrincipal; +import org.apache.qpid.server.security.auth.sasl.external.ExternalSaslServer; + +public class ExternalAuthenticationManagerImpl extends AbstractAuthenticationManager<ExternalAuthenticationManagerImpl> + implements ExternalAuthenticationManager<ExternalAuthenticationManagerImpl> +{ + private static final String EXTERNAL = "EXTERNAL"; + + @ManagedAttributeField + private boolean _useFullDN; + + protected ExternalAuthenticationManagerImpl(final Broker broker, + final Map<String, Object> attributes) + { + super(broker, attributes); + } + + + @Override + public void initialise() + { + + } + + @Override + public boolean getUseFullDN() + { + return _useFullDN; + } + + @Override + public String getMechanisms() + { + return EXTERNAL; + } + + @Override + public SaslServer createSaslServer(String mechanism, String localFQDN, Principal externalPrincipal) throws SaslException + { + if(EXTERNAL.equals(mechanism)) + { + return new ExternalSaslServer(externalPrincipal, _useFullDN); + } + else + { + throw new SaslException("Unknown mechanism: " + mechanism); + } + } + + @Override + public AuthenticationResult authenticate(SaslServer server, byte[] response) + { + // Process response from the client + try + { + server.evaluateResponse(response != null ? response : new byte[0]); + + Principal principal = ((ExternalSaslServer)server).getAuthenticatedPrincipal(); + + if(principal != null) + { + return new AuthenticationResult(principal); + } + else + { + return new AuthenticationResult(AuthenticationResult.AuthenticationStatus.ERROR); + } + } + catch (SaslException e) + { + return new AuthenticationResult(AuthenticationResult.AuthenticationStatus.ERROR,e); + } + + } + + @Override + public AuthenticationResult authenticate(String username, String password) + { + return new AuthenticationResult(new UsernamePrincipal(username)); + } + + @Override + public void close() + { + } + + @Override + public void delete() + { + // nothing to do, no external resource is used + } +} diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java index c51ab38328..e454b1b50a 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/PrincipalDatabaseAuthenticationManager.java @@ -31,6 +31,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import javax.security.auth.login.AccountNotFoundException; import javax.security.sasl.SaslException; @@ -48,7 +49,7 @@ import org.apache.qpid.server.security.auth.database.PrincipalDatabase; public abstract class PrincipalDatabaseAuthenticationManager<T extends PrincipalDatabaseAuthenticationManager<T>> extends AbstractAuthenticationManager<T> - implements PasswordCredentialManagingAuthenticationProvider<T> + implements ExternalFileBasedAuthenticationManager<T> { private static final Logger LOGGER = Logger.getLogger(PrincipalDatabaseAuthenticationManager.class); @@ -96,7 +97,7 @@ public abstract class PrincipalDatabaseAuthenticationManager<T extends Principal protected abstract PrincipalDatabase createDatabase(); - @ManagedAttribute( automate = true , mandatory = true ) + @Override public String getPath() { return _path; @@ -316,30 +317,25 @@ public abstract class PrincipalDatabaseAuthenticationManager<T extends Principal super.childRemoved(child); } - protected void validateAttributes(Map<String, Object> attributes) + @Override + protected void validateChange(final ConfiguredObject<?> updatedObject, final Set<String> changedAttributes) { - super.validateChangeAttributes(attributes); + super.validateChange(updatedObject, changedAttributes); - String newName = (String)attributes.get(NAME); - String currentName = getName(); - if (!currentName.equals(newName)) + ExternalFileBasedAuthenticationManager<?> updated = (ExternalFileBasedAuthenticationManager<?>) updatedObject; + if (changedAttributes.contains(NAME) && !getName().equals(updated.getName())) { throw new IllegalConfigurationException("Changing the name of authentication provider is not supported"); } - String newType = (String)attributes.get(TYPE); - String currentType = (String)getAttribute(TYPE); - if (!currentType.equals(newType)) + if (changedAttributes.contains(TYPE) && !getType().equals(updated.getType())) { throw new IllegalConfigurationException("Changing the type of authentication provider is not supported"); } - } @Override protected void changeAttributes(Map<String, Object> attributes) { - Map<String, Object> effectiveAttributes = super.generateEffectiveAttributes(attributes); - validateAttributes(effectiveAttributes); super.changeAttributes(attributes); initialise(); diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManager.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManager.java index 259780f4ee..2e3568ff57 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManager.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManager.java @@ -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 @@ -15,456 +16,33 @@ * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. + * */ - package org.apache.qpid.server.security.auth.manager; -import java.io.IOException; -import java.security.GeneralSecurityException; -import java.security.KeyManagementException; -import java.security.NoSuchAlgorithmException; -import java.security.Principal; -import java.util.Hashtable; -import java.util.Map; - -import javax.naming.AuthenticationException; -import javax.naming.Context; -import javax.naming.NamingEnumeration; -import javax.naming.NamingException; -import javax.naming.directory.InitialDirContext; -import javax.naming.directory.SearchControls; -import javax.naming.directory.SearchResult; -import javax.net.SocketFactory; -import javax.net.ssl.SSLContext; -import javax.security.auth.callback.Callback; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.callback.NameCallback; -import javax.security.auth.callback.UnsupportedCallbackException; -import javax.security.sasl.AuthorizeCallback; -import javax.security.sasl.SaslException; -import javax.security.sasl.SaslServer; - -import org.apache.log4j.Logger; - -import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.AuthenticationProvider; import org.apache.qpid.server.model.ManagedAttribute; -import org.apache.qpid.server.model.ManagedAttributeField; import org.apache.qpid.server.model.ManagedObject; import org.apache.qpid.server.model.TrustStore; -import org.apache.qpid.server.security.auth.AuthenticationResult; -import org.apache.qpid.server.security.auth.AuthenticationResult.AuthenticationStatus; -import org.apache.qpid.server.security.auth.UsernamePrincipal; -import org.apache.qpid.server.security.auth.manager.ldap.AbstractLDAPSSLSocketFactory; -import org.apache.qpid.server.security.auth.manager.ldap.LDAPSSLSocketFactoryGenerator; -import org.apache.qpid.server.security.auth.sasl.plain.PlainPasswordCallback; -import org.apache.qpid.server.security.auth.sasl.plain.PlainSaslServer; -import org.apache.qpid.server.util.ServerScopedRuntimeException; -import org.apache.qpid.server.util.StringUtil; -import org.apache.qpid.ssl.SSLContextFactory; @ManagedObject( category = false, type = "SimpleLDAP" ) -public class SimpleLDAPAuthenticationManager extends AbstractAuthenticationManager<SimpleLDAPAuthenticationManager> +public interface SimpleLDAPAuthenticationManager<X extends SimpleLDAPAuthenticationManager<X>> extends AuthenticationProvider<X> { - private static final Logger _logger = Logger.getLogger(SimpleLDAPAuthenticationManager.class); - - /** - * Environment key to instruct {@link InitialDirContext} to override the socket factory. - */ - private static final String JAVA_NAMING_LDAP_FACTORY_SOCKET = "java.naming.ldap.factory.socket"; - - @ManagedAttributeField - private String _providerUrl; - @ManagedAttributeField - private String _providerAuthUrl; - @ManagedAttributeField - private String _searchContext; - @ManagedAttributeField - private String _searchFilter; - @ManagedAttributeField - private String _ldapContextFactory; - - - /** - * Trust store - typically used when the Directory has been secured with a certificate signed by a - * private CA (or self-signed certificate). - */ - @ManagedAttributeField - private TrustStore _trustStore; - - /** - * Dynamically created SSL Socket Factory implementation used in the case where user has specified a trust store. - */ - private Class<? extends SocketFactory> _sslSocketFactoryOverrideClass; - - protected SimpleLDAPAuthenticationManager(final Broker broker, - final Map<String, Object> attributes) - { - super(broker, attributes); - } - - - @Override - public void initialise() - { - _sslSocketFactoryOverrideClass = createSslSocketFactoryOverrideClass(); - - validateInitialDirContext(); - } - @ManagedAttribute( automate = true ) - public String getProviderUrl() - { - return _providerUrl; - } + String getProviderUrl(); @ManagedAttribute( automate = true ) - public String getProviderAuthUrl() - { - return _providerAuthUrl; - } + String getProviderAuthUrl(); @ManagedAttribute( automate = true ) - public String getSearchContext() - { - return _searchContext; - } + String getSearchContext(); @ManagedAttribute( automate = true ) - public String getSearchFilter() - { - return _searchFilter; - } + String getSearchFilter(); @ManagedAttribute( automate = true ) - public String getLdapContextFactory() - { - return _ldapContextFactory; - } + String getLdapContextFactory(); @ManagedAttribute( automate = true ) - public TrustStore getTrustStore() - { - return _trustStore; - } - - - @Override - public String getMechanisms() - { - return PlainSaslServer.MECHANISM; - } - - @Override - public SaslServer createSaslServer(String mechanism, String localFQDN, Principal externalPrincipal) throws SaslException - { - if(PlainSaslServer.MECHANISM.equals(mechanism)) - { - return new PlainSaslServer(new SimpleLDAPPlainCallbackHandler()); - } - else - { - throw new SaslException("Unknown mechanism: " + mechanism); - } - } - - @Override - public AuthenticationResult authenticate(SaslServer server, byte[] response) - { - try - { - // Process response from the client - byte[] challenge = server.evaluateResponse(response != null ? response : new byte[0]); - - if (server.isComplete()) - { - String authorizationID = server.getAuthorizationID(); - if (_logger.isDebugEnabled()) - { - _logger.debug("Authenticated as " + authorizationID); - } - - return new AuthenticationResult(new UsernamePrincipal(authorizationID)); - } - else - { - return new AuthenticationResult(challenge, AuthenticationResult.AuthenticationStatus.CONTINUE); - } - } - catch (SaslException e) - { - return new AuthenticationResult(AuthenticationResult.AuthenticationStatus.ERROR, e); - } - } - - @Override - public AuthenticationResult authenticate(String username, String password) - { - try - { - AuthenticationResult result = doLDAPNameAuthentication(getNameFromId(username), password); - if(result.getStatus() == AuthenticationStatus.SUCCESS) - { - //Return a result based on the supplied username rather than the search name - return new AuthenticationResult(new UsernamePrincipal(username)); - } - else - { - return result; - } - } - catch (NamingException e) - { - return new AuthenticationResult(AuthenticationResult.AuthenticationStatus.ERROR, e); - } - } - - private AuthenticationResult doLDAPNameAuthentication(String name, String password) - { - if(name == null) - { - //The search didn't return anything, class as not-authenticated before it NPEs below - return new AuthenticationResult(AuthenticationStatus.CONTINUE); - } - - String providerAuthUrl = _providerAuthUrl == null ? _providerUrl : _providerAuthUrl; - Hashtable<String, Object> env = createInitialDirContextEnvironment(providerAuthUrl); - - env.put(Context.SECURITY_AUTHENTICATION, "simple"); - env.put(Context.SECURITY_PRINCIPAL, name); - env.put(Context.SECURITY_CREDENTIALS, password); - - InitialDirContext ctx = null; - try - { - ctx = createInitialDirContext(env); - - //Authentication succeeded - return new AuthenticationResult(new UsernamePrincipal(name)); - } - catch(AuthenticationException ae) - { - //Authentication failed - return new AuthenticationResult(AuthenticationStatus.CONTINUE); - } - catch (NamingException e) - { - //Some other failure - return new AuthenticationResult(AuthenticationResult.AuthenticationStatus.ERROR, e); - } - finally - { - if(ctx != null) - { - closeSafely(ctx); - } - } - } - - @Override - public void close() - { - } - - private Hashtable<String, Object> createInitialDirContextEnvironment(String providerUrl) - { - Hashtable<String,Object> env = new Hashtable<String,Object>(); - env.put(Context.INITIAL_CONTEXT_FACTORY, _ldapContextFactory); - env.put(Context.PROVIDER_URL, providerUrl); - return env; - } - - private InitialDirContext createInitialDirContext(Hashtable<String, Object> env) throws NamingException - { - ClassLoader existingContextClassLoader = null; - - boolean isLdaps = String.valueOf(env.get(Context.PROVIDER_URL)).trim().toLowerCase().startsWith("ldaps:"); - - boolean revertContentClassLoader = false; - try - { - if (isLdaps && _sslSocketFactoryOverrideClass != null) - { - existingContextClassLoader = Thread.currentThread().getContextClassLoader(); - env.put(JAVA_NAMING_LDAP_FACTORY_SOCKET, _sslSocketFactoryOverrideClass.getName()); - Thread.currentThread().setContextClassLoader(_sslSocketFactoryOverrideClass.getClassLoader()); - revertContentClassLoader = true; - } - return new InitialDirContext(env); - } - finally - { - if (revertContentClassLoader) - { - Thread.currentThread().setContextClassLoader(existingContextClassLoader); - } - } - } - - /** - * If a trust store has been specified, create a {@link SSLContextFactory} class that is - * associated with the {@link SSLContext} generated from that trust store. - * - * @return generated socket factory class - */ - private Class<? extends SocketFactory> createSslSocketFactoryOverrideClass() - { - if (_trustStore != null) - { - String clazzName = new StringUtil().createUniqueJavaName(getName()); - SSLContext sslContext = null; - try - { - sslContext = SSLContext.getInstance("TLS"); - sslContext.init(null, _trustStore.getTrustManagers(), null); - } - catch (NoSuchAlgorithmException e) - { - _logger.error("Exception creating SSLContext", e); - throw new ServerScopedRuntimeException("Error creating SSLContext for trust store : " + _trustStore.getName() , e); - } - catch (KeyManagementException e) - { - _logger.error("Exception creating SSLContext", e); - throw new ServerScopedRuntimeException("Error creating SSLContext for trust store : " + _trustStore.getName() , e); - } - catch (GeneralSecurityException e) - { - _logger.error("Exception creating SSLContext", e); - throw new ServerScopedRuntimeException("Error creating SSLContext for trust store : " + _trustStore.getName() , e); - } - - Class<? extends AbstractLDAPSSLSocketFactory> clazz = LDAPSSLSocketFactoryGenerator.createSubClass(clazzName, sslContext.getSocketFactory()); - if (_logger.isDebugEnabled()) - { - _logger.debug("Connection to Directory will use custom SSL socket factory : " + clazz); - } - return clazz; - } - - return null; - } - - private void validateInitialDirContext() - { - Hashtable<String,Object> env = createInitialDirContextEnvironment(_providerUrl); - env.put(Context.SECURITY_AUTHENTICATION, "none"); - - InitialDirContext ctx = null; - try - { - ctx = createInitialDirContext(env); - } - catch (NamingException e) - { - throw new ServerScopedRuntimeException("Unable to establish anonymous connection to the ldap server at " + _providerUrl, e); - } - finally - { - closeSafely(ctx); - } - } - - - private class SimpleLDAPPlainCallbackHandler implements CallbackHandler - { - @Override - public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException - { - String name = null; - String password = null; - AuthenticationResult authenticated = null; - for(Callback callback : callbacks) - { - if (callback instanceof NameCallback) - { - String id = ((NameCallback) callback).getDefaultName(); - try - { - name = getNameFromId(id); - } - catch (NamingException e) - { - _logger.warn("SASL Authentication Exception", e); - } - if(password != null) - { - authenticated = doLDAPNameAuthentication(name, password); - } - } - else if (callback instanceof PlainPasswordCallback) - { - password = ((PlainPasswordCallback)callback).getPlainPassword(); - if(name != null) - { - authenticated = doLDAPNameAuthentication(name, password); - if(authenticated.getStatus()== AuthenticationResult.AuthenticationStatus.SUCCESS) - { - ((PlainPasswordCallback)callback).setAuthenticated(true); - } - } - } - else if (callback instanceof AuthorizeCallback) - { - ((AuthorizeCallback) callback).setAuthorized(authenticated != null && authenticated.getStatus() == AuthenticationResult.AuthenticationStatus.SUCCESS); - } - else - { - throw new UnsupportedCallbackException(callback); - } - } - } - } - - private String getNameFromId(String id) throws NamingException - { - Hashtable<String,Object> env = createInitialDirContextEnvironment(_providerUrl); - - env.put(Context.SECURITY_AUTHENTICATION, "none"); - InitialDirContext ctx = createInitialDirContext(env); - - try - { - SearchControls searchControls = new SearchControls(); - searchControls.setReturningAttributes(new String[] {}); - searchControls.setCountLimit(1l); - searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE); - NamingEnumeration<?> namingEnum = null; - String name = null; - - namingEnum = ctx.search(_searchContext, _searchFilter, new String[] { id }, searchControls); - if(namingEnum.hasMore()) - { - SearchResult result = (SearchResult) namingEnum.next(); - name = result.getNameInNamespace(); - } - return name; - } - finally - { - closeSafely(ctx); - } - - } - - private void closeSafely(InitialDirContext ctx) - { - try - { - if (ctx != null) - { - ctx.close(); - ctx = null; - } - } - catch (Exception e) - { - _logger.warn("Exception closing InitialDirContext", e); - } - } - - @Override - public void delete() - { - // nothing to do, no external resource is used - } + TrustStore getTrustStore(); } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManagerFactory.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManagerFactory.java index 79c7e71255..28163b8800 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManagerFactory.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManagerFactory.java @@ -19,17 +19,17 @@ */ package org.apache.qpid.server.security.auth.manager; -import org.apache.qpid.server.model.AuthenticationProvider; -import org.apache.qpid.server.model.Broker; -import org.apache.qpid.server.model.ConfiguredObject; -import org.apache.qpid.server.util.ResourceBundleLoader; - import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Map; -public class SimpleLDAPAuthenticationManagerFactory extends AbstractAuthenticationManagerFactory<SimpleLDAPAuthenticationManager> +import org.apache.qpid.server.model.AuthenticationProvider; +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.ConfiguredObject; +import org.apache.qpid.server.util.ResourceBundleLoader; + +public class SimpleLDAPAuthenticationManagerFactory extends AbstractAuthenticationManagerFactory<SimpleLDAPAuthenticationManagerImpl> { public static final String RESOURCE_BUNDLE = "org.apache.qpid.server.security.auth.manager.SimpleLDAPAuthenticationProviderAttributeDescriptions"; @@ -55,7 +55,7 @@ public class SimpleLDAPAuthenticationManagerFactory extends AbstractAuthenticati public SimpleLDAPAuthenticationManagerFactory() { - super(SimpleLDAPAuthenticationManager.class); + super(SimpleLDAPAuthenticationManagerImpl.class); } @Override @@ -71,10 +71,10 @@ public class SimpleLDAPAuthenticationManagerFactory extends AbstractAuthenticati } @Override - public SimpleLDAPAuthenticationManager createInstance(final Map<String, Object> attributes, + public SimpleLDAPAuthenticationManagerImpl createInstance(final Map<String, Object> attributes, final ConfiguredObject<?>... parents) { - return new SimpleLDAPAuthenticationManager(getParent(Broker.class, parents), attributes); + return new SimpleLDAPAuthenticationManagerImpl(getParent(Broker.class, parents), attributes); } } diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManagerImpl.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManagerImpl.java new file mode 100644 index 0000000000..3756931c64 --- /dev/null +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/SimpleLDAPAuthenticationManagerImpl.java @@ -0,0 +1,468 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.qpid.server.security.auth.manager; + +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.security.Principal; +import java.util.Hashtable; +import java.util.Map; + +import javax.naming.AuthenticationException; +import javax.naming.Context; +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +import javax.naming.directory.InitialDirContext; +import javax.naming.directory.SearchControls; +import javax.naming.directory.SearchResult; +import javax.net.SocketFactory; +import javax.net.ssl.SSLContext; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.UnsupportedCallbackException; +import javax.security.sasl.AuthorizeCallback; +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; + +import org.apache.log4j.Logger; + +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.ManagedAttributeField; +import org.apache.qpid.server.model.TrustStore; +import org.apache.qpid.server.security.auth.AuthenticationResult; +import org.apache.qpid.server.security.auth.AuthenticationResult.AuthenticationStatus; +import org.apache.qpid.server.security.auth.UsernamePrincipal; +import org.apache.qpid.server.security.auth.manager.ldap.AbstractLDAPSSLSocketFactory; +import org.apache.qpid.server.security.auth.manager.ldap.LDAPSSLSocketFactoryGenerator; +import org.apache.qpid.server.security.auth.sasl.plain.PlainPasswordCallback; +import org.apache.qpid.server.security.auth.sasl.plain.PlainSaslServer; +import org.apache.qpid.server.util.ServerScopedRuntimeException; +import org.apache.qpid.server.util.StringUtil; +import org.apache.qpid.ssl.SSLContextFactory; + +public class SimpleLDAPAuthenticationManagerImpl extends AbstractAuthenticationManager<SimpleLDAPAuthenticationManagerImpl> + implements SimpleLDAPAuthenticationManager<SimpleLDAPAuthenticationManagerImpl> +{ + private static final Logger _logger = Logger.getLogger(SimpleLDAPAuthenticationManagerImpl.class); + + /** + * Environment key to instruct {@link InitialDirContext} to override the socket factory. + */ + private static final String JAVA_NAMING_LDAP_FACTORY_SOCKET = "java.naming.ldap.factory.socket"; + + @ManagedAttributeField + private String _providerUrl; + @ManagedAttributeField + private String _providerAuthUrl; + @ManagedAttributeField + private String _searchContext; + @ManagedAttributeField + private String _searchFilter; + @ManagedAttributeField + private String _ldapContextFactory; + + + /** + * Trust store - typically used when the Directory has been secured with a certificate signed by a + * private CA (or self-signed certificate). + */ + @ManagedAttributeField + private TrustStore _trustStore; + + /** + * Dynamically created SSL Socket Factory implementation used in the case where user has specified a trust store. + */ + private Class<? extends SocketFactory> _sslSocketFactoryOverrideClass; + + protected SimpleLDAPAuthenticationManagerImpl(final Broker broker, + final Map<String, Object> attributes) + { + super(broker, attributes); + } + + + @Override + public void initialise() + { + _sslSocketFactoryOverrideClass = createSslSocketFactoryOverrideClass(); + + validateInitialDirContext(); + } + + @Override + public String getProviderUrl() + { + return _providerUrl; + } + + @Override + public String getProviderAuthUrl() + { + return _providerAuthUrl; + } + + @Override + public String getSearchContext() + { + return _searchContext; + } + + @Override + public String getSearchFilter() + { + return _searchFilter; + } + + @Override + public String getLdapContextFactory() + { + return _ldapContextFactory; + } + + @Override + public TrustStore getTrustStore() + { + return _trustStore; + } + + + @Override + public String getMechanisms() + { + return PlainSaslServer.MECHANISM; + } + + @Override + public SaslServer createSaslServer(String mechanism, String localFQDN, Principal externalPrincipal) throws SaslException + { + if(PlainSaslServer.MECHANISM.equals(mechanism)) + { + return new PlainSaslServer(new SimpleLDAPPlainCallbackHandler()); + } + else + { + throw new SaslException("Unknown mechanism: " + mechanism); + } + } + + @Override + public AuthenticationResult authenticate(SaslServer server, byte[] response) + { + try + { + // Process response from the client + byte[] challenge = server.evaluateResponse(response != null ? response : new byte[0]); + + if (server.isComplete()) + { + String authorizationID = server.getAuthorizationID(); + if (_logger.isDebugEnabled()) + { + _logger.debug("Authenticated as " + authorizationID); + } + + return new AuthenticationResult(new UsernamePrincipal(authorizationID)); + } + else + { + return new AuthenticationResult(challenge, AuthenticationResult.AuthenticationStatus.CONTINUE); + } + } + catch (SaslException e) + { + return new AuthenticationResult(AuthenticationResult.AuthenticationStatus.ERROR, e); + } + } + + @Override + public AuthenticationResult authenticate(String username, String password) + { + try + { + AuthenticationResult result = doLDAPNameAuthentication(getNameFromId(username), password); + if(result.getStatus() == AuthenticationStatus.SUCCESS) + { + //Return a result based on the supplied username rather than the search name + return new AuthenticationResult(new UsernamePrincipal(username)); + } + else + { + return result; + } + } + catch (NamingException e) + { + return new AuthenticationResult(AuthenticationResult.AuthenticationStatus.ERROR, e); + } + } + + private AuthenticationResult doLDAPNameAuthentication(String name, String password) + { + if(name == null) + { + //The search didn't return anything, class as not-authenticated before it NPEs below + return new AuthenticationResult(AuthenticationStatus.CONTINUE); + } + + String providerAuthUrl = _providerAuthUrl == null ? _providerUrl : _providerAuthUrl; + Hashtable<String, Object> env = createInitialDirContextEnvironment(providerAuthUrl); + + env.put(Context.SECURITY_AUTHENTICATION, "simple"); + env.put(Context.SECURITY_PRINCIPAL, name); + env.put(Context.SECURITY_CREDENTIALS, password); + + InitialDirContext ctx = null; + try + { + ctx = createInitialDirContext(env); + + //Authentication succeeded + return new AuthenticationResult(new UsernamePrincipal(name)); + } + catch(AuthenticationException ae) + { + //Authentication failed + return new AuthenticationResult(AuthenticationStatus.CONTINUE); + } + catch (NamingException e) + { + //Some other failure + return new AuthenticationResult(AuthenticationResult.AuthenticationStatus.ERROR, e); + } + finally + { + if(ctx != null) + { + closeSafely(ctx); + } + } + } + + @Override + public void close() + { + } + + private Hashtable<String, Object> createInitialDirContextEnvironment(String providerUrl) + { + Hashtable<String,Object> env = new Hashtable<String,Object>(); + env.put(Context.INITIAL_CONTEXT_FACTORY, _ldapContextFactory); + env.put(Context.PROVIDER_URL, providerUrl); + return env; + } + + private InitialDirContext createInitialDirContext(Hashtable<String, Object> env) throws NamingException + { + ClassLoader existingContextClassLoader = null; + + boolean isLdaps = String.valueOf(env.get(Context.PROVIDER_URL)).trim().toLowerCase().startsWith("ldaps:"); + + boolean revertContentClassLoader = false; + try + { + if (isLdaps && _sslSocketFactoryOverrideClass != null) + { + existingContextClassLoader = Thread.currentThread().getContextClassLoader(); + env.put(JAVA_NAMING_LDAP_FACTORY_SOCKET, _sslSocketFactoryOverrideClass.getName()); + Thread.currentThread().setContextClassLoader(_sslSocketFactoryOverrideClass.getClassLoader()); + revertContentClassLoader = true; + } + return new InitialDirContext(env); + } + finally + { + if (revertContentClassLoader) + { + Thread.currentThread().setContextClassLoader(existingContextClassLoader); + } + } + } + + /** + * If a trust store has been specified, create a {@link SSLContextFactory} class that is + * associated with the {@link SSLContext} generated from that trust store. + * + * @return generated socket factory class + */ + private Class<? extends SocketFactory> createSslSocketFactoryOverrideClass() + { + if (_trustStore != null) + { + String clazzName = new StringUtil().createUniqueJavaName(getName()); + SSLContext sslContext = null; + try + { + sslContext = SSLContext.getInstance("TLS"); + sslContext.init(null, _trustStore.getTrustManagers(), null); + } + catch (NoSuchAlgorithmException e) + { + _logger.error("Exception creating SSLContext", e); + throw new ServerScopedRuntimeException("Error creating SSLContext for trust store : " + _trustStore.getName() , e); + } + catch (KeyManagementException e) + { + _logger.error("Exception creating SSLContext", e); + throw new ServerScopedRuntimeException("Error creating SSLContext for trust store : " + _trustStore.getName() , e); + } + catch (GeneralSecurityException e) + { + _logger.error("Exception creating SSLContext", e); + throw new ServerScopedRuntimeException("Error creating SSLContext for trust store : " + _trustStore.getName() , e); + } + + Class<? extends AbstractLDAPSSLSocketFactory> clazz = LDAPSSLSocketFactoryGenerator.createSubClass(clazzName, sslContext.getSocketFactory()); + if (_logger.isDebugEnabled()) + { + _logger.debug("Connection to Directory will use custom SSL socket factory : " + clazz); + } + return clazz; + } + + return null; + } + + private void validateInitialDirContext() + { + Hashtable<String,Object> env = createInitialDirContextEnvironment(_providerUrl); + env.put(Context.SECURITY_AUTHENTICATION, "none"); + + InitialDirContext ctx = null; + try + { + ctx = createInitialDirContext(env); + } + catch (NamingException e) + { + throw new ServerScopedRuntimeException("Unable to establish anonymous connection to the ldap server at " + _providerUrl, e); + } + finally + { + closeSafely(ctx); + } + } + + + private class SimpleLDAPPlainCallbackHandler implements CallbackHandler + { + @Override + public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException + { + String name = null; + String password = null; + AuthenticationResult authenticated = null; + for(Callback callback : callbacks) + { + if (callback instanceof NameCallback) + { + String id = ((NameCallback) callback).getDefaultName(); + try + { + name = getNameFromId(id); + } + catch (NamingException e) + { + _logger.warn("SASL Authentication Exception", e); + } + if(password != null) + { + authenticated = doLDAPNameAuthentication(name, password); + } + } + else if (callback instanceof PlainPasswordCallback) + { + password = ((PlainPasswordCallback)callback).getPlainPassword(); + if(name != null) + { + authenticated = doLDAPNameAuthentication(name, password); + if(authenticated.getStatus()== AuthenticationResult.AuthenticationStatus.SUCCESS) + { + ((PlainPasswordCallback)callback).setAuthenticated(true); + } + } + } + else if (callback instanceof AuthorizeCallback) + { + ((AuthorizeCallback) callback).setAuthorized(authenticated != null && authenticated.getStatus() == AuthenticationResult.AuthenticationStatus.SUCCESS); + } + else + { + throw new UnsupportedCallbackException(callback); + } + } + } + } + + private String getNameFromId(String id) throws NamingException + { + Hashtable<String,Object> env = createInitialDirContextEnvironment(_providerUrl); + + env.put(Context.SECURITY_AUTHENTICATION, "none"); + InitialDirContext ctx = createInitialDirContext(env); + + try + { + SearchControls searchControls = new SearchControls(); + searchControls.setReturningAttributes(new String[] {}); + searchControls.setCountLimit(1l); + searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE); + NamingEnumeration<?> namingEnum = null; + String name = null; + + namingEnum = ctx.search(_searchContext, _searchFilter, new String[] { id }, searchControls); + if(namingEnum.hasMore()) + { + SearchResult result = (SearchResult) namingEnum.next(); + name = result.getNameInNamespace(); + } + return name; + } + finally + { + closeSafely(ctx); + } + + } + + private void closeSafely(InitialDirContext ctx) + { + try + { + if (ctx != null) + { + ctx.close(); + ctx = null; + } + } + catch (Exception e) + { + _logger.warn("Exception closing InitialDirContext", e); + } + } + + @Override + public void delete() + { + // nothing to do, no external resource is used + } +} diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/virtualhost/AbstractVirtualHost.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/virtualhost/AbstractVirtualHost.java index 340b3ff08c..007baf3422 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/virtualhost/AbstractVirtualHost.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/virtualhost/AbstractVirtualHost.java @@ -30,6 +30,7 @@ import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.UUID; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ScheduledFuture; @@ -302,16 +303,7 @@ public abstract class AbstractVirtualHost<X extends AbstractVirtualHost<X>> exte } @Override - protected void authoriseSetAttribute(String name, Object expected, Object desired) throws AccessControlException - { - if (!_broker.getSecurityManager().authoriseConfiguringBroker(getName(), org.apache.qpid.server.model.VirtualHost.class, Operation.UPDATE)) - { - throw new AccessControlException("Setting of virtual host attributes is denied"); - } - } - - @Override - protected void authoriseSetAttributes(Map<String, Object> attributes) throws AccessControlException + protected void authoriseSetAttributes(ConfiguredObject<?> modified, Set<String> attributes) throws AccessControlException { if (!_broker.getSecurityManager().authoriseConfiguringBroker(getName(), org.apache.qpid.server.model.VirtualHost.class, Operation.UPDATE)) { diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/configuration/BrokerConfigurationStoreCreatorTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/configuration/BrokerConfigurationStoreCreatorTest.java index b1c60351ee..8df5576715 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/configuration/BrokerConfigurationStoreCreatorTest.java +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/configuration/BrokerConfigurationStoreCreatorTest.java @@ -43,6 +43,7 @@ import org.apache.qpid.server.model.Broker; import org.apache.qpid.server.model.ConfiguredObjectFactory; import org.apache.qpid.server.model.Model; import org.apache.qpid.server.model.SystemContext; +import org.apache.qpid.server.model.SystemContextImpl; import org.apache.qpid.test.utils.QpidTestCase; import org.apache.qpid.test.utils.TestFileUtils; import org.apache.qpid.util.FileUtils; @@ -68,7 +69,7 @@ public class BrokerConfigurationStoreCreatorTest extends QpidTestCase _userStoreLocation = new File(TMP_FOLDER, "_store_" + System.currentTimeMillis() + "_" + getTestName()); final BrokerOptions brokerOptions = mock(BrokerOptions.class); when(brokerOptions.getConfigurationStoreLocation()).thenReturn(_userStoreLocation.getAbsolutePath()); - _systemContext = new SystemContext(new TaskExecutor(), + _systemContext = new SystemContextImpl(new TaskExecutor(), new ConfiguredObjectFactory(Model.getInstance()), mock(EventLogger.class), mock(LogRecorder.class), diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/configuration/startup/BrokerRecovererTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/configuration/startup/BrokerRecovererTest.java index edd6b647d6..04e41aa584 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/configuration/startup/BrokerRecovererTest.java +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/configuration/startup/BrokerRecovererTest.java @@ -47,11 +47,13 @@ import org.apache.qpid.server.model.GroupProvider; import org.apache.qpid.server.model.Model; import org.apache.qpid.server.model.Port; import org.apache.qpid.server.model.SystemContext; +import org.apache.qpid.server.model.SystemContextImpl; import org.apache.qpid.server.model.VirtualHost; import org.apache.qpid.server.store.ConfiguredObjectRecord; import org.apache.qpid.server.store.ConfiguredObjectRecordImpl; import org.apache.qpid.server.store.MessageStore; import org.apache.qpid.server.store.TestMemoryMessageStore; +import org.apache.qpid.server.store.UnresolvedConfiguredObject; public class BrokerRecovererTest extends TestCase { @@ -71,7 +73,7 @@ public class BrokerRecovererTest extends TestCase super.setUp(); _configuredObjectFactory = new ConfiguredObjectFactory(Model.getInstance()); - _systemContext = new SystemContext(mock(TaskExecutor.class), + _systemContext = new SystemContextImpl(mock(TaskExecutor.class), _configuredObjectFactory, mock(EventLogger.class), mock(LogRecorder.class), mock(BrokerOptions.class)); when(_brokerEntry.getId()).thenReturn(_brokerId); @@ -305,7 +307,10 @@ public class BrokerRecovererTest extends TestCase try { - Broker broker = (Broker) _configuredObjectFactory.recover(_brokerEntry, _systemContext).resolve(); + UnresolvedConfiguredObject<? extends ConfiguredObject> recover = + _configuredObjectFactory.recover(_brokerEntry, _systemContext); + + Broker<?> broker = (Broker<?>) recover.resolve(); broker.open(); fail("The broker creation should fail due to unsupported model version"); } @@ -329,7 +334,9 @@ public class BrokerRecovererTest extends TestCase try { - Broker broker = (Broker) _configuredObjectFactory.recover(_brokerEntry, _systemContext).resolve(); + UnresolvedConfiguredObject<? extends ConfiguredObject> recover = + _configuredObjectFactory.recover(_brokerEntry, _systemContext); + Broker<?> broker = (Broker<?>) recover.resolve(); broker.open(); fail("The broker creation should fail due to unsupported model version"); } diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/configuration/startup/FileTrustStoreCreationTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/configuration/startup/FileTrustStoreCreationTest.java index 66f31a4e3d..f5e6772572 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/configuration/startup/FileTrustStoreCreationTest.java +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/configuration/startup/FileTrustStoreCreationTest.java @@ -34,6 +34,7 @@ import org.apache.qpid.server.model.AbstractConfiguredObject; import org.apache.qpid.server.model.Broker; import org.apache.qpid.server.model.TrustStore; import org.apache.qpid.server.security.FileTrustStore; +import org.apache.qpid.server.security.FileTrustStoreImpl; import org.apache.qpid.server.security.SecurityManager; import org.apache.qpid.test.utils.QpidTestCase; import org.apache.qpid.test.utils.TestSSLConstants; @@ -48,7 +49,7 @@ public class FileTrustStoreCreationTest extends QpidTestCase UUID id = UUID.randomUUID(); Broker broker = mock(Broker.class); - final FileTrustStore trustStore = new FileTrustStore(id, broker, attributes); + final FileTrustStore trustStore = new FileTrustStoreImpl(id, broker, attributes); trustStore.open(); assertNotNull("Trust store configured object is not created", trustStore); assertEquals(id, trustStore.getId()); @@ -92,7 +93,7 @@ public class FileTrustStoreCreationTest extends QpidTestCase properties.remove(mandatoryProperties[i]); try { - TrustStore trustStore = new FileTrustStore(id, broker, properties); + TrustStore trustStore = new FileTrustStoreImpl(id, broker, properties); trustStore.open(); fail("Cannot create key store without a " + mandatoryProperties[i]); } diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/configuration/startup/PreferencesProviderCreationTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/configuration/startup/PreferencesProviderCreationTest.java index 9c224aead3..62b258e72e 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/configuration/startup/PreferencesProviderCreationTest.java +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/configuration/startup/PreferencesProviderCreationTest.java @@ -25,6 +25,7 @@ import org.apache.qpid.server.model.AuthenticationProvider; import org.apache.qpid.server.model.Broker; import org.apache.qpid.server.model.PreferencesProvider; import org.apache.qpid.server.model.adapter.FileSystemPreferencesProvider; +import org.apache.qpid.server.model.adapter.FileSystemPreferencesProviderImpl; import org.apache.qpid.server.util.BrokerTestHelper; import org.apache.qpid.test.utils.QpidTestCase; import org.apache.qpid.test.utils.TestFileUtils; @@ -96,11 +97,12 @@ public class PreferencesProviderCreationTest extends QpidTestCase try { attributes.put(FileSystemPreferencesProvider.PATH, file.getAbsolutePath()); - PreferencesProvider provider = new FileSystemPreferencesProvider(id,attributes,_authenticationProvider); + PreferencesProvider provider = new FileSystemPreferencesProviderImpl(id,attributes,_authenticationProvider); assertNotNull("Preferences provider was not recovered", provider); assertEquals("Unexpected name", "test-provider", provider.getName()); assertEquals("Unexpected id", id, provider.getId()); - assertEquals("Unexpected path", file.getAbsolutePath(), provider.getAttribute(FileSystemPreferencesProvider.PATH)); + assertEquals("Unexpected path", file.getAbsolutePath(), provider.getAttribute( + FileSystemPreferencesProvider.PATH)); } finally { diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/configuration/store/JsonConfigurationEntryStoreTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/configuration/store/JsonConfigurationEntryStoreTest.java index 9f15953b3b..e6d47e6966 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/configuration/store/JsonConfigurationEntryStoreTest.java +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/configuration/store/JsonConfigurationEntryStoreTest.java @@ -50,6 +50,7 @@ import org.apache.qpid.server.model.ConfiguredObjectFactory; import org.apache.qpid.server.model.Model; import org.apache.qpid.server.model.PreferencesProvider; import org.apache.qpid.server.model.SystemContext; +import org.apache.qpid.server.model.SystemContextImpl; import org.apache.qpid.server.model.adapter.FileSystemPreferencesProvider; import org.apache.qpid.server.store.DurableConfigurationStore; import org.apache.qpid.test.utils.TestFileUtils; @@ -99,7 +100,7 @@ public class JsonConfigurationEntryStoreTest extends ConfigurationEntryStoreTest { final BrokerOptions brokerOptions = mock(BrokerOptions.class); when(brokerOptions.getConfigurationStoreLocation()).thenReturn(absolutePath); - SystemContext context = new SystemContext(new TaskExecutor(), + SystemContext context = new SystemContextImpl(new TaskExecutor(), new ConfiguredObjectFactory(Model.getInstance()), mock(EventLogger.class), mock(LogRecorder.class), diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/configuration/store/ManagementModeStoreHandlerTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/configuration/store/ManagementModeStoreHandlerTest.java index 43335cdea3..0fe116570a 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/configuration/store/ManagementModeStoreHandlerTest.java +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/configuration/store/ManagementModeStoreHandlerTest.java @@ -50,6 +50,7 @@ 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.SystemContext; +import org.apache.qpid.server.model.SystemContextImpl; import org.apache.qpid.server.model.VirtualHost; import org.apache.qpid.server.store.ConfiguredObjectRecord; import org.apache.qpid.server.store.ConfiguredObjectRecordImpl; @@ -75,7 +76,7 @@ public class ManagementModeStoreHandlerTest extends QpidTestCase _store = mock(DurableConfigurationStore.class); - _systemContext = new SystemContext(new TaskExecutor(), new ConfiguredObjectFactory(Model.getInstance()), mock( + _systemContext = new SystemContextImpl(new TaskExecutor(), new ConfiguredObjectFactory(Model.getInstance()), mock( EventLogger.class), mock(LogRecorder.class), new BrokerOptions()); diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/configuration/store/MemoryConfigurationEntryStoreTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/configuration/store/MemoryConfigurationEntryStoreTest.java index bdc43e6a99..bf8da6f364 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/configuration/store/MemoryConfigurationEntryStoreTest.java +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/configuration/store/MemoryConfigurationEntryStoreTest.java @@ -43,6 +43,7 @@ import org.apache.qpid.server.model.Broker; import org.apache.qpid.server.model.ConfiguredObjectFactory; import org.apache.qpid.server.model.Model; import org.apache.qpid.server.model.SystemContext; +import org.apache.qpid.server.model.SystemContextImpl; public class MemoryConfigurationEntryStoreTest extends ConfigurationEntryStoreTestCase { @@ -52,7 +53,7 @@ public class MemoryConfigurationEntryStoreTest extends ConfigurationEntryStoreTe public void setUp() throws Exception { super.setUp(); - _systemContext = new SystemContext(new TaskExecutor(), new ConfiguredObjectFactory(Model.getInstance()), + _systemContext = new SystemContextImpl(new TaskExecutor(), new ConfiguredObjectFactory(Model.getInstance()), mock(EventLogger.class), mock(LogRecorder.class), new BrokerOptions()); diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/adapter/FileSystemPreferencesProviderFactoryTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/adapter/FileSystemPreferencesProviderFactoryTest.java index 27ad46dcfc..db9d3db2d8 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/adapter/FileSystemPreferencesProviderFactoryTest.java +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/adapter/FileSystemPreferencesProviderFactoryTest.java @@ -131,7 +131,8 @@ public class FileSystemPreferencesProviderFactoryTest extends QpidTestCase assertNotNull("Preferences provider was not recovered", provider); assertEquals("Unexpected name", "test-provider", provider.getName()); assertEquals("Unexpected id", id, provider.getId()); - assertEquals("Unexpected path", file.getAbsolutePath(), provider.getAttribute(FileSystemPreferencesProvider.PATH)); + assertEquals("Unexpected path", file.getAbsolutePath(), provider.getAttribute( + FileSystemPreferencesProvider.PATH)); assertTrue("Preferences store file should exist", file.exists()); } finally diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/adapter/FileSystemPreferencesProviderTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/adapter/FileSystemPreferencesProviderTest.java index 70cbfae9d4..30a12fbb19 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/adapter/FileSystemPreferencesProviderTest.java +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/adapter/FileSystemPreferencesProviderTest.java @@ -34,6 +34,7 @@ import java.util.UUID; import org.apache.qpid.server.configuration.updater.TaskExecutor; import org.apache.qpid.server.model.AuthenticationProvider; import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.ConfiguredObject; import org.apache.qpid.server.model.State; import org.apache.qpid.server.util.BrokerTestHelper; import org.apache.qpid.test.utils.QpidTestCase; @@ -43,7 +44,7 @@ public class FileSystemPreferencesProviderTest extends QpidTestCase { private static final String TEST_PREFERENCES = "{\"user1\":{\"pref1\":\"pref1User1Value\", \"pref2\": true, \"pref3\": 1.0, \"pref4\": 2}," + "\"user2\":{\"pref1\":\"pref1User2Value\", \"pref2\": false, \"pref3\": 2.0, \"pref4\": 3}}"; - private FileSystemPreferencesProvider _preferencesProvider; + private FileSystemPreferencesProviderImpl _preferencesProvider; private AuthenticationProvider _authenticationProvider; private Broker _broker; private String _user1, _user2; @@ -96,8 +97,8 @@ public class FileSystemPreferencesProviderTest extends QpidTestCase { Map<String, Object> attributes = new HashMap<String, Object>(); attributes.put(FileSystemPreferencesProvider.PATH, nonExistingFile.getAbsolutePath()); - attributes.put(FileSystemPreferencesProvider.NAME, getTestName()); - _preferencesProvider = new FileSystemPreferencesProvider(UUID.randomUUID(), attributes, _authenticationProvider); + attributes.put(ConfiguredObject.NAME, getTestName()); + _preferencesProvider = new FileSystemPreferencesProviderImpl(UUID.randomUUID(), attributes, _authenticationProvider); _preferencesProvider.createStoreIfNotExist(); assertEquals(State.INITIALISING, _preferencesProvider.getState()); assertTrue("Preferences file was not created", nonExistingFile.exists()); @@ -116,9 +117,9 @@ public class FileSystemPreferencesProviderTest extends QpidTestCase try { Map<String, Object> attributes = new HashMap<String, Object>(); - attributes.put(FileSystemPreferencesProvider.NAME, getTestName()); + attributes.put(ConfiguredObject.NAME, getTestName()); attributes.put(FileSystemPreferencesProvider.PATH, emptyPrefsFile.getAbsolutePath()); - _preferencesProvider = new FileSystemPreferencesProvider(UUID.randomUUID(), attributes, _authenticationProvider); + _preferencesProvider = new FileSystemPreferencesProviderImpl(UUID.randomUUID(), attributes, _authenticationProvider); assertEquals(State.INITIALISING, _preferencesProvider.getState()); } finally @@ -273,12 +274,12 @@ public class FileSystemPreferencesProviderTest extends QpidTestCase assertEquals("Unexpected user names", new HashSet<String>(Arrays.asList("user1", "user2")), userNames); } - private FileSystemPreferencesProvider createPreferencesProvider() + private FileSystemPreferencesProviderImpl createPreferencesProvider() { Map<String, Object> attributes = new HashMap<String, Object>(); attributes.put(FileSystemPreferencesProvider.PATH, _preferencesFile.getAbsolutePath()); - attributes.put(FileSystemPreferencesProvider.NAME, "test"); - return _preferencesProvider = new FileSystemPreferencesProvider(UUID.randomUUID(), attributes, _authenticationProvider); + attributes.put(ConfiguredObject.NAME, "test"); + return _preferencesProvider = new FileSystemPreferencesProviderImpl(UUID.randomUUID(), attributes, _authenticationProvider); } private void assertUser1Preferences(Map<String, Object> preferences1) diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/adapter/PortFactoryTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/adapter/PortFactoryTest.java index 7d83d81d4e..80b29ac6b2 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/adapter/PortFactoryTest.java +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/model/adapter/PortFactoryTest.java @@ -320,7 +320,7 @@ public class PortFactoryTest extends QpidTestCase Port port = _portFactory.createPort(_portId, _broker, _attributes); assertNotNull(port); - assertFalse("Port should be a PortAdapter, not its AMQP-specific subclass", port instanceof AmqpPort); + assertFalse("Port should not be an AMQP-specific subclass", port instanceof AmqpPort); assertEquals(_portId, port.getId()); assertEquals(_portNumber, port.getPort()); assertEquals(_tcpTransports, port.getTransports()); @@ -345,7 +345,7 @@ public class PortFactoryTest extends QpidTestCase Port port = _portFactory.createPort(_portId, _broker, _attributes); assertNotNull(port); - assertFalse("Port should be a PortAdapter, not its AMQP-specific subclass", port instanceof AmqpPort); + assertFalse("Port not be an AMQP-specific port subclass", port instanceof AmqpPort); assertEquals(_portId, port.getId()); assertEquals(_portNumber, port.getPort()); assertEquals(Collections.singleton(PortFactory.DEFAULT_TRANSPORT), port.getTransports()); diff --git a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationManagerTest.java b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationManagerTest.java index c450d4970b..68adf2c5b6 100644 --- a/qpid/java/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationManagerTest.java +++ b/qpid/java/broker-core/src/test/java/org/apache/qpid/server/security/auth/manager/ExternalAuthenticationManagerTest.java @@ -48,13 +48,13 @@ public class ExternalAuthenticationManagerTest extends QpidTestCase attrs.put(AuthenticationProvider.ID, UUID.randomUUID()); attrs.put(AuthenticationProvider.NAME, getTestName()); attrs.put("useFullDN",false); - _manager = new ExternalAuthenticationManager(mock(Broker.class), attrs); + _manager = new ExternalAuthenticationManagerImpl(mock(Broker.class), attrs); _manager.open(); HashMap<String, Object> attrsFullDN = new HashMap<String, Object>(); attrsFullDN.put(AuthenticationProvider.ID, UUID.randomUUID()); attrsFullDN.put(AuthenticationProvider.NAME, getTestName()+"FullDN"); attrsFullDN.put("useFullDN",true); - _managerUsingFullDN = new ExternalAuthenticationManager(mock(Broker.class), attrsFullDN); + _managerUsingFullDN = new ExternalAuthenticationManagerImpl(mock(Broker.class), attrsFullDN); _managerUsingFullDN.open(); } @@ -198,7 +198,7 @@ public class ExternalAuthenticationManagerTest extends QpidTestCase assertNull(saslServer.getAuthorizationID()); } - private void createSaslServerTestImpl(AuthenticationManager manager) throws Exception + private void createSaslServerTestImpl(AuthenticationProvider<?> manager) throws Exception { SaslServer server = manager.createSaslServer("EXTERNAL", "example.example.com", null); diff --git a/qpid/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/ACLFileAccessControlProvider.java b/qpid/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/ACLFileAccessControlProvider.java index 55de9fc902..961eb25236 100644 --- a/qpid/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/ACLFileAccessControlProvider.java +++ b/qpid/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/ACLFileAccessControlProvider.java @@ -20,224 +20,13 @@ */ package org.apache.qpid.server.security.access.plugins; -import java.security.AccessControlException; -import java.util.Collection; -import java.util.Collections; -import java.util.Map; -import java.util.concurrent.atomic.AtomicReference; - -import org.apache.log4j.Logger; -import org.apache.qpid.server.model.*; -import org.apache.qpid.server.model.AbstractConfiguredObject; -import org.apache.qpid.server.plugin.AccessControlProviderFactory; -import org.apache.qpid.server.security.AccessControl; -import org.apache.qpid.server.security.access.Operation; -import org.apache.qpid.server.util.MapValueConverter; +import org.apache.qpid.server.model.AccessControlProvider; +import org.apache.qpid.server.model.ManagedAttribute; +import org.apache.qpid.server.model.ManagedObject; @ManagedObject( category = false, type="AclFile" ) -public class ACLFileAccessControlProvider - extends AbstractConfiguredObject<ACLFileAccessControlProvider> - implements AccessControlProvider<ACLFileAccessControlProvider> +public interface ACLFileAccessControlProvider<X extends ACLFileAccessControlProvider<X>> extends AccessControlProvider<X> { - private static final Logger LOGGER = Logger.getLogger(ACLFileAccessControlProvider.class); - - protected DefaultAccessControl _accessControl; - protected final Broker _broker; - - protected Map<String, AccessControlProviderFactory> _factories; - private AtomicReference<State> _state; - - @ManagedAttributeField - private String _path; - - public ACLFileAccessControlProvider(Broker broker, - Map<String, Object> attributes) - { - super(parentsMap(broker), - attributes, broker.getTaskExecutor()); - - - _broker = broker; - - State state = MapValueConverter.getEnumAttribute(State.class, STATE, attributes, State.INITIALISING); - _state = new AtomicReference<State>(state); - - } - - @Override - protected void onOpen() - { - super.onOpen(); - _accessControl = new DefaultAccessControl(getPath(), _broker); - } - @ManagedAttribute( automate = true, mandatory = true ) - public String getPath() - { - return _path; - } - - @Override - public String setName(String currentName, String desiredName) throws IllegalStateException, AccessControlException - { - return null; - } - - @Override - public State getState() - { - return _state.get(); - } - - @Override - public boolean isDurable() - { - return true; - } - - @Override - public void setDurable(boolean durable) - throws IllegalStateException, AccessControlException, IllegalArgumentException - { - } - - @Override - public LifetimePolicy getLifetimePolicy() - { - return LifetimePolicy.PERMANENT; - } - - @Override - public LifetimePolicy setLifetimePolicy(LifetimePolicy expected, LifetimePolicy desired) - throws IllegalStateException, AccessControlException, IllegalArgumentException - { - return null; - } - - @Override - public Collection<String> getAttributeNames() - { - return getAttributeNames(getClass()); - } - - @Override - public Object getAttribute(String name) - { - if(DURABLE.equals(name)) - { - return true; - } - else if(LIFETIME_POLICY.equals(name)) - { - return LifetimePolicy.PERMANENT; - } - else if(STATE.equals(name)) - { - return getState(); - } - return super.getAttribute(name); - } - - @Override - public <C extends ConfiguredObject> Collection<C> getChildren(Class<C> clazz) - { - return Collections.emptySet(); - } - - @Override - public boolean setState(State currentState, State desiredState) - throws IllegalStateTransitionException, AccessControlException - { - State state = _state.get(); - - if(desiredState == State.DELETED) - { - deleted(); - return _state.compareAndSet(state, State.DELETED); - } - else if (desiredState == State.QUIESCED) - { - return _state.compareAndSet(state, State.QUIESCED); - } - else if(desiredState == State.ACTIVE) - { - if ((state == State.INITIALISING || state == State.QUIESCED) && _state.compareAndSet(state, State.ACTIVE)) - { - try - { - _accessControl.open(); - return true; - } - catch(RuntimeException e) - { - _state.compareAndSet(State.ACTIVE, State.ERRORED); - if (_broker.isManagementMode()) - { - LOGGER.warn("Failed to activate ACL provider: " + getName(), e); - } - else - { - throw e; - } - } - } - else - { - throw new IllegalStateException("Can't activate access control provider in " + state + " state"); - } - } - else if(desiredState == State.STOPPED) - { - if(_state.compareAndSet(state, State.STOPPED)) - { - _accessControl.close(); - return true; - } - - return false; - } - return false; - } - - - @Override - protected void changeAttributes(Map<String, Object> attributes) - { - throw new UnsupportedOperationException("Changing attributes on AccessControlProvider is not supported"); - } - - @Override - protected void authoriseSetDesiredState(State currentState, State desiredState) throws AccessControlException - { - if(desiredState == State.DELETED) - { - if (!_broker.getSecurityManager().authoriseConfiguringBroker(getName(), AccessControlProvider.class, Operation.DELETE)) - { - throw new AccessControlException("Deletion of AccessControlProvider is denied"); - } - } - } - - @Override - protected void authoriseSetAttribute(String name, Object expected, Object desired) throws AccessControlException - { - if (!_broker.getSecurityManager().authoriseConfiguringBroker(getName(), AccessControlProvider.class, Operation.UPDATE)) - { - throw new AccessControlException("Setting of AccessControlProvider attributes is denied"); - } - } - - @Override - protected void authoriseSetAttributes(Map<String, Object> attributes) throws AccessControlException - { - if (!_broker.getSecurityManager().authoriseConfiguringBroker(getName(), AccessControlProvider.class, Operation.UPDATE)) - { - throw new AccessControlException("Setting of AccessControlProvider attributes is denied"); - } - } - - public AccessControl getAccessControl() - { - return _accessControl; - } + String getPath(); } diff --git a/qpid/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/ACLFileAccessControlProviderFactory.java b/qpid/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/ACLFileAccessControlProviderFactory.java index e9de449804..f20d468a14 100644 --- a/qpid/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/ACLFileAccessControlProviderFactory.java +++ b/qpid/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/ACLFileAccessControlProviderFactory.java @@ -20,21 +20,21 @@ */ package org.apache.qpid.server.security.access.plugins; +import java.util.Map; + import org.apache.qpid.server.model.AbstractConfiguredObjectTypeFactory; import org.apache.qpid.server.model.Broker; import org.apache.qpid.server.model.ConfiguredObject; import org.apache.qpid.server.plugin.AccessControlProviderFactory; import org.apache.qpid.server.util.ResourceBundleLoader; -import java.util.Map; - -public class ACLFileAccessControlProviderFactory extends AbstractConfiguredObjectTypeFactory<ACLFileAccessControlProvider> implements AccessControlProviderFactory<ACLFileAccessControlProvider> +public class ACLFileAccessControlProviderFactory extends AbstractConfiguredObjectTypeFactory<ACLFileAccessControlProviderImpl> implements AccessControlProviderFactory<ACLFileAccessControlProviderImpl> { public static final String RESOURCE_BUNDLE = "org.apache.qpid.server.security.access.plugins.FileAccessControlProviderAttributeDescriptions"; public ACLFileAccessControlProviderFactory() { - super(ACLFileAccessControlProvider.class); + super(ACLFileAccessControlProviderImpl.class); } @Override @@ -44,10 +44,10 @@ public class ACLFileAccessControlProviderFactory extends AbstractConfiguredObjec } @Override - public ACLFileAccessControlProvider createInstance(final Map<String, Object> attributes, + public ACLFileAccessControlProviderImpl createInstance(final Map<String, Object> attributes, final ConfiguredObject<?>... parents) { - return new ACLFileAccessControlProvider(getParent(Broker.class,parents), attributes); + return new ACLFileAccessControlProviderImpl(getParent(Broker.class,parents), attributes); } } diff --git a/qpid/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/ACLFileAccessControlProviderImpl.java b/qpid/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/ACLFileAccessControlProviderImpl.java new file mode 100644 index 0000000000..db2b44c5e6 --- /dev/null +++ b/qpid/java/broker-plugins/access-control/src/main/java/org/apache/qpid/server/security/access/plugins/ACLFileAccessControlProviderImpl.java @@ -0,0 +1,241 @@ +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.server.security.access.plugins; + +import java.security.AccessControlException; +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.atomic.AtomicReference; + +import org.apache.log4j.Logger; + +import org.apache.qpid.server.model.AbstractConfiguredObject; +import org.apache.qpid.server.model.AccessControlProvider; +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.ConfiguredObject; +import org.apache.qpid.server.model.IllegalStateTransitionException; +import org.apache.qpid.server.model.LifetimePolicy; +import org.apache.qpid.server.model.ManagedAttributeField; +import org.apache.qpid.server.model.State; +import org.apache.qpid.server.plugin.AccessControlProviderFactory; +import org.apache.qpid.server.security.AccessControl; +import org.apache.qpid.server.security.access.Operation; +import org.apache.qpid.server.util.MapValueConverter; + +public class ACLFileAccessControlProviderImpl + extends AbstractConfiguredObject<ACLFileAccessControlProviderImpl> + implements ACLFileAccessControlProvider<ACLFileAccessControlProviderImpl> +{ + private static final Logger LOGGER = Logger.getLogger(ACLFileAccessControlProviderImpl.class); + + protected DefaultAccessControl _accessControl; + protected final Broker _broker; + + protected Map<String, AccessControlProviderFactory> _factories; + private AtomicReference<State> _state; + + @ManagedAttributeField + private String _path; + + public ACLFileAccessControlProviderImpl(Broker broker, + Map<String, Object> attributes) + { + super(parentsMap(broker), + attributes, broker.getTaskExecutor()); + + + _broker = broker; + + State state = MapValueConverter.getEnumAttribute(State.class, STATE, attributes, State.INITIALISING); + _state = new AtomicReference<State>(state); + + } + + @Override + protected void onOpen() + { + super.onOpen(); + _accessControl = new DefaultAccessControl(getPath(), _broker); + } + + @Override + public String getPath() + { + return _path; + } + + @Override + public String setName(String currentName, String desiredName) throws IllegalStateException, AccessControlException + { + return null; + } + + @Override + public State getState() + { + return _state.get(); + } + + @Override + public boolean isDurable() + { + return true; + } + + @Override + public void setDurable(boolean durable) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + } + + @Override + public LifetimePolicy getLifetimePolicy() + { + return LifetimePolicy.PERMANENT; + } + + @Override + public LifetimePolicy setLifetimePolicy(LifetimePolicy expected, LifetimePolicy desired) + throws IllegalStateException, AccessControlException, IllegalArgumentException + { + return null; + } + + @Override + public Collection<String> getAttributeNames() + { + return getAttributeNames(getClass()); + } + + @Override + public Object getAttribute(String name) + { + if(DURABLE.equals(name)) + { + return true; + } + else if(LIFETIME_POLICY.equals(name)) + { + return LifetimePolicy.PERMANENT; + } + else if(STATE.equals(name)) + { + return getState(); + } + return super.getAttribute(name); + } + + @Override + public <C extends ConfiguredObject> Collection<C> getChildren(Class<C> clazz) + { + return Collections.emptySet(); + } + + @Override + public boolean setState(State currentState, State desiredState) + throws IllegalStateTransitionException, AccessControlException + { + State state = _state.get(); + + if(desiredState == State.DELETED) + { + deleted(); + return _state.compareAndSet(state, State.DELETED); + } + else if (desiredState == State.QUIESCED) + { + return _state.compareAndSet(state, State.QUIESCED); + } + else if(desiredState == State.ACTIVE) + { + if ((state == State.INITIALISING || state == State.QUIESCED) && _state.compareAndSet(state, State.ACTIVE)) + { + try + { + _accessControl.open(); + return true; + } + catch(RuntimeException e) + { + _state.compareAndSet(State.ACTIVE, State.ERRORED); + if (_broker.isManagementMode()) + { + LOGGER.warn("Failed to activate ACL provider: " + getName(), e); + } + else + { + throw e; + } + } + } + else + { + throw new IllegalStateException("Can't activate access control provider in " + state + " state"); + } + } + else if(desiredState == State.STOPPED) + { + if(_state.compareAndSet(state, State.STOPPED)) + { + _accessControl.close(); + return true; + } + + return false; + } + return false; + } + + + @Override + protected void changeAttributes(Map<String, Object> attributes) + { + throw new UnsupportedOperationException("Changing attributes on AccessControlProvider is not supported"); + } + + @Override + protected void authoriseSetDesiredState(State currentState, State desiredState) throws AccessControlException + { + if(desiredState == State.DELETED) + { + if (!_broker.getSecurityManager().authoriseConfiguringBroker(getName(), AccessControlProvider.class, Operation.DELETE)) + { + throw new AccessControlException("Deletion of AccessControlProvider is denied"); + } + } + } + + @Override + protected void authoriseSetAttributes(ConfiguredObject<?> modified, Set<String> attributes) throws AccessControlException + { + if (!_broker.getSecurityManager().authoriseConfiguringBroker(getName(), AccessControlProvider.class, Operation.UPDATE)) + { + throw new AccessControlException("Setting of AccessControlProvider attributes is denied"); + } + } + + public AccessControl getAccessControl() + { + return _accessControl; + } +} diff --git a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java index 555c12037d..5427d81bd5 100644 --- a/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java +++ b/qpid/java/broker-plugins/management-http/src/main/java/org/apache/qpid/server/management/plugin/HttpManagement.java @@ -69,7 +69,7 @@ import org.apache.qpid.server.management.plugin.servlet.rest.StructureServlet; import org.apache.qpid.server.management.plugin.servlet.rest.UserPreferencesServlet; import org.apache.qpid.server.model.*; import org.apache.qpid.server.model.adapter.AbstractPluginAdapter; -import org.apache.qpid.server.model.port.PortWithAuthProvider; +import org.apache.qpid.server.model.port.AbstractPortWithAuthProvider; import org.apache.qpid.server.util.MapValueConverter; import org.apache.qpid.server.util.ServerScopedRuntimeException; import org.apache.qpid.transport.network.security.ssl.QpidMultipleTrustManager; @@ -218,8 +218,10 @@ public class HttpManagement extends AbstractPluginAdapter<HttpManagement> implem throw new IllegalConfigurationException("Key store is not configured. Cannot start management on HTTPS port without keystore"); } SslContextFactory factory = new SslContextFactory(); - final boolean needClientAuth = port instanceof PortWithAuthProvider && ((PortWithAuthProvider)port).getNeedClientAuth(); - final boolean wantClientAuth = port instanceof PortWithAuthProvider && ((PortWithAuthProvider)port).getWantClientAuth(); + final boolean needClientAuth = port instanceof AbstractPortWithAuthProvider + && ((AbstractPortWithAuthProvider)port).getNeedClientAuth(); + final boolean wantClientAuth = port instanceof AbstractPortWithAuthProvider + && ((AbstractPortWithAuthProvider)port).getWantClientAuth(); boolean needClientCert = needClientAuth || wantClientAuth; if (needClientCert && trustStores.isEmpty()) { diff --git a/qpid/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXManagedObjectRegistry.java b/qpid/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXManagedObjectRegistry.java index f359cec694..79465dbf39 100644 --- a/qpid/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXManagedObjectRegistry.java +++ b/qpid/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXManagedObjectRegistry.java @@ -81,13 +81,13 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry public JMXManagedObjectRegistry( Broker broker, Port connectorPort, Port registryPort, - JMXManagement jmxManagement) + JMXManagementPlugin jmxManagement) { _broker = broker; _registryPort = registryPort; _connectorPort = connectorPort; - boolean usePlatformServer = (Boolean)jmxManagement.getAttribute(JMXManagement.USE_PLATFORM_MBEAN_SERVER); + boolean usePlatformServer = (Boolean)jmxManagement.getAttribute(JMXManagementPlugin.USE_PLATFORM_MBEAN_SERVER); _mbeanServer = usePlatformServer ? ManagementFactory.getPlatformMBeanServer() diff --git a/qpid/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXManagementFactory.java b/qpid/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXManagementFactory.java index dd21225099..0d8b36cdd9 100644 --- a/qpid/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXManagementFactory.java +++ b/qpid/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXManagementFactory.java @@ -18,27 +18,27 @@ */ package org.apache.qpid.server.jmx; -import org.apache.qpid.server.model.AbstractConfiguredObjectTypeFactory; -import org.apache.qpid.server.model.Broker; -import org.apache.qpid.server.model.ConfiguredObject; - import java.util.HashMap; import java.util.Map; import java.util.UUID; -public class JMXManagementFactory extends AbstractConfiguredObjectTypeFactory<JMXManagement> +import org.apache.qpid.server.model.AbstractConfiguredObjectTypeFactory; +import org.apache.qpid.server.model.Broker; +import org.apache.qpid.server.model.ConfiguredObject; + +public class JMXManagementFactory extends AbstractConfiguredObjectTypeFactory<JMXManagementPluginImpl> { public JMXManagementFactory() { - super(JMXManagement.class); + super(JMXManagementPluginImpl.class); } @Override - public JMXManagement createInstance(final Map<String, Object> attributes, final ConfiguredObject<?>... parents) + public JMXManagementPluginImpl createInstance(final Map<String, Object> attributes, final ConfiguredObject<?>... parents) { Map<String,Object> attributesWithoutId = new HashMap<String, Object>(attributes); Object idObj = attributesWithoutId.remove(ConfiguredObject.ID); UUID id = idObj == null ? UUID.randomUUID() : idObj instanceof UUID ? (UUID) idObj : UUID.fromString(idObj.toString()); - return new JMXManagement(id, getParent(Broker.class,parents),attributes); + return new JMXManagementPluginImpl(id, getParent(Broker.class,parents),attributes); } } diff --git a/qpid/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXManagementPlugin.java b/qpid/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXManagementPlugin.java new file mode 100644 index 0000000000..472be5a1a1 --- /dev/null +++ b/qpid/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXManagementPlugin.java @@ -0,0 +1,35 @@ +/* + * + * 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.qpid.server.model.*; + +@org.apache.qpid.server.model.ManagedObject( category = false , type = "MANAGEMENT-JMX" ) +public interface JMXManagementPlugin<X extends JMXManagementPlugin<X>> extends Plugin<X> +{ + String PLUGIN_TYPE = "MANAGEMENT-JMX"; + // attributes + String USE_PLATFORM_MBEAN_SERVER = "usePlatformMBeanServer"; + String DEFAULT_USE_PLATFORM_MBEAN_SERVER = "true"; + + @ManagedAttribute( automate = true, defaultValue = DEFAULT_USE_PLATFORM_MBEAN_SERVER ) + boolean getUsePlatformMBeanServer(); +} diff --git a/qpid/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXManagement.java b/qpid/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXManagementPluginImpl.java index e03633f026..61bd7ab1a0 100644 --- a/qpid/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXManagement.java +++ b/qpid/java/broker-plugins/management-jmx/src/main/java/org/apache/qpid/server/jmx/JMXManagementPluginImpl.java @@ -43,9 +43,7 @@ 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.ManagedAttribute; import org.apache.qpid.server.model.ManagedAttributeField; -import org.apache.qpid.server.model.ManagedObject; import org.apache.qpid.server.model.PasswordCredentialManagingAuthenticationProvider; import org.apache.qpid.server.model.Port; import org.apache.qpid.server.model.Protocol; @@ -56,20 +54,16 @@ import org.apache.qpid.server.plugin.QpidServiceLoader; import org.apache.qpid.server.util.MapValueConverter; import org.apache.qpid.server.util.ServerScopedRuntimeException; -@ManagedObject( category = false , type = "MANAGEMENT-JMX" ) -public class JMXManagement extends AbstractPluginAdapter<JMXManagement> implements ConfigurationChangeListener +public class JMXManagementPluginImpl + extends AbstractPluginAdapter<JMXManagementPluginImpl> implements ConfigurationChangeListener, + JMXManagementPlugin<JMXManagementPluginImpl> { - private static final Logger LOGGER = Logger.getLogger(JMXManagement.class); + private static final Logger LOGGER = Logger.getLogger(JMXManagementPluginImpl.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 Map<String, Type> ATTRIBUTE_TYPES = new HashMap<String, Type>(){{ @@ -86,7 +80,7 @@ public class JMXManagement extends AbstractPluginAdapter<JMXManagement> implemen @ManagedAttributeField private boolean _usePlatformMBeanServer; - public JMXManagement(UUID id, Broker broker, Map<String, Object> attributes) + public JMXManagementPluginImpl(UUID id, Broker broker, Map<String, Object> attributes) { super(id, attributes, broker); } @@ -321,7 +315,7 @@ public class JMXManagement extends AbstractPluginAdapter<JMXManagement> implemen @Override public Collection<String> getAttributeNames() { - return getAttributeNames(JMXManagement.class); + return getAttributeNames(JMXManagementPluginImpl.class); } @Override @@ -335,9 +329,9 @@ public class JMXManagement extends AbstractPluginAdapter<JMXManagement> implemen private void validateAttributes(Map<String, Object> convertedAttributes) { - if(convertedAttributes.containsKey(JMXManagement.NAME)) + if(convertedAttributes.containsKey(JMXManagementPluginImpl.NAME)) { - String newName = (String) convertedAttributes.get(JMXManagement.NAME); + String newName = (String) convertedAttributes.get(JMXManagementPluginImpl.NAME); if(!getName().equals(newName)) { throw new IllegalConfigurationException("Changing the name of jmx management plugin is not allowed"); @@ -360,7 +354,7 @@ public class JMXManagement extends AbstractPluginAdapter<JMXManagement> implemen } } - @ManagedAttribute( automate = true, defaultValue = "true" ) + @Override public boolean getUsePlatformMBeanServer() { return _usePlatformMBeanServer; diff --git a/qpid/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/server/jmx/JMXManagementFactoryTest.java b/qpid/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/server/jmx/JMXManagementFactoryTest.java index e1e3db763c..de5b056d9d 100644 --- a/qpid/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/server/jmx/JMXManagementFactoryTest.java +++ b/qpid/java/broker-plugins/management-jmx/src/test/java/org/apache/qpid/server/jmx/JMXManagementFactoryTest.java @@ -38,14 +38,14 @@ public class JMXManagementFactoryTest extends QpidTestCase public void testJMXConfigured() throws Exception { _attributes.put(ConfiguredObject.ID,UUID.randomUUID()); - _attributes.put(ConfiguredObject.TYPE, JMXManagement.PLUGIN_TYPE); + _attributes.put(ConfiguredObject.TYPE, JMXManagementPlugin.PLUGIN_TYPE); _attributes.put(ConfiguredObject.NAME, getName()); - JMXManagement jmxManagement = _jmxManagementFactory.createInstance( _attributes, _broker); + JMXManagementPlugin jmxManagement = _jmxManagementFactory.createInstance( _attributes, _broker); jmxManagement.open(); assertNotNull(jmxManagement); - assertEquals("Unexpected plugin type", JMXManagement.PLUGIN_TYPE, jmxManagement.getType()); - assertEquals("Unexpected default mbean platform", JMXManagement.DEFAULT_USE_PLATFORM_MBEAN_SERVER, jmxManagement.getAttribute(JMXManagement.USE_PLATFORM_MBEAN_SERVER)); + assertEquals("Unexpected plugin type", JMXManagementPlugin.PLUGIN_TYPE, jmxManagement.getType()); + assertEquals("Unexpected default mbean platform", Boolean.parseBoolean(JMXManagementPlugin.DEFAULT_USE_PLATFORM_MBEAN_SERVER), jmxManagement.getUsePlatformMBeanServer()); } diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/QueueRestTest.java b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/QueueRestTest.java index 3063f9182c..8c8db3b358 100644 --- a/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/QueueRestTest.java +++ b/qpid/java/systests/src/main/java/org/apache/qpid/systest/rest/QueueRestTest.java @@ -147,7 +147,7 @@ public class QueueRestTest extends QpidRestTestCase attributes.put(Queue.MAXIMUM_DELIVERY_ATTEMPTS, 10); responseCode = getRestTestHelper().submitRequest("/rest/queue/test/" + queueName, "PUT", attributes); - assertEquals("Setting of queue attribites should be allowed", 200, responseCode); + assertEquals("Setting of queue attributes should be allowed", 200, responseCode); Map<String, Object> queueData = getRestTestHelper().getJsonAsSingletonList("/rest/queue/test/" + queueName); assertEquals("Unexpected " + Queue.QUEUE_FLOW_CONTROL_SIZE_BYTES, 100000, queueData.get(Queue.QUEUE_FLOW_CONTROL_SIZE_BYTES) ); diff --git a/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/TestBrokerConfiguration.java b/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/TestBrokerConfiguration.java index 645fc57677..99c0e351d4 100644 --- a/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/TestBrokerConfiguration.java +++ b/qpid/java/systests/src/main/java/org/apache/qpid/test/utils/TestBrokerConfiguration.java @@ -42,7 +42,7 @@ import org.apache.qpid.server.model.GroupProvider; import org.apache.qpid.server.model.Model; import org.apache.qpid.server.model.Plugin; import org.apache.qpid.server.model.PreferencesProvider; -import org.apache.qpid.server.model.SystemContext; +import org.apache.qpid.server.model.SystemContextImpl; import org.apache.qpid.server.model.UUIDGenerator; import org.apache.qpid.server.security.access.FileAccessControlProviderConstants; import org.apache.qpid.server.security.group.FileGroupManagerFactory; @@ -75,7 +75,7 @@ public class TestBrokerConfiguration public TestBrokerConfiguration(String storeType, String intialStoreLocation) { - _store = new MemoryConfigurationEntryStore(new SystemContext(new TaskExecutor(), new ConfiguredObjectFactory( + _store = new MemoryConfigurationEntryStore(new SystemContextImpl(new TaskExecutor(), new ConfiguredObjectFactory( Model.getInstance()), mock(EventLogger.class), mock(LogRecorder.class), mock(BrokerOptions.class)), |
