package org.opendaylight.controller.usermanager;
import java.util.ArrayList;
-import java.util.Iterator;
import java.util.List;
import org.opendaylight.controller.sal.utils.Status;
return status;
}
+ @Override
public String toString() {
return "AuthorizationConfig=[user: " + user + ", roles: " + roles + "]";
}
+ @Override
public String getRolesString() {
return super.getRolesString();
}
package org.opendaylight.controller.usermanager;
+import java.util.Locale;
+
import org.opendaylight.controller.sal.authorization.UserLevel;
import org.springframework.security.core.GrantedAuthority;
@Override
public String getAuthority() {
- return "ROLE_" + this.userLevel.toString().toUpperCase();
+ return "ROLE_" + this.userLevel.toString().toUpperCase(Locale.ENGLISH);
}
}
package org.opendaylight.controller.usermanager;
import java.io.Serializable;
+import java.nio.charset.Charset;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Pattern;
import org.opendaylight.controller.sal.authorization.AuthResultEnum;
+import org.opendaylight.controller.sal.utils.HexEncode;
import org.opendaylight.controller.sal.utils.Status;
import org.opendaylight.controller.sal.utils.StatusCode;
import org.opendaylight.controller.usermanager.AuthResponse;
public class UserConfig implements Serializable {
private static final long serialVersionUID = 1L;
- /*
- * Clear text password as we are moving to some MD5 digest for when saving
- * configurations
- */
protected String user;
protected List<String> roles;
private String password;
private static final int USERNAME_MAXLENGTH = 32;
private static final int PASSWORD_MINLENGTH = 5;
private static final int PASSWORD_MAXLENGTH = 256;
- private static final Pattern INVALID_USERNAME_CHARACTERS = Pattern
- .compile("([/\\s\\.\\?#%;\\\\]+)");
+ private static final Pattern INVALID_USERNAME_CHARACTERS = Pattern.compile("([/\\s\\.\\?#%;\\\\]+)");
+ private static MessageDigest oneWayFunction = null;
+ static {
+ try {
+ UserConfig.oneWayFunction = MessageDigest.getInstance("SHA-1");
+ } catch (NoSuchAlgorithmException e) {
+ e.printStackTrace();
+ }
+ }
public UserConfig() {
}
+ /**
+ * Construct a UserConfig object and takes care of hashing the user password
+ *
+ * @param user
+ * the user name
+ * @param password
+ * the plain text password
+ * @param roles
+ * the list of roles
+ */
public UserConfig(String user, String password, List<String> roles) {
this.user = user;
+
this.password = password;
- this.roles = (roles == null) ? new ArrayList<String>()
- : new ArrayList<String>(roles);
+ if (this.validatePassword().isSuccess()) {
+ /*
+ * Only if the password is a valid one, hash it. So in case it is not
+ * valid, when UserConfig.validate() is called, the proper
+ * validation error will be returned to the caller. If we hashed a
+ * priori instead, the mis-configuration would be masked
+ */
+ this.password = hash(this.password);
+ }
+
+ this.roles = (roles == null) ? new ArrayList<String>() : new ArrayList<String>(roles);
}
public String getUser() {
@Override
public boolean equals(Object obj) {
- if (this == obj)
+ if (this == obj) {
return true;
- if (obj == null)
+ }
+ if (obj == null) {
return false;
- if (getClass() != obj.getClass())
+ }
+ if (getClass() != obj.getClass()) {
return false;
+ }
UserConfig other = (UserConfig) obj;
if (password == null) {
- if (other.password != null)
+ if (other.password != null) {
return false;
- } else if (!password.equals(other.password))
+ }
+ } else if (!password.equals(other.password)) {
return false;
+ }
if (roles == null) {
- if (other.roles != null)
+ if (other.roles != null) {
return false;
- } else if (!roles.equals(other.roles))
+ }
+ } else if (!roles.equals(other.roles)) {
return false;
+ }
if (user == null) {
- if (other.user != null)
+ if (other.user != null) {
return false;
- } else if (!user.equals(other.user))
+ }
+ } else if (!user.equals(other.user)) {
return false;
+ }
return true;
}
}
Matcher mUser = UserConfig.INVALID_USERNAME_CHARACTERS.matcher(user);
- if (user.length() > UserConfig.USERNAME_MAXLENGTH
- || mUser.find() == true) {
+ if (user.length() > UserConfig.USERNAME_MAXLENGTH || mUser.find() == true) {
return new Status(StatusCode.BADREQUEST,
"Username can have 1-32 non-whitespace "
+ "alphanumeric characters and any special "
return new Status(StatusCode.SUCCESS);
}
- public Status update(String currentPassword, String newPassword,
- List<String> newRoles) {
+ public Status update(String currentPassword, String newPassword, List<String> newRoles) {
+
// To make any changes to a user configured profile, current password
// must always be provided
- if (!this.password.equals(currentPassword)) {
- return new Status(StatusCode.BADREQUEST,
- "Current password is incorrect");
+ if (!this.password.equals(hash(currentPassword))) {
+ return new Status(StatusCode.BADREQUEST, "Current password is incorrect");
}
// Create a new object with the proposed modifications
UserConfig proposed = new UserConfig();
proposed.user = this.user;
- proposed.password = (newPassword != null)? newPassword : this.password;
- proposed.roles = (newRoles != null)? newRoles : this.roles;
+ proposed.password = (newPassword == null)? this.password : hash(newPassword);
+ proposed.roles = (newRoles == null)? this.roles : newRoles;
// Validate it
Status status = proposed.validate();
public AuthResponse authenticate(String clearTextPass) {
AuthResponse locResponse = new AuthResponse();
- if (password.equals(clearTextPass)) {
+ if (password.equals(hash(clearTextPass))) {
locResponse.setStatus(AuthResultEnum.AUTH_ACCEPT_LOC);
locResponse.addData(getRolesString());
} else {
}
return buffer.toString();
}
+
+ public static String hash(String message) {
+ if (message == null) {
+ return message;
+ }
+ UserConfig.oneWayFunction.reset();
+ return HexEncode.bytesToHexString(UserConfig.oneWayFunction.digest(message.getBytes(Charset.defaultCharset())));
+ }
}
public class AuthorizationUserConfigTest {
@Test
- public void AuthorizationConfigTest() {
+ public void authorizationConfigTest() {
AuthorizationConfig authConfig;
List<String> roles = new ArrayList<String>();
}
@Test
- public void UserConfigTest() {
+ public void userConfigTest() {
UserConfig userConfig;
List<String> roles = new ArrayList<String>();
.isSuccess());
// New Password = null, No change in password
- assertTrue(userConfig.getPassword().equals("ciscocisco"));
+ assertTrue(userConfig.getPassword().equals(UserConfig.hash("ciscocisco")));
// Password changed successfully, no change in user role
assertTrue(userConfig.update("ciscocisco", "cisco123", roles)
.isSuccess());
- assertTrue(userConfig.getPassword().equals("cisco123"));
+ assertTrue(userConfig.getPassword().equals(UserConfig.hash("cisco123")));
assertTrue(userConfig.getRoles().get(0).equals(
UserLevel.NETWORKOPERATOR.toString()));
roles.add(UserLevel.SYSTEMADMIN.toString());
assertTrue(userConfig.update("cisco123", "cisco123", roles)
.isSuccess());
- assertTrue(userConfig.getPassword().equals("cisco123"));
+ assertTrue(userConfig.getPassword().equals(UserConfig.hash("cisco123")));
assertTrue(userConfig.getRoles().get(0)
.equals(UserLevel.SYSTEMADMIN.toString()));
// Password and role changed successfully
assertTrue(userConfig.update("cisco123", "ciscocisco", roles)
.isSuccess());
- assertTrue(userConfig.getPassword().equals("ciscocisco"));
+ assertTrue(userConfig.getPassword().equals(UserConfig.hash("ciscocisco")));
assertTrue(userConfig.getRoles().get(0)
.equals(UserLevel.SYSTEMADMIN.toString()));
package org.opendaylight.controller.usermanager.internal;
-import java.util.Dictionary;
-import java.util.HashSet;
-import java.util.Hashtable;
-import java.util.Set;
-
import org.apache.felix.dm.Component;
import org.opendaylight.controller.clustering.services.IClusterGlobalServices;
import org.opendaylight.controller.configuration.IConfigurationAware;
* ComponentActivatorAbstractBase.
*
*/
+ @Override
public void init() {
}
* cleanup done by ComponentActivatorAbstractBase
*
*/
+ @Override
public void destroy() {
}
* instantiated in order to get an fully working implementation
* Object
*/
+ @Override
public Object[] getImplementations() {
return null;
}
* also optional per-container different behavior if needed, usually
* should not be the case though.
*/
+ @Override
public void configureInstance(Component c, Object imp, String containerName) {
}
* @return The list of implementations the bundle will support,
* in Global version
*/
+ @Override
protected Object[] getGlobalImplementations() {
- Object[] res = { UserManagerImpl.class };
+ Object[] res = { UserManager.class };
return res;
}
* @param imp implementation to be configured
* @param containerName container on which the configuration happens
*/
+ @Override
protected void configureGlobalInstance(Component c, Object imp) {
- if (imp.equals(UserManagerImpl.class)) {
+ if (imp.equals(UserManager.class)) {
// export the service
c.setInterface(new String[] {
/**
* The internal implementation of the User Manager.
*/
-public class UserManagerImpl implements IUserManager, IObjectReader,
+public class UserManager implements IUserManager, IObjectReader,
IConfigurationAware, CommandProvider, AuthenticationProvider {
- private static final Logger logger = LoggerFactory
- .getLogger(UserManagerImpl.class);
+ private static final Logger logger = LoggerFactory.getLogger(UserManager.class);
private static final String defaultAdmin = "admin";
private static final String defaultAdminPassword = "admin";
- private static final String defaultAdminRole = UserLevel.NETWORKADMIN
- .toString();
+ private static final String defaultAdminRole = UserLevel.NETWORKADMIN.toString();
private static final String ROOT = GlobalConstants.STARTUPHOME.toString();
- private static final String SAVE = "save";
private static final String usersFileName = ROOT + "users.conf";
private static final String serversFileName = ROOT + "servers.conf";
private static final String authFileName = ROOT + "authorization.conf";
private ConcurrentMap<String, AuthorizationConfig> authorizationConfList;
private ConcurrentMap<String, AuthenticatedUser> activeUsers;
private ConcurrentMap<String, IAAAProvider> authProviders;
- private ConcurrentMap<Long, String> localUserListSaveConfigEvent,
- remoteServerSaveConfigEvent, authorizationSaveConfigEvent;
private IClusterGlobalServices clusterGlobalService = null;
private SecurityContextRepository securityContextRepo = new UserSecurityContextRepository();
private IContainerAuthorization containerAuthorizationClient;
return authProviders.keySet();
}
- @SuppressWarnings("deprecation")
private void allocateCaches() {
- this.applicationAuthorizationClients = Collections
- .synchronizedSet(new HashSet<IResourceAuthorization>());
+ this.applicationAuthorizationClients = Collections.synchronizedSet(new HashSet<IResourceAuthorization>());
if (clusterGlobalService == null) {
logger.error("un-initialized clusterGlobalService, can't create cache");
return;
clusterGlobalService.createCache("usermanager.activeUsers",
EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
-
- clusterGlobalService.createCache(
- "usermanager.localUserSaveConfigEvent",
- EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
-
- clusterGlobalService.createCache(
- "usermanager.remoteServerSaveConfigEvent",
- EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
-
- clusterGlobalService.createCache(
- "usermanager.authorizationSaveConfigEvent",
- EnumSet.of(IClusterServices.cacheMode.TRANSACTIONAL));
} catch (CacheConfigException cce) {
logger.error("Cache configuration invalid - check cache mode");
} catch (CacheExistException ce) {
}
}
- @SuppressWarnings({ "unchecked", "deprecation" })
+ @SuppressWarnings({ "unchecked" })
private void retrieveCaches() {
if (clusterGlobalService == null) {
logger.error("un-initialized clusterService, can't retrieve cache");
if (authorizationConfList == null) {
logger.error("Failed to get cache for authorizationConfList");
}
-
- localUserListSaveConfigEvent = (ConcurrentMap<Long, String>) clusterGlobalService
- .getCache("usermanager.localUserSaveConfigEvent");
- if (localUserListSaveConfigEvent == null) {
- logger.error("Failed to get cache for localUserSaveConfigEvent");
- }
-
- remoteServerSaveConfigEvent = (ConcurrentMap<Long, String>) clusterGlobalService
- .getCache("usermanager.remoteServerSaveConfigEvent");
- if (remoteServerSaveConfigEvent == null) {
- logger.error("Failed to get cache for remoteServerSaveConfigEvent");
- }
-
- authorizationSaveConfigEvent = (ConcurrentMap<Long, String>) clusterGlobalService
- .getCache("usermanager.authorizationSaveConfigEvent");
- if (authorizationSaveConfigEvent == null) {
- logger.error("Failed to get cache for authorizationSaveConfigEvent");
- }
}
private void loadConfigurations() {
private void checkDefaultNetworkAdmin() {
// If startup config is not there, it's old or it was deleted,
- // need to add Default Admin
+ // need to add Default Network Admin User
if (!localUserConfigList.containsKey(defaultAdmin)) {
List<String> roles = new ArrayList<String>(1);
roles.add(defaultAdminRole);
- localUserConfigList.put(defaultAdmin, new UserConfig(defaultAdmin,
- defaultAdminPassword, roles));
+ localUserConfigList.put(defaultAdmin, new UserConfig(defaultAdmin, defaultAdminPassword, roles));
}
}
String user = AAAconf.getUser();
// Check default admin user
- if (user.equals(UserManagerImpl.defaultAdmin)) {
+ if (user.equals(UserManager.defaultAdmin)) {
String msg = "Invalid Request: Default Network Admin User cannot be " + ((delete)? "removed" : "added");
logger.debug(msg);
return new Status(StatusCode.NOTALLOWED, msg);
}
@Override
- public Status changeLocalUserPassword(String user, String curPassword,
- String newPassword) {
+ public Status changeLocalUserPassword(String user, String curPassword, String newPassword) {
UserConfig targetConfigEntry = null;
// update configuration entry
if (targetConfigEntry == null) {
return new Status(StatusCode.NOTFOUND, "User not found");
}
- Status status = targetConfigEntry
- .update(curPassword, newPassword, null);
+ Status status = targetConfigEntry.update(curPassword, newPassword, null);
if (!status.isSuccess()) {
return status;
}
role = ci.nextArgument();
}
- if (userName == null || userName.trim().isEmpty() || password == null
- || password.trim().isEmpty() || roles == null
+ if (userName == null || userName.trim().isEmpty() || password == null || password.trim().isEmpty()
|| roles.isEmpty()) {
ci.println("Invalid Arguments");
ci.println("umAddUser <user_name> <password> <user_role>");
import org.opendaylight.controller.usermanager.AuthorizationConfig;
/**
- * Unit Tests for UserManagerImpl
+ * Unit Tests for UserManager
*/
public class UserManagerImplTest {
- private static UserManagerImpl um;
+ private static UserManager um;
/**
* @throws java.lang.Exception
IUserManager userManager = (IUserManager) ServiceHelper
.getGlobalInstance(IUserManager.class, new Object());
- if (userManager instanceof UserManagerImpl) {
- um = (UserManagerImpl) userManager;
+ if (userManager instanceof UserManager) {
+ um = (UserManager) userManager;
} else {
- um = new UserManagerImpl();
+ um = new UserManager();
um.setAuthProviders(new ConcurrentHashMap<String, IAAAProvider>());
// mock up a remote server list with a dummy server
/**
* Test method for
- * {@link org.opendaylight.controller.usermanager.internal.UserManagerImpl#addAAAProvider(org.opendaylight.controller.usermanager.IAAAProvider)}
+ * {@link org.opendaylight.controller.usermanager.internal.UserManager#addAAAProvider(org.opendaylight.controller.usermanager.IAAAProvider)}
* .
*/
@Test
/**
* Test method for
- * {@link org.opendaylight.controller.usermanager.internal.UserManagerImpl#removeAAAProvider(org.opendaylight.controller.usermanager.IAAAProvider)}
+ * {@link org.opendaylight.controller.usermanager.internal.UserManager#removeAAAProvider(org.opendaylight.controller.usermanager.IAAAProvider)}
* and for for
- * {@link org.opendaylight.controller.usermanager.internal.UserManagerImpl#getAAAProvider(java.lang.String)}
+ * {@link org.opendaylight.controller.usermanager.internal.UserManager#getAAAProvider(java.lang.String)}
* .
*/
@Test
/**
* Test method for
- * {@link org.opendaylight.controller.usermanager.internal.UserManagerImpl#authenticate(java.lang.String, java.lang.String)}
+ * {@link org.opendaylight.controller.usermanager.internal.UserManager#authenticate(java.lang.String, java.lang.String)}
* .
*/
@Test
/**
* Test method for
- * {@link org.opendaylight.controller.usermanager.internal.UserManagerImpl#addRemoveLocalUser(org.opendaylight.controller.usermanager.org.opendaylight.controller.usermanager.internal.UserConfig, boolean)}
+ * {@link org.opendaylight.controller.usermanager.internal.UserManager#addRemoveLocalUser(org.opendaylight.controller.usermanager.org.opendaylight.controller.usermanager.internal.UserConfig, boolean)}
* .
*/
@Test
/**
* Test method for
- * {@link org.opendaylight.controller.usermanager.internal.UserManagerImpl#changeLocalUserPassword(java.lang.String, java.lang.String, java.lang.String)}
+ * {@link org.opendaylight.controller.usermanager.internal.UserManager#changeLocalUserPassword(java.lang.String, java.lang.String, java.lang.String)}
* .
*/
@Test
/**
* Test method for
- * {@link org.opendaylight.controller.usermanager.internal.UserManagerImpl#userLogout(java.lang.String)}
+ * {@link org.opendaylight.controller.usermanager.internal.UserManager#userLogout(java.lang.String)}
* .
*/
@Test
/**
* Test method for
- * {@link org.opendaylight.controller.usermanager.internal.UserManagerImpl#userTimedOut(java.lang.String)}
+ * {@link org.opendaylight.controller.usermanager.internal.UserManager#userTimedOut(java.lang.String)}
* .
*/
@Test
/**
* Test method for
- * {@link org.opendaylight.controller.usermanager.internal.UserManagerImpl#authenticate(org.springframework.security.core.Authentication)}
+ * {@link org.opendaylight.controller.usermanager.internal.UserManager#authenticate(org.springframework.security.core.Authentication)}
* .
*/
@Test
/**
* Test method for
- * {@link org.opendaylight.controller.usermanager.internal.UserManagerImpl#saveLocalUserList()}
+ * {@link org.opendaylight.controller.usermanager.internal.UserManager#saveLocalUserList()}
* .
*/
@Test
/**
* Test method for
- * {@link org.opendaylight.controller.usermanager.internal.UserManagerImpl#saveAAAServerList()}
+ * {@link org.opendaylight.controller.usermanager.internal.UserManager#saveAAAServerList()}
* .
*/
@Test
/**
* Test method for
- * {@link org.opendaylight.controller.usermanager.internal.UserManagerImpl#saveAuthorizationList()}
+ * {@link org.opendaylight.controller.usermanager.internal.UserManager#saveAuthorizationList()}
* .
*/
@Test
/**
* Test method for
- * {@link org.opendaylight.controller.usermanager.internal.UserManagerImpl#readObject(java.io.ObjectInputStream)}
+ * {@link org.opendaylight.controller.usermanager.internal.UserManager#readObject(java.io.ObjectInputStream)}
* .
*/
@Test
}
Gson gson = new Gson();
- UserConfig config = gson.fromJson(json, UserConfig.class);
+ UserConfig plainConfig = gson.fromJson(json, UserConfig.class);
+ // Recreate using the proper constructor which will hash the password
+ UserConfig config = new UserConfig(plainConfig.getUser(), plainConfig.getPassword(), plainConfig.getRoles());
Status result = (action.equals("add")) ? userManager.addLocalUser(config) : userManager.removeLocalUser(config);
if (result.isSuccess()) {