1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.syncope.wa.starter;
20
21 import com.fasterxml.jackson.databind.json.JsonMapper;
22 import com.fasterxml.jackson.jakarta.rs.json.JacksonJsonProvider;
23 import jakarta.ws.rs.NotFoundException;
24 import jakarta.ws.rs.core.Response;
25 import java.time.LocalDateTime;
26 import java.util.ArrayList;
27 import java.util.HashMap;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.Objects;
31 import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
32 import org.apache.cxf.jaxrs.lifecycle.SingletonResourceProvider;
33 import org.apache.syncope.common.keymaster.client.api.ServiceOps;
34 import org.apache.syncope.common.keymaster.client.api.model.NetworkService;
35 import org.apache.syncope.common.lib.Attr;
36 import org.apache.syncope.common.lib.to.AttrRepoTO;
37 import org.apache.syncope.common.lib.to.AuditConfTO;
38 import org.apache.syncope.common.lib.to.AuditEventTO;
39 import org.apache.syncope.common.lib.to.AuthModuleTO;
40 import org.apache.syncope.common.lib.to.PagedResult;
41 import org.apache.syncope.common.lib.to.PasswordManagementTO;
42 import org.apache.syncope.common.lib.types.ClientAppType;
43 import org.apache.syncope.common.lib.types.OpEvent;
44 import org.apache.syncope.common.lib.wa.GoogleMfaAuthToken;
45 import org.apache.syncope.common.lib.wa.ImpersonationAccount;
46 import org.apache.syncope.common.lib.wa.WAClientApp;
47 import org.apache.syncope.common.rest.api.beans.AuditQuery;
48 import org.apache.syncope.common.rest.api.service.AttrRepoService;
49 import org.apache.syncope.common.rest.api.service.AuditService;
50 import org.apache.syncope.common.rest.api.service.AuthModuleService;
51 import org.apache.syncope.common.rest.api.service.PasswordManagementService;
52 import org.apache.syncope.common.rest.api.service.wa.GoogleMfaAuthTokenService;
53 import org.apache.syncope.common.rest.api.service.wa.ImpersonationService;
54 import org.apache.syncope.common.rest.api.service.wa.WAClientAppService;
55 import org.apache.syncope.common.rest.api.service.wa.WAConfigService;
56 import org.springframework.beans.factory.annotation.Autowired;
57 import org.springframework.context.ApplicationListener;
58 import org.springframework.context.event.ContextRefreshedEvent;
59
60 public class SyncopeCoreTestingServer implements ApplicationListener<ContextRefreshedEvent> {
61
62 private static final String ADDRESS = "http://localhost:9081/syncope/rest";
63
64 public static final List<AuthModuleTO> AUTH_MODULES = new ArrayList<>();
65
66 public static final List<AttrRepoTO> ATTR_REPOS = new ArrayList<>();
67
68 public static final List<PasswordManagementTO> PASSWORD_MANAGEMENTS = new ArrayList<>();
69
70 public static final List<WAClientApp> CLIENT_APPS = new ArrayList<>();
71
72 public static final List<Attr> CONFIG = new ArrayList<>();
73
74 protected static class StubAuthModuleService implements AuthModuleService {
75
76 @Override
77 public AuthModuleTO read(final String key) {
78 return AUTH_MODULES.stream().filter(m -> Objects.equals(key, m.getKey())).
79 findFirst().orElseThrow(() -> new NotFoundException("AuthModule with key " + key));
80 }
81
82 @Override
83 public List<AuthModuleTO> list() {
84 return AUTH_MODULES;
85 }
86
87 @Override
88 public Response create(final AuthModuleTO authModuleTO) {
89 AUTH_MODULES.add(authModuleTO);
90 return Response.created(null).build();
91 }
92
93 @Override
94 public void update(final AuthModuleTO authModuleTO) {
95 delete(authModuleTO.getKey());
96 create(authModuleTO);
97 }
98
99 @Override
100 public void delete(final String key) {
101 AUTH_MODULES.removeIf(m -> Objects.equals(key, m.getKey()));
102 }
103 }
104
105 protected static class StubAttrRepoService implements AttrRepoService {
106
107 @Override
108 public AttrRepoTO read(final String key) {
109 return ATTR_REPOS.stream().filter(m -> Objects.equals(key, m.getKey())).
110 findFirst().orElseThrow(() -> new NotFoundException("Attr Repo with key " + key));
111 }
112
113 @Override
114 public List<AttrRepoTO> list() {
115 return ATTR_REPOS;
116 }
117
118 @Override
119 public Response create(final AttrRepoTO attrRepoTO) {
120 ATTR_REPOS.add(attrRepoTO);
121 return Response.created(null).build();
122 }
123
124 @Override
125 public void update(final AttrRepoTO attrRepoTO) {
126 delete(attrRepoTO.getKey());
127 create(attrRepoTO);
128 }
129
130 @Override
131 public void delete(final String key) {
132 ATTR_REPOS.removeIf(m -> Objects.equals(key, m.getKey()));
133 }
134 }
135
136 protected static class StubPasswordManagementService implements PasswordManagementService {
137
138 @Override
139 public PasswordManagementTO read(final String key) {
140 return PASSWORD_MANAGEMENTS.stream().filter(pm -> Objects.equals(key, pm.getKey())).
141 findFirst().orElseThrow(() -> new NotFoundException("Password Management with key " + key));
142 }
143
144 @Override
145 public List<PasswordManagementTO> list() {
146 return PASSWORD_MANAGEMENTS;
147 }
148
149 @Override
150 public Response create(final PasswordManagementTO passwordManagementTO) {
151 PASSWORD_MANAGEMENTS.add(passwordManagementTO);
152 return Response.created(null).build();
153 }
154
155 @Override
156 public void update(final PasswordManagementTO passwordManagementTO) {
157 delete(passwordManagementTO.getKey());
158 create(passwordManagementTO);
159 }
160
161 @Override
162 public void delete(final String key) {
163 PASSWORD_MANAGEMENTS.removeIf(pm -> Objects.equals(key, pm.getKey()));
164 }
165 }
166
167 protected static class StubWAClientAppService implements WAClientAppService {
168
169 @Override
170 public List<WAClientApp> list() {
171 return CLIENT_APPS;
172 }
173
174 @Override
175 public WAClientApp read(final Long clientAppId, final ClientAppType type) {
176 return CLIENT_APPS.stream().
177 filter(app -> Objects.equals(clientAppId, app.getClientAppTO().getClientAppId())).
178 findFirst().orElseThrow(() -> new NotFoundException("ClientApp with clientId " + clientAppId));
179 }
180
181 @Override
182 public WAClientApp read(final String name, final ClientAppType type) {
183 return CLIENT_APPS.stream().filter(app -> Objects.equals(name, app.getClientAppTO().getName())).
184 findFirst().orElseThrow(() -> new NotFoundException("ClientApp with name " + name));
185 }
186 }
187
188 protected static class StubWAConfigService implements WAConfigService {
189
190 @Override
191 public List<Attr> list() {
192 return CONFIG;
193 }
194
195 @Override
196 public Attr get(final String schema) {
197 return CONFIG.stream().filter(c -> Objects.equals(schema, c.getSchema())).
198 findFirst().orElseThrow(() -> new NotFoundException("Config with schema " + schema));
199 }
200
201 @Override
202 public void set(final Attr value) {
203 delete(value.getSchema());
204 CONFIG.add(value);
205 }
206
207 @Override
208 public void delete(final String schema) {
209 CONFIG.removeIf(c -> Objects.equals(schema, c.getSchema()));
210 }
211
212 @Override
213 public void pushToWA(final PushSubject subject, final List<String> services) {
214
215 }
216 }
217
218 protected static class StubImpersonationService implements ImpersonationService {
219
220 private final Map<String, List<ImpersonationAccount>> accounts = new HashMap<>();
221
222 @Override
223 public List<ImpersonationAccount> read(final String owner) {
224 return accounts.containsKey(owner) ? accounts.get(owner) : List.of();
225 }
226
227 @Override
228 public void create(final String owner, final ImpersonationAccount account) {
229 try {
230 if (accounts.containsKey(owner) && accounts.get(owner).stream().
231 noneMatch(acct -> acct.getImpersonated().equalsIgnoreCase(account.getImpersonated()))) {
232
233 accounts.get(owner).add(account);
234 } else {
235 List<ImpersonationAccount> list = new ArrayList<>();
236 list.add(account);
237 accounts.put(owner, list);
238 }
239 } catch (final Exception e) {
240 throw new IllegalStateException(e);
241 }
242 }
243
244 @Override
245 public void delete(final String owner, final String impersonated) {
246 if (accounts.containsKey(owner)) {
247 accounts.get(owner).removeIf(acct -> acct.getImpersonated().equalsIgnoreCase(impersonated));
248 }
249 }
250 }
251
252 protected static class StubGoogleMfaAuthTokenService implements GoogleMfaAuthTokenService {
253
254 private final Map<String, GoogleMfaAuthToken> tokens = new HashMap<>();
255
256 @Override
257 public void delete(final LocalDateTime expirationDate) {
258 if (expirationDate == null) {
259 tokens.clear();
260 } else {
261 tokens.entrySet().removeIf(token -> token.getValue().getIssueDate().compareTo(expirationDate) >= 0);
262 }
263 }
264
265 @Override
266 public void delete(final String owner, final int otp) {
267 tokens.entrySet().
268 removeIf(e -> e.getValue().getOtp() == otp && e.getKey().equalsIgnoreCase(owner));
269 }
270
271 @Override
272 public void delete(final String owner) {
273 tokens.entrySet().removeIf(e -> e.getKey().equalsIgnoreCase(owner));
274 }
275
276 @Override
277 public void delete(final int otp) {
278 tokens.entrySet().removeIf(to -> to.getValue().getOtp() == otp);
279 }
280
281 @Override
282 public void store(final String owner, final GoogleMfaAuthToken tokenTO) {
283 tokens.put(owner, tokenTO);
284 }
285
286 @Override
287 public GoogleMfaAuthToken read(final String owner, final int otp) {
288 return tokens.entrySet().stream().
289 filter(to -> to.getValue().getOtp() == otp && to.getKey().equalsIgnoreCase(owner)).
290 findFirst().get().getValue();
291 }
292
293 @Override
294 public PagedResult<GoogleMfaAuthToken> read(final String user) {
295 PagedResult<GoogleMfaAuthToken> result = new PagedResult<>();
296 result.getResult().addAll(tokens.entrySet().stream().
297 filter(to -> to.getKey().equalsIgnoreCase(user)).
298 map(Map.Entry::getValue).
299 toList());
300 result.setSize(result.getResult().size());
301 result.setTotalCount(result.getSize());
302 return result;
303 }
304
305 @Override
306 public PagedResult<GoogleMfaAuthToken> list() {
307 PagedResult<GoogleMfaAuthToken> result = new PagedResult<>();
308 result.setSize(tokens.size());
309 result.setTotalCount(tokens.size());
310 result.getResult().addAll(tokens.values());
311 return result;
312 }
313 }
314
315 protected static class StubAuditService implements AuditService {
316
317 @Override
318 public List<AuditConfTO> confs() {
319 return List.of();
320 }
321
322 @Override
323 public AuditConfTO getConf(final String key) {
324 throw new NotFoundException();
325 }
326
327 @Override
328 public void setConf(final AuditConfTO auditTO) {
329
330 }
331
332 @Override
333 public void deleteConf(final String key) {
334
335 }
336
337 @Override
338 public List<OpEvent> events() {
339 return List.of();
340 }
341
342 @Override
343 public PagedResult<AuditEventTO> search(final AuditQuery auditQuery) {
344 return new PagedResult<>();
345 }
346
347 @Override
348 public void create(final AuditEventTO auditEvent) {
349
350 }
351 }
352
353 @Autowired
354 private ServiceOps serviceOps;
355
356 @Override
357 public void onApplicationEvent(final ContextRefreshedEvent event) {
358 synchronized (ADDRESS) {
359 if (serviceOps.list(NetworkService.Type.CORE).isEmpty()) {
360
361 JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean();
362 sf.setAddress(ADDRESS);
363 sf.setResourceClasses(
364 AuditService.class,
365 AuthModuleService.class,
366 AttrRepoService.class,
367 PasswordManagementService.class,
368 WAClientAppService.class,
369 WAConfigService.class,
370 GoogleMfaAuthTokenService.class,
371 ImpersonationService.class);
372 sf.setResourceProvider(
373 AuditService.class,
374 new SingletonResourceProvider(new StubAuditService(), true));
375 sf.setResourceProvider(
376 AuthModuleService.class,
377 new SingletonResourceProvider(new StubAuthModuleService(), true));
378 sf.setResourceProvider(
379 AttrRepoService.class,
380 new SingletonResourceProvider(new StubAttrRepoService(), true));
381 sf.setResourceProvider(
382 PasswordManagementService.class,
383 new SingletonResourceProvider(new StubPasswordManagementService(), true));
384 sf.setResourceProvider(
385 WAClientAppService.class,
386 new SingletonResourceProvider(new StubWAClientAppService(), true));
387 sf.setResourceProvider(
388 WAConfigService.class,
389 new SingletonResourceProvider(new StubWAConfigService(), true));
390 sf.setResourceProvider(
391 GoogleMfaAuthTokenService.class,
392 new SingletonResourceProvider(new StubGoogleMfaAuthTokenService(), true));
393 sf.setResourceProvider(
394 ImpersonationService.class,
395 new SingletonResourceProvider(new StubImpersonationService(), true));
396 sf.setProviders(List.of(new JacksonJsonProvider(JsonMapper.builder().findAndAddModules().build())));
397 sf.create();
398
399
400 NetworkService core = new NetworkService();
401 core.setType(NetworkService.Type.CORE);
402 core.setAddress(ADDRESS);
403 serviceOps.register(core);
404 }
405 }
406 }
407 }