This is an automated email from the ASF dual-hosted git repository. ilgrosso pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/syncope.git
The following commit(s) were added to refs/heads/master by this push: new 7bb3e38f11 [SYNCOPE-1740] Introducing UsernameAttributeProviderConf (#426) 7bb3e38f11 is described below commit 7bb3e38f11a22d09e0e3d3f30939068ddbefef06 Author: Francesco Chicchiriccò <ilgro...@users.noreply.github.com> AuthorDate: Wed Mar 15 17:37:39 2023 +0100 [SYNCOPE-1740] Introducing UsernameAttributeProviderConf (#426) --- .../clientapps/ClientAppDirectoryPanel.java | 15 +++ .../clientapps/ClientAppModalPanelBuilder.java | 18 ++- ...UsernameAttributeProviderModalPanelBuilder.java | 150 +++++++++++++++++++++ .../AMClassPathScanImplementationContributor.java | 5 + .../console/wizards/AuthModuleWizardBuilder.java | 25 ++-- .../clientapps/ClientAppDirectoryPanel.properties | 5 + .../ClientAppDirectoryPanel_fr_CA.properties | 5 + .../ClientAppDirectoryPanel_it.properties | 5 + .../ClientAppDirectoryPanel_ja.properties | 5 + .../ClientAppDirectoryPanel_pt_BR.properties | 5 + .../ClientAppDirectoryPanel_ru.properties | 5 + ...AttributeProviderModalPanelBuilder$Profile.html | 24 ++++ .../syncope/client/console/panels/BeanPanel.java | 62 +-------- .../client/console/wizards/AttrWizardBuilder.java | 2 +- .../common/lib/auth/OAuth20AuthModuleConf.java | 11 -- .../AnonymousUsernameAttributeProviderConf.java | 65 +++++++++ .../DefaultUsernameAttributeProviderConf.java} | 16 +-- .../GroovyUsernameAttributeProviderConf.java | 64 +++++++++ .../PairwiseOidcUsernameAttributeProviderConf.java | 65 +++++++++ ...ipalAttributeUsernameAttributeProviderConf.java | 64 +++++++++ .../clientapps/UsernameAttributeProviderConf.java} | 28 ++-- .../apache/syncope/common/lib/to/ClientAppTO.java | 61 +++++++-- .../common/lib/types/PersistentIdGenerator.java} | 14 +- .../core/persistence/api/entity/am/ClientApp.java | 21 ++- .../src/test/resources/domains/MasterContent.xml | 3 +- .../jpa/entity/am/AbstractClientApp.java | 63 +++++++-- .../src/test/resources/domains/MasterContent.xml | 2 +- .../java/data/ClientAppDataBinderImpl.java | 8 +- .../apache/syncope/fit/core/AuthModuleITCase.java | 1 - .../concepts/clientapplications.adoc | 3 + .../bootstrap/AuthModulePropertySourceMapper.java | 1 - .../AuthModulePropertySourceMapperTest.java | 1 - .../starter/mapping/AbstractClientAppMapper.java | 6 + ...DefaultUsernameAttributeProviderConfMapper.java | 101 ++++++++++++++ 34 files changed, 778 insertions(+), 151 deletions(-) diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/clientapps/ClientAppDirectoryPanel.java b/client/am/console/src/main/java/org/apache/syncope/client/console/clientapps/ClientAppDirectoryPanel.java index 68ea786219..b6c1f4492e 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/clientapps/ClientAppDirectoryPanel.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/clientapps/ClientAppDirectoryPanel.java @@ -128,6 +128,21 @@ public abstract class ClientAppDirectoryPanel<T extends ClientAppTO> } }, ActionLink.ActionType.EDIT, AMEntitlement.CLIENTAPP_UPDATE); + panel.add(new ActionLink<>() { + + private static final long serialVersionUID = -3722207913631435501L; + + @Override + public void onClick(final AjaxRequestTarget target, final ClientAppTO ignore) { + model.setObject(ClientAppRestClient.read(type, model.getObject().getKey())); + modal.setContent(new UsernameAttributeProviderModalPanelBuilder<>( + type, model.getObject(), modal, pageRef).build(actualId, 1, AjaxWizard.Mode.EDIT)); + modal.header(new Model<>(getString("usernameAttributeProviderConf.title", model))); + modal.show(true); + target.add(modal); + } + }, ActionLink.ActionType.COMPOSE, AMEntitlement.CLIENTAPP_UPDATE); + panel.add(new ActionLink<>() { private static final long serialVersionUID = -3722207913631435501L; diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/clientapps/ClientAppModalPanelBuilder.java b/client/am/console/src/main/java/org/apache/syncope/client/console/clientapps/ClientAppModalPanelBuilder.java index 89c7303a4a..62a31da3a5 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/clientapps/ClientAppModalPanelBuilder.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/clientapps/ClientAppModalPanelBuilder.java @@ -186,6 +186,22 @@ public class ClientAppModalPanelBuilder<T extends ClientAppTO> extends AbstractM "field", "logo", new PropertyModel<>(clientAppTO, "logo"), false)); + fields.add(new AjaxTextFieldPanel( + "field", "theme", + new PropertyModel<>(clientAppTO, "theme"), false)); + + AjaxTextFieldPanel informationUrl = new AjaxTextFieldPanel( + "field", "informationUrl", + new PropertyModel<>(clientAppTO, "informationUrl"), false); + informationUrl.addValidator(new UrlValidator()); + fields.add(informationUrl); + + AjaxTextFieldPanel privacyUrl = new AjaxTextFieldPanel( + "field", "privacyUrl", + new PropertyModel<>(clientAppTO, "privacyUrl"), false); + privacyUrl.addValidator(new UrlValidator()); + fields.add(privacyUrl); + AjaxDropDownChoicePanel<String> accessPolicy = new AjaxDropDownChoicePanel<>( "field", "accessPolicy", new PropertyModel<>(clientAppTO, "accessPolicy"), false); accessPolicy.setChoiceRenderer(new PolicyRenderer(accessPolicies.getObject())); @@ -208,8 +224,6 @@ public class ClientAppModalPanelBuilder<T extends ClientAppTO> extends AbstractM ((AbstractSingleSelectChoice<?>) authPolicy.getField()).setNullValid(true); fields.add(authPolicy); - fields.add(new AjaxTextFieldPanel("field", "theme", new PropertyModel<>(clientAppTO, "theme"), false)); - switch (type) { case CASSP: fields.add(new AjaxTextFieldPanel( diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/clientapps/UsernameAttributeProviderModalPanelBuilder.java b/client/am/console/src/main/java/org/apache/syncope/client/console/clientapps/UsernameAttributeProviderModalPanelBuilder.java new file mode 100644 index 0000000000..c70d211529 --- /dev/null +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/clientapps/UsernameAttributeProviderModalPanelBuilder.java @@ -0,0 +1,150 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.syncope.client.console.clientapps; + +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; +import org.apache.syncope.client.console.SyncopeConsoleSession; +import org.apache.syncope.client.console.SyncopeWebApplication; +import org.apache.syncope.client.console.panels.AbstractModalPanel; +import org.apache.syncope.client.console.panels.BeanPanel; +import org.apache.syncope.client.console.rest.ClientAppRestClient; +import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal; +import org.apache.syncope.client.ui.commons.Constants; +import org.apache.syncope.client.ui.commons.markup.html.form.AjaxDropDownChoicePanel; +import org.apache.syncope.client.ui.commons.pages.BaseWebPage; +import org.apache.syncope.client.ui.commons.panels.WizardModalPanel; +import org.apache.syncope.client.ui.commons.wizards.AbstractModalPanelBuilder; +import org.apache.syncope.client.ui.commons.wizards.AjaxWizard; +import org.apache.syncope.common.lib.clientapps.UsernameAttributeProviderConf; +import org.apache.syncope.common.lib.to.ClientAppTO; +import org.apache.syncope.common.lib.types.ClientAppType; +import org.apache.wicket.PageReference; +import org.apache.wicket.ajax.AjaxEventBehavior; +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.model.LoadableDetachableModel; +import org.apache.wicket.model.Model; +import org.apache.wicket.model.PropertyModel; +import org.springframework.util.ClassUtils; + +public class UsernameAttributeProviderModalPanelBuilder<T extends ClientAppTO> extends AbstractModalPanelBuilder<T> { + + private static final long serialVersionUID = -4106998301911573852L; + + private final LoadableDetachableModel<List<String>> usernameAttributeProviderConfs = + new LoadableDetachableModel<>() { + + private static final long serialVersionUID = 5275935387613157437L; + + @Override + protected List<String> load() { + return SyncopeWebApplication.get().getLookup().getClasses(UsernameAttributeProviderConf.class).stream(). + map(Class::getName).sorted().collect(Collectors.toList()); + } + }; + + private final BaseModal<T> modal; + + private final ClientAppType type; + + public UsernameAttributeProviderModalPanelBuilder( + final ClientAppType type, final T defaultItem, final BaseModal<T> modal, final PageReference pageRef) { + + super(defaultItem, pageRef); + this.type = type; + this.modal = modal; + } + + @Override + public WizardModalPanel<T> build(final String id, final int index, final AjaxWizard.Mode mode) { + return new Profile(newModelObject(), modal, pageRef); + } + + private class Profile extends AbstractModalPanel<T> { + + private static final long serialVersionUID = 7647959917047450318L; + + private final T clientAppTO; + + Profile(final T clientAppTO, final BaseModal<T> modal, final PageReference pageRef) { + super(modal, pageRef); + modal.setFormModel(clientAppTO); + + this.clientAppTO = clientAppTO; + + AjaxDropDownChoicePanel<String> conf = new AjaxDropDownChoicePanel<>( + "conf", "conf", new Model<>()); + Optional.ofNullable(clientAppTO.getUsernameAttributeProviderConf()). + ifPresent(uapc -> conf.setModelObject(uapc.getClass().getName())); + conf.setChoices(usernameAttributeProviderConfs.getObject()); + conf.setNullValid(true); + add(conf); + + PropertyModel<UsernameAttributeProviderConf> beanPanelModel = + new PropertyModel<>(clientAppTO, "usernameAttributeProviderConf"); + BeanPanel<UsernameAttributeProviderConf> bean = new BeanPanel<>( + "bean", + beanPanelModel, + pageRef, + Constants.NAME_FIELD_NAME, + "reportlet"); + add(bean.setRenderBodyOnly(false)); + + conf.add(new AjaxEventBehavior(Constants.ON_CHANGE) { + + private static final long serialVersionUID = -7133385027739964990L; + + @SuppressWarnings("unchecked") + @Override + protected void onEvent(final AjaxRequestTarget target) { + if (conf.getModelObject() == null) { + beanPanelModel.setObject(null); + } else { + try { + Class<? extends UsernameAttributeProviderConf> clazz = + (Class<? extends UsernameAttributeProviderConf>) ClassUtils.resolveClassName( + conf.getModelObject(), ClassUtils.getDefaultClassLoader()); + + beanPanelModel.setObject(clazz.getConstructor().newInstance()); + } catch (Exception e) { + LOG.error("Cannot instantiate {}", conf.getModelObject(), e); + } + } + + target.add(bean); + } + }); + } + + @Override + public void onSubmit(final AjaxRequestTarget target) { + try { + ClientAppRestClient.update(type, clientAppTO); + + SyncopeConsoleSession.get().success(getString(Constants.OPERATION_SUCCEEDED)); + UsernameAttributeProviderModalPanelBuilder.Profile.this.modal.close(target); + } catch (Exception e) { + LOG.error("While creating/updating clientApp", e); + SyncopeConsoleSession.get().onException(e); + } + ((BaseWebPage) pageRef.getPage()).getNotificationPanel().refresh(target); + } + } +} diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/init/AMClassPathScanImplementationContributor.java b/client/am/console/src/main/java/org/apache/syncope/client/console/init/AMClassPathScanImplementationContributor.java index 9a67d508cf..f995e5de2a 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/init/AMClassPathScanImplementationContributor.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/init/AMClassPathScanImplementationContributor.java @@ -21,6 +21,7 @@ package org.apache.syncope.client.console.init; import java.util.Optional; import org.apache.syncope.common.lib.attr.AttrRepoConf; import org.apache.syncope.common.lib.auth.AuthModuleConf; +import org.apache.syncope.common.lib.clientapps.UsernameAttributeProviderConf; import org.apache.syncope.common.lib.policy.AccessPolicyConf; import org.apache.syncope.common.lib.policy.AttrReleasePolicyConf; import org.apache.syncope.common.lib.policy.AuthPolicyConf; @@ -38,6 +39,7 @@ public class AMClassPathScanImplementationContributor implements ClassPathScanIm scanner.addIncludeFilter(new AssignableTypeFilter(AccessPolicyConf.class)); scanner.addIncludeFilter(new AssignableTypeFilter(AttrReleasePolicyConf.class)); scanner.addIncludeFilter(new AssignableTypeFilter(AuthPolicyConf.class)); + scanner.addIncludeFilter(new AssignableTypeFilter(UsernameAttributeProviderConf.class)); } @Override @@ -57,6 +59,9 @@ public class AMClassPathScanImplementationContributor implements ClassPathScanIm if (AuthPolicyConf.class.isAssignableFrom(clazz)) { return Optional.of(AuthPolicyConf.class.getName()); } + if (UsernameAttributeProviderConf.class.isAssignableFrom(clazz)) { + return Optional.of(UsernameAttributeProviderConf.class.getName()); + } return Optional.empty(); } } diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/wizards/AuthModuleWizardBuilder.java b/client/am/console/src/main/java/org/apache/syncope/client/console/wizards/AuthModuleWizardBuilder.java index d976f5ab8a..b07475b0a4 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/wizards/AuthModuleWizardBuilder.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/wizards/AuthModuleWizardBuilder.java @@ -52,24 +52,21 @@ public class AuthModuleWizardBuilder extends BaseAjaxWizardBuilder<AuthModuleTO> private static final long serialVersionUID = -6163230263062920394L; - protected final LoadableDetachableModel<List<String>> authModuleConfs; + protected final LoadableDetachableModel<List<String>> authModuleConfs = new LoadableDetachableModel<>() { + + private static final long serialVersionUID = 5275935387613157437L; + + @Override + protected List<String> load() { + return SyncopeWebApplication.get().getLookup().getClasses(AuthModuleConf.class).stream(). + map(Class::getName).sorted().collect(Collectors.toList()); + } + }; protected Model<Class<? extends AuthModuleConf>> authModuleConfClass = Model.of(); public AuthModuleWizardBuilder(final AuthModuleTO defaultItem, final PageReference pageRef) { - super(defaultItem, pageRef); - - authModuleConfs = new LoadableDetachableModel<>() { - - private static final long serialVersionUID = 5275935387613157437L; - - @Override - protected List<String> load() { - return SyncopeWebApplication.get().getLookup().getClasses(AuthModuleConf.class).stream(). - map(Class::getName).sorted().collect(Collectors.toList()); - } - }; } @Override @@ -152,7 +149,7 @@ public class AuthModuleWizardBuilder extends BaseAjaxWizardBuilder<AuthModuleTO> authModule.setConf(clazz.getConstructor().newInstance()); authModuleConfClass.setObject(clazz); } catch (Exception e) { - LOG.error("During deserialization", e); + LOG.error("Cannot instantiate {}", conf.getModelObject(), e); } } }); diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/clientapps/ClientAppDirectoryPanel.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/clientapps/ClientAppDirectoryPanel.properties index a51a303773..c238d9877b 100644 --- a/client/am/console/src/main/resources/org/apache/syncope/client/console/clientapps/ClientAppDirectoryPanel.properties +++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/clientapps/ClientAppDirectoryPanel.properties @@ -59,3 +59,8 @@ properties.title=Properties for ${name} type_extensions.title=properties bypassApprovalPrompt=Bypass Approval Prompt scopes=Scopes +logo=Logo +informationUrl=Information URL +privacyUrl=Privacy URL +compose.title=username attribute provider +usernameAttributeProviderConf.title=Username Attribute Provider for ${name} diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/clientapps/ClientAppDirectoryPanel_fr_CA.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/clientapps/ClientAppDirectoryPanel_fr_CA.properties index 6ab6528c25..a32e6c0626 100644 --- a/client/am/console/src/main/resources/org/apache/syncope/client/console/clientapps/ClientAppDirectoryPanel_fr_CA.properties +++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/clientapps/ClientAppDirectoryPanel_fr_CA.properties @@ -59,3 +59,8 @@ properties.title=Properties for ${name} type_extensions.title=properties bypassApprovalPrompt=Bypass Approval Prompt scopes=Scopes +logo=Logo +informationUrl=Information URL +privacyUrl=Privacy URL +compose.title=username attribute provider +usernameAttributeProviderConf.title=Username Attribute Provider for ${name} diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/clientapps/ClientAppDirectoryPanel_it.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/clientapps/ClientAppDirectoryPanel_it.properties index 1e4aa4611b..61a171ccef 100644 --- a/client/am/console/src/main/resources/org/apache/syncope/client/console/clientapps/ClientAppDirectoryPanel_it.properties +++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/clientapps/ClientAppDirectoryPanel_it.properties @@ -59,3 +59,8 @@ properties.title=Propriet\u00e0 di ${name} type_extensions.title=propriet\u00e0 bypassApprovalPrompt=Salta richiesta approvazione scopes=Scope +logo=Logo +informationUrl=URL informativa +privacyUrl=URL privacy +compose.title=username attribute provider +usernameAttributeProviderConf.title=Username Attribute Provider per ${name} diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/clientapps/ClientAppDirectoryPanel_ja.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/clientapps/ClientAppDirectoryPanel_ja.properties index ce61864b46..670175063f 100644 --- a/client/am/console/src/main/resources/org/apache/syncope/client/console/clientapps/ClientAppDirectoryPanel_ja.properties +++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/clientapps/ClientAppDirectoryPanel_ja.properties @@ -59,3 +59,8 @@ properties.title=Properties for ${name} type_extensions.title=properties bypassApprovalPrompt=Bypass Approval Prompt scopes=Scopes +logo=Logo +informationUrl=Information URL +privacyUrl=Privacy URL +compose.title=username attribute provider +usernameAttributeProviderConf.title=Username Attribute Provider for ${name} diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/clientapps/ClientAppDirectoryPanel_pt_BR.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/clientapps/ClientAppDirectoryPanel_pt_BR.properties index a51a303773..c238d9877b 100644 --- a/client/am/console/src/main/resources/org/apache/syncope/client/console/clientapps/ClientAppDirectoryPanel_pt_BR.properties +++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/clientapps/ClientAppDirectoryPanel_pt_BR.properties @@ -59,3 +59,8 @@ properties.title=Properties for ${name} type_extensions.title=properties bypassApprovalPrompt=Bypass Approval Prompt scopes=Scopes +logo=Logo +informationUrl=Information URL +privacyUrl=Privacy URL +compose.title=username attribute provider +usernameAttributeProviderConf.title=Username Attribute Provider for ${name} diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/clientapps/ClientAppDirectoryPanel_ru.properties b/client/am/console/src/main/resources/org/apache/syncope/client/console/clientapps/ClientAppDirectoryPanel_ru.properties index b9af8ebe0f..a88ccce746 100644 --- a/client/am/console/src/main/resources/org/apache/syncope/client/console/clientapps/ClientAppDirectoryPanel_ru.properties +++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/clientapps/ClientAppDirectoryPanel_ru.properties @@ -60,3 +60,8 @@ properties.title=Properties for ${name} type_extensions.title=properties bypassApprovalPrompt=Bypass Approval Prompt scopes=Scopes +logo=Logo +informationUrl=Information URL +privacyUrl=Privacy URL +compose.title=username attribute provider +usernameAttributeProviderConf.title=Username Attribute Provider for ${name} diff --git a/client/am/console/src/main/resources/org/apache/syncope/client/console/clientapps/UsernameAttributeProviderModalPanelBuilder$Profile.html b/client/am/console/src/main/resources/org/apache/syncope/client/console/clientapps/UsernameAttributeProviderModalPanelBuilder$Profile.html new file mode 100644 index 0000000000..d86e001927 --- /dev/null +++ b/client/am/console/src/main/resources/org/apache/syncope/client/console/clientapps/UsernameAttributeProviderModalPanelBuilder$Profile.html @@ -0,0 +1,24 @@ +<!-- +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +--> +<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wicket="http://wicket.apache.org"> + <wicket:panel> + <div class="form-group"><span wicket:id="conf">[conf]</span></div> + <span wicket:id="bean"/> + </wicket:panel> +</html> diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/BeanPanel.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/BeanPanel.java index 40eee868fd..bdbb57d963 100644 --- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/BeanPanel.java +++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/BeanPanel.java @@ -34,18 +34,11 @@ import java.util.Map; import java.util.Optional; import java.util.stream.Collectors; import org.apache.commons.lang3.time.DateFormatUtils; -import org.apache.commons.lang3.tuple.Pair; import org.apache.commons.lang3.tuple.Triple; import org.apache.syncope.client.console.SyncopeConsoleSession; import org.apache.syncope.client.console.SyncopeWebApplication; -import org.apache.syncope.client.console.panels.search.AnyObjectSearchPanel; -import org.apache.syncope.client.console.panels.search.GroupSearchPanel; -import org.apache.syncope.client.console.panels.search.SearchClause; -import org.apache.syncope.client.console.panels.search.SearchUtils; -import org.apache.syncope.client.console.panels.search.UserSearchPanel; import org.apache.syncope.client.console.rest.SchemaRestClient; import org.apache.syncope.client.console.wicket.markup.html.form.MultiFieldPanel; -import org.apache.syncope.client.lib.SyncopeClient; import org.apache.syncope.client.ui.commons.DateOps; import org.apache.syncope.client.ui.commons.markup.html.form.AjaxCheckBoxPanel; import org.apache.syncope.client.ui.commons.markup.html.form.AjaxDateTimeFieldPanel; @@ -55,8 +48,6 @@ import org.apache.syncope.client.ui.commons.markup.html.form.AjaxPalettePanel; import org.apache.syncope.client.ui.commons.markup.html.form.AjaxSpinnerFieldPanel; import org.apache.syncope.client.ui.commons.markup.html.form.AjaxTextFieldPanel; import org.apache.syncope.client.ui.commons.markup.html.form.FieldPanel; -import org.apache.syncope.common.lib.report.SearchCondition; -import org.apache.syncope.common.lib.search.AbstractFiqlSearchConditionBuilder; import org.apache.syncope.common.lib.to.SchemaTO; import org.apache.syncope.common.lib.types.SchemaType; import org.apache.wicket.PageReference; @@ -75,8 +66,6 @@ import org.apache.wicket.model.ResourceModel; import org.apache.wicket.model.util.ListModel; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.BeanWrapper; -import org.springframework.beans.PropertyAccessorFactory; import org.springframework.util.ClassUtils; import org.springframework.util.ReflectionUtils; @@ -88,24 +77,10 @@ public class BeanPanel<T extends Serializable> extends Panel { private final List<String> excluded; - private final Map<String, Pair<AbstractFiqlSearchConditionBuilder<?, ?, ?>, List<SearchClause>>> sCondWrapper; - public BeanPanel(final String id, final IModel<T> bean, final PageReference pageRef, final String... excluded) { - this(id, bean, null, pageRef, excluded); - } - - public BeanPanel( - final String id, - final IModel<T> bean, - final Map<String, Pair<AbstractFiqlSearchConditionBuilder<?, ?, ?>, List<SearchClause>>> sCondWrapper, - final PageReference pageRef, - final String... excluded) { - super(id, bean); setOutputMarkupId(true); - this.sCondWrapper = sCondWrapper; - this.excluded = new ArrayList<>(List.of(excluded)); this.excluded.add("serialVersionUID"); this.excluded.add("class"); @@ -157,7 +132,7 @@ public class BeanPanel<T extends Serializable> extends Panel { item.replace(fragment); } - @SuppressWarnings({"unchecked", "rawtypes"}) + @SuppressWarnings({ "unchecked", "rawtypes" }) @Override protected void populateItem(final ListItem<String> item) { item.add(new Fragment("required", "emptyFragment", this)); @@ -172,40 +147,9 @@ public class BeanPanel<T extends Serializable> extends Panel { return; } - BeanWrapper wrapper = PropertyAccessorFactory.forBeanPropertyAccess(bean.getObject()); - Panel panel; - SearchCondition scondAnnot = field.getAnnotation(SearchCondition.class); - if (scondAnnot != null) { - String fiql = (String) wrapper.getPropertyValue(fieldName); - - List<SearchClause> clauses = SearchUtils.getSearchClauses(fiql); - - AbstractFiqlSearchConditionBuilder<?, ?, ?> builder; - switch (scondAnnot.type()) { - case "USER": - panel = new UserSearchPanel.Builder( - new ListModel<>(clauses), pageRef).required(false).build("value"); - builder = SyncopeClient.getUserSearchConditionBuilder(); - break; - - case "GROUP": - panel = new GroupSearchPanel.Builder( - new ListModel<>(clauses), pageRef).required(false).build("value"); - builder = SyncopeClient.getGroupSearchConditionBuilder(); - break; - - default: - panel = new AnyObjectSearchPanel.Builder( - scondAnnot.type(), - new ListModel<>(clauses), pageRef).required(false).build("value"); - builder = SyncopeClient.getAnyObjectSearchConditionBuilder(scondAnnot.type()); - } - - Optional.ofNullable(BeanPanel.this.sCondWrapper). - ifPresent(scw -> scw.put(fieldName, Pair.of(builder, clauses))); - } else if (List.class.equals(field.getType())) { + if (List.class.equals(field.getType())) { Class<?> listItemType = field.getGenericType() instanceof ParameterizedType ? (Class<?>) ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0] : String.class; @@ -278,7 +222,7 @@ public class BeanPanel<T extends Serializable> extends Panel { item.add(panel.setRenderBodyOnly(true)); } - }.setReuseItems(true).setOutputMarkupId(true)); + }.setReuseItems(false)); } @SuppressWarnings({ "unchecked", "rawtypes" }) diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wizards/AttrWizardBuilder.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wizards/AttrWizardBuilder.java index 03e0221e03..8eb63d4ef7 100644 --- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wizards/AttrWizardBuilder.java +++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wizards/AttrWizardBuilder.java @@ -30,7 +30,7 @@ import org.apache.wicket.model.PropertyModel; public abstract class AttrWizardBuilder extends BaseAjaxWizardBuilder<Attr> { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 7618745848468848923L; public AttrWizardBuilder(final Attr defaultItem, final PageReference pageRef) { super(defaultItem, pageRef); diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/OAuth20AuthModuleConf.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/OAuth20AuthModuleConf.java index 34d445743f..86fbde2282 100644 --- a/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/OAuth20AuthModuleConf.java +++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/auth/OAuth20AuthModuleConf.java @@ -18,7 +18,6 @@ */ package org.apache.syncope.common.lib.auth; -import java.util.LinkedHashMap; import java.util.Map; import org.apache.syncope.common.lib.to.AuthModuleTO; @@ -30,8 +29,6 @@ public class OAuth20AuthModuleConf extends AbstractOIDCAuthModuleConf implements protected String profileUrl; - protected Map<String, String> profileAttrs = new LinkedHashMap<>(); - protected boolean withState; protected String profileVerb = "POST"; @@ -44,14 +41,6 @@ public class OAuth20AuthModuleConf extends AbstractOIDCAuthModuleConf implements this.authUrl = authUrl; } - public Map<String, String> getProfileAttrs() { - return profileAttrs; - } - - public void setProfileAttrs(final Map<String, String> profileAttrs) { - this.profileAttrs = profileAttrs; - } - public boolean isWithState() { return withState; } diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/clientapps/AnonymousUsernameAttributeProviderConf.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/clientapps/AnonymousUsernameAttributeProviderConf.java new file mode 100644 index 0000000000..101f145a89 --- /dev/null +++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/clientapps/AnonymousUsernameAttributeProviderConf.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.syncope.common.lib.clientapps; + +import java.util.Objects; +import org.apache.syncope.common.lib.types.PersistentIdGenerator; + +public class AnonymousUsernameAttributeProviderConf implements UsernameAttributeProviderConf { + + private static final long serialVersionUID = -4762223354637243358L; + + private PersistentIdGenerator persistentIdGenerator = PersistentIdGenerator.SHIBBOLETH; + + public PersistentIdGenerator getPersistentIdGenerator() { + return persistentIdGenerator; + } + + public void setPersistentIdGenerator(final PersistentIdGenerator persistentIdGenerator) { + this.persistentIdGenerator = persistentIdGenerator; + } + + @Override + public void map(final Mapper mapper) { + mapper.map(this); + } + + @Override + public int hashCode() { + int hash = 7; + hash = 97 * hash + Objects.hashCode(this.persistentIdGenerator); + return hash; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final AnonymousUsernameAttributeProviderConf other = + (AnonymousUsernameAttributeProviderConf) obj; + return Objects.equals(this.persistentIdGenerator, other.persistentIdGenerator); + } +} diff --git a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/report/SearchCondition.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/clientapps/DefaultUsernameAttributeProviderConf.java similarity index 70% copy from common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/report/SearchCondition.java copy to common/am/lib/src/main/java/org/apache/syncope/common/lib/clientapps/DefaultUsernameAttributeProviderConf.java index 0570dabdfe..b72113a9cf 100644 --- a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/report/SearchCondition.java +++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/clientapps/DefaultUsernameAttributeProviderConf.java @@ -16,16 +16,14 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.syncope.common.lib.report; +package org.apache.syncope.common.lib.clientapps; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; +public class DefaultUsernameAttributeProviderConf implements UsernameAttributeProviderConf { -@Target({ ElementType.FIELD }) -@Retention(RetentionPolicy.RUNTIME) -public @interface SearchCondition { + private static final long serialVersionUID = 4315599812817709524L; - String type() default "USER"; + @Override + public void map(final Mapper mapper) { + mapper.map(this); + } } diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/clientapps/GroovyUsernameAttributeProviderConf.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/clientapps/GroovyUsernameAttributeProviderConf.java new file mode 100644 index 0000000000..1c00786bd7 --- /dev/null +++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/clientapps/GroovyUsernameAttributeProviderConf.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.syncope.common.lib.clientapps; + +import java.util.Objects; + +public class GroovyUsernameAttributeProviderConf implements UsernameAttributeProviderConf { + + private static final long serialVersionUID = -4762223354637243358L; + + private String groovyScript; + + public String getGroovyScript() { + return groovyScript; + } + + public void setGroovyScript(final String groovyScript) { + this.groovyScript = groovyScript; + } + + @Override + public void map(final Mapper mapper) { + mapper.map(this); + } + + @Override + public int hashCode() { + int hash = 7; + hash = 97 * hash + Objects.hashCode(this.groovyScript); + return hash; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final GroovyUsernameAttributeProviderConf other = + (GroovyUsernameAttributeProviderConf) obj; + return Objects.equals(this.groovyScript, other.groovyScript); + } +} diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/clientapps/PairwiseOidcUsernameAttributeProviderConf.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/clientapps/PairwiseOidcUsernameAttributeProviderConf.java new file mode 100644 index 0000000000..9cf00f514a --- /dev/null +++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/clientapps/PairwiseOidcUsernameAttributeProviderConf.java @@ -0,0 +1,65 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.syncope.common.lib.clientapps; + +import java.util.Objects; +import org.apache.syncope.common.lib.types.PersistentIdGenerator; + +public class PairwiseOidcUsernameAttributeProviderConf implements UsernameAttributeProviderConf { + + private static final long serialVersionUID = -4762223354637243358L; + + private PersistentIdGenerator persistentIdGenerator = PersistentIdGenerator.OIDC; + + public PersistentIdGenerator getPersistentIdGenerator() { + return persistentIdGenerator; + } + + public void setPersistentIdGenerator(final PersistentIdGenerator persistentIdGenerator) { + this.persistentIdGenerator = persistentIdGenerator; + } + + @Override + public void map(final Mapper mapper) { + mapper.map(this); + } + + @Override + public int hashCode() { + int hash = 7; + hash = 97 * hash + Objects.hashCode(this.persistentIdGenerator); + return hash; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final PairwiseOidcUsernameAttributeProviderConf other = + (PairwiseOidcUsernameAttributeProviderConf) obj; + return Objects.equals(this.persistentIdGenerator, other.persistentIdGenerator); + } +} diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/clientapps/PrincipalAttributeUsernameAttributeProviderConf.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/clientapps/PrincipalAttributeUsernameAttributeProviderConf.java new file mode 100644 index 0000000000..4f9c4121bd --- /dev/null +++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/clientapps/PrincipalAttributeUsernameAttributeProviderConf.java @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.syncope.common.lib.clientapps; + +import java.util.Objects; + +public class PrincipalAttributeUsernameAttributeProviderConf implements UsernameAttributeProviderConf { + + private static final long serialVersionUID = -4762223354637243358L; + + private String usernameAttribute; + + public String getUsernameAttribute() { + return usernameAttribute; + } + + public void setUsernameAttribute(final String usernameAttribute) { + this.usernameAttribute = usernameAttribute; + } + + @Override + public void map(final Mapper mapper) { + mapper.map(this); + } + + @Override + public int hashCode() { + int hash = 7; + hash = 97 * hash + Objects.hashCode(this.usernameAttribute); + return hash; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final PrincipalAttributeUsernameAttributeProviderConf other = + (PrincipalAttributeUsernameAttributeProviderConf) obj; + return Objects.equals(this.usernameAttribute, other.usernameAttribute); + } +} diff --git a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/report/SearchCondition.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/clientapps/UsernameAttributeProviderConf.java similarity index 53% copy from common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/report/SearchCondition.java copy to common/am/lib/src/main/java/org/apache/syncope/common/lib/clientapps/UsernameAttributeProviderConf.java index 0570dabdfe..d349670d5a 100644 --- a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/report/SearchCondition.java +++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/clientapps/UsernameAttributeProviderConf.java @@ -16,16 +16,26 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.syncope.common.lib.report; +package org.apache.syncope.common.lib.clientapps; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import org.apache.syncope.common.lib.BaseBean; -@Target({ ElementType.FIELD }) -@Retention(RetentionPolicy.RUNTIME) -public @interface SearchCondition { +@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.PROPERTY, property = "_class") +public interface UsernameAttributeProviderConf extends BaseBean { - String type() default "USER"; + interface Mapper { + + void map(AnonymousUsernameAttributeProviderConf conf); + + void map(DefaultUsernameAttributeProviderConf conf); + + void map(GroovyUsernameAttributeProviderConf conf); + + void map(PairwiseOidcUsernameAttributeProviderConf conf); + + void map(PrincipalAttributeUsernameAttributeProviderConf conf); + } + + void map(Mapper mapper); } diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/to/ClientAppTO.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/to/ClientAppTO.java index 4fcee875bf..b25a8b9dfc 100644 --- a/common/am/lib/src/main/java/org/apache/syncope/common/lib/to/ClientAppTO.java +++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/to/ClientAppTO.java @@ -30,6 +30,7 @@ import java.util.List; import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder; import org.apache.syncope.common.lib.Attr; +import org.apache.syncope.common.lib.clientapps.UsernameAttributeProviderConf; @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "_class") @JsonPropertyOrder(value = { "_class", "key", "description" }) @@ -55,14 +56,20 @@ public abstract class ClientAppTO implements NamedEntityTO { private String logo; + private String theme; + + private String informationUrl; + + private String privacyUrl; + + private UsernameAttributeProviderConf usernameAttributeProviderConf; + private String authPolicy; private String accessPolicy; private String attrReleasePolicy; - private String theme; - private final List<Attr> properties = new ArrayList<>(); @Schema(name = "_class", requiredMode = Schema.RequiredMode.REQUIRED) @@ -96,14 +103,6 @@ public abstract class ClientAppTO implements NamedEntityTO { this.authPolicy = authPolicy; } - public String getTheme() { - return theme; - } - - public void setTheme(final String theme) { - this.theme = theme; - } - @Override public String getKey() { return key; @@ -157,6 +156,38 @@ public abstract class ClientAppTO implements NamedEntityTO { this.logo = logo; } + public String getTheme() { + return theme; + } + + public void setTheme(final String theme) { + this.theme = theme; + } + + public String getInformationUrl() { + return informationUrl; + } + + public void setInformationUrl(final String informationUrl) { + this.informationUrl = informationUrl; + } + + public String getPrivacyUrl() { + return privacyUrl; + } + + public void setPrivacyUrl(final String privacyUrl) { + this.privacyUrl = privacyUrl; + } + + public UsernameAttributeProviderConf getUsernameAttributeProviderConf() { + return usernameAttributeProviderConf; + } + + public void setUsernameAttributeProviderConf(final UsernameAttributeProviderConf usernameAttributeProviderConf) { + this.usernameAttributeProviderConf = usernameAttributeProviderConf; + } + @JacksonXmlElementWrapper(localName = "properties") @JacksonXmlProperty(localName = "property") public List<Attr> getProperties() { @@ -173,10 +204,13 @@ public abstract class ClientAppTO implements NamedEntityTO { .append(name) .append(description) .append(logo) + .append(theme) + .append(informationUrl) + .append(privacyUrl) + .append(usernameAttributeProviderConf) .append(authPolicy) .append(accessPolicy) .append(attrReleasePolicy) - .append(theme) .append(properties) .toHashCode(); } @@ -201,10 +235,13 @@ public abstract class ClientAppTO implements NamedEntityTO { .append(this.name, rhs.name) .append(this.description, rhs.description) .append(this.logo, rhs.logo) + .append(this.theme, rhs.theme) + .append(this.informationUrl, rhs.informationUrl) + .append(this.privacyUrl, rhs.privacyUrl) + .append(this.usernameAttributeProviderConf, rhs.usernameAttributeProviderConf) .append(this.authPolicy, rhs.authPolicy) .append(this.accessPolicy, rhs.accessPolicy) .append(this.attrReleasePolicy, rhs.attrReleasePolicy) - .append(this.theme, rhs.theme) .append(this.properties, rhs.properties) .isEquals(); } diff --git a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/report/SearchCondition.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/PersistentIdGenerator.java similarity index 70% rename from common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/report/SearchCondition.java rename to common/am/lib/src/main/java/org/apache/syncope/common/lib/types/PersistentIdGenerator.java index 0570dabdfe..f30c0818e0 100644 --- a/common/idrepo/lib/src/main/java/org/apache/syncope/common/lib/report/SearchCondition.java +++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/PersistentIdGenerator.java @@ -16,16 +16,10 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.syncope.common.lib.report; +package org.apache.syncope.common.lib.types; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; +public enum PersistentIdGenerator { + SHIBBOLETH, + OIDC; -@Target({ ElementType.FIELD }) -@Retention(RetentionPolicy.RUNTIME) -public @interface SearchCondition { - - String type() default "USER"; } diff --git a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/am/ClientApp.java b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/am/ClientApp.java index 800f0c9923..e82890ee0d 100644 --- a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/am/ClientApp.java +++ b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/am/ClientApp.java @@ -20,6 +20,7 @@ package org.apache.syncope.core.persistence.api.entity.am; import java.util.List; import org.apache.syncope.common.lib.Attr; +import org.apache.syncope.common.lib.clientapps.UsernameAttributeProviderConf; import org.apache.syncope.core.persistence.api.entity.Entity; import org.apache.syncope.core.persistence.api.entity.Realm; import org.apache.syncope.core.persistence.api.entity.policy.AccessPolicy; @@ -44,6 +45,22 @@ public interface ClientApp extends Entity { void setLogo(String logo); + void setTheme(String name); + + String getTheme(); + + String getInformationUrl(); + + void setInformationUrl(String informationUrl); + + String getPrivacyUrl(); + + void setPrivacyUrl(String privacyUrl); + + UsernameAttributeProviderConf getUsernameAttributeProviderConf(); + + void setUsernameAttributeProviderConf(UsernameAttributeProviderConf conf); + AuthPolicy getAuthPolicy(); void setAuthPolicy(AuthPolicy policy); @@ -60,10 +77,6 @@ public interface ClientApp extends Entity { void setRealm(Realm realm); - void setTheme(String name); - - String getTheme(); - List<Attr> getProperties(); void setProperties(List<Attr> properties); diff --git a/core/persistence-jpa-json/src/test/resources/domains/MasterContent.xml b/core/persistence-jpa-json/src/test/resources/domains/MasterContent.xml index cbfd264869..223c6b0719 100644 --- a/core/persistence-jpa-json/src/test/resources/domains/MasterContent.xml +++ b/core/persistence-jpa-json/src/test/resources/domains/MasterContent.xml @@ -88,8 +88,7 @@ under the License. <AuthModule id="DefaultU2FAuthModule" authModuleState="ACTIVE" description="U2F auth module" jsonConf='{"_class":"org.apache.syncope.common.lib.auth.U2FAuthModuleConf","expireDevices":40}'/> <AuthModule id="DefaultOAuth20AuthModule" description="OAuth20 auth module" authModuleOrder="0" - jsonConf='{"_class":"org.apache.syncope.common.lib.auth.OAuth20AuthModuleConf","clientName":"oauth20","clientId":"OAUTH20","clientSecret":"secret","enabled":true,"customParams":{},"tokenUrl":"https://localhost/oauth2/token","responseType":"code","scope":"oauth test","userIdAttribute":"username","authUrl":"https://localhost/oauth2/auth","profileUrl":"https://localhost/oauth2/profile","profileAttrs":{},"withState":false,"profileVerb":"POST"}' authModuleState="ACTIVE"/> - + jsonConf='{"_class":"org.apache.syncope.common.lib.auth.OAuth20AuthModuleConf","clientName":"oauth20","clientId":"OAUTH20","clientSecret":"secret","enabled":true,"customParams":{},"tokenUrl":"https://localhost/oauth2/token","responseType":"code","scope":"oauth test","userIdAttribute":"username","authUrl":"https://localhost/oauth2/auth","profileUrl":"https://localhost/oauth2/profile","withState":false,"profileVerb":"POST"}' authModuleState="ACTIVE"/> <!-- Attribute repositories --> <AttrRepo id="DefaultLDAPAttrRepo" attrRepoState="ACTIVE" diff --git a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/am/AbstractClientApp.java b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/am/AbstractClientApp.java index aa6acd3311..8a76bb9ed9 100644 --- a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/am/AbstractClientApp.java +++ b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/am/AbstractClientApp.java @@ -26,7 +26,9 @@ import jakarta.persistence.ManyToOne; import jakarta.persistence.MappedSuperclass; import java.util.ArrayList; import java.util.List; +import java.util.Optional; import org.apache.syncope.common.lib.Attr; +import org.apache.syncope.common.lib.clientapps.UsernameAttributeProviderConf; import org.apache.syncope.core.persistence.api.entity.Realm; import org.apache.syncope.core.persistence.api.entity.am.ClientApp; import org.apache.syncope.core.persistence.api.entity.policy.AccessPolicy; @@ -53,15 +55,19 @@ public class AbstractClientApp extends AbstractGeneratedKeyEntity implements Cli @Column(unique = true, nullable = false) private Long clientAppId; - @Column private String description; - @Column private String logo; - @Column + @Lob + private String usernameAttributeProviderConf; + private String theme; + private String informationUrl; + + private String privacyUrl; + @ManyToOne(fetch = FetchType.EAGER) private JPARealm realm; @@ -117,6 +123,47 @@ public class AbstractClientApp extends AbstractGeneratedKeyEntity implements Cli this.logo = logo; } + @Override + public String getTheme() { + return theme; + } + + @Override + public void setTheme(final String theme) { + this.theme = theme; + } + + @Override + public String getInformationUrl() { + return informationUrl; + } + + @Override + public void setInformationUrl(final String informationUrl) { + this.informationUrl = informationUrl; + } + + @Override + public String getPrivacyUrl() { + return privacyUrl; + } + + @Override + public void setPrivacyUrl(final String privacyUrl) { + this.privacyUrl = privacyUrl; + } + + @Override + public UsernameAttributeProviderConf getUsernameAttributeProviderConf() { + return Optional.ofNullable(usernameAttributeProviderConf). + map(conf -> POJOHelper.deserialize(conf, UsernameAttributeProviderConf.class)).orElse(null); + } + + @Override + public void setUsernameAttributeProviderConf(final UsernameAttributeProviderConf conf) { + this.usernameAttributeProviderConf = conf == null ? null : POJOHelper.serialize(conf); + } + @Override public JPAAuthPolicy getAuthPolicy() { return authPolicy; @@ -161,16 +208,6 @@ public class AbstractClientApp extends AbstractGeneratedKeyEntity implements Cli this.realm = (JPARealm) realm; } - @Override - public String getTheme() { - return theme; - } - - @Override - public void setTheme(final String theme) { - this.theme = theme; - } - @Override public List<Attr> getProperties() { return properties == null diff --git a/core/persistence-jpa/src/test/resources/domains/MasterContent.xml b/core/persistence-jpa/src/test/resources/domains/MasterContent.xml index a2231a184c..a2f86a8566 100644 --- a/core/persistence-jpa/src/test/resources/domains/MasterContent.xml +++ b/core/persistence-jpa/src/test/resources/domains/MasterContent.xml @@ -88,7 +88,7 @@ under the License. <AuthModule id="DefaultU2FAuthModule" authModuleState="ACTIVE" description="U2F auth module" jsonConf='{"_class":"org.apache.syncope.common.lib.auth.U2FAuthModuleConf","expireDevices":40}'/> <AuthModule id="DefaultOAuth20AuthModule" description="OAuth20 auth module" authModuleOrder="0" - jsonConf='{"_class":"org.apache.syncope.common.lib.auth.OAuth20AuthModuleConf","clientName":"oauth20","clientId":"OAUTH20","clientSecret":"secret","enabled":true,"customParams":{},"tokenUrl":"https://localhost/oauth2/token","responseType":"code","scope":"oauth test","userIdAttribute":"username","authUrl":"https://localhost/oauth2/auth","profileUrl":"https://localhost/oauth2/profile","profileAttrs":{},"withState":false,"profileVerb":"POST"}' authModuleState="ACTIVE"/> + jsonConf='{"_class":"org.apache.syncope.common.lib.auth.OAuth20AuthModuleConf","clientName":"oauth20","clientId":"OAUTH20","clientSecret":"secret","enabled":true,"customParams":{},"tokenUrl":"https://localhost/oauth2/token","responseType":"code","scope":"oauth test","userIdAttribute":"username","authUrl":"https://localhost/oauth2/auth","profileUrl":"https://localhost/oauth2/profile","withState":false,"profileVerb":"POST"}' authModuleState="ACTIVE"/> <!-- Attribute repositories --> <AttrRepo id="DefaultLDAPAttrRepo" attrRepoState="ACTIVE" diff --git a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ClientAppDataBinderImpl.java b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ClientAppDataBinderImpl.java index 13b858d728..d5c441c7c5 100644 --- a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ClientAppDataBinderImpl.java +++ b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/ClientAppDataBinderImpl.java @@ -154,10 +154,13 @@ public class ClientAppDataBinderImpl implements ClientAppDataBinder { clientAppTO.setKey(clientApp.getKey()); clientAppTO.setRealm(Optional.ofNullable(clientApp.getRealm()).map(Realm::getFullPath).orElse(null)); clientAppTO.setName(clientApp.getName()); + clientAppTO.setClientAppId(clientApp.getClientAppId()); clientAppTO.setDescription(clientApp.getDescription()); clientAppTO.setLogo(clientApp.getLogo()); - clientAppTO.setClientAppId(clientApp.getClientAppId()); clientAppTO.setTheme(clientApp.getTheme()); + clientAppTO.setInformationUrl(clientApp.getInformationUrl()); + clientAppTO.setPrivacyUrl(clientApp.getPrivacyUrl()); + clientAppTO.setUsernameAttributeProviderConf(clientApp.getUsernameAttributeProviderConf()); clientAppTO.setAuthPolicy( Optional.ofNullable(clientApp.getAuthPolicy()).map(AuthPolicy::getKey).orElse(null)); @@ -274,6 +277,9 @@ public class ClientAppDataBinderImpl implements ClientAppDataBinder { clientApp.setDescription(clientAppTO.getDescription()); clientApp.setLogo(clientAppTO.getLogo()); clientApp.setTheme(clientAppTO.getTheme()); + clientApp.setInformationUrl(clientAppTO.getInformationUrl()); + clientApp.setPrivacyUrl(clientAppTO.getPrivacyUrl()); + clientApp.setUsernameAttributeProviderConf(clientAppTO.getUsernameAttributeProviderConf()); if (clientAppTO.getAuthPolicy() == null) { clientApp.setAuthPolicy(null); diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AuthModuleITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AuthModuleITCase.java index 9b46d13a75..99bd35631b 100644 --- a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AuthModuleITCase.java +++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/AuthModuleITCase.java @@ -147,7 +147,6 @@ public class AuthModuleITCase extends AbstractITCase { OAuth20AuthModuleConf.class.cast(conf).setEnabled(true); OAuth20AuthModuleConf.class.cast(conf).setCustomParams(Map.of("param1", "param1")); OAuth20AuthModuleConf.class.cast(conf).setAuthUrl("https://localhost/oauth2/auth"); - OAuth20AuthModuleConf.class.cast(conf).setProfileAttrs(Map.of("uid", "id")); OAuth20AuthModuleConf.class.cast(conf).setProfileUrl("https://localhost/oauth2/profile"); OAuth20AuthModuleConf.class.cast(conf).setTokenUrl("https://localhost/oauth2/token"); OAuth20AuthModuleConf.class.cast(conf).setResponseType("code"); diff --git a/src/main/asciidoc/reference-guide/concepts/clientapplications.adoc b/src/main/asciidoc/reference-guide/concepts/clientapplications.adoc index 46f741723f..dd7b1a9494 100644 --- a/src/main/asciidoc/reference-guide/concepts/clientapplications.adoc +++ b/src/main/asciidoc/reference-guide/concepts/clientapplications.adoc @@ -30,8 +30,11 @@ Depending on the communication protocol, the following client applications are s When defining a client application, the following parameters shall be specified: . id - unique number identifier of the current client application +. <<realms,realm>> - used to inherit policies . name - regular expression to match requests . description - optional textual description +. username attribute provider, mapping to +https://apereo.github.io/cas/6.6.x/integration/Attribute-Release-PrincipalId-Attribute.html[CAS Attribute-based Principal Id^] . <<policies-authentication,authentication policy>> . <<policies-access,access policy>> . <<policies-attribute-release,attribute release policy>> diff --git a/wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/AuthModulePropertySourceMapper.java b/wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/AuthModulePropertySourceMapper.java index 7044758142..04386f5606 100644 --- a/wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/AuthModulePropertySourceMapper.java +++ b/wa/bootstrap/src/main/java/org/apache/syncope/wa/bootstrap/AuthModulePropertySourceMapper.java @@ -176,7 +176,6 @@ public class AuthModulePropertySourceMapper extends PropertySourceMapper impleme props.setEnabled(authModuleTO.getState() == AuthModuleState.ACTIVE); props.setCustomParams(conf.getCustomParams()); props.setAuthUrl(conf.getAuthUrl()); - props.setProfileAttrs(conf.getProfileAttrs()); props.setProfileVerb(conf.getProfileVerb()); props.setProfileUrl(conf.getProfileUrl()); props.setTokenUrl(conf.getTokenUrl()); diff --git a/wa/bootstrap/src/test/java/org/apache/syncope/wa/bootstrap/AuthModulePropertySourceMapperTest.java b/wa/bootstrap/src/test/java/org/apache/syncope/wa/bootstrap/AuthModulePropertySourceMapperTest.java index 88d0452182..a6934e0c6a 100644 --- a/wa/bootstrap/src/test/java/org/apache/syncope/wa/bootstrap/AuthModulePropertySourceMapperTest.java +++ b/wa/bootstrap/src/test/java/org/apache/syncope/wa/bootstrap/AuthModulePropertySourceMapperTest.java @@ -62,7 +62,6 @@ public class AuthModulePropertySourceMapperTest { conf.setEnabled(true); conf.setCustomParams(Map.of("param1", "param1")); conf.setAuthUrl("https://localhost/oauth2/auth"); - conf.setProfileAttrs(Map.of("uid", "id")); conf.setProfileUrl("https://localhost/oauth2/profile"); conf.setTokenUrl("https://localhost/oauth2/token"); conf.setResponseType("code"); diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/AbstractClientAppMapper.java b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/AbstractClientAppMapper.java index 37e3f1b25e..75aebb1030 100644 --- a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/AbstractClientAppMapper.java +++ b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/AbstractClientAppMapper.java @@ -19,6 +19,7 @@ package org.apache.syncope.wa.starter.mapping; import java.util.Map; +import java.util.Optional; import java.util.stream.Collectors; import org.apache.syncope.common.lib.Attr; import org.apache.syncope.common.lib.to.ClientAppTO; @@ -37,6 +38,11 @@ abstract class AbstractClientAppMapper implements ClientAppMapper { service.setName(clientApp.getName()); service.setDescription(clientApp.getDescription()); service.setLogo(clientApp.getLogo()); + service.setTheme(clientApp.getTheme()); + service.setInformationUrl(clientApp.getInformationUrl()); + service.setPrivacyUrl(clientApp.getPrivacyUrl()); + Optional.ofNullable(clientApp.getUsernameAttributeProviderConf()). + ifPresent(conf -> conf.map(new DefaultUsernameAttributeProviderConfMapper(service))); if (!clientApp.getProperties().isEmpty()) { Map<String, RegisteredServiceProperty> properties = clientApp.getProperties().stream(). diff --git a/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/DefaultUsernameAttributeProviderConfMapper.java b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/DefaultUsernameAttributeProviderConfMapper.java new file mode 100644 index 0000000000..10746e8b79 --- /dev/null +++ b/wa/starter/src/main/java/org/apache/syncope/wa/starter/mapping/DefaultUsernameAttributeProviderConfMapper.java @@ -0,0 +1,101 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.syncope.wa.starter.mapping; + +import java.util.Optional; +import org.apache.syncope.common.lib.clientapps.AnonymousUsernameAttributeProviderConf; +import org.apache.syncope.common.lib.clientapps.DefaultUsernameAttributeProviderConf; +import org.apache.syncope.common.lib.clientapps.GroovyUsernameAttributeProviderConf; +import org.apache.syncope.common.lib.clientapps.PairwiseOidcUsernameAttributeProviderConf; +import org.apache.syncope.common.lib.clientapps.PrincipalAttributeUsernameAttributeProviderConf; +import org.apache.syncope.common.lib.clientapps.UsernameAttributeProviderConf; +import org.apache.syncope.common.lib.types.PersistentIdGenerator; +import org.apereo.cas.authentication.principal.OidcPairwisePersistentIdGenerator; +import org.apereo.cas.authentication.principal.ShibbolethCompatiblePersistentIdGenerator; +import org.apereo.cas.services.AnonymousRegisteredServiceUsernameAttributeProvider; +import org.apereo.cas.services.BaseWebBasedRegisteredService; +import org.apereo.cas.services.DefaultRegisteredServiceUsernameProvider; +import org.apereo.cas.services.GroovyRegisteredServiceUsernameProvider; +import org.apereo.cas.services.PairwiseOidcRegisteredServiceUsernameAttributeProvider; +import org.apereo.cas.services.PrincipalAttributeRegisteredServiceUsernameProvider; +import org.apereo.cas.util.RandomUtils; + +public class DefaultUsernameAttributeProviderConfMapper implements UsernameAttributeProviderConf.Mapper { + + protected static Optional<org.apereo.cas.authentication.principal.PersistentIdGenerator> toPersistentIdGenerator( + final PersistentIdGenerator persistentIdGenerator) { + + if (persistentIdGenerator == null) { + return Optional.empty(); + } + + org.apereo.cas.authentication.principal.PersistentIdGenerator result = null; + switch (persistentIdGenerator) { + case SHIBBOLETH: + result = new ShibbolethCompatiblePersistentIdGenerator(RandomUtils.randomAlphanumeric(16)); + break; + + case OIDC: + result = new OidcPairwisePersistentIdGenerator(); + break; + + default: + } + + return Optional.ofNullable(result); + } + + protected final BaseWebBasedRegisteredService service; + + public DefaultUsernameAttributeProviderConfMapper(final BaseWebBasedRegisteredService service) { + this.service = service; + } + + @Override + public void map(final AnonymousUsernameAttributeProviderConf conf) { + AnonymousRegisteredServiceUsernameAttributeProvider arsuap = + new AnonymousRegisteredServiceUsernameAttributeProvider(); + toPersistentIdGenerator(conf.getPersistentIdGenerator()).ifPresent(arsuap::setPersistentIdGenerator); + service.setUsernameAttributeProvider(arsuap); + } + + @Override + public void map(final DefaultUsernameAttributeProviderConf conf) { + service.setUsernameAttributeProvider(new DefaultRegisteredServiceUsernameProvider()); + } + + @Override + public void map(final GroovyUsernameAttributeProviderConf conf) { + service.setUsernameAttributeProvider(new GroovyRegisteredServiceUsernameProvider(conf.getGroovyScript())); + } + + @Override + public void map(final PairwiseOidcUsernameAttributeProviderConf conf) { + PairwiseOidcRegisteredServiceUsernameAttributeProvider porsuap = + new PairwiseOidcRegisteredServiceUsernameAttributeProvider(); + toPersistentIdGenerator(conf.getPersistentIdGenerator()).ifPresent(porsuap::setPersistentIdGenerator); + service.setUsernameAttributeProvider(porsuap); + } + + @Override + public void map(final PrincipalAttributeUsernameAttributeProviderConf conf) { + service.setUsernameAttributeProvider( + new PrincipalAttributeRegisteredServiceUsernameProvider(conf.getUsernameAttribute())); + } +}