1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.syncope.fit.core;
20
21 import static org.awaitility.Awaitility.await;
22 import static org.junit.jupiter.api.Assertions.assertEquals;
23 import static org.junit.jupiter.api.Assertions.assertFalse;
24 import static org.junit.jupiter.api.Assertions.assertNotNull;
25 import static org.junit.jupiter.api.Assertions.assertNull;
26 import static org.junit.jupiter.api.Assertions.assertThrows;
27 import static org.junit.jupiter.api.Assertions.assertTrue;
28 import static org.junit.jupiter.api.Assertions.fail;
29 import static org.junit.jupiter.api.Assumptions.assumeTrue;
30
31 import java.security.AccessControlException;
32 import java.util.ArrayList;
33 import java.util.Date;
34 import java.util.List;
35 import java.util.Map;
36 import java.util.UUID;
37 import java.util.concurrent.TimeUnit;
38 import java.util.concurrent.atomic.AtomicReference;
39 import java.util.function.Function;
40 import javax.ws.rs.core.GenericType;
41 import javax.ws.rs.core.Response;
42 import org.apache.syncope.client.lib.SyncopeClientFactoryBean;
43 import org.apache.syncope.common.keymaster.client.api.KeymasterException;
44 import org.apache.syncope.common.keymaster.client.api.model.Domain;
45 import org.apache.syncope.common.keymaster.client.api.model.NetworkService;
46 import org.apache.syncope.common.keymaster.client.self.SelfKeymasterDomainOps;
47 import org.apache.syncope.common.lib.SyncopeConstants;
48 import org.apache.syncope.common.lib.request.UserCR;
49 import org.apache.syncope.common.lib.to.PagedResult;
50 import org.apache.syncope.common.lib.to.ProvisioningResult;
51 import org.apache.syncope.common.lib.to.UserTO;
52 import org.apache.syncope.common.lib.types.CipherAlgorithm;
53 import org.apache.syncope.common.rest.api.beans.AnyQuery;
54 import org.apache.syncope.common.rest.api.service.UserService;
55 import org.apache.syncope.core.spring.security.Encryptor;
56 import org.apache.syncope.fit.AbstractITCase;
57 import org.junit.jupiter.api.Test;
58
59 public class KeymasterITCase extends AbstractITCase {
60
61 @Test
62 public void confParamList() {
63 Map<String, Object> confParams = confParamOps.list(SyncopeConstants.MASTER_DOMAIN);
64 assertNotNull(confParams);
65 assertFalse(confParams.isEmpty());
66 }
67
68 @Test
69 public void confParamGet() {
70 String stringValue = confParamOps.get(
71 SyncopeConstants.MASTER_DOMAIN, "password.cipher.algorithm", null, String.class);
72 assertNotNull(stringValue);
73 assertEquals("SHA1", stringValue);
74
75 Long longValue = confParamOps.get(
76 SyncopeConstants.MASTER_DOMAIN, "jwt.lifetime.minutes", null, Long.class);
77 assertNotNull(longValue);
78 assertEquals(120L, longValue.longValue());
79
80 Boolean booleanValue = confParamOps.get(
81 SyncopeConstants.MASTER_DOMAIN, "return.password.value", null, Boolean.class);
82 assertNotNull(booleanValue);
83 assertEquals(false, booleanValue);
84
85 List<String> stringValues =
86 List.of(confParamOps.get(
87 SyncopeConstants.MASTER_DOMAIN, "authentication.attributes", null, String[].class));
88 assertNotNull(stringValues);
89 List<String> actualStringValues = new ArrayList<>();
90 actualStringValues.add("username");
91 actualStringValues.add("userId");
92 assertEquals(actualStringValues, stringValues);
93 }
94
95 @Test
96 public void confParamSetGetRemove() {
97 String key = UUID.randomUUID().toString();
98
99 String stringValue = "stringValue";
100 confParamOps.set(SyncopeConstants.MASTER_DOMAIN, key, stringValue);
101 String actualStringValue = confParamOps.get(SyncopeConstants.MASTER_DOMAIN, key, null, String.class);
102 assertEquals(stringValue, actualStringValue);
103
104 Long longValue = 1L;
105 confParamOps.set(SyncopeConstants.MASTER_DOMAIN, key, longValue);
106 Long actualLongValue = confParamOps.get(SyncopeConstants.MASTER_DOMAIN, key, null, Long.class);
107 assertEquals(longValue, actualLongValue);
108
109 Double doubleValue = 2.0;
110 confParamOps.set(SyncopeConstants.MASTER_DOMAIN, key, doubleValue);
111 Double actualDoubleValue = confParamOps.get(SyncopeConstants.MASTER_DOMAIN, key, null, Double.class);
112 assertEquals(doubleValue, actualDoubleValue);
113
114 Date dateValue = new Date();
115 confParamOps.set(SyncopeConstants.MASTER_DOMAIN, key, dateValue);
116 Date actualDateValue = confParamOps.get(SyncopeConstants.MASTER_DOMAIN, key, null, Date.class);
117 assertEquals(dateValue, actualDateValue);
118
119 Boolean booleanValue = true;
120 confParamOps.set(SyncopeConstants.MASTER_DOMAIN, key, booleanValue);
121 Boolean actualBooleanValue = confParamOps.get(SyncopeConstants.MASTER_DOMAIN, key, null, Boolean.class);
122 assertEquals(booleanValue, actualBooleanValue);
123
124 List<String> stringValues = new ArrayList<>();
125 stringValues.add("stringValue1");
126 stringValues.add("stringValue2");
127 confParamOps.set(SyncopeConstants.MASTER_DOMAIN, key, stringValues);
128 List<String> actualStringValues =
129 List.of(confParamOps.get(SyncopeConstants.MASTER_DOMAIN, key, null, String[].class));
130 assertEquals(stringValues, actualStringValues);
131
132 confParamOps.remove(SyncopeConstants.MASTER_DOMAIN, key);
133 assertNull(confParamOps.get(SyncopeConstants.MASTER_DOMAIN, key, null, String.class));
134 assertEquals(
135 "defaultValue",
136 confParamOps.get(SyncopeConstants.MASTER_DOMAIN, key, "defaultValue", String.class));
137 }
138
139 @Test
140 public void serviceList() {
141 List<NetworkService> services = serviceOps.list(NetworkService.Type.CORE);
142 assertFalse(services.isEmpty());
143 assertEquals(1, services.size());
144
145 services = serviceOps.list(NetworkService.Type.SRA);
146 assertTrue(services.isEmpty());
147
148 services = serviceOps.list(NetworkService.Type.WA);
149 assertTrue(services.isEmpty());
150 }
151
152 private List<NetworkService> findNetworkServices(
153 final NetworkService.Type type,
154 final Function<List<NetworkService>, Boolean> check,
155 final int maxWaitSeconds) {
156
157 AtomicReference<List<NetworkService>> holder = new AtomicReference<>();
158 await().atMost(maxWaitSeconds, TimeUnit.SECONDS).pollInterval(1, TimeUnit.SECONDS).until(() -> {
159 try {
160 holder.set(serviceOps.list(type));
161 return !check.apply(holder.get());
162 } catch (Exception e) {
163 return false;
164 }
165 });
166 return holder.get();
167 }
168
169 @Test
170 public void serviceRun() {
171 List<NetworkService> list = serviceOps.list(NetworkService.Type.SRA);
172 assertTrue(list.isEmpty());
173
174 NetworkService sra1 = new NetworkService();
175 sra1.setType(NetworkService.Type.SRA);
176 sra1.setAddress("http://localhost:9080/syncope-sra");
177 serviceOps.register(sra1);
178
179 list = findNetworkServices(NetworkService.Type.SRA, List::isEmpty, 30);
180 assertFalse(list.isEmpty());
181 assertEquals(1, list.size());
182 assertEquals(sra1, list.get(0));
183
184 assertEquals(sra1, serviceOps.get(NetworkService.Type.SRA));
185
186 NetworkService sra2 = new NetworkService();
187 sra2.setType(NetworkService.Type.SRA);
188 sra2.setAddress("http://localhost:9080/syncope-sra");
189 assertEquals(sra1, sra2);
190 serviceOps.register(sra2);
191
192 list = findNetworkServices(NetworkService.Type.SRA, List::isEmpty, 30);
193 assertFalse(list.isEmpty());
194 assertEquals(1, list.size());
195 assertEquals(sra1, list.get(0));
196
197 assertEquals(sra1, serviceOps.get(NetworkService.Type.SRA));
198
199 serviceOps.unregister(sra1);
200 list = findNetworkServices(NetworkService.Type.SRA, l -> !l.isEmpty(), 30);
201 assertTrue(list.isEmpty());
202
203 try {
204 serviceOps.get(NetworkService.Type.SRA);
205 fail();
206 } catch (KeymasterException e) {
207 assertNotNull(e);
208 }
209 }
210
211 @Test
212 public void domainCRUD() throws Exception {
213 List<Domain> initial = domainOps.list();
214 assertNotNull(initial);
215 assumeTrue(initial.stream().anyMatch(domain -> "Two".equals(domain.getKey())));
216
217
218 String key = UUID.randomUUID().toString();
219
220 domainOps.create(new Domain.Builder(key).
221 jdbcDriver("org.h2.Driver").
222 jdbcURL("jdbc:h2:mem:syncopetest" + key + ";DB_CLOSE_DELAY=-1").
223 dbUsername("sa").
224 dbPassword("").
225 databasePlatform("org.apache.openjpa.jdbc.sql.H2Dictionary").
226 transactionIsolation(Domain.TransactionIsolation.TRANSACTION_READ_UNCOMMITTED).
227 adminPassword(Encryptor.getInstance().encode("password", CipherAlgorithm.BCRYPT)).
228 adminCipherAlgorithm(CipherAlgorithm.BCRYPT).
229 build());
230
231 Domain domain = domainOps.read(key);
232 assertEquals(Domain.TransactionIsolation.TRANSACTION_READ_UNCOMMITTED, domain.getTransactionIsolation());
233 assertEquals(CipherAlgorithm.BCRYPT, domain.getAdminCipherAlgorithm());
234 assertEquals(10, domain.getPoolMaxActive());
235 assertEquals(2, domain.getPoolMinIdle());
236
237 assertEquals(domain, domainOps.read(key));
238
239
240 domainOps.adjustPoolSize(key, 100, 23);
241
242 domain = domainOps.read(key);
243 assertEquals(100, domain.getPoolMaxActive());
244 assertEquals(23, domain.getPoolMinIdle());
245
246
247
248
249
250
251
252
253
254
255
256
257
258 assumeTrue(domainOps instanceof SelfKeymasterDomainOps);
259
260
261 CLIENT_FACTORY = new SyncopeClientFactoryBean().setAddress(ADDRESS).setDomain(key);
262 ADMIN_CLIENT = CLIENT_FACTORY.create(ADMIN_UNAME, "password");
263
264 USER_SERVICE = ADMIN_CLIENT.getService(UserService.class);
265
266 PagedResult<UserTO> users = USER_SERVICE.search(
267 new AnyQuery.Builder().realm(SyncopeConstants.ROOT_REALM).page(1).size(1).build());
268 assertNotNull(users);
269 assertTrue(users.getResult().isEmpty());
270 assertEquals(0, users.getTotalCount());
271
272 Response response = USER_SERVICE.create(
273 new UserCR.Builder(SyncopeConstants.ROOT_REALM, "monteverdi").
274 password("password123").
275 plainAttr(attr("email", "monteverdi@syncope.apache.org")).
276 build());
277 assertEquals(Response.Status.CREATED.getStatusCode(), response.getStatus());
278
279 UserTO user = response.readEntity(new GenericType<ProvisioningResult<UserTO>>() {
280 }).getEntity();
281 assertNotNull(user);
282 assertEquals("monteverdi", user.getUsername());
283
284 if (IS_EXT_SEARCH_ENABLED) {
285 try {
286 Thread.sleep(2000);
287 } catch (InterruptedException ex) {
288
289 }
290 }
291
292 users = USER_SERVICE.search(
293 new AnyQuery.Builder().realm(SyncopeConstants.ROOT_REALM).page(1).size(1).build());
294 assertNotNull(users);
295 assertFalse(users.getResult().isEmpty());
296 assertEquals(1, users.getTotalCount());
297
298
299 domainOps.delete(key);
300
301 List<Domain> list = domainOps.list();
302 assertEquals(initial, list);
303 }
304
305 @Test
306 public void domainCreateMaster() {
307 assertThrows(
308 KeymasterException.class,
309 () -> domainOps.create(new Domain.Builder(SyncopeConstants.MASTER_DOMAIN).build()));
310 }
311
312 @Test
313 public void domainCreateDuplicateKey() {
314 assertThrows(KeymasterException.class, () -> domainOps.create(new Domain.Builder("Two").build()));
315 }
316
317 @Test
318 public void domainUpdateAdminPassword() throws Exception {
319 List<Domain> initial = domainOps.list();
320 assertNotNull(initial);
321 assumeTrue(initial.stream().anyMatch(domain -> "Two".equals(domain.getKey())));
322
323 Domain two = domainOps.read("Two");
324 assertNotNull(two);
325
326 String origPasswowrd = two.getAdminPassword();
327 CipherAlgorithm origCipherAlgo = two.getAdminCipherAlgorithm();
328
329 try {
330
331 domainOps.changeAdminPassword(
332 two.getKey(),
333 Encryptor.getInstance().encode("password3", CipherAlgorithm.AES),
334 CipherAlgorithm.AES);
335
336
337 try {
338 new SyncopeClientFactoryBean().
339 setAddress(ADDRESS).setDomain(two.getKey()).setContentType(CLIENT_FACTORY.getContentType()).
340 create(ADMIN_UNAME, "password2").self();
341 } catch (AccessControlException e) {
342 assertNotNull(e);
343 }
344
345
346 new SyncopeClientFactoryBean().
347 setAddress(ADDRESS).setDomain(two.getKey()).setContentType(CLIENT_FACTORY.getContentType()).
348 create(ADMIN_UNAME, "password3").self();
349 } finally {
350 domainOps.changeAdminPassword(two.getKey(), origPasswowrd, origCipherAlgo);
351 }
352 }
353 }