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.inner;
20  
21  import static org.junit.jupiter.api.Assertions.assertEquals;
22  import static org.junit.jupiter.api.Assertions.assertNotEquals;
23  import static org.junit.jupiter.api.Assertions.assertNotNull;
24  import static org.junit.jupiter.api.Assertions.assertNull;
25  import static org.junit.jupiter.api.Assertions.assertTrue;
26  import static org.junit.jupiter.api.Assertions.fail;
27  
28  import java.io.UnsupportedEncodingException;
29  import java.util.Arrays;
30  import java.util.Base64;
31  import java.util.Random;
32  import javax.validation.ValidationException;
33  import org.apache.syncope.common.lib.SyncopeConstants;
34  import org.apache.syncope.common.lib.types.AnyTypeKind;
35  import org.apache.syncope.common.lib.types.AttrSchemaType;
36  import org.apache.syncope.common.lib.types.CipherAlgorithm;
37  import org.apache.syncope.common.lib.types.EntityViolationType;
38  import org.apache.syncope.core.persistence.api.attrvalue.validation.InvalidEntityException;
39  import org.apache.syncope.core.persistence.api.attrvalue.validation.PlainAttrValidationManager;
40  import org.apache.syncope.core.persistence.api.dao.AnyTypeClassDAO;
41  import org.apache.syncope.core.persistence.api.dao.PlainAttrDAO;
42  import org.apache.syncope.core.persistence.api.dao.PlainSchemaDAO;
43  import org.apache.syncope.core.persistence.api.dao.UserDAO;
44  import org.apache.syncope.core.persistence.api.entity.PlainSchema;
45  import org.apache.syncope.core.persistence.api.entity.user.UPlainAttr;
46  import org.apache.syncope.core.persistence.api.entity.user.UPlainAttrUniqueValue;
47  import org.apache.syncope.core.persistence.api.entity.user.User;
48  import org.apache.syncope.core.persistence.jpa.AbstractTest;
49  import org.apache.syncope.core.spring.security.Encryptor;
50  import org.apache.syncope.core.spring.security.SecureRandomUtils;
51  import org.junit.jupiter.api.Tag;
52  import org.junit.jupiter.api.Test;
53  import org.springframework.beans.factory.annotation.Autowired;
54  import org.springframework.transaction.annotation.Transactional;
55  
56  @Transactional("Master")
57  public class PlainAttrTest extends AbstractTest {
58  
59      @Autowired
60      private UserDAO userDAO;
61  
62      @Autowired
63      private PlainAttrDAO plainAttrDAO;
64  
65      @Autowired
66      private PlainSchemaDAO plainSchemaDAO;
67  
68      @Autowired
69      private AnyTypeClassDAO anyTypeClassDAO;
70  
71      @Autowired
72      private PlainAttrValidationManager validator;
73  
74      @Tag("plainAttrTable")
75      @Test
76      public void findByKey() {
77          UPlainAttr attribute = findPlainAttr("01f22fbd-b672-40af-b528-686d9b27ebc4", UPlainAttr.class);
78          assertNotNull(attribute);
79          attribute = findPlainAttr("9d0d9e40-1b18-488e-9482-37dab82163c9", UPlainAttr.class);
80          assertNotNull(attribute);
81      }
82  
83      @Tag("plainAttrTable")
84      @Test
85      public void read() {
86          UPlainAttr attribute = findPlainAttr("01f22fbd-b672-40af-b528-686d9b27ebc4", UPlainAttr.class);
87          assertNotNull(attribute);
88          assertTrue(attribute.getValues().isEmpty());
89          assertNotNull(attribute.getUniqueValue());
90      }
91  
92      @Test
93      public void save() throws ClassNotFoundException {
94          User user = userDAO.find("1417acbe-cbf6-4277-9372-e75e04f97000");
95  
96          PlainSchema emailSchema = plainSchemaDAO.find("email");
97          assertNotNull(emailSchema);
98  
99          UPlainAttr attr = entityFactory.newEntity(UPlainAttr.class);
100         attr.setOwner(user);
101         attr.setSchema(emailSchema);
102 
103         Exception thrown = null;
104         try {
105             attr.add(validator, "john.doe@gmail.com", anyUtilsFactory.getInstance(AnyTypeKind.USER));
106             attr.add(validator, "mario.rossi@gmail.com", anyUtilsFactory.getInstance(AnyTypeKind.USER));
107         } catch (ValidationException e) {
108             thrown = e;
109         }
110         assertNull(thrown);
111 
112         try {
113             attr.add(validator, "http://www.apache.org", anyUtilsFactory.getInstance(AnyTypeKind.USER));
114         } catch (ValidationException e) {
115             thrown = e;
116         }
117         assertNotNull(thrown);
118     }
119 
120     @Test
121     public void saveWithEnum() throws ClassNotFoundException {
122         User user = userDAO.find("1417acbe-cbf6-4277-9372-e75e04f97000");
123         assertNotNull(user);
124 
125         PlainSchema gender = plainSchemaDAO.find("gender");
126         assertNotNull(gender);
127         assertNotNull(gender.getType());
128         assertNotNull(gender.getEnumerationValues());
129 
130         UPlainAttr attribute = entityFactory.newEntity(UPlainAttr.class);
131         attribute.setOwner(user);
132         attribute.setSchema(gender);
133         user.add(attribute);
134 
135         Exception thrown = null;
136         try {
137             attribute.add(validator, "A", anyUtilsFactory.getInstance(AnyTypeKind.USER));
138         } catch (ValidationException e) {
139             thrown = e;
140         }
141         assertNotNull(thrown);
142 
143         attribute.add(validator, "M", anyUtilsFactory.getInstance(AnyTypeKind.USER));
144 
145         InvalidEntityException iee = null;
146         try {
147             userDAO.save(user);
148         } catch (InvalidEntityException e) {
149             iee = e;
150         }
151         assertNull(iee);
152     }
153 
154     @Test
155     public void invalidValueList() {
156         User user = userDAO.find("1417acbe-cbf6-4277-9372-e75e04f97000");
157 
158         PlainSchema emailSchema = plainSchemaDAO.find("email");
159         assertNotNull(emailSchema);
160 
161         PlainSchema fullnameSchema = plainSchemaDAO.find("fullname");
162         assertNotNull(fullnameSchema);
163 
164         UPlainAttr attr = entityFactory.newEntity(UPlainAttr.class);
165         attr.setOwner(user);
166         attr.setSchema(emailSchema);
167 
168         user.add(attr);
169 
170         InvalidEntityException iee = null;
171         try {
172             userDAO.save(user);
173             fail("This should not happen");
174         } catch (InvalidEntityException e) {
175             iee = e;
176         }
177         assertNotNull(iee);
178         // for attr because no values are set
179         assertTrue(iee.hasViolation(EntityViolationType.InvalidValueList));
180     }
181 
182     @Tag("plainAttrTable")
183     @Test
184     public void invalidPlainAttr() {
185         User user = userDAO.find("1417acbe-cbf6-4277-9372-e75e04f97000");
186 
187         PlainSchema emailSchema = plainSchemaDAO.find("email");
188         assertNotNull(emailSchema);
189 
190         PlainSchema fullnameSchema = plainSchemaDAO.find("fullname");
191         assertNotNull(fullnameSchema);
192 
193         UPlainAttr attr = entityFactory.newEntity(UPlainAttr.class);
194         attr.setOwner(user);
195         attr.setSchema(emailSchema);
196 
197         UPlainAttrUniqueValue uauv = entityFactory.newEntity(UPlainAttrUniqueValue.class);
198         uauv.setAttr(attr);
199         uauv.setSchema(fullnameSchema);
200         uauv.setStringValue("a value");
201 
202         attr.setUniqueValue(uauv);
203 
204         user.add(attr);
205 
206         InvalidEntityException iee = null;
207         try {
208             userDAO.save(user);
209             fail("This should not happen");
210         } catch (InvalidEntityException e) {
211             iee = e;
212         }
213         assertNotNull(iee);
214         // for attr because no values are set
215         assertTrue(iee.hasViolation(EntityViolationType.InvalidValueList));
216         // for uauv because uauv.schema and uauv.attr.schema are different
217         assertTrue(iee.hasViolation(EntityViolationType.InvalidPlainAttr));
218     }
219 
220     @Test
221     public void saveWithEncrypted() throws Exception {
222         User user = userDAO.find("1417acbe-cbf6-4277-9372-e75e04f97000");
223 
224         PlainSchema obscureSchema = plainSchemaDAO.find("obscure");
225         assertNotNull(obscureSchema);
226         assertNotNull(obscureSchema.getSecretKey());
227         assertNotNull(obscureSchema.getCipherAlgorithm());
228 
229         UPlainAttr attr = entityFactory.newEntity(UPlainAttr.class);
230         attr.setOwner(user);
231         attr.setSchema(obscureSchema);
232         attr.add(validator, "testvalue", anyUtilsFactory.getInstance(AnyTypeKind.USER));
233         user.add(attr);
234 
235         userDAO.save(user);
236 
237         UPlainAttr obscure = user.getPlainAttr("obscure").get();
238         assertNotNull(obscure);
239         assertEquals(1, obscure.getValues().size());
240         assertEquals(Encryptor.getInstance(obscureSchema.getSecretKey()).
241                 encode("testvalue", obscureSchema.getCipherAlgorithm()), obscure.getValues().get(0).getStringValue());
242     }
243 
244     @Test
245     public void encryptedWithKeyAsSysProp() throws Exception {
246         PlainSchema obscureSchema = plainSchemaDAO.find("obscure");
247         assertNotNull(obscureSchema);
248 
249         PlainSchema obscureWithKeyAsSysprop = entityFactory.newEntity(PlainSchema.class);
250         obscureWithKeyAsSysprop.setKey("obscureWithKeyAsSysprop");
251         obscureWithKeyAsSysprop.setAnyTypeClass(obscureSchema.getAnyTypeClass());
252         obscureWithKeyAsSysprop.setType(AttrSchemaType.Encrypted);
253         obscureWithKeyAsSysprop.setCipherAlgorithm(obscureSchema.getCipherAlgorithm());
254         obscureWithKeyAsSysprop.setSecretKey("${obscureSecretKey}");
255 
256         obscureWithKeyAsSysprop = plainSchemaDAO.save(obscureWithKeyAsSysprop);
257 
258         System.setProperty("obscureSecretKey", obscureSchema.getSecretKey());
259 
260         UPlainAttr attr = entityFactory.newEntity(UPlainAttr.class);
261         attr.setSchema(obscureWithKeyAsSysprop);
262         attr.add(validator, "testvalue", anyUtilsFactory.getInstance(AnyTypeKind.USER));
263 
264         assertEquals(Encryptor.getInstance(obscureSchema.getSecretKey()).
265                 encode("testvalue", obscureSchema.getCipherAlgorithm()), attr.getValues().get(0).getStringValue());
266     }
267 
268     @Test
269     public void encryptedWithDecodeConversionPattern() throws Exception {
270         PlainSchema obscureWithDecodeConversionPattern = entityFactory.newEntity(PlainSchema.class);
271         obscureWithDecodeConversionPattern.setKey("obscureWithDecodeConversionPattern");
272         obscureWithDecodeConversionPattern.setAnyTypeClass(anyTypeClassDAO.find("other"));
273         obscureWithDecodeConversionPattern.setType(AttrSchemaType.Encrypted);
274         obscureWithDecodeConversionPattern.setCipherAlgorithm(CipherAlgorithm.AES);
275         obscureWithDecodeConversionPattern.setSecretKey(SecureRandomUtils.generateRandomUUID().toString());
276 
277         obscureWithDecodeConversionPattern = plainSchemaDAO.save(obscureWithDecodeConversionPattern);
278 
279         UPlainAttr attr = entityFactory.newEntity(UPlainAttr.class);
280         attr.setSchema(obscureWithDecodeConversionPattern);
281         attr.add(validator, "testvalue", anyUtilsFactory.getInstance(AnyTypeKind.USER));
282 
283         assertEquals(Encryptor.getInstance(obscureWithDecodeConversionPattern.getSecretKey()).
284                 encode("testvalue", obscureWithDecodeConversionPattern.getCipherAlgorithm()),
285                 attr.getValues().get(0).getStringValue());
286 
287         obscureWithDecodeConversionPattern.setConversionPattern(SyncopeConstants.ENCRYPTED_DECODE_CONVERSION_PATTERN);
288         plainSchemaDAO.save(obscureWithDecodeConversionPattern);
289 
290         assertNotEquals("testvalue", attr.getValues().get(0).getStringValue());
291         assertEquals("testvalue", attr.getValuesAsStrings().get(0));
292     }
293 
294     @Test
295     public void saveWithBinary() throws UnsupportedEncodingException {
296         User user = userDAO.find("1417acbe-cbf6-4277-9372-e75e04f97000");
297 
298         PlainSchema photoSchema = plainSchemaDAO.find("photo");
299         assertNotNull(photoSchema);
300         assertNotNull(photoSchema.getMimeType());
301 
302         byte[] bytes = new byte[20];
303         new Random().nextBytes(bytes);
304         String photoB64Value = Base64.getEncoder().encodeToString(bytes);
305 
306         UPlainAttr attr = entityFactory.newEntity(UPlainAttr.class);
307         attr.setOwner(user);
308         attr.setSchema(photoSchema);
309         attr.add(validator, photoB64Value, anyUtilsFactory.getInstance(AnyTypeKind.USER));
310         user.add(attr);
311 
312         userDAO.save(user);
313 
314         UPlainAttr photo = user.getPlainAttr("photo").get();
315         assertNotNull(photo);
316         assertEquals(1, photo.getValues().size());
317         assertTrue(Arrays.equals(bytes, photo.getValues().get(0).getBinaryValue()));
318     }
319 
320     @Tag("plainAttrTable")
321     @Test
322     public void delete() {
323         UPlainAttr attribute = findPlainAttr("9d0d9e40-1b18-488e-9482-37dab82163c9", UPlainAttr.class);
324         String attrSchemaName = attribute.getSchema().getKey();
325 
326         plainAttrDAO.delete(attribute);
327 
328         PlainSchema schema = plainSchemaDAO.find(attrSchemaName);
329         assertNotNull(schema);
330     }
331 }