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.provisioning.java.pushpull;
20  
21  import java.util.ArrayList;
22  import java.util.Base64;
23  import java.util.List;
24  import java.util.Objects;
25  import java.util.Optional;
26  import org.apache.commons.lang3.tuple.Pair;
27  import org.apache.cxf.jaxrs.ext.search.client.CompleteCondition;
28  import org.apache.syncope.common.lib.policy.DefaultPushCorrelationRuleConf;
29  import org.apache.syncope.common.lib.policy.PushCorrelationRuleConf;
30  import org.apache.syncope.common.lib.search.ConnObjectTOFiqlSearchConditionBuilder;
31  import org.apache.syncope.common.lib.to.Provision;
32  import org.apache.syncope.common.lib.types.MappingPurpose;
33  import org.apache.syncope.core.persistence.api.entity.Any;
34  import org.apache.syncope.core.persistence.api.entity.ExternalResource;
35  import org.apache.syncope.core.provisioning.api.AccountGetter;
36  import org.apache.syncope.core.provisioning.api.MappingManager;
37  import org.apache.syncope.core.provisioning.api.PlainAttrGetter;
38  import org.apache.syncope.core.provisioning.api.rules.PushCorrelationRule;
39  import org.apache.syncope.core.provisioning.api.rules.PushCorrelationRuleConfClass;
40  import org.identityconnectors.common.security.GuardedByteArray;
41  import org.identityconnectors.common.security.GuardedString;
42  import org.identityconnectors.common.security.SecurityUtil;
43  import org.identityconnectors.framework.common.objects.Attribute;
44  import org.identityconnectors.framework.common.objects.AttributeBuilder;
45  import org.identityconnectors.framework.common.objects.ConnectorObject;
46  import org.identityconnectors.framework.common.objects.filter.Filter;
47  import org.identityconnectors.framework.common.objects.filter.FilterBuilder;
48  import org.springframework.beans.factory.annotation.Autowired;
49  import org.springframework.util.CollectionUtils;
50  
51  @PushCorrelationRuleConfClass(DefaultPushCorrelationRuleConf.class)
52  public class DefaultPushCorrelationRule implements PushCorrelationRule {
53  
54      protected static final ConnObjectTOFiqlSearchConditionBuilder FIQL_BUILDER =
55              new ConnObjectTOFiqlSearchConditionBuilder();
56  
57      @Autowired
58      protected MappingManager mappingManager;
59  
60      protected DefaultPushCorrelationRuleConf conf;
61  
62      @Override
63      public void setConf(final PushCorrelationRuleConf conf) {
64          if (conf instanceof DefaultPushCorrelationRuleConf) {
65              this.conf = DefaultPushCorrelationRuleConf.class.cast(conf);
66          } else {
67              throw new IllegalArgumentException(
68                      DefaultPushCorrelationRuleConf.class.getName() + " expected, got " + conf.getClass().getName());
69          }
70      }
71  
72      @Override
73      public Filter getFilter(final Any<?> any, final ExternalResource resource, final Provision provision) {
74          List<Filter> filters = new ArrayList<>();
75  
76          provision.getMapping().getItems().stream().filter(
77                  item -> conf.getSchemas().contains(item.getIntAttrName()) && item.getPurpose() != MappingPurpose.NONE).
78                  forEach(item -> {
79                      Pair<String, Attribute> attr = mappingManager.prepareAttr(
80                              resource,
81                              provision,
82                              item,
83                              any,
84                              null,
85                              AccountGetter.DEFAULT,
86                              AccountGetter.DEFAULT,
87                              PlainAttrGetter.DEFAULT);
88                      if (attr != null) {
89                          Attribute toFilter = null;
90                          if (attr.getLeft() != null) {
91                              toFilter = AttributeBuilder.build(item.getExtAttrName(), attr.getLeft());
92                          } else if (attr.getRight() != null) {
93                              toFilter = attr.getRight();
94                          }
95                          if (toFilter != null) {
96                              filters.add(provision.isIgnoreCaseMatch()
97                                      ? FilterBuilder.equalsIgnoreCase(toFilter)
98                                      : FilterBuilder.equalTo(toFilter));
99                          }
100                     }
101                 });
102 
103         return conf.isOrSchemas()
104                 ? FilterBuilder.or(filters)
105                 : FilterBuilder.and(filters);
106     }
107 
108     @Override
109     public String getFIQL(final ConnectorObject connectorObject, final Provision provision) {
110         List<CompleteCondition> conditions = new ArrayList<>();
111 
112         provision.getMapping().getItems().stream().filter(
113                 item -> conf.getSchemas().contains(item.getIntAttrName()) && item.getPurpose() != MappingPurpose.NONE).
114                 forEach(item -> Optional.ofNullable(connectorObject.getAttributeByName(item.getExtAttrName())).
115                 ifPresent(attr -> {
116                     if (CollectionUtils.isEmpty(attr.getValue())) {
117                         conditions.add(FIQL_BUILDER.isNull(attr.getName()));
118                     } else {
119                         List<CompleteCondition> valueConditions = new ArrayList<>();
120 
121                         attr.getValue().stream().filter(Objects::nonNull).forEach(value -> {
122                             if (value instanceof GuardedString) {
123                                 valueConditions.add(FIQL_BUILDER.is(attr.getName()).
124                                         equalTo(SecurityUtil.decrypt((GuardedString) value)));
125                             } else if (value instanceof GuardedByteArray) {
126                                 valueConditions.add(FIQL_BUILDER.is(attr.getName()).
127                                         equalTo(new String(SecurityUtil.decrypt((GuardedByteArray) value))));
128                             } else if (value instanceof byte[]) {
129                                 valueConditions.add(FIQL_BUILDER.is(attr.getName()).
130                                         equalTo(Base64.getEncoder().encodeToString((byte[]) value)));
131                             } else {
132                                 valueConditions.add(FIQL_BUILDER.is(attr.getName()).equalTo(value.toString()));
133                             }
134                         });
135 
136                         if (!valueConditions.isEmpty()) {
137                             conditions.add(valueConditions.size() == 1
138                                     ? valueConditions.get(0)
139                                     : FIQL_BUILDER.and(valueConditions));
140                         }
141                     }
142                 }));
143 
144         return conf.isOrSchemas()
145                 ? FIQL_BUILDER.or(conditions).query()
146                 : FIQL_BUILDER.and(conditions).query();
147     }
148 }