1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.syncope.client.console.authprofiles;
20
21 import de.agilecoders.wicket.core.markup.html.bootstrap.dialog.Modal;
22 import java.io.Serializable;
23 import java.util.ArrayList;
24 import java.util.Collection;
25 import java.util.Iterator;
26 import java.util.List;
27 import org.apache.syncope.client.console.SyncopeConsoleSession;
28 import org.apache.syncope.client.console.authprofiles.AuthProfileDirectoryPanel.AuthProfileProvider;
29 import org.apache.syncope.client.console.commons.AMConstants;
30 import org.apache.syncope.client.console.commons.DirectoryDataProvider;
31 import org.apache.syncope.client.console.panels.DirectoryPanel;
32 import org.apache.syncope.client.console.panels.ModalDirectoryPanel;
33 import org.apache.syncope.client.console.rest.AuthProfileRestClient;
34 import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.BooleanConditionColumn;
35 import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.DatePropertyColumn;
36 import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.KeyPropertyColumn;
37 import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
38 import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
39 import org.apache.syncope.client.console.wicket.markup.html.form.ActionsPanel;
40 import org.apache.syncope.client.ui.commons.Constants;
41 import org.apache.syncope.client.ui.commons.markup.html.form.AjaxTextFieldPanel;
42 import org.apache.syncope.client.ui.commons.pages.BaseWebPage;
43 import org.apache.syncope.common.lib.to.AuthProfileTO;
44 import org.apache.syncope.common.lib.types.AMEntitlement;
45 import org.apache.syncope.common.lib.wa.GoogleMfaAuthAccount;
46 import org.apache.syncope.common.lib.wa.GoogleMfaAuthToken;
47 import org.apache.syncope.common.lib.wa.ImpersonationAccount;
48 import org.apache.syncope.common.lib.wa.MfaTrustedDevice;
49 import org.apache.syncope.common.lib.wa.U2FDevice;
50 import org.apache.syncope.common.lib.wa.WebAuthnDeviceCredential;
51 import org.apache.wicket.PageReference;
52 import org.apache.wicket.ajax.AjaxRequestTarget;
53 import org.apache.wicket.authroles.authorization.strategies.role.metadata.MetaDataRoleAuthorizationStrategy;
54 import org.apache.wicket.extensions.markup.html.repeater.data.sort.SortOrder;
55 import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
56 import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn;
57 import org.apache.wicket.extensions.wizard.WizardModel;
58 import org.apache.wicket.model.CompoundPropertyModel;
59 import org.apache.wicket.model.IModel;
60 import org.apache.wicket.model.Model;
61 import org.apache.wicket.model.PropertyModel;
62 import org.apache.wicket.model.ResourceModel;
63 import org.apache.wicket.model.StringResourceModel;
64
65 public class AuthProfileDirectoryPanel
66 extends DirectoryPanel<AuthProfileTO, AuthProfileTO, AuthProfileProvider, AuthProfileRestClient> {
67
68 private static final long serialVersionUID = 2018518567549153364L;
69
70 private final BaseModal<AuthProfileTO> authProfileModal;
71
72 public AuthProfileDirectoryPanel(
73 final String id, final AuthProfileRestClient restClient, final PageReference pageRef) {
74
75 super(id, restClient, pageRef);
76
77 authProfileModal = new BaseModal<>(Constants.OUTER) {
78
79 private static final long serialVersionUID = 389935548143327858L;
80
81 @Override
82 protected void onConfigure() {
83 super.onConfigure();
84 setFooterVisible(false);
85 }
86 };
87 authProfileModal.size(Modal.Size.Large);
88 authProfileModal.setWindowClosedCallback(target -> {
89 updateResultTable(target);
90 authProfileModal.show(false);
91 });
92 addOuterObject(authProfileModal);
93
94 addNewItemPanelBuilder(new CreateAuthProfileWizardBuilder(pageRef), true);
95 MetaDataRoleAuthorizationStrategy.authorize(addAjaxLink, RENDER, AMEntitlement.AUTH_PROFILE_CREATE);
96
97 disableCheckBoxes();
98 initResultTable();
99 }
100
101 @Override
102 protected AuthProfileProvider dataProvider() {
103 return new AuthProfileProvider(rows);
104 }
105
106 @Override
107 protected String paginatorRowsKey() {
108 return AMConstants.PREF_AUTHPROFILE_PAGINATOR_ROWS;
109 }
110
111 @Override
112 protected Collection<ActionLink.ActionType> getBatches() {
113 return List.of();
114 }
115
116 @Override
117 protected List<IColumn<AuthProfileTO, String>> getColumns() {
118 List<IColumn<AuthProfileTO, String>> columns = new ArrayList<>();
119
120 columns.add(new KeyPropertyColumn<>(
121 new StringResourceModel(Constants.KEY_FIELD_NAME, this), Constants.KEY_FIELD_NAME));
122
123 columns.add(new PropertyColumn<>(new ResourceModel("owner"), "owner", "owner"));
124
125 columns.add(new BooleanConditionColumn<>(new StringResourceModel("impersonationAccounts")) {
126
127 private static final long serialVersionUID = -8236820422411536323L;
128
129 @Override
130 protected boolean isCondition(final IModel<AuthProfileTO> rowModel) {
131 return !rowModel.getObject().getImpersonationAccounts().isEmpty();
132 }
133 });
134 columns.add(new BooleanConditionColumn<>(new StringResourceModel("googleMfaAuthTokens")) {
135
136 private static final long serialVersionUID = -8236820422411536323L;
137
138 @Override
139 protected boolean isCondition(final IModel<AuthProfileTO> rowModel) {
140 return !rowModel.getObject().getGoogleMfaAuthTokens().isEmpty();
141 }
142 });
143 columns.add(new BooleanConditionColumn<>(new StringResourceModel("googleMfaAuthAccounts")) {
144
145 private static final long serialVersionUID = -8236820422411536323L;
146
147 @Override
148 protected boolean isCondition(final IModel<AuthProfileTO> rowModel) {
149 return !rowModel.getObject().getGoogleMfaAuthAccounts().isEmpty();
150 }
151 });
152 columns.add(new BooleanConditionColumn<>(new StringResourceModel("u2fRegisteredDevices")) {
153
154 private static final long serialVersionUID = -8236820422411536323L;
155
156 @Override
157 protected boolean isCondition(final IModel<AuthProfileTO> rowModel) {
158 return !rowModel.getObject().getU2FRegisteredDevices().isEmpty();
159 }
160 });
161 columns.add(new BooleanConditionColumn<>(new StringResourceModel("mfaTrustedDevices")) {
162
163 private static final long serialVersionUID = -8236820422411536323L;
164
165 @Override
166 protected boolean isCondition(final IModel<AuthProfileTO> rowModel) {
167 return !rowModel.getObject().getMfaTrustedDevices().isEmpty();
168 }
169 });
170 columns.add(new BooleanConditionColumn<>(new StringResourceModel("webAuthnAccount")) {
171
172 private static final long serialVersionUID = -8236820422411536323L;
173
174 @Override
175 protected boolean isCondition(final IModel<AuthProfileTO> rowModel) {
176 return !rowModel.getObject().getWebAuthnDeviceCredentials().isEmpty();
177 }
178 });
179
180 return columns;
181 }
182
183 @Override
184 public ActionsPanel<AuthProfileTO> getActions(final IModel<AuthProfileTO> model) {
185 ActionsPanel<AuthProfileTO> panel = super.getActions(model);
186
187 panel.add(new ActionLink<>() {
188
189 private static final long serialVersionUID = -3722207913631435501L;
190
191 @Override
192 public void onClick(final AjaxRequestTarget target, final AuthProfileTO ignore) {
193 model.setObject(restClient.read(model.getObject().getKey()));
194 target.add(authProfileModal.setContent(new ModalDirectoryPanel<>(
195 authProfileModal,
196 new AuthProfileItemDirectoryPanel<ImpersonationAccount>(
197 "panel", restClient, authProfileModal, model.getObject(), pageRef) {
198
199 private static final long serialVersionUID = -5380664539000792237L;
200
201 @Override
202 protected List<ImpersonationAccount> getItems() {
203 return model.getObject().getImpersonationAccounts();
204 }
205
206 @Override
207 protected ImpersonationAccount defaultItem() {
208 return new ImpersonationAccount();
209 }
210
211 @Override
212 protected String sortProperty() {
213 return "impersonated";
214 }
215
216 @Override
217 protected String paginatorRowsKey() {
218 return AMConstants.PREF_AUTHPROFILE_IMPERSONATED_PAGINATOR_ROWS;
219 }
220
221 @Override
222 protected List<IColumn<ImpersonationAccount, String>> getColumns() {
223 List<IColumn<ImpersonationAccount, String>> columns = new ArrayList<>();
224 columns.add(new PropertyColumn<>(new ResourceModel("impersonated"),
225 "impersonated", "impersonated"));
226 return columns;
227 }
228 }, pageRef)));
229 authProfileModal.header(new Model<>(getString("impersonationAccounts", model)));
230 authProfileModal.show(true);
231 }
232 }, ActionLink.ActionType.TYPE_EXTENSIONS, AMEntitlement.AUTH_PROFILE_UPDATE);
233
234 panel.add(new ActionLink<>() {
235
236 private static final long serialVersionUID = -3722207913631435501L;
237
238 @Override
239 public void onClick(final AjaxRequestTarget target, final AuthProfileTO ignore) {
240 model.setObject(restClient.read(model.getObject().getKey()));
241 target.add(authProfileModal.setContent(new ModalDirectoryPanel<>(
242 authProfileModal,
243 new AuthProfileItemDirectoryPanel<GoogleMfaAuthToken>(
244 "panel", restClient, authProfileModal, model.getObject(), pageRef) {
245
246 private static final long serialVersionUID = 7332357430197837993L;
247
248 @Override
249 protected List<GoogleMfaAuthToken> getItems() {
250 return model.getObject().getGoogleMfaAuthTokens();
251 }
252
253 @Override
254 protected GoogleMfaAuthToken defaultItem() {
255 return new GoogleMfaAuthToken();
256 }
257
258 @Override
259 protected String sortProperty() {
260 return "issueDate";
261 }
262
263 @Override
264 protected String paginatorRowsKey() {
265 return AMConstants.PREF_AUTHPROFILE_GOOGLEMFAAUTHTOKENS_PAGINATOR_ROWS;
266 }
267
268 @Override
269 protected List<IColumn<GoogleMfaAuthToken, String>> getColumns() {
270 List<IColumn<GoogleMfaAuthToken, String>> columns = new ArrayList<>();
271 columns.add(new DatePropertyColumn<>(
272 new ResourceModel("issueDate"), "issueDate", "issueDate"));
273 columns.add(new PropertyColumn<>(
274 new ResourceModel("otp"), "otp", "otp"));
275 return columns;
276 }
277 }, pageRef)));
278 authProfileModal.header(new Model<>(getString("googleMfaAuthTokens", model)));
279 authProfileModal.show(true);
280 }
281 }, ActionLink.ActionType.EDIT_APPROVAL, AMEntitlement.AUTH_PROFILE_UPDATE);
282
283 panel.add(new ActionLink<>() {
284
285 private static final long serialVersionUID = -3722207913631435501L;
286
287 @Override
288 public void onClick(final AjaxRequestTarget target, final AuthProfileTO ignore) {
289 model.setObject(restClient.read(model.getObject().getKey()));
290 target.add(authProfileModal.setContent(new ModalDirectoryPanel<>(
291 authProfileModal,
292 new AuthProfileItemDirectoryPanel<GoogleMfaAuthAccount>(
293 "panel", restClient, authProfileModal, model.getObject(), pageRef) {
294
295 private static final long serialVersionUID = -670769282358547044L;
296
297 @Override
298 protected List<GoogleMfaAuthAccount> getItems() {
299 return model.getObject().getGoogleMfaAuthAccounts();
300 }
301
302 @Override
303 protected GoogleMfaAuthAccount defaultItem() {
304 return new GoogleMfaAuthAccount();
305 }
306
307 @Override
308 protected String sortProperty() {
309 return "id";
310 }
311
312 @Override
313 protected String paginatorRowsKey() {
314 return AMConstants.PREF_AUTHPROFILE_GOOGLEMFAAUTHACCOUNTS_PAGINATOR_ROWS;
315 }
316
317 @Override
318 protected List<IColumn<GoogleMfaAuthAccount, String>> getColumns() {
319 List<IColumn<GoogleMfaAuthAccount, String>> columns = new ArrayList<>();
320 columns.add(new PropertyColumn<>(new ResourceModel("id"), "id", "id"));
321 columns.add(new DatePropertyColumn<>(
322 new ResourceModel("registrationDate"), "registrationDate", "registrationDate"));
323 columns.add(new PropertyColumn<>(new ResourceModel("name"), "name", "name"));
324 return columns;
325 }
326 }, pageRef)));
327 authProfileModal.header(new Model<>(getString("googleMfaAuthAccounts", model)));
328 authProfileModal.show(true);
329 }
330 }, ActionLink.ActionType.EXECUTE, AMEntitlement.AUTH_PROFILE_UPDATE);
331
332 panel.add(new ActionLink<>() {
333
334 private static final long serialVersionUID = -3722207913631435501L;
335
336 @Override
337 public void onClick(final AjaxRequestTarget target, final AuthProfileTO ignore) {
338 model.setObject(restClient.read(model.getObject().getKey()));
339 target.add(authProfileModal.setContent(new ModalDirectoryPanel<>(
340 authProfileModal,
341 new AuthProfileItemDirectoryPanel<U2FDevice>(
342 "panel", restClient, authProfileModal, model.getObject(), pageRef) {
343
344 private static final long serialVersionUID = 5788448799796630011L;
345
346 @Override
347 protected List<U2FDevice> getItems() {
348 return model.getObject().getU2FRegisteredDevices();
349 }
350
351 @Override
352 protected U2FDevice defaultItem() {
353 return new U2FDevice();
354 }
355
356 @Override
357 protected String sortProperty() {
358 return "id";
359 }
360
361 @Override
362 protected String paginatorRowsKey() {
363 return AMConstants.PREF_AUTHPROFILE_U2FDEVICES_PAGINATOR_ROWS;
364 }
365
366 @Override
367 protected List<IColumn<U2FDevice, String>> getColumns() {
368 List<IColumn<U2FDevice, String>> columns = new ArrayList<>();
369 columns.add(new PropertyColumn<>(new ResourceModel("id"), "id", "id"));
370 columns.add(new DatePropertyColumn<>(
371 new ResourceModel("issueDate"), "issueDate", "issueDate"));
372 columns.add(new PropertyColumn<>(new ResourceModel("record"), "record", "record"));
373 return columns;
374 }
375 }, pageRef)));
376 authProfileModal.header(new Model<>(getString("u2fRegisteredDevices", model)));
377 authProfileModal.show(true);
378 }
379 }, ActionLink.ActionType.DEPROVISION, AMEntitlement.AUTH_PROFILE_UPDATE);
380
381 panel.add(new ActionLink<>() {
382
383 private static final long serialVersionUID = -3722207913631435501L;
384
385 @Override
386 public void onClick(final AjaxRequestTarget target, final AuthProfileTO ignore) {
387 model.setObject(restClient.read(model.getObject().getKey()));
388 target.add(authProfileModal.setContent(new ModalDirectoryPanel<>(
389 authProfileModal,
390 new AuthProfileItemDirectoryPanel<MfaTrustedDevice>(
391 "panel", restClient, authProfileModal, model.getObject(), pageRef) {
392
393 private static final long serialVersionUID = 5788448799796630011L;
394
395 @Override
396 protected List<MfaTrustedDevice> getItems() {
397 return model.getObject().getMfaTrustedDevices();
398 }
399
400 @Override
401 protected MfaTrustedDevice defaultItem() {
402 return new MfaTrustedDevice();
403 }
404
405 @Override
406 protected String sortProperty() {
407 return "id";
408 }
409
410 @Override
411 protected String paginatorRowsKey() {
412 return AMConstants.PREF_AUTHPROFILE_MFA_TRUSTED_FDEVICES_PAGINATOR_ROWS;
413 }
414
415 @Override
416 protected List<IColumn<MfaTrustedDevice, String>> getColumns() {
417 List<IColumn<MfaTrustedDevice, String>> columns = new ArrayList<>();
418 columns.add(new PropertyColumn<>(new ResourceModel("id"), "id", "id"));
419 columns.add(new PropertyColumn<>(new ResourceModel("name"), "name", "name"));
420 columns.add(new DatePropertyColumn<>(
421 new ResourceModel("recordDate"), "recordDate", "recordDate"));
422 columns.add(new DatePropertyColumn<>(
423 new ResourceModel("expirationDate"), "expirationDate", "expirationDate"));
424 return columns;
425 }
426 }, pageRef)));
427 authProfileModal.header(new Model<>(getString("mfaTrustedDevices", model)));
428 authProfileModal.show(true);
429 }
430 }, ActionLink.ActionType.DOWN, AMEntitlement.AUTH_PROFILE_UPDATE);
431
432 panel.add(new ActionLink<>() {
433
434 private static final long serialVersionUID = -3722207913631435501L;
435
436 @Override
437 public void onClick(final AjaxRequestTarget target, final AuthProfileTO ignore) {
438 model.setObject(restClient.read(model.getObject().getKey()));
439 target.add(authProfileModal.setContent(new ModalDirectoryPanel<>(
440 authProfileModal,
441 new AuthProfileItemDirectoryPanel<WebAuthnDeviceCredential>(
442 "panel", restClient, authProfileModal, model.getObject(), pageRef) {
443
444 private static final long serialVersionUID = 6820212423488933184L;
445
446 @Override
447 protected List<WebAuthnDeviceCredential> getItems() {
448 return model.getObject().getWebAuthnDeviceCredentials();
449 }
450
451 @Override
452 protected WebAuthnDeviceCredential defaultItem() {
453 return new WebAuthnDeviceCredential();
454 }
455
456 @Override
457 protected String sortProperty() {
458 return "identifier";
459 }
460
461 @Override
462 protected String paginatorRowsKey() {
463 return AMConstants.PREF_AUTHPROFILE_WEBAUTHNDEVICECREDENTIALS_PAGINATOR_ROWS;
464 }
465
466 @Override
467 protected List<IColumn<WebAuthnDeviceCredential, String>> getColumns() {
468 List<IColumn<WebAuthnDeviceCredential, String>> columns = new ArrayList<>();
469 columns.add(new PropertyColumn<>(
470 new ResourceModel("identifier"), "identifier", "identifier"));
471 columns.add(new PropertyColumn<>(
472 new ResourceModel("json"), "json", "json"));
473 return columns;
474 }
475 }, pageRef)));
476 authProfileModal.header(new Model<>(getString("webAuthnDeviceCredentials", model)));
477 authProfileModal.show(true);
478 }
479 }, ActionLink.ActionType.HTML, AMEntitlement.AUTH_PROFILE_UPDATE);
480
481 panel.add(new ActionLink<>() {
482
483 private static final long serialVersionUID = -3722207913631435501L;
484
485 @Override
486 public void onClick(final AjaxRequestTarget target, final AuthProfileTO ignore) {
487 try {
488 restClient.delete(model.getObject().getKey());
489
490 SyncopeConsoleSession.get().success(getString(Constants.OPERATION_SUCCEEDED));
491 target.add(container);
492 } catch (Exception e) {
493 LOG.error("While deleting {}", model.getObject().getKey(), e);
494 SyncopeConsoleSession.get().onException(e);
495 }
496 ((BaseWebPage) pageRef.getPage()).getNotificationPanel().refresh(target);
497 }
498 }, ActionLink.ActionType.DELETE, AMEntitlement.AUTH_PROFILE_DELETE, true);
499
500 return panel;
501 }
502
503 protected final class AuthProfileProvider extends DirectoryDataProvider<AuthProfileTO> {
504
505 private static final long serialVersionUID = -185944053385660794L;
506
507 private AuthProfileProvider(final int paginatorRows) {
508 super(paginatorRows);
509 setSort("owner", SortOrder.ASCENDING);
510 }
511
512 @Override
513 public Iterator<AuthProfileTO> iterator(final long first, final long count) {
514 int page = ((int) first / paginatorRows);
515 return restClient.list((page < 0 ? 0 : page) + 1, paginatorRows).iterator();
516 }
517
518 @Override
519 public long size() {
520 return restClient.count();
521 }
522
523 @Override
524 public IModel<AuthProfileTO> model(final AuthProfileTO object) {
525 return new CompoundPropertyModel<>(object);
526 }
527 }
528
529 private class CreateAuthProfileWizardBuilder extends AuthProfileWizardBuilder<AuthProfileTO> {
530
531 private static final long serialVersionUID = -2478221092672979490L;
532
533 private class NewAuthProfileStep extends AuthProfileWizardBuilder<AuthProfileTO>.Step {
534
535 private static final long serialVersionUID = 6290450377240300418L;
536
537 NewAuthProfileStep(final AuthProfileTO modelObject) {
538 super(modelObject);
539
540 AjaxTextFieldPanel owner = new AjaxTextFieldPanel(
541 "bean", "owner", new PropertyModel<>(modelObject, "owner"));
542 owner.addRequiredLabel();
543 addOrReplace(owner);
544 }
545 }
546
547 CreateAuthProfileWizardBuilder(final PageReference pageRef) {
548 super(new AuthProfileTO(), new StepModel<>(), pageRef);
549 }
550
551 @Override
552 protected WizardModel buildModelSteps(final AuthProfileTO modelObject, final WizardModel wizardModel) {
553 wizardModel.add(new NewAuthProfileStep(modelObject));
554 return wizardModel;
555 }
556
557 @Override
558 protected Serializable onApplyInternal(final AuthProfileTO modelObject) {
559 restClient.create(modelObject);
560 return modelObject;
561 }
562 }
563 }