Repository: brooklyn-server
Updated Branches:
  refs/heads/master ba05e9642 -> 703cd0d31


CreatePassworkSensor: support "character groups"

Character groups are groups like "capital letters", "numbers", etc. This
option allows a blueprint to require that the generated password
contains at least one character from every group.

It is common (e.g. Micrsoft default password policy) to see a requirement
like "must contain characters from at least 3 groups". Previously, this
sensor could not guarantee that this would happen.

Use it like this:

      - type: org.apache.brooklyn.core.sensor.password.CreatePasswordSensor
        brooklyn.config:
          name: my.password
          password.length: 10
          password.character.groups:
           - "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
           - "abcdefghijklmnopqrstuvwxyz"
           - "1234567890"
           - "-_=+[{]};:|`~,<.>/?!@#$%^&*()"


Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/d2ecd112
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/d2ecd112
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/d2ecd112

Branch: refs/heads/master
Commit: d2ecd112601ba709fc8fd5ae6cb30f4be2a967b4
Parents: ba05e96
Author: Richard Downer <rich...@apache.org>
Authored: Fri Dec 1 13:39:17 2017 +0000
Committer: Richard Downer <rich...@apache.org>
Committed: Fri Dec 1 14:59:52 2017 +0000

----------------------------------------------------------------------
 .../sensor/password/CreatePasswordSensor.java   | 34 +++++++++++++++++---
 .../password/CreatePasswordSensorTest.java      | 19 +++++++++++
 2 files changed, 49 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d2ecd112/core/src/main/java/org/apache/brooklyn/core/sensor/password/CreatePasswordSensor.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/brooklyn/core/sensor/password/CreatePasswordSensor.java
 
b/core/src/main/java/org/apache/brooklyn/core/sensor/password/CreatePasswordSensor.java
index 7b7a908..e62b332 100644
--- 
a/core/src/main/java/org/apache/brooklyn/core/sensor/password/CreatePasswordSensor.java
+++ 
b/core/src/main/java/org/apache/brooklyn/core/sensor/password/CreatePasswordSensor.java
@@ -18,8 +18,13 @@
  */
 package org.apache.brooklyn.core.sensor.password;
 
+import java.util.List;
 import java.util.Map;
 
+import com.google.common.base.Preconditions;
+import com.google.common.base.Predicates;
+import com.google.common.collect.Iterables;
+import com.google.common.reflect.TypeToken;
 import org.apache.brooklyn.api.entity.EntityLocal;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
@@ -33,8 +38,11 @@ public class CreatePasswordSensor extends AddSensor<String> {
 
     public static final ConfigKey<String> ACCEPTABLE_CHARS = 
ConfigKeys.newStringConfigKey("password.chars", "The characters allowed in 
password");
 
+    public static final ConfigKey<List<String>> CHARACTER_GROUPS = 
ConfigKeys.newConfigKey(new TypeToken<List<String>>() {}, 
"password.character.groups", "A list of strings, where each string is a 
character group (such as letters, or numbers). The password will be constructed 
using only characters from these strings, and will use at least one character 
from each group. When using this option, `password.length` must be at least as 
long as the number of character groups given.");
+
     private Integer passwordLength;
     private String acceptableChars;
+    private List<String> characterGroups;
 
     public CreatePasswordSensor(Map<String, String> params) {
         this(ConfigBag.newInstance(params));
@@ -44,16 +52,34 @@ public class CreatePasswordSensor extends AddSensor<String> 
{
         super(params);
         passwordLength = params.get(PASSWORD_LENGTH);
         acceptableChars = params.get(ACCEPTABLE_CHARS);
+        characterGroups = params.get(CHARACTER_GROUPS);
     }
 
     @Override
     public void apply(EntityLocal entity) {
         super.apply(entity);
 
-        String password = acceptableChars == null
-                ? Identifiers.makeRandomPassword(passwordLength)
-                : Identifiers.makeRandomPassword(passwordLength, 
acceptableChars);
-        
+        boolean isCharacterGroupsPresent = characterGroups != null
+                && characterGroups.size() > 0;
+        boolean isCharacterGroupsValid = isCharacterGroupsPresent
+                && !Iterables.contains(characterGroups, Predicates.isNull())
+                && !Iterables.contains(characterGroups, 
Predicates.equalTo(""));
+        boolean isAcceptableCharsPresentAndValid = acceptableChars != null
+                && !acceptableChars.isEmpty();
+
+        Preconditions.checkArgument(!isCharacterGroupsPresent || 
isCharacterGroupsValid, "password.character.groups config key was given but 
does not contain any valid groups");
+        Preconditions.checkArgument(!(isCharacterGroupsPresent && 
isAcceptableCharsPresentAndValid), "password.chars and 
password.character.groups both provided - please provide only ONE of them");
+        Preconditions.checkArgument(!isCharacterGroupsValid || 
characterGroups.size() <= passwordLength, "password.length must be longer than 
the number of entries in password.character.groups");
+
+        String password;
+        if (isCharacterGroupsValid) {
+            password = Identifiers.makeRandomPassword(passwordLength, 
characterGroups.toArray(new String[0]));
+        } else if (isAcceptableCharsPresentAndValid) {
+            password = Identifiers.makeRandomPassword(passwordLength, 
acceptableChars);
+        } else {
+            password = Identifiers.makeRandomPassword(passwordLength);
+        }
+
         entity.sensors().set(sensor, password);
     }
 }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/d2ecd112/core/src/test/java/org/apache/brooklyn/core/sensor/password/CreatePasswordSensorTest.java
----------------------------------------------------------------------
diff --git 
a/core/src/test/java/org/apache/brooklyn/core/sensor/password/CreatePasswordSensorTest.java
 
b/core/src/test/java/org/apache/brooklyn/core/sensor/password/CreatePasswordSensorTest.java
index d033e3d..55041ab 100644
--- 
a/core/src/test/java/org/apache/brooklyn/core/sensor/password/CreatePasswordSensorTest.java
+++ 
b/core/src/test/java/org/apache/brooklyn/core/sensor/password/CreatePasswordSensorTest.java
@@ -57,4 +57,23 @@ public class CreatePasswordSensorTest extends 
BrooklynAppUnitTestSupport{
         String password = entity.getAttribute(SENSOR_STRING);
         Asserts.assertEquals(password.length(), 12);
     }
+
+    @Test
+    public void testCreatePasswordCharacterGroups() {
+        final CreatePasswordSensor sensor = new 
CreatePasswordSensor(ConfigBag.newInstance()
+                .configure(CreatePasswordSensor.SENSOR_NAME, 
SENSOR_STRING.getName())
+                .configure(CreatePasswordSensor.PASSWORD_LENGTH, 6)
+                .configure(CreatePasswordSensor.CHARACTER_GROUPS, 
ImmutableList.of("abc", "def", "ghi"))
+        );
+        sensor.apply(entity);
+
+        String password = entity.getAttribute(SENSOR_STRING);
+        Asserts.assertEquals(password.length(), 6);
+        Asserts.assertStringMatchesRegex(password,
+                "[a-i]{6}", // whole string consists of exactly 6 characters 
from all groups
+                ".*[a-c].*", // at least one from the a-c group
+                ".*[d-f].*", // at least one from the d-f group
+                ".*[g-i].*" // at least one from the g-i group
+        );
+    }
 }
\ No newline at end of file

Reply via email to