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.client.console.panels;
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.commons.lang3.StringUtils;
28  import org.apache.syncope.client.console.SyncopeConsoleSession;
29  import org.apache.syncope.client.console.commons.DirectoryDataProvider;
30  import org.apache.syncope.client.console.commons.IdMConstants;
31  import org.apache.syncope.client.console.layout.AnyLayoutUtils;
32  import org.apache.syncope.client.console.layout.AnyObjectFormLayoutInfo;
33  import org.apache.syncope.client.console.layout.GroupFormLayoutInfo;
34  import org.apache.syncope.client.console.layout.UserFormLayoutInfo;
35  import org.apache.syncope.client.console.pages.BasePage;
36  import org.apache.syncope.client.console.panels.RemediationDirectoryPanel.RemediationProvider;
37  import org.apache.syncope.client.console.rest.AnyObjectRestClient;
38  import org.apache.syncope.client.console.rest.AnyTypeRestClient;
39  import org.apache.syncope.client.console.rest.GroupRestClient;
40  import org.apache.syncope.client.console.rest.RemediationRestClient;
41  import org.apache.syncope.client.console.rest.RoleRestClient;
42  import org.apache.syncope.client.console.rest.UserRestClient;
43  import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.DatePropertyColumn;
44  import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.KeyPropertyColumn;
45  import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
46  import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
47  import org.apache.syncope.client.console.wicket.markup.html.form.ActionsPanel;
48  import org.apache.syncope.client.console.wizards.any.AnyObjectWizardBuilder;
49  import org.apache.syncope.client.console.wizards.any.GroupWizardBuilder;
50  import org.apache.syncope.client.console.wizards.any.UserWizardBuilder;
51  import org.apache.syncope.client.ui.commons.Constants;
52  import org.apache.syncope.client.ui.commons.wizards.AjaxWizard;
53  import org.apache.syncope.client.ui.commons.wizards.any.AnyWrapper;
54  import org.apache.syncope.common.lib.AnyOperations;
55  import org.apache.syncope.common.lib.EntityTOUtils;
56  import org.apache.syncope.common.lib.SyncopeClientException;
57  import org.apache.syncope.common.lib.request.AnyObjectCR;
58  import org.apache.syncope.common.lib.request.AnyObjectUR;
59  import org.apache.syncope.common.lib.request.GroupCR;
60  import org.apache.syncope.common.lib.request.GroupUR;
61  import org.apache.syncope.common.lib.request.PasswordPatch;
62  import org.apache.syncope.common.lib.request.UserCR;
63  import org.apache.syncope.common.lib.request.UserUR;
64  import org.apache.syncope.common.lib.to.AnyObjectTO;
65  import org.apache.syncope.common.lib.to.GroupTO;
66  import org.apache.syncope.common.lib.to.ProvisioningResult;
67  import org.apache.syncope.common.lib.to.RemediationTO;
68  import org.apache.syncope.common.lib.to.UserTO;
69  import org.apache.syncope.common.lib.types.AnyEntitlement;
70  import org.apache.syncope.common.lib.types.AnyTypeKind;
71  import org.apache.syncope.common.lib.types.IdMEntitlement;
72  import org.apache.syncope.common.lib.types.IdRepoEntitlement;
73  import org.apache.syncope.common.lib.types.ResourceOperation;
74  import org.apache.wicket.PageReference;
75  import org.apache.wicket.ajax.AjaxRequestTarget;
76  import org.apache.wicket.authroles.authorization.strategies.role.metadata.MetaDataRoleAuthorizationStrategy;
77  import org.apache.wicket.event.Broadcast;
78  import org.apache.wicket.extensions.markup.html.repeater.data.sort.SortOrder;
79  import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
80  import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn;
81  import org.apache.wicket.model.CompoundPropertyModel;
82  import org.apache.wicket.model.IModel;
83  import org.apache.wicket.model.ResourceModel;
84  import org.apache.wicket.model.StringResourceModel;
85  import org.apache.wicket.spring.injection.annot.SpringBean;
86  
87  public class RemediationDirectoryPanel
88          extends DirectoryPanel<RemediationTO, RemediationTO, RemediationProvider, RemediationRestClient> {
89  
90      private static final long serialVersionUID = 8525204188127106587L;
91  
92      @SpringBean
93      protected AnyTypeRestClient anyTypeRestClient;
94  
95      @SpringBean
96      protected RoleRestClient roleRestClient;
97  
98      @SpringBean
99      protected UserRestClient userRestClient;
100 
101     @SpringBean
102     protected GroupRestClient groupRestClient;
103 
104     @SpringBean
105     protected AnyObjectRestClient anyObjectRestClient;
106 
107     public RemediationDirectoryPanel(
108             final String id,
109             final RemediationRestClient restClient,
110             final PageReference pageRef) {
111 
112         super(id, restClient, pageRef, true);
113         disableCheckBoxes();
114         setFooterVisibility(false);
115         modal.size(Modal.Size.Large);
116 
117         initResultTable();
118 
119         MetaDataRoleAuthorizationStrategy.authorize(addAjaxLink, RENDER, IdMEntitlement.REMEDIATION_REMEDY);
120     }
121 
122     @Override
123     protected List<IColumn<RemediationTO, String>> getColumns() {
124         List<IColumn<RemediationTO, String>> columns = new ArrayList<>();
125 
126         columns.add(new KeyPropertyColumn<>(
127                 new StringResourceModel(Constants.KEY_FIELD_NAME, this), Constants.KEY_FIELD_NAME));
128         columns.add(new PropertyColumn<>(
129                 new ResourceModel("operation"), "operation", "operation"));
130         columns.add(new PropertyColumn<>(
131                 new ResourceModel("anyType"), "anyType", "anyType"));
132         columns.add(new PropertyColumn<>(
133                 new ResourceModel("remoteName"), "remoteName", "remoteName"));
134         columns.add(new PropertyColumn<>(
135                 new ResourceModel("resource"), "resource", "resource"));
136         columns.add(new DatePropertyColumn<>(
137                 new ResourceModel("instant"), "instant", "instant"));
138 
139         return columns;
140     }
141 
142     @Override
143     protected ActionsPanel<RemediationTO> getActions(final IModel<RemediationTO> model) {
144         ActionsPanel<RemediationTO> panel = super.getActions(model);
145 
146         panel.add(new ActionLink<>() {
147 
148             private static final long serialVersionUID = 6193210574968203299L;
149 
150             @Override
151             public void onClick(final AjaxRequestTarget target, final RemediationTO ignore) {
152                 modal.header(new ResourceModel("error"));
153                 modal.setContent(new ExecMessageModal(model.getObject().getError()));
154                 modal.show(true);
155                 target.add(modal);
156             }
157         }, ActionLink.ActionType.VIEW_DETAILS, IdMEntitlement.REMEDIATION_READ);
158 
159         if (model.getObject().getOperation() == ResourceOperation.DELETE) {
160             String entitlements = StringUtils.join(new String[] {
161                 IdMEntitlement.REMEDIATION_REMEDY,
162                 AnyTypeKind.USER.name().equals(model.getObject().getAnyType())
163                 ? IdRepoEntitlement.USER_DELETE
164                 : AnyTypeKind.GROUP.name().equals(model.getObject().getAnyType())
165                 ? IdRepoEntitlement.GROUP_DELETE
166                 : AnyEntitlement.DELETE.getFor(model.getObject().getAnyType()) }, ",");
167 
168             panel.add(new ActionLink<>() {
169 
170                 private static final long serialVersionUID = 6193210574968203299L;
171 
172                 @Override
173                 public void onClick(final AjaxRequestTarget target, final RemediationTO ignore) {
174                     try {
175                         restClient.remedy(model.getObject().getKey(), model.getObject().getKeyPayload());
176 
177                         SyncopeConsoleSession.get().success(getString(Constants.OPERATION_SUCCEEDED));
178                         target.add(container);
179                     } catch (SyncopeClientException e) {
180                         LOG.error("While performing remediation {}", model.getObject().getKey(), e);
181                         SyncopeConsoleSession.get().onException(e);
182                     }
183                     ((BasePage) pageRef.getPage()).getNotificationPanel().refresh(target);
184                 }
185             }, ActionLink.ActionType.CLOSE, entitlements, true);
186         } else {
187             String entitlements = model.getObject().getOperation() == ResourceOperation.CREATE
188                     ? StringUtils.join(new String[] {
189                 IdMEntitlement.REMEDIATION_REMEDY,
190                 AnyTypeKind.USER.name().equals(model.getObject().getAnyType())
191                 ? IdRepoEntitlement.USER_CREATE
192                 : AnyTypeKind.GROUP.name().equals(model.getObject().getAnyType())
193                 ? IdRepoEntitlement.GROUP_CREATE
194                 : AnyEntitlement.CREATE.getFor(model.getObject().getAnyType()) }, ",")
195                     : StringUtils.join(new String[] {
196                 IdMEntitlement.REMEDIATION_REMEDY,
197                 AnyTypeKind.USER.name().equals(model.getObject().getAnyType())
198                 ? IdRepoEntitlement.USER_UPDATE
199                 : AnyTypeKind.GROUP.name().equals(model.getObject().getAnyType())
200                 ? IdRepoEntitlement.GROUP_UPDATE
201                 : AnyEntitlement.UPDATE.getFor(model.getObject().getAnyType()) }, ",");
202 
203             panel.add(new ActionLink<>() {
204 
205                 private static final long serialVersionUID = 6193210574968203299L;
206 
207                 @Override
208                 public void onClick(final AjaxRequestTarget target, final RemediationTO ignore) {
209                     modal.setFormModel(new CompoundPropertyModel<>(model.getObject()));
210                     RemediationTO remediationTO = model.getObject();
211 
212                     switch (remediationTO.getAnyType()) {
213                         case "USER":
214                             UserTO newUserTO;
215                             UserTO previousUserTO;
216                             if (remediationTO.getAnyURPayload() == null) {
217                                 newUserTO = new UserTO();
218                                 EntityTOUtils.toAnyTO(remediationTO.getAnyCRPayload(), newUserTO);
219                                 previousUserTO = null;
220                             } else {
221                                 previousUserTO = userRestClient.read(remediationTO.getAnyURPayload().getKey());
222                                 newUserTO = AnyOperations.patch(
223                                         previousUserTO, (UserUR) remediationTO.getAnyURPayload());
224                             }
225 
226                             AjaxWizard.EditItemActionEvent<UserTO> userEvent =
227                                     new AjaxWizard.EditItemActionEvent<>(newUserTO, target);
228                             userEvent.forceModalPanel(new RemediationUserWizardBuilder(
229                                     model.getObject(),
230                                     previousUserTO,
231                                     newUserTO,
232                                     anyTypeRestClient.read(remediationTO.getAnyType()).getClasses(),
233                                     AnyLayoutUtils.fetch(roleRestClient, List.of(remediationTO.getAnyType())).getUser(),
234                                     userRestClient,
235                                     pageRef
236                             ).build(BaseModal.CONTENT_ID, AjaxWizard.Mode.EDIT));
237                             send(RemediationDirectoryPanel.this, Broadcast.EXACT, userEvent);
238                             break;
239 
240                         case "GROUP":
241                             GroupTO newGroupTO;
242                             GroupTO previousGroupTO;
243                             if (remediationTO.getAnyURPayload() == null) {
244                                 newGroupTO = new GroupTO();
245                                 EntityTOUtils.toAnyTO(remediationTO.getAnyCRPayload(), newGroupTO);
246                                 previousGroupTO = null;
247                             } else {
248                                 previousGroupTO = groupRestClient.read(remediationTO.getAnyURPayload().getKey());
249                                 newGroupTO = AnyOperations.patch(
250                                         previousGroupTO, (GroupUR) remediationTO.getAnyURPayload());
251                             }
252 
253                             AjaxWizard.EditItemActionEvent<GroupTO> groupEvent =
254                                     new AjaxWizard.EditItemActionEvent<>(newGroupTO, target);
255                             groupEvent.forceModalPanel(new RemediationGroupWizardBuilder(
256                                     model.getObject(),
257                                     previousGroupTO,
258                                     newGroupTO,
259                                     anyTypeRestClient.read(remediationTO.getAnyType()).getClasses(),
260                                     AnyLayoutUtils.fetch(
261                                             roleRestClient, List.of(remediationTO.getAnyType())).getGroup(),
262                                     pageRef
263                             ).build(BaseModal.CONTENT_ID, AjaxWizard.Mode.EDIT));
264                             send(RemediationDirectoryPanel.this, Broadcast.EXACT, groupEvent);
265                             break;
266 
267                         default:
268                             AnyObjectTO newAnyObjectTO;
269                             AnyObjectTO previousAnyObjectTO;
270                             if (remediationTO.getAnyURPayload() == null) {
271                                 newAnyObjectTO = new AnyObjectTO();
272                                 EntityTOUtils.toAnyTO(remediationTO.getAnyCRPayload(), newAnyObjectTO);
273                                 previousAnyObjectTO = null;
274                             } else {
275                                 previousAnyObjectTO = anyObjectRestClient.
276                                         read(remediationTO.getAnyURPayload().getKey());
277                                 newAnyObjectTO = AnyOperations.patch(
278                                         previousAnyObjectTO, (AnyObjectUR) remediationTO.getAnyURPayload());
279                             }
280 
281                             AjaxWizard.EditItemActionEvent<AnyObjectTO> anyObjectEvent =
282                                     new AjaxWizard.EditItemActionEvent<>(newAnyObjectTO, target);
283                             anyObjectEvent.forceModalPanel(new RemediationAnyObjectWizardBuilder(
284                                     model.getObject(),
285                                     previousAnyObjectTO,
286                                     newAnyObjectTO,
287                                     anyTypeRestClient.read(remediationTO.getAnyType()).getClasses(),
288                                     AnyLayoutUtils.fetch(roleRestClient, List.of(remediationTO.getAnyType())).
289                                             getAnyObjects().get(remediationTO.getAnyType()),
290                                     pageRef
291                             ).build(BaseModal.CONTENT_ID, AjaxWizard.Mode.EDIT));
292                             send(RemediationDirectoryPanel.this, Broadcast.EXACT, anyObjectEvent);
293                     }
294                 }
295             }, ActionLink.ActionType.EDIT, entitlements);
296         }
297 
298         panel.add(new ActionLink<>() {
299 
300             private static final long serialVersionUID = 6193210574968203299L;
301 
302             @Override
303             public void onClick(final AjaxRequestTarget target, final RemediationTO ignore) {
304                 try {
305                     restClient.delete(model.getObject().getKey());
306 
307                     SyncopeConsoleSession.get().success(getString(Constants.OPERATION_SUCCEEDED));
308                     target.add(container);
309                 } catch (SyncopeClientException e) {
310                     LOG.error("While deleting {}", model.getObject().getKey(), e);
311                     SyncopeConsoleSession.get().onException(e);
312                 }
313                 ((BasePage) pageRef.getPage()).getNotificationPanel().refresh(target);
314             }
315         }, ActionLink.ActionType.DELETE, IdMEntitlement.REMEDIATION_DELETE, true);
316 
317         return panel;
318     }
319 
320     @Override
321     protected RemediationProvider dataProvider() {
322         return new RemediationProvider(rows);
323     }
324 
325     @Override
326     protected String paginatorRowsKey() {
327         return IdMConstants.PREF_REMEDIATION_PAGINATOR_ROWS;
328     }
329 
330     @Override
331     protected Collection<ActionLink.ActionType> getBatches() {
332         return List.of();
333     }
334 
335     public class RemediationProvider extends DirectoryDataProvider<RemediationTO> {
336 
337         private static final long serialVersionUID = -2311716167583335852L;
338 
339         public RemediationProvider(final int paginatorRows) {
340             super(paginatorRows);
341 
342             setSort("instant", SortOrder.ASCENDING);
343         }
344 
345         @Override
346         public Iterator<RemediationTO> iterator(final long first, final long count) {
347             int page = ((int) first / paginatorRows);
348             return restClient.getRemediations((page < 0 ? 0 : page) + 1,
349                     paginatorRows, getSort()).iterator();
350         }
351 
352         @Override
353         public long size() {
354             return restClient.countRemediations();
355         }
356 
357         @Override
358         public IModel<RemediationTO> model(final RemediationTO remediation) {
359             return new IModel<>() {
360 
361                 private static final long serialVersionUID = -2566070996511906708L;
362 
363                 @Override
364                 public RemediationTO getObject() {
365                     return remediation;
366                 }
367             };
368         }
369     }
370 
371     private class RemediationUserWizardBuilder extends UserWizardBuilder {
372 
373         private static final long serialVersionUID = 6840699724316612700L;
374 
375         private final UserTO previousUserTO;
376 
377         private final RemediationTO remediationTO;
378 
379         RemediationUserWizardBuilder(
380                 final RemediationTO remediationTO,
381                 final UserTO previousUserTO,
382                 final UserTO userTO,
383                 final List<String> anyTypeClasses,
384                 final UserFormLayoutInfo formLayoutInfo,
385                 final UserRestClient userRestClient,
386                 final PageReference pageRef) {
387 
388             super(previousUserTO, userTO, anyTypeClasses, formLayoutInfo, userRestClient, pageRef);
389             this.previousUserTO = previousUserTO;
390             this.remediationTO = remediationTO;
391         }
392 
393         @Override
394         protected Serializable onApplyInternal(final AnyWrapper<UserTO> modelObject) {
395             UserTO inner = modelObject.getInnerObject();
396 
397             ProvisioningResult<UserTO> result;
398 
399             if (remediationTO.getAnyURPayload() == null) {
400                 UserCR req = new UserCR();
401                 EntityTOUtils.toAnyCR(inner, req);
402 
403                 result = restClient.remedy(remediationTO.getKey(), req);
404             } else {
405                 UserUR req = AnyOperations.diff(inner, previousUserTO, false);
406 
407                 if (StringUtils.isNotBlank(inner.getPassword())) {
408                     PasswordPatch passwordPatch = new PasswordPatch.Builder().
409                             value(inner.getPassword()).onSyncope(true).resources(inner.
410                             getResources()).
411                             build();
412                     req.setPassword(passwordPatch);
413                 }
414                 // update just if it is changed
415                 if (req.isEmpty()) {
416                     result = new ProvisioningResult<>();
417                     result.setEntity(inner);
418                 } else {
419                     result = restClient.remedy(remediationTO.getKey(), req);
420                 }
421             }
422 
423             return result;
424         }
425     }
426 
427     private class RemediationGroupWizardBuilder extends GroupWizardBuilder {
428 
429         private static final long serialVersionUID = -5233791906979150786L;
430 
431         private final GroupTO previousGroupTO;
432 
433         private final RemediationTO remediationTO;
434 
435         RemediationGroupWizardBuilder(
436                 final RemediationTO remediationTO,
437                 final GroupTO previousGroupTO,
438                 final GroupTO groupTO,
439                 final List<String> anyTypeClasses,
440                 final GroupFormLayoutInfo formLayoutInfo,
441                 final PageReference pageRef) {
442 
443             super(previousGroupTO, groupTO, anyTypeClasses, formLayoutInfo, pageRef);
444             this.previousGroupTO = previousGroupTO;
445             this.remediationTO = remediationTO;
446         }
447 
448         @Override
449         protected Serializable onApplyInternal(final AnyWrapper<GroupTO> modelObject) {
450             GroupTO inner = modelObject.getInnerObject();
451 
452             ProvisioningResult<GroupTO> result;
453 
454             if (remediationTO.getAnyURPayload() == null) {
455                 GroupCR req = new GroupCR();
456                 EntityTOUtils.toAnyCR(inner, req);
457 
458                 result = restClient.remedy(remediationTO.getKey(), req);
459             } else {
460                 GroupUR req = AnyOperations.diff(inner, previousGroupTO, false);
461 
462                 // update just if it is changed
463                 if (req.isEmpty()) {
464                     result = new ProvisioningResult<>();
465                     result.setEntity(inner);
466                 } else {
467                     result = restClient.remedy(remediationTO.getKey(), req);
468                 }
469             }
470 
471             return result;
472         }
473     }
474 
475     private class RemediationAnyObjectWizardBuilder extends AnyObjectWizardBuilder {
476 
477         private static final long serialVersionUID = 6993139499479015083L;
478 
479         private final AnyObjectTO previousAnyObjectTO;
480 
481         private final RemediationTO remediationTO;
482 
483         RemediationAnyObjectWizardBuilder(
484                 final RemediationTO remediationTO,
485                 final AnyObjectTO previousAnyObjectTO,
486                 final AnyObjectTO anyObjectTO,
487                 final List<String> anyTypeClasses,
488                 final AnyObjectFormLayoutInfo formLayoutInfo,
489                 final PageReference pageRef) {
490 
491             super(previousAnyObjectTO, anyObjectTO, anyTypeClasses, formLayoutInfo, pageRef);
492             this.previousAnyObjectTO = previousAnyObjectTO;
493             this.remediationTO = remediationTO;
494         }
495 
496         @Override
497         protected Serializable onApplyInternal(final AnyWrapper<AnyObjectTO> modelObject) {
498             AnyObjectTO inner = modelObject.getInnerObject();
499 
500             ProvisioningResult<AnyObjectTO> result;
501 
502             if (remediationTO.getAnyURPayload() == null) {
503                 AnyObjectCR req = new AnyObjectCR();
504                 EntityTOUtils.toAnyCR(inner, req);
505 
506                 result = restClient.remedy(remediationTO.getKey(), req);
507             } else {
508                 AnyObjectUR req = AnyOperations.diff(inner, previousAnyObjectTO, false);
509 
510                 // update just if it is changed
511                 if (req.isEmpty()) {
512                     result = new ProvisioningResult<>();
513                     result.setEntity(inner);
514                 } else {
515                     result = restClient.remedy(remediationTO.getKey(), req);
516                 }
517             }
518 
519             return result;
520         }
521     }
522 }