From: Prasanth Pallamreddy Date: Wed, 16 Apr 2014 18:48:08 +0000 (-0700) Subject: Allow abilitiy to boot controller with non-default admin credentials X-Git-Tag: autorelease-tag-v20140601202136_82eb3f9~210 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=commitdiff_plain;h=c198e5355b6702b6d96f1174bc4d1477143397cc Allow abilitiy to boot controller with non-default admin credentials - Default admin password can be overridden using the reset mechanism. NETWORK_ADMIN_PASSWORD_RECOVERY can optionally contain the password to be reset to. - Provide optional configuration to disallow factory default password. (-Dusermanager.disable-default-admin-password=true) - Convert ATN & ATZ security sensitive messages to 'trace' level instead of 'info' level Change-Id: I7dcaf15e8d562f61a3a4636a8abc244b0d6365ae Signed-off-by: Prasanth Pallamreddy --- diff --git a/opendaylight/security/src/main/java/org/opendaylight/controller/security/ControllerCustomRealm.java b/opendaylight/security/src/main/java/org/opendaylight/controller/security/ControllerCustomRealm.java index 6657571f89..157909424b 100644 --- a/opendaylight/security/src/main/java/org/opendaylight/controller/security/ControllerCustomRealm.java +++ b/opendaylight/security/src/main/java/org/opendaylight/controller/security/ControllerCustomRealm.java @@ -71,7 +71,7 @@ public class ControllerCustomRealm extends RealmBase { || result.equals(AuthResultEnum.AUTH_ACCEPT)) { return this.getPrincipal(username); } else { - logger.error("Authentication failed for user " + username); + logger.debug("Authentication failed for user " + username); return null; } } else { diff --git a/opendaylight/usermanager/api/src/main/java/org/opendaylight/controller/usermanager/UserConfig.java b/opendaylight/usermanager/api/src/main/java/org/opendaylight/controller/usermanager/UserConfig.java index 958b15978c..8298f5b76a 100644 --- a/opendaylight/usermanager/api/src/main/java/org/opendaylight/controller/usermanager/UserConfig.java +++ b/opendaylight/usermanager/api/src/main/java/org/opendaylight/controller/usermanager/UserConfig.java @@ -223,7 +223,7 @@ public class UserConfig extends ConfigurationObject implements Serializable { return new Status(StatusCode.SUCCESS); } - private Status validateClearTextPassword(String password) { + public static Status validateClearTextPassword(String password) { if (password == null || password.isEmpty()) { return new Status(StatusCode.BADREQUEST, "Password cannot be empty"); } @@ -247,7 +247,7 @@ public class UserConfig extends ConfigurationObject implements Serializable { // To make any changes to a user configured profile, current password // must always be provided - if (!this.password.equals(hash(this.salt, currentPassword))) { + if (!isPasswordMatch(currentPassword)) { return new Status(StatusCode.BADREQUEST, "Current password is incorrect"); } @@ -271,9 +271,13 @@ public class UserConfig extends ConfigurationObject implements Serializable { return status; } + public boolean isPasswordMatch(String otherPass) { + return this.password.equals(hash(this.salt, otherPass)); + } + public AuthResponse authenticate(String clearTextPassword) { AuthResponse locResponse = new AuthResponse(); - if (password.equals(hash(this.salt, clearTextPassword))) { + if (isPasswordMatch(clearTextPassword)) { locResponse.setStatus(AuthResultEnum.AUTH_ACCEPT_LOC); locResponse.addData(getRolesString()); } else { diff --git a/opendaylight/usermanager/implementation/src/main/java/org/opendaylight/controller/usermanager/internal/UserManager.java b/opendaylight/usermanager/implementation/src/main/java/org/opendaylight/controller/usermanager/internal/UserManager.java index be4b796a56..3f6ac4a8c7 100644 --- a/opendaylight/usermanager/implementation/src/main/java/org/opendaylight/controller/usermanager/internal/UserManager.java +++ b/opendaylight/usermanager/implementation/src/main/java/org/opendaylight/controller/usermanager/internal/UserManager.java @@ -8,9 +8,10 @@ package org.opendaylight.controller.usermanager.internal; +import java.io.BufferedReader; import java.io.File; -import java.io.FileInputStream; import java.io.FileNotFoundException; +import java.io.FileReader; import java.io.IOException; import java.io.ObjectInputStream; import java.util.ArrayList; @@ -52,6 +53,7 @@ import org.opendaylight.controller.usermanager.UserConfig; import org.opendaylight.controller.usermanager.security.SessionManager; import org.opendaylight.controller.usermanager.security.UserSecurityContextRepository; import org.osgi.framework.BundleContext; +import org.osgi.framework.BundleException; import org.osgi.framework.FrameworkUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -79,6 +81,8 @@ public class UserManager implements IUserManager, IObjectReader, private static final String SERVERS_FILE_NAME = "servers.conf"; private static final String AUTH_FILE_NAME = "authorization.conf"; private static final String RECOVERY_FILE = "NETWORK_ADMIN_PASSWORD_RECOVERY"; + private static final boolean DISALLOW_DEFAULT_ADMIN_PASSWORD = + Boolean.getBoolean("usermanager.disable-default-admin-password"); private ConcurrentMap localUserConfigList; private ConcurrentMap remoteServerConfigList; // local authorization info for remotely authenticated users @@ -95,8 +99,8 @@ public class UserManager implements IUserManager, IObjectReader, ADD("add", "added"), MODIFY("modify", "modified"), REMOVE("remove", "removed"); - private String action; - private String postAction; + private final String action; + private final String postAction; private Command(String action, String postAction) { this.action = action; this.postAction = postAction; @@ -212,46 +216,94 @@ public class UserManager implements IUserManager, IObjectReader, } - private void checkDefaultNetworkAdmin() { - /* - * If startup config is not there, it's old or it was deleted or if a - * password recovery was run, need to add Default Network Admin User - */ - if (!localUserConfigList.containsKey(DEFAULT_ADMIN)) { - List roles = new ArrayList(1); - roles.add(DEFAULT_ADMIN_ROLE); - // Need to skip the strong password check for the default admin - UserConfig defaultAdmin = UserConfig.getUncheckedUserConfig(UserManager.DEFAULT_ADMIN, - UserManager.DEFAULT_ADMIN_PASSWORD, roles); - localUserConfigList.put(UserManager.DEFAULT_ADMIN, defaultAdmin); + private void checkDefaultNetworkAdmin(String newPass) { + boolean usingFactoryPassword = false; + // network admin already configured. + if (localUserConfigList.containsKey(DEFAULT_ADMIN)) { + UserConfig uc = localUserConfigList.get(DEFAULT_ADMIN); + if (!uc.isPasswordMatch(DEFAULT_ADMIN_PASSWORD)) { + return; + } else { + usingFactoryPassword = true; + } + } + + List defaultRoles = new ArrayList(1); + defaultRoles.add(DEFAULT_ADMIN_ROLE); + if (newPass == null) { + if (!localUserConfigList.containsKey(DEFAULT_ADMIN)) { + // Need to skip the strong password check for the default admin + UserConfig defaultAdmin = UserConfig.getUncheckedUserConfig( + UserManager.DEFAULT_ADMIN, UserManager.DEFAULT_ADMIN_PASSWORD, + defaultRoles); + localUserConfigList.put(UserManager.DEFAULT_ADMIN, defaultAdmin); + usingFactoryPassword = true; + } + } else { + // use new password for admin + Status status = UserConfig.validateClearTextPassword(newPass); + if (status.isSuccess()) { + localUserConfigList.put(UserManager.DEFAULT_ADMIN, + new UserConfig(UserManager.DEFAULT_ADMIN, newPass, defaultRoles)); + logger.trace("Network Adminstrator password is reset."); + if (newPass.equals(DEFAULT_ADMIN_PASSWORD)) { + usingFactoryPassword = true; + } + } else { + logger.warn("Password is invalid - {}. Network Adminstrator password " + + "cannot be set.", status.getDescription()); + } + } + + if (usingFactoryPassword) { + if (DISALLOW_DEFAULT_ADMIN_PASSWORD) { + logger.warn("Network Administrator factory default password " + + "is disallowed. Please set the password prior to starting " + + "the controller. Shutting down now."); + // shutdown osgi + try { + BundleContext bundleContext = FrameworkUtil.getBundle( + getClass()).getBundleContext(); + bundleContext.getBundle(0).stop(); + } catch (BundleException e) { + logger.warn("Cannot stop framework ", e); + } + } else { + logger.warn("Network Administrator password is set to factory default. " + + "Please change the password as soon as possible."); + } } } - private void checkPasswordRecovery() { + private String checkPasswordRecovery() { final String fileDescription = "Default Network Administrator password recovery file"; + File recoveryFile = new File(UserManager.RECOVERY_FILE); + if (!recoveryFile.exists()) return null; + // read the recovery file + String pwd = null; try { - FileInputStream fis = new FileInputStream(UserManager.RECOVERY_FILE); + BufferedReader reader = new BufferedReader(new FileReader(recoveryFile)); + // read password from recovery file if it has one + pwd = reader.readLine(); + if (pwd != null && pwd.trim().length() == 0) { + pwd = null; + } + reader.close(); /* * Recovery file detected, remove current default network * administrator entry from local users configuration list. * Warn user and delete recovery file. */ this.localUserConfigList.remove(UserManager.DEFAULT_ADMIN); - logger.info("Default Network Administrator password has been reset to factory default."); - logger.info("Please change the default Network Administrator password as soon as possible"); - File filePointer = new File(UserManager.RECOVERY_FILE); - boolean status = filePointer.delete(); - if (!status) { + if (!recoveryFile.delete()) { logger.warn("Failed to delete {}", fileDescription); } else { logger.trace("{} deleted", fileDescription); } - fis.close(); - } catch (FileNotFoundException fnf) { - logger.trace("{} not present", fileDescription); } catch (IOException e) { - logger.warn("Failed to close file stream for {}", fileDescription); + logger.warn("Failed to process file {}", fileDescription); } + return pwd; } @Override @@ -295,20 +347,20 @@ public class UserManager implements IUserManager, IObjectReader, if (!remotelyAuthenticated) { UserConfig localUser = this.localUserConfigList.get(userName); if (localUser == null) { - logger.info( + logger.trace( "Local Authentication Failed for User:\"{}\", Reason: " + "user not found in Local Database", userName); return (AuthResultEnum.AUTH_INVALID_LOC_USER); } rcResponse = localUser.authenticate(password); if (rcResponse.getStatus() != AuthResultEnum.AUTH_ACCEPT_LOC) { - logger.info( + logger.trace( "Local Authentication Failed for User: \"{}\", Reason: {}", userName, rcResponse.getStatus().toString()); return (rcResponse.getStatus()); } - logger.info("Local Authentication Succeeded for User: \"{}\"", + logger.trace("Local Authentication Succeeded for User: \"{}\"", userName); } @@ -336,16 +388,16 @@ public class UserManager implements IUserManager, IObjectReader, * data to the rcResponse */ if (remotelyAuthenticated && !authorizationInfoIsPresent) { - logger.info( + logger.trace( "No Remote Authorization Info provided by Server for User: \"{}\"", userName); - logger.info( + logger.trace( "Looking for Local Authorization Info for User: \"{}\"", userName); AuthorizationConfig resource = authorizationConfList.get(userName); if (resource != null) { - logger.info("Found Local Authorization Info for User: \"{}\"", + logger.trace("Found Local Authorization Info for User: \"{}\"", userName); attributes = resource.getRolesString(); @@ -362,7 +414,7 @@ public class UserManager implements IUserManager, IObjectReader, result.setRoleList(attributes.split(" ")); authorized = true; } else { - logger.info("Not able to find Authorization Info for User: \"{}\"", + logger.trace("Not able to find Authorization Info for User: \"{}\"", userName); } @@ -371,10 +423,10 @@ public class UserManager implements IUserManager, IObjectReader, */ putUserInActiveList(userName, result); if (authorized) { - logger.info("User \"{}\" authorized for the following role(s): {}", + logger.trace("User \"{}\" authorized for the following role(s): {}", userName, result.getUserRoles()); } else { - logger.info("User \"{}\" Not Authorized for any role ", userName); + logger.trace("User \"{}\" Not Authorized for any role ", userName); } return rcResponse.getStatus(); @@ -843,10 +895,10 @@ public class UserManager implements IUserManager, IObjectReader, loadConfigurations(); // Check if a password recovery was triggered for default network admin user - checkPasswordRecovery(); + String pwd = checkPasswordRecovery(); // Make sure default Network Admin account is there - checkDefaultNetworkAdmin(); + checkDefaultNetworkAdmin(pwd); BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass()).getBundleContext(); bundleContext.registerService(CommandProvider.class.getName(), this, null);