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.wizards.any;
20
21 import java.util.ArrayList;
22 import java.util.Comparator;
23 import java.util.HashMap;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.stream.Collectors;
27 import org.apache.commons.lang3.StringUtils;
28 import org.apache.cxf.jaxrs.ext.search.client.CompleteCondition;
29 import org.apache.syncope.client.console.SyncopeConsoleSession;
30 import org.apache.syncope.client.console.SyncopeWebApplication;
31 import org.apache.syncope.client.console.commons.RealmsUtils;
32 import org.apache.syncope.client.console.rest.GroupRestClient;
33 import org.apache.syncope.client.console.rest.SyncopeRestClient;
34 import org.apache.syncope.client.lib.SyncopeClient;
35 import org.apache.syncope.client.ui.commons.Constants;
36 import org.apache.syncope.client.ui.commons.markup.html.form.AjaxPalettePanel;
37 import org.apache.syncope.client.ui.commons.wizards.any.AbstractGroups;
38 import org.apache.syncope.client.ui.commons.wizards.any.AbstractGroupsModel;
39 import org.apache.syncope.client.ui.commons.wizards.any.AnyWrapper;
40 import org.apache.syncope.common.lib.SyncopeConstants;
41 import org.apache.syncope.common.lib.search.GroupFiqlSearchConditionBuilder;
42 import org.apache.syncope.common.lib.to.AnyTO;
43 import org.apache.syncope.common.lib.to.DynRealmTO;
44 import org.apache.syncope.common.lib.to.GroupTO;
45 import org.apache.syncope.common.lib.to.GroupableRelatableTO;
46 import org.apache.syncope.common.lib.to.MembershipTO;
47 import org.apache.syncope.common.lib.types.IdRepoEntitlement;
48 import org.apache.wicket.authroles.authorization.strategies.role.metadata.ActionPermissions;
49 import org.apache.wicket.authroles.authorization.strategies.role.metadata.MetaDataRoleAuthorizationStrategy;
50 import org.apache.wicket.extensions.markup.html.repeater.util.SortParam;
51 import org.apache.wicket.markup.html.WebMarkupContainer;
52 import org.apache.wicket.markup.html.basic.Label;
53 import org.apache.wicket.markup.html.form.IChoiceRenderer;
54 import org.apache.wicket.model.IModel;
55 import org.apache.wicket.model.PropertyModel;
56 import org.apache.wicket.model.util.ListModel;
57 import org.apache.wicket.spring.injection.annot.SpringBean;
58
59 public class Groups extends AbstractGroups {
60
61 private static final long serialVersionUID = 552437609667518888L;
62
63 @SpringBean
64 protected GroupRestClient groupRestClient;
65
66 @SpringBean
67 protected SyncopeRestClient syncopeRestClient;
68
69 protected final List<DynRealmTO> allDynRealms = new ArrayList<>();
70
71 protected final boolean templateMode;
72
73 protected final ConsoleGroupsModel groupsModel;
74
75 protected AjaxPalettePanel.Builder<MembershipTO> groups;
76
77 public <T extends AnyTO> Groups(final AnyWrapper<T> modelObject, final boolean templateMode) {
78 super(modelObject);
79 this.templateMode = templateMode;
80 this.groupsModel = new ConsoleGroupsModel();
81
82
83
84
85 ActionPermissions permissions = new ActionPermissions();
86 setMetaData(MetaDataRoleAuthorizationStrategy.ACTION_PERMISSIONS, permissions);
87 permissions.authorizeAll(RENDER);
88
89
90 addDynamicGroupsContainer();
91 addGroupsPanel();
92 addDynamicRealmsContainer();
93 }
94
95 protected List<GroupTO> searchAssignable(final String realm, final String term) {
96 return syncopeRestClient.searchAssignableGroups(realm, term, 1, Constants.MAX_GROUP_LIST_SIZE);
97 }
98
99 @Override
100 protected void addDynamicRealmsContainer() {
101 dynrealmsContainer = new WebMarkupContainer("dynrealmsContainer");
102 dynrealmsContainer.setOutputMarkupId(true);
103 dynrealmsContainer.setOutputMarkupPlaceholderTag(true);
104 dynrealmsContainer.add(new AjaxPalettePanel.Builder<>().build("dynrealms",
105 new PropertyModel<>(anyTO, "dynRealms"),
106 new ListModel<>(allDynRealms.stream().map(DynRealmTO::getKey).collect(Collectors.toList()))).
107 hideLabel().setEnabled(false).setOutputMarkupId(true));
108 add(dynrealmsContainer);
109 }
110
111 @Override
112 protected void addGroupsPanel() {
113 if (anyTO instanceof GroupTO) {
114 groupsContainer.add(new Label("groups").setVisible(false));
115 groupsContainer.setVisible(false);
116 dyngroupsContainer.add(new Label("dyngroups").setVisible(false));
117 dyngroupsContainer.setVisible(false);
118 } else {
119 groups = new AjaxPalettePanel.Builder<MembershipTO>().setRenderer(new IChoiceRenderer<>() {
120
121 private static final long serialVersionUID = -3086661086073628855L;
122
123 @Override
124 public Object getDisplayValue(final MembershipTO object) {
125 return object.getGroupName();
126 }
127
128 @Override
129 public String getIdValue(final MembershipTO object, final int index) {
130 return object.getGroupName();
131 }
132
133 @Override
134 public MembershipTO getObject(
135 final String id, final IModel<? extends List<? extends MembershipTO>> choices) {
136
137 return choices.getObject().stream().
138 filter(object -> id.equalsIgnoreCase(object.getGroupName())).findAny().orElse(null);
139 }
140 });
141
142 groupsContainer.add(groups.setAllowOrder(true).withFilter("*").build("groups", new ListModel<>() {
143
144 private static final long serialVersionUID = -2583290457773357445L;
145
146 @Override
147 public List<MembershipTO> getObject() {
148 return Groups.this.groupsModel.getMemberships();
149 }
150 }, new AjaxPalettePanel.Builder.Query<>() {
151
152 private static final long serialVersionUID = -7223078772249308813L;
153
154 @Override
155 public List<MembershipTO> execute(final String filter) {
156 return StringUtils.isEmpty(filter)
157 ? List.of()
158 : ("*".equals(filter)
159 ? groupsModel.getObject()
160 : searchAssignable(anyTO.getRealm(), filter)).stream().
161 map(group -> new MembershipTO.Builder(group.getKey()).
162 groupName(group.getName()).build()).
163 collect(Collectors.toList());
164 }
165 }).hideLabel().setOutputMarkupId(true));
166
167 dyngroupsContainer.add(new AjaxPalettePanel.Builder<String>().setAllowOrder(true).build("dyngroups",
168 new ListModel<>() {
169
170 private static final long serialVersionUID = -2583290457773357445L;
171
172 @Override
173 public List<String> getObject() {
174 return Groups.this.groupsModel.getDynMemberships();
175 }
176 }, new ListModel<>(groupsModel.getObject().stream().
177 map(GroupTO::getName).collect(Collectors.toList()))).
178 hideLabel().setEnabled(false).setOutputMarkupId(true));
179 }
180 }
181
182 @Override
183 protected void addDynamicGroupsContainer() {
184 dyngroupsContainer = new WebMarkupContainer("dyngroupsContainer");
185 dyngroupsContainer.setOutputMarkupId(true);
186 dyngroupsContainer.setOutputMarkupPlaceholderTag(true);
187 add(dyngroupsContainer);
188 }
189
190 @Override
191 public boolean evaluate() {
192 return (anyTO instanceof GroupTO
193 ? !allDynRealms.isEmpty()
194 : !allDynRealms.isEmpty() || !groupsModel.getObject().isEmpty())
195 && SyncopeWebApplication.get().getSecuritySettings().getAuthorizationStrategy().
196 isActionAuthorized(this, RENDER);
197 }
198
199 public class ConsoleGroupsModel extends AbstractGroupsModel {
200
201 private static final long serialVersionUID = -4541954630939063927L;
202
203 protected List<GroupTO> groupsObj;
204
205 protected List<MembershipTO> membershipsObj;
206
207 protected List<String> dynMembershipsObj;
208
209 protected String realmObj;
210
211 @Override
212 public List<GroupTO> getObject() {
213 reload();
214 return groupsObj;
215 }
216
217
218
219
220 @Override
221 protected void reloadObject() {
222 groupsObj = searchAssignable(realmObj, null);
223 }
224
225 @Override
226 public List<MembershipTO> getMemberships() {
227 reload();
228 return membershipsObj;
229 }
230
231
232
233
234 @Override
235 protected void reloadMemberships() {
236
237 Map<String, String> assignedGroups = new HashMap<>();
238
239 int total = GroupableRelatableTO.class.cast(anyTO).getMemberships().size();
240 int pages = (total / Constants.MAX_GROUP_LIST_SIZE) + 1;
241 SortParam<String> sort = new SortParam<>(Constants.NAME_FIELD_NAME, true);
242 for (int page = 1; page <= pages; page++) {
243 GroupFiqlSearchConditionBuilder builder = SyncopeClient.getGroupSearchConditionBuilder();
244
245 List<CompleteCondition> conditions = GroupableRelatableTO.class.cast(anyTO).getMemberships().
246 stream().
247 skip((page - 1L) * Constants.MAX_GROUP_LIST_SIZE).
248 limit(Constants.MAX_GROUP_LIST_SIZE).
249 map(m -> builder.is(Constants.KEY_FIELD_NAME).equalTo(m.getGroupKey()).wrap()).
250 collect(Collectors.toList());
251
252 if (!conditions.isEmpty()) {
253 assignedGroups.putAll(groupRestClient.search(
254 realmObj,
255 builder.or(conditions).query(),
256 1,
257 Constants.MAX_GROUP_LIST_SIZE,
258 sort,
259 null).stream().collect(Collectors.toMap(GroupTO::getKey, GroupTO::getName)));
260 }
261 }
262
263
264 GroupableRelatableTO.class.cast(anyTO).getMemberships().stream().
265 filter(m -> m.getGroupName() == null && assignedGroups.containsKey(m.getGroupKey())).
266 forEach(m -> m.setGroupName(assignedGroups.get(m.getGroupKey())));
267 GroupableRelatableTO.class.cast(anyTO).getMemberships().removeIf(m -> m.getGroupName() == null);
268
269 membershipsObj = GroupableRelatableTO.class.cast(anyTO).getMemberships();
270 membershipsObj.sort(Comparator.comparing(MembershipTO::getGroupName));
271 }
272
273 @Override
274 public List<String> getDynMemberships() {
275 reload();
276 return dynMembershipsObj;
277 }
278
279
280
281
282 @Override
283 protected void reloadDynMemberships() {
284 GroupFiqlSearchConditionBuilder builder = SyncopeClient.getGroupSearchConditionBuilder();
285
286 List<CompleteCondition> conditions = GroupableRelatableTO.class.cast(anyTO).getDynMemberships().
287 stream().map(membership -> builder.is(Constants.KEY_FIELD_NAME).
288 equalTo(membership.getGroupKey()).wrap()).
289 collect(Collectors.toList());
290
291 dynMembershipsObj = new ArrayList<>();
292 if (SyncopeConsoleSession.get().owns(IdRepoEntitlement.GROUP_SEARCH) && !conditions.isEmpty()) {
293 dynMembershipsObj.addAll(groupRestClient.search(
294 SyncopeConstants.ROOT_REALM,
295 builder.or(conditions).query(),
296 -1,
297 -1,
298 new SortParam<>(Constants.NAME_FIELD_NAME, true),
299 null).stream().map(GroupTO::getName).collect(Collectors.toList()));
300 }
301 }
302
303
304
305
306 @Override
307 protected void reload() {
308 boolean reload;
309 if (Groups.this.templateMode) {
310 reload = realmObj == null;
311 realmObj = SyncopeConstants.ROOT_REALM;
312 } else {
313 reload = !Groups.this.anyTO.getRealm().equalsIgnoreCase(realmObj);
314 realmObj = RealmsUtils.getFullPath(Groups.this.anyTO.getRealm());
315 }
316
317 if (reload) {
318 reloadObject();
319 reloadMemberships();
320 reloadDynMemberships();
321 }
322 }
323 }
324 }