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.clientapps;
20
21 import java.nio.charset.StandardCharsets;
22 import java.util.ArrayList;
23 import java.util.Base64;
24 import java.util.Comparator;
25 import java.util.Iterator;
26 import java.util.LinkedHashMap;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.stream.Collectors;
30 import java.util.stream.Stream;
31 import javax.ws.rs.core.MediaType;
32 import org.apache.commons.lang3.RandomStringUtils;
33 import org.apache.commons.lang3.StringUtils;
34 import org.apache.syncope.client.console.SyncopeConsoleSession;
35 import org.apache.syncope.client.console.SyncopeWebApplication;
36 import org.apache.syncope.client.console.commons.RealmsUtils;
37 import org.apache.syncope.client.console.panels.AbstractModalPanel;
38 import org.apache.syncope.client.console.rest.ClientAppRestClient;
39 import org.apache.syncope.client.console.rest.PolicyRestClient;
40 import org.apache.syncope.client.console.rest.RealmRestClient;
41 import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal;
42 import org.apache.syncope.client.console.wicket.markup.html.form.AjaxSearchFieldPanel;
43 import org.apache.syncope.client.console.wicket.markup.html.form.BinaryFieldPanel;
44 import org.apache.syncope.client.console.wicket.markup.html.form.MultiFieldPanel;
45 import org.apache.syncope.client.console.wicket.markup.html.form.PolicyRenderer;
46 import org.apache.syncope.client.ui.commons.Constants;
47 import org.apache.syncope.client.ui.commons.ajax.form.IndicatorAjaxFormComponentUpdatingBehavior;
48 import org.apache.syncope.client.ui.commons.markup.html.form.AjaxCheckBoxPanel;
49 import org.apache.syncope.client.ui.commons.markup.html.form.AjaxDropDownChoicePanel;
50 import org.apache.syncope.client.ui.commons.markup.html.form.AjaxPalettePanel;
51 import org.apache.syncope.client.ui.commons.markup.html.form.AjaxSpinnerFieldPanel;
52 import org.apache.syncope.client.ui.commons.markup.html.form.AjaxTextFieldPanel;
53 import org.apache.syncope.client.ui.commons.pages.BaseWebPage;
54 import org.apache.syncope.client.ui.commons.panels.WizardModalPanel;
55 import org.apache.syncope.client.ui.commons.wizards.AbstractModalPanelBuilder;
56 import org.apache.syncope.client.ui.commons.wizards.AjaxWizard;
57 import org.apache.syncope.common.lib.OIDCScopeConstants;
58 import org.apache.syncope.common.lib.policy.PolicyTO;
59 import org.apache.syncope.common.lib.to.ClientAppTO;
60 import org.apache.syncope.common.lib.to.OIDCRPClientAppTO;
61 import org.apache.syncope.common.lib.to.RealmTO;
62 import org.apache.syncope.common.lib.types.ClientAppType;
63 import org.apache.syncope.common.lib.types.LogoutType;
64 import org.apache.syncope.common.lib.types.OIDCClientAuthenticationMethod;
65 import org.apache.syncope.common.lib.types.OIDCGrantType;
66 import org.apache.syncope.common.lib.types.OIDCResponseType;
67 import org.apache.syncope.common.lib.types.OIDCSubjectType;
68 import org.apache.syncope.common.lib.types.PolicyType;
69 import org.apache.syncope.common.lib.types.SAML2SPNameId;
70 import org.apache.syncope.common.lib.types.XmlSecAlgorithm;
71 import org.apache.wicket.Component;
72 import org.apache.wicket.PageReference;
73 import org.apache.wicket.ajax.AjaxRequestTarget;
74 import org.apache.wicket.extensions.ajax.markup.html.autocomplete.AutoCompleteSettings;
75 import org.apache.wicket.markup.html.form.AbstractSingleSelectChoice;
76 import org.apache.wicket.markup.html.list.ListItem;
77 import org.apache.wicket.markup.html.list.ListView;
78 import org.apache.wicket.model.IModel;
79 import org.apache.wicket.model.LoadableDetachableModel;
80 import org.apache.wicket.model.Model;
81 import org.apache.wicket.model.PropertyModel;
82 import org.apache.wicket.model.util.ListModel;
83 import org.apache.wicket.validation.validator.UrlValidator;
84
85 public class ClientAppModalPanelBuilder<T extends ClientAppTO> extends AbstractModalPanelBuilder<T> {
86
87 private static final long serialVersionUID = 5945391813567245081L;
88
89 protected final IModel<Map<String, String>> accessPolicies = new LoadableDetachableModel<>() {
90
91 private static final long serialVersionUID = -2012833443695917883L;
92
93 @Override
94 protected Map<String, String> load() {
95 return policyRestClient.list(PolicyType.ACCESS).stream().
96 collect(Collectors.toMap(PolicyTO::getKey, PolicyTO::getName, (v1, v2) -> v1, LinkedHashMap::new));
97 }
98 };
99
100 protected final IModel<Map<String, String>> attrReleasePolicies = new LoadableDetachableModel<>() {
101
102 private static final long serialVersionUID = -2012833443695917883L;
103
104 @Override
105 protected Map<String, String> load() {
106 return policyRestClient.list(PolicyType.ATTR_RELEASE).stream().
107 collect(Collectors.toMap(PolicyTO::getKey, PolicyTO::getName, (v1, v2) -> v1, LinkedHashMap::new));
108 }
109 };
110
111 protected final IModel<Map<String, String>> authPolicies = new LoadableDetachableModel<>() {
112
113 private static final long serialVersionUID = -2012833443695917883L;
114
115 @Override
116 protected Map<String, String> load() {
117 return policyRestClient.list(PolicyType.AUTH).stream().
118 collect(Collectors.toMap(PolicyTO::getKey, PolicyTO::getName, (v1, v2) -> v1, LinkedHashMap::new));
119 }
120 };
121
122 protected final IModel<Map<String, String>> ticketExpirationPolicies = new LoadableDetachableModel<>() {
123
124 private static final long serialVersionUID = -2012833443695917883L;
125
126 @Override
127 protected Map<String, String> load() {
128 return policyRestClient.list(PolicyType.TICKET_EXPIRATION).stream().
129 collect(Collectors.toMap(PolicyTO::getKey, PolicyTO::getName, (v1, v2) -> v1, LinkedHashMap::new));
130 }
131 };
132
133 protected final BaseModal<T> modal;
134
135 protected final ClientAppType type;
136
137 protected final PolicyRestClient policyRestClient;
138
139 protected final ClientAppRestClient clientAppRestClient;
140
141 protected final RealmRestClient realmRestClient;
142
143 public ClientAppModalPanelBuilder(
144 final ClientAppType type,
145 final T defaultItem,
146 final BaseModal<T> modal,
147 final PolicyRestClient policyRestClient,
148 final ClientAppRestClient clientAppRestClient,
149 final RealmRestClient realmRestClient,
150 final PageReference pageRef) {
151
152 super(defaultItem, pageRef);
153 this.type = type;
154 this.modal = modal;
155 this.policyRestClient = policyRestClient;
156 this.clientAppRestClient = clientAppRestClient;
157 this.realmRestClient = realmRestClient;
158 }
159
160 @Override
161 public WizardModalPanel<T> build(final String id, final int index, final AjaxWizard.Mode mode) {
162 return new Profile(newModelObject(), modal, pageRef);
163 }
164
165 private class Profile extends AbstractModalPanel<T> {
166
167 private static final long serialVersionUID = 7647959917047450318L;
168
169 private final T clientAppTO;
170
171 Profile(final T clientAppTO, final BaseModal<T> modal, final PageReference pageRef) {
172 super(modal, pageRef);
173 modal.setFormModel(clientAppTO);
174
175 this.clientAppTO = clientAppTO;
176
177 List<Component> fields = new ArrayList<>();
178
179 boolean fullRealmsTree = SyncopeWebApplication.get().fullRealmsTree(realmRestClient);
180 AutoCompleteSettings settings = new AutoCompleteSettings();
181 settings.setShowCompleteListOnFocusGain(fullRealmsTree);
182 settings.setShowListOnEmptyInput(fullRealmsTree);
183 AjaxSearchFieldPanel realm = new AjaxSearchFieldPanel(
184 "field", "realm", new PropertyModel<>(clientAppTO, "realm"), settings) {
185
186 private static final long serialVersionUID = -6390474600233486704L;
187
188 @Override
189 protected Iterator<String> getChoices(final String input) {
190 return realmRestClient.search(fullRealmsTree
191 ? RealmsUtils.buildRootQuery()
192 : RealmsUtils.buildKeywordQuery(input)).getResult().stream().
193 map(RealmTO::getFullPath).collect(Collectors.toList()).iterator();
194 }
195 };
196 fields.add(realm.setOutputMarkupId(true));
197
198 AjaxTextFieldPanel name = new AjaxTextFieldPanel(
199 "field", Constants.NAME_FIELD_NAME,
200 new PropertyModel<>(clientAppTO, Constants.NAME_FIELD_NAME), false);
201 fields.add(name.setRequired(true));
202
203 if (clientAppTO.getClientAppId() == null) {
204 Stream.of(ClientAppType.values()).map(clientAppRestClient::list).flatMap(List::stream).
205 max(Comparator.comparing(ClientAppTO::getClientAppId)).
206 ifPresent(app -> clientAppTO.setClientAppId(app.getClientAppId() + 1));
207 }
208 fields.add(new AjaxSpinnerFieldPanel.Builder<Long>().build(
209 "field", "clientAppId", Long.class,
210 new PropertyModel<>(clientAppTO, "clientAppId")).setRequired(true));
211
212 fields.add(new AjaxTextFieldPanel(
213 "field", Constants.DESCRIPTION_FIELD_NAME,
214 new PropertyModel<>(clientAppTO, Constants.DESCRIPTION_FIELD_NAME), false));
215
216 fields.add(new AjaxTextFieldPanel(
217 "field", "logo",
218 new PropertyModel<>(clientAppTO, "logo"), false));
219
220 fields.add(new AjaxTextFieldPanel(
221 "field", "theme",
222 new PropertyModel<>(clientAppTO, "theme"), false));
223
224 AjaxTextFieldPanel informationUrl = new AjaxTextFieldPanel(
225 "field", "informationUrl",
226 new PropertyModel<>(clientAppTO, "informationUrl"), false);
227 informationUrl.addValidator(new UrlValidator());
228 fields.add(informationUrl);
229
230 AjaxTextFieldPanel privacyUrl = new AjaxTextFieldPanel(
231 "field", "privacyUrl",
232 new PropertyModel<>(clientAppTO, "privacyUrl"), false);
233 privacyUrl.addValidator(new UrlValidator());
234 fields.add(privacyUrl);
235
236 AjaxDropDownChoicePanel<String> accessPolicy = new AjaxDropDownChoicePanel<>(
237 "field", "accessPolicy", new PropertyModel<>(clientAppTO, "accessPolicy"), false);
238 accessPolicy.setChoiceRenderer(new PolicyRenderer(accessPolicies.getObject()));
239 accessPolicy.setChoices(new ArrayList<>(accessPolicies.getObject().keySet()));
240 ((AbstractSingleSelectChoice<?>) accessPolicy.getField()).setNullValid(true);
241 fields.add(accessPolicy);
242
243 AjaxDropDownChoicePanel<String> attrReleasePolicy = new AjaxDropDownChoicePanel<>(
244 "field", "attrReleasePolicy", new PropertyModel<>(clientAppTO, "attrReleasePolicy"), false);
245 attrReleasePolicy.setChoiceRenderer(new PolicyRenderer(attrReleasePolicies.getObject()));
246 attrReleasePolicy.setChoices(new ArrayList<>(attrReleasePolicies.getObject().keySet()));
247 ((AbstractSingleSelectChoice<?>) attrReleasePolicy.getField()).setNullValid(true);
248 fields.add(attrReleasePolicy);
249
250 AjaxDropDownChoicePanel<String> authPolicy = new AjaxDropDownChoicePanel<>(
251 "field", "authPolicy", new PropertyModel<>(clientAppTO, "authPolicy"), false);
252 authPolicy.setChoiceRenderer(new PolicyRenderer(authPolicies.getObject()));
253 authPolicy.setChoices(new ArrayList<>(authPolicies.getObject().keySet()));
254 fields.add(authPolicy);
255
256 AjaxDropDownChoicePanel<String> ticketExpirationPolicy = new AjaxDropDownChoicePanel<>(
257 "field", "ticketExpirationPolicy",
258 new PropertyModel<>(clientAppTO, "ticketExpirationPolicy"), false);
259 ticketExpirationPolicy.setChoiceRenderer(new PolicyRenderer(ticketExpirationPolicies.getObject()));
260 ticketExpirationPolicy.setChoices(new ArrayList<>(ticketExpirationPolicies.getObject().keySet()));
261 ((AbstractSingleSelectChoice<?>) ticketExpirationPolicy.getField()).setNullValid(true);
262 fields.add(ticketExpirationPolicy);
263
264 AjaxDropDownChoicePanel<LogoutType> logoutType = new AjaxDropDownChoicePanel<>(
265 "field", "logoutType", new PropertyModel<>(clientAppTO, "logoutType"), false);
266 logoutType.setChoices(List.of(LogoutType.values()));
267 fields.add(logoutType.setRequired(true));
268
269 switch (type) {
270 case CASSP:
271 fields.add(new AjaxTextFieldPanel(
272 "field", "serviceId", new PropertyModel<>(clientAppTO, "serviceId"), false).
273 setRequired(true));
274 break;
275
276 case OIDCRP:
277 AjaxTextFieldPanel clientId = new AjaxTextFieldPanel(
278 "field", "clientId", new PropertyModel<>(clientAppTO, "clientId"), false);
279 fields.add(clientId.setRequired(true));
280 name.getField().add(new IndicatorAjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
281
282 private static final long serialVersionUID = -6139318907146065915L;
283
284 @Override
285 protected void onUpdate(final AjaxRequestTarget target) {
286 if (StringUtils.isBlank(clientId.getModelObject())) {
287 clientId.setModelObject(name.getModelObject());
288 target.add(clientId);
289 }
290 }
291 });
292
293 AjaxTextFieldPanel clientSecret = new AjaxTextFieldPanel(
294 "field", "clientSecret", new PropertyModel<>(clientAppTO, "clientSecret"), false);
295 clientSecret.setChoices(List.of(RandomStringUtils.randomAlphanumeric(15)));
296 fields.add(clientSecret.setRequired(true));
297
298 fields.add(new AjaxCheckBoxPanel(
299 "field", "signIdToken", new PropertyModel<>(clientAppTO, "signIdToken")));
300 fields.add(new AjaxCheckBoxPanel(
301 "field", "jwtAccessToken", new PropertyModel<>(clientAppTO, "jwtAccessToken")));
302 fields.add(new AjaxCheckBoxPanel(
303 "field", "bypassApprovalPrompt", new PropertyModel<>(clientAppTO, "bypassApprovalPrompt")));
304 fields.add(new AjaxCheckBoxPanel(
305 "field", "generateRefreshToken", new PropertyModel<>(clientAppTO, "generateRefreshToken")));
306
307 AjaxDropDownChoicePanel<OIDCSubjectType> subjectType = new AjaxDropDownChoicePanel<>(
308 "field", "subjectType", new PropertyModel<>(clientAppTO, "subjectType"), false);
309 subjectType.setChoices(List.of(OIDCSubjectType.values()));
310 subjectType.addRequiredLabel().setEnabled(true);
311 fields.add(subjectType);
312
313 AjaxTextFieldPanel redirectUri = new AjaxTextFieldPanel("panel", "redirectUris", new Model<>());
314 fields.add(new MultiFieldPanel.Builder<String>(
315 new PropertyModel<>(clientAppTO, "redirectUris")).build(
316 "field",
317 "redirectUris",
318 redirectUri));
319
320 fields.add(new AjaxPalettePanel.Builder<OIDCGrantType>().setName("supportedGrantTypes").build(
321 "field",
322 new PropertyModel<>(clientAppTO, "supportedGrantTypes"),
323 new ListModel<>(List.of(OIDCGrantType.values()))));
324
325 fields.add(new AjaxPalettePanel.Builder<OIDCResponseType>().setName("supportedResponseTypes").build(
326 "field",
327 new PropertyModel<>(clientAppTO, "supportedResponseTypes"),
328 new ListModel<>(List.of(OIDCResponseType.values()))));
329
330 AutoCompleteSettings scopesSettings = new AutoCompleteSettings();
331 scopesSettings.setShowCompleteListOnFocusGain(true);
332 scopesSettings.setShowListOnEmptyInput(true);
333 AjaxSearchFieldPanel scopes = new AjaxSearchFieldPanel(
334 "panel", "scopes", new PropertyModel<>(clientAppTO, "scopes"), scopesSettings) {
335
336 private static final long serialVersionUID = 7160878678968866138L;
337
338 @Override
339 protected Iterator<String> getChoices(final String input) {
340 List<String> choices = new ArrayList<>(OIDCScopeConstants.ALL_STANDARD_SCOPES);
341 choices.add(OIDCScopeConstants.SYNCOPE);
342 return choices.iterator();
343 }
344 };
345 fields.add(new MultiFieldPanel.Builder<String>(
346 new PropertyModel<>(clientAppTO, "scopes")).build(
347 "field",
348 "scopes",
349 scopes));
350
351 AjaxTextFieldPanel logoutUri = new AjaxTextFieldPanel(
352 "field", "logoutUri", new PropertyModel<>(clientAppTO, "logoutUri"), false);
353 logoutUri.addValidator(new UrlValidator());
354 fields.add(logoutUri);
355
356 BinaryFieldPanel jwks = new BinaryFieldPanel(
357 "field",
358 "jwks",
359 new Model<>() {
360
361 private static final long serialVersionUID = 7666049400663637482L;
362
363 @Override
364 public String getObject() {
365 OIDCRPClientAppTO oidcRPCA = (OIDCRPClientAppTO) clientAppTO;
366 return StringUtils.isBlank(oidcRPCA.getJwks())
367 ? null
368 : Base64.getEncoder().encodeToString(
369 oidcRPCA.getJwks().getBytes(StandardCharsets.UTF_8));
370 }
371
372 @Override
373 public void setObject(final String object) {
374 OIDCRPClientAppTO oidcRPCA = (OIDCRPClientAppTO) clientAppTO;
375 if (StringUtils.isBlank(object)) {
376 oidcRPCA.setJwks(null);
377 } else {
378 oidcRPCA.setJwks(
379 new String(Base64.getDecoder().decode(object), StandardCharsets.UTF_8));
380 }
381 }
382 },
383 MediaType.APPLICATION_JSON,
384 "client-jwks");
385 fields.add(jwks);
386
387 AjaxTextFieldPanel jwksUri = new AjaxTextFieldPanel(
388 "field", "jwksUri", new PropertyModel<>(clientAppTO, "jwksUri"), false);
389 jwksUri.addValidator(new UrlValidator());
390 fields.add(jwksUri);
391
392 AjaxDropDownChoicePanel<OIDCClientAuthenticationMethod> tokenEndpointAuthenticationMethod =
393 new AjaxDropDownChoicePanel<>(
394 "field",
395 "tokenEndpointAuthenticationMethod",
396 new PropertyModel<>(clientAppTO, "tokenEndpointAuthenticationMethod"),
397 false);
398 tokenEndpointAuthenticationMethod.setChoices(List.of(OIDCClientAuthenticationMethod.values()));
399 fields.add(tokenEndpointAuthenticationMethod);
400 break;
401
402 case SAML2SP:
403 AjaxTextFieldPanel entityId = new AjaxTextFieldPanel(
404 "field", "entityId", new PropertyModel<>(clientAppTO, "entityId"), false);
405 fields.add(entityId.setRequired(true));
406
407 fields.add(new AjaxTextFieldPanel("field", "metadataLocation",
408 new PropertyModel<>(clientAppTO, "metadataLocation"), false).setRequired(true));
409
410 fields.add(new AjaxTextFieldPanel(
411 "field", "metadataSignatureLocation",
412 new PropertyModel<>(clientAppTO, "metadataSignatureLocation"), false));
413
414 fields.add(new AjaxCheckBoxPanel(
415 "field", "signAssertions", new PropertyModel<>(clientAppTO, "signAssertions")));
416
417 fields.add(new AjaxCheckBoxPanel(
418 "field", "signResponses", new PropertyModel<>(clientAppTO, "signResponses")));
419
420 fields.add(new AjaxCheckBoxPanel(
421 "field", "encryptionOptional", new PropertyModel<>(clientAppTO, "encryptionOptional")));
422
423 fields.add(new AjaxCheckBoxPanel(
424 "field", "encryptAssertions", new PropertyModel<>(clientAppTO, "encryptAssertions")));
425
426 fields.add(new AjaxTextFieldPanel(
427 "field", "requiredAuthenticationContextClass",
428 new PropertyModel<>(clientAppTO, "requiredAuthenticationContextClass"), false));
429
430 AjaxDropDownChoicePanel<SAML2SPNameId> requiredNameIdFormat = new AjaxDropDownChoicePanel<>(
431 "field", "requiredNameIdFormat", new PropertyModel<>(clientAppTO, "requiredNameIdFormat"),
432 false);
433 requiredNameIdFormat.setChoices(List.of(SAML2SPNameId.values()));
434 requiredNameIdFormat.addRequiredLabel().setEnabled(true);
435 fields.add(requiredNameIdFormat);
436
437 fields.add(new AjaxSpinnerFieldPanel.Builder<Integer>().min(0).build(
438 "field", "skewAllowance", Integer.class,
439 new PropertyModel<>(clientAppTO, "skewAllowance")));
440
441 fields.add(new AjaxTextFieldPanel(
442 "field", "nameIdQualifier", new PropertyModel<>(clientAppTO, "nameIdQualifier"), false));
443
444 AjaxTextFieldPanel assertionAudience = new AjaxTextFieldPanel(
445 "panel", "assertionAudience", new Model<>());
446 assertionAudience.addValidator(new UrlValidator());
447 fields.add(new MultiFieldPanel.Builder<String>(
448 new PropertyModel<>(clientAppTO, "assertionAudiences")).build(
449 "field",
450 "assertionAudiences",
451 assertionAudience));
452
453 fields.add(new AjaxTextFieldPanel(
454 "field", "serviceProviderNameIdQualifier",
455 new PropertyModel<>(clientAppTO, "serviceProviderNameIdQualifier"), false));
456
457 fields.add(new AjaxPalettePanel.Builder<XmlSecAlgorithm>().
458 setName("signingSignatureAlgorithms").build(
459 "field",
460 new PropertyModel<>(clientAppTO, "signingSignatureAlgorithms"),
461 new ListModel<>(List.of(XmlSecAlgorithm.values()))));
462
463 fields.add(new AjaxPalettePanel.Builder<XmlSecAlgorithm>().
464 setName("signingSignatureReferenceDigestMethods").build(
465 "field",
466 new PropertyModel<>(clientAppTO, "signingSignatureReferenceDigestMethods"),
467 new ListModel<>(List.of(XmlSecAlgorithm.values()))));
468
469 fields.add(new AjaxPalettePanel.Builder<XmlSecAlgorithm>().
470 setName("encryptionDataAlgorithms").build(
471 "field",
472 new PropertyModel<>(clientAppTO, "encryptionDataAlgorithms"),
473 new ListModel<>(List.of(XmlSecAlgorithm.values()))));
474
475 fields.add(new AjaxPalettePanel.Builder<XmlSecAlgorithm>().
476 setName("encryptionKeyAlgorithms").build(
477 "field",
478 new PropertyModel<>(clientAppTO, "encryptionKeyAlgorithms"),
479 new ListModel<>(List.of(XmlSecAlgorithm.values()))));
480
481 fields.add(new AjaxPalettePanel.Builder<XmlSecAlgorithm>().
482 setName("signingSignatureBlackListedAlgorithms").build(
483 "field",
484 new PropertyModel<>(clientAppTO, "signingSignatureBlackListedAlgorithms"),
485 new ListModel<>(List.of(XmlSecAlgorithm.values()))));
486
487 fields.add(new AjaxPalettePanel.Builder<XmlSecAlgorithm>().
488 setName("encryptionBlackListedAlgorithms").build(
489 "field",
490 new PropertyModel<>(clientAppTO, "encryptionBlackListedAlgorithms"),
491 new ListModel<>(List.of(XmlSecAlgorithm.values()))));
492 break;
493
494 default:
495 }
496
497 add(new ListView<>("fields", fields) {
498
499 private static final long serialVersionUID = -9180479401817023838L;
500
501 @Override
502 protected void populateItem(final ListItem<Component> item) {
503 item.add(item.getModelObject());
504 }
505 });
506 }
507
508 @Override
509 public void onSubmit(final AjaxRequestTarget target) {
510 try {
511 if (clientAppTO.getKey() == null) {
512 clientAppRestClient.create(type, clientAppTO);
513 } else {
514 clientAppRestClient.update(type, clientAppTO);
515 }
516 SyncopeConsoleSession.get().success(getString(Constants.OPERATION_SUCCEEDED));
517 Profile.this.modal.close(target);
518 } catch (Exception e) {
519 LOG.error("While creating/updating clientApp", e);
520 SyncopeConsoleSession.get().onException(e);
521 }
522 ((BaseWebPage) pageRef.getPage()).getNotificationPanel().refresh(target);
523 }
524 }
525 }