http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAUser.java ---------------------------------------------------------------------- diff --git a/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAUser.java b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAUser.java new file mode 100644 index 0000000..6820c73 --- /dev/null +++ b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/user/JPAUser.java @@ -0,0 +1,538 @@ +/* + * 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.entity.user; + +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import javax.persistence.Basic; +import javax.persistence.Cacheable; +import javax.persistence.CascadeType; +import javax.persistence.CollectionTable; +import javax.persistence.Column; +import javax.persistence.ElementCollection; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.FetchType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.JoinTable; +import javax.persistence.Lob; +import javax.persistence.ManyToMany; +import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; +import javax.persistence.Table; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; +import javax.persistence.Transient; +import javax.validation.Valid; +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; +import org.apache.syncope.common.lib.types.CipherAlgorithm; +import org.apache.syncope.core.persistence.api.entity.ExternalResource; +import org.apache.syncope.core.persistence.api.entity.membership.Membership; +import org.apache.syncope.core.persistence.api.entity.role.Role; +import org.apache.syncope.core.persistence.api.entity.user.SecurityQuestion; +import org.apache.syncope.core.persistence.api.entity.user.UDerAttr; +import org.apache.syncope.core.persistence.api.entity.user.UPlainAttr; +import org.apache.syncope.core.persistence.api.entity.user.UVirAttr; +import org.apache.syncope.core.persistence.api.entity.user.User; +import org.apache.syncope.core.persistence.jpa.validation.entity.UserCheck; +import org.apache.syncope.core.persistence.jpa.entity.AbstractSubject; +import org.apache.syncope.core.persistence.jpa.entity.JPAExternalResource; +import org.apache.syncope.core.persistence.jpa.entity.JPASecurityQuestion; +import org.apache.syncope.core.persistence.jpa.entity.membership.JPAMembership; +import org.apache.syncope.core.misc.security.Encryptor; +import org.apache.syncope.core.misc.security.SecureRandomUtil; + +/** + * JPA user bean. + */ +@Entity +@Table(name = JPAUser.TABLE) +@Cacheable +@UserCheck +public class JPAUser extends AbstractSubject<UPlainAttr, UDerAttr, UVirAttr> implements User { + + private static final long serialVersionUID = -3905046855521446823L; + + public static final String TABLE = "SyncopeUser"; + + @Id + private Long id; + + @Column(nullable = true) + private String password; + + @Transient + private String clearPassword; + + @OneToMany(cascade = CascadeType.MERGE, mappedBy = "user") + @Valid + private List<JPAMembership> memberships; + + @OneToMany(cascade = CascadeType.ALL, mappedBy = "owner") + @Valid + private List<JPAUPlainAttr> plainAttrs; + + @OneToMany(cascade = CascadeType.ALL, mappedBy = "owner") + @Valid + private List<JPAUDerAttr> derAttrs; + + @OneToMany(cascade = CascadeType.ALL, mappedBy = "owner") + @Valid + private List<JPAUVirAttr> virAttrs; + + private String workflowId; + + @Column(nullable = true) + private String status; + + @Lob + private String token; + + @Temporal(TemporalType.TIMESTAMP) + private Date tokenExpireTime; + + @Column(nullable = true) + @Enumerated(EnumType.STRING) + private CipherAlgorithm cipherAlgorithm; + + @ElementCollection + @Column(name = "passwordHistoryValue") + @CollectionTable(name = "SyncopeUser_passwordHistory", + joinColumns = + @JoinColumn(name = "SyncopeUser_id", referencedColumnName = "id")) + private List<String> passwordHistory; + + /** + * Subsequent failed logins. + */ + @Column(nullable = true) + private Integer failedLogins; + + /** + * Username/Login. + */ + @Column(unique = true) + @NotNull(message = "Blank username") + private String username; + + /** + * Last successful login date. + */ + @Column(nullable = true) + @Temporal(TemporalType.TIMESTAMP) + private Date lastLoginDate; + + /** + * Change password date. + */ + @Column(nullable = true) + @Temporal(TemporalType.TIMESTAMP) + private Date changePwdDate; + + @Basic + @Min(0) + @Max(1) + private Integer suspended; + + /** + * Provisioning external resources. + */ + @ManyToMany(fetch = FetchType.EAGER) + @JoinTable(joinColumns = + @JoinColumn(name = "user_id"), + inverseJoinColumns = + @JoinColumn(name = "resource_name")) + @Valid + private Set<JPAExternalResource> resources; + + @ManyToOne(fetch = FetchType.EAGER, optional = true) + private JPASecurityQuestion securityQuestion; + + @Column(nullable = true) + private String securityAnswer; + + public JPAUser() { + super(); + + memberships = new ArrayList<>(); + plainAttrs = new ArrayList<>(); + derAttrs = new ArrayList<>(); + virAttrs = new ArrayList<>(); + passwordHistory = new ArrayList<>(); + failedLogins = 0; + suspended = getBooleanAsInteger(Boolean.FALSE); + resources = new HashSet<>(); + } + + @Override + public Long getKey() { + return id; + } + + @Override + protected Set<? extends ExternalResource> internalGetResources() { + return resources; + } + + @Override + public boolean addMembership(final Membership membership) { + checkType(membership, JPAMembership.class); + return memberships.contains((JPAMembership) membership) || memberships.add((JPAMembership) membership); + } + + @Override + public boolean removeMembership(final Membership membership) { + return memberships.remove(membership); + } + + @Override + public Membership getMembership(final Long roleKey) { + Membership result = null; + Membership membership; + for (Iterator<? extends Membership> itor = getMemberships().iterator(); result == null && itor.hasNext();) { + membership = itor.next(); + if (membership.getRole() != null && roleKey.equals(membership.getRole().getKey())) { + result = membership; + } + } + return result; + } + + @Override + public List<? extends Membership> getMemberships() { + return memberships; + } + + @Override + public List<Role> getRoles() { + List<Role> result = new ArrayList<>(); + + for (Membership membership : memberships) { + if (membership.getRole() != null) { + result.add(membership.getRole()); + } + } + + return result; + } + + @Override + public Set<Long> getRoleKeys() { + List<Role> roles = getRoles(); + + Set<Long> result = new HashSet<>(roles.size()); + for (Role role : roles) { + result.add(role.getKey()); + } + + return result; + } + + @Override + public Set<ExternalResource> getResources() { + Set<ExternalResource> result = new HashSet<>(); + result.addAll(super.getResources()); + for (Role role : getRoles()) { + result.addAll(role.getResources()); + } + + return result; + } + + @Override + public Set<? extends ExternalResource> getOwnResources() { + return super.getResources(); + } + + @Override + public String getPassword() { + return password; + } + + @Override + public String getClearPassword() { + return clearPassword; + } + + @Override + public void removeClearPassword() { + clearPassword = null; + } + + @Override + public void setEncodedPassword(final String password, final CipherAlgorithm cipherAlgoritm) { + // clear password + this.clearPassword = null; + + this.password = password; + this.cipherAlgorithm = cipherAlgoritm; + } + + @Override + public void setPassword(final String password, final CipherAlgorithm cipherAlgoritm) { + // clear password + this.clearPassword = password; + + try { + this.password = Encryptor.getInstance().encode(password, cipherAlgoritm); + this.cipherAlgorithm = cipherAlgoritm; + } catch (Exception e) { + LOG.error("Could not encode password", e); + this.password = null; + } + } + + @Override + public CipherAlgorithm getCipherAlgorithm() { + return cipherAlgorithm; + } + + @Override + public boolean canDecodePassword() { + return this.cipherAlgorithm != null && this.cipherAlgorithm.isInvertible(); + } + + @Override + public boolean addPlainAttr(final UPlainAttr attr) { + checkType(attr, JPAUPlainAttr.class); + return plainAttrs.add((JPAUPlainAttr) attr); + } + + @Override + public boolean removePlainAttr(final UPlainAttr attr) { + checkType(attr, JPAUPlainAttr.class); + return plainAttrs.remove((JPAUPlainAttr) attr); + } + + @Override + public List<? extends UPlainAttr> getPlainAttrs() { + return plainAttrs; + } + + @Override + public boolean addDerAttr(final UDerAttr attr) { + checkType(attr, JPAUDerAttr.class); + return derAttrs.add((JPAUDerAttr) attr); + } + + @Override + public boolean removeDerAttr(final UDerAttr attr) { + checkType(attr, JPAUDerAttr.class); + return derAttrs.remove((JPAUDerAttr) attr); + } + + @Override + public List<? extends UDerAttr> getDerAttrs() { + return derAttrs; + } + + @Override + public boolean addVirAttr(final UVirAttr attr) { + checkType(attr, JPAUVirAttr.class); + return virAttrs.add((JPAUVirAttr) attr); + } + + @Override + public boolean removeVirAttr(final UVirAttr attr) { + checkType(attr, JPAUVirAttr.class); + return virAttrs.remove((JPAUVirAttr) attr); + } + + @Override + public List<? extends UVirAttr> getVirAttrs() { + return virAttrs; + } + + @Override + public String getWorkflowId() { + return workflowId; + } + + @Override + public void setWorkflowId(final String workflowId) { + this.workflowId = workflowId; + } + + @Override + public String getStatus() { + return status; + } + + @Override + public void setStatus(final String status) { + this.status = status; + } + + @Override + public void generateToken(final int tokenLength, final int tokenExpireTime) { + this.token = SecureRandomUtil.generateRandomPassword(tokenLength); + + Calendar calendar = Calendar.getInstance(); + calendar.add(Calendar.MINUTE, tokenExpireTime); + this.tokenExpireTime = calendar.getTime(); + } + + @Override + public void removeToken() { + this.token = null; + this.tokenExpireTime = null; + } + + @Override + public String getToken() { + return token; + } + + @Override + public Date getTokenExpireTime() { + return tokenExpireTime == null + ? null + : new Date(tokenExpireTime.getTime()); + } + + @Override + public boolean checkToken(final String token) { + return this.token == null || this.token.equals(token) && !hasTokenExpired(); + } + + @Override + public boolean hasTokenExpired() { + return tokenExpireTime == null + ? false + : tokenExpireTime.before(new Date()); + } + + @Override + public void setCipherAlgorithm(final CipherAlgorithm cipherAlgorithm) { + this.cipherAlgorithm = cipherAlgorithm; + } + + @Override + public List<String> getPasswordHistory() { + return passwordHistory; + } + + @Override + public Date getChangePwdDate() { + return changePwdDate == null + ? null + : new Date(changePwdDate.getTime()); + } + + @Override + public void setChangePwdDate(final Date changePwdDate) { + this.changePwdDate = changePwdDate == null + ? null + : new Date(changePwdDate.getTime()); + } + + @Override + public Integer getFailedLogins() { + return failedLogins == null ? 0 : failedLogins; + } + + @Override + public void setFailedLogins(final Integer failedLogins) { + this.failedLogins = failedLogins; + } + + @Override + public Date getLastLoginDate() { + return lastLoginDate == null + ? null + : new Date(lastLoginDate.getTime()); + } + + @Override + public void setLastLoginDate(final Date lastLoginDate) { + this.lastLoginDate = lastLoginDate == null + ? null + : new Date(lastLoginDate.getTime()); + } + + @Override + public String getUsername() { + return username; + } + + @Override + public void setUsername(final String username) { + this.username = username; + } + + @Override + public void setSuspended(final Boolean suspended) { + this.suspended = getBooleanAsInteger(suspended); + } + + @Override + public Boolean isSuspended() { + return suspended == null ? null : isBooleanAsInteger(suspended); + } + + @Override + public boolean verifyPasswordHistory(final String password, final int size) { + boolean res = false; + + if (size > 0) { + try { + res = passwordHistory.subList(size >= passwordHistory.size() + ? 0 + : passwordHistory.size() - size, passwordHistory.size()).contains(cipherAlgorithm == null + ? password + : Encryptor.getInstance().encode(password, cipherAlgorithm)); + } catch (Exception e) { + LOG.error("Error evaluating password history", e); + } + } + + return res; + } + + @Override + public SecurityQuestion getSecurityQuestion() { + return securityQuestion; + } + + @Override + public void setSecurityQuestion(final SecurityQuestion securityQuestion) { + checkType(securityQuestion, JPASecurityQuestion.class); + this.securityQuestion = (JPASecurityQuestion) securityQuestion; + } + + @Override + public String getSecurityAnswer() { + return securityAnswer; + } + + @Override + public void setSecurityAnswer(final String securityAnswer) { + this.securityAnswer = securityAnswer; + } + +}
http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/spring/MultiJarAwarePersistenceUnitPostProcessor.java ---------------------------------------------------------------------- diff --git a/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/spring/MultiJarAwarePersistenceUnitPostProcessor.java b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/spring/MultiJarAwarePersistenceUnitPostProcessor.java new file mode 100644 index 0000000..b4a598f --- /dev/null +++ b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/spring/MultiJarAwarePersistenceUnitPostProcessor.java @@ -0,0 +1,49 @@ +/* + * 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.spring; + +import javax.persistence.Entity; +import org.apache.syncope.core.persistence.jpa.entity.AbstractEntity; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; +import org.springframework.core.type.filter.AnnotationTypeFilter; +import org.springframework.orm.jpa.persistenceunit.MutablePersistenceUnitInfo; +import org.springframework.orm.jpa.persistenceunit.PersistenceUnitPostProcessor; + +/** + * Allows having JPA entities spread in several JAR files; this is needed in order to support the Syncope extensions. + */ +public class MultiJarAwarePersistenceUnitPostProcessor implements PersistenceUnitPostProcessor { + + private static final Logger LOG = LoggerFactory.getLogger(MultiJarAwarePersistenceUnitPostProcessor.class); + + @Override + public void postProcessPersistenceUnitInfo(final MutablePersistenceUnitInfo pui) { + ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false); + scanner.addIncludeFilter(new AnnotationTypeFilter(Entity.class)); + + for (BeanDefinition bd : scanner.findCandidateComponents(AbstractEntity.class.getPackage().getName())) { + LOG.debug("Adding JPA entity {}", bd.getBeanClassName()); + pui.addManagedClassName(bd.getBeanClassName()); + } + } + +} http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/AbstractValidator.java ---------------------------------------------------------------------- diff --git a/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/AbstractValidator.java b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/AbstractValidator.java new file mode 100644 index 0000000..4308de6 --- /dev/null +++ b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/AbstractValidator.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.syncope.core.persistence.jpa.validation.entity; + +import java.lang.annotation.Annotation; +import java.util.regex.Pattern; +import javax.validation.ConstraintValidator; +import org.apache.syncope.common.lib.types.EntityViolationType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public abstract class AbstractValidator<A extends Annotation, T> implements ConstraintValidator<A, T> { + + /** + * Logger. + */ + protected static final Logger LOG = LoggerFactory.getLogger(AbstractValidator.class); + + protected static final Pattern NAME_PATTERN = + Pattern.compile("^[\\w \\-@.]+", Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE); + + @Override + public void initialize(final A annotation) { + // no initialization + } + + protected final String getTemplate(final EntityViolationType type, final String message) { + return type.name() + ";" + message; + } +} http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/ConnInstanceCheck.java ---------------------------------------------------------------------- diff --git a/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/ConnInstanceCheck.java b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/ConnInstanceCheck.java new file mode 100644 index 0000000..b80ee19 --- /dev/null +++ b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/ConnInstanceCheck.java @@ -0,0 +1,41 @@ +/* + * 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.validation.entity; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import javax.validation.Constraint; +import javax.validation.Payload; + +@Target({ ElementType.TYPE }) +@Retention(RetentionPolicy.RUNTIME) +@Constraint(validatedBy = ConnInstanceValidator.class) +@Documented +public @interface ConnInstanceCheck { + + String message() default "{org.apache.syncope.core.persistence.validation.connninstance}"; + + Class<?>[] groups() default {}; + + Class<? extends Payload>[] payload() default {}; +} http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/ConnInstanceValidator.java ---------------------------------------------------------------------- diff --git a/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/ConnInstanceValidator.java b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/ConnInstanceValidator.java new file mode 100644 index 0000000..d99c5ae --- /dev/null +++ b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/ConnInstanceValidator.java @@ -0,0 +1,64 @@ +/* + * 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.validation.entity; + +import javax.validation.ConstraintValidatorContext; +import org.apache.syncope.common.lib.types.EntityViolationType; +import org.apache.syncope.core.persistence.api.entity.ConnInstance; +import org.apache.syncope.core.persistence.jpa.entity.JPAConnPoolConf; +import org.apache.syncope.core.provisioning.api.URIUtil; +import org.apache.syncope.core.provisioning.api.ConnPoolConfUtil; + +public class ConnInstanceValidator extends AbstractValidator<ConnInstanceCheck, ConnInstance> { + + @Override + public boolean isValid(final ConnInstance connInstance, final ConstraintValidatorContext context) { + boolean isValid = true; + + try { + URIUtil.buildForConnId(connInstance.getLocation()); + } catch (Exception e) { + LOG.error("While validating {}", connInstance.getLocation(), e); + + context.disableDefaultConstraintViolation(); + context.buildConstraintViolationWithTemplate( + getTemplate(EntityViolationType.InvalidConnInstanceLocation, e.getMessage())). + addPropertyNode("location").addConstraintViolation(); + + isValid = false; + } + + if (isValid && connInstance.getPoolConf() != null) { + try { + ConnPoolConfUtil.getObjectPoolConfiguration(connInstance.getPoolConf()).validate(); + } catch (Exception e) { + LOG.error("Invalid pool configuration", e); + + context.disableDefaultConstraintViolation(); + context.buildConstraintViolationWithTemplate( + getTemplate(EntityViolationType.InvalidConnPoolConf, e.getMessage())). + addPropertyNode("poolConf").addConstraintViolation(); + + isValid = false; + } + } + + return isValid; + } +} http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/EntityValidationListener.java ---------------------------------------------------------------------- diff --git a/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/EntityValidationListener.java b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/EntityValidationListener.java new file mode 100644 index 0000000..a22359e --- /dev/null +++ b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/EntityValidationListener.java @@ -0,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.core.persistence.jpa.validation.entity; + +import java.util.Set; +import javax.persistence.PrePersist; +import javax.persistence.PreUpdate; +import javax.validation.ConstraintViolation; +import javax.validation.Validator; +import org.apache.commons.lang3.ClassUtils; +import org.apache.syncope.core.persistence.api.attrvalue.validation.InvalidEntityException; +import org.apache.syncope.core.misc.spring.ApplicationContextProvider; +import org.apache.syncope.core.persistence.api.entity.AnnotatedEntity; +import org.apache.syncope.core.persistence.api.entity.Attr; +import org.apache.syncope.core.persistence.api.entity.Attributable; +import org.apache.syncope.core.persistence.api.entity.Entity; +import org.apache.syncope.core.persistence.api.entity.Policy; +import org.apache.syncope.core.persistence.api.entity.Schema; +import org.apache.syncope.core.persistence.api.entity.Subject; +import org.apache.syncope.core.persistence.api.entity.task.Task; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * JPA validation listener implementing bean validation. + */ +public class EntityValidationListener { + + /** + * Logger. + */ + private static final Logger LOG = LoggerFactory.getLogger(EntityValidationListener.class); + + @PrePersist + @PreUpdate + public void validate(final Object object) { + final Validator validator = ApplicationContextProvider.getApplicationContext().getBean(Validator.class); + Set<ConstraintViolation<Object>> violations = validator.validate(object); + if (!violations.isEmpty()) { + LOG.warn("Bean validation errors found: {}", violations); + + Class<?> entityInt = null; + for (Class<?> interf : ClassUtils.getAllInterfaces(object.getClass())) { + if (!Entity.class.equals(interf) + && !AnnotatedEntity.class.equals(interf) + && !Schema.class.equals(interf) + && !Attr.class.equals(interf) + && !Task.class.equals(interf) + && !Policy.class.equals(interf) + && !Attributable.class.equals(interf) + && !Subject.class.equals(interf) + && Entity.class.isAssignableFrom(interf)) { + + entityInt = interf; + } + } + + throw new InvalidEntityException(entityInt == null ? "Entity" : entityInt.getSimpleName(), violations); + } + } +} http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/ExternalResourceCheck.java ---------------------------------------------------------------------- diff --git a/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/ExternalResourceCheck.java b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/ExternalResourceCheck.java new file mode 100644 index 0000000..0ffec4a --- /dev/null +++ b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/ExternalResourceCheck.java @@ -0,0 +1,41 @@ +/* + * 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.validation.entity; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import javax.validation.Constraint; +import javax.validation.Payload; + +@Target({ ElementType.TYPE }) +@Retention(RetentionPolicy.RUNTIME) +@Constraint(validatedBy = ExternalResourceValidator.class) +@Documented +public @interface ExternalResourceCheck { + + String message() default "{org.apache.syncope.core.persistence.validation.externalresource}"; + + Class<?>[] groups() default {}; + + Class<? extends Payload>[] payload() default {}; +} http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/ExternalResourceValidator.java ---------------------------------------------------------------------- diff --git a/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/ExternalResourceValidator.java b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/ExternalResourceValidator.java new file mode 100644 index 0000000..1d512bb --- /dev/null +++ b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/ExternalResourceValidator.java @@ -0,0 +1,130 @@ +/* + * 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.validation.entity; + +import javax.validation.ConstraintValidatorContext; +import org.apache.commons.lang3.StringUtils; +import org.apache.syncope.common.lib.types.EntityViolationType; +import org.apache.syncope.core.persistence.api.entity.ExternalResource; +import org.apache.syncope.core.persistence.api.entity.Mapping; +import org.apache.syncope.core.persistence.api.entity.MappingItem; +import org.apache.syncope.core.provisioning.api.propagation.PropagationActions; + +public class ExternalResourceValidator extends AbstractValidator<ExternalResourceCheck, ExternalResource> { + + private boolean isValid(final MappingItem item, final ConstraintValidatorContext context) { + if (StringUtils.isBlank(item.getExtAttrName())) { + context.buildConstraintViolationWithTemplate( + getTemplate(EntityViolationType.InvalidMapping, item + ".extAttrName is null")). + addPropertyNode("extAttrName").addConstraintViolation(); + + return false; + } + + if (StringUtils.isBlank(item.getIntAttrName())) { + context.buildConstraintViolationWithTemplate( + getTemplate(EntityViolationType.InvalidMapping, item + ".intAttrName is null")). + addPropertyNode("intAttrName").addConstraintViolation(); + + return false; + } + + if (item.getPurpose() == null) { + context.buildConstraintViolationWithTemplate( + getTemplate(EntityViolationType.InvalidMapping, item + ".purpose is null")). + addPropertyNode("purpose").addConstraintViolation(); + + return false; + } + + return true; + } + + private boolean isValid(final Mapping<?> mapping, final ConstraintValidatorContext context) { + if (mapping == null) { + return true; + } + + int accountIds = 0; + for (MappingItem item : mapping.getItems()) { + if (item.isAccountid()) { + accountIds++; + } + } + if (accountIds != 1) { + context.buildConstraintViolationWithTemplate( + getTemplate(EntityViolationType.InvalidMapping, "One and only one accountId mapping is needed")). + addPropertyNode("accountId.size").addConstraintViolation(); + return false; + } + + boolean isValid = true; + + int passwords = 0; + for (MappingItem item : mapping.getItems()) { + isValid &= isValid(item, context); + + if (item.isPassword()) { + passwords++; + } + } + if (passwords > 1) { + context.buildConstraintViolationWithTemplate( + getTemplate(EntityViolationType.InvalidMapping, "One and only one password mapping is allowed")). + addPropertyNode("password.size").addConstraintViolation(); + isValid = false; + } + + return isValid; + } + + @Override + public boolean isValid(final ExternalResource resource, final ConstraintValidatorContext context) { + context.disableDefaultConstraintViolation(); + + if (!NAME_PATTERN.matcher(resource.getKey()).matches()) { + context.buildConstraintViolationWithTemplate( + getTemplate(EntityViolationType.InvalidName, "Invalid Resource name")). + addPropertyNode("name").addConstraintViolation(); + return false; + } + + if (!resource.getPropagationActionsClassNames().isEmpty()) { + for (String className : resource.getPropagationActionsClassNames()) { + Class<?> actionsClass = null; + boolean isAssignable = false; + try { + actionsClass = Class.forName(className); + isAssignable = PropagationActions.class.isAssignableFrom(actionsClass); + } catch (Exception e) { + LOG.error("Invalid PropagationActions specified: {}", className, e); + } + + if (actionsClass == null || !isAssignable) { + context.buildConstraintViolationWithTemplate( + getTemplate(EntityViolationType.InvalidResource, "Invalid actions class name")). + addPropertyNode("actionsClassName").addConstraintViolation(); + return false; + } + } + } + + return isValid(resource.getUmapping(), context) && isValid(resource.getRmapping(), context); + } +} http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/NotificationCheck.java ---------------------------------------------------------------------- diff --git a/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/NotificationCheck.java b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/NotificationCheck.java new file mode 100644 index 0000000..be10d6b --- /dev/null +++ b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/NotificationCheck.java @@ -0,0 +1,41 @@ +/* + * 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.validation.entity; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import javax.validation.Constraint; +import javax.validation.Payload; + +@Target({ ElementType.TYPE }) +@Retention(RetentionPolicy.RUNTIME) +@Constraint(validatedBy = NotificationValidator.class) +@Documented +public @interface NotificationCheck { + + String message() default "{org.apache.syncope.core.persistence.validation.notification}"; + + Class<?>[] groups() default {}; + + Class<? extends Payload>[] payload() default {}; +} http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/NotificationValidator.java ---------------------------------------------------------------------- diff --git a/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/NotificationValidator.java b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/NotificationValidator.java new file mode 100644 index 0000000..6843a94 --- /dev/null +++ b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/NotificationValidator.java @@ -0,0 +1,59 @@ +/* + * 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.validation.entity; + +import java.util.regex.Matcher; +import javax.validation.ConstraintValidatorContext; +import org.apache.syncope.common.lib.SyncopeConstants; +import org.apache.syncope.common.lib.types.EntityViolationType; +import org.apache.syncope.core.persistence.api.entity.Notification; + +public class NotificationValidator extends AbstractValidator<NotificationCheck, Notification> { + + @Override + public boolean isValid(final Notification value, final ConstraintValidatorContext context) { + context.disableDefaultConstraintViolation(); + + boolean isValid = true; + + if (value.getEvents().isEmpty()) { + isValid = false; + + context.buildConstraintViolationWithTemplate( + getTemplate(EntityViolationType.InvalidNotification, "No events")). + addPropertyNode("events").addConstraintViolation(); + } + + if (!value.getStaticRecipients().isEmpty()) { + for (String mail : value.getStaticRecipients()) { + Matcher matcher = SyncopeConstants.EMAIL_PATTERN.matcher(mail); + if (!matcher.matches()) { + LOG.error("Invalid mail address: {}", mail); + isValid = false; + + context.buildConstraintViolationWithTemplate( + getTemplate(EntityViolationType.InvalidNotification, "Invalid mail address: " + mail)). + addPropertyNode("staticRecipients").addConstraintViolation(); + } + } + } + + return isValid; + } +} http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainAttrCheck.java ---------------------------------------------------------------------- diff --git a/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainAttrCheck.java b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainAttrCheck.java new file mode 100644 index 0000000..ed1bc5e --- /dev/null +++ b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainAttrCheck.java @@ -0,0 +1,41 @@ +/* + * 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.validation.entity; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import javax.validation.Constraint; +import javax.validation.Payload; + +@Target( { ElementType.TYPE }) +@Retention(RetentionPolicy.RUNTIME) +@Constraint(validatedBy = PlainAttrValidator.class) +@Documented +public @interface PlainAttrCheck { + + String message() default "{org.apache.syncope.syncope.validation.attr}"; + + Class<?>[] groups() default {}; + + Class<? extends Payload>[] payload() default {}; +} http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainAttrValidator.java ---------------------------------------------------------------------- diff --git a/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainAttrValidator.java b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainAttrValidator.java new file mode 100644 index 0000000..5dc7f55 --- /dev/null +++ b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainAttrValidator.java @@ -0,0 +1,59 @@ +/* + * 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.validation.entity; + +import javax.validation.ConstraintValidatorContext; +import org.apache.syncope.common.lib.types.EntityViolationType; +import org.apache.syncope.core.persistence.api.entity.PlainAttr; + +public class PlainAttrValidator extends AbstractValidator<PlainAttrCheck, PlainAttr> { + + @Override + public boolean isValid(final PlainAttr object, final ConstraintValidatorContext context) { + boolean isValid; + + if (object == null) { + isValid = true; + } else { + if (object.getSchema().isUniqueConstraint()) { + isValid = object.getValues().isEmpty() && object.getUniqueValue() != null; + } else { + isValid = !object.getValues().isEmpty() && object.getUniqueValue() == null; + + if (!object.getSchema().isMultivalue()) { + isValid &= object.getValues().size() == 1; + } + } + + if (!isValid) { + LOG.error("Invalid values for attribute " + object + ": " + "schema=" + object.getSchema().getKey() + + ", " + "values={}", object.getValuesAsStrings()); + + context.disableDefaultConstraintViolation(); + + context.buildConstraintViolationWithTemplate( + getTemplate(EntityViolationType.InvalidValueList, + "Invalid values " + object.getValuesAsStrings())). + addPropertyNode(object.getSchema().getKey()).addConstraintViolation(); + } + } + + return isValid; + } +} http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainAttrValueCheck.java ---------------------------------------------------------------------- diff --git a/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainAttrValueCheck.java b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainAttrValueCheck.java new file mode 100644 index 0000000..a8488e0 --- /dev/null +++ b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainAttrValueCheck.java @@ -0,0 +1,41 @@ +/* + * 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.validation.entity; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import javax.validation.Constraint; +import javax.validation.Payload; + +@Target({ ElementType.TYPE }) +@Retention(RetentionPolicy.RUNTIME) +@Constraint(validatedBy = PlainAttrValueValidator.class) +@Documented +public @interface PlainAttrValueCheck { + + String message() default "{org.apache.syncope.core.persistence.validation.attrvalue}"; + + Class<?>[] groups() default {}; + + Class<? extends Payload>[] payload() default {}; +} http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainAttrValueValidator.java ---------------------------------------------------------------------- diff --git a/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainAttrValueValidator.java b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainAttrValueValidator.java new file mode 100644 index 0000000..6069882 --- /dev/null +++ b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainAttrValueValidator.java @@ -0,0 +1,98 @@ +/* + * 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.validation.entity; + +import javax.validation.ConstraintValidatorContext; +import org.apache.syncope.common.lib.types.EntityViolationType; +import org.apache.syncope.core.persistence.api.entity.PlainAttrUniqueValue; +import org.apache.syncope.core.persistence.api.entity.PlainAttrValue; +import org.apache.syncope.core.persistence.api.entity.PlainSchema; +import org.apache.syncope.core.persistence.api.entity.membership.MPlainSchema; +import org.apache.syncope.core.persistence.api.entity.role.RPlainSchema; +import org.apache.syncope.core.persistence.api.entity.user.UPlainSchema; + +public class PlainAttrValueValidator extends AbstractValidator<PlainAttrValueCheck, PlainAttrValue> { + + @Override + public boolean isValid(final PlainAttrValue object, final ConstraintValidatorContext context) { + boolean isValid; + + if (object == null) { + isValid = true; + } else { + int nonNullVales = 0; + if (object.getBooleanValue() != null) { + nonNullVales++; + } + if (object.getDateValue() != null) { + nonNullVales++; + } + if (object.getDoubleValue() != null) { + nonNullVales++; + } + if (object.getLongValue() != null) { + nonNullVales++; + } + if (object.getBinaryValue() != null) { + nonNullVales++; + } + if (object.getStringValue() != null) { + nonNullVales++; + } + isValid = nonNullVales == 1; + + if (!isValid) { + LOG.error("More than one non-null value for " + object); + + context.disableDefaultConstraintViolation(); + context.buildConstraintViolationWithTemplate( + getTemplate(EntityViolationType.MoreThanOneNonNull, "More than one non-null value found")). + addPropertyNode(object.getClass().getSimpleName().replaceAll("\\n", " ")). + addConstraintViolation(); + + } else if (object instanceof PlainAttrUniqueValue) { + PlainSchema uniqueValueSchema = ((PlainAttrUniqueValue) object).getSchema(); + PlainSchema attrSchema = object.getAttr().getSchema(); + + isValid = uniqueValueSchema.equals(attrSchema); + + if (!isValid) { + LOG.error("Unique value schema for " + object.getClass().getSimpleName() + "[" + object.getKey() + + "]" + " is " + uniqueValueSchema + ", while owning attribute schema is " + attrSchema); + + EntityViolationType violationType = attrSchema instanceof UPlainSchema + ? EntityViolationType.InvalidUPlainSchema + : attrSchema instanceof RPlainSchema + ? EntityViolationType.InvalidRPlainSchema + : attrSchema instanceof MPlainSchema + ? EntityViolationType.InvalidMPlainSchema + : EntityViolationType.InvalidCPlainSchema; + + context.disableDefaultConstraintViolation(); + context.buildConstraintViolationWithTemplate(getTemplate(violationType, + "Unique value schema is " + uniqueValueSchema + + ", while owning attribute schema is " + attrSchema)).addPropertyNode("schema"). + addConstraintViolation(); + } + } + } + + return isValid; + } +} http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainSchemaCheck.java ---------------------------------------------------------------------- diff --git a/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainSchemaCheck.java b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainSchemaCheck.java new file mode 100644 index 0000000..d06cb63 --- /dev/null +++ b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainSchemaCheck.java @@ -0,0 +1,41 @@ +/* + * 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.validation.entity; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import javax.validation.Constraint; +import javax.validation.Payload; + +@Target({ ElementType.TYPE }) +@Retention(RetentionPolicy.RUNTIME) +@Constraint(validatedBy = PlainSchemaValidator.class) +@Documented +public @interface PlainSchemaCheck { + + String message() default "{org.apache.syncope.core.persistence.validation.schema}"; + + Class<?>[] groups() default {}; + + Class<? extends Payload>[] payload() default {}; +} http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainSchemaValidator.java ---------------------------------------------------------------------- diff --git a/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainSchemaValidator.java b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainSchemaValidator.java new file mode 100644 index 0000000..2817795 --- /dev/null +++ b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PlainSchemaValidator.java @@ -0,0 +1,61 @@ +/* + * 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.validation.entity; + +import javax.validation.ConstraintValidatorContext; +import org.apache.commons.lang3.StringUtils; +import org.apache.syncope.common.lib.types.AttrSchemaType; +import org.apache.syncope.common.lib.types.EntityViolationType; +import org.apache.syncope.core.persistence.api.entity.PlainSchema; + +public class PlainSchemaValidator extends AbstractValidator<PlainSchemaCheck, PlainSchema> { + + @Override + public boolean isValid(final PlainSchema schema, final ConstraintValidatorContext context) { + boolean isValid = schema.getType() != AttrSchemaType.Enum + || StringUtils.isNotBlank(schema.getEnumerationValues()); + if (!isValid) { + context.disableDefaultConstraintViolation(); + context.buildConstraintViolationWithTemplate( + getTemplate(EntityViolationType.InvalidSchemaEnum, "Enumeration values missing")). + addPropertyNode("enumerationValues").addConstraintViolation(); + } else { + isValid = schema.getType() != AttrSchemaType.Encrypted + || (schema.getSecretKey() != null && schema.getCipherAlgorithm() != null); + if (!isValid) { + context.disableDefaultConstraintViolation(); + context.buildConstraintViolationWithTemplate( + getTemplate(EntityViolationType.InvalidSchemaEncrypted, + "SecretKey or CipherAlgorithm missing")). + addPropertyNode("secretKey").addPropertyNode("cipherAlgorithm").addConstraintViolation(); + } else { + isValid = !schema.isMultivalue() || !schema.isUniqueConstraint(); + if (!isValid) { + context.disableDefaultConstraintViolation(); + context.buildConstraintViolationWithTemplate( + getTemplate(EntityViolationType.InvalidSchemaMultivalueUnique, + "Cannot contemporary be multivalue and have unique constraint")). + addPropertyNode("multiValue").addConstraintViolation(); + } + } + } + + return isValid; + } +} http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PolicyCheck.java ---------------------------------------------------------------------- diff --git a/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PolicyCheck.java b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PolicyCheck.java new file mode 100644 index 0000000..45873be --- /dev/null +++ b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PolicyCheck.java @@ -0,0 +1,41 @@ +/* + * 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.validation.entity; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import javax.validation.Constraint; +import javax.validation.Payload; + +@Target({ ElementType.TYPE }) +@Retention(RetentionPolicy.RUNTIME) +@Constraint(validatedBy = PolicyValidator.class) +@Documented +public @interface PolicyCheck { + + String message() default "{org.apache.syncope.core.persistence.validation.policy}"; + + Class<?>[] groups() default {}; + + Class<? extends Payload>[] payload() default {}; +} http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PolicyValidator.java ---------------------------------------------------------------------- diff --git a/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PolicyValidator.java b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PolicyValidator.java new file mode 100644 index 0000000..fd95c4c --- /dev/null +++ b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PolicyValidator.java @@ -0,0 +1,59 @@ +/* + * 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.validation.entity; + +import javax.validation.ConstraintValidatorContext; +import org.apache.syncope.common.lib.types.AccountPolicySpec; +import org.apache.syncope.common.lib.types.EntityViolationType; +import org.apache.syncope.common.lib.types.PasswordPolicySpec; +import org.apache.syncope.common.lib.types.SyncPolicySpec; +import org.apache.syncope.core.persistence.api.entity.AccountPolicy; +import org.apache.syncope.core.persistence.api.entity.PasswordPolicy; +import org.apache.syncope.core.persistence.api.entity.Policy; +import org.apache.syncope.core.persistence.api.entity.SyncPolicy; + +public class PolicyValidator extends AbstractValidator<PolicyCheck, Policy> { + + @Override + public boolean isValid(final Policy object, final ConstraintValidatorContext context) { + context.disableDefaultConstraintViolation(); + + EntityViolationType violationType = + object instanceof PasswordPolicy + && !(object.getSpecification(PasswordPolicySpec.class) instanceof PasswordPolicySpec) + ? EntityViolationType.InvalidPasswordPolicy + : object instanceof AccountPolicy + && !(object.getSpecification(AccountPolicySpec.class) instanceof AccountPolicySpec) + ? EntityViolationType.InvalidAccountPolicy + : object instanceof SyncPolicy + && !(object.getSpecification(SyncPolicySpec.class) instanceof SyncPolicySpec) + ? EntityViolationType.InvalidSyncPolicy + : null; + + if (violationType != null) { + context.buildConstraintViolationWithTemplate(getTemplate(violationType, + "Invalid policy specification")).addPropertyNode("specification"). + addConstraintViolation(); + + return false; + } + + return true; + } +} http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PropagationTaskCheck.java ---------------------------------------------------------------------- diff --git a/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PropagationTaskCheck.java b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PropagationTaskCheck.java new file mode 100644 index 0000000..8a0e08b --- /dev/null +++ b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PropagationTaskCheck.java @@ -0,0 +1,41 @@ +/* + * 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.validation.entity; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import javax.validation.Constraint; +import javax.validation.Payload; + +@Target({ ElementType.TYPE }) +@Retention(RetentionPolicy.RUNTIME) +@Constraint(validatedBy = PropagationTaskValidator.class) +@Documented +public @interface PropagationTaskCheck { + + String message() default "{org.apache.syncope.core.persistence.validation.propagationtask}"; + + Class<?>[] groups() default {}; + + Class<? extends Payload>[] payload() default {}; +} http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PropagationTaskValidator.java ---------------------------------------------------------------------- diff --git a/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PropagationTaskValidator.java b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PropagationTaskValidator.java new file mode 100644 index 0000000..43db7f5 --- /dev/null +++ b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/PropagationTaskValidator.java @@ -0,0 +1,65 @@ +/* + * 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.validation.entity; + +import java.util.List; + +import javax.validation.ConstraintValidatorContext; +import org.apache.syncope.common.lib.types.EntityViolationType; +import org.apache.syncope.common.lib.types.PropagationTaskExecStatus; +import org.apache.syncope.core.persistence.api.entity.task.PropagationTask; +import org.apache.syncope.core.persistence.api.entity.task.TaskExec; + +public class PropagationTaskValidator extends AbstractValidator<PropagationTaskCheck, PropagationTask> { + + @Override + public boolean isValid(final PropagationTask task, final ConstraintValidatorContext context) { + boolean isValid; + + if (task == null) { + isValid = true; + } else { + isValid = task.getPropagationMode() != null + && task.getPropagationOperation() != null + && !task.getAttributes().isEmpty() + && task.getResource() != null; + + if (isValid) { + List<? extends TaskExec> executions = task.getExecs(); + for (TaskExec execution : executions) { + try { + PropagationTaskExecStatus.valueOf(execution.getStatus()); + } catch (IllegalArgumentException e) { + LOG.error("Invalid execution status '" + execution.getStatus() + "'", e); + isValid = false; + } + } + } + + if (!isValid) { + context.disableDefaultConstraintViolation(); + context.buildConstraintViolationWithTemplate( + getTemplate(EntityViolationType.InvalidPropagationTask, "Invalid task")). + addPropertyNode(task.getClass().getSimpleName()).addConstraintViolation(); + } + } + + return isValid; + } +} http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/ProvisioningTaskCheck.java ---------------------------------------------------------------------- diff --git a/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/ProvisioningTaskCheck.java b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/ProvisioningTaskCheck.java new file mode 100644 index 0000000..a48f4c6 --- /dev/null +++ b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/ProvisioningTaskCheck.java @@ -0,0 +1,41 @@ +/* + * 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.validation.entity; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import javax.validation.Constraint; +import javax.validation.Payload; + +@Target({ ElementType.TYPE }) +@Retention(RetentionPolicy.RUNTIME) +@Constraint(validatedBy = ProvisioningTaskValidator.class) +@Documented +public @interface ProvisioningTaskCheck { + + String message() default "{org.apache.syncope.core.persistence.validation.abstractsynctask}"; + + Class<?>[] groups() default {}; + + Class<? extends Payload>[] payload() default {}; +} http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/ProvisioningTaskValidator.java ---------------------------------------------------------------------- diff --git a/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/ProvisioningTaskValidator.java b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/ProvisioningTaskValidator.java new file mode 100644 index 0000000..2b6e4e0 --- /dev/null +++ b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/ProvisioningTaskValidator.java @@ -0,0 +1,84 @@ +/* + * 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.validation.entity; + +import javax.validation.ConstraintValidatorContext; +import org.apache.syncope.common.lib.types.EntityViolationType; +import org.apache.syncope.core.persistence.api.entity.task.ProvisioningTask; +import org.apache.syncope.core.persistence.jpa.entity.task.JPAPushTask; +import org.apache.syncope.core.persistence.jpa.entity.task.JPASyncTask; +import org.apache.syncope.core.provisioning.api.sync.PushActions; +import org.apache.syncope.core.provisioning.api.sync.SyncActions; + +public class ProvisioningTaskValidator extends AbstractValidator<ProvisioningTaskCheck, ProvisioningTask> { + + private final SchedTaskValidator schedV; + + public ProvisioningTaskValidator() { + super(); + + schedV = new SchedTaskValidator(); + } + + @Override + public boolean isValid(final ProvisioningTask object, final ConstraintValidatorContext context) { + boolean isValid = schedV.isValid(object, context); + + if (isValid) { + isValid = object.getResource() != null; + if (!isValid) { + LOG.error("Resource is null"); + + context.disableDefaultConstraintViolation(); + context.buildConstraintViolationWithTemplate( + getTemplate(EntityViolationType.InvalidSyncTask, "Resource cannot be null")). + addPropertyNode("resource").addConstraintViolation(); + } + + if (!object.getActionsClassNames().isEmpty()) { + for (String className : object.getActionsClassNames()) { + Class<?> actionsClass = null; + boolean isAssignable = false; + try { + actionsClass = Class.forName(className); + isAssignable = object instanceof JPASyncTask + ? SyncActions.class.isAssignableFrom(actionsClass) + : object instanceof JPAPushTask + ? PushActions.class.isAssignableFrom(actionsClass) + : false; + } catch (Exception e) { + LOG.error("Invalid SyncActions specified", e); + isValid = false; + } + + if (actionsClass == null || !isAssignable) { + isValid = false; + + context.disableDefaultConstraintViolation(); + context.buildConstraintViolationWithTemplate( + getTemplate(EntityViolationType.InvalidSyncTask, "Invalid class name")). + addPropertyNode("actionsClassName").addConstraintViolation(); + } + } + } + } + + return isValid; + } +} http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/ReportCheck.java ---------------------------------------------------------------------- diff --git a/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/ReportCheck.java b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/ReportCheck.java new file mode 100644 index 0000000..d480262 --- /dev/null +++ b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/ReportCheck.java @@ -0,0 +1,41 @@ +/* + * 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.validation.entity; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import javax.validation.Constraint; +import javax.validation.Payload; + +@Target({ ElementType.TYPE }) +@Retention(RetentionPolicy.RUNTIME) +@Constraint(validatedBy = ReportValidator.class) +@Documented +public @interface ReportCheck { + + String message() default "{org.apache.syncope.core.persistence.validation.report}"; + + Class<?>[] groups() default {}; + + Class<? extends Payload>[] payload() default {}; +} http://git-wip-us.apache.org/repos/asf/syncope/blob/d30c8526/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/ReportValidator.java ---------------------------------------------------------------------- diff --git a/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/ReportValidator.java b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/ReportValidator.java new file mode 100644 index 0000000..0025725 --- /dev/null +++ b/syncope620/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/validation/entity/ReportValidator.java @@ -0,0 +1,67 @@ +/* + * 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.validation.entity; + +import java.text.ParseException; +import java.util.HashSet; +import java.util.Set; +import javax.validation.ConstraintValidatorContext; +import org.apache.syncope.common.lib.report.ReportletConf; +import org.apache.syncope.common.lib.types.EntityViolationType; +import org.apache.syncope.core.persistence.api.entity.Report; +import org.quartz.CronExpression; + +public class ReportValidator extends AbstractValidator<ReportCheck, Report> { + + @Override + @SuppressWarnings("ResultOfObjectAllocationIgnored") + public boolean isValid(final Report object, final ConstraintValidatorContext context) { + boolean isValid = true; + + if (object.getCronExpression() != null) { + try { + new CronExpression(object.getCronExpression()); + } catch (ParseException e) { + LOG.error("Invalid cron expression '" + object.getCronExpression() + "'", e); + isValid = false; + + context.disableDefaultConstraintViolation(); + context.buildConstraintViolationWithTemplate( + getTemplate(EntityViolationType.InvalidReport, "Invalid cron expression")). + addPropertyNode("cronExpression").addConstraintViolation(); + } + } + + Set<String> reportletNames = new HashSet<>(); + for (ReportletConf conf : object.getReportletConfs()) { + reportletNames.add(conf.getName()); + } + if (reportletNames.size() != object.getReportletConfs().size()) { + LOG.error("Reportlet name must be unique"); + isValid = false; + + context.disableDefaultConstraintViolation(); + context.buildConstraintViolationWithTemplate( + getTemplate(EntityViolationType.InvalidReport, "Reportlet name must be unique")). + addPropertyNode("reportletConfs").addConstraintViolation(); + } + + return isValid; + } +}
