You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by ma...@apache.org on 2012/10/23 10:51:36 UTC

svn commit: r1401200 - in /incubator/syncope/trunk/core/src: main/java/org/apache/syncope/core/persistence/validation/entity/ main/java/org/apache/syncope/core/policy/ main/java/org/apache/syncope/core/util/ test/java/org/apache/syncope/core/persistenc...

Author: massi
Date: Tue Oct 23 08:51:35 2012
New Revision: 1401200

URL: http://svn.apache.org/viewvc?rev=1401200&view=rev
Log:
Issue 121 closed

Added:
    incubator/syncope/trunk/core/src/main/java/org/apache/syncope/core/policy/PolicyPattern.java   (with props)
    incubator/syncope/trunk/core/src/main/java/org/apache/syncope/core/util/IncompatiblePolicyException.java   (with props)
    incubator/syncope/trunk/core/src/main/java/org/apache/syncope/core/util/PasswordGenerator.java   (with props)
    incubator/syncope/trunk/core/src/test/java/org/apache/syncope/core/util/
    incubator/syncope/trunk/core/src/test/java/org/apache/syncope/core/util/PasswordGeneratorTest.java   (with props)
Modified:
    incubator/syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/validation/entity/SyncopeUserValidator.java
    incubator/syncope/trunk/core/src/main/java/org/apache/syncope/core/policy/PasswordPolicyEnforcer.java
    incubator/syncope/trunk/core/src/test/java/org/apache/syncope/core/persistence/dao/UserTest.java
    incubator/syncope/trunk/core/src/test/java/org/apache/syncope/core/rest/UserTestITCase.java
    incubator/syncope/trunk/core/src/test/resources/content.xml

Modified: incubator/syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/validation/entity/SyncopeUserValidator.java
URL: http://svn.apache.org/viewvc/incubator/syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/validation/entity/SyncopeUserValidator.java?rev=1401200&r1=1401199&r2=1401200&view=diff
==============================================================================
--- incubator/syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/validation/entity/SyncopeUserValidator.java (original)
+++ incubator/syncope/trunk/core/src/main/java/org/apache/syncope/core/persistence/validation/entity/SyncopeUserValidator.java Tue Oct 23 08:51:35 2012
@@ -22,11 +22,10 @@ import java.util.ArrayList;
 import java.util.List;
 import javax.validation.ConstraintValidator;
 import javax.validation.ConstraintValidatorContext;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.apache.syncope.core.persistence.beans.AccountPolicy;
-import org.apache.syncope.core.persistence.beans.Policy;
 import org.apache.syncope.core.persistence.beans.ExternalResource;
 import org.apache.syncope.core.persistence.beans.PasswordPolicy;
+import org.apache.syncope.core.persistence.beans.Policy;
 import org.apache.syncope.core.persistence.beans.role.SyncopeRole;
 import org.apache.syncope.core.persistence.beans.user.SyncopeUser;
 import org.apache.syncope.core.persistence.dao.PolicyDAO;
@@ -36,6 +35,7 @@ import org.apache.syncope.core.policy.Po
 import org.apache.syncope.types.AccountPolicySpec;
 import org.apache.syncope.types.EntityViolationType;
 import org.apache.syncope.types.PasswordPolicySpec;
+import org.springframework.beans.factory.annotation.Autowired;
 
 public class SyncopeUserValidator extends AbstractValidator implements
         ConstraintValidator<SyncopeUserCheck, SyncopeUser> {

Modified: incubator/syncope/trunk/core/src/main/java/org/apache/syncope/core/policy/PasswordPolicyEnforcer.java
URL: http://svn.apache.org/viewvc/incubator/syncope/trunk/core/src/main/java/org/apache/syncope/core/policy/PasswordPolicyEnforcer.java?rev=1401200&r1=1401199&r2=1401200&view=diff
==============================================================================
--- incubator/syncope/trunk/core/src/main/java/org/apache/syncope/core/policy/PasswordPolicyEnforcer.java (original)
+++ incubator/syncope/trunk/core/src/main/java/org/apache/syncope/core/policy/PasswordPolicyEnforcer.java Tue Oct 23 08:51:35 2012
@@ -18,36 +18,13 @@
  */
 package org.apache.syncope.core.policy;
 
-import java.util.regex.Pattern;
-import org.springframework.stereotype.Component;
 import org.apache.syncope.types.PasswordPolicySpec;
 import org.apache.syncope.types.PolicyType;
+import org.springframework.stereotype.Component;
 
 @Component
 public class PasswordPolicyEnforcer extends PolicyEnforcer<PasswordPolicySpec, String> {
 
-    private static final Pattern DIGIT = Pattern.compile(".*\\d+.*");
-
-    private static final Pattern ALPHA_LOWERCASE = Pattern.compile(".*[a-z]+.*");
-
-    private static final Pattern ALPHA_UPPERCASE = Pattern.compile(".*[A-Z]+.*");
-
-    private static final Pattern FIRSTDIGIT = Pattern.compile("\\d.*");
-
-    private static final Pattern LASTDIGIT = Pattern.compile(".*\\d");
-
-    private static final Pattern ALPHANUMERIC = Pattern.compile(".*\\w.*");
-
-    private static final Pattern FIRSTALPHANUMERIC = Pattern.compile("\\w.*");
-
-    private static final Pattern LASTALPHANUMERIC = Pattern.compile(".*\\w");
-
-    private static final Pattern NONALPHANUMERIC = Pattern.compile(".*\\W.*");
-
-    private static final Pattern FIRSTNONALPHANUMERIC = Pattern.compile("\\W.*");
-
-    private static final Pattern LASTNONALPHANUMERIC = Pattern.compile(".*\\W");
-
     @Override
     public void enforce(final PasswordPolicySpec policy, final PolicyType type, final String password)
             throws PasswordPolicyException, PolicyEnforceException {
@@ -171,46 +148,46 @@ public class PasswordPolicyEnforcer exte
     }
 
     private boolean checkForDigit(String str) {
-        return DIGIT.matcher((CharSequence) str).matches();
+        return PolicyPattern.DIGIT.matcher((CharSequence) str).matches();
     }
 
     private boolean checkForLowercase(String str) {
-        return ALPHA_LOWERCASE.matcher((CharSequence) str).matches();
+        return PolicyPattern.ALPHA_LOWERCASE.matcher((CharSequence) str).matches();
     }
 
     private boolean checkForUppercase(String str) {
-        return ALPHA_UPPERCASE.matcher((CharSequence) str).matches();
+        return PolicyPattern.ALPHA_UPPERCASE.matcher((CharSequence) str).matches();
     }
 
     private boolean checkForFirstDigit(String str) {
-        return FIRSTDIGIT.matcher((CharSequence) str).matches();
+        return PolicyPattern.FIRST_DIGIT.matcher((CharSequence) str).matches();
     }
 
     private boolean checkForLastDigit(String str) {
-        return LASTDIGIT.matcher((CharSequence) str).matches();
+        return PolicyPattern.LAST_DIGIT.matcher((CharSequence) str).matches();
     }
 
     private boolean checkForAlphanumeric(String str) {
-        return ALPHANUMERIC.matcher(str).matches();
+        return PolicyPattern.ALPHANUMERIC.matcher(str).matches();
     }
 
     private boolean checkForFirstAlphanumeric(String str) {
-        return FIRSTALPHANUMERIC.matcher(str).matches();
+        return PolicyPattern.FIRST_ALPHANUMERIC.matcher(str).matches();
     }
 
     private boolean checkForLastAlphanumeric(String str) {
-        return LASTALPHANUMERIC.matcher(str).matches();
+        return PolicyPattern.LAST_ALPHANUMERIC.matcher(str).matches();
     }
 
     private boolean checkForNonAlphanumeric(String str) {
-        return NONALPHANUMERIC.matcher(str).matches();
+        return PolicyPattern.NON_ALPHANUMERIC.matcher(str).matches();
     }
 
     private boolean checkForFirstNonAlphanumeric(String str) {
-        return FIRSTNONALPHANUMERIC.matcher(str).matches();
+        return PolicyPattern.FIRST_NON_ALPHANUMERIC.matcher(str).matches();
     }
 
     private boolean checkForLastNonAlphanumeric(String str) {
-        return LASTNONALPHANUMERIC.matcher(str).matches();
+        return PolicyPattern.LAST_NON_ALPHANUMERIC.matcher(str).matches();
     }
 }

Added: incubator/syncope/trunk/core/src/main/java/org/apache/syncope/core/policy/PolicyPattern.java
URL: http://svn.apache.org/viewvc/incubator/syncope/trunk/core/src/main/java/org/apache/syncope/core/policy/PolicyPattern.java?rev=1401200&view=auto
==============================================================================
--- incubator/syncope/trunk/core/src/main/java/org/apache/syncope/core/policy/PolicyPattern.java (added)
+++ incubator/syncope/trunk/core/src/main/java/org/apache/syncope/core/policy/PolicyPattern.java Tue Oct 23 08:51:35 2012
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.policy;
+
+import java.util.regex.Pattern;
+
+public class PolicyPattern {
+
+    public static final Pattern DIGIT = Pattern.compile(".*\\d+.*");
+
+    public static final Pattern ALPHA_LOWERCASE = Pattern.compile(".*[a-z]+.*");
+
+    public static final Pattern ALPHA_UPPERCASE = Pattern.compile(".*[A-Z]+.*");
+
+    public static final Pattern FIRST_DIGIT = Pattern.compile("\\d.*");
+
+    public static final Pattern LAST_DIGIT = Pattern.compile(".*\\d");
+
+    public static final Pattern ALPHANUMERIC = Pattern.compile(".*\\w.*");
+
+    public static final Pattern FIRST_ALPHANUMERIC = Pattern.compile("\\w.*");
+
+    public static final Pattern LAST_ALPHANUMERIC = Pattern.compile(".*\\w");
+
+    public static final Pattern NON_ALPHANUMERIC = Pattern.compile(".*\\W.*");
+
+    public static final Pattern FIRST_NON_ALPHANUMERIC = Pattern.compile("\\W.*");
+
+    public static final Pattern LAST_NON_ALPHANUMERIC = Pattern.compile(".*\\W");
+}

Propchange: incubator/syncope/trunk/core/src/main/java/org/apache/syncope/core/policy/PolicyPattern.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/syncope/trunk/core/src/main/java/org/apache/syncope/core/policy/PolicyPattern.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: incubator/syncope/trunk/core/src/main/java/org/apache/syncope/core/policy/PolicyPattern.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: incubator/syncope/trunk/core/src/main/java/org/apache/syncope/core/util/IncompatiblePolicyException.java
URL: http://svn.apache.org/viewvc/incubator/syncope/trunk/core/src/main/java/org/apache/syncope/core/util/IncompatiblePolicyException.java?rev=1401200&view=auto
==============================================================================
--- incubator/syncope/trunk/core/src/main/java/org/apache/syncope/core/util/IncompatiblePolicyException.java (added)
+++ incubator/syncope/trunk/core/src/main/java/org/apache/syncope/core/util/IncompatiblePolicyException.java Tue Oct 23 08:51:35 2012
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.util;
+
+public class IncompatiblePolicyException extends Exception {
+
+    private static final long serialVersionUID = 4810651743226663580L;
+
+    public IncompatiblePolicyException(String msg) {
+        super(msg);
+    }
+
+    public IncompatiblePolicyException(String msg, Exception e) {
+        super(msg, e);
+    }
+}

Propchange: incubator/syncope/trunk/core/src/main/java/org/apache/syncope/core/util/IncompatiblePolicyException.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/syncope/trunk/core/src/main/java/org/apache/syncope/core/util/IncompatiblePolicyException.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: incubator/syncope/trunk/core/src/main/java/org/apache/syncope/core/util/IncompatiblePolicyException.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: incubator/syncope/trunk/core/src/main/java/org/apache/syncope/core/util/PasswordGenerator.java
URL: http://svn.apache.org/viewvc/incubator/syncope/trunk/core/src/main/java/org/apache/syncope/core/util/PasswordGenerator.java?rev=1401200&view=auto
==============================================================================
--- incubator/syncope/trunk/core/src/main/java/org/apache/syncope/core/util/PasswordGenerator.java (added)
+++ incubator/syncope/trunk/core/src/main/java/org/apache/syncope/core/util/PasswordGenerator.java Tue Oct 23 08:51:35 2012
@@ -0,0 +1,334 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.util;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import org.apache.commons.lang3.RandomStringUtils;
+import org.apache.syncope.core.persistence.beans.ExternalResource;
+import org.apache.syncope.core.persistence.beans.role.SyncopeRole;
+import org.apache.syncope.core.persistence.beans.user.SyncopeUser;
+import org.apache.syncope.core.persistence.dao.PolicyDAO;
+import org.apache.syncope.core.policy.PolicyPattern;
+import org.apache.syncope.types.PasswordPolicySpec;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class PasswordGenerator {
+
+    private static final Logger LOG = LoggerFactory.getLogger(PasswordGenerator.class);
+
+    private static final String[] SPECIAL_CHAR = {"!", "£", "%", "&", "(", ")", "?", "#", "_", "$"};
+
+    @Autowired
+    private PolicyDAO policyDAO;
+
+    public String generatePasswordFromPwdSpec(final List<PasswordPolicySpec> passwordPolicySpecs)
+            throws IncompatiblePolicyException {
+        PasswordPolicySpec policySpec = mergePolicySpecs(passwordPolicySpecs);
+
+        evaluateFinalPolicySpec(policySpec);
+        return generatePassword(policySpec);
+    }
+
+    public String generateUserPassword(final SyncopeUser user)
+            throws IncompatiblePolicyException {
+        List<PasswordPolicySpec> userPasswordPolicies = new ArrayList<PasswordPolicySpec>();
+        PasswordPolicySpec passwordPolicySpec = policyDAO.getGlobalPasswordPolicy().getSpecification();
+
+        userPasswordPolicies.add(passwordPolicySpec);
+
+        PasswordPolicySpec rolePasswordPolicySpec;
+        if ((user.getRoles() != null) || (!user.getRoles().isEmpty())) {
+            for (Iterator<SyncopeRole> rolesIterator = user.getRoles().iterator(); rolesIterator.hasNext();) {
+                SyncopeRole syncopeRole = rolesIterator.next();
+                rolePasswordPolicySpec = syncopeRole.getPasswordPolicy().getSpecification();
+                userPasswordPolicies.add(rolePasswordPolicySpec);
+            }
+        }
+
+        PasswordPolicySpec resourcePasswordPolicySpec;
+
+        if ((user.getResources() != null) || (!user.getResources().isEmpty())) {
+            for (Iterator<ExternalResource> resourcesIterator = user.getResources().iterator();
+                    resourcesIterator.hasNext();) {
+                ExternalResource externalResource = resourcesIterator.next();
+                if (externalResource.getPasswordPolicy() != null) {
+                    resourcePasswordPolicySpec = externalResource.getPasswordPolicy().getSpecification();
+                    userPasswordPolicies.add(resourcePasswordPolicySpec);
+                }
+            }
+        }
+
+        PasswordPolicySpec policySpec = mergePolicySpecs(userPasswordPolicies);
+
+        evaluateFinalPolicySpec(policySpec);
+        return generatePassword(policySpec);
+    }
+
+    private PasswordPolicySpec mergePolicySpecs(List<PasswordPolicySpec> userPasswordPolicies) {
+
+        PasswordPolicySpec fpps = new PasswordPolicySpec();
+        fpps.setMinLength(0);
+        fpps.setMaxLength(1000);
+
+        for (Iterator<PasswordPolicySpec> it = userPasswordPolicies.iterator(); it.hasNext();) {
+            PasswordPolicySpec policySpec = it.next();
+            if (policySpec.getMinLength() > fpps.getMinLength()) {
+                fpps.setMinLength(policySpec.getMinLength());
+            }
+
+            if ((policySpec.getMaxLength() != 0) && ((policySpec.getMaxLength() < fpps.getMaxLength()))) {
+                fpps.setMaxLength(policySpec.getMaxLength());
+            }
+            fpps.setPrefixesNotPermitted(policySpec.getPrefixesNotPermitted());
+            fpps.setSuffixesNotPermitted(policySpec.getSuffixesNotPermitted());
+
+            if (!fpps.isNonAlphanumericRequired()) {
+                fpps.setNonAlphanumericRequired(policySpec.isNonAlphanumericRequired());
+            }
+
+            if (!fpps.isAlphanumericRequired()) {
+                fpps.setAlphanumericRequired(policySpec.isAlphanumericRequired());
+            }
+            if (!fpps.isDigitRequired()) {
+                fpps.setDigitRequired(policySpec.isDigitRequired());
+            }
+
+            if (!fpps.isLowercaseRequired()) {
+                fpps.setLowercaseRequired(policySpec.isLowercaseRequired());
+            }
+            if (!fpps.isUppercaseRequired()) {
+                fpps.setUppercaseRequired(policySpec.isUppercaseRequired());
+            }
+            if (!fpps.isMustStartWithDigit()) {
+                fpps.setMustStartWithDigit(policySpec.isMustStartWithDigit());
+            }
+            if (!fpps.isMustntStartWithDigit()) {
+                fpps.setMustntStartWithDigit(policySpec.isMustntStartWithDigit());
+            }
+            if (!fpps.isMustEndWithDigit()) {
+                fpps.setMustEndWithDigit(policySpec.isMustEndWithDigit());
+            }
+            if (fpps.isMustntEndWithDigit()) {
+                fpps.setMustntEndWithDigit(policySpec.isMustntEndWithDigit());
+            }
+            if (!fpps.isMustStartWithAlpha()) {
+                fpps.setMustStartWithAlpha(policySpec.isMustStartWithAlpha());
+            }
+            if (!fpps.isMustntStartWithAlpha()) {
+                fpps.setMustntStartWithAlpha(policySpec.isMustntStartWithAlpha());
+            }
+            if (!fpps.isMustStartWithNonAlpha()) {
+                fpps.setMustStartWithNonAlpha(policySpec.isMustStartWithNonAlpha());
+            }
+            if (!fpps.isMustntStartWithNonAlpha()) {
+                fpps.setMustntStartWithNonAlpha(policySpec.isMustntStartWithNonAlpha());
+            }
+            if (!fpps.isMustEndWithNonAlpha()) {
+                fpps.setMustEndWithNonAlpha(policySpec.isMustEndWithNonAlpha());
+            }
+            if (!fpps.isMustntEndWithNonAlpha()) {
+                fpps.setMustntEndWithNonAlpha(policySpec.isMustntEndWithNonAlpha());
+            }
+            if (!fpps.isMustEndWithAlpha()) {
+                fpps.setMustEndWithAlpha(policySpec.isMustEndWithAlpha());
+            }
+            if (!fpps.isMustntEndWithAlpha()) {
+                fpps.setMustntEndWithAlpha(policySpec.isMustntEndWithAlpha());
+            }
+        }
+        return fpps;
+    }
+
+    private void evaluateFinalPolicySpec(final PasswordPolicySpec policySpec)
+            throws IncompatiblePolicyException {
+        if (policySpec.getMinLength() == 0) {
+            LOG.error("Minimum lenght given is zero");
+            throw new IncompatiblePolicyException("Minimum lenght given is zero");
+        }
+        if (policySpec.isMustEndWithAlpha() && policySpec.isMustntEndWithAlpha()) {
+            LOG.error("Incompatible password policy specification: mustEndWithAlpha and"
+                    + "mustntEndWithAlpha are true");
+            throw new IncompatiblePolicyException("Incompatible password policy specification: mustEndWithAlpha and"
+                    + "mustntEndWithAlpha are true");
+        }
+        if (policySpec.isMustEndWithAlpha() && policySpec.isMustEndWithDigit()) {
+            LOG.error("Incompatible password policy specification: mustEndWithAlpha and"
+                    + "mustEndWithDigit are true");
+            throw new IncompatiblePolicyException("Incompatible password policy specification: mustEndWithAlpha and"
+                    + "mustEndWithDigit are true");
+        }
+        if (policySpec.isMustEndWithDigit() && policySpec.isMustntEndWithDigit()) {
+            LOG.error("Incompatible password policy specification: mustEndWithDigit and"
+                    + "mustntEndWithDigit are true");
+            throw new IncompatiblePolicyException("Incompatible password policy specification: mustEndWithDigit and"
+                    + "mustntEndWithDigit are true");
+        }
+        if (policySpec.isMustEndWithNonAlpha() && policySpec.isMustntEndWithNonAlpha()) {
+            LOG.error("Incompatible password policy specification: mustEndWithNonAlpha and"
+                    + "mustntEndWithNonAlpha are true");
+            throw new IncompatiblePolicyException("Incompatible password policy specification: mustEndWithNonAlpha and"
+                    + "mustntEndWithNonAlpha are true");
+        }
+        if (policySpec.isMustStartWithAlpha() && policySpec.isMustntStartWithAlpha()) {
+            LOG.error("Incompatible password policy specification: mustStartWithAlpha and"
+                    + "mustntStartWithAlpha are true");
+            throw new IncompatiblePolicyException("Incompatible password policy specification: mustStartWithAlpha and"
+                    + "mustntStartWithAlpha are true");
+        }
+        if (policySpec.isMustStartWithAlpha() && policySpec.isMustStartWithDigit()) {
+            LOG.error("Incompatible password policy specification: mustStartWithAlpha and"
+                    + "mustStartWithDigit are true");
+            throw new IncompatiblePolicyException("Incompatible password policy specification: mustStartWithAlpha and"
+                    + "mustStartWithDigit are true");
+        }
+        if (policySpec.isMustStartWithDigit() && policySpec.isMustntStartWithDigit()) {
+            LOG.error("Incompatible password policy specification: mustStartWithDigit and"
+                    + "mustntStartWithDigit are true");
+            throw new IncompatiblePolicyException("Incompatible password policy specification: mustStartWithDigit and"
+                    + " mustntStartWithDigit are true");
+        }
+        if (policySpec.isMustStartWithNonAlpha() && policySpec.isMustntStartWithNonAlpha()) {
+            LOG.error("Incompatible password policy specification: mustStartWithNonAlpha"
+                    + "and mustntStartWithNonAlpha are true");
+            throw new IncompatiblePolicyException("Incompatible password policy specification: mustStartWithNonAlpha"
+                    + "and mustntStartWithNonAlpha are true");
+        }
+        if (policySpec.getMinLength() > policySpec.getMaxLength()) {
+            LOG.error("Minimun length given (" + policySpec.getMinLength() + ") is higher than"
+                    + "maximum allowed (" + policySpec.getMaxLength() + ")");
+            throw new IncompatiblePolicyException("Minimun length given (" + policySpec.getMinLength() + ")"
+                    + "is higher than maximum allowed (" + policySpec.getMaxLength() + ")");
+        }
+    }
+
+    private String generatePassword(final PasswordPolicySpec policySpec) {
+        StringBuilder generatedPassword = new StringBuilder(policySpec.getMinLength());
+
+        if (policySpec.isDigitRequired() || policySpec.isAlphanumericRequired()) {
+            generatedPassword.append(RandomStringUtils.randomAlphanumeric(policySpec.getMinLength()));
+        }
+
+        if (policySpec.isDigitRequired() && !PolicyPattern.DIGIT.matcher(generatedPassword.toString()).matches()) {
+            int where = randomNumber(policySpec.getMinLength());
+            generatedPassword.deleteCharAt(where);
+            generatedPassword.insert(where, RandomStringUtils.randomNumeric(1));
+        }
+
+        if (!policySpec.isAlphanumericRequired() && !policySpec.isDigitRequired()) {
+            generatedPassword.append(RandomStringUtils.randomAlphabetic(policySpec.getMinLength()));
+        }
+
+        if (policySpec.isUppercaseRequired() && !PolicyPattern.ALPHA_UPPERCASE
+                .matcher(generatedPassword.toString()).matches()) {
+            int where = randomNumber(policySpec.getMinLength());
+            generatedPassword.deleteCharAt(where);
+            generatedPassword.insert(where, RandomStringUtils.randomAlphabetic(1));
+        }
+
+        if (policySpec.isLowercaseRequired() && !PolicyPattern.ALPHA_LOWERCASE.
+                matcher(generatedPassword.toString()).matches()) {
+            int where = randomNumber(policySpec.getMinLength());
+            generatedPassword.deleteCharAt(where);
+            generatedPassword.insert(where, RandomStringUtils.randomAlphabetic(1).toLowerCase());
+        }
+
+        if (policySpec.isNonAlphanumericRequired()) {
+            int where = randomNumber(policySpec.getMinLength());
+            generatedPassword.deleteCharAt(where);
+            generatedPassword.insert(where, SPECIAL_CHAR[randomNumber(SPECIAL_CHAR.length - 1)]);
+        }
+
+        checkEndChar(generatedPassword, policySpec);
+
+        checkstartChar(generatedPassword, policySpec);
+
+        for (Iterator<String> it = policySpec.getPrefixesNotPermitted().iterator(); it.hasNext();) {
+            String prefix = it.next();
+            if (generatedPassword.toString().startsWith(prefix)) {
+                checkstartChar(generatedPassword, policySpec);
+            }
+        }
+
+        for (Iterator<String> it = policySpec.getSuffixesNotPermitted().iterator(); it.hasNext();) {
+            String suffix = it.next();
+            if (generatedPassword.toString().endsWith(suffix)) {
+                checkEndChar(generatedPassword, policySpec);
+            }
+        }
+        return generatedPassword.toString();
+    }
+
+    private int randomNumber(int range) {
+        int randomNumber = (int) (Math.random() * (range - 1));
+        return randomNumber == 0 ? 1 : randomNumber;
+    }
+
+    private void checkstartChar(final StringBuilder generatedPassword, final PasswordPolicySpec policySpec) {
+        if (policySpec.isMustStartWithAlpha()) {
+            generatedPassword.deleteCharAt(0);
+            generatedPassword.insert(0, RandomStringUtils.randomAlphabetic(1));
+        }
+        if (policySpec.isMustStartWithNonAlpha() || policySpec.isMustStartWithDigit()) {
+            generatedPassword.deleteCharAt(0);
+            generatedPassword.insert(0, RandomStringUtils.randomNumeric(1));
+        }
+        if (policySpec.isMustntStartWithAlpha()) {
+            generatedPassword.deleteCharAt(0);
+            generatedPassword.insert(0, RandomStringUtils.randomNumeric(1));
+        }
+        if (policySpec.isMustntStartWithDigit()) {
+            generatedPassword.deleteCharAt(0);
+            generatedPassword.insert(0, RandomStringUtils.randomAlphabetic(1));
+        }
+        if (policySpec.isMustntStartWithNonAlpha()) {
+            generatedPassword.deleteCharAt(0);
+            generatedPassword.insert(0, RandomStringUtils.randomAlphanumeric(1));
+        }
+    }
+
+    private void checkEndChar(final StringBuilder generatedPassword, final PasswordPolicySpec policySpec) {
+        if (policySpec.isMustEndWithAlpha()) {
+            generatedPassword.deleteCharAt(policySpec.getMinLength() - 1);
+            generatedPassword.insert(policySpec.getMinLength() - 1, RandomStringUtils.randomAlphabetic(1));
+        }
+        if (policySpec.isMustEndWithNonAlpha() || policySpec.isMustEndWithDigit()) {
+            generatedPassword.deleteCharAt(policySpec.getMinLength() - 1);
+            generatedPassword.insert(policySpec.getMinLength() - 1, RandomStringUtils.randomNumeric(1));
+        }
+
+        if (policySpec.isMustntEndWithAlpha()) {
+            generatedPassword.deleteCharAt(policySpec.getMinLength() - 1);
+            generatedPassword.insert(policySpec.getMinLength() - 1, RandomStringUtils.randomNumeric(1));
+        }
+        if (policySpec.isMustntEndWithDigit()) {
+            generatedPassword.deleteCharAt(policySpec.getMinLength() - 1);
+            generatedPassword.insert(policySpec.getMinLength() - 1, RandomStringUtils.randomAlphabetic(1));
+        }
+        if (policySpec.isMustntEndWithNonAlpha()) {
+            generatedPassword.deleteCharAt(policySpec.getMinLength() - 1);
+            generatedPassword.insert(policySpec.getMinLength() - 1, RandomStringUtils.randomAlphabetic(1));
+        }
+    }
+}

Propchange: incubator/syncope/trunk/core/src/main/java/org/apache/syncope/core/util/PasswordGenerator.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/syncope/trunk/core/src/main/java/org/apache/syncope/core/util/PasswordGenerator.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: incubator/syncope/trunk/core/src/main/java/org/apache/syncope/core/util/PasswordGenerator.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: incubator/syncope/trunk/core/src/test/java/org/apache/syncope/core/persistence/dao/UserTest.java
URL: http://svn.apache.org/viewvc/incubator/syncope/trunk/core/src/test/java/org/apache/syncope/core/persistence/dao/UserTest.java?rev=1401200&r1=1401199&r2=1401200&view=diff
==============================================================================
--- incubator/syncope/trunk/core/src/test/java/org/apache/syncope/core/persistence/dao/UserTest.java (original)
+++ incubator/syncope/trunk/core/src/test/java/org/apache/syncope/core/persistence/dao/UserTest.java Tue Oct 23 08:51:35 2012
@@ -18,26 +18,30 @@
  */
 package org.apache.syncope.core.persistence.dao;
 
-import static org.junit.Assert.*;
-
 import java.util.Date;
 import java.util.List;
 import java.util.Set;
-import org.junit.Test;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.transaction.annotation.Transactional;
-import org.apache.syncope.core.persistence.beans.user.SyncopeUser;
 import org.apache.syncope.core.AbstractTest;
+import org.apache.syncope.core.persistence.beans.user.SyncopeUser;
 import org.apache.syncope.core.persistence.beans.user.UAttrValue;
 import org.apache.syncope.core.persistence.validation.entity.InvalidEntityException;
 import org.apache.syncope.core.rest.controller.InvalidSearchConditionException;
 import org.apache.syncope.core.util.EntitlementUtil;
+import org.apache.syncope.core.util.IncompatiblePolicyException;
+import org.apache.syncope.core.util.PasswordGenerator;
 import org.apache.syncope.types.CipherAlgorithm;
+import static org.junit.Assert.*;
+import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Transactional;
 
 @Transactional
 public class UserTest extends AbstractTest {
 
     @Autowired
+    private PasswordGenerator passwordGenerator;
+
+    @Autowired
     private UserDAO userDAO;
 
     @Autowired
@@ -78,18 +82,21 @@ public class UserTest extends AbstractTe
     }
 
     @Test
-    public void findByDerAttributeValue() throws InvalidSearchConditionException {
+    public void findByDerAttributeValue()
+            throws InvalidSearchConditionException {
         final List<SyncopeUser> list = userDAO.findByDerAttrValue("cn", "Doe, John");
         assertEquals("did not get expected number of users ", 1, list.size());
     }
 
     @Test(expected = InvalidSearchConditionException.class)
-    public void findByInvalidDerAttrValue() throws InvalidSearchConditionException {
+    public void findByInvalidDerAttrValue()
+            throws InvalidSearchConditionException {
         userDAO.findByDerAttrValue("cn", "Antonio, Maria, Rossi");
     }
 
     @Test(expected = InvalidSearchConditionException.class)
-    public void findByInvalidDerAttrExpression() throws InvalidSearchConditionException {
+    public void findByInvalidDerAttrExpression()
+            throws InvalidSearchConditionException {
         userDAO.findByDerAttrValue("noschema", "Antonio, Maria");
     }
 
@@ -191,8 +198,16 @@ public class UserTest extends AbstractTe
     @Test
     public void issueSYNCOPE226() {
         SyncopeUser user = userDAO.find(5L);
+        String password = "";
+        try {
+            password = passwordGenerator.generateUserPassword(user);
+            System.out.println("PASSWORD GENERATA: " + password);
+        } catch (IncompatiblePolicyException ex) {
+            fail(ex.getMessage());
+        }
+        assertNotNull(password);
 
-        user.setPassword("123password", CipherAlgorithm.AES, 0);
+        user.setPassword(password, CipherAlgorithm.AES, 0);
 
         SyncopeUser actual = userDAO.save(user);
         assertNotNull(actual);

Modified: incubator/syncope/trunk/core/src/test/java/org/apache/syncope/core/rest/UserTestITCase.java
URL: http://svn.apache.org/viewvc/incubator/syncope/trunk/core/src/test/java/org/apache/syncope/core/rest/UserTestITCase.java?rev=1401200&r1=1401199&r2=1401200&view=diff
==============================================================================
--- incubator/syncope/trunk/core/src/test/java/org/apache/syncope/core/rest/UserTestITCase.java (original)
+++ incubator/syncope/trunk/core/src/test/java/org/apache/syncope/core/rest/UserTestITCase.java Tue Oct 23 08:51:35 2012
@@ -1138,7 +1138,7 @@ public class UserTestITCase extends Abst
 
         UserMod userMod = new UserMod();
         userMod.setId(userTO.getId());
-        userMod.setPassword("newPassword");
+        userMod.setPassword("new2Password");
 
         userMod.addAttributeToBeRemoved("userId");
         attributeMod = new AttributeMod();
@@ -1160,7 +1160,7 @@ public class UserTestITCase extends Abst
         assertNotNull(userTO);
 
         SyncopeUser passwordTestUser = new SyncopeUser();
-        passwordTestUser.setPassword("newPassword", CipherAlgorithm.SHA1, 0);
+        passwordTestUser.setPassword("new2Password", CipherAlgorithm.SHA1, 0);
         assertEquals(passwordTestUser.getPassword(), userTO.getPassword());
 
         assertEquals(1, userTO.getMemberships().size());
@@ -1204,7 +1204,7 @@ public class UserTestITCase extends Abst
 
         UserMod userMod = new UserMod();
         userMod.setId(userTO.getId());
-        userMod.setPassword("newPassword");
+        userMod.setPassword("newPassword123");
 
         userTO = restTemplate.postForObject(BASE_URL + "user/update", userMod, UserTO.class);
 
@@ -1212,7 +1212,7 @@ public class UserTestITCase extends Abst
         assertNotNull(userTO.getChangePwdDate());
 
         SyncopeUser passwordTestUser = new SyncopeUser();
-        passwordTestUser.setPassword("newPassword", CipherAlgorithm.SHA1, 0);
+        passwordTestUser.setPassword("newPassword123", CipherAlgorithm.SHA1, 0);
         assertEquals(passwordTestUser.getPassword(), userTO.getPassword());
 
         List<PropagationTaskTO> afterTasks = Arrays.asList(restTemplate.getForObject(

Added: incubator/syncope/trunk/core/src/test/java/org/apache/syncope/core/util/PasswordGeneratorTest.java
URL: http://svn.apache.org/viewvc/incubator/syncope/trunk/core/src/test/java/org/apache/syncope/core/util/PasswordGeneratorTest.java?rev=1401200&view=auto
==============================================================================
--- incubator/syncope/trunk/core/src/test/java/org/apache/syncope/core/util/PasswordGeneratorTest.java (added)
+++ incubator/syncope/trunk/core/src/test/java/org/apache/syncope/core/util/PasswordGeneratorTest.java Tue Oct 23 08:51:35 2012
@@ -0,0 +1,145 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.core.util;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.syncope.core.AbstractTest;
+import org.apache.syncope.core.persistence.beans.user.SyncopeUser;
+import org.apache.syncope.core.persistence.dao.UserDAO;
+import org.apache.syncope.core.policy.PolicyPattern;
+import org.apache.syncope.types.CipherAlgorithm;
+import org.apache.syncope.types.PasswordPolicySpec;
+import static org.junit.Assert.*;
+import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Transactional;
+
+@Transactional
+public class PasswordGeneratorTest extends AbstractTest {
+
+    @Autowired
+    private PasswordGenerator passwordGenerator;
+
+    @Autowired
+    private UserDAO userDAO;
+
+    @Test
+    public void testPasswordGenerator() {
+        SyncopeUser user = userDAO.find(5L);
+
+        String password = "";
+        try {
+            password = passwordGenerator.generateUserPassword(user);
+
+        } catch (IncompatiblePolicyException ex) {
+            fail(ex.getMessage());
+        }
+        assertNotNull(password);
+        user.setPassword(password, CipherAlgorithm.SHA1, 0);
+        userDAO.save(user);
+    }
+
+    @Test
+    public void startEndWithDigit()
+            throws IncompatiblePolicyException {
+        PasswordPolicySpec passwordPolicySpec = createBasePasswordPolicySpec();
+        passwordPolicySpec.setMustStartWithDigit(true);
+
+        PasswordPolicySpec passwordPolicySpec2 = createBasePasswordPolicySpec();
+        passwordPolicySpec.setMustEndWithDigit(true);
+        List<PasswordPolicySpec> passwordPolicySpecs = new ArrayList<PasswordPolicySpec>();
+        passwordPolicySpecs.add(passwordPolicySpec);
+        passwordPolicySpecs.add(passwordPolicySpec2);
+        String generatedPassword = passwordGenerator.generatePasswordFromPwdSpec(passwordPolicySpecs);
+        assertTrue(Character.isDigit(generatedPassword.charAt(0)));
+        assertTrue(Character.isDigit(generatedPassword.charAt(generatedPassword.length() - 1)));
+    }
+
+    @Test
+    public void startWithDigitAndWithAlpha()
+            throws IncompatiblePolicyException {
+        PasswordPolicySpec passwordPolicySpec = createBasePasswordPolicySpec();
+        passwordPolicySpec.setMustStartWithDigit(true);
+
+        PasswordPolicySpec passwordPolicySpec2 = createBasePasswordPolicySpec();
+        passwordPolicySpec.setMustEndWithAlpha(true);
+        List<PasswordPolicySpec> passwordPolicySpecs = new ArrayList<PasswordPolicySpec>();
+        passwordPolicySpecs.add(passwordPolicySpec);
+        passwordPolicySpecs.add(passwordPolicySpec2);
+        String generatedPassword = passwordGenerator.generatePasswordFromPwdSpec(passwordPolicySpecs);
+        assertTrue(Character.isDigit(generatedPassword.charAt(0)));
+        assertTrue(Character.isLetter(generatedPassword.charAt(generatedPassword.length() - 1)));
+    }
+
+    @Test
+    public void passwordWithNonAlpha()
+            throws IncompatiblePolicyException {
+        PasswordPolicySpec passwordPolicySpec = createBasePasswordPolicySpec();
+        passwordPolicySpec.setNonAlphanumericRequired(true);
+
+        PasswordPolicySpec passwordPolicySpec2 = createBasePasswordPolicySpec();
+        passwordPolicySpec.setMustEndWithAlpha(true);
+        List<PasswordPolicySpec> passwordPolicySpecs = new ArrayList<PasswordPolicySpec>();
+        passwordPolicySpecs.add(passwordPolicySpec);
+        passwordPolicySpecs.add(passwordPolicySpec2);
+        String generatedPassword = passwordGenerator.generatePasswordFromPwdSpec(passwordPolicySpecs);
+        assertTrue(PolicyPattern.NON_ALPHANUMERIC.matcher(generatedPassword.toString()).matches());
+        assertTrue(Character.isLetter(generatedPassword.charAt(generatedPassword.length() - 1)));
+    }
+
+    @Test(expected = IncompatiblePolicyException.class)
+    public void incopatiblePolicies()
+            throws IncompatiblePolicyException {
+        PasswordPolicySpec passwordPolicySpec = createBasePasswordPolicySpec();
+        passwordPolicySpec.setMinLength(12);
+
+        PasswordPolicySpec passwordPolicySpec2 = createBasePasswordPolicySpec();
+        passwordPolicySpec.setMaxLength(10);
+
+        List<PasswordPolicySpec> passwordPolicySpecs = new ArrayList<PasswordPolicySpec>();
+        passwordPolicySpecs.add(passwordPolicySpec);
+        passwordPolicySpecs.add(passwordPolicySpec2);
+        passwordGenerator.generatePasswordFromPwdSpec(passwordPolicySpecs);
+    }
+
+    private PasswordPolicySpec createBasePasswordPolicySpec() {
+        PasswordPolicySpec basePasswordPolicySpec = new PasswordPolicySpec();
+        basePasswordPolicySpec.setAlphanumericRequired(false);
+        basePasswordPolicySpec.setDigitRequired(false);
+        basePasswordPolicySpec.setLowercaseRequired(false);
+        basePasswordPolicySpec.setMaxLength(1000);
+        basePasswordPolicySpec.setMinLength(8);
+        basePasswordPolicySpec.setMustEndWithAlpha(false);
+        basePasswordPolicySpec.setMustEndWithDigit(false);
+        basePasswordPolicySpec.setMustEndWithNonAlpha(false);
+        basePasswordPolicySpec.setMustStartWithAlpha(false);
+        basePasswordPolicySpec.setMustStartWithDigit(false);
+        basePasswordPolicySpec.setMustStartWithNonAlpha(false);
+        basePasswordPolicySpec.setMustntEndWithAlpha(false);
+        basePasswordPolicySpec.setMustntEndWithDigit(false);
+        basePasswordPolicySpec.setMustntEndWithNonAlpha(false);
+        basePasswordPolicySpec.setMustntStartWithAlpha(false);
+        basePasswordPolicySpec.setMustntStartWithDigit(false);
+        basePasswordPolicySpec.setMustntStartWithNonAlpha(false);
+        basePasswordPolicySpec.setNonAlphanumericRequired(false);
+        basePasswordPolicySpec.setUppercaseRequired(false);
+        return basePasswordPolicySpec;
+    }
+}

Propchange: incubator/syncope/trunk/core/src/test/java/org/apache/syncope/core/util/PasswordGeneratorTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/syncope/trunk/core/src/test/java/org/apache/syncope/core/util/PasswordGeneratorTest.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: incubator/syncope/trunk/core/src/test/java/org/apache/syncope/core/util/PasswordGeneratorTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: incubator/syncope/trunk/core/src/test/resources/content.xml
URL: http://svn.apache.org/viewvc/incubator/syncope/trunk/core/src/test/resources/content.xml?rev=1401200&r1=1401199&r2=1401200&view=diff
==============================================================================
--- incubator/syncope/trunk/core/src/test/resources/content.xml (original)
+++ incubator/syncope/trunk/core/src/test/resources/content.xml Tue Oct 23 08:51:35 2012
@@ -36,11 +36,11 @@ under the License.
   <Policy DTYPE="SyncPolicy" id="1" description="sync policy 1" type="GLOBAL_SYNC" specification="%3Corg.apache.syncope.types.SyncPolicySpec%2F%3E"/>
   <Policy DTYPE="PasswordPolicy" id="2" description="global password policy" type="GLOBAL_PASSWORD" specification="%3Corg.apache.syncope.types.PasswordPolicySpec%3E%0A++%3ChistoryLength%3E1%3C%2FhistoryLength%3E%0A++%3CmaxLength%3E0%3C%2FmaxLength%3E%0A++%3CminLength%3E8%3C%2FminLength%3E%0A++%3CnonAlphanumericRequired%3Efalse%3C%2FnonAlphanumericRequired%3E%0A++%3CalphanumericRequired%3Efalse%3C%2FalphanumericRequired%3E%0A++%3CdigitRequired%3Efalse%3C%2FdigitRequired%3E%0A++%3ClowercaseRequired%3Efalse%3C%2FlowercaseRequired%3E%0A++%3CuppercaseRequired%3Efalse%3C%2FuppercaseRequired%3E%0A++%3CmustStartWithDigit%3Efalse%3C%2FmustStartWithDigit%3E%0A++%3CmustntStartWithDigit%3Efalse%3C%2FmustntStartWithDigit%3E%0A++%3CmustEndWithDigit%3Efalse%3C%2FmustEndWithDigit%3E%0A++%3CmustntEndWithDigit%3Efalse%3C%2FmustntEndWithDigit%3E%0A++%3CmustStartWithNonAlpha%3Efalse%3C%2FmustStartWithNonAlpha%3E%0A++%3CmustStartWithAlpha%3Efalse%3C%2FmustStartWithAlpha%3E%0A++%3CmustntStartWith
 NonAlpha%3Efalse%3C%2FmustntStartWithNonAlpha%3E%0A++%3CmustntStartWithAlpha%3Efalse%3C%2FmustntStartWithAlpha%3E%0A++%3CmustEndWithNonAlpha%3Efalse%3C%2FmustEndWithNonAlpha%3E%0A++%3CmustEndWithAlpha%3Efalse%3C%2FmustEndWithAlpha%3E%0A++%3CmustntEndWithNonAlpha%3Efalse%3C%2FmustntEndWithNonAlpha%3E%0A++%3CmustntEndWithAlpha%3Efalse%3C%2FmustntEndWithAlpha%3E%0A++%3CprefixesNotPermitted%3E%0A++++%3Cstring%3Enotpermitted1%3C%2Fstring%3E%0A++++%3Cstring%3Enotpermitted2%3C%2Fstring%3E%0A++%3C%2FprefixesNotPermitted%3E%0A%3C%2Forg.apache.syncope.types.PasswordPolicySpec%3E"/>
   <Policy DTYPE="SyncPolicy" id="3" description="sync policy 2" type="SYNC" specification="%3Corg.apache.syncope.types.SyncPolicySpec%3E%0A++%3CalternativeSearchAttrs%3E%0A++++%3Cstring%3Eusername%3C%2Fstring%3E%0A++++%3Cstring%3Efirstname%3C%2Fstring%3E%0A++%3C%2FalternativeSearchAttrs%3E%0A++%3CconflictResolutionAction%3EALL%3C%2FconflictResolutionAction%3E%0A%3C%2Forg.apache.syncope.types.SyncPolicySpec%3E"/>
-  <Policy DTYPE="PasswordPolicy" id="4" description="sample password policy" type="PASSWORD" specification="%3Corg.apache.syncope.types.PasswordPolicySpec%3E%0A++%3ChistoryLength%3E0%3C%2FhistoryLength%3E%0A++%3CmaxLength%3E0%3C%2FmaxLength%3E%0A++%3CminLength%3E10%3C%2FminLength%3E%0A++%3CnonAlphanumericRequired%3Efalse%3C%2FnonAlphanumericRequired%3E%0A++%3CalphanumericRequired%3Efalse%3C%2FalphanumericRequired%3E%0A++%3CdigitRequired%3Efalse%3C%2FdigitRequired%3E%0A++%3ClowercaseRequired%3Efalse%3C%2FlowercaseRequired%3E%0A++%3CuppercaseRequired%3Efalse%3C%2FuppercaseRequired%3E%0A++%3CmustStartWithDigit%3Efalse%3C%2FmustStartWithDigit%3E%0A++%3CmustntStartWithDigit%3Efalse%3C%2FmustntStartWithDigit%3E%0A++%3CmustEndWithDigit%3Efalse%3C%2FmustEndWithDigit%3E%0A++%3CmustntEndWithDigit%3Efalse%3C%2FmustntEndWithDigit%3E%0A++%3CmustStartWithNonAlpha%3Efalse%3C%2FmustStartWithNonAlpha%3E%0A++%3CmustStartWithAlpha%3Efalse%3C%2FmustStartWithAlpha%3E%0A++%3CmustntStartWithNonAlp
 ha%3Efalse%3C%2FmustntStartWithNonAlpha%3E%0A++%3CmustntStartWithAlpha%3Efalse%3C%2FmustntStartWithAlpha%3E%0A++%3CmustEndWithNonAlpha%3Efalse%3C%2FmustEndWithNonAlpha%3E%0A++%3CmustEndWithAlpha%3Efalse%3C%2FmustEndWithAlpha%3E%0A++%3CmustntEndWithNonAlpha%3Efalse%3C%2FmustntEndWithNonAlpha%3E%0A++%3CmustntEndWithAlpha%3Efalse%3C%2FmustntEndWithAlpha%3E%0A++%3CprefixesNotPermitted%3E%0A++++%3Cstring%3Enotpermitted1%3C%2Fstring%3E%0A++++%3Cstring%3Enotpermitted2%3C%2Fstring%3E%0A++%3C%2FprefixesNotPermitted%3E%0A%3C%2Forg.apache.syncope.types.PasswordPolicySpec%3E"/>
+  <Policy DTYPE="PasswordPolicy" id="4" description="sample password policy" type="PASSWORD" specification="%3Corg.apache.syncope.types.PasswordPolicySpec%3E%0A++%3ChistoryLength%3E0%3C%2FhistoryLength%3E%0A++%3CmaxLength%3E0%3C%2FmaxLength%3E%0A++%3CminLength%3E10%3C%2FminLength%3E%0A++%3CnonAlphanumericRequired%3Efalse%3C%2FnonAlphanumericRequired%3E%0A++%3CalphanumericRequired%3Efalse%3C%2FalphanumericRequired%3E%0A++%3CdigitRequired%3Etrue%3C%2FdigitRequired%3E%0A++%3ClowercaseRequired%3Efalse%3C%2FlowercaseRequired%3E%0A++%3CuppercaseRequired%3Efalse%3C%2FuppercaseRequired%3E%0A++%3CmustStartWithDigit%3Efalse%3C%2FmustStartWithDigit%3E%0A++%3CmustntStartWithDigit%3Efalse%3C%2FmustntStartWithDigit%3E%0A++%3CmustEndWithDigit%3Efalse%3C%2FmustEndWithDigit%3E%0A++%3CmustntEndWithDigit%3Efalse%3C%2FmustntEndWithDigit%3E%0A++%3CmustStartWithNonAlpha%3Efalse%3C%2FmustStartWithNonAlpha%3E%0A++%3CmustStartWithAlpha%3Efalse%3C%2FmustStartWithAlpha%3E%0A++%3CmustntStartWithNonAlph
 a%3Efalse%3C%2FmustntStartWithNonAlpha%3E%0A++%3CmustntStartWithAlpha%3Efalse%3C%2FmustntStartWithAlpha%3E%0A++%3CmustEndWithNonAlpha%3Efalse%3C%2FmustEndWithNonAlpha%3E%0A++%3CmustEndWithAlpha%3Efalse%3C%2FmustEndWithAlpha%3E%0A++%3CmustntEndWithNonAlpha%3Efalse%3C%2FmustntEndWithNonAlpha%3E%0A++%3CmustntEndWithAlpha%3Efalse%3C%2FmustntEndWithAlpha%3E%0A++%3CprefixesNotPermitted%3E%0A++++%3Cstring%3Enotpermitted1%3C%2Fstring%3E%0A++++%3Cstring%3Enotpermitted2%3C%2Fstring%3E%0A++%3C%2FprefixesNotPermitted%3E%0A%3C%2Forg.apache.syncope.types.PasswordPolicySpec%3E"/>
   <Policy DTYPE="AccountPolicy" id="5" description="global account policy" type="GLOBAL_ACCOUNT" specification="%3Corg.apache.syncope.types.AccountPolicySpec%3E%0A++%3CmaxLength%3E0%3C%2FmaxLength%3E%0A++%3CminLength%3E0%3C%2FminLength%3E%0A++%3CallUpperCase%3Efalse%3C%2FallUpperCase%3E%0A++%3CallLowerCase%3Efalse%3C%2FallLowerCase%3E%0A++%3CpropagateSuspension%3Efalse%3C%2FpropagateSuspension%3E%0A++%3CpermittedLoginRetries%3E0%3C%2FpermittedLoginRetries%3E%0A%3C%2Forg.apache.syncope.types.AccountPolicySpec%3E"/>
   <Policy DTYPE="AccountPolicy" id="6" description="sample account policy" type="ACCOUNT" specification="%3Corg.apache.syncope.types.AccountPolicySpec%3E%0A++%3CmaxLength%3E0%3C%2FmaxLength%3E%0A++%3CminLength%3E4%3C%2FminLength%3E%0A++%3CprefixesNotPermitted%3E%0A++++%3Cstring%3Enotpermitted1%3C%2Fstring%3E%0A++++%3Cstring%3Enotpermitted2%3C%2Fstring%3E%0A++%3C%2FprefixesNotPermitted%3E%0A++%3CallUpperCase%3Efalse%3C%2FallUpperCase%3E%0A++%3CallLowerCase%3Efalse%3C%2FallLowerCase%3E%0A++%3CpropagateSuspension%3Efalse%3C%2FpropagateSuspension%3E%0A++%3CpermittedLoginRetries%3E3%3C%2FpermittedLoginRetries%3E%0A%3C%2Forg.apache.syncope.types.AccountPolicySpec%3E"/>
   <Policy DTYPE="SyncPolicy" id="7" description="sync policy 1" type="SYNC" specification="%3Corg.apache.syncope.types.SyncPolicySpec%2F%3E"/>
-  <Policy DTYPE="PasswordPolicy" id="8" description="sample password policy" type="PASSWORD" specification="%3Corg.apache.syncope.types.PasswordPolicySpec%3E%0A++%3ChistoryLength%3E0%3C%2FhistoryLength%3E%0A++%3CmaxLength%3E0%3C%2FmaxLength%3E%0A++%3CminLength%3E10%3C%2FminLength%3E%0A++%3CnonAlphanumericRequired%3Efalse%3C%2FnonAlphanumericRequired%3E%0A++%3CalphanumericRequired%3Efalse%3C%2FalphanumericRequired%3E%0A++%3CdigitRequired%3Etrue%3C%2FdigitRequired%3E%0A++%3ClowercaseRequired%3Efalse%3C%2FlowercaseRequired%3E%0A++%3CuppercaseRequired%3Efalse%3C%2FuppercaseRequired%3E%0A++%3CmustStartWithDigit%3Efalse%3C%2FmustStartWithDigit%3E%0A++%3CmustntStartWithDigit%3Efalse%3C%2FmustntStartWithDigit%3E%0A++%3CmustEndWithDigit%3Efalse%3C%2FmustEndWithDigit%3E%0A++%3CmustntEndWithDigit%3Efalse%3C%2FmustntEndWithDigit%3E%0A++%3CmustStartWithNonAlpha%3Efalse%3C%2FmustStartWithNonAlpha%3E%0A++%3CmustStartWithAlpha%3Efalse%3C%2FmustStartWithAlpha%3E%0A++%3CmustntStartWithNonAlph
 a%3Efalse%3C%2FmustntStartWithNonAlpha%3E%0A++%3CmustntStartWithAlpha%3Efalse%3C%2FmustntStartWithAlpha%3E%0A++%3CmustEndWithNonAlpha%3Efalse%3C%2FmustEndWithNonAlpha%3E%0A++%3CmustEndWithAlpha%3Efalse%3C%2FmustEndWithAlpha%3E%0A++%3CmustntEndWithNonAlpha%3Efalse%3C%2FmustntEndWithNonAlpha%3E%0A++%3CmustntEndWithAlpha%3Efalse%3C%2FmustntEndWithAlpha%3E%0A++%3CprefixesNotPermitted%3E%0A++++%3Cstring%3Enotpermitted1%3C%2Fstring%3E%0A++++%3Cstring%3Enotpermitted2%3C%2Fstring%3E%0A++%3C%2FprefixesNotPermitted%3E%0A%3C%2Forg.apache.syncope.types.PasswordPolicySpec%3E"/>
+  <Policy DTYPE="PasswordPolicy" id="8" description="sample password policy" type="PASSWORD" specification="%3Corg.apache.syncope.types.PasswordPolicySpec%3E%0A++%3ChistoryLength%3E0%3C%2FhistoryLength%3E%0A++%3CmaxLength%3E0%3C%2FmaxLength%3E%0A++%3CminLength%3E10%3C%2FminLength%3E%0A++%3CnonAlphanumericRequired%3Etrue%3C%2FnonAlphanumericRequired%3E%0A++%3CalphanumericRequired%3Efalse%3C%2FalphanumericRequired%3E%0A++%3CdigitRequired%3Etrue%3C%2FdigitRequired%3E%0A++%3ClowercaseRequired%3Etrue%3C%2FlowercaseRequired%3E%0A++%3CuppercaseRequired%3Etrue%3C%2FuppercaseRequired%3E%0A++%3CmustStartWithDigit%3Etrue%3C%2FmustStartWithDigit%3E%0A++%3CmustntStartWithDigit%3Efalse%3C%2FmustntStartWithDigit%3E%0A++%3CmustEndWithDigit%3Etrue%3C%2FmustEndWithDigit%3E%0A++%3CmustntEndWithDigit%3Efalse%3C%2FmustntEndWithDigit%3E%0A++%3CmustStartWithNonAlpha%3Efalse%3C%2FmustStartWithNonAlpha%3E%0A++%3CmustStartWithAlpha%3Efalse%3C%2FmustStartWithAlpha%3E%0A++%3CmustntStartWithNonAlpha%3Ef
 alse%3C%2FmustntStartWithNonAlpha%3E%0A++%3CmustntStartWithAlpha%3Efalse%3C%2FmustntStartWithAlpha%3E%0A++%3CmustEndWithNonAlpha%3Efalse%3C%2FmustEndWithNonAlpha%3E%0A++%3CmustEndWithAlpha%3Efalse%3C%2FmustEndWithAlpha%3E%0A++%3CmustntEndWithNonAlpha%3Efalse%3C%2FmustntEndWithNonAlpha%3E%0A++%3CmustntEndWithAlpha%3Efalse%3C%2FmustntEndWithAlpha%3E%0A++%3CprefixesNotPermitted%3E%0A++++%3Cstring%3Enotpermitted1%3C%2Fstring%3E%0A++++%3Cstring%3Enotpermitted2%3C%2Fstring%3E%0A++%3C%2FprefixesNotPermitted%3E%0A%3C%2Forg.apache.syncope.types.PasswordPolicySpec%3E"/>
     
   <SyncopeUser id="1" workflowId="0" status="active" password="5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8" cipherAlgorithm="SHA1"
                username="user1" creationDate="2010-10-20 11:00:00"/>