Allow abilitiy to boot controller with non-default admin credentials 48/6248/2
authorPrasanth Pallamreddy <ppallamr@cisco.com>
Wed, 16 Apr 2014 18:48:08 +0000 (11:48 -0700)
committerPrasanth Pallamreddy <ppallamr@cisco.com>
Wed, 16 Apr 2014 22:13:18 +0000 (15:13 -0700)
  - 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 <ppallamr@cisco.com>
opendaylight/security/src/main/java/org/opendaylight/controller/security/ControllerCustomRealm.java
opendaylight/usermanager/api/src/main/java/org/opendaylight/controller/usermanager/UserConfig.java
opendaylight/usermanager/implementation/src/main/java/org/opendaylight/controller/usermanager/internal/UserManager.java

index 6657571f898061003b386bba1ee9e0f76e2cac2e..157909424bb152dab343c15905d9675eb91712fb 100644 (file)
@@ -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 {
index 958b15978cf648114597047198c07375a7133802..8298f5b76a730e1d39e74db1115bf55fc0196ca5 100644 (file)
@@ -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 {
index be4b796a56cb3b76b19ae7c08a69dbe0933102e2..3f6ac4a8c786af11cb88bf16e4ab0c44ae8b3097 100644 (file)
@@ -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<String, UserConfig> localUserConfigList;
     private ConcurrentMap<String, ServerConfig> 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<String> roles = new ArrayList<String>(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<String> defaultRoles = new ArrayList<String>(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);