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