View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.syncope.core.persistence.jpa.validation.entity;
20  
21  import java.util.HashSet;
22  import java.util.Set;
23  import javax.validation.ConstraintValidatorContext;
24  import org.apache.syncope.common.lib.to.Item;
25  import org.apache.syncope.common.lib.to.ItemContainer;
26  import org.apache.syncope.common.lib.to.Mapping;
27  import org.apache.syncope.common.lib.to.OrgUnit;
28  import org.apache.syncope.common.lib.types.EntityViolationType;
29  import org.apache.syncope.core.persistence.api.entity.AnyType;
30  import org.apache.syncope.core.persistence.api.entity.Entity;
31  import org.apache.syncope.core.persistence.api.entity.ExternalResource;
32  import org.identityconnectors.framework.common.objects.ObjectClass;
33  
34  public class ExternalResourceValidator extends AbstractValidator<ExternalResourceCheck, ExternalResource> {
35  
36      private static boolean areItemsValid(
37              final ItemContainer itemContainer,
38              final ConstraintValidatorContext context) {
39  
40          if (itemContainer.getItems().stream().
41                  anyMatch(item -> item.getIntAttrName() == null
42                  || item.getExtAttrName() == null
43                  || item.getPurpose() == null)) {
44  
45              context.buildConstraintViolationWithTemplate(
46                      getTemplate(EntityViolationType.InvalidMapping,
47                              "intAttrName, extAttrName and purpose must be specified for each item")).
48                      addPropertyNode("items").addConstraintViolation();
49              return false;
50          }
51  
52          if (itemContainer.getConnObjectKeyItem().isEmpty()) {
53              context.buildConstraintViolationWithTemplate(
54                      getTemplate(EntityViolationType.InvalidMapping, "Single ConnObjectKey mapping is required")).
55                      addPropertyNode("connObjectKey.size").addConstraintViolation();
56              return false;
57          }
58  
59          return true;
60      }
61  
62      private static boolean isValid(final OrgUnit orgUnit, final ConstraintValidatorContext context) {
63          if (orgUnit == null) {
64              return true;
65          }
66  
67          return areItemsValid(orgUnit, context);
68      }
69  
70      private static boolean isValid(final Mapping mapping, final ConstraintValidatorContext context) {
71          if (mapping == null) {
72              return true;
73          }
74  
75          boolean isValid = true;
76  
77          long passwords = mapping.getItems().stream().filter(Item::isPassword).count();
78          if (passwords > 1) {
79              context.buildConstraintViolationWithTemplate(
80                      getTemplate(EntityViolationType.InvalidMapping, "One password mapping is allowed at most")).
81                      addPropertyNode("password.size").addConstraintViolation();
82              isValid = false;
83          }
84  
85          return isValid && areItemsValid(mapping, context);
86      }
87  
88      @Override
89      public boolean isValid(final ExternalResource resource, final ConstraintValidatorContext context) {
90          context.disableDefaultConstraintViolation();
91  
92          if (resource.getKey() == null || !Entity.ID_PATTERN.matcher(resource.getKey()).matches()) {
93              context.buildConstraintViolationWithTemplate(
94                      getTemplate(EntityViolationType.InvalidKey, resource.getKey())).
95                      addPropertyNode("key").addConstraintViolation();
96              return false;
97          }
98  
99          Set<String> anyTypes = new HashSet<>();
100         Set<String> objectClasses = new HashSet<>();
101         boolean validMappings = resource.getProvisions().stream().allMatch(provision -> {
102             anyTypes.add(provision.getAnyType());
103             if (provision.getObjectClass() != null) {
104                 objectClasses.add(provision.getObjectClass());
105             }
106             return isValid(provision.getMapping(), context);
107         });
108         validMappings &= isValid(resource.getOrgUnit(), context);
109 
110         if (anyTypes.size() < resource.getProvisions().size()) {
111             context.buildConstraintViolationWithTemplate(getTemplate(EntityViolationType.InvalidResource,
112                     "Each provision requires a different " + AnyType.class.getSimpleName())).
113                     addPropertyNode("provisions").addConstraintViolation();
114             return false;
115         }
116         if (objectClasses.size() < resource.getProvisions().size()) {
117             context.buildConstraintViolationWithTemplate(getTemplate(EntityViolationType.InvalidResource,
118                     "Each provision requires a different" + ObjectClass.class.getSimpleName())).
119                     addPropertyNode("provisions").addConstraintViolation();
120             return false;
121         }
122 
123         return validMappings;
124     }
125 }