summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Ritchie <ritchiem@apache.org>2007-04-11 13:31:18 +0000
committerMartin Ritchie <ritchiem@apache.org>2007-04-11 13:31:18 +0000
commit786f4c78363db63f613f5d792d5f4465027e111b (patch)
treef4dc03210d786a236876bfd4c59c6504eae6cf30
parentc9aeb7dcd4cba2f47b0df7062108ef0b837c43bc (diff)
downloadqpid-python-786f4c78363db63f613f5d792d5f4465027e111b.tar.gz
QPID-446 AMQUserManagementMBean Initial implementation of user management in authentication file.
UserManagement - Added annotations for MBeanOperations PrincipalDatabase - Added new methods to update,create,delete Principal. - Implemented method on all PrincipalDatabase implementations, most return false to say not complete except Base64MD5PasswordFilePrincipalDatabase - which now stores in memory the password file and flushes any changes to disk. git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/branches/M2@527487 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/access/AMQUserManagementMBean.java143
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/access/UserManagement.java15
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java365
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java37
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java17
-rw-r--r--java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java44
-rw-r--r--java/client/src/main/java/org/apache/qpid/client/security/UsernameHashedPasswordCallbackHandler.java7
7 files changed, 561 insertions, 67 deletions
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/AMQUserManagementMBean.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/AMQUserManagementMBean.java
index 452479a3ba..c8b4c92a60 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/security/access/AMQUserManagementMBean.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/access/AMQUserManagementMBean.java
@@ -24,15 +24,33 @@ import org.apache.qpid.server.management.MBeanDescription;
import org.apache.qpid.server.management.AMQManagedObject;
import org.apache.qpid.server.management.MBeanOperationParameter;
import org.apache.qpid.server.management.MBeanOperation;
+import org.apache.qpid.server.security.auth.database.PrincipalDatabase;
+import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal;
+import org.apache.log4j.Logger;
import javax.management.JMException;
import javax.management.openmbean.TabularData;
+import javax.security.auth.login.AccountNotFoundException;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.Properties;
+import java.util.Map;
+import java.util.HashMap;
+import java.security.Principal;
/** MBean class for AMQUserManagementMBean. It implements all the management features exposed for managing users. */
@MBeanDescription("User Management Interface")
public class AMQUserManagementMBean extends AMQManagedObject implements UserManagement
{
+ private static final Logger _logger = Logger.getLogger(AMQUserManagementMBean.class);
+
+ private PrincipalDatabase _principalDatabase;
+ private File _accessFile;
+
+ Map<String, Principal> _users = new HashMap<String, Principal>();
+
public AMQUserManagementMBean() throws JMException
{
super(UserManagement.class, UserManagement.TYPE);
@@ -43,24 +61,84 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana
return UserManagement.TYPE;
}
- public boolean setPassword(@MBeanOperationParameter(name = "username", description = "Username")String username, @MBeanOperationParameter(name = "password", description = "Password")String password)
+ public boolean setPassword(@MBeanOperationParameter(name = "username", description = "Username")String username,
+ @MBeanOperationParameter(name = "password", description = "Password")String password)
{
- return true;
+ try
+ {
+ return _principalDatabase.updatePassword(new UsernamePrincipal(username), password);
+ }
+ catch (AccountNotFoundException e)
+ {
+ _logger.warn("Attempt to set password of non-existant user'" + username + "'");
+ return false;
+ }
}
- public boolean setRights(@MBeanOperationParameter(name = "username", description = "Username")String username, @MBeanOperationParameter(name = "read", description = "Administration read")boolean read, @MBeanOperationParameter(name = "write", description = "Administration write")boolean write, @MBeanOperationParameter(name = "admin", description = "Administration rights")boolean admin)
+ public boolean setRights(@MBeanOperationParameter(name = "username", description = "Username")String username,
+ @MBeanOperationParameter(name = "read", description = "Administration read")boolean read,
+ @MBeanOperationParameter(name = "write", description = "Administration write")boolean write,
+ @MBeanOperationParameter(name = "admin", description = "Administration rights")boolean admin)
{
return true;
}
- public boolean createUser(@MBeanOperationParameter(name = "username", description = "Username")String username, @MBeanOperationParameter(name = "password", description = "Password")String password, @MBeanOperationParameter(name = "read", description = "Administration read")boolean read, @MBeanOperationParameter(name = "write", description = "Administration write")boolean write, @MBeanOperationParameter(name = "admin", description = "Administration rights")boolean admin)
+ public boolean createUser(@MBeanOperationParameter(name = "username", description = "Username")String username,
+ @MBeanOperationParameter(name = "password", description = "Password")String password,
+ @MBeanOperationParameter(name = "read", description = "Administration read")boolean read,
+ @MBeanOperationParameter(name = "write", description = "Administration write")boolean write,
+ @MBeanOperationParameter(name = "admin", description = "Administration rights")boolean admin)
{
- return true;
+ try
+ {
+ if (_principalDatabase.createPrincipal(new UsernamePrincipal(username), password))
+ {
+ _users.remove(username);
+ return true;
+ }
+ }
+ catch (AccountNotFoundException e)
+ {
+ _logger.warn("Attempt to delete user (" + username + ") that doesn't exist");
+ }
+
+ return false;
}
public boolean deleteUser(@MBeanOperationParameter(name = "username", description = "Username")String username)
{
- return true;
+
+ try
+ {
+ if (_principalDatabase.deletePrincipal(new UsernamePrincipal(username)))
+ {
+ _users.remove(username);
+ return true;
+ }
+ }
+ catch (AccountNotFoundException e)
+ {
+ _logger.warn("Attempt to delete user (" + username + ") that doesn't exist");
+ }
+
+ return false;
+ }
+
+ public boolean reloadData()
+ {
+ try
+ {
+ loadAccessFile();
+
+ // Reload successful
+ return true;
+ }
+ catch (IOException e)
+ {
+ _logger.info("Reload failed due to:" + e);
+ // Reload unsuccessful
+ return false;
+ }
}
@MBeanOperation(name = "viewUsers", description = "All users with access rights to the system.")
@@ -68,4 +146,57 @@ public class AMQUserManagementMBean extends AMQManagedObject implements UserMana
{
return null;
}
+
+ /*** Broker Methods **/
+
+ /**
+ * setPrincipalDatabase
+ *
+ * @param database
+ *
+ * @throws java.io.IOException If the file cannot be read
+ */
+ public void setPrincipalDatabase(PrincipalDatabase database)
+ {
+ _principalDatabase = database;
+ }
+
+ /**
+ * setAccessFile
+ *
+ * @param accessFile the file to use for updating.
+ *
+ * @throws java.io.IOException If the file cannot be read
+ */
+ public void setAccessFile(File accessFile) throws IOException
+ {
+ _accessFile = accessFile;
+
+ if (_accessFile != null)
+ {
+ loadAccessFile();
+ }
+ else
+ {
+ _logger.warn("Access rights file specified is null. Access rights not changed.");
+ }
+ }
+
+ private void loadAccessFile() throws IOException
+ {
+ Properties accessRights = new Properties();
+ accessRights.load(new FileInputStream(_accessFile));
+ processAccessRights(accessRights);
+
+ }
+
+ /**
+ * user=read user=write user=readwrite user=admin
+ *
+ * @param accessRights The properties list of access rights to process
+ */
+ private void processAccessRights(Properties accessRights)
+ {
+ //To change body of created methods use File | Settings | File Templates.
+ }
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/access/UserManagement.java b/java/broker/src/main/java/org/apache/qpid/server/security/access/UserManagement.java
index e18d49a6d7..a29da431ef 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/security/access/UserManagement.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/access/UserManagement.java
@@ -35,8 +35,6 @@ public interface UserManagement
String TYPE = "UserManagement";
//********** Operations *****************//
-
-
/**
* set password for user
*
@@ -45,6 +43,7 @@ public interface UserManagement
*
* @return The result of the operation
*/
+ @MBeanOperation(name = "setPassword", description = "Set password for user.")
boolean setPassword(@MBeanOperationParameter(name = "username", description = "Username")String username,
@MBeanOperationParameter(name = "password", description = "Password")String password);
@@ -58,6 +57,7 @@ public interface UserManagement
*
* @return The result of the operation
*/
+ @MBeanOperation(name = "setRights", description = "Set access rights for user.")
boolean setRights(@MBeanOperationParameter(name = "username", description = "Username")String username,
@MBeanOperationParameter(name = "read", description = "Administration read")boolean read,
@MBeanOperationParameter(name = "write", description = "Administration write")boolean write,
@@ -74,6 +74,7 @@ public interface UserManagement
*
* @return The result of the operation
*/
+ @MBeanOperation(name = "createUser", description = "Create new user from system.")
boolean createUser(@MBeanOperationParameter(name = "username", description = "Username")String username,
@MBeanOperationParameter(name = "password", description = "Password")String password,
@MBeanOperationParameter(name = "read", description = "Administration read")boolean read,
@@ -87,8 +88,18 @@ public interface UserManagement
*
* @return The result of the operation
*/
+ @MBeanOperation(name = "deleteUser", description = "Delete user from system.")
boolean deleteUser(@MBeanOperationParameter(name = "username", description = "Username")String username);
+
+ /**
+ * Reload the date from disk
+ *
+ * @return The result of the operation
+ */
+ @MBeanOperation(name = "reloadData", description = "Reload the authentication file from disk.")
+ boolean reloadData();
+
/**
* View users returns all the users that are currently available to the system.
*
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java
index c603a0d5c3..1fd86f0bac 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/Base64MD5PasswordFilePrincipalDatabase.java
@@ -23,19 +23,29 @@ package org.apache.qpid.server.security.auth.database;
import org.apache.log4j.Logger;
import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser;
import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5HashedInitialiser;
+import org.apache.qpid.server.security.access.AMQUserManagementMBean;
+import org.apache.qpid.server.security.Passwd;
import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.codec.EncoderException;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.login.AccountNotFoundException;
+import javax.management.JMException;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.FileReader;
+import java.io.UnsupportedEncodingException;
+import java.io.BufferedWriter;
+import java.io.FileWriter;
+import java.io.PrintStream;
import java.util.regex.Pattern;
import java.util.Map;
import java.util.HashMap;
+import java.util.List;
import java.security.Principal;
+import java.security.NoSuchAlgorithmException;
/**
* Represents a user database where the account information is stored in a simple flat file.
@@ -54,6 +64,10 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase
private Map<String, AuthenticationProviderInitialiser> _saslServers;
+ AMQUserManagementMBean _mbean;
+ private static final String DEFAULT_ENCODING = "utf-8";
+ private Map<String, User> _users = new HashMap<String, User>();
+
public Base64MD5PasswordFilePrincipalDatabase()
{
_saslServers = new HashMap<String, AuthenticationProviderInitialiser>();
@@ -66,9 +80,19 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase
CRAMMD5HashedInitialiser cram = new CRAMMD5HashedInitialiser();
cram.initialise(this);
_saslServers.put(cram.getMechanismName(), cram);
+
+ try
+ {
+ _mbean = new AMQUserManagementMBean();
+ _mbean.setPrincipalDatabase(this);
+ }
+ catch (JMException e)
+ {
+ _logger.warn("User management disabled as unable to create MBean:" + e);
+ }
}
- public void setPasswordFile(String passwordFile) throws FileNotFoundException
+ public void setPasswordFile(String passwordFile) throws IOException
{
File f = new File(passwordFile);
_logger.info("PasswordFilePrincipalDatabase using file " + f.getAbsolutePath());
@@ -82,10 +106,11 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase
throw new FileNotFoundException("Cannot read password file " + f +
". Check permissions.");
}
+
+ loadPasswordFile();
}
- public void setPassword(Principal principal, PasswordCallback callback) throws IOException,
- AccountNotFoundException
+ public void setPassword(Principal principal, PasswordCallback callback) throws AccountNotFoundException
{
if (_passwordFile == null)
{
@@ -95,7 +120,9 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase
{
throw new IllegalArgumentException("principal must not be null");
}
+
char[] pwd = lookupPassword(principal.getName());
+
if (pwd != null)
{
callback.setPassword(pwd);
@@ -106,55 +133,169 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase
}
}
- public boolean verifyPassword(Principal principal, char[] password) throws AccountNotFoundException
+ public boolean verifyPassword(Principal principal, String password) throws AccountNotFoundException
{
try
{
char[] pwd = lookupPassword(principal.getName());
- return compareCharArray(pwd, password);
+ byte[] passwordBytes = password.getBytes(DEFAULT_ENCODING);
+
+ int index = 0;
+ boolean verified = true;
+
+ while (verified & index < passwordBytes.length)
+ {
+ verified = (pwd[index] == (char) passwordBytes[index]);
+ index++;
+ }
+ return verified;
}
- catch (IOException e)
+ catch (UnsupportedEncodingException e)
{
return false;
}
}
- public Map<String, AuthenticationProviderInitialiser> getMechanisms()
+ public boolean updatePassword(Principal principal, String password) throws AccountNotFoundException
{
- return _saslServers;
- }
+ User user = _users.get(principal.getName());
- private boolean compareCharArray(char[] a, char[] b)
- {
- boolean equal = false;
- if (a.length == b.length)
+ if (user == null)
{
- equal = true;
- int index = 0;
- while (equal && index < a.length)
+ throw new AccountNotFoundException(principal.getName());
+ }
+
+ try
+ {
+
+ char[] passwd = convertPassword(password);
+
+ user.setPassword(passwd);
+
+ try
{
- equal = a[index] == b[index];
- index++;
+ savePasswordFile();
}
+ catch (IOException e)
+ {
+ _logger.error("Unable to save password file, password change for user'"
+ + principal + "' will revert at restart");
+ return false;
+ }
+ return true;
+ }
+ catch (UnsupportedEncodingException e)
+ {
+ return false;
}
- return equal;
}
+ private char[] convertPassword(String password) throws UnsupportedEncodingException
+ {
+ byte[] passwdBytes = password.getBytes(DEFAULT_ENCODING);
+
+ char[] passwd = new char[passwdBytes.length];
+
+ int index = 0;
+
+ for (byte b : passwdBytes)
+ {
+ passwd[index] = (char) b;
+ }
+
+ return passwd;
+ }
+
+ public boolean createPrincipal(Principal principal, String password) throws AccountNotFoundException
+ {
+ if (_users.get(principal.getName()) != null)
+ {
+ return false;
+ }
+
+ User user = null;
+ try
+ {
+ user = new User(principal.getName(), convertPassword(password));
+ }
+ catch (UnsupportedEncodingException e)
+ {
+ _logger.warn("Unable to encode password:" + e);
+ return false;
+ }
+
+ _users.put(user.getName(), user);
+
+ try
+ {
+ savePasswordFile();
+ return true;
+ }
+ catch (IOException e)
+ {
+ return false;
+ }
+
+ }
+
+ public boolean deletePrincipal(Principal principal) throws AccountNotFoundException
+ {
+ User user = _users.get(principal.getName());
+
+ if (user == null)
+ {
+ throw new AccountNotFoundException(principal.getName());
+ }
+
+ user.delete();
+
+ try
+ {
+ savePasswordFile();
+ }
+ catch (IOException e)
+ {
+ _logger.warn("Unable to remove user '" + user.getName() + "' from password file.");
+ return false;
+ }
+
+ _users.remove(user.getName());
+
+ return true;
+ }
+
+ public Map<String, AuthenticationProviderInitialiser> getMechanisms()
+ {
+ return _saslServers;
+ }
/**
* Looks up the password for a specified user in the password file. Note this code is <b>not</b> secure since it
* creates strings of passwords. It should be modified to create only char arrays which get nulled out.
*
- * @param name
+ * @param name The principal name to lookup
*
- * @return
- *
- * @throws java.io.IOException
+ * @return a char[] for use in SASL.
*/
- private char[] lookupPassword(String name) throws IOException
+ private char[] lookupPassword(String name)
+ {
+ User user = _users.get(name);
+ if (user == null)
+ {
+ return null;
+ }
+ else
+ {
+ return user.getPassword();
+ }
+ }
+
+
+ private void loadPasswordFile() throws IOException
{
+ _users.clear();
+
BufferedReader reader = null;
- byte[] passwd = null;
try
{
reader = new BufferedReader(new FileReader(_passwordFile));
@@ -163,43 +304,75 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase
while ((line = reader.readLine()) != null)
{
String[] result = _regexp.split(line);
- if (result == null || result.length < 2)
+ if (result == null || result.length < 2 || result[0].startsWith("#"))
{
continue;
}
- if (name.equals(result[0]))
- {
+ User user = new User(result);
+ _users.put(user.getName(), user);
+ }
+ }
+ finally
+ {
+ if (reader != null)
+ {
+ reader.close();
+ }
+ }
+ }
+ private void savePasswordFile() throws IOException
+ {
+ BufferedReader reader = null;
+ PrintStream writer = null;
+ File tmp = new File(_passwordFile.getAbsolutePath() + ".tmp");
+ try
+ {
+ writer = new PrintStream(tmp);
+ reader = new BufferedReader(new FileReader(_passwordFile));
+ String line;
- char[] raw = result[1].toCharArray();
+ while ((line = reader.readLine()) != null)
+ {
+ String[] result = _regexp.split(line);
+ if (result == null || result.length < 2 || result[0].startsWith("#"))
+ {
+ writer.write(line.getBytes(DEFAULT_ENCODING));
+ continue;
+ }
- byte[] encoded = new byte[result[1].length() + 1];
+ User user = _users.get(result[0]);
- int index = 0;
- for (char c : raw)
+ if (user == null)
+ {
+ writer.write(line.getBytes(DEFAULT_ENCODING));
+ }
+ else if (!user.isDeleted())
+ {
+ if (!user.isModified())
{
- index++;
- encoded[index] = (byte) c;
+ writer.write(line.getBytes(DEFAULT_ENCODING));
}
-
- Base64 b64 = new Base64();
- byte[] decoded = b64.decode(encoded);
-
-
- char[] hashedPassword = new char[decoded.length + 1];
-
- index = 0;
- for (byte c : decoded)
+ else
{
- index++;
- hashedPassword[index] = (char) c;
- }
+ try
+ {
+ byte[] encodedPassword = user.getEncodePassword();
- return hashedPassword;
+ writer.write((user.getName() + ":").getBytes(DEFAULT_ENCODING));
+ writer.write(encodedPassword);
+ }
+ catch (EncoderException e)
+ {
+ _logger.warn("Unable to encode new password reverting to old password.");
+ writer.write(line.getBytes(DEFAULT_ENCODING));
+ }
+ }
}
+
+
}
- return null;
}
finally
{
@@ -207,6 +380,102 @@ public class Base64MD5PasswordFilePrincipalDatabase implements PrincipalDatabase
{
reader.close();
}
+
+ if (writer != null)
+ {
+ writer.close();
+ }
+
+ // Swap temp file to main password file.
+ tmp.renameTo(_passwordFile);
+ }
+ }
+
+ private class User
+ {
+ String _name;
+ char[] _password;
+ byte[] _encodedPassword = null;
+ private boolean _modified = false;
+ private boolean _deleted = false;
+
+ User(String[] data) throws UnsupportedEncodingException
+ {
+ if (data.length != 2)
+ {
+ throw new IllegalArgumentException("User Data should be lenght 2, username, password");
+ }
+
+ _name = data[0];
+
+ byte[] encoded_password = data[1].getBytes(DEFAULT_ENCODING);
+
+ Base64 b64 = new Base64();
+ byte[] decoded = b64.decode(encoded_password);
+
+ _encodedPassword = encoded_password;
+
+ _password = new char[decoded.length];
+
+ int index = 0;
+ for (byte c : decoded)
+ {
+ _password[index++] = (char) c;
+ }
+ }
+
+ public User(String name, char[] password)
+ {
+ _name = name;
+ setPassword(password);
+ }
+
+ String getName()
+ {
+ return _name;
+ }
+
+ char[] getPassword()
+ {
+ return _password;
+ }
+
+ void setPassword(char[] password)
+ {
+ _password = password;
+ _modified = true;
+ _encodedPassword = null;
+ }
+
+
+ byte[] getEncodePassword() throws EncoderException, UnsupportedEncodingException
+ {
+ if (_encodedPassword == null)
+ {
+ encodePassword();
+ }
+ return _encodedPassword;
+ }
+
+ private void encodePassword() throws EncoderException, UnsupportedEncodingException
+ {
+ Base64 b64 = new Base64();
+ _encodedPassword = b64.encode(new String(_password).getBytes(DEFAULT_ENCODING));
+ }
+
+ public boolean isModified()
+ {
+ return _modified;
+ }
+
+ public boolean isDeleted()
+ {
+ return _deleted;
+ }
+
+ public void delete()
+ {
+ _deleted = true;
}
}
}
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java
index fc20b0693b..ac7bfa29a3 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PlainPasswordFilePrincipalDatabase.java
@@ -34,6 +34,7 @@ import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.FileReader;
+import java.io.UnsupportedEncodingException;
import java.util.regex.Pattern;
import java.util.Map;
import java.util.HashMap;
@@ -119,12 +120,13 @@ public class PlainPasswordFilePrincipalDatabase implements PrincipalDatabase
}
}
- public boolean verifyPassword(Principal principal, char[] password) throws AccountNotFoundException
+ public boolean verifyPassword(Principal principal, String password) throws AccountNotFoundException
{
try
{
char[] pwd = lookupPassword(principal.getName());
- return compareCharArray(pwd, password);
+
+ return compareCharArray(pwd, convertPassword(password));
}
catch (IOException e)
{
@@ -132,6 +134,37 @@ public class PlainPasswordFilePrincipalDatabase implements PrincipalDatabase
}
}
+ private char[] convertPassword(String password) throws UnsupportedEncodingException
+ {
+ byte[] passwdBytes = password.getBytes("utf-8");
+
+ char[] passwd = new char[passwdBytes.length];
+
+ int index = 0;
+
+ for (byte b : passwdBytes)
+ {
+ passwd[index] = (char) b;
+ }
+
+ return passwd;
+ }
+
+ public boolean updatePassword(Principal principal, String password) throws AccountNotFoundException
+ {
+ return false; // updates denied
+ }
+
+ public boolean createPrincipal(Principal principal, String password) throws AccountNotFoundException
+ {
+ return false; // updates denied
+ }
+
+ public boolean deletePrincipal(Principal principal) throws AccountNotFoundException
+ {
+ return false; // updates denied
+ }
+
public Map<String, AuthenticationProviderInitialiser> getMechanisms()
{
return _saslServers;
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java
index 32ef9cc0d2..50a2845b4f 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PrincipalDatabase.java
@@ -23,6 +23,7 @@ package org.apache.qpid.server.security.auth.database;
import org.apache.qpid.server.security.auth.sasl.AuthenticationProviderInitialiser;
import java.io.IOException;
+import java.io.UnsupportedEncodingException;
import java.security.Principal;
import java.util.Map;
@@ -46,7 +47,7 @@ public interface PrincipalDatabase
void setPassword(Principal principal, PasswordCallback callback)
throws IOException, AccountNotFoundException;
- /**
+ /**
* Set the password for a given principal in the specified callback. This is used for certain SASL providers. The
* user database implementation should look up the password in any way it chooses and set it in the callback by
* calling its setPassword method.
@@ -54,10 +55,20 @@ public interface PrincipalDatabase
* @param principal the principal
* @param password the password to be verified
*
- * @throws AccountNotFoundException if the account for specified principal could not be found
* @return true if the account is verified.
+ *
+ * @throws AccountNotFoundException if the account for specified principal could not be found
*/
- boolean verifyPassword(Principal principal, char[] password)
+ boolean verifyPassword(Principal principal, String password)
+ throws AccountNotFoundException;
+
+ boolean updatePassword(Principal principal, String password)
+ throws AccountNotFoundException;
+
+ boolean createPrincipal(Principal principal, String password)
+ throws AccountNotFoundException;
+
+ boolean deletePrincipal(Principal principal)
throws AccountNotFoundException;
public Map<String, AuthenticationProviderInitialiser> getMechanisms();
diff --git a/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java b/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java
index f5332b6e6b..86d7ed40ee 100644
--- a/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java
+++ b/java/broker/src/main/java/org/apache/qpid/server/security/auth/database/PropertiesPrincipalDatabase.java
@@ -31,6 +31,7 @@ import java.util.Map;
import java.util.HashMap;
import java.security.Principal;
import java.io.IOException;
+import java.io.UnsupportedEncodingException;
public class PropertiesPrincipalDatabase implements PrincipalDatabase
{
@@ -76,11 +77,33 @@ public class PropertiesPrincipalDatabase implements PrincipalDatabase
}
}
- public boolean verifyPassword(Principal principal, char[] password) throws AccountNotFoundException
+ public boolean verifyPassword(Principal principal, String password) throws AccountNotFoundException
{
char[] pwd = _users.getProperty(principal.getName()).toCharArray();
- return compareCharArray(pwd, password);
+ try
+ {
+ return compareCharArray(pwd, convertPassword(password));
+ }
+ catch (UnsupportedEncodingException e)
+ {
+ return false;
+ }
+ }
+
+ public boolean updatePassword(Principal principal, String password) throws AccountNotFoundException
+ {
+ return false; // updates denied
+ }
+
+ public boolean createPrincipal(Principal principal, String password) throws AccountNotFoundException
+ {
+ return false; // updates denied
+ }
+
+ public boolean deletePrincipal(Principal principal) throws AccountNotFoundException
+ {
+ return false; // updates denied
}
private boolean compareCharArray(char[] a, char[] b)
@@ -99,6 +122,23 @@ public class PropertiesPrincipalDatabase implements PrincipalDatabase
return equal;
}
+ private char[] convertPassword(String password) throws UnsupportedEncodingException
+ {
+ byte[] passwdBytes = password.getBytes("utf-8");
+
+ char[] passwd = new char[passwdBytes.length];
+
+ int index = 0;
+
+ for (byte b : passwdBytes)
+ {
+ passwd[index] = (char) b;
+ }
+
+ return passwd;
+ }
+
+
public Map<String, AuthenticationProviderInitialiser> getMechanisms()
{
return _saslServers;
diff --git a/java/client/src/main/java/org/apache/qpid/client/security/UsernameHashedPasswordCallbackHandler.java b/java/client/src/main/java/org/apache/qpid/client/security/UsernameHashedPasswordCallbackHandler.java
index dcca55e6c2..46323e8c09 100644
--- a/java/client/src/main/java/org/apache/qpid/client/security/UsernameHashedPasswordCallbackHandler.java
+++ b/java/client/src/main/java/org/apache/qpid/client/security/UsernameHashedPasswordCallbackHandler.java
@@ -91,13 +91,12 @@ public class UsernameHashedPasswordCallbackHandler implements AMQCallbackHandler
byte[] digest = md.digest();
- char[] hash = new char[digest.length + 1];
+ char[] hash = new char[digest.length ];
int index = 0;
for (byte b : digest)
- {
- index++;
- hash[index] = (char) b;
+ {
+ hash[index++] = (char) b;
}
return hash;