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.stream.Collectors;
24  import org.apache.commons.lang3.StringUtils;
25  import org.apache.syncope.client.console.SyncopeWebApplication;
26  import org.apache.syncope.client.console.panels.BeanPanel;
27  import org.apache.syncope.client.console.rest.AuthModuleRestClient;
28  import org.apache.syncope.client.console.wizards.mapping.AuthModuleMappingPanel;
29  import org.apache.syncope.client.ui.commons.Constants;
30  import org.apache.syncope.client.ui.commons.ajax.form.IndicatorAjaxFormComponentUpdatingBehavior;
31  import org.apache.syncope.client.ui.commons.markup.html.form.AjaxCheckBoxPanel;
32  import org.apache.syncope.client.ui.commons.markup.html.form.AjaxDropDownChoicePanel;
33  import org.apache.syncope.client.ui.commons.markup.html.form.AjaxSpinnerFieldPanel;
34  import org.apache.syncope.client.ui.commons.markup.html.form.AjaxTextFieldPanel;
35  import org.apache.syncope.client.ui.commons.wizards.AjaxWizard;
36  import org.apache.syncope.common.lib.auth.AuthModuleConf;
37  import org.apache.syncope.common.lib.auth.GoogleMfaAuthModuleConf;
38  import org.apache.syncope.common.lib.to.AuthModuleTO;
39  import org.apache.syncope.common.lib.types.AuthModuleState;
40  import org.apache.wicket.PageReference;
41  import org.apache.wicket.ajax.AjaxEventBehavior;
42  import org.apache.wicket.ajax.AjaxRequestTarget;
43  import org.apache.wicket.extensions.wizard.WizardModel;
44  import org.apache.wicket.extensions.wizard.WizardStep;
45  import org.apache.wicket.model.IModel;
46  import org.apache.wicket.model.LoadableDetachableModel;
47  import org.apache.wicket.model.Model;
48  import org.apache.wicket.model.PropertyModel;
49  import org.springframework.util.ClassUtils;
50  
51  public class AuthModuleWizardBuilder extends BaseAjaxWizardBuilder<AuthModuleTO> {
52  
53      private static final long serialVersionUID = -6163230263062920394L;
54  
55      protected final LoadableDetachableModel<List<String>> authModuleConfs = new LoadableDetachableModel<>() {
56  
57          private static final long serialVersionUID = 5275935387613157437L;
58  
59          @Override
60          protected List<String> load() {
61              return SyncopeWebApplication.get().getLookup().getClasses(AuthModuleConf.class).stream().
62                      map(Class::getName).sorted().collect(Collectors.toList());
63          }
64      };
65  
66      protected final AuthModuleRestClient authModuleRestClient;
67  
68      protected final Model<Class<? extends AuthModuleConf>> authModuleConfClass = Model.of();
69  
70      public AuthModuleWizardBuilder(
71              final AuthModuleTO defaultItem,
72              final AuthModuleRestClient authModuleRestClient,
73              final PageReference pageRef) {
74  
75          super(defaultItem, pageRef);
76          this.authModuleRestClient = authModuleRestClient;
77      }
78  
79      @Override
80      protected Serializable onApplyInternal(final AuthModuleTO modelObject) {
81          if (mode == AjaxWizard.Mode.CREATE) {
82              authModuleRestClient.create(modelObject);
83          } else {
84              authModuleRestClient.update(modelObject);
85          }
86          return modelObject;
87      }
88  
89      @Override
90      protected WizardModel buildModelSteps(final AuthModuleTO modelObject, final WizardModel wizardModel) {
91          wizardModel.add(new Profile(modelObject, authModuleConfs, authModuleConfClass));
92          wizardModel.add(new Configuration(modelObject));
93          wizardModel.add(new GoogleMfaAuthModuleConfLDAP(modelObject, authModuleConfClass));
94          wizardModel.add(new Mapping(modelObject));
95          return wizardModel;
96      }
97  
98      protected static class Profile extends WizardStep {
99  
100         private static final long serialVersionUID = -3043839139187792810L;
101 
102         Profile(
103                 final AuthModuleTO authModule,
104                 final LoadableDetachableModel<List<String>> authModuleConfs,
105                 final Model<Class<? extends AuthModuleConf>> authModuleConfClass) {
106 
107             boolean isNew = authModule.getConf() == null;
108             if (!isNew) {
109                 authModuleConfClass.setObject(authModule.getConf().getClass());
110             }
111 
112             AjaxTextFieldPanel key = new AjaxTextFieldPanel(
113                     Constants.KEY_FIELD_NAME, Constants.KEY_FIELD_NAME,
114                     new PropertyModel<>(authModule, Constants.KEY_FIELD_NAME));
115             key.addRequiredLabel();
116             key.setEnabled(isNew);
117             add(key);
118 
119             AjaxTextFieldPanel description = new AjaxTextFieldPanel(
120                     Constants.DESCRIPTION_FIELD_NAME, getString(Constants.DESCRIPTION_FIELD_NAME),
121                     new PropertyModel<>(authModule, Constants.DESCRIPTION_FIELD_NAME));
122             add(description);
123 
124             AjaxDropDownChoicePanel<AuthModuleState> state = new AjaxDropDownChoicePanel<>(
125                     "state", getString("state"), new PropertyModel<>(authModule, "state"));
126             state.setChoices(List.of(AuthModuleState.values()));
127             state.addRequiredLabel();
128             state.setNullValid(false);
129             add(state);
130 
131             add(new AjaxSpinnerFieldPanel.Builder<Integer>().build(
132                     "order",
133                     "order",
134                     Integer.class,
135                     new PropertyModel<>(authModule, "order")).addRequiredLabel());
136 
137             AjaxDropDownChoicePanel<String> conf = new AjaxDropDownChoicePanel<>("conf", getString("type"), isNew
138                     ? Model.of()
139                     : Model.of(authModule.getConf().getClass().getName()));
140             conf.setChoices(authModuleConfs.getObject());
141             conf.addRequiredLabel();
142             conf.setNullValid(false);
143             conf.setEnabled(isNew);
144             conf.add(new AjaxEventBehavior(Constants.ON_CHANGE) {
145 
146                 private static final long serialVersionUID = -7133385027739964990L;
147 
148                 @SuppressWarnings("unchecked")
149                 @Override
150                 protected void onEvent(final AjaxRequestTarget target) {
151                     try {
152                         Class<? extends AuthModuleConf> clazz =
153                                 (Class<? extends AuthModuleConf>) ClassUtils.resolveClassName(
154                                         conf.getModelObject(), ClassUtils.getDefaultClassLoader());
155 
156                         authModule.setConf(clazz.getConstructor().newInstance());
157                         authModuleConfClass.setObject(clazz);
158                     } catch (Exception e) {
159                         LOG.error("Cannot instantiate {}", conf.getModelObject(), e);
160                     }
161                 }
162             });
163             add(conf);
164         }
165     }
166 
167     protected class Configuration extends WizardStep {
168 
169         private static final long serialVersionUID = -785981096328637758L;
170 
171         Configuration(final AuthModuleTO authModule) {
172             add(new BeanPanel<>("bean", new PropertyModel<>(authModule, "conf"), pageRef, "ldap").
173                     setRenderBodyOnly(true));
174         }
175     }
176 
177     protected class GoogleMfaAuthModuleConfLDAP extends WizardStep implements WizardModel.ICondition {
178 
179         private static final long serialVersionUID = 5328049907748683944L;
180 
181         private final Model<Class<? extends AuthModuleConf>> authModuleConfClass;
182 
183         GoogleMfaAuthModuleConfLDAP(
184                 final AuthModuleTO authModule,
185                 final Model<Class<? extends AuthModuleConf>> authModuleConfClass) {
186 
187             this.authModuleConfClass = authModuleConfClass;
188 
189             PropertyModel<GoogleMfaAuthModuleConf.LDAP> beanPanelModel = new PropertyModel<>(authModule, "conf.ldap");
190 
191             AjaxCheckBoxPanel enable = new AjaxCheckBoxPanel("enable", "enableLDAP", new IModel<Boolean>() {
192 
193                 private static final long serialVersionUID = -7126718045816207110L;
194 
195                 @Override
196                 public Boolean getObject() {
197                     return beanPanelModel.getObject() != null;
198                 }
199 
200                 @Override
201                 public void setObject(final Boolean object) {
202                     // nothing to do
203                 }
204             });
205             enable.getField().add(new IndicatorAjaxFormComponentUpdatingBehavior(Constants.ON_CHANGE) {
206 
207                 private static final long serialVersionUID = -1107858522700306810L;
208 
209                 @Override
210                 protected void onUpdate(final AjaxRequestTarget target) {
211                     if (beanPanelModel.getObject() == null) {
212                         beanPanelModel.setObject(new GoogleMfaAuthModuleConf.LDAP());
213                     } else {
214                         beanPanelModel.setObject(null);
215                     }
216                     target.add(GoogleMfaAuthModuleConfLDAP.this);
217                 }
218             });
219             add(enable);
220 
221             add(new BeanPanel<>("bean", beanPanelModel, pageRef).setRenderBodyOnly(true));
222             setOutputMarkupId(true);
223         }
224 
225         @Override
226         public boolean evaluate() {
227             return GoogleMfaAuthModuleConf.class.equals(authModuleConfClass.getObject());
228         }
229     }
230 
231     protected static final class Mapping extends WizardStep {
232 
233         private static final long serialVersionUID = 3454904947720856253L;
234 
235         Mapping(final AuthModuleTO authModule) {
236             setTitleModel(Model.of("Mapping"));
237             setSummaryModel(Model.of(StringUtils.EMPTY));
238             add(new AuthModuleMappingPanel("mapping", authModule));
239         }
240     }
241 }