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.data;
20  
21  import java.text.ParseException;
22  import java.util.Base64;
23  import java.util.stream.Collectors;
24  import org.apache.syncope.common.lib.SyncopeClientCompositeException;
25  import org.apache.syncope.common.lib.SyncopeClientException;
26  import org.apache.syncope.common.lib.to.Item;
27  import org.apache.syncope.common.lib.to.SAML2SP4UIIdPTO;
28  import org.apache.syncope.common.lib.to.UserTO;
29  import org.apache.syncope.common.lib.types.AnyTypeKind;
30  import org.apache.syncope.common.lib.types.ClientExceptionType;
31  import org.apache.syncope.common.lib.types.MappingPurpose;
32  import org.apache.syncope.common.lib.types.SchemaType;
33  import org.apache.syncope.core.persistence.api.dao.AnyTypeDAO;
34  import org.apache.syncope.core.persistence.api.dao.ImplementationDAO;
35  import org.apache.syncope.core.persistence.api.dao.SAML2SP4UIIdPDAO;
36  import org.apache.syncope.core.persistence.api.entity.Entity;
37  import org.apache.syncope.core.persistence.api.entity.Implementation;
38  import org.apache.syncope.core.persistence.api.entity.SAML2SP4UIEntityFactory;
39  import org.apache.syncope.core.persistence.api.entity.SAML2SP4UIIdP;
40  import org.apache.syncope.core.persistence.api.entity.SAML2SP4UIUserTemplate;
41  import org.apache.syncope.core.provisioning.api.IntAttrName;
42  import org.apache.syncope.core.provisioning.api.IntAttrNameParser;
43  import org.apache.syncope.core.provisioning.api.data.SAML2SP4UIIdPDataBinder;
44  import org.apache.syncope.core.provisioning.api.jexl.JexlUtils;
45  import org.slf4j.Logger;
46  import org.slf4j.LoggerFactory;
47  
48  public class SAML2SP4UIIdPDataBinderImpl implements SAML2SP4UIIdPDataBinder {
49  
50      protected static final Logger LOG = LoggerFactory.getLogger(SAML2SP4UIIdPDataBinder.class);
51  
52      protected final AnyTypeDAO anyTypeDAO;
53  
54      protected final SAML2SP4UIIdPDAO idapDAO;
55  
56      protected final ImplementationDAO implementationDAO;
57  
58      protected final SAML2SP4UIEntityFactory entityFactory;
59  
60      protected final IntAttrNameParser intAttrNameParser;
61  
62      public SAML2SP4UIIdPDataBinderImpl(
63              final AnyTypeDAO anyTypeDAO,
64              final SAML2SP4UIIdPDAO idapDAO,
65              final ImplementationDAO implementationDAO,
66              final SAML2SP4UIEntityFactory entityFactory,
67              final IntAttrNameParser intAttrNameParser) {
68  
69          this.anyTypeDAO = anyTypeDAO;
70          this.idapDAO = idapDAO;
71          this.implementationDAO = implementationDAO;
72          this.entityFactory = entityFactory;
73          this.intAttrNameParser = intAttrNameParser;
74      }
75  
76      @Override
77      public SAML2SP4UIIdP create(final SAML2SP4UIIdPTO idpTO) {
78          return update(entityFactory.newEntity(SAML2SP4UIIdP.class), idpTO);
79      }
80  
81      protected void populateItems(final SAML2SP4UIIdPTO idpTO, final SAML2SP4UIIdP idp) {
82          SyncopeClientCompositeException scce = SyncopeClientException.buildComposite();
83          SyncopeClientException invalidMapping =
84                  SyncopeClientException.build(ClientExceptionType.InvalidMapping);
85          SyncopeClientException requiredValuesMissing =
86                  SyncopeClientException.build(ClientExceptionType.RequiredValuesMissing);
87  
88          idpTO.getItems().forEach(itemTO -> {
89              if (itemTO == null) {
90                  LOG.error("Null {}", Item.class.getSimpleName());
91                  invalidMapping.getElements().add("Null " + Item.class.getSimpleName());
92              } else if (itemTO.getIntAttrName() == null) {
93                  requiredValuesMissing.getElements().add("intAttrName");
94                  scce.addException(requiredValuesMissing);
95              } else {
96                  IntAttrName intAttrName = null;
97                  try {
98                      intAttrName = intAttrNameParser.parse(itemTO.getIntAttrName(), AnyTypeKind.USER);
99                  } catch (ParseException e) {
100                     LOG.error("Invalid intAttrName '{}' specified, ignoring", itemTO.getIntAttrName(), e);
101                 }
102 
103                 if (intAttrName == null || intAttrName.getSchemaType() == null && intAttrName.getField() == null) {
104                     LOG.error("'{}' not existing", itemTO.getIntAttrName());
105                     invalidMapping.getElements().add('\'' + itemTO.getIntAttrName() + "' not existing");
106                 } else {
107                     // no mandatory condition implies mandatory condition false
108                     if (!JexlUtils.isExpressionValid(itemTO.getMandatoryCondition() == null
109                             ? "false" : itemTO.getMandatoryCondition())) {
110 
111                         SyncopeClientException invalidMandatoryCondition = SyncopeClientException.build(
112                                 ClientExceptionType.InvalidValues);
113                         invalidMandatoryCondition.getElements().add(itemTO.getMandatoryCondition());
114                         scce.addException(invalidMandatoryCondition);
115                     }
116 
117                     Item item = new Item();
118                     item.setIntAttrName(itemTO.getIntAttrName());
119                     item.setExtAttrName(itemTO.getExtAttrName());
120                     item.setMandatoryCondition(itemTO.getMandatoryCondition());
121                     item.setConnObjectKey(itemTO.isConnObjectKey());
122                     item.setPassword(itemTO.isPassword());
123                     item.setPropagationJEXLTransformer(itemTO.getPropagationJEXLTransformer());
124                     item.setPullJEXLTransformer(itemTO.getPullJEXLTransformer());
125                     item.setPurpose(MappingPurpose.NONE);
126 
127                     itemTO.getTransformers().forEach(transformerKey -> {
128                         Implementation transformer = implementationDAO.find(transformerKey);
129                         if (transformer == null) {
130                             LOG.debug("Invalid " + Implementation.class.getSimpleName() + " {}, ignoring...",
131                                     transformerKey);
132                         } else {
133                             item.getTransformers().add(transformer.getKey());
134                         }
135                         // remove all implementations not contained in the TO
136                         item.getTransformers().
137                                 removeIf(implementation -> !itemTO.getTransformers().contains(implementation));
138                     });
139 
140                     if (item.isConnObjectKey()) {
141                         if (intAttrName.getSchemaType() == SchemaType.VIRTUAL) {
142                             invalidMapping.getElements().
143                                     add("Virtual attributes cannot be set as ConnObjectKey");
144                         }
145                         if ("password".equals(intAttrName.getField())) {
146                             invalidMapping.getElements().add(
147                                     "Password attributes cannot be set as ConnObjectKey");
148                         }
149 
150                         idp.setConnObjectKeyItem(item);
151                     } else {
152                         idp.getItems().add(item);
153                     }
154                 }
155             }
156         });
157 
158         if (!invalidMapping.getElements().isEmpty()) {
159             scce.addException(invalidMapping);
160         }
161         if (scce.hasExceptions()) {
162             throw scce;
163         }
164     }
165 
166     @Override
167     public SAML2SP4UIIdP update(final SAML2SP4UIIdP idp, final SAML2SP4UIIdPTO idpTO) {
168         idp.setEntityID(idpTO.getEntityID());
169         idp.setName(idpTO.getName());
170         idp.setMetadata(Base64.getMimeDecoder().decode(idpTO.getMetadata()));
171         idp.setLogoutSupported(idpTO.isLogoutSupported());
172         idp.setCreateUnmatching(idpTO.isCreateUnmatching());
173         idp.setSelfRegUnmatching(idpTO.isSelfRegUnmatching());
174         idp.setUpdateMatching(idpTO.isUpdateMatching());
175         idp.setBindingType(idpTO.getBindingType());
176 
177         if (idpTO.getRequestedAuthnContextProvider() == null) {
178             idp.setRequestedAuthnContextProvider(null);
179         } else {
180             Implementation implementation = implementationDAO.find(idpTO.getRequestedAuthnContextProvider());
181             if (implementation == null) {
182                 LOG.debug("Invalid " + Implementation.class.getSimpleName() + " {}, ignoring...",
183                         idpTO.getRequestedAuthnContextProvider());
184             } else {
185                 idp.setRequestedAuthnContextProvider(implementation);
186             }
187         }
188 
189         if (idpTO.getUserTemplate() == null) {
190             idp.setUserTemplate(null);
191         } else {
192             SAML2SP4UIUserTemplate userTemplate = idp.getUserTemplate();
193             if (userTemplate == null) {
194                 userTemplate = entityFactory.newEntity(SAML2SP4UIUserTemplate.class);
195                 userTemplate.setAnyType(anyTypeDAO.findUser());
196                 userTemplate.setIdP(idp);
197                 idp.setUserTemplate(userTemplate);
198             }
199             userTemplate.set(idpTO.getUserTemplate());
200         }
201 
202         idp.getItems().clear();
203         populateItems(idpTO, idp);
204 
205         idpTO.getActions().forEach(action -> {
206             Implementation implementation = implementationDAO.find(action);
207             if (implementation == null) {
208                 LOG.debug("Invalid " + Implementation.class.getSimpleName() + " {}, ignoring...", action);
209             } else {
210                 idp.add(implementation);
211             }
212         });
213         // remove all implementations not contained in the TO
214         idp.getActions().removeIf(impl -> !idpTO.getActions().contains(impl.getKey()));
215 
216         return idapDAO.save(idp);
217     }
218 
219     protected void populateItems(final SAML2SP4UIIdP idp, final SAML2SP4UIIdPTO idpTO) {
220         idp.getItems().forEach(item -> {
221             Item itemTO = new Item();
222             itemTO.setIntAttrName(item.getIntAttrName());
223             itemTO.setExtAttrName(item.getExtAttrName());
224             itemTO.setMandatoryCondition(item.getMandatoryCondition());
225             itemTO.setConnObjectKey(item.isConnObjectKey());
226             itemTO.setPassword(item.isPassword());
227             itemTO.setPropagationJEXLTransformer(item.getPropagationJEXLTransformer());
228             itemTO.setPullJEXLTransformer(item.getPullJEXLTransformer());
229             itemTO.getTransformers().addAll(item.getTransformers());
230             itemTO.setPurpose(MappingPurpose.NONE);
231 
232             if (itemTO.isConnObjectKey()) {
233                 idpTO.setConnObjectKeyItem(itemTO);
234             } else {
235                 idpTO.add(itemTO);
236             }
237         });
238     }
239 
240     @Override
241     public SAML2SP4UIIdPTO getIdPTO(final SAML2SP4UIIdP idp) {
242         SAML2SP4UIIdPTO idpTO = new SAML2SP4UIIdPTO();
243 
244         idpTO.setKey(idp.getKey());
245         idpTO.setEntityID(idp.getEntityID());
246         idpTO.setName(idp.getName());
247         idpTO.setMetadata(Base64.getMimeEncoder().encodeToString(idp.getMetadata()));
248         idpTO.setLogoutSupported(idp.isLogoutSupported());
249         idpTO.setBindingType(idp.getBindingType());
250         idpTO.setCreateUnmatching(idp.isCreateUnmatching());
251         idpTO.setSelfRegUnmatching(idp.isSelfRegUnmatching());
252         idpTO.setUpdateMatching(idp.isUpdateMatching());
253 
254         if (idp.getRequestedAuthnContextProvider() != null) {
255             idpTO.setRequestedAuthnContextProvider(idp.getRequestedAuthnContextProvider().getKey());
256         }
257 
258         if (idp.getUserTemplate() != null) {
259             idpTO.setUserTemplate((UserTO) idp.getUserTemplate().get());
260         }
261 
262         populateItems(idp, idpTO);
263 
264         idpTO.getActions().addAll(idp.getActions().stream().map(Entity::getKey).collect(Collectors.toList()));
265 
266         return idpTO;
267     }
268 }