summaryrefslogtreecommitdiff
path: root/java/broker-core/src/main/java/org/apache/qpid/server/security
diff options
context:
space:
mode:
Diffstat (limited to 'java/broker-core/src/main/java/org/apache/qpid/server/security')
-rw-r--r--java/broker-core/src/main/java/org/apache/qpid/server/security/SubjectCreator.java4
-rw-r--r--java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/AbstractAuthenticationManager.java14
-rw-r--r--java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/AbstractScramAuthenticationManager.java210
-rw-r--r--java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/ConfigModelPasswordManagingAuthenticationProvider.java229
-rw-r--r--java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/MD5AuthenticationProvider.java227
-rw-r--r--java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/ManagedUser.java (renamed from java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/ScramAuthUser.java)48
-rw-r--r--java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/PlainAuthenticationProvider.java176
7 files changed, 671 insertions, 237 deletions
diff --git a/java/broker-core/src/main/java/org/apache/qpid/server/security/SubjectCreator.java b/java/broker-core/src/main/java/org/apache/qpid/server/security/SubjectCreator.java
index ac8d002577..bbec239d74 100644
--- a/java/broker-core/src/main/java/org/apache/qpid/server/security/SubjectCreator.java
+++ b/java/broker-core/src/main/java/org/apache/qpid/server/security/SubjectCreator.java
@@ -53,10 +53,10 @@ public class SubjectCreator
{
private final boolean _secure;
private AuthenticationProvider<?> _authenticationProvider;
- private Collection<GroupProvider> _groupProviders;
+ private Collection<GroupProvider<?>> _groupProviders;
public SubjectCreator(AuthenticationProvider<?> authenticationProvider,
- Collection<GroupProvider> groupProviders,
+ Collection<GroupProvider<?>> groupProviders,
final boolean secure)
{
_authenticationProvider = authenticationProvider;
diff --git a/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/AbstractAuthenticationManager.java b/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/AbstractAuthenticationManager.java
index b2cf1739ab..7f98468726 100644
--- a/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/AbstractAuthenticationManager.java
+++ b/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/AbstractAuthenticationManager.java
@@ -53,13 +53,13 @@ public abstract class AbstractAuthenticationManager<T extends AbstractAuthentica
{
private static final Logger LOGGER = Logger.getLogger(AbstractAuthenticationManager.class);
- private final Broker _broker;
- private PreferencesProvider _preferencesProvider;
+ private final Broker<?> _broker;
+ private PreferencesProvider<?> _preferencesProvider;
@ManagedAttributeField
private List<String> _secureOnlyMechanisms;
- protected AbstractAuthenticationManager(final Map<String, Object> attributes, final Broker broker)
+ protected AbstractAuthenticationManager(final Map<String, Object> attributes, final Broker<?> broker)
{
super(parentsMap(broker), attributes);
_broker = broker;
@@ -120,13 +120,13 @@ public abstract class AbstractAuthenticationManager<T extends AbstractAuthentica
}
@Override
- public PreferencesProvider getPreferencesProvider()
+ public PreferencesProvider<?> getPreferencesProvider()
{
return _preferencesProvider;
}
@Override
- public void setPreferencesProvider(final PreferencesProvider preferencesProvider)
+ public void setPreferencesProvider(final PreferencesProvider<?> preferencesProvider)
{
_preferencesProvider = preferencesProvider;
}
@@ -143,8 +143,8 @@ public abstract class AbstractAuthenticationManager<T extends AbstractAuthentica
{
if(childClass == PreferencesProvider.class)
{
- attributes = new HashMap<String, Object>(attributes);
- PreferencesProvider pp = getObjectFactory().create(PreferencesProvider.class, attributes, this);
+ attributes = new HashMap<>(attributes);
+ PreferencesProvider<?> pp = getObjectFactory().create(PreferencesProvider.class, attributes, this);
_preferencesProvider = pp;
return (C)pp;
diff --git a/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/AbstractScramAuthenticationManager.java b/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/AbstractScramAuthenticationManager.java
index 152a9086ec..6887cb99d4 100644
--- a/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/AbstractScramAuthenticationManager.java
+++ b/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/AbstractScramAuthenticationManager.java
@@ -20,52 +20,38 @@
*/
package org.apache.qpid.server.security.auth.manager;
-import java.io.IOException;
-import java.nio.charset.Charset;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.Principal;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Collections;
-import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.UUID;
-import java.util.concurrent.ConcurrentHashMap;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
-import javax.security.auth.login.AccountNotFoundException;
import javax.security.sasl.SaslException;
import javax.security.sasl.SaslServer;
import javax.xml.bind.DatatypeConverter;
-import org.apache.qpid.server.configuration.updater.Task;
-import org.apache.qpid.server.configuration.updater.VoidTaskWithException;
import org.apache.qpid.server.model.Broker;
-import org.apache.qpid.server.model.ConfiguredObject;
import org.apache.qpid.server.model.PasswordCredentialManagingAuthenticationProvider;
-import org.apache.qpid.server.model.User;
-import org.apache.qpid.server.security.access.Operation;
import org.apache.qpid.server.security.auth.AuthenticationResult;
import org.apache.qpid.server.security.auth.UsernamePrincipal;
import org.apache.qpid.server.security.auth.sasl.plain.PlainAdapterSaslServer;
import org.apache.qpid.server.security.auth.sasl.scram.ScramSaslServer;
public abstract class AbstractScramAuthenticationManager<X extends AbstractScramAuthenticationManager<X>>
- extends AbstractAuthenticationManager<X>
+ extends ConfigModelPasswordManagingAuthenticationProvider<X>
implements PasswordCredentialManagingAuthenticationProvider<X>
{
- static final Charset ASCII = Charset.forName("ASCII");
public static final String PLAIN = "PLAIN";
private final SecureRandom _random = new SecureRandom();
private int _iterationCount = 4096;
- private Map<String, ScramAuthUser> _users = new ConcurrentHashMap<String, ScramAuthUser>();
-
protected AbstractScramAuthenticationManager(final Map<String, Object> attributes, final Broker broker)
{
@@ -103,33 +89,9 @@ public abstract class AbstractScramAuthenticationManager<X extends AbstractScram
protected abstract String getDigestName();
@Override
- public AuthenticationResult authenticate(final SaslServer server, final byte[] response)
- {
- try
- {
- // Process response from the client
- byte[] challenge = server.evaluateResponse(response != null ? response : new byte[0]);
-
- if (server.isComplete() && (challenge == null || challenge.length == 0))
- {
- final String userId = server.getAuthorizationID();
- return new AuthenticationResult(new UsernamePrincipal(userId));
- }
- else
- {
- return new AuthenticationResult(challenge, AuthenticationResult.AuthenticationStatus.CONTINUE);
- }
- }
- catch (SaslException e)
- {
- return new AuthenticationResult(AuthenticationResult.AuthenticationStatus.ERROR, e);
- }
- }
-
- @Override
public AuthenticationResult authenticate(final String username, final String password)
{
- ScramAuthUser user = getUser(username);
+ ManagedUser user = getUser(username);
if(user != null)
{
final String[] usernamePassword = user.getPassword().split(",");
@@ -142,7 +104,7 @@ public abstract class AbstractScramAuthenticationManager<X extends AbstractScram
return new AuthenticationResult(new UsernamePrincipal(username));
}
}
- catch (SaslException e)
+ catch (IllegalArgumentException e)
{
return new AuthenticationResult(AuthenticationResult.AuthenticationStatus.ERROR,e);
}
@@ -162,7 +124,7 @@ public abstract class AbstractScramAuthenticationManager<X extends AbstractScram
public byte[] getSalt(final String username)
{
- ScramAuthUser user = getUser(username);
+ ManagedUser user = getUser(username);
if(user == null)
{
@@ -183,7 +145,7 @@ public abstract class AbstractScramAuthenticationManager<X extends AbstractScram
public byte[] getSaltedPassword(final String username) throws SaslException
{
- ScramAuthUser user = getUser(username);
+ ManagedUser user = getUser(username);
if(user == null)
{
throw new SaslException("Authentication Failed");
@@ -194,14 +156,9 @@ public abstract class AbstractScramAuthenticationManager<X extends AbstractScram
}
}
- private ScramAuthUser getUser(final String username)
- {
- return _users.get(username);
- }
-
- private byte[] createSaltedPassword(byte[] salt, String password) throws SaslException
+ private byte[] createSaltedPassword(byte[] salt, String password)
{
- Mac mac = createSha1Hmac(password.getBytes(ASCII));
+ Mac mac = createShaHmac(password.getBytes(ASCII));
mac.update(salt);
mac.update(INT_1);
@@ -222,8 +179,7 @@ public abstract class AbstractScramAuthenticationManager<X extends AbstractScram
}
- private Mac createSha1Hmac(final byte[] keyBytes)
- throws SaslException
+ private Mac createShaHmac(final byte[] keyBytes)
{
try
{
@@ -232,132 +188,16 @@ public abstract class AbstractScramAuthenticationManager<X extends AbstractScram
mac.init(key);
return mac;
}
- catch (NoSuchAlgorithmException e)
- {
- throw new SaslException(e.getMessage(), e);
- }
- catch (InvalidKeyException e)
+ catch (NoSuchAlgorithmException | InvalidKeyException e)
{
- throw new SaslException(e.getMessage(), e);
+ throw new IllegalArgumentException(e.getMessage(), e);
}
}
protected abstract String getHmacName();
@Override
- public boolean createUser(final String username, final String password, final Map<String, String> attributes)
- {
- return runTask(new Task<Boolean>()
- {
- @Override
- public Boolean execute()
- {
- getSecurityManager().authoriseUserOperation(Operation.CREATE, username);
- if (_users.containsKey(username))
- {
- throw new IllegalArgumentException("User '" + username + "' already exists");
- }
- try
- {
- Map<String, Object> userAttrs = new HashMap<String, Object>();
- userAttrs.put(User.ID, UUID.randomUUID());
- userAttrs.put(User.NAME, username);
- userAttrs.put(User.PASSWORD, createStoredPassword(password));
- userAttrs.put(User.TYPE, ScramAuthUser.SCRAM_USER_TYPE);
- ScramAuthUser user = new ScramAuthUser(userAttrs, AbstractScramAuthenticationManager.this);
- user.create();
-
- return true;
- }
- catch (SaslException e)
- {
- throw new IllegalArgumentException(e);
- }
- }
- });
- }
-
- org.apache.qpid.server.security.SecurityManager getSecurityManager()
- {
- return getBroker().getSecurityManager();
- }
-
- @Override
- public void deleteUser(final String user) throws AccountNotFoundException
- {
- runTask(new VoidTaskWithException<AccountNotFoundException>()
- {
- @Override
- public void execute() throws AccountNotFoundException
- {
- final ScramAuthUser authUser = getUser(user);
- if(authUser != null)
- {
- authUser.delete();
- }
- else
- {
- throw new AccountNotFoundException("No such user: '" + user + "'");
- }
- }
- });
- }
-
- @Override
- public void setPassword(final String username, final String password) throws AccountNotFoundException
- {
- runTask(new VoidTaskWithException<AccountNotFoundException>()
- {
- @Override
- public void execute() throws AccountNotFoundException
- {
-
- final ScramAuthUser authUser = getUser(username);
- if (authUser != null)
- {
- authUser.setPassword(password);
- }
- else
- {
- throw new AccountNotFoundException("No such user: '" + username + "'");
- }
- }
- });
-
- }
-
- @Override
- public Map<String, Map<String, String>> getUsers()
- {
- return runTask(new Task<Map<String, Map<String, String>>>()
- {
- @Override
- public Map<String, Map<String, String>> execute()
- {
-
- Map<String, Map<String, String>> users = new HashMap<String, Map<String, String>>();
- for (String user : _users.keySet())
- {
- users.put(user, Collections.<String, String>emptyMap());
- }
- return users;
- }
- });
- }
-
- @Override
- public void reload() throws IOException
- {
-
- }
-
- @Override
- public void recoverUser(final User user)
- {
- _users.put(user.getName(), (ScramAuthUser) user);
- }
-
- protected String createStoredPassword(final String password) throws SaslException
+ protected String createStoredPassword(final String password)
{
byte[] salt = new byte[32];
_random.nextBytes(salt);
@@ -366,33 +206,11 @@ public abstract class AbstractScramAuthenticationManager<X extends AbstractScram
}
@Override
- public <C extends ConfiguredObject> C addChild(final Class<C> childClass,
- final Map<String, Object> attributes,
- final ConfiguredObject... otherParents)
+ void validateUser(final ManagedUser managedUser)
{
- if(childClass == User.class)
+ if(!ASCII.newEncoder().canEncode(managedUser.getName()))
{
- String username = (String) attributes.get("name");
- String password = (String) attributes.get("password");
-
- if(createUser(username, password,null))
- {
- @SuppressWarnings("unchecked")
- C user = (C) _users.get(username);
- return user;
- }
- else
- {
- return null;
-
- }
+ throw new IllegalArgumentException("User names are restricted to characters in the ASCII charset");
}
- return super.addChild(childClass, attributes, otherParents);
}
-
- Map<String, ScramAuthUser> getUserMap()
- {
- return _users;
- }
-
}
diff --git a/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/ConfigModelPasswordManagingAuthenticationProvider.java b/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/ConfigModelPasswordManagingAuthenticationProvider.java
new file mode 100644
index 0000000000..5126e6978d
--- /dev/null
+++ b/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/ConfigModelPasswordManagingAuthenticationProvider.java
@@ -0,0 +1,229 @@
+/*
+ *
+ * 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.nio.charset.Charset;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.security.auth.login.AccountNotFoundException;
+import javax.security.sasl.SaslException;
+import javax.security.sasl.SaslServer;
+
+import org.apache.qpid.server.configuration.updater.Task;
+import org.apache.qpid.server.configuration.updater.VoidTaskWithException;
+import org.apache.qpid.server.model.Broker;
+import org.apache.qpid.server.model.ConfiguredObject;
+import org.apache.qpid.server.model.PasswordCredentialManagingAuthenticationProvider;
+import org.apache.qpid.server.model.User;
+import org.apache.qpid.server.security.SecurityManager;
+import org.apache.qpid.server.security.access.Operation;
+import org.apache.qpid.server.security.auth.AuthenticationResult;
+import org.apache.qpid.server.security.auth.UsernamePrincipal;
+
+public abstract class ConfigModelPasswordManagingAuthenticationProvider<X extends ConfigModelPasswordManagingAuthenticationProvider<X>>
+ extends AbstractAuthenticationManager<X>
+ implements PasswordCredentialManagingAuthenticationProvider<X>
+{
+ static final Charset ASCII = Charset.forName("ASCII");
+ protected Map<String, ManagedUser> _users = new ConcurrentHashMap<>();
+
+ protected ConfigModelPasswordManagingAuthenticationProvider(final Map<String, Object> attributes,
+ final Broker broker)
+ {
+ super(attributes, broker);
+ }
+
+ ManagedUser getUser(final String username)
+ {
+ return _users.get(username);
+ }
+
+ @Override
+ public boolean createUser(final String username, final String password, final Map<String, String> attributes)
+ {
+ return runTask(new Task<Boolean>()
+ {
+ @Override
+ public Boolean execute()
+ {
+ getSecurityManager().authoriseUserOperation(Operation.CREATE, username);
+ if (_users.containsKey(username))
+ {
+ throw new IllegalArgumentException("User '" + username + "' already exists");
+ }
+
+ Map<String, Object> userAttrs = new HashMap<>();
+ userAttrs.put(User.ID, UUID.randomUUID());
+ userAttrs.put(User.NAME, username);
+ userAttrs.put(User.PASSWORD, createStoredPassword(password));
+ userAttrs.put(User.TYPE, ManagedUser.MANAGED_USER_TYPE);
+ ManagedUser user = new ManagedUser(userAttrs, ConfigModelPasswordManagingAuthenticationProvider.this);
+ user.create();
+
+ return true;
+
+ }
+ });
+ }
+
+ SecurityManager getSecurityManager()
+ {
+ return getBroker().getSecurityManager();
+ }
+
+ @Override
+ public void deleteUser(final String user) throws AccountNotFoundException
+ {
+ runTask(new VoidTaskWithException<AccountNotFoundException>()
+ {
+ @Override
+ public void execute() throws AccountNotFoundException
+ {
+ final ManagedUser authUser = getUser(user);
+ if(authUser != null)
+ {
+ authUser.delete();
+ }
+ else
+ {
+ throw new AccountNotFoundException("No such user: '" + user + "'");
+ }
+ }
+ });
+ }
+
+ @Override
+ public Map<String, Map<String, String>> getUsers()
+ {
+ return runTask(new Task<Map<String, Map<String, String>>>()
+ {
+ @Override
+ public Map<String, Map<String, String>> execute()
+ {
+
+ Map<String, Map<String, String>> users = new HashMap<>();
+ for (String user : _users.keySet())
+ {
+ users.put(user, Collections.<String, String>emptyMap());
+ }
+ return users;
+ }
+ });
+ }
+
+ @Override
+ public void reload() throws IOException
+ {
+
+ }
+
+ @Override
+ public void recoverUser(final User user)
+ {
+ _users.put(user.getName(), (ManagedUser) user);
+ }
+
+ @Override
+ public void setPassword(final String username, final String password) throws AccountNotFoundException
+ {
+ runTask(new VoidTaskWithException<AccountNotFoundException>()
+ {
+ @Override
+ public void execute() throws AccountNotFoundException
+ {
+
+ final ManagedUser authUser = getUser(username);
+ if (authUser != null)
+ {
+ authUser.setPassword(password);
+ }
+ else
+ {
+ throw new AccountNotFoundException("No such user: '" + username + "'");
+ }
+ }
+ });
+
+ }
+
+ @Override
+ public AuthenticationResult authenticate(final SaslServer server, final byte[] response)
+ {
+ try
+ {
+ // Process response from the client
+ byte[] challenge = server.evaluateResponse(response != null ? response : new byte[0]);
+
+ if (server.isComplete() && (challenge == null || challenge.length == 0))
+ {
+ final String userId = server.getAuthorizationID();
+ return new AuthenticationResult(new UsernamePrincipal(userId));
+ }
+ else
+ {
+ return new AuthenticationResult(challenge, AuthenticationResult.AuthenticationStatus.CONTINUE);
+ }
+ }
+ catch (SaslException e)
+ {
+ return new AuthenticationResult(AuthenticationResult.AuthenticationStatus.ERROR, e);
+ }
+ }
+
+ protected abstract String createStoredPassword(String password);
+
+ Map<String, ManagedUser> getUserMap()
+ {
+ return _users;
+ }
+
+ @Override
+ public <C extends ConfiguredObject> C addChild(final Class<C> childClass,
+ final Map<String, Object> attributes,
+ final ConfiguredObject... otherParents)
+ {
+ if(childClass == User.class)
+ {
+ String username = (String) attributes.get("name");
+ String password = (String) attributes.get("password");
+
+ if(createUser(username, password,null))
+ {
+ @SuppressWarnings("unchecked")
+ C user = (C) getUser(username);
+ return user;
+ }
+ else
+ {
+ return null;
+
+ }
+ }
+ return super.addChild(childClass, attributes, otherParents);
+ }
+
+ abstract void validateUser(final ManagedUser managedUser);
+}
diff --git a/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/MD5AuthenticationProvider.java b/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/MD5AuthenticationProvider.java
new file mode 100644
index 0000000000..cdb2f3dcc7
--- /dev/null
+++ b/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/MD5AuthenticationProvider.java
@@ -0,0 +1,227 @@
+/*
+ *
+ * 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.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.sasl.AuthorizeCallback;
+import javax.security.sasl.SaslException;
+import javax.security.sasl.SaslServer;
+import javax.xml.bind.DatatypeConverter;
+
+import org.apache.qpid.server.model.Broker;
+import org.apache.qpid.server.model.ManagedObject;
+import org.apache.qpid.server.model.ManagedObjectFactoryConstructor;
+import org.apache.qpid.server.security.auth.AuthenticationResult;
+import org.apache.qpid.server.security.auth.UsernamePrincipal;
+import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5HashedSaslServer;
+import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5HexSaslServer;
+import org.apache.qpid.server.security.auth.sasl.plain.PlainAdapterSaslServer;
+import org.apache.qpid.server.security.auth.sasl.plain.PlainSaslServer;
+import org.apache.qpid.server.util.ServerScopedRuntimeException;
+
+@ManagedObject( category = false, type = "MD5" )
+public class MD5AuthenticationProvider
+ extends ConfigModelPasswordManagingAuthenticationProvider<MD5AuthenticationProvider>
+{
+ private final List<String> _mechanisms = Collections.unmodifiableList(Arrays.asList(PlainSaslServer.MECHANISM,
+ CRAMMD5HashedSaslServer.MECHANISM,
+ CRAMMD5HexSaslServer.MECHANISM));
+
+
+ @ManagedObjectFactoryConstructor
+ protected MD5AuthenticationProvider(final Map<String, Object> attributes, final Broker broker)
+ {
+ super(attributes, broker);
+ }
+
+ @Override
+ protected String createStoredPassword(final String password)
+ {
+ byte[] data = password.getBytes(StandardCharsets.UTF_8);
+ MessageDigest md = null;
+ try
+ {
+ md = MessageDigest.getInstance("MD5");
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ throw new ServerScopedRuntimeException("MD5 not supported although Java compliance requires it");
+ }
+
+ md.update(data);
+ return DatatypeConverter.printBase64Binary(md.digest());
+ }
+
+ @Override
+ void validateUser(final ManagedUser managedUser)
+ {
+ }
+
+ @Override
+ public List<String> getMechanisms()
+ {
+ return _mechanisms;
+ }
+
+ @Override
+ public SaslServer createSaslServer(final String mechanism,
+ final String localFQDN,
+ final Principal externalPrincipal)
+ throws SaslException
+ {
+ if(PlainSaslServer.MECHANISM.equals(mechanism))
+ {
+ return new PlainAdapterSaslServer(this);
+ }
+ else if(CRAMMD5HashedSaslServer.MECHANISM.equals(mechanism))
+ {
+ //simply delegate to the built in CRAM-MD5 SaslServer
+ return new CRAMMD5HashedSaslServer(mechanism, "AMQP", localFQDN, null, new MD5Callbackhandler(false));
+ }
+ else if(CRAMMD5HexSaslServer.MECHANISM.equals(mechanism))
+ {
+ //simply delegate to the built in CRAM-MD5 SaslServer
+ return new CRAMMD5HashedSaslServer(mechanism, "AMQP", localFQDN, null, new MD5Callbackhandler(true));
+ }
+ else
+ {
+ throw new SaslException("Unsupported mechanism: " + mechanism);
+ }
+ }
+
+ @Override
+ public AuthenticationResult authenticate(final String username, final String password)
+ {
+ ManagedUser user = getUser(username);
+ AuthenticationResult result;
+ if(user != null && user.getPassword().equals(createStoredPassword(password)))
+ {
+ result = new AuthenticationResult(new UsernamePrincipal(username));
+ }
+ else
+ {
+ result = new AuthenticationResult(AuthenticationResult.AuthenticationStatus.ERROR);
+ }
+ return result;
+ }
+ private static final char[] HEX_CHARACTERS =
+ {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+
+ private class MD5Callbackhandler implements CallbackHandler
+ {
+ private final boolean _hexify;
+ private String _username;
+
+ public MD5Callbackhandler(final boolean hexify)
+ {
+ _hexify = hexify;
+ }
+
+ public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException
+ {
+ List<Callback> callbackList = new ArrayList<>(Arrays.asList(callbacks));
+ Iterator<Callback> iter = callbackList.iterator();
+ while(iter.hasNext())
+ {
+ Callback callback = iter.next();
+ if (callback instanceof NameCallback)
+ {
+ _username = ((NameCallback) callback).getDefaultName();
+ iter.remove();
+ break;
+ }
+ }
+
+ if(_username != null)
+ {
+ iter = callbackList.iterator();
+ while (iter.hasNext())
+ {
+ Callback callback = iter.next();
+ if (callback instanceof PasswordCallback)
+ {
+ iter.remove();
+ ManagedUser user = getUser(_username);
+ if(user != null)
+ {
+ String passwordData = user.getPassword();
+ byte[] passwordBytes = DatatypeConverter.parseBase64Binary(passwordData);
+ char[] password;
+ if(_hexify)
+ {
+ password = new char[passwordBytes.length];
+
+ for(int i = 0; i < passwordBytes.length; i--)
+ {
+ password[2*i] = HEX_CHARACTERS[(((int)passwordBytes[i]) & 0xf0)>>4];
+ password[(2*i)+1] = HEX_CHARACTERS[(((int)passwordBytes[i]) & 0x0f)];
+ }
+ }
+ else
+ {
+ password = new char[passwordBytes.length];
+ for(int i = 0; i < passwordBytes.length; i++)
+ {
+ password[i] = (char) passwordBytes[i];
+ }
+ }
+ ((PasswordCallback) callback).setPassword(password);
+ }
+ else
+ {
+ ((PasswordCallback) callback).setPassword(null);
+ }
+ break;
+ }
+ }
+ }
+
+ for (Callback callback : callbackList)
+ {
+
+ if (callback instanceof AuthorizeCallback)
+ {
+ ((AuthorizeCallback) callback).setAuthorized(true);
+ }
+ else
+ {
+ throw new UnsupportedCallbackException(callback);
+ }
+ }
+ }
+ }
+}
diff --git a/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/ScramAuthUser.java b/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/ManagedUser.java
index b3de1d1f17..c8884e15a8 100644
--- a/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/ScramAuthUser.java
+++ b/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/ManagedUser.java
@@ -27,8 +27,6 @@ import java.util.HashMap;
import java.util.Map;
import java.util.Set;
-import javax.security.sasl.SaslException;
-
import org.apache.qpid.server.configuration.updater.VoidTask;
import org.apache.qpid.server.model.AbstractConfiguredObject;
import org.apache.qpid.server.model.ConfiguredObject;
@@ -41,24 +39,21 @@ import org.apache.qpid.server.model.StateTransition;
import org.apache.qpid.server.model.User;
import org.apache.qpid.server.security.access.Operation;
-@ManagedObject( category = false, type = ScramAuthUser.SCRAM_USER_TYPE)
-class ScramAuthUser extends AbstractConfiguredObject<ScramAuthUser> implements User<ScramAuthUser>
+@ManagedObject( category = false, type = ManagedUser.MANAGED_USER_TYPE)
+class ManagedUser extends AbstractConfiguredObject<ManagedUser> implements User<ManagedUser>
{
- public static final String SCRAM_USER_TYPE = "scram";
+ public static final String MANAGED_USER_TYPE = "managed";
- private AbstractScramAuthenticationManager _authenticationManager;
+ private ConfigModelPasswordManagingAuthenticationProvider<?> _authenticationManager;
@ManagedAttributeField
private String _password;
@ManagedObjectFactoryConstructor
- ScramAuthUser(final Map<String, Object> attributes, AbstractScramAuthenticationManager parent)
+ ManagedUser(final Map<String, Object> attributes, ConfigModelPasswordManagingAuthenticationProvider<?> parent)
{
super(parentsMap(parent), attributes);
_authenticationManager = parent;
- if(!ScramSHA1AuthenticationManager.ASCII.newEncoder().canEncode(getName()))
- {
- throw new IllegalArgumentException("Scram SHA1 user names are restricted to characters in the ASCII charset");
- }
+
setState(State.ACTIVE);
}
@@ -73,6 +68,7 @@ class ScramAuthUser extends AbstractConfiguredObject<ScramAuthUser> implements U
public void onValidate()
{
super.onValidate();
+ _authenticationManager.validateUser(this);
if(!isDurable())
{
throw new IllegalArgumentException(getClass().getSimpleName() + " must be durable");
@@ -122,17 +118,11 @@ class ScramAuthUser extends AbstractConfiguredObject<ScramAuthUser> implements U
if (attributes.containsKey(User.PASSWORD)
&& !newPassword.equals(getActualAttributes().get(User.PASSWORD)))
{
- try
- {
- modifiedAttributes.put(User.PASSWORD,
- _authenticationManager.createStoredPassword(newPassword));
- }
- catch (SaslException e)
- {
- throw new IllegalArgumentException(e);
- }
+ modifiedAttributes.put(User.PASSWORD,
+ _authenticationManager.createStoredPassword(newPassword));
+
}
- ScramAuthUser.super.setAttributes(modifiedAttributes);
+ ManagedUser.super.setAttributes(modifiedAttributes);
}
});
@@ -150,15 +140,9 @@ class ScramAuthUser extends AbstractConfiguredObject<ScramAuthUser> implements U
{
_authenticationManager.getSecurityManager().authoriseUserOperation(Operation.UPDATE, getName());
- try
- {
- changeAttribute(User.PASSWORD, getAttribute(User.PASSWORD), _authenticationManager.createStoredPassword(
- password));
- }
- catch (SaslException e)
- {
- throw new IllegalArgumentException(e);
- }
+ changeAttribute(User.PASSWORD, getAttribute(User.PASSWORD),
+ _authenticationManager.createStoredPassword(password));
+
}
@Override
@@ -170,7 +154,7 @@ class ScramAuthUser extends AbstractConfiguredObject<ScramAuthUser> implements U
@Override
public Map<String, Object> getPreferences()
{
- PreferencesProvider preferencesProvider = _authenticationManager.getPreferencesProvider();
+ PreferencesProvider<?> preferencesProvider = _authenticationManager.getPreferencesProvider();
if (preferencesProvider == null)
{
return null;
@@ -192,7 +176,7 @@ class ScramAuthUser extends AbstractConfiguredObject<ScramAuthUser> implements U
@Override
public Map<String, Object> setPreferences(Map<String, Object> preferences)
{
- PreferencesProvider preferencesProvider = _authenticationManager.getPreferencesProvider();
+ PreferencesProvider<?> preferencesProvider = _authenticationManager.getPreferencesProvider();
if (preferencesProvider == null)
{
return null;
diff --git a/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/PlainAuthenticationProvider.java b/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/PlainAuthenticationProvider.java
new file mode 100644
index 0000000000..5c79253ebb
--- /dev/null
+++ b/java/broker-core/src/main/java/org/apache/qpid/server/security/auth/manager/PlainAuthenticationProvider.java
@@ -0,0 +1,176 @@
+/*
+ *
+ * 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.Principal;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.sasl.AuthorizeCallback;
+import javax.security.sasl.Sasl;
+import javax.security.sasl.SaslException;
+import javax.security.sasl.SaslServer;
+
+import org.apache.qpid.server.model.Broker;
+import org.apache.qpid.server.model.ManagedObject;
+import org.apache.qpid.server.model.ManagedObjectFactoryConstructor;
+import org.apache.qpid.server.security.auth.AuthenticationResult;
+import org.apache.qpid.server.security.auth.UsernamePrincipal;
+import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5Initialiser;
+import org.apache.qpid.server.security.auth.sasl.plain.PlainAdapterSaslServer;
+import org.apache.qpid.server.security.auth.sasl.plain.PlainSaslServer;
+
+@ManagedObject( category = false, type = "Plain" )
+public class PlainAuthenticationProvider
+ extends ConfigModelPasswordManagingAuthenticationProvider<PlainAuthenticationProvider>
+{
+ private final List<String> _mechanisms = Collections.unmodifiableList(Arrays.asList(PlainSaslServer.MECHANISM,
+ CRAMMD5Initialiser.MECHANISM));
+
+
+ @ManagedObjectFactoryConstructor
+ protected PlainAuthenticationProvider(final Map<String, Object> attributes, final Broker broker)
+ {
+ super(attributes, broker);
+ }
+
+ @Override
+ protected String createStoredPassword(final String password)
+ {
+ return password;
+ }
+
+ @Override
+ void validateUser(final ManagedUser managedUser)
+ {
+ // NOOP
+ }
+
+ @Override
+ public List<String> getMechanisms()
+ {
+ return _mechanisms;
+ }
+
+ @Override
+ public SaslServer createSaslServer(final String mechanism,
+ final String localFQDN,
+ final Principal externalPrincipal)
+ throws SaslException
+ {
+ if(PlainSaslServer.MECHANISM.equals(mechanism))
+ {
+ return new PlainAdapterSaslServer(this);
+ }
+ else if(CRAMMD5Initialiser.MECHANISM.equals(mechanism))
+ {
+ //simply delegate to the built in CRAM-MD5 SaslServer
+ return Sasl.createSaslServer(mechanism, "AMQP", localFQDN, null, new ServerCallbackHandler());
+ }
+ else
+ {
+ throw new SaslException("Unsupported mechanism: " + mechanism);
+ }
+ }
+
+ @Override
+ public AuthenticationResult authenticate(final String username, final String password)
+ {
+ ManagedUser user = getUser(username);
+ AuthenticationResult result;
+ if(user != null && user.getPassword().equals(password))
+ {
+ result = new AuthenticationResult(new UsernamePrincipal(username));
+ }
+ else
+ {
+ result = new AuthenticationResult(AuthenticationResult.AuthenticationStatus.ERROR);
+ }
+ return result;
+ }
+
+ private class ServerCallbackHandler implements CallbackHandler
+ {
+ String _username;
+
+ public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException
+ {
+ List<Callback> callbackList = new ArrayList<>(Arrays.asList(callbacks));
+ Iterator<Callback> iter = callbackList.iterator();
+ while(iter.hasNext())
+ {
+ Callback callback = iter.next();
+ if (callback instanceof NameCallback)
+ {
+ _username = ((NameCallback) callback).getDefaultName();
+ iter.remove();
+ break;
+ }
+ }
+
+ if(_username != null)
+ {
+ iter = callbackList.iterator();
+ while (iter.hasNext())
+ {
+ Callback callback = iter.next();
+ if (callback instanceof PasswordCallback)
+ {
+ iter.remove();
+ ManagedUser user = getUser(_username);
+ if(user != null)
+ {
+ ((PasswordCallback) callback).setPassword(user.getPassword().toCharArray());
+ }
+ else
+ {
+ ((PasswordCallback) callback).setPassword(null);
+ }
+ break;
+ }
+ }
+ }
+
+ for (Callback callback : callbackList)
+ {
+
+ if (callback instanceof AuthorizeCallback)
+ {
+ ((AuthorizeCallback) callback).setAuthorized(true);
+ }
+ else
+ {
+ throw new UnsupportedCallbackException(callback);
+ }
+ }
+ }
+ }
+}