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.wizards;
20  
21  import java.io.Serializable;
22  import java.util.List;
23  import java.util.concurrent.Callable;
24  import java.util.concurrent.Future;
25  import java.util.stream.Collectors;
26  import org.apache.commons.lang3.StringUtils;
27  import org.apache.commons.lang3.tuple.Pair;
28  import org.apache.syncope.client.console.SyncopeConsoleSession;
29  import org.apache.syncope.client.console.SyncopeWebApplication;
30  import org.apache.syncope.client.console.panels.OIDCProvidersDirectoryPanel;
31  import org.apache.syncope.client.console.rest.ImplementationRestClient;
32  import org.apache.syncope.client.console.rest.OIDCProviderRestClient;
33  import org.apache.syncope.client.console.wicket.markup.html.form.MultiFieldPanel;
34  import org.apache.syncope.client.console.wizards.mapping.ItemTransformersTogglePanel;
35  import org.apache.syncope.client.console.wizards.mapping.JEXLTransformersTogglePanel;
36  import org.apache.syncope.client.console.wizards.mapping.OIDCProviderMappingPanel;
37  import org.apache.syncope.client.ui.commons.Constants;
38  import org.apache.syncope.client.ui.commons.ajax.form.IndicatorAjaxFormComponentUpdatingBehavior;
39  import org.apache.syncope.client.ui.commons.markup.html.form.AjaxCheckBoxPanel;
40  import org.apache.syncope.client.ui.commons.markup.html.form.AjaxPalettePanel;
41  import org.apache.syncope.client.ui.commons.markup.html.form.AjaxTextFieldPanel;
42  import org.apache.syncope.client.ui.commons.wizards.AjaxWizardBuilder;
43  import org.apache.syncope.common.lib.OIDCScopeConstants;
44  import org.apache.syncope.common.lib.to.ImplementationTO;
45  import org.apache.syncope.common.lib.to.OIDCC4UIProviderTO;
46  import org.apache.syncope.common.lib.types.OIDCClientImplementationType;
47  import org.apache.wicket.PageReference;
48  import org.apache.wicket.ajax.AjaxRequestTarget;
49  import org.apache.wicket.extensions.wizard.WizardModel;
50  import org.apache.wicket.extensions.wizard.WizardStep;
51  import org.apache.wicket.markup.html.WebMarkupContainer;
52  import org.apache.wicket.model.IModel;
53  import org.apache.wicket.model.LoadableDetachableModel;
54  import org.apache.wicket.model.Model;
55  import org.apache.wicket.model.PropertyModel;
56  import org.apache.wicket.model.StringResourceModel;
57  import org.apache.wicket.model.util.ListModel;
58  import org.apache.wicket.validation.validator.UrlValidator;
59  
60  public class OIDCProviderWizardBuilder extends AjaxWizardBuilder<OIDCC4UIProviderTO> {
61  
62      private static final long serialVersionUID = -3310772400714122768L;
63  
64      protected final OIDCProvidersDirectoryPanel directoryPanel;
65  
66      protected final ImplementationRestClient implementationRestClient;
67  
68      protected final OIDCProviderRestClient oidcProviderRestClient;
69  
70      protected final IModel<List<String>> opActions = new LoadableDetachableModel<>() {
71  
72          private static final long serialVersionUID = 5275935387613157437L;
73  
74          @Override
75          protected List<String> load() {
76              return implementationRestClient.list(OIDCClientImplementationType.OP_ACTIONS).stream().
77                      map(ImplementationTO::getKey).sorted().collect(Collectors.toList());
78          }
79      };
80  
81      public OIDCProviderWizardBuilder(
82              final OIDCProvidersDirectoryPanel directoryPanel,
83              final OIDCC4UIProviderTO defaultItem,
84              final ImplementationRestClient implementationRestClient,
85              final OIDCProviderRestClient oidcProviderRestClient,
86              final PageReference pageRef) {
87  
88          super(defaultItem, pageRef);
89          this.directoryPanel = directoryPanel;
90          this.implementationRestClient = implementationRestClient;
91          this.oidcProviderRestClient = oidcProviderRestClient;
92      }
93  
94      @Override
95      protected Serializable onApplyInternal(final OIDCC4UIProviderTO modelObject) {
96          if (modelObject.getKey() == null) {
97              if (modelObject.getHasDiscovery()) {
98                  oidcProviderRestClient.createFromDiscovery(modelObject);
99              } else {
100                 oidcProviderRestClient.create(modelObject);
101             }
102 
103         } else {
104             oidcProviderRestClient.update(modelObject);
105         }
106         return modelObject;
107     }
108 
109     @Override
110     protected WizardModel buildModelSteps(final OIDCC4UIProviderTO modelObject, final WizardModel wizardModel) {
111         wizardModel.add(new OP(modelObject));
112         wizardModel.add(new OPContinue(modelObject, modelObject.getKey() != null));
113 
114         Mapping mapping = new Mapping();
115         mapping.setOutputMarkupId(true);
116 
117         ItemTransformersTogglePanel mapItemTransformers = new ItemTransformersTogglePanel(mapping, pageRef);
118         addOuterObject(mapItemTransformers);
119         JEXLTransformersTogglePanel jexlTransformers = new JEXLTransformersTogglePanel(mapping, pageRef);
120         addOuterObject(jexlTransformers);
121         mapping.add(new OIDCProviderMappingPanel("mapping", modelObject, mapItemTransformers, jexlTransformers));
122 
123         wizardModel.add(mapping);
124 
125         return wizardModel;
126     }
127 
128     @Override
129     protected long getMaxWaitTimeInSeconds() {
130         return SyncopeWebApplication.get().getMaxWaitTimeInSeconds();
131     }
132 
133     @Override
134     protected void sendError(final Exception exception) {
135         SyncopeConsoleSession.get().onException(exception);
136     }
137 
138     @Override
139     protected void sendWarning(final String message) {
140         SyncopeConsoleSession.get().warn(message);
141     }
142 
143     @Override
144     protected Future<Pair<Serializable, Serializable>> execute(
145             final Callable<Pair<Serializable, Serializable>> future) {
146 
147         return SyncopeConsoleSession.get().execute(future);
148     }
149 
150     public class OP extends WizardStep {
151 
152         private static final long serialVersionUID = 7127421283216134900L;
153 
154         public OP(final OIDCC4UIProviderTO opTO) {
155             AjaxTextFieldPanel name = new AjaxTextFieldPanel(
156                     "name", "name", new PropertyModel<>(opTO, "name"), false);
157             name.addRequiredLabel();
158             name.setEnabled(true);
159             add(name);
160 
161             AjaxTextFieldPanel clientID = new AjaxTextFieldPanel(
162                     "clientID", "clientID", new PropertyModel<>(opTO, "clientID"), false);
163             clientID.addRequiredLabel();
164             clientID.setEnabled(true);
165             add(clientID);
166 
167             AjaxTextFieldPanel clientSecret = new AjaxTextFieldPanel(
168                     "clientSecret", "clientSecret", new PropertyModel<>(opTO, "clientSecret"), false);
169             clientSecret.addRequiredLabel();
170             clientSecret.setEnabled(true);
171             add(clientSecret);
172 
173             AjaxCheckBoxPanel createUnmatching = new AjaxCheckBoxPanel(
174                     "createUnmatching", "createUnmatching", new PropertyModel<>(opTO, "createUnmatching"),
175                     false);
176             add(createUnmatching);
177 
178             AjaxCheckBoxPanel selfRegUnmatching = new AjaxCheckBoxPanel(
179                     "selfRegUnmatching", "selfRegUnmatching", new PropertyModel<>(opTO, "selfRegUnmatching"),
180                     false);
181             add(selfRegUnmatching);
182 
183             AjaxCheckBoxPanel updateMatching = new AjaxCheckBoxPanel(
184                     "updateMatching", "updateMatching", new PropertyModel<>(opTO, "updateMatching"), false);
185             add(updateMatching);
186 
187             AjaxPalettePanel<String> actions = new AjaxPalettePanel.Builder<String>().
188                     setName(new StringResourceModel("actions", directoryPanel).getString()).
189                     setAllowMoveAll(true).setAllowOrder(true).
190                     build("actions",
191                             new PropertyModel<>(opTO, "actions"),
192                             new ListModel<>(opActions.getObject()));
193             actions.setOutputMarkupId(true);
194             add(actions);
195         }
196     }
197 
198     public static class OPContinue extends WizardStep {
199 
200         private static final long serialVersionUID = -7087008312629522790L;
201 
202         public OPContinue(final OIDCC4UIProviderTO opTO, final boolean readOnly) {
203             this.setOutputMarkupId(true);
204 
205             WebMarkupContainer content = new WebMarkupContainer("content");
206             content.setOutputMarkupId(true);
207             add(content);
208 
209             UrlValidator urlValidator = new UrlValidator();
210 
211             AjaxTextFieldPanel issuer = new AjaxTextFieldPanel(
212                     "issuer", "issuer", new PropertyModel<>(opTO, "issuer"));
213             issuer.addValidator(urlValidator);
214             issuer.addRequiredLabel();
215             content.add(issuer.setReadOnly(readOnly));
216 
217             AjaxCheckBoxPanel hasDiscovery = new AjaxCheckBoxPanel(
218                     "hasDiscovery", "hasDiscovery", new PropertyModel<>(opTO, "hasDiscovery"));
219             content.add(hasDiscovery);
220 
221             AjaxTextFieldPanel authorizationEndpoint = new AjaxTextFieldPanel("authorizationEndpoint",
222                     "authorizationEndpoint", new PropertyModel<>(opTO, "authorizationEndpoint"));
223             authorizationEndpoint.addRequiredLabel();
224             authorizationEndpoint.addValidator(urlValidator);
225             content.add(authorizationEndpoint.setReadOnly(readOnly));
226 
227             AjaxTextFieldPanel userinfoEndpoint = new AjaxTextFieldPanel("userinfoEndpoint",
228                     "userinfoEndpoint", new PropertyModel<>(opTO, "userinfoEndpoint"));
229             userinfoEndpoint.addValidator(urlValidator);
230             content.add(userinfoEndpoint.setReadOnly(readOnly));
231 
232             AjaxTextFieldPanel tokenEndpoint = new AjaxTextFieldPanel("tokenEndpoint",
233                     "tokenEndpoint", new PropertyModel<>(opTO, "tokenEndpoint"));
234             tokenEndpoint.addRequiredLabel();
235             tokenEndpoint.addValidator(urlValidator);
236             content.add(tokenEndpoint.setReadOnly(readOnly));
237 
238             AjaxTextFieldPanel jwksUri = new AjaxTextFieldPanel("jwksUri",
239                     "jwksUri", new PropertyModel<>(opTO, "jwksUri"));
240             jwksUri.addRequiredLabel();
241             jwksUri.addValidator(urlValidator);
242             content.add(jwksUri.setReadOnly(readOnly));
243 
244             AjaxTextFieldPanel endSessionEndpoint = new AjaxTextFieldPanel("endSessionEndpoint",
245                     "endSessionEndpoint", new PropertyModel<>(opTO, "endSessionEndpoint"));
246             endSessionEndpoint.addValidator(urlValidator);
247             content.add(endSessionEndpoint.setReadOnly(readOnly));
248 
249             WebMarkupContainer visibleParams = new WebMarkupContainer("visibleParams");
250             visibleParams.setOutputMarkupPlaceholderTag(true);
251             visibleParams.add(authorizationEndpoint);
252             visibleParams.add(userinfoEndpoint);
253             visibleParams.add(tokenEndpoint);
254             visibleParams.add(jwksUri);
255             visibleParams.add(endSessionEndpoint);
256             content.add(visibleParams);
257 
258             showHide(hasDiscovery, visibleParams);
259 
260             hasDiscovery.getField().add(new IndicatorAjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
261 
262                 private static final long serialVersionUID = -1107858522700306810L;
263 
264                 @Override
265                 protected void onUpdate(final AjaxRequestTarget target) {
266                     showHide(hasDiscovery, visibleParams);
267                     target.add(visibleParams);
268                 }
269             });
270 
271             AjaxTextFieldPanel value = new AjaxTextFieldPanel("panel", "scopes", new Model<>());
272             value.setChoices(OIDCScopeConstants.ALL_STANDARD_SCOPES);
273             content.add(new MultiFieldPanel.Builder<String>(
274                     new PropertyModel<>(opTO, "scopes")).build("scopes", "scopes", value));
275         }
276     }
277 
278     private static void showHide(final AjaxCheckBoxPanel hasDiscovery, final WebMarkupContainer visibleParams) {
279         visibleParams.setVisible("false".equals(hasDiscovery.getField().getValue()));
280     }
281 
282     /**
283      * Mapping definition step.
284      */
285     private static final class Mapping extends WizardStep {
286 
287         private static final long serialVersionUID = 3454904947720856253L;
288 
289         Mapping() {
290             setTitleModel(Model.of("Mapping"));
291             setSummaryModel(Model.of(StringUtils.EMPTY));
292         }
293     }
294 }