This is an automated email from the ASF dual-hosted git repository. ilgrosso pushed a commit to branch 3_0_X in repository https://gitbox.apache.org/repos/asf/syncope.git
commit ecffb85b6f089df3e57f120661de1716cf4b6370 Author: Francesco Chicchiriccò <[email protected]> AuthorDate: Fri May 16 19:10:51 2025 +0200 [SYNCOPE-1866] AuthProfile management in Enduser (#1083) --- .../authprofiles/AuthProfileDirectoryPanel.java | 43 ---- .../AuthProfileItemDirectoryPanel.java | 2 - .../authprofiles/AuthProfileWizardBuilder.java | 4 +- .../client/console/rest/AuthProfileRestClient.java | 4 - client/am/enduser/pom.xml | 84 +++++++ .../syncope/client/enduser/AMEnduserContext.java | 34 +++ .../syncope/client/enduser/pages/AuthProfile.java | 220 ++++++++++++++++++ .../enduser}/rest/AuthProfileRestClient.java | 35 ++- .../syncope/client/enduser/pages/AuthProfile.html | 255 +++++++++++++++++++++ .../client/enduser/pages/AuthProfile.properties} | 30 ++- .../enduser/pages/AuthProfile_it.properties} | 30 ++- .../enduser/pages/AuthProfile_ja.properties} | 30 ++- .../enduser/pages/AuthProfile_pt_BR.properties} | 30 ++- .../enduser/pages/AuthProfile_ru.properties} | 30 ++- client/am/pom.xml | 1 + .../console/topology/TopologyTogglePanel.java | 2 +- .../commons}/markup/html/form/ConfirmBehavior.java | 6 +- .../html/form/IndicatingOnConfirmAjaxLink.java | 2 +- .../syncope/client/console/pages/BasePage.java | 2 +- .../console/panels/DelegationSelectionPanel.java | 2 +- .../wicket/markup/html/form/ActionPanel.java | 1 + client/idrepo/enduser/pom.xml | 6 + .../client/enduser/panels/ChangePasswordPanel.java | 3 +- .../src/test/resources/enduser-debug.properties | 4 +- .../common/lib/wa/ImpersonationAccount.java | 8 +- .../syncope/common/lib/wa/MfaTrustedDevice.java | 18 +- .../common/lib/wa/WebAuthnDeviceCredential.java | 10 +- .../rest/api/service/AuthProfileSelfService.java | 72 ++++++ .../api/service/wa/GoogleMfaAuthTokenService.java | 16 +- .../syncope/core/logic/AuthProfileLogic.java | 53 ++++- .../syncope/core/rest/cxf/AMRESTCXFContext.java | 8 + .../cxf/service/AuthProfileSelfServiceImpl.java | 47 ++++ .../rest/cxf/service/AuthProfileServiceImpl.java | 10 +- .../console/panels/UserRequestDirectoryPanel.java | 2 +- .../syncope/client/enduser/pages/Flowable.java | 37 ++- .../syncope/client/enduser/pages/Flowable.html | 17 +- .../syncope/fit/console/AnyObjectsITCase.java | 2 +- .../apache/syncope/fit/console/GroupsITCase.java | 2 +- .../apache/syncope/fit/console/UsersITCase.java | 2 +- 39 files changed, 941 insertions(+), 223 deletions(-) diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/authprofiles/AuthProfileDirectoryPanel.java b/client/am/console/src/main/java/org/apache/syncope/client/console/authprofiles/AuthProfileDirectoryPanel.java index dcd59952d8..0693dd6244 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/authprofiles/AuthProfileDirectoryPanel.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/authprofiles/AuthProfileDirectoryPanel.java @@ -19,7 +19,6 @@ package org.apache.syncope.client.console.authprofiles; import de.agilecoders.wicket.core.markup.html.bootstrap.dialog.Modal; -import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; @@ -39,7 +38,6 @@ import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.Bas import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink; import org.apache.syncope.client.console.wicket.markup.html.form.ActionsPanel; import org.apache.syncope.client.ui.commons.Constants; -import org.apache.syncope.client.ui.commons.markup.html.form.AjaxTextFieldPanel; import org.apache.syncope.client.ui.commons.pages.BaseWebPage; import org.apache.syncope.common.lib.to.AuthProfileTO; import org.apache.syncope.common.lib.types.AMEntitlement; @@ -51,15 +49,12 @@ import org.apache.syncope.common.lib.wa.U2FDevice; import org.apache.syncope.common.lib.wa.WebAuthnDeviceCredential; import org.apache.wicket.PageReference; import org.apache.wicket.ajax.AjaxRequestTarget; -import org.apache.wicket.authroles.authorization.strategies.role.metadata.MetaDataRoleAuthorizationStrategy; import org.apache.wicket.extensions.markup.html.repeater.data.sort.SortOrder; import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn; import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn; -import org.apache.wicket.extensions.wizard.WizardModel; import org.apache.wicket.model.CompoundPropertyModel; import org.apache.wicket.model.IModel; import org.apache.wicket.model.Model; -import org.apache.wicket.model.PropertyModel; import org.apache.wicket.model.ResourceModel; import org.apache.wicket.model.StringResourceModel; @@ -92,9 +87,6 @@ public class AuthProfileDirectoryPanel }); addOuterObject(authProfileModal); - addNewItemPanelBuilder(new CreateAuthProfileWizardBuilder(pageRef), true); - MetaDataRoleAuthorizationStrategy.authorize(addAjaxLink, RENDER, AMEntitlement.AUTH_PROFILE_CREATE); - disableCheckBoxes(); initResultTable(); } @@ -526,39 +518,4 @@ public class AuthProfileDirectoryPanel return new CompoundPropertyModel<>(object); } } - - private class CreateAuthProfileWizardBuilder extends AuthProfileWizardBuilder<AuthProfileTO> { - - private static final long serialVersionUID = -2478221092672979490L; - - private class NewAuthProfileStep extends AuthProfileWizardBuilder<AuthProfileTO>.Step { - - private static final long serialVersionUID = 6290450377240300418L; - - NewAuthProfileStep(final AuthProfileTO modelObject) { - super(modelObject); - - AjaxTextFieldPanel owner = new AjaxTextFieldPanel( - "bean", "owner", new PropertyModel<>(modelObject, "owner")); - owner.addRequiredLabel(); - addOrReplace(owner); - } - } - - CreateAuthProfileWizardBuilder(final PageReference pageRef) { - super(new AuthProfileTO(), new StepModel<>(), pageRef); - } - - @Override - protected WizardModel buildModelSteps(final AuthProfileTO modelObject, final WizardModel wizardModel) { - wizardModel.add(new NewAuthProfileStep(modelObject)); - return wizardModel; - } - - @Override - protected Serializable onApplyInternal(final AuthProfileTO modelObject) { - restClient.create(modelObject); - return modelObject; - } - } } diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/authprofiles/AuthProfileItemDirectoryPanel.java b/client/am/console/src/main/java/org/apache/syncope/client/console/authprofiles/AuthProfileItemDirectoryPanel.java index 6d89dcdc69..c1e4604163 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/authprofiles/AuthProfileItemDirectoryPanel.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/authprofiles/AuthProfileItemDirectoryPanel.java @@ -75,8 +75,6 @@ public abstract class AuthProfileItemDirectoryPanel<I extends BaseBean> enableUtilityButton(); setFooterVisibility(false); - addNewItemPanelBuilder(new AuthProfileItemWizardBuilder(pageRef), true); - disableCheckBoxes(); initResultTable(); } diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/authprofiles/AuthProfileWizardBuilder.java b/client/am/console/src/main/java/org/apache/syncope/client/console/authprofiles/AuthProfileWizardBuilder.java index 08475c4110..41a5ff9958 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/authprofiles/AuthProfileWizardBuilder.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/authprofiles/AuthProfileWizardBuilder.java @@ -29,7 +29,7 @@ import org.apache.wicket.model.Model; public abstract class AuthProfileWizardBuilder<T extends BaseBean> extends BaseAjaxWizardBuilder<T> { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = -723891643398238220L; protected final StepModel<T> model; @@ -46,7 +46,7 @@ public abstract class AuthProfileWizardBuilder<T extends BaseBean> extends BaseA protected static class StepModel<T extends BaseBean> extends Model<T> { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = -3300650579312254364L; private T initialModelObject; diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/rest/AuthProfileRestClient.java b/client/am/console/src/main/java/org/apache/syncope/client/console/rest/AuthProfileRestClient.java index 61b636cd9b..92f858e026 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/rest/AuthProfileRestClient.java +++ b/client/am/console/src/main/java/org/apache/syncope/client/console/rest/AuthProfileRestClient.java @@ -38,10 +38,6 @@ public class AuthProfileRestClient extends BaseRestClient { return getService(AuthProfileService.class).read(key); } - public void create(final AuthProfileTO authProfile) { - getService(AuthProfileService.class).create(authProfile); - } - public void update(final AuthProfileTO authProfile) { getService(AuthProfileService.class).update(authProfile); } diff --git a/client/am/enduser/pom.xml b/client/am/enduser/pom.xml new file mode 100644 index 0000000000..1a735b20bd --- /dev/null +++ b/client/am/enduser/pom.xml @@ -0,0 +1,84 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +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. +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.apache.syncope.client</groupId> + <artifactId>syncope-client-am</artifactId> + <version>3.0.12-SNAPSHOT</version> + </parent> + + <name>Apache Syncope Client AM Enduser</name> + <description>Apache Syncope Client AM Enduser</description> + <groupId>org.apache.syncope.client.am</groupId> + <artifactId>syncope-client-am-enduser</artifactId> + <packaging>jar</packaging> + + <properties> + <rootpom.basedir>${basedir}/../../..</rootpom.basedir> + </properties> + + <dependencies> + <dependency> + <groupId>jakarta.servlet</groupId> + <artifactId>jakarta.servlet-api</artifactId> + <scope>provided</scope> + </dependency> + + <dependency> + <groupId>org.apache.syncope.client.idrepo</groupId> + <artifactId>syncope-client-idrepo-enduser</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.apache.syncope.client.am</groupId> + <artifactId>syncope-client-am-lib</artifactId> + <version>${project.version}</version> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-checkstyle-plugin</artifactId> + </plugin> + </plugins> + + <resources> + <resource> + <directory>src/main/resources</directory> + <filtering>true</filtering> + <excludes> + <exclude>org/apache/syncope/**/*.properties</exclude> + </excludes> + </resource> + <resource> + <directory>src/main/resources</directory> + <filtering>false</filtering> + <includes> + <include>org/apache/syncope/**/*.properties</include> + </includes> + </resource> + </resources> + </build> +</project> diff --git a/client/am/enduser/src/main/java/org/apache/syncope/client/enduser/AMEnduserContext.java b/client/am/enduser/src/main/java/org/apache/syncope/client/enduser/AMEnduserContext.java new file mode 100644 index 0000000000..3b840e520f --- /dev/null +++ b/client/am/enduser/src/main/java/org/apache/syncope/client/enduser/AMEnduserContext.java @@ -0,0 +1,34 @@ +/* + * 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.enduser; + +import org.apache.syncope.client.enduser.rest.AuthProfileRestClient; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration(proxyBeanMethods = false) +public class AMEnduserContext { + + @ConditionalOnMissingBean + @Bean + public AuthProfileRestClient authProfileRestClient() { + return new AuthProfileRestClient(); + } +} diff --git a/client/am/enduser/src/main/java/org/apache/syncope/client/enduser/pages/AuthProfile.java b/client/am/enduser/src/main/java/org/apache/syncope/client/enduser/pages/AuthProfile.java new file mode 100644 index 0000000000..932b57d5f2 --- /dev/null +++ b/client/am/enduser/src/main/java/org/apache/syncope/client/enduser/pages/AuthProfile.java @@ -0,0 +1,220 @@ +/* + * 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.enduser.pages; + +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; +import org.apache.syncope.client.enduser.rest.AuthProfileRestClient; +import org.apache.syncope.client.ui.commons.Constants; +import org.apache.syncope.client.ui.commons.annotations.ExtPage; +import org.apache.syncope.client.ui.commons.markup.html.form.IndicatingOnConfirmAjaxLink; +import org.apache.syncope.common.lib.to.AuthProfileTO; +import org.apache.syncope.common.lib.wa.GoogleMfaAuthAccount; +import org.apache.syncope.common.lib.wa.GoogleMfaAuthToken; +import org.apache.syncope.common.lib.wa.ImpersonationAccount; +import org.apache.syncope.common.lib.wa.MfaTrustedDevice; +import org.apache.syncope.common.lib.wa.WebAuthnDeviceCredential; +import org.apache.wicket.ajax.AjaxRequestTarget; +import org.apache.wicket.ajax.markup.html.navigation.paging.AjaxPagingNavigator; +import org.apache.wicket.markup.html.WebMarkupContainer; +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.markup.repeater.Item; +import org.apache.wicket.markup.repeater.data.DataView; +import org.apache.wicket.markup.repeater.data.ListDataProvider; +import org.apache.wicket.request.mapper.parameter.PageParameters; +import org.apache.wicket.spring.injection.annot.SpringBean; + +@ExtPage(label = "Auth Profile", icon = "fa fa-passport", listEntitlement = "") +public class AuthProfile extends BaseExtPage { + + private static final long serialVersionUID = -3147262161518280928L; + + protected static final String AUTH_PROFILE = "page.authProfile"; + + protected static final int ROWS_PER_PAGE = 5; + + @SpringBean + protected AuthProfileRestClient restClient; + + public AuthProfile(final PageParameters parameters) { + super(parameters, AUTH_PROFILE); + + Optional<AuthProfileTO> authProfile = restClient.read(); + + WebMarkupContainer container = new WebMarkupContainer("content"); + contentWrapper.add(container.setOutputMarkupId(true)); + + DataView<ImpersonationAccount> impersonationAccounts = new DataView<>( + "impersonationAccounts", new ListDataProvider<>( + authProfile.map(AuthProfileTO::getImpersonationAccounts).orElseGet(() -> List.of()))) { + + private static final long serialVersionUID = 6127875313385810666L; + + @Override + public void populateItem(final Item<ImpersonationAccount> item) { + item.add(new Label("impersonated", item.getModelObject().getImpersonated())); + item.add(new IndicatingOnConfirmAjaxLink<>( + "impersonationAccountDelete", Constants.CONFIRM_DELETE, true) { + + private static final long serialVersionUID = 1632838687547839512L; + + @Override + public void onClick(final AjaxRequestTarget target) { + authProfile.ifPresent(p -> { + p.getImpersonationAccounts().remove(item.getModelObject()); + restClient.update(p); + target.add(container); + }); + } + }); + } + }; + impersonationAccounts.setItemsPerPage(ROWS_PER_PAGE); + container.add(impersonationAccounts.setOutputMarkupPlaceholderTag(true)); + container.add(new AjaxPagingNavigator("impersonationAccountsNavigator", impersonationAccounts)); + + DataView<GoogleMfaAuthToken> googleMfaAuthTokens = new DataView<>( + "googleMfaAuthTokens", new ListDataProvider<>( + authProfile.map(AuthProfileTO::getGoogleMfaAuthTokens).orElseGet(() -> List.of()))) { + + private static final long serialVersionUID = 6127875313385810666L; + + @Override + public void populateItem(final Item<GoogleMfaAuthToken> item) { + item.add(new Label("otp", item.getModelObject().getOtp())); + item.add(new Label("issueDate", item.getModelObject().getIssueDate())); + item.add(new IndicatingOnConfirmAjaxLink<>( + "googleMfaAuthTokenDelete", Constants.CONFIRM_DELETE, true) { + + private static final long serialVersionUID = 1632838687547839512L; + + @Override + public void onClick(final AjaxRequestTarget target) { + authProfile.ifPresent(p -> { + p.getGoogleMfaAuthTokens().remove(item.getModelObject()); + restClient.update(p); + target.add(container); + }); + } + }); + } + }; + googleMfaAuthTokens.setItemsPerPage(ROWS_PER_PAGE); + container.add(googleMfaAuthTokens.setOutputMarkupPlaceholderTag(true)); + container.add(new AjaxPagingNavigator("googleMfaAuthTokensNavigator", googleMfaAuthTokens)); + + DataView<GoogleMfaAuthAccount> googleMfaAuthAccounts = new DataView<>( + "googleMfaAuthAccounts", new ListDataProvider<>( + authProfile.map(AuthProfileTO::getGoogleMfaAuthAccounts).orElseGet(() -> List.of()))) { + + private static final long serialVersionUID = 6127875313385810666L; + + @Override + public void populateItem(final Item<GoogleMfaAuthAccount> item) { + item.add(new Label("id", item.getModelObject().getId())); + item.add(new Label("name", item.getModelObject().getName())); + item.add(new Label("secretKey", item.getModelObject().getSecretKey())); + item.add(new Label("validationCode", item.getModelObject().getValidationCode())); + item.add(new Label("scratchCodes", item.getModelObject().getScratchCodes().stream(). + map(String::valueOf).collect(Collectors.joining(", ")))); + item.add(new Label("registrationDate", item.getModelObject().getRegistrationDate())); + item.add(new IndicatingOnConfirmAjaxLink<>( + "googleMfaAuthAccountDelete", Constants.CONFIRM_DELETE, true) { + + private static final long serialVersionUID = 1632838687547839512L; + + @Override + public void onClick(final AjaxRequestTarget target) { + authProfile.ifPresent(p -> { + p.getGoogleMfaAuthAccounts().remove(item.getModelObject()); + restClient.update(p); + target.add(container); + }); + } + }); + } + }; + googleMfaAuthAccounts.setItemsPerPage(ROWS_PER_PAGE); + container.add(googleMfaAuthAccounts.setOutputMarkupPlaceholderTag(true)); + container.add(new AjaxPagingNavigator("googleMfaAuthAccountsNavigator", googleMfaAuthAccounts)); + + DataView<MfaTrustedDevice> mfaTrustedDevices = new DataView<>( + "mfaTrustedDevices", new ListDataProvider<>( + authProfile.map(AuthProfileTO::getMfaTrustedDevices).orElseGet(() -> List.of()))) { + + private static final long serialVersionUID = 6127875313385810666L; + + @Override + public void populateItem(final Item<MfaTrustedDevice> item) { + item.add(new Label("id", item.getModelObject().getId())); + item.add(new Label("name", item.getModelObject().getName())); + item.add(new Label("deviceFingerprint", item.getModelObject().getDeviceFingerprint())); + item.add(new Label("recordDate", item.getModelObject().getRecordDate())); + item.add(new Label("expirationDate", item.getModelObject().getExpirationDate())); + item.add(new IndicatingOnConfirmAjaxLink<>( + "mfaTrustedDeviceDelete", Constants.CONFIRM_DELETE, true) { + + private static final long serialVersionUID = 1632838687547839512L; + + @Override + public void onClick(final AjaxRequestTarget target) { + authProfile.ifPresent(p -> { + p.getMfaTrustedDevices().remove(item.getModelObject()); + restClient.update(p); + target.add(container); + }); + } + }); + } + }; + mfaTrustedDevices.setItemsPerPage(ROWS_PER_PAGE); + container.add(mfaTrustedDevices.setOutputMarkupPlaceholderTag(true)); + container.add(new AjaxPagingNavigator("mfaTrustedDevicesNavigator", mfaTrustedDevices)); + + DataView<WebAuthnDeviceCredential> webAuthnDeviceCredentials = new DataView<>( + "webAuthnDeviceCredentials", new ListDataProvider<>( + authProfile.map(AuthProfileTO::getWebAuthnDeviceCredentials).orElseGet(() -> List.of()))) { + + private static final long serialVersionUID = 6127875313385810666L; + + @Override + public void populateItem(final Item<WebAuthnDeviceCredential> item) { + item.add(new Label("identifier", item.getModelObject().getIdentifier())); + item.add(new IndicatingOnConfirmAjaxLink<>( + "webAuthnDeviceCredentialDelete", Constants.CONFIRM_DELETE, true) { + + private static final long serialVersionUID = 1632838687547839512L; + + @Override + public void onClick(final AjaxRequestTarget target) { + authProfile.ifPresent(p -> { + p.getWebAuthnDeviceCredentials().remove(item.getModelObject()); + restClient.update(p); + target.add(container); + }); + } + }); + } + }; + webAuthnDeviceCredentials.setItemsPerPage(ROWS_PER_PAGE); + container.add(webAuthnDeviceCredentials.setOutputMarkupPlaceholderTag(true)); + container.add(new AjaxPagingNavigator("webAuthnDeviceCredentialsNavigator", webAuthnDeviceCredentials)); + } +} diff --git a/client/am/console/src/main/java/org/apache/syncope/client/console/rest/AuthProfileRestClient.java b/client/am/enduser/src/main/java/org/apache/syncope/client/enduser/rest/AuthProfileRestClient.java similarity index 52% copy from client/am/console/src/main/java/org/apache/syncope/client/console/rest/AuthProfileRestClient.java copy to client/am/enduser/src/main/java/org/apache/syncope/client/enduser/rest/AuthProfileRestClient.java index 61b636cd9b..413247746f 100644 --- a/client/am/console/src/main/java/org/apache/syncope/client/console/rest/AuthProfileRestClient.java +++ b/client/am/enduser/src/main/java/org/apache/syncope/client/enduser/rest/AuthProfileRestClient.java @@ -16,37 +16,30 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.syncope.client.console.rest; +package org.apache.syncope.client.enduser.rest; -import java.util.List; +import java.util.Optional; import org.apache.syncope.common.lib.to.AuthProfileTO; -import org.apache.syncope.common.rest.api.service.AuthProfileService; +import org.apache.syncope.common.rest.api.service.AuthProfileSelfService; public class AuthProfileRestClient extends BaseRestClient { - private static final long serialVersionUID = -7379778542101161274L; + private static final long serialVersionUID = 4139153766778113329L; - public int count() { - return getService(AuthProfileService.class).list(1, 1).getTotalCount(); - } - - public List<AuthProfileTO> list(final int page, final int size) { - return getService(AuthProfileService.class).list(page, size).getResult(); - } - - public AuthProfileTO read(final String key) { - return getService(AuthProfileService.class).read(key); - } - - public void create(final AuthProfileTO authProfile) { - getService(AuthProfileService.class).create(authProfile); + public Optional<AuthProfileTO> read() { + try { + return Optional.of(getService(AuthProfileSelfService.class).read()); + } catch (Exception e) { + LOG.debug("While attempting to read the auth profile", e); + return Optional.empty(); + } } public void update(final AuthProfileTO authProfile) { - getService(AuthProfileService.class).update(authProfile); + getService(AuthProfileSelfService.class).update(authProfile); } - public void delete(final String key) { - getService(AuthProfileService.class).delete(key); + public void delete() { + getService(AuthProfileSelfService.class).delete(); } } diff --git a/client/am/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/AuthProfile.html b/client/am/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/AuthProfile.html new file mode 100644 index 0000000000..6c748cbacb --- /dev/null +++ b/client/am/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/AuthProfile.html @@ -0,0 +1,255 @@ +<!DOCTYPE html> +<!-- +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:extend> + <section class="container-fluid" wicket:id="content"> + <div class="card card-outline"> + <div class="card-body"> + <div class="col-md-12"> + <div class="col-md-6 col-md-offset-3"> + <div> + <h3 class="box-title"></h3> + </div> + <div class="box-body"> + <div class="box-header formcard"> + <header class="card-container bg-danger"> + <label class="form-label card-header-style"> + <wicket:message key="impersonation.accounts.title"/> + </label> + </header> + <div class="card-container-body"> + <div> + <div class="col-xs-12"> + <div class="form-group"> + <table class="table table-striped table-bordered"> + <thead> + <tr> + <th><wicket:message key="impersonated"/></th> + <th></th> + </tr> + </thead> + <tbody> + <tr wicket:id="impersonationAccounts"> + <td><span wicket:id="impersonated"/></td> + <td style="width: 20px;"> + <a href="#" wicket:id="impersonationAccountDelete"><i class="fas fa-trash"></i></a> + </td> + </tr> + </tbody> + </table> + <table class="paginator"> + <tfoot> + <tr> + <td wicket:id="impersonationAccountsNavigator"></td> + </tr> + </tfoot> + </table> + </div> + </div> + </div> + </div> + </div> + </div> + <div class="box-body"> + <div class="box-header formcard"> + <header class="card-container bg-danger"> + <label class="form-label card-header-style"> + <wicket:message key="google.mfa.authtokens.title"/> + </label> + </header> + <div class="card-container-body"> + <div> + <div class="col-xs-12"> + <div class="form-group"> + <table class="table table-striped table-bordered"> + <thead> + <tr> + <th><wicket:message key="otp"/></th> + <th><wicket:message key="issueDate"/></th> + <th></th> + </tr> + </thead> + <tbody> + <tr wicket:id="googleMfaAuthTokens"> + <td><span wicket:id="otp"/></td> + <td><span wicket:id="issueDate"/></td> + <td style="width: 20px;"> + <a href="#" wicket:id="googleMfaAuthTokenDelete"><i class="fas fa-trash"></i></a> + </td> + </tr> + </tbody> + </table> + <table class="paginator"> + <tfoot> + <tr> + <td wicket:id="googleMfaAuthTokensNavigator"></td> + </tr> + </tfoot> + </table> + </div> + </div> + </div> + </div> + </div> + </div> + <div class="box-body"> + <div class="box-header formcard"> + <header class="card-container bg-danger"> + <label class="form-label card-header-style"> + <wicket:message key="google.mfa.authaccounts.title"/> + </label> + </header> + <div class="card-container-body"> + <div> + <div class="col-xs-12"> + <div class="form-group"> + <table class="table table-striped table-bordered"> + <thead> + <tr> + <th><wicket:message key="id"/></th> + <th><wicket:message key="name"/></th> + <th><wicket:message key="secretKey"/></th> + <th><wicket:message key="validationCode"/></th> + <th><wicket:message key="scratchCodes"/></th> + <th><wicket:message key="registrationDate"/></th> + <th></th> + </tr> + </thead> + <tbody> + <tr wicket:id="googleMfaAuthAccounts"> + <td><span wicket:id="id"/></td> + <td><span wicket:id="name"/></td> + <td style="word-wrap: anywhere;"><span wicket:id="secretKey"/></td> + <td><span wicket:id="validationCode"/></td> + <td><span wicket:id="scratchCodes"/></td> + <td><span wicket:id="registrationDate"/></td> + <td style="width: 20px;"> + <a href="#" wicket:id="googleMfaAuthAccountDelete"><i class="fas fa-trash"></i></a> + </td> + </tr> + </tbody> + </table> + <table class="paginator"> + <tfoot> + <tr> + <td wicket:id="googleMfaAuthAccountsNavigator"></td> + </tr> + </tfoot> + </table> + </div> + </div> + </div> + </div> + </div> + </div> + <div class="box-body"> + <div class="box-header formcard"> + <header class="card-container bg-danger"> + <label class="form-label card-header-style"> + <wicket:message key="mfa.trusted.devices.title"/> + </label> + </header> + <div class="card-container-body"> + <div> + <div class="col-xs-12"> + <div class="form-group"> + <table class="table table-striped table-bordered"> + <thead> + <tr> + <th><wicket:message key="id"/></th> + <th><wicket:message key="name"/></th> + <th><wicket:message key="deviceFingerprint"/></th> + <th><wicket:message key="recordDate"/></th> + <th><wicket:message key="expirationDate"/></th> + <th></th> + </tr> + </thead> + <tbody> + <tr wicket:id="mfaTrustedDevices"> + <td><span wicket:id="id"/></td> + <td><span wicket:id="name"/></td> + <td style="word-wrap: anywhere;"><span wicket:id="deviceFingerprint"/></td> + <td><span wicket:id="recordDate"/></td> + <td><span wicket:id="expirationDate"/></td> + <td style="width: 20px;"> + <a href="#" wicket:id="mfaTrustedDeviceDelete"><i class="fas fa-trash"></i></a> + </td> + </tr> + </tbody> + </table> + <table class="paginator"> + <tfoot> + <tr> + <td wicket:id="mfaTrustedDevicesNavigator"></td> + </tr> + </tfoot> + </table> + </div> + </div> + </div> + </div> + </div> + </div> <div class="box-body"> + <div class="box-header formcard"> + <header class="card-container bg-danger"> + <label class="form-label card-header-style"> + <wicket:message key="webauthn.device.credentials.title"/> + </label> + </header> + <div class="card-container-body"> + <div> + <div class="col-xs-12"> + <div class="form-group"> + <table class="table table-striped table-bordered"> + <thead> + <tr> + <th><wicket:message key="id"/></th> + <th></th> + </tr> + </thead> + <tbody> + <tr wicket:id="webAuthnDeviceCredentials"> + <td><span wicket:id="identifier"/></td> + <td style="width: 20px;"> + <a href="#" wicket:id="webAuthnDeviceCredentialDelete"><i class="fas fa-trash"></i></a> + </td> + </tr> + </tbody> + </table> + <table class="paginator"> + <tfoot> + <tr> + <td wicket:id="webAuthnDeviceCredentialsNavigator"></td> + </tr> + </tfoot> + </table> + </div> + </div> + </div> + </div> + </div> + </div> + </div> + </div> + </div> + </div> + </section> + </wicket:extend> +</html> diff --git a/client/idrepo/enduser/src/test/resources/enduser-debug.properties b/client/am/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/AuthProfile.properties similarity index 58% copy from client/idrepo/enduser/src/test/resources/enduser-debug.properties copy to client/am/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/AuthProfile.properties index e34599c3d0..4caaab9284 100644 --- a/client/idrepo/enduser/src/test/resources/enduser-debug.properties +++ b/client/am/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/AuthProfile.properties @@ -14,15 +14,21 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. - -management.endpoints.web.exposure.include=health,info,beans,env,loggers - -keymaster.address=http://localhost:9080/syncope/rest/keymaster -#keymaster.address=https://localhost:9443/syncope/rest/keymaster -keymaster.username=${anonymousUser} -keymaster.password=${anonymousKey} - -server.port=9091 -service.discovery.address=http://localhost:9091/syncope-enduser/ - -logging.config=file://${project.build.testOutputDirectory}/log4j2.xml +page.authProfile=Auth Profile +impersonation.accounts.title=Impersonation Accounts +google.mfa.authtokens.title=Google MFA Tokens +google.mfa.authaccounts.title=Google MFA Accounts +mfa.trusted.devices.title=MFA Trusted Devices +webauthn.device.credentials.title=WebAuthn Device Credentials +otp=OTP +issueDate=Issue Date +impersonated=Impersonated +id=Id +name=Name +secretKey=Secret Key +validationCode=Validation Code +scratchCodes=Scratch Codes +registrationDate=Registration Date +deviceFingerprint=Fingerprint +recordDate=Record Date +expirationDate=Expiration Date diff --git a/client/idrepo/enduser/src/test/resources/enduser-debug.properties b/client/am/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/AuthProfile_it.properties similarity index 56% copy from client/idrepo/enduser/src/test/resources/enduser-debug.properties copy to client/am/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/AuthProfile_it.properties index e34599c3d0..ae0822ff62 100644 --- a/client/idrepo/enduser/src/test/resources/enduser-debug.properties +++ b/client/am/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/AuthProfile_it.properties @@ -14,15 +14,21 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. - -management.endpoints.web.exposure.include=health,info,beans,env,loggers - -keymaster.address=http://localhost:9080/syncope/rest/keymaster -#keymaster.address=https://localhost:9443/syncope/rest/keymaster -keymaster.username=${anonymousUser} -keymaster.password=${anonymousKey} - -server.port=9091 -service.discovery.address=http://localhost:9091/syncope-enduser/ - -logging.config=file://${project.build.testOutputDirectory}/log4j2.xml +page.authProfile=Auth Profile +impersonation.accounts.title=Account di impersonificazione +google.mfa.authtokens.title=Token MFA Google +google.mfa.authaccounts.title=Account MFA Google +mfa.trusted.devices.title=Dispositivi MFA +webauthn.device.credentials.title=Credenziali dispositivi WebAuthn +otp=OTP +issueDate=Data di emissione +impersonated=Impersonificato +id=Id +name=Nome +secretKey=Chiave segreta +validationCode=Codice di validazione +scratchCodes=Codici Scratch +registrationDate=Data di registrazione +deviceFingerprint=Fingerprint +recordDate=Data di registrazione +expirationDate=Data di scadenza diff --git a/client/idrepo/enduser/src/test/resources/enduser-debug.properties b/client/am/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/AuthProfile_ja.properties similarity index 58% copy from client/idrepo/enduser/src/test/resources/enduser-debug.properties copy to client/am/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/AuthProfile_ja.properties index e34599c3d0..4caaab9284 100644 --- a/client/idrepo/enduser/src/test/resources/enduser-debug.properties +++ b/client/am/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/AuthProfile_ja.properties @@ -14,15 +14,21 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. - -management.endpoints.web.exposure.include=health,info,beans,env,loggers - -keymaster.address=http://localhost:9080/syncope/rest/keymaster -#keymaster.address=https://localhost:9443/syncope/rest/keymaster -keymaster.username=${anonymousUser} -keymaster.password=${anonymousKey} - -server.port=9091 -service.discovery.address=http://localhost:9091/syncope-enduser/ - -logging.config=file://${project.build.testOutputDirectory}/log4j2.xml +page.authProfile=Auth Profile +impersonation.accounts.title=Impersonation Accounts +google.mfa.authtokens.title=Google MFA Tokens +google.mfa.authaccounts.title=Google MFA Accounts +mfa.trusted.devices.title=MFA Trusted Devices +webauthn.device.credentials.title=WebAuthn Device Credentials +otp=OTP +issueDate=Issue Date +impersonated=Impersonated +id=Id +name=Name +secretKey=Secret Key +validationCode=Validation Code +scratchCodes=Scratch Codes +registrationDate=Registration Date +deviceFingerprint=Fingerprint +recordDate=Record Date +expirationDate=Expiration Date diff --git a/client/idrepo/enduser/src/test/resources/enduser-debug.properties b/client/am/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/AuthProfile_pt_BR.properties similarity index 58% copy from client/idrepo/enduser/src/test/resources/enduser-debug.properties copy to client/am/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/AuthProfile_pt_BR.properties index e34599c3d0..4caaab9284 100644 --- a/client/idrepo/enduser/src/test/resources/enduser-debug.properties +++ b/client/am/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/AuthProfile_pt_BR.properties @@ -14,15 +14,21 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. - -management.endpoints.web.exposure.include=health,info,beans,env,loggers - -keymaster.address=http://localhost:9080/syncope/rest/keymaster -#keymaster.address=https://localhost:9443/syncope/rest/keymaster -keymaster.username=${anonymousUser} -keymaster.password=${anonymousKey} - -server.port=9091 -service.discovery.address=http://localhost:9091/syncope-enduser/ - -logging.config=file://${project.build.testOutputDirectory}/log4j2.xml +page.authProfile=Auth Profile +impersonation.accounts.title=Impersonation Accounts +google.mfa.authtokens.title=Google MFA Tokens +google.mfa.authaccounts.title=Google MFA Accounts +mfa.trusted.devices.title=MFA Trusted Devices +webauthn.device.credentials.title=WebAuthn Device Credentials +otp=OTP +issueDate=Issue Date +impersonated=Impersonated +id=Id +name=Name +secretKey=Secret Key +validationCode=Validation Code +scratchCodes=Scratch Codes +registrationDate=Registration Date +deviceFingerprint=Fingerprint +recordDate=Record Date +expirationDate=Expiration Date diff --git a/client/idrepo/enduser/src/test/resources/enduser-debug.properties b/client/am/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/AuthProfile_ru.properties similarity index 58% copy from client/idrepo/enduser/src/test/resources/enduser-debug.properties copy to client/am/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/AuthProfile_ru.properties index e34599c3d0..4caaab9284 100644 --- a/client/idrepo/enduser/src/test/resources/enduser-debug.properties +++ b/client/am/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/AuthProfile_ru.properties @@ -14,15 +14,21 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. - -management.endpoints.web.exposure.include=health,info,beans,env,loggers - -keymaster.address=http://localhost:9080/syncope/rest/keymaster -#keymaster.address=https://localhost:9443/syncope/rest/keymaster -keymaster.username=${anonymousUser} -keymaster.password=${anonymousKey} - -server.port=9091 -service.discovery.address=http://localhost:9091/syncope-enduser/ - -logging.config=file://${project.build.testOutputDirectory}/log4j2.xml +page.authProfile=Auth Profile +impersonation.accounts.title=Impersonation Accounts +google.mfa.authtokens.title=Google MFA Tokens +google.mfa.authaccounts.title=Google MFA Accounts +mfa.trusted.devices.title=MFA Trusted Devices +webauthn.device.credentials.title=WebAuthn Device Credentials +otp=OTP +issueDate=Issue Date +impersonated=Impersonated +id=Id +name=Name +secretKey=Secret Key +validationCode=Validation Code +scratchCodes=Scratch Codes +registrationDate=Registration Date +deviceFingerprint=Fingerprint +recordDate=Record Date +expirationDate=Expiration Date diff --git a/client/am/pom.xml b/client/am/pom.xml index e72c994191..8a26ac0045 100644 --- a/client/am/pom.xml +++ b/client/am/pom.xml @@ -40,5 +40,6 @@ under the License. <modules> <module>lib</module> <module>console</module> + <module>enduser</module> </modules> </project> diff --git a/client/idm/console/src/main/java/org/apache/syncope/client/console/topology/TopologyTogglePanel.java b/client/idm/console/src/main/java/org/apache/syncope/client/console/topology/TopologyTogglePanel.java index 8c36d718bd..de6097868b 100644 --- a/client/idm/console/src/main/java/org/apache/syncope/client/console/topology/TopologyTogglePanel.java +++ b/client/idm/console/src/main/java/org/apache/syncope/client/console/topology/TopologyTogglePanel.java @@ -35,12 +35,12 @@ import org.apache.syncope.client.console.tasks.PropagationTasks; import org.apache.syncope.client.console.tasks.PullTasks; import org.apache.syncope.client.console.tasks.PushTasks; import org.apache.syncope.client.console.wicket.markup.html.bootstrap.dialog.BaseModal; -import org.apache.syncope.client.console.wicket.markup.html.form.IndicatingOnConfirmAjaxLink; import org.apache.syncope.client.console.wizards.resources.ConnectorWizardBuilder; import org.apache.syncope.client.console.wizards.resources.ResourceProvision; import org.apache.syncope.client.console.wizards.resources.ResourceProvisionPanel; import org.apache.syncope.client.console.wizards.resources.ResourceWizardBuilder; import org.apache.syncope.client.ui.commons.Constants; +import org.apache.syncope.client.ui.commons.markup.html.form.IndicatingOnConfirmAjaxLink; import org.apache.syncope.client.ui.commons.pages.BaseWebPage; import org.apache.syncope.client.ui.commons.wizards.AjaxWizard; import org.apache.syncope.common.lib.SyncopeClientException; diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ConfirmBehavior.java b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/ConfirmBehavior.java similarity index 93% rename from client/idrepo/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ConfirmBehavior.java rename to client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/ConfirmBehavior.java index c4f0218a57..0a59c422af 100644 --- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ConfirmBehavior.java +++ b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/ConfirmBehavior.java @@ -16,14 +16,14 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.syncope.client.console.wicket.markup.html.form; +package org.apache.syncope.client.ui.commons.markup.html.form; import static de.agilecoders.wicket.jquery.JQuery.$; import de.agilecoders.wicket.jquery.function.JavaScriptInlineFunction; import java.util.ArrayList; -import org.apache.syncope.client.console.SyncopeConsoleSession; import org.apache.wicket.Component; +import org.apache.wicket.Session; import org.apache.wicket.behavior.Behavior; import org.apache.wicket.markup.head.IHeaderResponse; import org.apache.wicket.markup.head.JavaScriptHeaderItem; @@ -63,7 +63,7 @@ public class ConfirmBehavior extends Behavior { + " className: 'btn-danger'" + " }" + "}," - + "locale: '" + SyncopeConsoleSession.get().getLocale().getLanguage() + "'," + + "locale: '" + Session.get().getLocale().getLanguage() + "'," + "callback: function(result) {" + " if (result == true) {" + " proceed = true;" diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/IndicatingOnConfirmAjaxLink.java b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/IndicatingOnConfirmAjaxLink.java similarity index 96% rename from client/idrepo/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/IndicatingOnConfirmAjaxLink.java rename to client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/IndicatingOnConfirmAjaxLink.java index d3ae2a383f..8df5ef4adf 100644 --- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/IndicatingOnConfirmAjaxLink.java +++ b/client/idrepo/common-ui/src/main/java/org/apache/syncope/client/ui/commons/markup/html/form/IndicatingOnConfirmAjaxLink.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.syncope.client.console.wicket.markup.html.form; +package org.apache.syncope.client.ui.commons.markup.html.form; import org.apache.syncope.client.ui.commons.Constants; import org.apache.wicket.extensions.ajax.markup.html.IndicatingAjaxLink; diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/pages/BasePage.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/pages/BasePage.java index 72a59b4e04..6156d0b1b7 100644 --- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/pages/BasePage.java +++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/pages/BasePage.java @@ -33,12 +33,12 @@ import org.apache.syncope.client.console.annotations.IdMPage; import org.apache.syncope.client.console.panels.DelegationSelectionPanel; import org.apache.syncope.client.console.rest.SyncopeRestClient; import org.apache.syncope.client.console.wicket.markup.head.MetaHeaderItem; -import org.apache.syncope.client.console.wicket.markup.html.form.IndicatingOnConfirmAjaxLink; import org.apache.syncope.client.console.widgets.ExtAlertWidget; import org.apache.syncope.client.ui.commons.Constants; import org.apache.syncope.client.ui.commons.HttpResourceStream; import org.apache.syncope.client.ui.commons.ajax.form.IndicatorAjaxFormComponentUpdatingBehavior; import org.apache.syncope.client.ui.commons.annotations.ExtPage; +import org.apache.syncope.client.ui.commons.markup.html.form.IndicatingOnConfirmAjaxLink; import org.apache.syncope.client.ui.commons.pages.BaseWebPage; import org.apache.syncope.client.ui.commons.rest.ResponseHolder; import org.apache.syncope.common.lib.SyncopeConstants; diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/DelegationSelectionPanel.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/DelegationSelectionPanel.java index 177430975a..6bc123d657 100644 --- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/DelegationSelectionPanel.java +++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/panels/DelegationSelectionPanel.java @@ -20,7 +20,7 @@ package org.apache.syncope.client.console.panels; import org.apache.syncope.client.console.SyncopeConsoleSession; import org.apache.syncope.client.console.pages.Dashboard; -import org.apache.syncope.client.console.wicket.markup.html.form.IndicatingOnConfirmAjaxLink; +import org.apache.syncope.client.ui.commons.markup.html.form.IndicatingOnConfirmAjaxLink; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.markup.ComponentTag; import org.apache.wicket.markup.html.basic.Label; diff --git a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionPanel.java b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionPanel.java index 3a33c3bafa..20bd29068a 100644 --- a/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionPanel.java +++ b/client/idrepo/console/src/main/java/org/apache/syncope/client/console/wicket/markup/html/form/ActionPanel.java @@ -25,6 +25,7 @@ import org.apache.syncope.client.console.SyncopeConsoleSession; import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink.ActionType; import org.apache.syncope.client.console.wicket.markup.html.link.VeilPopupSettings; import org.apache.syncope.client.ui.commons.Constants; +import org.apache.syncope.client.ui.commons.markup.html.form.IndicatingOnConfirmAjaxLink; import org.apache.wicket.AttributeModifier; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.authroles.authorization.strategies.role.metadata.MetaDataRoleAuthorizationStrategy; diff --git a/client/idrepo/enduser/pom.xml b/client/idrepo/enduser/pom.xml index ea2a9e4fd8..a514edef22 100644 --- a/client/idrepo/enduser/pom.xml +++ b/client/idrepo/enduser/pom.xml @@ -323,6 +323,12 @@ under the License. <version>${project.version}</version> </dependency> + <dependency> + <groupId>org.apache.syncope.client.am</groupId> + <artifactId>syncope-client-am-enduser</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> <groupId>org.apache.syncope.ext.flowable</groupId> <artifactId>syncope-ext-flowable-client-enduser</artifactId> diff --git a/client/idrepo/enduser/src/main/java/org/apache/syncope/client/enduser/panels/ChangePasswordPanel.java b/client/idrepo/enduser/src/main/java/org/apache/syncope/client/enduser/panels/ChangePasswordPanel.java index b9f5111f1e..05482d42d0 100644 --- a/client/idrepo/enduser/src/main/java/org/apache/syncope/client/enduser/panels/ChangePasswordPanel.java +++ b/client/idrepo/enduser/src/main/java/org/apache/syncope/client/enduser/panels/ChangePasswordPanel.java @@ -33,6 +33,7 @@ import org.apache.wicket.Component; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.ajax.markup.html.form.AjaxButton; import org.apache.wicket.core.util.string.CssUtils; +import org.apache.wicket.markup.head.IHeaderResponse; import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.form.Button; import org.apache.wicket.markup.html.form.Form; @@ -68,7 +69,7 @@ public abstract class ChangePasswordPanel extends Panel { private static final long serialVersionUID = 418292023846536149L; @Override - protected void appendDefaultButtonField() { + protected void addDefaultSubmitButtonHandler(final IHeaderResponse headerResponse) { AppendingStringBuffer buffer = new AppendingStringBuffer(); String cssClass = getString(CssUtils.key(Form.class, "hidden-fields")); diff --git a/client/idrepo/enduser/src/test/resources/enduser-debug.properties b/client/idrepo/enduser/src/test/resources/enduser-debug.properties index e34599c3d0..a8905a8f27 100644 --- a/client/idrepo/enduser/src/test/resources/enduser-debug.properties +++ b/client/idrepo/enduser/src/test/resources/enduser-debug.properties @@ -17,8 +17,8 @@ management.endpoints.web.exposure.include=health,info,beans,env,loggers -keymaster.address=http://localhost:9080/syncope/rest/keymaster -#keymaster.address=https://localhost:9443/syncope/rest/keymaster +#keymaster.address=http://localhost:9080/syncope/rest/keymaster +keymaster.address=https://localhost:9443/syncope/rest/keymaster keymaster.username=${anonymousUser} keymaster.password=${anonymousKey} diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/wa/ImpersonationAccount.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/wa/ImpersonationAccount.java index 6936b6363a..a0f5458ae7 100644 --- a/common/am/lib/src/main/java/org/apache/syncope/common/lib/wa/ImpersonationAccount.java +++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/wa/ImpersonationAccount.java @@ -55,7 +55,7 @@ public class ImpersonationAccount implements BaseBean { public int hashCode() { return new HashCodeBuilder() .append(impersonated) - .toHashCode(); + .build(); } @Override @@ -71,14 +71,14 @@ public class ImpersonationAccount implements BaseBean { } ImpersonationAccount other = (ImpersonationAccount) obj; return new EqualsBuilder() - .append(this.impersonated, other.impersonated) - .isEquals(); + .append(impersonated, other.impersonated) + .build(); } @Override public String toString() { return new ToStringBuilder(this) .append("impersonated", impersonated) - .toString(); + .build(); } } diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/wa/MfaTrustedDevice.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/wa/MfaTrustedDevice.java index b53efdd2e0..fbc208afb5 100644 --- a/common/am/lib/src/main/java/org/apache/syncope/common/lib/wa/MfaTrustedDevice.java +++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/wa/MfaTrustedDevice.java @@ -97,7 +97,7 @@ public class MfaTrustedDevice implements BaseBean { .append(recordDate) .append(recordKey) .append(expirationDate) - .toHashCode(); + .build(); } @Override @@ -113,13 +113,13 @@ public class MfaTrustedDevice implements BaseBean { } MfaTrustedDevice other = (MfaTrustedDevice) obj; return new EqualsBuilder() - .append(this.id, other.id) - .append(this.name, other.name) - .append(this.deviceFingerprint, other.deviceFingerprint) - .append(this.recordDate, other.recordDate) - .append(this.recordKey, other.recordKey) - .append(this.expirationDate, other.expirationDate) - .isEquals(); + .append(id, other.id) + .append(name, other.name) + .append(deviceFingerprint, other.deviceFingerprint) + .append(recordDate, other.recordDate) + .append(recordKey, other.recordKey) + .append(expirationDate, other.expirationDate) + .build(); } @Override @@ -131,6 +131,6 @@ public class MfaTrustedDevice implements BaseBean { .append("recordDate", recordDate) .append("recordKey", recordKey) .append("expirationDate", expirationDate) - .toString(); + .build(); } } diff --git a/common/am/lib/src/main/java/org/apache/syncope/common/lib/wa/WebAuthnDeviceCredential.java b/common/am/lib/src/main/java/org/apache/syncope/common/lib/wa/WebAuthnDeviceCredential.java index 40db6cfe54..88ca96b814 100644 --- a/common/am/lib/src/main/java/org/apache/syncope/common/lib/wa/WebAuthnDeviceCredential.java +++ b/common/am/lib/src/main/java/org/apache/syncope/common/lib/wa/WebAuthnDeviceCredential.java @@ -71,7 +71,7 @@ public class WebAuthnDeviceCredential implements BaseBean { return new HashCodeBuilder() .append(json) .append(identifier) - .toHashCode(); + .build(); } @Override @@ -87,9 +87,9 @@ public class WebAuthnDeviceCredential implements BaseBean { } WebAuthnDeviceCredential other = (WebAuthnDeviceCredential) obj; return new EqualsBuilder() - .append(this.json, other.json) - .append(this.identifier, other.identifier) - .isEquals(); + .append(json, other.json) + .append(identifier, other.identifier) + .build(); } @Override @@ -97,6 +97,6 @@ public class WebAuthnDeviceCredential implements BaseBean { return new ToStringBuilder(this) .append("records", json) .append("identifier", identifier) - .toString(); + .build(); } } diff --git a/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/AuthProfileSelfService.java b/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/AuthProfileSelfService.java new file mode 100644 index 0000000000..01331a9c06 --- /dev/null +++ b/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/AuthProfileSelfService.java @@ -0,0 +1,72 @@ +/* + * 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.rest.api.service; + +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.security.SecurityRequirements; +import io.swagger.v3.oas.annotations.tags.Tag; +import javax.validation.constraints.NotNull; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import org.apache.syncope.common.lib.to.AuthProfileTO; +import org.apache.syncope.common.rest.api.RESTHeaders; + +/** + * REST operations for Auth profile self-management. + */ +@Tag(name = "AuthProfileSelf") +@SecurityRequirements({ + @SecurityRequirement(name = "BasicAuthentication"), + @SecurityRequirement(name = "Bearer") }) +@Path("authProfiles/self") +public interface AuthProfileSelfService extends JAXRSService { + + /** + * Returns the auth profile matching the user making the service call, if found. + * + * @return auth profile matching the user making the service call, if found + */ + @GET + @Consumes({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML }) + @Produces({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML }) + AuthProfileTO read(); + + /** + * Updates the auth profile matching the user making the service call, if found. + * + * @param authProfileTO auth profile + */ + @PUT + @Consumes({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML }) + @Produces({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML }) + void update(@NotNull AuthProfileTO authProfileTO); + + /** + * Deletes the auth profile matching the user making the service call, if found. + */ + @DELETE + @Consumes({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML }) + @Produces({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML }) + void delete(); +} diff --git a/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/wa/GoogleMfaAuthTokenService.java b/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/wa/GoogleMfaAuthTokenService.java index 053f9e25ca..34af0937d5 100644 --- a/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/wa/GoogleMfaAuthTokenService.java +++ b/common/am/rest-api/src/main/java/org/apache/syncope/common/rest/api/service/wa/GoogleMfaAuthTokenService.java @@ -41,35 +41,34 @@ import org.apache.syncope.common.rest.api.service.JAXRSService; @SecurityRequirements({ @SecurityRequirement(name = "BasicAuthentication"), @SecurityRequirement(name = "Bearer") }) -@Path("wa/gauth") +@Path("wa/gauth/tokens") public interface GoogleMfaAuthTokenService extends JAXRSService { @DELETE - @Path("tokens") @Consumes({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML }) @Produces({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML }) void delete(@QueryParam("expirationDate") LocalDateTime expirationDate); @DELETE - @Path("tokens/{owner}/{otp}") + @Path("{owner}/{otp}") @Consumes({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML }) @Produces({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML }) void delete(@NotNull @PathParam("owner") String owner, @NotNull @PathParam("otp") int otp); @DELETE - @Path("tokens/{owner}") + @Path("{owner}") @Consumes({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML }) @Produces({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML }) void delete(@NotNull @PathParam("owner") String owner); @DELETE - @Path("tokens/otp/{otp}") + @Path("otp/{otp}") @Consumes({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML }) @Produces({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML }) void delete(@NotNull @PathParam("otp") int otp); @PUT - @Path("tokens/{owner}") + @Path("{owner}") @Consumes({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML }) @Produces({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML }) void store(@NotNull @PathParam("owner") String owner, @NotNull GoogleMfaAuthToken token); @@ -77,18 +76,17 @@ public interface GoogleMfaAuthTokenService extends JAXRSService { @GET @Consumes({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML }) @Produces({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML }) - @Path("tokens/{owner}/{otp}") + @Path("{owner}/{otp}") GoogleMfaAuthToken read(@NotNull @PathParam("owner") String owner, @NotNull @PathParam("otp") int otp); @GET @Consumes({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML }) @Produces({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML }) - @Path("tokens/{owner}") + @Path("{owner}") PagedResult<GoogleMfaAuthToken> read(@NotNull @PathParam("owner") String owner); @GET @Consumes({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML }) @Produces({ MediaType.APPLICATION_JSON, RESTHeaders.APPLICATION_YAML, MediaType.APPLICATION_XML }) - @Path("tokens") PagedResult<GoogleMfaAuthToken> list(); } diff --git a/core/am/logic/src/main/java/org/apache/syncope/core/logic/AuthProfileLogic.java b/core/am/logic/src/main/java/org/apache/syncope/core/logic/AuthProfileLogic.java index 31b1d17430..03e0af7e29 100644 --- a/core/am/logic/src/main/java/org/apache/syncope/core/logic/AuthProfileLogic.java +++ b/core/am/logic/src/main/java/org/apache/syncope/core/logic/AuthProfileLogic.java @@ -24,10 +24,14 @@ import java.util.stream.Collectors; import org.apache.commons.lang3.tuple.Pair; import org.apache.syncope.common.lib.to.AuthProfileTO; import org.apache.syncope.common.lib.types.AMEntitlement; +import org.apache.syncope.common.lib.types.AnyTypeKind; +import org.apache.syncope.common.lib.types.IdRepoEntitlement; import org.apache.syncope.core.persistence.api.dao.AuthProfileDAO; import org.apache.syncope.core.persistence.api.dao.NotFoundException; import org.apache.syncope.core.persistence.api.entity.am.AuthProfile; import org.apache.syncope.core.provisioning.api.data.AuthProfileDataBinder; +import org.apache.syncope.core.spring.security.AuthContextUtils; +import org.apache.syncope.core.spring.security.DelegatedAdministrationException; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.transaction.annotation.Transactional; @@ -37,9 +41,17 @@ public class AuthProfileLogic extends AbstractAuthProfileLogic { super(authProfileDAO, binder); } - @PreAuthorize("hasRole('" + AMEntitlement.AUTH_PROFILE_DELETE + "') ") - public void delete(final String key) { - authProfileDAO.delete(key); + @PreAuthorize("hasRole('" + AMEntitlement.AUTH_PROFILE_LIST + "')") + @Transactional(readOnly = true) + public Pair<Integer, List<AuthProfileTO>> list(final int page, final int size) { + int count = authProfileDAO.count(); + + List<AuthProfileTO> result = authProfileDAO.findAll(page, size). + stream(). + map(binder::getAuthProfileTO). + collect(Collectors.toList()); + + return Pair.of(count, result); } @PreAuthorize("hasRole('" + AMEntitlement.AUTH_PROFILE_READ + "') ") @@ -50,6 +62,14 @@ public class AuthProfileLogic extends AbstractAuthProfileLogic { orElseThrow(() -> new NotFoundException(key + " not found")); } + @PreAuthorize("isAuthenticated() and not(hasRole('" + IdRepoEntitlement.ANONYMOUS + "'))") + @Transactional(readOnly = true) + public AuthProfileTO selfRead() { + return authProfileDAO.findByOwner(AuthContextUtils.getUsername()). + map(binder::getAuthProfileTO). + orElseThrow(() -> new NotFoundException("AuthProfile for " + AuthContextUtils.getUsername())); + } + @PreAuthorize("hasRole('" + AMEntitlement.AUTH_PROFILE_CREATE + "') ") public AuthProfileTO create(final AuthProfileTO authProfileTO) { return binder.getAuthProfileTO(authProfileDAO.save(binder.create(authProfileTO))); @@ -63,16 +83,25 @@ public class AuthProfileLogic extends AbstractAuthProfileLogic { authProfileDAO.save(authProfile); } - @PreAuthorize("hasRole('" + AMEntitlement.AUTH_PROFILE_LIST + "')") - @Transactional(readOnly = true) - public Pair<Integer, List<AuthProfileTO>> list(final int page, final int size) { - int count = authProfileDAO.count(); + @PreAuthorize("isAuthenticated() and not(hasRole('" + IdRepoEntitlement.ANONYMOUS + "'))") + public void selfUpdate(final AuthProfileTO authProfileTO) { + authProfileDAO.findByOwner(AuthContextUtils.getUsername()). + filter(authProfile -> authProfile.getKey().equals(authProfileTO.getKey()) + && authProfile.getOwner().equals(authProfileTO.getOwner())). + orElseThrow(() -> new DelegatedAdministrationException(AnyTypeKind.USER, authProfileTO.getOwner())); - List<AuthProfileTO> result = authProfileDAO.findAll(page, size). - stream(). - map(binder::getAuthProfileTO). - collect(Collectors.toList()); + update(authProfileTO); + } - return Pair.of(count, result); + @PreAuthorize("hasRole('" + AMEntitlement.AUTH_PROFILE_DELETE + "') ") + public void delete(final String key) { + authProfileDAO.delete(key); + } + + @PreAuthorize("isAuthenticated() and not(hasRole('" + IdRepoEntitlement.ANONYMOUS + "'))") + public void selfDelete() { + authProfileDAO.delete(authProfileDAO.findByOwner(AuthContextUtils.getUsername()). + orElseThrow(() -> new DelegatedAdministrationException( + AnyTypeKind.USER, AuthContextUtils.getUsername())).getKey()); } } diff --git a/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/AMRESTCXFContext.java b/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/AMRESTCXFContext.java index 81942ea9ec..e4995955d1 100644 --- a/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/AMRESTCXFContext.java +++ b/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/AMRESTCXFContext.java @@ -20,6 +20,7 @@ package org.apache.syncope.core.rest.cxf; import org.apache.syncope.common.rest.api.service.AttrRepoService; import org.apache.syncope.common.rest.api.service.AuthModuleService; +import org.apache.syncope.common.rest.api.service.AuthProfileSelfService; import org.apache.syncope.common.rest.api.service.AuthProfileService; import org.apache.syncope.common.rest.api.service.ClientAppService; import org.apache.syncope.common.rest.api.service.OIDCJWKSService; @@ -52,6 +53,7 @@ import org.apache.syncope.core.logic.wa.WAConfigLogic; import org.apache.syncope.core.logic.wa.WebAuthnRegistrationLogic; import org.apache.syncope.core.rest.cxf.service.AttrRepoServiceImpl; import org.apache.syncope.core.rest.cxf.service.AuthModuleServiceImpl; +import org.apache.syncope.core.rest.cxf.service.AuthProfileSelfServiceImpl; import org.apache.syncope.core.rest.cxf.service.AuthProfileServiceImpl; import org.apache.syncope.core.rest.cxf.service.ClientAppServiceImpl; import org.apache.syncope.core.rest.cxf.service.OIDCJWKSServiceImpl; @@ -91,6 +93,12 @@ public class AMRESTCXFContext { return new AuthProfileServiceImpl(authProfileLogic); } + @ConditionalOnMissingBean + @Bean + public AuthProfileSelfService authProfileSelfService(final AuthProfileLogic authProfileLogic) { + return new AuthProfileSelfServiceImpl(authProfileLogic); + } + @ConditionalOnMissingBean @Bean public ClientAppService clientAppService(final ClientAppLogic clientAppLogic) { diff --git a/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AuthProfileSelfServiceImpl.java b/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AuthProfileSelfServiceImpl.java new file mode 100644 index 0000000000..9d65169c8e --- /dev/null +++ b/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AuthProfileSelfServiceImpl.java @@ -0,0 +1,47 @@ +/* + * 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.core.rest.cxf.service; + +import org.apache.syncope.common.lib.to.AuthProfileTO; +import org.apache.syncope.common.rest.api.service.AuthProfileSelfService; +import org.apache.syncope.core.logic.AuthProfileLogic; + +public class AuthProfileSelfServiceImpl extends AbstractService implements AuthProfileSelfService { + + protected final AuthProfileLogic logic; + + public AuthProfileSelfServiceImpl(final AuthProfileLogic logic) { + this.logic = logic; + } + + @Override + public AuthProfileTO read() { + return logic.selfRead(); + } + + @Override + public void update(final AuthProfileTO authProfileTO) { + logic.selfUpdate(authProfileTO); + } + + @Override + public void delete() { + logic.selfDelete(); + } +} diff --git a/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AuthProfileServiceImpl.java b/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AuthProfileServiceImpl.java index 4ee5424119..5db5590117 100644 --- a/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AuthProfileServiceImpl.java +++ b/core/am/rest-cxf/src/main/java/org/apache/syncope/core/rest/cxf/service/AuthProfileServiceImpl.java @@ -39,8 +39,9 @@ public class AuthProfileServiceImpl extends AbstractService implements AuthProfi } @Override - public void delete(final String key) { - logic.delete(key); + public PagedResult<AuthProfileTO> list(final int page, final int size) { + Pair<Integer, List<AuthProfileTO>> result = logic.list(page, size); + return buildPagedResult(result.getRight(), page, size, result.getLeft()); } @Override @@ -63,8 +64,7 @@ public class AuthProfileServiceImpl extends AbstractService implements AuthProfi } @Override - public PagedResult<AuthProfileTO> list(final int page, final int size) { - Pair<Integer, List<AuthProfileTO>> result = logic.list(page, size); - return buildPagedResult(result.getRight(), page, size, result.getLeft()); + public void delete(final String key) { + logic.delete(key); } } diff --git a/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/panels/UserRequestDirectoryPanel.java b/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/panels/UserRequestDirectoryPanel.java index 3df79c8633..8e6bc4aee0 100644 --- a/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/panels/UserRequestDirectoryPanel.java +++ b/ext/flowable/client-console/src/main/java/org/apache/syncope/client/console/panels/UserRequestDirectoryPanel.java @@ -33,9 +33,9 @@ import org.apache.syncope.client.console.rest.UserRequestRestClient; import org.apache.syncope.client.console.wicket.extensions.markup.html.repeater.data.table.DatePropertyColumn; import org.apache.syncope.client.console.wicket.markup.html.form.ActionLink; import org.apache.syncope.client.console.wicket.markup.html.form.ActionsPanel; -import org.apache.syncope.client.console.wicket.markup.html.form.ConfirmBehavior; import org.apache.syncope.client.lib.batch.BatchRequest; import org.apache.syncope.client.ui.commons.Constants; +import org.apache.syncope.client.ui.commons.markup.html.form.ConfirmBehavior; import org.apache.syncope.common.lib.SyncopeClientException; import org.apache.syncope.common.lib.to.UserRequest; import org.apache.syncope.common.lib.types.FlowableEntitlement; diff --git a/ext/flowable/client-enduser/src/main/java/org/apache/syncope/client/enduser/pages/Flowable.java b/ext/flowable/client-enduser/src/main/java/org/apache/syncope/client/enduser/pages/Flowable.java index 0aa720edb5..589b067092 100644 --- a/ext/flowable/client-enduser/src/main/java/org/apache/syncope/client/enduser/pages/Flowable.java +++ b/ext/flowable/client-enduser/src/main/java/org/apache/syncope/client/enduser/pages/Flowable.java @@ -18,8 +18,9 @@ */ package org.apache.syncope.client.enduser.pages; -import java.util.Collections; import java.util.Iterator; +import java.util.List; +import java.util.function.Predicate; import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; import org.apache.syncope.client.enduser.SyncopeEnduserSession; @@ -38,7 +39,6 @@ import org.apache.wicket.ajax.markup.html.AjaxLink; import org.apache.wicket.ajax.markup.html.navigation.paging.AjaxPagingNavigator; import org.apache.wicket.extensions.markup.html.repeater.util.SortParam; import org.apache.wicket.extensions.markup.html.tabs.AbstractTab; -import org.apache.wicket.extensions.markup.html.tabs.ITab; import org.apache.wicket.markup.html.WebMarkupContainer; import org.apache.wicket.markup.repeater.Item; import org.apache.wicket.markup.repeater.data.DataView; @@ -64,27 +64,22 @@ public class Flowable extends BaseExtPage { @SpringBean protected BpmnProcessRestClient bpmnProcessRestClient; - protected final Model<String> bpmnProcessModel = new Model<>(); - - protected final WebMarkupContainer container; - - protected final DataView<UserRequest> urDataView; - public Flowable(final PageParameters parameters) { super(parameters, USER_REQUESTS); - container = new WebMarkupContainer("content"); - container.setOutputMarkupId(true); + WebMarkupContainer container = new WebMarkupContainer("content"); + contentWrapper.add(container.setOutputMarkupId(true)); // list of accordions containing request form (if any) and delete button - urDataView = new DataView<>("userRequests", new URDataProvider(ROWS_PER_PAGE, "bpmnProcess")) { + DataView<UserRequest> urDataView = new DataView<>( + "userRequests", new URDataProvider(ROWS_PER_PAGE, "bpmnProcess")) { private static final long serialVersionUID = -5002600396458362774L; @Override protected void populateItem(final Item<UserRequest> item) { - final UserRequest userRequest = item.getModelObject(); - item.add(new Accordion("userRequestDetails", Collections.<ITab>singletonList(new AbstractTab( + UserRequest userRequest = item.getModelObject(); + item.add(new Accordion("userRequestDetails", List.of(new AbstractTab( new StringResourceModel("user.requests.accordion", container, Model.of(userRequest))) { private static final long serialVersionUID = 1037272333056449378L; @@ -97,12 +92,12 @@ public class Flowable extends BaseExtPage { }), Model.of(-1)).setOutputMarkupId(true)); } }; - urDataView.setItemsPerPage(ROWS_PER_PAGE); urDataView.setOutputMarkupId(true); container.add(urDataView); container.add(new AjaxPagingNavigator("navigator", urDataView)); + Model<String> bpmnProcessModel = new Model<>(); AjaxLink<Void> startButton = new AjaxLink<>("start") { private static final long serialVersionUID = 3669569969172391336L; @@ -134,20 +129,14 @@ public class Flowable extends BaseExtPage { @Override protected void onUpdate(final AjaxRequestTarget target) { - if (StringUtils.isNotBlank(bpmnProcessModel.getObject())) { - startButton.setEnabled(true); - } else { - startButton.setEnabled(false); - } + startButton.setEnabled(StringUtils.isNotBlank(bpmnProcessModel.getObject())); target.add(container); } }); - bpmnProcesses.setChoices(bpmnProcessRestClient.getDefinitions().stream() - .filter(definition -> !definition.isUserWorkflow()) - .map(BpmnProcess::getKey).collect(Collectors.toList())); + bpmnProcesses.setChoices(bpmnProcessRestClient.getDefinitions().stream(). + filter(Predicate.not(BpmnProcess::isUserWorkflow)). + map(BpmnProcess::getKey).collect(Collectors.toList())); container.add(bpmnProcesses); - - contentWrapper.add(container); } protected class URDataProvider implements IDataProvider<UserRequest> { diff --git a/ext/flowable/client-enduser/src/main/resources/org/apache/syncope/client/enduser/pages/Flowable.html b/ext/flowable/client-enduser/src/main/resources/org/apache/syncope/client/enduser/pages/Flowable.html index cde3097c8a..2550f79e5f 100644 --- a/ext/flowable/client-enduser/src/main/resources/org/apache/syncope/client/enduser/pages/Flowable.html +++ b/ext/flowable/client-enduser/src/main/resources/org/apache/syncope/client/enduser/pages/Flowable.html @@ -56,21 +56,20 @@ under the License. <div wicket:id="userRequests"> <div wicket:id="userRequestDetails"/> </div> + + <table class="paginator"> + <tfoot> + <tr> + <td wicket:id="navigator"></td> + </tr> + </tfoot> + </table> </div> </div> </div> </div> </div> </div> - <div class="box-footer"> - <table class="paginator"> - <tfoot> - <tr> - <td wicket:id="navigator"></td> - </tr> - </tfoot> - </table> - </div> </div> </div> </div> diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/console/AnyObjectsITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/AnyObjectsITCase.java index a03979406d..b10afdd8ee 100644 --- a/fit/core-reference/src/test/java/org/apache/syncope/fit/console/AnyObjectsITCase.java +++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/AnyObjectsITCase.java @@ -20,8 +20,8 @@ package org.apache.syncope.fit.console; import static org.junit.jupiter.api.Assertions.assertNotNull; -import org.apache.syncope.client.console.wicket.markup.html.form.IndicatingOnConfirmAjaxLink; import org.apache.syncope.client.ui.commons.Constants; +import org.apache.syncope.client.ui.commons.markup.html.form.IndicatingOnConfirmAjaxLink; import org.apache.wicket.Component; import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.form.TextField; diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/console/GroupsITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/GroupsITCase.java index 69122a42a9..5f037b4967 100644 --- a/fit/core-reference/src/test/java/org/apache/syncope/fit/console/GroupsITCase.java +++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/GroupsITCase.java @@ -22,8 +22,8 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import org.apache.commons.lang3.StringUtils; -import org.apache.syncope.client.console.wicket.markup.html.form.IndicatingOnConfirmAjaxLink; import org.apache.syncope.client.ui.commons.Constants; +import org.apache.syncope.client.ui.commons.markup.html.form.IndicatingOnConfirmAjaxLink; import org.apache.wicket.Component; import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.form.TextField; diff --git a/fit/core-reference/src/test/java/org/apache/syncope/fit/console/UsersITCase.java b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/UsersITCase.java index a363a1072f..1a02eda814 100644 --- a/fit/core-reference/src/test/java/org/apache/syncope/fit/console/UsersITCase.java +++ b/fit/core-reference/src/test/java/org/apache/syncope/fit/console/UsersITCase.java @@ -23,8 +23,8 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import java.util.Calendar; -import org.apache.syncope.client.console.wicket.markup.html.form.IndicatingOnConfirmAjaxLink; import org.apache.syncope.client.ui.commons.Constants; +import org.apache.syncope.client.ui.commons.markup.html.form.IndicatingOnConfirmAjaxLink; import org.apache.wicket.Component; import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.form.TextField;
