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");
++ }
++ }
++ }
++
++}