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.policies;
20  
21  import java.io.Serializable;
22  import java.util.ArrayList;
23  import java.util.Collection;
24  import java.util.Iterator;
25  import java.util.List;
26  import java.util.stream.Collectors;
27  import org.apache.syncope.client.console.SyncopeConsoleSession;
28  import org.apache.syncope.client.console.commons.DirectoryDataProvider;
29  import org.apache.syncope.client.console.commons.IdRepoConstants;
30  import org.apache.syncope.client.console.commons.SortableDataProviderComparator;
31  import org.apache.syncope.client.console.panels.DirectoryPanel;
32  import org.apache.syncope.client.console.rest.ImplementationRestClient;
33  import org.apache.syncope.client.console.rest.PolicyRestClient;
34  import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
35  import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink;
36  import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink.ActionType;
37  import org.apache.syncope.client.console.wicket.markup.html.form.ActionsPanel;
38  import org.apache.syncope.client.ui.commons.Constants;
39  import org.apache.syncope.client.ui.commons.pages.BaseWebPage;
40  import org.apache.syncope.client.ui.commons.panels.ModalPanel;
41  import org.apache.syncope.client.ui.commons.wizards.AjaxWizard;
42  import org.apache.syncope.common.lib.SyncopeClientException;
43  import org.apache.syncope.common.lib.policy.ComposablePolicy;
44  import org.apache.syncope.common.lib.policy.PolicyTO;
45  import org.apache.syncope.common.lib.policy.RuleConf;
46  import org.apache.syncope.common.lib.to.ImplementationTO;
47  import org.apache.syncope.common.lib.types.IdRepoEntitlement;
48  import org.apache.syncope.common.lib.types.IdRepoImplementationType;
49  import org.apache.syncope.common.lib.types.ImplementationEngine;
50  import org.apache.syncope.common.lib.types.PolicyType;
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.event.Broadcast;
55  import org.apache.wicket.event.IEvent;
56  import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
57  import org.apache.wicket.extensions.markup.html.repeater.data.sort.SortOrder;
58  import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn;
59  import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
60  import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn;
61  import org.apache.wicket.markup.html.basic.Label;
62  import org.apache.wicket.markup.repeater.Item;
63  import org.apache.wicket.model.CompoundPropertyModel;
64  import org.apache.wicket.model.IModel;
65  import org.apache.wicket.model.StringResourceModel;
66  import org.apache.wicket.spring.injection.annot.SpringBean;
67  
68  /**
69   * Policy rules page.
70   *
71   * @param <T> policy type.
72   */
73  public class PolicyRuleDirectoryPanel<T extends PolicyTO> extends DirectoryPanel<
74          PolicyRuleWrapper, PolicyRuleWrapper, DirectoryDataProvider<PolicyRuleWrapper>, PolicyRestClient>
75          implements ModalPanel {
76  
77      private static final long serialVersionUID = 4984337552918213290L;
78  
79      @SpringBean
80      protected ImplementationRestClient implementationRestClient;
81  
82      private final BaseModal<T> baseModal;
83  
84      private final PolicyType type;
85  
86      private final String implementationType;
87  
88      private final String policy;
89  
90      protected PolicyRuleDirectoryPanel(
91              final BaseModal<T> baseModal,
92              final String policy,
93              final PolicyType type,
94              final PolicyRestClient restClient,
95              final PageReference pageRef) {
96  
97          super(BaseModal.CONTENT_ID, restClient, pageRef, false);
98  
99          disableCheckBoxes();
100 
101         this.baseModal = baseModal;
102         this.type = type;
103         this.implementationType = type == PolicyType.ACCOUNT
104                 ? IdRepoImplementationType.ACCOUNT_RULE
105                 : IdRepoImplementationType.PASSWORD_RULE;
106         this.policy = policy;
107 
108         enableUtilityButton();
109 
110         this.addNewItemPanelBuilder(new PolicyRuleWizardBuilder(
111                 policy, type, new PolicyRuleWrapper(true), restClient, implementationRestClient, pageRef), true);
112 
113         MetaDataRoleAuthorizationStrategy.authorize(addAjaxLink, RENDER, IdRepoEntitlement.POLICY_UPDATE);
114         initResultTable();
115     }
116 
117     @Override
118     protected List<IColumn<PolicyRuleWrapper, String>> getColumns() {
119         List<IColumn<PolicyRuleWrapper, String>> columns = new ArrayList<>();
120 
121         columns.add(new PropertyColumn<>(
122                 new StringResourceModel("rule", this), "implementationKey", "implementationKey"));
123 
124         columns.add(new AbstractColumn<>(
125                 new StringResourceModel("configuration", this)) {
126 
127             private static final long serialVersionUID = -4008579357070833846L;
128 
129             @Override
130             public void populateItem(
131                     final Item<ICellPopulator<PolicyRuleWrapper>> cellItem,
132                     final String componentId,
133                     final IModel<PolicyRuleWrapper> rowModel) {
134 
135                 if (rowModel.getObject().getConf() == null) {
136                     cellItem.add(new Label(componentId, ""));
137                 } else {
138                     cellItem.add(new Label(componentId, rowModel.getObject().getConf().getClass().getName()));
139                 }
140             }
141         });
142 
143         return columns;
144     }
145 
146     @Override
147     public ActionsPanel<PolicyRuleWrapper> getActions(final IModel<PolicyRuleWrapper> model) {
148         final ActionsPanel<PolicyRuleWrapper> panel = super.getActions(model);
149 
150         panel.add(new ActionLink<>() {
151 
152             private static final long serialVersionUID = -3722207913631435501L;
153 
154             @Override
155             public void onClick(final AjaxRequestTarget target, final PolicyRuleWrapper ignore) {
156                 PolicyRuleDirectoryPanel.this.getTogglePanel().close(target);
157                 if (model.getObject().getConf() == null) {
158                     SyncopeConsoleSession.get().info(getString("noConf"));
159                     ((BaseWebPage) pageRef.getPage()).getNotificationPanel().refresh(target);
160                 } else {
161                     send(PolicyRuleDirectoryPanel.this, Broadcast.EXACT,
162                             new AjaxWizard.EditItemActionEvent<>(model.getObject(), target));
163                 }
164             }
165         }, ActionLink.ActionType.EDIT, IdRepoEntitlement.POLICY_UPDATE);
166 
167         panel.add(new ActionLink<>() {
168 
169             private static final long serialVersionUID = -3722207913631435501L;
170 
171             @Override
172             public void onClick(final AjaxRequestTarget target, final PolicyRuleWrapper ignore) {
173                 RuleConf rule = model.getObject().getConf();
174                 try {
175                     T actual = restClient.read(type, policy);
176                     if (actual instanceof ComposablePolicy) {
177                         ((ComposablePolicy) actual).getRules().remove(model.getObject().getImplementationKey());
178                         restClient.update(type, actual);
179 
180                         SyncopeConsoleSession.get().success(getString(Constants.OPERATION_SUCCEEDED));
181                         customActionOnFinishCallback(target);
182                     }
183                 } catch (SyncopeClientException e) {
184                     LOG.error("While deleting {}", rule.getName(), e);
185                     SyncopeConsoleSession.get().onException(e);
186                 }
187                 ((BaseWebPage) pageRef.getPage()).getNotificationPanel().refresh(target);
188             }
189         }, ActionLink.ActionType.DELETE, IdRepoEntitlement.POLICY_DELETE, true);
190 
191         return panel;
192     }
193 
194     @Override
195     public ActionsPanel<Serializable> getHeader(final String componentId) {
196         ActionsPanel<Serializable> panel = new ActionsPanel<>(componentId, null);
197 
198         panel.add(new ActionLink<>() {
199 
200             private static final long serialVersionUID = -7978723352517770644L;
201 
202             @Override
203             public void onClick(final AjaxRequestTarget target, final Serializable ignore) {
204                 if (target != null) {
205                     customActionOnFinishCallback(target);
206                 }
207             }
208         }, ActionLink.ActionType.RELOAD, IdRepoEntitlement.POLICY_LIST).hideLabel();
209 
210         return panel;
211     }
212 
213     @Override
214     protected Collection<ActionType> getBatches() {
215         return List.of();
216     }
217 
218     @Override
219     protected PolicyRuleDataProvider dataProvider() {
220         return new PolicyRuleDataProvider(rows);
221     }
222 
223     @Override
224     protected String paginatorRowsKey() {
225         return IdRepoConstants.PREF_POLICY_RULE_PAGINATOR_ROWS;
226     }
227 
228     protected class PolicyRuleDataProvider extends DirectoryDataProvider<PolicyRuleWrapper> {
229 
230         private static final long serialVersionUID = 4725679400450513556L;
231 
232         private final SortableDataProviderComparator<PolicyRuleWrapper> comparator;
233 
234         public PolicyRuleDataProvider(final int paginatorRows) {
235             super(paginatorRows);
236 
237             // Default sorting
238             setSort("implementationKey", SortOrder.ASCENDING);
239             comparator = new SortableDataProviderComparator<>(this);
240         }
241 
242         @SuppressWarnings("unchecked")
243         private List<PolicyRuleWrapper> getPolicyRuleWrappers(final ComposablePolicy policy) {
244             return policy.getRules().stream().map(rule -> {
245                 ImplementationTO implementation = implementationRestClient.read(implementationType, rule);
246 
247                 PolicyRuleWrapper wrapper = new PolicyRuleWrapper(false).
248                         setImplementationKey(implementation.getKey()).
249                         setImplementationEngine(implementation.getEngine());
250                 if (implementation.getEngine() == ImplementationEngine.JAVA) {
251                     try {
252                         RuleConf ruleConf = MAPPER.readValue(implementation.getBody(), RuleConf.class);
253                         wrapper.setConf(ruleConf);
254                     } catch (Exception e) {
255                         LOG.error("During deserialization", e);
256                     }
257                 }
258 
259                 return wrapper;
260             }).collect(Collectors.toList());
261         }
262 
263         @Override
264         public Iterator<PolicyRuleWrapper> iterator(final long first, final long count) {
265             T actual = restClient.read(type, policy);
266 
267             List<PolicyRuleWrapper> rules = actual instanceof ComposablePolicy
268                     ? getPolicyRuleWrappers((ComposablePolicy) actual)
269                     : new ArrayList<>();
270 
271             rules.sort(comparator);
272             return rules.subList((int) first, (int) (first + count)).iterator();
273         }
274 
275         @Override
276         public long size() {
277             T actual = restClient.read(type, policy);
278             return actual instanceof ComposablePolicy
279                     ? getPolicyRuleWrappers((ComposablePolicy) actual).size()
280                     : 0;
281         }
282 
283         @Override
284         public IModel<PolicyRuleWrapper> model(final PolicyRuleWrapper object) {
285             return new CompoundPropertyModel<>(object);
286         }
287     }
288 
289     @Override
290     public void onEvent(final IEvent<?> event) {
291         super.onEvent(event);
292         if (event.getPayload() instanceof ExitEvent) {
293             AjaxRequestTarget target = ExitEvent.class.cast(event.getPayload()).getTarget();
294             baseModal.show(false);
295             baseModal.close(target);
296         }
297     }
298 }