Merge "UI: Allow admin to reset password for other users"
authorGiovanni Meo <gmeo@cisco.com>
Thu, 19 Sep 2013 14:19:39 +0000 (14:19 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Thu, 19 Sep 2013 14:19:39 +0000 (14:19 +0000)
18 files changed:
opendaylight/distribution/opendaylight/pom.xml
opendaylight/distribution/opendaylight/src/main/resources/configuration/config.ini
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/authorization/AppRoleLevel.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/Node.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/NodeConnector.java
opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/core/NodeTable.java
opendaylight/topologymanager/implementation/pom.xml [moved from opendaylight/topologymanager/pom.xml with 97% similarity]
opendaylight/topologymanager/implementation/src/main/java/org/opendaylight/controller/topologymanager/ITopologyManager.java [moved from opendaylight/topologymanager/src/main/java/org/opendaylight/controller/topologymanager/ITopologyManager.java with 100% similarity]
opendaylight/topologymanager/implementation/src/main/java/org/opendaylight/controller/topologymanager/ITopologyManagerAware.java [moved from opendaylight/topologymanager/src/main/java/org/opendaylight/controller/topologymanager/ITopologyManagerAware.java with 100% similarity]
opendaylight/topologymanager/implementation/src/main/java/org/opendaylight/controller/topologymanager/ITopologyManagerClusterWideAware.java [moved from opendaylight/topologymanager/src/main/java/org/opendaylight/controller/topologymanager/ITopologyManagerClusterWideAware.java with 100% similarity]
opendaylight/topologymanager/implementation/src/main/java/org/opendaylight/controller/topologymanager/TopologyUserLinkConfig.java [moved from opendaylight/topologymanager/src/main/java/org/opendaylight/controller/topologymanager/TopologyUserLinkConfig.java with 100% similarity]
opendaylight/topologymanager/implementation/src/main/java/org/opendaylight/controller/topologymanager/internal/Activator.java [moved from opendaylight/topologymanager/src/main/java/org/opendaylight/controller/topologymanager/internal/Activator.java with 100% similarity]
opendaylight/topologymanager/implementation/src/main/java/org/opendaylight/controller/topologymanager/internal/TopologyManagerImpl.java [moved from opendaylight/topologymanager/src/main/java/org/opendaylight/controller/topologymanager/internal/TopologyManagerImpl.java with 100% similarity]
opendaylight/topologymanager/implementation/src/test/java/org/opendaylight/controller/topologymanager/internal/TopologyManagerImplTest.java [moved from opendaylight/topologymanager/src/test/java/org/opendaylight/controller/topologymanager/internal/TopologyManagerImplTest.java with 100% similarity]
opendaylight/usermanager/api/src/main/java/org/opendaylight/controller/usermanager/UserConfig.java
opendaylight/usermanager/api/src/test/java/org/opendaylight/controller/usermanager/AuthorizationUserConfigTest.java
opendaylight/usermanager/implementation/src/main/java/org/opendaylight/controller/usermanager/internal/Activator.java
opendaylight/usermanager/implementation/src/main/java/org/opendaylight/controller/usermanager/internal/UserManager.java

index 1fb131e4aff8fc6e5c505e6437bc8a5dc6c2e2b9..3efd97e2aa3857fa549e752ae16d1aa6990ab0f3 100644 (file)
@@ -74,7 +74,7 @@
     <module>../../statisticsmanager/api</module>
     <module>../../statisticsmanager/implementation</module>
     <module>../../statisticsmanager/integrationtest</module>
-    <module>../../topologymanager</module>
+    <module>../../topologymanager/implementation</module>
     <module>../../usermanager/api</module>
     <module>../../usermanager/implementation</module>
     <module>../../connectionmanager/api</module>
index 970929f794b93d2e329ddbfa7b5684b51fbf043a..12f18ff6452b1cbec6f9a6d4bec1c6949b1d2836 100644 (file)
@@ -94,3 +94,6 @@ controllerKeyStore=
 controllerKeyStorePassword=
 controllerTrustStore=
 controllerTrustStorePassword=
+
+# User Manager configurations
+enableStrongPasswordCheck = false
index 7e73dd414f4e18dd927b3085b074bd02af56f762..124b495147db61d99b53b24138bf47e5dda4083c 100644 (file)
@@ -45,9 +45,9 @@ public enum AppRoleLevel implements Serializable {
     }
 
     public static AppRoleLevel fromString(String levelString) {
-        for (AppRoleLevel level : AppRoleLevel.values()) {
-                if (level.toString().equals(levelString)) {
-                        return level;
+        for (AppRoleLevel rolelevel : AppRoleLevel.values()) {
+                if (rolelevel.toString().equals(levelString)) {
+                        return rolelevel;
                 }
         }
         return null;
index d21a147506dfd8e2f546ddd5210df33b1fc29c20..0ea04c32065e7746518504901abc454f4d5e6281 100644 (file)
@@ -323,10 +323,10 @@ public class Node implements Serializable {
     @Override
     public String toString() {
         if (this.nodeType.equals(NodeIDType.OPENFLOW)) {
-            return this.nodeType.toString() + "|"
+            return this.nodeType + "|"
                 + HexEncode.longToHexString((Long) this.nodeID);
         } else {
-            return this.nodeType.toString() + "|" + this.nodeID.toString();
+            return this.nodeType + "|" + this.nodeID.toString();
         }
     }
 
index 50ccf69b4090ad220aebb5b97b35559f978efd56..46c5a9dae933baee49c47e98476a37dd9222dae5 100644 (file)
@@ -464,9 +464,9 @@ public class NodeConnector implements Serializable {
             .equals(NodeConnectorIDType.SWSTACK) ||
             this.nodeConnectorType
             .equals(NodeConnectorIDType.HWPATH)) {
-            return this.nodeConnectorType.toString();
+            return this.nodeConnectorType;
         } else {
-            return this.nodeConnectorType.toString() + "|"
+            return this.nodeConnectorType + "|"
                     + this.nodeConnectorID.toString();
         }
     }
index 7b7f1ccaeaf22f29dc4fa2a9c35b75854086b46f..9e763eb241a273375edf7c27a6ed40871a9b0a0a 100644 (file)
@@ -292,7 +292,7 @@ public class NodeTable implements Serializable {
     }
 
     public String getNodeTableIdAsString() {
-        return this.nodeTableType.toString() + "|"
+        return this.nodeTableType + "|"
                 + this.nodeTableID.toString();
     }
 
similarity index 97%
rename from opendaylight/topologymanager/pom.xml
rename to opendaylight/topologymanager/implementation/pom.xml
index 98bc0e42c81cf0cb08b7bcd5225289726c67b84e..399f878223aa639e5acd421ecb55b7134ab83d12 100755 (executable)
@@ -6,7 +6,7 @@
     <groupId>org.opendaylight.controller</groupId>
     <artifactId>commons.opendaylight</artifactId>
     <version>1.4.0-SNAPSHOT</version>
-    <relativePath>../commons/opendaylight</relativePath>
+    <relativePath>../../commons/opendaylight</relativePath>
   </parent>
   <scm>
     <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
index cca194e95337e30877aaff50332e37e6df4be30f..07c814adf14c7b2d35f9991a9bd3e5875296f922 100644 (file)
@@ -34,9 +34,11 @@ public class UserConfig implements Serializable {
     protected String user;
     protected List<String> roles;
     private String password;
+
+    private static final boolean strongPasswordCheck = Boolean.getBoolean("enableStrongPasswordCheck");
+    private static final String BAD_PASSWORD = "Bad Password";
     private static final int USERNAME_MAXLENGTH = 32;
-    private static final int PASSWORD_MINLENGTH = 5;
-    private static final int PASSWORD_MAXLENGTH = 256;
+    protected static final String PASSWORD_REGEX = "(?=.*[^\\w])(?=.*\\d)(?=.*[a-z])(?=.*[A-Z]).{8,256}$";
     private static final Pattern INVALID_USERNAME_CHARACTERS = Pattern.compile("([/\\s\\.\\?#%;\\\\]+)");
     private static MessageDigest oneWayFunction = null;
     static {
@@ -63,16 +65,12 @@ public class UserConfig implements Serializable {
     public UserConfig(String user, String password, List<String> roles) {
         this.user = user;
 
-        this.password = password;
-        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);
-        }
+        /*
+         * Password validation to be done on clear text password. If fails, mark
+         * the password with a well known label, so that object validation can
+         * report the proper error. Only if password is a valid one, hash it.
+         */
+        this.password = (validatePassword(password).isSuccess()) ? hash(password) : BAD_PASSWORD;
 
         this.roles = (roles == null) ? new ArrayList<String>() : new ArrayList<String>(roles);
     }
@@ -142,12 +140,15 @@ public class UserConfig implements Serializable {
     }
 
     public Status validate() {
-        Status validCheck = validateRoles();
+        Status validCheck = validateUsername();
         if (validCheck.isSuccess()) {
-            validCheck = validateUsername();
+            validCheck = (!password.equals(BAD_PASSWORD)) ? new Status(StatusCode.SUCCESS) : new Status(
+                    StatusCode.BADREQUEST,
+                    "Password should be 8 to 256 characters long, contain both upper and lower case letters, "
+                            + "at least one number and at least one non alphanumeric character");
         }
         if (validCheck.isSuccess()) {
-            validCheck = validatePassword();
+            validCheck = validateRoles();
         }
         return validCheck;
     }
@@ -168,15 +169,15 @@ public class UserConfig implements Serializable {
         return new Status(StatusCode.SUCCESS);
     }
 
-    private Status validatePassword() {
+    private Status validatePassword(String password) {
         if (password == null || password.isEmpty()) {
             return new Status(StatusCode.BADREQUEST, "Password cannot be empty");
         }
 
-        if (password.length() < UserConfig.PASSWORD_MINLENGTH
-                || password.length() > UserConfig.PASSWORD_MAXLENGTH) {
-            return new Status(StatusCode.BADREQUEST,
-                    "Password should have 5-256 characters");
+        if (strongPasswordCheck && !password.matches(UserConfig.PASSWORD_REGEX)) {
+            return new Status(StatusCode.BADREQUEST, "Password should be 8 to 256 characters long, "
+                    + "contain both upper and lower case letters, at least one number "
+                    + "and at least one non alphanumeric character");
         }
         return new Status(StatusCode.SUCCESS);
     }
@@ -247,4 +248,25 @@ public class UserConfig implements Serializable {
         UserConfig.oneWayFunction.reset();
         return HexEncode.bytesToHexString(UserConfig.oneWayFunction.digest(message.getBytes(Charset.defaultCharset())));
     }
+
+    /**
+     * Returns UserConfig instance populated with the passed parameters. It does
+     * not run any checks on the passed parameters.
+     *
+     * @param userName
+     *            the user name
+     * @param password
+     *            the plain text password
+     * @param roles
+     *            the list of roles
+     * @return the UserConfig object populated with the passed parameters. No
+     *         validity check is run on the input parameters.
+     */
+    public static UserConfig getUncheckedUserConfig(String userName, String password, List<String> roles) {
+        UserConfig config = new UserConfig();
+        config.user = userName;
+        config.password = hash(password);
+        config.roles = roles;
+        return config;
+    }
 }
index 4c2a19e426f1a88194b5f223a4245b2e67f3fd27..8c029a7488361b778b2749fe327a48a812d675c0 100644 (file)
@@ -117,4 +117,41 @@ public class AuthorizationUserConfigTest {
         UserConfig userConfig2 = new UserConfig("uname", "ciscocisco", roles);
         assertEquals(userConfig, userConfig2);
     }
+
+    @Test
+    public void userConfigPasswordTest() {
+
+        String regex = UserConfig.PASSWORD_REGEX;
+        String password = null;
+
+        // Good password
+        password = "aBc@eF#h9";
+        assertTrue(password.matches(regex));
+        password = "^aBc@eF#h9$88ad*o&";
+        assertTrue(password.matches(regex));
+        password = "_^aBc@\":eF#h;9$\\8|8ad*o&-(){}/,.><?+-";
+        assertTrue(password.matches(regex));
+        password = "culonE1)";
+        assertTrue(password.matches(regex));
+
+        // Too short
+        password = "aB3@eF#";
+        assertFalse(password.matches(regex));
+
+        // No number
+        password = "#BeCCC#CeDfDf";
+        assertFalse(password.matches(regex));
+
+        // No lower case
+        password = "AB8C#CC@C4";
+        assertFalse(password.matches(regex));
+
+        // No upper case
+        password = "ab8defg9!";
+        assertFalse(password.matches(regex));
+
+        // No special characters
+        password = "aBc4ef7H8";
+        assertFalse(password.matches(regex));
+    }
 }
index 0e7e2a37a73f19aefda0919ea8304ac8b375d34f..3898ca589ae710d36ea847eae03aa3742a6cccd6 100644 (file)
@@ -61,7 +61,7 @@ public class Activator extends ComponentActivatorAbstractBase {
      */
     @Override
     public Object[] getImplementations() {
-        return null;
+        return new Object[]{};
     }
 
     /**
index e53e962aa82590db6d48890278657926de57dfb0..8d9e34717e31651cc4086b5a70798e11aceae9e5 100644 (file)
@@ -204,12 +204,17 @@ public class UserManager implements IUserManager, IObjectReader,
     }
 
     private void checkDefaultNetworkAdmin() {
-        // If startup config is not there, it's old or it was deleted,
-        // need to add Default Network Admin User
+        /*
+         * 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);
-            localUserConfigList.put(DEFAULT_ADMIN, new UserConfig(DEFAULT_ADMIN, DEFAULT_ADMIN_PASSWORD, roles));
+            // 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);
         }
     }