You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@syncope.apache.org by il...@apache.org on 2015/08/20 11:47:48 UTC

[08/12] syncope git commit: Merge branch 'master' of https://git-wip-us.apache.org/repos/asf/syncope

Merge branch 'master' of https://git-wip-us.apache.org/repos/asf/syncope


Project: http://git-wip-us.apache.org/repos/asf/syncope/repo
Commit: http://git-wip-us.apache.org/repos/asf/syncope/commit/77f697b2
Tree: http://git-wip-us.apache.org/repos/asf/syncope/tree/77f697b2
Diff: http://git-wip-us.apache.org/repos/asf/syncope/diff/77f697b2

Branch: refs/heads/master
Commit: 77f697b2dbb05c81818288f74f3f7b7656db8b7f
Parents: 8e21972 4cdb34b
Author: Francesco Chicchiriccò <il...@apache.org>
Authored: Thu Aug 20 11:41:11 2015 +0200
Committer: Francesco Chicchiriccò <il...@apache.org>
Committed: Thu Aug 20 11:41:11 2015 +0200

----------------------------------------------------------------------
 .../lib/policy/AbstractAccountRuleConf.java     |  52 +++
 .../lib/policy/AbstractPasswordRuleConf.java    |  52 +++
 .../common/lib/policy/AbstractPolicyTO.java     |  97 ++++++
 .../common/lib/policy/AccountPolicyTO.java      |  77 +++++
 .../common/lib/policy/AccountRuleConf.java      |  23 ++
 .../lib/policy/DefaultAccountRuleConf.java      |  94 ++++++
 .../lib/policy/DefaultPasswordRuleConf.java     | 277 ++++++++++++++++
 .../common/lib/policy/PasswordPolicyTO.java     |  68 ++++
 .../common/lib/policy/PasswordRuleConf.java     |  23 ++
 .../syncope/common/lib/policy/PolicyType.java   |  43 +++
 .../common/lib/policy/PushPolicySpec.java       |  28 ++
 .../syncope/common/lib/policy/RuleConf.java     |  32 ++
 .../common/lib/policy/SyncPolicySpec.java       |  63 ++++
 .../syncope/common/lib/policy/SyncPolicyTO.java |  45 +++
 .../common/lib/wrap/ReportletConfClass.java     |  30 --
 .../misc/policy/InvalidPasswordRuleConf.java    |  37 +++
 .../misc/security/DefaultPasswordGenerator.java | 330 +++++++++++++++++++
 .../core/persistence/api/dao/AccountRule.java   |  27 ++
 .../api/dao/AccountRuleConfClass.java           |  32 ++
 .../core/persistence/api/dao/PasswordRule.java  |  27 ++
 .../api/dao/PasswordRuleConfClass.java          |  32 ++
 .../api/entity/policy/AccountPolicy.java        |  50 +++
 .../api/entity/policy/PasswordPolicy.java       |  40 +++
 .../api/entity/policy/PushPolicy.java           |  29 ++
 .../api/entity/policy/SyncPolicy.java           |  30 ++
 .../persistence/jpa/dao/DefaultAccountRule.java | 112 +++++++
 .../jpa/dao/DefaultPasswordRule.java            | 218 ++++++++++++
 .../jpa/entity/policy/AbstractPolicy.java       |  67 ++++
 .../jpa/entity/policy/JPAAccountPolicy.java     | 160 +++++++++
 .../policy/JPAAccountRuleConfInstance.java      |  73 ++++
 .../jpa/entity/policy/JPAPasswordPolicy.java    | 115 +++++++
 .../policy/JPAPasswordRuleConfInstance.java     |  73 ++++
 .../jpa/entity/policy/JPAPushPolicy.java        |  55 ++++
 .../jpa/entity/policy/JPASyncPolicy.java        |  54 +++
 .../jpa/entity/task/AbstractTask.java           |  96 ++++++
 .../fit/core/reference/TestAccountRule.java     |  48 +++
 .../fit/core/reference/TestAccountRuleConf.java |  36 ++
 .../fit/core/reference/TestPasswordRule.java    |  48 +++
 .../core/reference/TestPasswordRuleConf.java    |  36 ++
 39 files changed, 2799 insertions(+), 30 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/syncope/blob/77f697b2/common/lib/src/main/java/org/apache/syncope/common/lib/policy/AbstractAccountRuleConf.java
----------------------------------------------------------------------
diff --cc common/lib/src/main/java/org/apache/syncope/common/lib/policy/AbstractAccountRuleConf.java
index 0000000,0000000..8fe5e24
new file mode 100644
--- /dev/null
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/policy/AbstractAccountRuleConf.java
@@@ -1,0 -1,0 +1,52 @@@
++/*
++ * 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.common.lib.report;
++
++import javax.xml.bind.annotation.XmlSeeAlso;
++import javax.xml.bind.annotation.XmlType;
++import org.apache.commons.lang3.StringUtils;
++import org.apache.syncope.common.lib.AbstractBaseBean;
++
++@XmlType
++@XmlSeeAlso({ StaticReportletConf.class, UserReportletConf.class, GroupReportletConf.class })
++public abstract class AbstractReportletConf extends AbstractBaseBean implements ReportletConf {
++
++    private static final long serialVersionUID = -6130008602014516608L;
++
++    private String name;
++
++    public AbstractReportletConf() {
++        this(StringUtils.EMPTY);
++        setName(getClass().getName());
++    }
++
++    public AbstractReportletConf(final String name) {
++        super();
++        this.name = name;
++    }
++
++    @Override
++    public final String getName() {
++        return name;
++    }
++
++    public final void setName(final String name) {
++        this.name = name;
++    }
++}

http://git-wip-us.apache.org/repos/asf/syncope/blob/77f697b2/common/lib/src/main/java/org/apache/syncope/common/lib/policy/AbstractPasswordRuleConf.java
----------------------------------------------------------------------
diff --cc common/lib/src/main/java/org/apache/syncope/common/lib/policy/AbstractPasswordRuleConf.java
index 0000000,0000000..8fe5e24
new file mode 100644
--- /dev/null
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/policy/AbstractPasswordRuleConf.java
@@@ -1,0 -1,0 +1,52 @@@
++/*
++ * 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.common.lib.report;
++
++import javax.xml.bind.annotation.XmlSeeAlso;
++import javax.xml.bind.annotation.XmlType;
++import org.apache.commons.lang3.StringUtils;
++import org.apache.syncope.common.lib.AbstractBaseBean;
++
++@XmlType
++@XmlSeeAlso({ StaticReportletConf.class, UserReportletConf.class, GroupReportletConf.class })
++public abstract class AbstractReportletConf extends AbstractBaseBean implements ReportletConf {
++
++    private static final long serialVersionUID = -6130008602014516608L;
++
++    private String name;
++
++    public AbstractReportletConf() {
++        this(StringUtils.EMPTY);
++        setName(getClass().getName());
++    }
++
++    public AbstractReportletConf(final String name) {
++        super();
++        this.name = name;
++    }
++
++    @Override
++    public final String getName() {
++        return name;
++    }
++
++    public final void setName(final String name) {
++        this.name = name;
++    }
++}

http://git-wip-us.apache.org/repos/asf/syncope/blob/77f697b2/common/lib/src/main/java/org/apache/syncope/common/lib/policy/AbstractPolicyTO.java
----------------------------------------------------------------------
diff --cc common/lib/src/main/java/org/apache/syncope/common/lib/policy/AbstractPolicyTO.java
index 0000000,0000000..9157ba2
new file mode 100644
--- /dev/null
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/policy/AbstractPolicyTO.java
@@@ -1,0 -1,0 +1,97 @@@
++/*
++ * 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.common.lib.policy;
++
++import com.fasterxml.jackson.annotation.JsonProperty;
++import com.fasterxml.jackson.annotation.JsonTypeInfo;
++import java.util.ArrayList;
++import java.util.List;
++import javax.ws.rs.PathParam;
++import javax.xml.bind.annotation.XmlElement;
++import javax.xml.bind.annotation.XmlElementWrapper;
++import javax.xml.bind.annotation.XmlRootElement;
++import javax.xml.bind.annotation.XmlSeeAlso;
++import javax.xml.bind.annotation.XmlType;
++import org.apache.syncope.common.lib.AbstractBaseBean;
++import org.apache.syncope.common.lib.types.PolicyType;
++
++@XmlRootElement(name = "abstractPolicy")
++@XmlType
++@XmlSeeAlso({ AccountPolicyTO.class, PasswordPolicyTO.class, SyncPolicyTO.class })
++@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class")
++public abstract class AbstractPolicyTO extends AbstractBaseBean {
++
++    private static final long serialVersionUID = -2903888572649721035L;
++
++    private long key;
++
++    private String description;
++
++    private final PolicyType type;
++
++    private final List<String> usedByResources = new ArrayList<>();
++
++    private final List<String> usedByRealms = new ArrayList<>();
++
++    private AbstractPolicyTO() {
++        super();
++        throw new UnsupportedOperationException("No-arg constructor is just to keep JAXB from complaining");
++    }
++
++    protected AbstractPolicyTO(final PolicyType type) {
++        super();
++        this.type = type;
++    }
++
++    public long getKey() {
++        return key;
++    }
++
++    @PathParam("key")
++    public void setKey(final long key) {
++        this.key = key;
++    }
++
++    public String getDescription() {
++        return description;
++    }
++
++    public void setDescription(final String description) {
++        this.description = description;
++    }
++
++    public PolicyType getType() {
++        return type;
++    }
++
++    @XmlElementWrapper(name = "usedByResources")
++    @XmlElement(name = "resource")
++    @JsonProperty("usedByResources")
++    public List<String> getUsedByResources() {
++        return usedByResources;
++    }
++
++    @XmlElementWrapper(name = "usedByRealms")
++    @XmlElement(name = "group")
++    @JsonProperty("usedByRealms")
++    public List<String> getUsedByRealms() {
++        return usedByRealms;
++    }
++
++}

http://git-wip-us.apache.org/repos/asf/syncope/blob/77f697b2/common/lib/src/main/java/org/apache/syncope/common/lib/policy/AccountPolicyTO.java
----------------------------------------------------------------------
diff --cc common/lib/src/main/java/org/apache/syncope/common/lib/policy/AccountPolicyTO.java
index 0000000,0000000..67d9fe0
new file mode 100644
--- /dev/null
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/policy/AccountPolicyTO.java
@@@ -1,0 -1,0 +1,77 @@@
++/*
++ * 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.common.lib.policy;
++
++import com.fasterxml.jackson.annotation.JsonProperty;
++import java.util.ArrayList;
++import java.util.List;
++import javax.xml.bind.annotation.XmlElement;
++import javax.xml.bind.annotation.XmlElementWrapper;
++import javax.xml.bind.annotation.XmlRootElement;
++import javax.xml.bind.annotation.XmlType;
++import org.apache.syncope.common.lib.types.PolicyType;
++
++@XmlRootElement(name = "accountPolicy")
++@XmlType
++public class AccountPolicyTO extends AbstractPolicyTO {
++
++    private static final long serialVersionUID = -1557150042828800134L;
++
++    private boolean propagateSuspension;
++
++    private int maxAuthenticationAttempts;
++
++    private final List<AccountRuleConf> ruleConfs = new ArrayList<>();
++
++    private final List<String> resources = new ArrayList<>();
++
++    public AccountPolicyTO() {
++        super(PolicyType.ACCOUNT);
++    }
++
++    public boolean isPropagateSuspension() {
++        return propagateSuspension;
++    }
++
++    public void setPropagateSuspension(final boolean propagateSuspension) {
++        this.propagateSuspension = propagateSuspension;
++    }
++
++    public int getMaxAuthenticationAttempts() {
++        return maxAuthenticationAttempts;
++    }
++
++    public void setMaxAuthenticationAttempts(final int maxAuthenticationAttempts) {
++        this.maxAuthenticationAttempts = maxAuthenticationAttempts;
++    }
++
++    @XmlElementWrapper(name = "ruleConfs")
++    @XmlElement(name = "ruleConf")
++    @JsonProperty("ruleConfs")
++    public List<AccountRuleConf> getRuleConfs() {
++        return ruleConfs;
++    }
++
++    @XmlElementWrapper(name = "resources")
++    @XmlElement(name = "resource")
++    @JsonProperty("resources")
++    public List<String> getResources() {
++        return resources;
++    }
++}

http://git-wip-us.apache.org/repos/asf/syncope/blob/77f697b2/common/lib/src/main/java/org/apache/syncope/common/lib/policy/AccountRuleConf.java
----------------------------------------------------------------------
diff --cc common/lib/src/main/java/org/apache/syncope/common/lib/policy/AccountRuleConf.java
index 0000000,0000000..aa107fc
new file mode 100644
--- /dev/null
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/policy/AccountRuleConf.java
@@@ -1,0 -1,0 +1,23 @@@
++/*
++ * 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.common.lib.policy;
++
++public interface AccountRuleConf extends RuleConf {
++
++}

http://git-wip-us.apache.org/repos/asf/syncope/blob/77f697b2/common/lib/src/main/java/org/apache/syncope/common/lib/policy/DefaultAccountRuleConf.java
----------------------------------------------------------------------
diff --cc common/lib/src/main/java/org/apache/syncope/common/lib/policy/DefaultAccountRuleConf.java
index 0000000,0000000..929f05b
new file mode 100644
--- /dev/null
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/policy/DefaultAccountRuleConf.java
@@@ -1,0 -1,0 +1,94 @@@
++/*
++ * 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.common.lib.policy;
++
++import javax.xml.bind.annotation.XmlRootElement;
++import javax.xml.bind.annotation.XmlType;
++
++@XmlRootElement(name = "defaultAccountRuleConf")
++@XmlType
++public class DefaultAccountRuleConf extends AbstractRuleConf implements AccountRuleConf {
++
++    private static final long serialVersionUID = 3259256974414758406L;
++
++    /**
++     * Minimum length.
++     */
++    private int maxLength;
++
++    /**
++     * Maximum length.
++     */
++    private int minLength;
++
++    /**
++     * Pattern (regular expression) that must match.
++     */
++    private String pattern;
++
++    /**
++     * Specify if one or more lowercase characters are permitted.
++     */
++    private boolean allUpperCase;
++
++    /**
++     * Specify if one or more uppercase characters are permitted.
++     */
++    private boolean allLowerCase;
++
++    public boolean isAllLowerCase() {
++        return allLowerCase;
++    }
++
++    public void setAllLowerCase(final boolean allLowerCase) {
++        this.allLowerCase = allLowerCase;
++    }
++
++    public boolean isAllUpperCase() {
++        return allUpperCase;
++    }
++
++    public void setAllUpperCase(final boolean allUpperCase) {
++        this.allUpperCase = allUpperCase;
++    }
++
++    public int getMaxLength() {
++        return maxLength;
++    }
++
++    public void setMaxLength(final int maxLength) {
++        this.maxLength = maxLength;
++    }
++
++    public int getMinLength() {
++        return minLength;
++    }
++
++    public void setMinLength(final int minLength) {
++        this.minLength = minLength;
++    }
++
++    public String getPattern() {
++        return pattern;
++    }
++
++    public void setPattern(final String pattern) {
++        this.pattern = pattern;
++    }
++}

http://git-wip-us.apache.org/repos/asf/syncope/blob/77f697b2/common/lib/src/main/java/org/apache/syncope/common/lib/policy/DefaultPasswordRuleConf.java
----------------------------------------------------------------------
diff --cc common/lib/src/main/java/org/apache/syncope/common/lib/policy/DefaultPasswordRuleConf.java
index 0000000,0000000..629e820
new file mode 100644
--- /dev/null
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/policy/DefaultPasswordRuleConf.java
@@@ -1,0 -1,0 +1,277 @@@
++/*
++ * 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.common.lib.policy;
++
++import javax.xml.bind.annotation.XmlRootElement;
++import javax.xml.bind.annotation.XmlType;
++
++@XmlRootElement(name = "defaultPasswordRuleConf")
++@XmlType
++public class DefaultPasswordRuleConf extends AbstractRuleConf implements PasswordRuleConf {
++
++    private static final long serialVersionUID = -7988778083915548547L;
++
++    /**
++     * Minimum length.
++     */
++    private int maxLength;
++
++    /**
++     * Maximum length.
++     */
++    private int minLength;
++
++    /**
++     * Specify if one or more non alphanumeric characters are required.
++     */
++    private boolean nonAlphanumericRequired;
++
++    /**
++     * Specify if one or more alphanumeric characters are required.
++     */
++    private boolean alphanumericRequired;
++
++    /**
++     * Specify if one or more digits are required.
++     */
++    private boolean digitRequired;
++
++    /**
++     * Specify if one or more lowercase alphabetic characters are required.
++     */
++    private boolean lowercaseRequired;
++
++    /**
++     * Specify if one or more uppercase alphabetic characters are required.
++     */
++    private boolean uppercaseRequired;
++
++    /**
++     * Specify if must start with a digit.
++     */
++    private boolean mustStartWithDigit;
++
++    /**
++     * Specify if mustn't start with a digit.
++     */
++    private boolean mustntStartWithDigit;
++
++    /**
++     * Specify if must end with a digit.
++     */
++    private boolean mustEndWithDigit;
++
++    /**
++     * Specify if mustn't end with a digit.
++     */
++    private boolean mustntEndWithDigit;
++
++    /**
++     * Specify if must start with a non alphanumeric character.
++     */
++    private boolean mustStartWithNonAlpha;
++
++    /**
++     * Specify if must start with a alphanumeric character.
++     */
++    private boolean mustStartWithAlpha;
++
++    /**
++     * Specify if mustn't start with a non alphanumeric character.
++     */
++    private boolean mustntStartWithNonAlpha;
++
++    /**
++     * Specify if mustn't start with a alphanumeric character.
++     */
++    private boolean mustntStartWithAlpha;
++
++    /**
++     * Specify if must end with a non alphanumeric character.
++     */
++    private boolean mustEndWithNonAlpha;
++
++    /**
++     * Specify if must end with a alphanumeric character.
++     */
++    private boolean mustEndWithAlpha;
++
++    /**
++     * Specify if mustn't end with a non alphanumeric character.
++     */
++    private boolean mustntEndWithNonAlpha;
++
++    /**
++     * Specify if mustn't end with a alphanumeric character.
++     */
++    private boolean mustntEndWithAlpha;
++
++    public boolean isDigitRequired() {
++        return digitRequired;
++    }
++
++    public void setDigitRequired(final boolean digitRequired) {
++        this.digitRequired = digitRequired;
++    }
++
++    public boolean isLowercaseRequired() {
++        return lowercaseRequired;
++    }
++
++    public void setLowercaseRequired(final boolean lowercaseRequired) {
++        this.lowercaseRequired = lowercaseRequired;
++    }
++
++    public int getMaxLength() {
++        return maxLength;
++    }
++
++    public void setMaxLength(final int maxLength) {
++        this.maxLength = maxLength;
++    }
++
++    public int getMinLength() {
++        return minLength;
++    }
++
++    public void setMinLength(final int minLength) {
++        this.minLength = minLength;
++    }
++
++    public boolean isMustEndWithDigit() {
++        return mustEndWithDigit;
++    }
++
++    public void setMustEndWithDigit(final boolean mustEndWithDigit) {
++        this.mustEndWithDigit = mustEndWithDigit;
++    }
++
++    public boolean isMustEndWithNonAlpha() {
++        return mustEndWithNonAlpha;
++    }
++
++    public void setMustEndWithNonAlpha(final boolean mustEndWithNonAlpha) {
++        this.mustEndWithNonAlpha = mustEndWithNonAlpha;
++    }
++
++    public boolean isMustStartWithDigit() {
++        return mustStartWithDigit;
++    }
++
++    public void setMustStartWithDigit(final boolean mustStartWithDigit) {
++        this.mustStartWithDigit = mustStartWithDigit;
++    }
++
++    public boolean isMustStartWithNonAlpha() {
++        return mustStartWithNonAlpha;
++    }
++
++    public void setMustStartWithNonAlpha(final boolean mustStartWithNonAlpha) {
++        this.mustStartWithNonAlpha = mustStartWithNonAlpha;
++    }
++
++    public boolean isMustntEndWithDigit() {
++        return mustntEndWithDigit;
++    }
++
++    public void setMustntEndWithDigit(final boolean mustntEndWithDigit) {
++        this.mustntEndWithDigit = mustntEndWithDigit;
++    }
++
++    public boolean isMustntEndWithNonAlpha() {
++        return mustntEndWithNonAlpha;
++    }
++
++    public void setMustntEndWithNonAlpha(final boolean mustntEndWithNonAlpha) {
++        this.mustntEndWithNonAlpha = mustntEndWithNonAlpha;
++    }
++
++    public boolean isMustntStartWithDigit() {
++        return mustntStartWithDigit;
++    }
++
++    public void setMustntStartWithDigit(final boolean mustntStartWithDigit) {
++        this.mustntStartWithDigit = mustntStartWithDigit;
++    }
++
++    public boolean isMustntStartWithNonAlpha() {
++        return mustntStartWithNonAlpha;
++    }
++
++    public void setMustntStartWithNonAlpha(final boolean mustntStartWithNonAlpha) {
++        this.mustntStartWithNonAlpha = mustntStartWithNonAlpha;
++    }
++
++    public boolean isNonAlphanumericRequired() {
++        return nonAlphanumericRequired;
++    }
++
++    public void setNonAlphanumericRequired(final boolean nonAlphanumericRequired) {
++        this.nonAlphanumericRequired = nonAlphanumericRequired;
++    }
++
++    public boolean isUppercaseRequired() {
++        return uppercaseRequired;
++    }
++
++    public void setUppercaseRequired(final boolean uppercaseRequired) {
++        this.uppercaseRequired = uppercaseRequired;
++    }
++
++    public boolean isAlphanumericRequired() {
++        return alphanumericRequired;
++    }
++
++    public void setAlphanumericRequired(final boolean alphanumericRequired) {
++        this.alphanumericRequired = alphanumericRequired;
++    }
++
++    public boolean isMustEndWithAlpha() {
++        return mustEndWithAlpha;
++    }
++
++    public void setMustEndWithAlpha(final boolean mustEndWithAlpha) {
++        this.mustEndWithAlpha = mustEndWithAlpha;
++    }
++
++    public boolean isMustStartWithAlpha() {
++        return mustStartWithAlpha;
++    }
++
++    public void setMustStartWithAlpha(final boolean mustStartWithAlpha) {
++        this.mustStartWithAlpha = mustStartWithAlpha;
++    }
++
++    public boolean isMustntEndWithAlpha() {
++        return mustntEndWithAlpha;
++    }
++
++    public void setMustntEndWithAlpha(final boolean mustntEndWithAlpha) {
++        this.mustntEndWithAlpha = mustntEndWithAlpha;
++    }
++
++    public boolean isMustntStartWithAlpha() {
++        return mustntStartWithAlpha;
++    }
++
++    public void setMustntStartWithAlpha(final boolean mustntStartWithAlpha) {
++        this.mustntStartWithAlpha = mustntStartWithAlpha;
++    }
++
++}

http://git-wip-us.apache.org/repos/asf/syncope/blob/77f697b2/common/lib/src/main/java/org/apache/syncope/common/lib/policy/PasswordPolicyTO.java
----------------------------------------------------------------------
diff --cc common/lib/src/main/java/org/apache/syncope/common/lib/policy/PasswordPolicyTO.java
index 0000000,0000000..cf91df2
new file mode 100644
--- /dev/null
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/policy/PasswordPolicyTO.java
@@@ -1,0 -1,0 +1,68 @@@
++/*
++ * 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.common.lib.policy;
++
++import com.fasterxml.jackson.annotation.JsonProperty;
++import java.util.ArrayList;
++import java.util.List;
++import javax.xml.bind.annotation.XmlElement;
++import javax.xml.bind.annotation.XmlElementWrapper;
++import javax.xml.bind.annotation.XmlRootElement;
++import javax.xml.bind.annotation.XmlType;
++import org.apache.syncope.common.lib.types.PolicyType;
++
++@XmlRootElement(name = "passwordPolicy")
++@XmlType
++public class PasswordPolicyTO extends AbstractPolicyTO {
++
++    private static final long serialVersionUID = -5606086441294799690L;
++
++    private boolean allowNullPassword;
++
++    private int historyLength;
++
++    private final List<PasswordRuleConf> ruleConfs = new ArrayList<>();
++
++    public PasswordPolicyTO() {
++        super(PolicyType.PASSWORD);
++    }
++
++    public boolean isAllowNullPassword() {
++        return allowNullPassword;
++    }
++
++    public void setAllowNullPassword(final boolean allowNullPassword) {
++        this.allowNullPassword = allowNullPassword;
++    }
++
++    public int getHistoryLength() {
++        return historyLength;
++    }
++
++    public void setHistoryLength(final int historyLength) {
++        this.historyLength = historyLength;
++    }
++
++    @XmlElementWrapper(name = "ruleConfs")
++    @XmlElement(name = "ruleConf")
++    @JsonProperty("ruleConfs")
++    public List<PasswordRuleConf> getRuleConfs() {
++        return ruleConfs;
++    }
++}

http://git-wip-us.apache.org/repos/asf/syncope/blob/77f697b2/common/lib/src/main/java/org/apache/syncope/common/lib/policy/PasswordRuleConf.java
----------------------------------------------------------------------
diff --cc common/lib/src/main/java/org/apache/syncope/common/lib/policy/PasswordRuleConf.java
index 0000000,0000000..cf71500
new file mode 100644
--- /dev/null
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/policy/PasswordRuleConf.java
@@@ -1,0 -1,0 +1,23 @@@
++/*
++ * 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.common.lib.policy;
++
++public interface PasswordRuleConf extends RuleConf {
++
++}

http://git-wip-us.apache.org/repos/asf/syncope/blob/77f697b2/common/lib/src/main/java/org/apache/syncope/common/lib/policy/PolicyType.java
----------------------------------------------------------------------
diff --cc common/lib/src/main/java/org/apache/syncope/common/lib/policy/PolicyType.java
index 0000000,0000000..7f1c11e
new file mode 100644
--- /dev/null
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/policy/PolicyType.java
@@@ -1,0 -1,0 +1,43 @@@
++/*
++ * 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.common.lib.types;
++
++import javax.xml.bind.annotation.XmlEnum;
++
++@XmlEnum
++public enum PolicyType {
++
++    /**
++     * How username values should look like.
++     */
++    ACCOUNT,
++    /**
++     * How password values should look like.
++     */
++    PASSWORD,
++    /**
++     * For handling conflicts resolution during synchronization.
++     */
++    SYNC,
++    /**
++     * For handling conflicts resolution during push.
++     */
++    PUSH;
++
++}

http://git-wip-us.apache.org/repos/asf/syncope/blob/77f697b2/common/lib/src/main/java/org/apache/syncope/common/lib/policy/PushPolicySpec.java
----------------------------------------------------------------------
diff --cc common/lib/src/main/java/org/apache/syncope/common/lib/policy/PushPolicySpec.java
index 0000000,0000000..4b61374
new file mode 100644
--- /dev/null
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/policy/PushPolicySpec.java
@@@ -1,0 -1,0 +1,28 @@@
++/*
++ * 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.common.lib.policy;
++
++import javax.xml.bind.annotation.XmlType;
++
++@XmlType
++public class PushPolicySpec {
++
++    private static final long serialVersionUID = 3641030189482617497L;
++
++}

http://git-wip-us.apache.org/repos/asf/syncope/blob/77f697b2/common/lib/src/main/java/org/apache/syncope/common/lib/policy/RuleConf.java
----------------------------------------------------------------------
diff --cc common/lib/src/main/java/org/apache/syncope/common/lib/policy/RuleConf.java
index 0000000,0000000..5a99cd1
new file mode 100644
--- /dev/null
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/policy/RuleConf.java
@@@ -1,0 -1,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.common.lib.policy;
++
++import com.fasterxml.jackson.annotation.JsonTypeInfo;
++
++@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "@class")
++public interface RuleConf {
++
++    /**
++     * Give name of related rule instance.
++     *
++     * @return name of this rule instance
++     */
++    String getName();
++}

http://git-wip-us.apache.org/repos/asf/syncope/blob/77f697b2/common/lib/src/main/java/org/apache/syncope/common/lib/policy/SyncPolicySpec.java
----------------------------------------------------------------------
diff --cc common/lib/src/main/java/org/apache/syncope/common/lib/policy/SyncPolicySpec.java
index 0000000,0000000..1eb578e
new file mode 100644
--- /dev/null
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/policy/SyncPolicySpec.java
@@@ -1,0 -1,0 +1,63 @@@
++/*
++ * 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.common.lib.policy;
++
++import com.fasterxml.jackson.annotation.JsonIgnore;
++import com.fasterxml.jackson.annotation.JsonProperty;
++import java.util.HashMap;
++import java.util.Map;
++import javax.xml.bind.annotation.XmlType;
++import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
++import org.apache.syncope.common.lib.jaxb.XmlGenericMapAdapter;
++import org.apache.syncope.common.lib.types.ConflictResolutionAction;
++
++@XmlType
++public class SyncPolicySpec {
++
++    private static final long serialVersionUID = -3144027171719498127L;
++
++    private ConflictResolutionAction conflictResolutionAction;
++
++    /**
++     * Associates anyTypeKey to either:
++     * <ol>
++     * <li>Java class name, implementing {@code SyncCorrelationRule}</li>
++     * <li>JSON array containing plain schema names - this will be used to feed
++     * {@code PlainAttrsSyncCorrelationRule}</li>
++     * </ol>
++     */
++    @XmlJavaTypeAdapter(XmlGenericMapAdapter.class)
++    @JsonIgnore
++    private final Map<String, String> correlationRules = new HashMap<>();
++
++    public ConflictResolutionAction getConflictResolutionAction() {
++        return conflictResolutionAction == null
++                ? ConflictResolutionAction.IGNORE
++                : conflictResolutionAction;
++    }
++
++    public void setConflictResolutionAction(final ConflictResolutionAction conflictResolutionAction) {
++        this.conflictResolutionAction = conflictResolutionAction;
++    }
++
++    @JsonProperty
++    public Map<String, String> getCorrelationRules() {
++        return correlationRules;
++    }
++}

http://git-wip-us.apache.org/repos/asf/syncope/blob/77f697b2/common/lib/src/main/java/org/apache/syncope/common/lib/policy/SyncPolicyTO.java
----------------------------------------------------------------------
diff --cc common/lib/src/main/java/org/apache/syncope/common/lib/policy/SyncPolicyTO.java
index 0000000,0000000..911c445
new file mode 100644
--- /dev/null
+++ b/common/lib/src/main/java/org/apache/syncope/common/lib/policy/SyncPolicyTO.java
@@@ -1,0 -1,0 +1,45 @@@
++/*
++ * 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.common.lib.policy;
++
++import javax.xml.bind.annotation.XmlRootElement;
++import javax.xml.bind.annotation.XmlType;
++import org.apache.syncope.common.lib.types.PolicyType;
++
++@XmlRootElement(name = "syncPolicy")
++@XmlType
++public class SyncPolicyTO extends AbstractPolicyTO {
++
++    private static final long serialVersionUID = 993024634238024242L;
++
++    private SyncPolicySpec specification;
++
++    public SyncPolicyTO() {
++        super(PolicyType.SYNC);
++    }
++
++    public SyncPolicySpec getSpecification() {
++        return specification;
++    }
++
++    public void setSpecification(final SyncPolicySpec specification) {
++        this.specification = specification;
++    }
++
++}

http://git-wip-us.apache.org/repos/asf/syncope/blob/77f697b2/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/ReportletConfClass.java
----------------------------------------------------------------------
diff --cc common/lib/src/main/java/org/apache/syncope/common/lib/wrap/ReportletConfClass.java
index 24ba188,24ba188..0000000
deleted file mode 100644,100644
--- a/common/lib/src/main/java/org/apache/syncope/common/lib/wrap/ReportletConfClass.java
+++ /dev/null
@@@ -1,30 -1,30 +1,0 @@@
--/*
-- * 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.common.lib.wrap;
--
--import javax.xml.bind.annotation.XmlRootElement;
--import javax.xml.bind.annotation.XmlType;
--
--@XmlRootElement(name = "reportletConfClass")
--@XmlType
--public class ReportletConfClass extends AbstractWrappable<String> {
--
--    private static final long serialVersionUID = 1343357929074360450L;
--
--}

http://git-wip-us.apache.org/repos/asf/syncope/blob/77f697b2/core/misc/src/main/java/org/apache/syncope/core/misc/policy/InvalidPasswordRuleConf.java
----------------------------------------------------------------------
diff --cc core/misc/src/main/java/org/apache/syncope/core/misc/policy/InvalidPasswordRuleConf.java
index 0000000,0000000..4b13807
new file mode 100644
--- /dev/null
+++ b/core/misc/src/main/java/org/apache/syncope/core/misc/policy/InvalidPasswordRuleConf.java
@@@ -1,0 -1,0 +1,37 @@@
++/*
++ * 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.misc.policy;
++
++/**
++ * Raise when the merge of two or more PasswordRuleconf instances led to an inconsistent condition.
++ *
++ * @see org.apache.syncope.common.lib.policy.PasswordRuleConf
++ */
++public class InvalidPasswordRuleConf extends Exception {
++
++    private static final long serialVersionUID = 4810651743226663580L;
++
++    public InvalidPasswordRuleConf(final String msg) {
++        super(msg);
++    }
++
++    public InvalidPasswordRuleConf(final String msg, final Exception e) {
++        super(msg, e);
++    }
++}

http://git-wip-us.apache.org/repos/asf/syncope/blob/77f697b2/core/misc/src/main/java/org/apache/syncope/core/misc/security/DefaultPasswordGenerator.java
----------------------------------------------------------------------
diff --cc core/misc/src/main/java/org/apache/syncope/core/misc/security/DefaultPasswordGenerator.java
index 0000000,0000000..a1a1822
new file mode 100644
--- /dev/null
+++ b/core/misc/src/main/java/org/apache/syncope/core/misc/security/DefaultPasswordGenerator.java
@@@ -1,0 -1,0 +1,330 @@@
++/*
++ * 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.misc.security;
++
++import java.util.ArrayList;
++import java.util.List;
++import org.apache.commons.lang3.StringUtils;
++import org.apache.syncope.common.lib.policy.DefaultPasswordRuleConf;
++import org.apache.syncope.common.lib.policy.PasswordRuleConf;
++import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
++import org.apache.syncope.core.persistence.api.entity.user.User;
++import org.apache.syncope.core.misc.policy.InvalidPasswordRuleConf;
++import org.apache.syncope.core.misc.policy.PolicyPattern;
++import org.apache.syncope.core.persistence.api.dao.RealmDAO;
++import org.apache.syncope.core.persistence.api.dao.UserDAO;
++import org.apache.syncope.core.persistence.api.entity.Realm;
++import org.springframework.beans.factory.annotation.Autowired;
++
++/**
++ * Generate random passwords according to given policies.
++ * When no minimum and / or maximum length are specified, default values are set.
++ *
++ * <strong>WARNING</strong>: This class only takes {@link DefaultPasswordRuleConf} into account.
++ */
++public class DefaultPasswordGenerator implements PasswordGenerator {
++
++    private static final char[] SPECIAL_CHARS = { '!', '£', '%', '&', '(', ')', '?', '#', '$' };
++
++    private static final int VERY_MIN_LENGTH = 0;
++
++    private static final int VERY_MAX_LENGTH = 64;
++
++    private static final int MIN_LENGTH_IF_ZERO = 6;
++
++    @Autowired
++    private UserDAO userDAO;
++
++    @Autowired
++    private RealmDAO realmDAO;
++
++    @Override
++    public String generate(final User user) throws InvalidPasswordRuleConf {
++        List<PasswordRuleConf> ruleConfs = new ArrayList<>();
++
++        for (Realm ancestor : realmDAO.findAncestors(user.getRealm())) {
++            if (ancestor.getPasswordPolicy() != null) {
++                ruleConfs.addAll(ancestor.getPasswordPolicy().getRuleConfs());
++            }
++        }
++
++        for (ExternalResource resource : userDAO.findAllResources(user)) {
++            if (resource.getPasswordPolicy() != null) {
++                ruleConfs.addAll(resource.getPasswordPolicy().getRuleConfs());
++            }
++        }
++
++        return generate(ruleConfs);
++    }
++
++    @Override
++    public String generate(final List<PasswordRuleConf> ruleConfs) throws InvalidPasswordRuleConf {
++        List<DefaultPasswordRuleConf> defaultRuleConfs = new ArrayList<>();
++        for (PasswordRuleConf ruleConf : ruleConfs) {
++            if (ruleConf instanceof DefaultPasswordRuleConf) {
++                defaultRuleConfs.add((DefaultPasswordRuleConf) ruleConf);
++            }
++        }
++
++        DefaultPasswordRuleConf ruleConf = merge(defaultRuleConfs);
++        check(ruleConf);
++        return generate(ruleConf);
++    }
++
++    private DefaultPasswordRuleConf merge(final List<DefaultPasswordRuleConf> defaultRuleConfs) {
++        DefaultPasswordRuleConf fpps = new DefaultPasswordRuleConf();
++        fpps.setMinLength(VERY_MIN_LENGTH);
++        fpps.setMaxLength(VERY_MAX_LENGTH);
++
++        for (DefaultPasswordRuleConf ruleConf : defaultRuleConfs) {
++            if (ruleConf.getMinLength() > fpps.getMinLength()) {
++                fpps.setMinLength(ruleConf.getMinLength());
++            }
++
++            if ((ruleConf.getMaxLength() != 0) && ((ruleConf.getMaxLength() < fpps.getMaxLength()))) {
++                fpps.setMaxLength(ruleConf.getMaxLength());
++            }
++            fpps.getPrefixesNotPermitted().addAll(ruleConf.getPrefixesNotPermitted());
++            fpps.getSuffixesNotPermitted().addAll(ruleConf.getSuffixesNotPermitted());
++
++            if (!fpps.isNonAlphanumericRequired()) {
++                fpps.setNonAlphanumericRequired(ruleConf.isNonAlphanumericRequired());
++            }
++
++            if (!fpps.isAlphanumericRequired()) {
++                fpps.setAlphanumericRequired(ruleConf.isAlphanumericRequired());
++            }
++            if (!fpps.isDigitRequired()) {
++                fpps.setDigitRequired(ruleConf.isDigitRequired());
++            }
++
++            if (!fpps.isLowercaseRequired()) {
++                fpps.setLowercaseRequired(ruleConf.isLowercaseRequired());
++            }
++            if (!fpps.isUppercaseRequired()) {
++                fpps.setUppercaseRequired(ruleConf.isUppercaseRequired());
++            }
++            if (!fpps.isMustStartWithDigit()) {
++                fpps.setMustStartWithDigit(ruleConf.isMustStartWithDigit());
++            }
++            if (!fpps.isMustntStartWithDigit()) {
++                fpps.setMustntStartWithDigit(ruleConf.isMustntStartWithDigit());
++            }
++            if (!fpps.isMustEndWithDigit()) {
++                fpps.setMustEndWithDigit(ruleConf.isMustEndWithDigit());
++            }
++            if (fpps.isMustntEndWithDigit()) {
++                fpps.setMustntEndWithDigit(ruleConf.isMustntEndWithDigit());
++            }
++            if (!fpps.isMustStartWithAlpha()) {
++                fpps.setMustStartWithAlpha(ruleConf.isMustStartWithAlpha());
++            }
++            if (!fpps.isMustntStartWithAlpha()) {
++                fpps.setMustntStartWithAlpha(ruleConf.isMustntStartWithAlpha());
++            }
++            if (!fpps.isMustStartWithNonAlpha()) {
++                fpps.setMustStartWithNonAlpha(ruleConf.isMustStartWithNonAlpha());
++            }
++            if (!fpps.isMustntStartWithNonAlpha()) {
++                fpps.setMustntStartWithNonAlpha(ruleConf.isMustntStartWithNonAlpha());
++            }
++            if (!fpps.isMustEndWithNonAlpha()) {
++                fpps.setMustEndWithNonAlpha(ruleConf.isMustEndWithNonAlpha());
++            }
++            if (!fpps.isMustntEndWithNonAlpha()) {
++                fpps.setMustntEndWithNonAlpha(ruleConf.isMustntEndWithNonAlpha());
++            }
++            if (!fpps.isMustEndWithAlpha()) {
++                fpps.setMustEndWithAlpha(ruleConf.isMustEndWithAlpha());
++            }
++            if (!fpps.isMustntEndWithAlpha()) {
++                fpps.setMustntEndWithAlpha(ruleConf.isMustntEndWithAlpha());
++            }
++        }
++
++        if (fpps.getMinLength() == 0) {
++            fpps.setMinLength(fpps.getMaxLength() < MIN_LENGTH_IF_ZERO ? fpps.getMaxLength() : MIN_LENGTH_IF_ZERO);
++        }
++
++        return fpps;
++    }
++
++    private void check(final DefaultPasswordRuleConf defaultPasswordRuleConf)
++            throws InvalidPasswordRuleConf {
++
++        if (defaultPasswordRuleConf.isMustEndWithAlpha() && defaultPasswordRuleConf.isMustntEndWithAlpha()) {
++            throw new InvalidPasswordRuleConf(
++                    "mustEndWithAlpha and mustntEndWithAlpha are both true");
++        }
++        if (defaultPasswordRuleConf.isMustEndWithAlpha() && defaultPasswordRuleConf.isMustEndWithDigit()) {
++            throw new InvalidPasswordRuleConf(
++                    "mustEndWithAlpha and mustEndWithDigit are both true");
++        }
++        if (defaultPasswordRuleConf.isMustEndWithDigit() && defaultPasswordRuleConf.isMustntEndWithDigit()) {
++            throw new InvalidPasswordRuleConf(
++                    "mustEndWithDigit and mustntEndWithDigit are both true");
++        }
++        if (defaultPasswordRuleConf.isMustEndWithNonAlpha() && defaultPasswordRuleConf.isMustntEndWithNonAlpha()) {
++            throw new InvalidPasswordRuleConf(
++                    "mustEndWithNonAlpha and mustntEndWithNonAlpha are both true");
++        }
++        if (defaultPasswordRuleConf.isMustStartWithAlpha() && defaultPasswordRuleConf.isMustntStartWithAlpha()) {
++            throw new InvalidPasswordRuleConf(
++                    "mustStartWithAlpha and mustntStartWithAlpha are both true");
++        }
++        if (defaultPasswordRuleConf.isMustStartWithAlpha() && defaultPasswordRuleConf.isMustStartWithDigit()) {
++            throw new InvalidPasswordRuleConf(
++                    "mustStartWithAlpha and mustStartWithDigit are both true");
++        }
++        if (defaultPasswordRuleConf.isMustStartWithDigit() && defaultPasswordRuleConf.isMustntStartWithDigit()) {
++            throw new InvalidPasswordRuleConf(
++                    "mustStartWithDigit and mustntStartWithDigit are both true");
++        }
++        if (defaultPasswordRuleConf.isMustStartWithNonAlpha() && defaultPasswordRuleConf.isMustntStartWithNonAlpha()) {
++            throw new InvalidPasswordRuleConf(
++                    "mustStartWithNonAlpha and mustntStartWithNonAlpha are both true");
++        }
++        if (defaultPasswordRuleConf.getMinLength() > defaultPasswordRuleConf.getMaxLength()) {
++            throw new InvalidPasswordRuleConf(
++                    "Minimun length (" + defaultPasswordRuleConf.getMinLength() + ")"
++                    + "is greater than maximum length (" + defaultPasswordRuleConf.getMaxLength() + ")");
++        }
++    }
++
++    private String generate(final DefaultPasswordRuleConf ruleConf) {
++        String[] generatedPassword = new String[ruleConf.getMinLength()];
++
++        for (int i = 0; i < generatedPassword.length; i++) {
++            generatedPassword[i] = StringUtils.EMPTY;
++        }
++
++        checkStartChar(generatedPassword, ruleConf);
++
++        checkEndChar(generatedPassword, ruleConf);
++
++        checkRequired(generatedPassword, ruleConf);
++
++        for (int firstEmptyChar = firstEmptyChar(generatedPassword);
++                firstEmptyChar < generatedPassword.length - 1; firstEmptyChar++) {
++
++            generatedPassword[firstEmptyChar] = SecureRandomUtils.generateRandomLetter();
++        }
++
++        checkPrefixAndSuffix(generatedPassword, ruleConf);
++
++        return StringUtils.join(generatedPassword);
++    }
++
++    private void checkStartChar(final String[] generatedPassword, final DefaultPasswordRuleConf ruleConf) {
++        if (ruleConf.isMustStartWithAlpha()) {
++            generatedPassword[0] = SecureRandomUtils.generateRandomLetter();
++        }
++        if (ruleConf.isMustStartWithNonAlpha() || ruleConf.isMustStartWithDigit()) {
++            generatedPassword[0] = SecureRandomUtils.generateRandomNumber();
++        }
++        if (ruleConf.isMustntStartWithAlpha()) {
++            generatedPassword[0] = SecureRandomUtils.generateRandomNumber();
++        }
++        if (ruleConf.isMustntStartWithDigit()) {
++            generatedPassword[0] = SecureRandomUtils.generateRandomLetter();
++        }
++        if (ruleConf.isMustntStartWithNonAlpha()) {
++            generatedPassword[0] = SecureRandomUtils.generateRandomLetter();
++        }
++
++        if (StringUtils.EMPTY.equals(generatedPassword[0])) {
++            generatedPassword[0] = SecureRandomUtils.generateRandomLetter();
++        }
++    }
++
++    private void checkEndChar(final String[] generatedPassword, final DefaultPasswordRuleConf ruleConf) {
++        if (ruleConf.isMustEndWithAlpha()) {
++            generatedPassword[ruleConf.getMinLength() - 1] = SecureRandomUtils.generateRandomLetter();
++        }
++        if (ruleConf.isMustEndWithNonAlpha() || ruleConf.isMustEndWithDigit()) {
++            generatedPassword[ruleConf.getMinLength() - 1] = SecureRandomUtils.generateRandomNumber();
++        }
++
++        if (ruleConf.isMustntEndWithAlpha()) {
++            generatedPassword[ruleConf.getMinLength() - 1] = SecureRandomUtils.generateRandomNumber();
++        }
++        if (ruleConf.isMustntEndWithDigit()) {
++            generatedPassword[ruleConf.getMinLength() - 1] = SecureRandomUtils.generateRandomLetter();
++        }
++        if (ruleConf.isMustntEndWithNonAlpha()) {
++            generatedPassword[ruleConf.getMinLength() - 1] = SecureRandomUtils.generateRandomLetter();
++        }
++
++        if (StringUtils.EMPTY.equals(generatedPassword[ruleConf.getMinLength() - 1])) {
++            generatedPassword[ruleConf.getMinLength() - 1] = SecureRandomUtils.generateRandomLetter();
++        }
++    }
++
++    private int firstEmptyChar(final String[] generatedPStrings) {
++        int index = 0;
++        while (!generatedPStrings[index].isEmpty()) {
++            index++;
++        }
++        return index;
++    }
++
++    private void checkRequired(final String[] generatedPassword, final DefaultPasswordRuleConf ruleConf) {
++        if (ruleConf.isDigitRequired()
++                && !PolicyPattern.DIGIT.matcher(StringUtils.join(generatedPassword)).matches()) {
++
++            generatedPassword[firstEmptyChar(generatedPassword)] = SecureRandomUtils.generateRandomNumber();
++        }
++
++        if (ruleConf.isUppercaseRequired()
++                && !PolicyPattern.ALPHA_UPPERCASE.matcher(StringUtils.join(generatedPassword)).matches()) {
++
++            generatedPassword[firstEmptyChar(generatedPassword)] =
++                    SecureRandomUtils.generateRandomLetter().toUpperCase();
++        }
++
++        if (ruleConf.isLowercaseRequired()
++                && !PolicyPattern.ALPHA_LOWERCASE.matcher(StringUtils.join(generatedPassword)).matches()) {
++
++            generatedPassword[firstEmptyChar(generatedPassword)] =
++                    SecureRandomUtils.generateRandomLetter().toLowerCase();
++        }
++
++        if (ruleConf.isNonAlphanumericRequired()
++                && !PolicyPattern.NON_ALPHANUMERIC.matcher(StringUtils.join(generatedPassword)).matches()) {
++
++            generatedPassword[firstEmptyChar(generatedPassword)] =
++                    SecureRandomUtils.generateRandomSpecialCharacter(SPECIAL_CHARS);
++        }
++    }
++
++    private void checkPrefixAndSuffix(final String[] generatedPassword, final DefaultPasswordRuleConf ruleConf) {
++        for (String prefix : ruleConf.getPrefixesNotPermitted()) {
++            if (StringUtils.join(generatedPassword).startsWith(prefix)) {
++                checkStartChar(generatedPassword, ruleConf);
++            }
++        }
++
++        for (String suffix : ruleConf.getSuffixesNotPermitted()) {
++            if (StringUtils.join(generatedPassword).endsWith(suffix)) {
++                checkEndChar(generatedPassword, ruleConf);
++            }
++        }
++    }
++
++}

http://git-wip-us.apache.org/repos/asf/syncope/blob/77f697b2/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AccountRule.java
----------------------------------------------------------------------
diff --cc core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AccountRule.java
index 0000000,0000000..25e9e86
new file mode 100644
--- /dev/null
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AccountRule.java
@@@ -1,0 -1,0 +1,27 @@@
++/*
++ * 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.persistence.api.dao;
++
++import org.apache.syncope.common.lib.policy.AccountRuleConf;
++
++public interface AccountRule extends PolicyRule {
++
++    void setConf(AccountRuleConf conf);
++
++}

http://git-wip-us.apache.org/repos/asf/syncope/blob/77f697b2/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AccountRuleConfClass.java
----------------------------------------------------------------------
diff --cc core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AccountRuleConfClass.java
index 0000000,0000000..5b6bace
new file mode 100644
--- /dev/null
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/AccountRuleConfClass.java
@@@ -1,0 -1,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.persistence.api.dao;
++
++import java.lang.annotation.ElementType;
++import java.lang.annotation.Retention;
++import java.lang.annotation.RetentionPolicy;
++import java.lang.annotation.Target;
++import org.apache.syncope.common.lib.policy.AccountRuleConf;
++
++@Target({ ElementType.TYPE })
++@Retention(RetentionPolicy.RUNTIME)
++public @interface AccountRuleConfClass {
++
++    Class<? extends AccountRuleConf> value();
++}

http://git-wip-us.apache.org/repos/asf/syncope/blob/77f697b2/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/PasswordRule.java
----------------------------------------------------------------------
diff --cc core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/PasswordRule.java
index 0000000,0000000..4f92092
new file mode 100644
--- /dev/null
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/PasswordRule.java
@@@ -1,0 -1,0 +1,27 @@@
++/*
++ * 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.persistence.api.dao;
++
++import org.apache.syncope.common.lib.policy.PasswordRuleConf;
++
++public interface PasswordRule extends PolicyRule {
++
++    void setConf(PasswordRuleConf conf);
++
++}

http://git-wip-us.apache.org/repos/asf/syncope/blob/77f697b2/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/PasswordRuleConfClass.java
----------------------------------------------------------------------
diff --cc core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/PasswordRuleConfClass.java
index 0000000,0000000..745e336
new file mode 100644
--- /dev/null
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/dao/PasswordRuleConfClass.java
@@@ -1,0 -1,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.persistence.api.dao;
++
++import java.lang.annotation.ElementType;
++import java.lang.annotation.Retention;
++import java.lang.annotation.RetentionPolicy;
++import java.lang.annotation.Target;
++import org.apache.syncope.common.lib.policy.PasswordRuleConf;
++
++@Target({ ElementType.TYPE })
++@Retention(RetentionPolicy.RUNTIME)
++public @interface PasswordRuleConfClass {
++
++    Class<? extends PasswordRuleConf> value();
++}

http://git-wip-us.apache.org/repos/asf/syncope/blob/77f697b2/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/policy/AccountPolicy.java
----------------------------------------------------------------------
diff --cc core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/policy/AccountPolicy.java
index 0000000,0000000..f9a8277
new file mode 100644
--- /dev/null
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/policy/AccountPolicy.java
@@@ -1,0 -1,0 +1,50 @@@
++/*
++ * 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.persistence.api.entity.policy;
++
++import java.util.List;
++import java.util.Set;
++import org.apache.syncope.common.lib.policy.AccountRuleConf;
++import org.apache.syncope.core.persistence.api.entity.Policy;
++import org.apache.syncope.core.persistence.api.entity.resource.ExternalResource;
++
++public interface AccountPolicy extends Policy {
++
++    boolean isPropagateSuspension();
++
++    void setPropagateSuspension(boolean propagateSuspension);
++
++    int getMaxAuthenticationAttempts();
++
++    void setMaxAuthenticationAttempts(int maxAuthenticationAttempts);
++
++    boolean add(AccountRuleConf accountRuleConf);
++
++    boolean remove(AccountRuleConf accountRuleConf);
++
++    List<AccountRuleConf> getRuleConfs();
++
++    boolean add(ExternalResource resource);
++
++    boolean remove(ExternalResource resource);
++
++    Set<String> getResourceNames();
++
++    Set<? extends ExternalResource> getResources();
++}

http://git-wip-us.apache.org/repos/asf/syncope/blob/77f697b2/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/policy/PasswordPolicy.java
----------------------------------------------------------------------
diff --cc core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/policy/PasswordPolicy.java
index 0000000,0000000..173608e
new file mode 100644
--- /dev/null
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/policy/PasswordPolicy.java
@@@ -1,0 -1,0 +1,40 @@@
++/*
++ * 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.persistence.api.entity.policy;
++
++import java.util.List;
++import org.apache.syncope.common.lib.policy.PasswordRuleConf;
++import org.apache.syncope.core.persistence.api.entity.Policy;
++
++public interface PasswordPolicy extends Policy {
++
++    boolean isAllowNullPassword();
++
++    void setAllowNullPassword(final boolean allowNullPassword);
++
++    int getHistoryLength();
++
++    void setHistoryLength(int historyLength);
++
++    boolean add(PasswordRuleConf passwordRuleConf);
++
++    boolean remove(PasswordRuleConf passwordRuleConf);
++
++    List<PasswordRuleConf> getRuleConfs();
++}

http://git-wip-us.apache.org/repos/asf/syncope/blob/77f697b2/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/policy/PushPolicy.java
----------------------------------------------------------------------
diff --cc core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/policy/PushPolicy.java
index 0000000,0000000..4365e72
new file mode 100644
--- /dev/null
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/policy/PushPolicy.java
@@@ -1,0 -1,0 +1,29 @@@
++/*
++ * 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.persistence.api.entity.policy;
++
++import org.apache.syncope.common.lib.policy.PushPolicySpec;
++import org.apache.syncope.core.persistence.api.entity.Policy;
++
++public interface PushPolicy extends Policy {
++
++    PushPolicySpec getSpecification();
++
++    void setSpecification(PushPolicySpec spec);
++}

http://git-wip-us.apache.org/repos/asf/syncope/blob/77f697b2/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/policy/SyncPolicy.java
----------------------------------------------------------------------
diff --cc core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/policy/SyncPolicy.java
index 0000000,0000000..78a9882
new file mode 100644
--- /dev/null
+++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/policy/SyncPolicy.java
@@@ -1,0 -1,0 +1,30 @@@
++/*
++ * 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.persistence.api.entity.policy;
++
++import org.apache.syncope.common.lib.policy.SyncPolicySpec;
++import org.apache.syncope.core.persistence.api.entity.Policy;
++
++public interface SyncPolicy extends Policy {
++
++    SyncPolicySpec getSpecification();
++
++    void setSpecification(SyncPolicySpec spec);
++
++}

http://git-wip-us.apache.org/repos/asf/syncope/blob/77f697b2/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/DefaultAccountRule.java
----------------------------------------------------------------------
diff --cc core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/DefaultAccountRule.java
index 0000000,0000000..7ef2ebf
new file mode 100644
--- /dev/null
+++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/dao/DefaultAccountRule.java
@@@ -1,0 -1,0 +1,112 @@@
++/*
++ * 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.persistence.jpa.dao;
++
++import java.util.List;
++import java.util.regex.Pattern;
++import org.apache.syncope.common.lib.policy.AccountRuleConf;
++import org.apache.syncope.common.lib.policy.DefaultAccountRuleConf;
++import org.apache.syncope.core.misc.policy.AccountPolicyException;
++import org.apache.syncope.core.persistence.api.dao.AccountRule;
++import org.apache.syncope.core.persistence.api.dao.AccountRuleConfClass;
++import org.apache.syncope.core.persistence.api.entity.PlainAttr;
++import org.apache.syncope.core.persistence.api.entity.user.User;
++import org.springframework.transaction.annotation.Transactional;
++
++@AccountRuleConfClass(DefaultAccountRuleConf.class)
++public class DefaultAccountRule implements AccountRule {
++
++    private static final Pattern DEFAULT_PATTERN = Pattern.compile("[a-zA-Z0-9-_@. ]+");
++
++    private DefaultAccountRuleConf conf;
++
++    @Override
++    public void setConf(final AccountRuleConf conf) {
++        if (conf instanceof DefaultAccountRuleConf) {
++            this.conf = (DefaultAccountRuleConf) conf;
++        } else {
++            throw new IllegalArgumentException(
++                    AccountRuleConf.class.getName() + " expected, got " + conf.getClass().getName());
++        }
++    }
++
++    @Transactional(readOnly = true)
++    @Override
++    public void isCompliant(final User user) {
++        for (String schema : conf.getSchemasNotPermitted()) {
++            PlainAttr<?> attr = user.getPlainAttr(schema);
++            if (attr != null) {
++                List<String> values = attr.getValuesAsStrings();
++                if (values != null && !values.isEmpty()) {
++                    conf.getWordsNotPermitted().add(values.get(0));
++                }
++            }
++        }
++
++        if (user.getUsername() == null) {
++            throw new AccountPolicyException("Invalid account");
++        }
++
++        // check min length
++        if (conf.getMinLength() > 0 && conf.getMinLength() > user.getUsername().length()) {
++            throw new AccountPolicyException("Username too short");
++        }
++
++        // check max length
++        if (conf.getMaxLength() > 0 && conf.getMaxLength() < user.getUsername().length()) {
++            throw new AccountPolicyException("Username too long");
++        }
++
++        // check words not permitted
++        for (String word : conf.getWordsNotPermitted()) {
++            if (user.getUsername().contains(word)) {
++                throw new AccountPolicyException("Used word(s) not permitted");
++            }
++        }
++
++        // check case
++        if (conf.isAllUpperCase() && !user.getUsername().equals(user.getUsername().toUpperCase())) {
++            throw new AccountPolicyException("No lowercase characters permitted");
++        }
++        if (conf.isAllLowerCase() && !user.getUsername().equals(user.getUsername().toLowerCase())) {
++            throw new AccountPolicyException("No uppercase characters permitted");
++        }
++
++        // check pattern
++        Pattern pattern = (conf.getPattern() == null) ? DEFAULT_PATTERN : Pattern.compile(conf.getPattern());
++        if (!pattern.matcher(user.getUsername()).matches()) {
++            throw new AccountPolicyException("Username does not match pattern");
++        }
++
++        // check prefix
++        for (String prefix : conf.getPrefixesNotPermitted()) {
++            if (user.getUsername().startsWith(prefix)) {
++                throw new AccountPolicyException("Prefix not permitted");
++            }
++        }
++
++        // check suffix
++        for (String suffix : conf.getSuffixesNotPermitted()) {
++            if (user.getUsername().endsWith(suffix)) {
++                throw new AccountPolicyException("Suffix not permitted");
++            }
++        }
++    }
++
++}