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 ff440fa5f5 [SYNCOPE-1866] AuthProfile management in Enduser (#1083)
ff440fa5f5 is described below
commit ff440fa5f57949b7dff5effb06e1a6d64ffbd94f
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 | 15 +-
.../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 | 221 ++++++++++++++++++
.../enduser}/rest/AuthProfileRestClient.java | 35 ++-
.../syncope/client/enduser/pages/AuthProfile.html | 257 +++++++++++++++++++++
.../client/enduser/pages/AuthProfile.properties} | 31 ++-
.../enduser/pages/AuthProfile_it.properties} | 31 ++-
.../enduser/pages/AuthProfile_ja.properties} | 31 ++-
.../enduser/pages/AuthProfile_pt_BR.properties} | 31 ++-
.../enduser/pages/AuthProfile_ru.properties} | 31 ++-
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 +-
.../syncope/client/enduser/panels/Sidebar.html | 2 +-
.../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 | 51 +++-
.../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 +-
40 files changed, 954 insertions(+), 231 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 f6e02fe580..fa3dde612d 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;
@@ -50,15 +48,12 @@ import org.apache.syncope.common.lib.wa.MfaTrustedDevice;
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;
@@ -91,9 +86,6 @@ public class AuthProfileDirectoryPanel
});
addOuterObject(authProfileModal);
- addNewItemPanelBuilder(new CreateAuthProfileWizardBuilder(pageRef),
true);
- MetaDataRoleAuthorizationStrategy.authorize(addAjaxLink, RENDER,
AMEntitlement.AUTH_PROFILE_CREATE);
-
disableCheckBoxes();
initResultTable();
}
@@ -467,39 +459,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 475d1ad60d..cfa57a04ea 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();
}
@@ -90,9 +88,8 @@ public abstract class AuthProfileItemDirectoryPanel<I extends
BaseBean>
@Override
@SuppressWarnings("unchecked")
public void onEvent(final IEvent<?> event) {
- if (event.getPayload() instanceof ExitEvent) {
- AjaxRequestTarget target =
ExitEvent.class.cast(event.getPayload()).getTarget();
- authProfileModal.close(target);
+ if (event.getPayload() instanceof ExitEvent exitEvent) {
+ authProfileModal.close(exitEvent.getTarget());
} else if (event.getPayload() instanceof final
AjaxWizard.EditItemActionEvent<?> payload) {
payload.getTarget().ifPresent(actionTogglePanel::close);
}
@@ -194,12 +191,12 @@ public abstract class AuthProfileItemDirectoryPanel<I
extends BaseBean>
List<Serializable> values = (List<Serializable>)
wrapper.getPropertyValue("scratchCodes");
if (values != null) {
List<Integer> converted = values.stream().map(value -> {
- if (value instanceof Integer) {
- return Integer.class.cast(value);
+ if (value instanceof Integer integer) {
+ return integer;
}
- if (value instanceof String) {
+ if (value instanceof String string) {
try {
- return Integer.valueOf((String) value);
+ return Integer.valueOf(string);
} catch (NumberFormatException e) {
LOG.error("Could not convert to Integer: {}",
value, e);
}
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 d2b062bc11..d6801145ed 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..2eb52d5089
--- /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>4.0.0-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..8a1a08a020
--- /dev/null
+++
b/client/am/enduser/src/main/java/org/apache/syncope/client/enduser/pages/AuthProfile.java
@@ -0,0 +1,221 @@
+/*
+ * 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 Label("source",
item.getModelObject().getSource()));
+ 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 d2b062bc11..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 long 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..fdbe3b190a
--- /dev/null
+++
b/client/am/enduser/src/main/resources/org/apache/syncope/client/enduser/pages/AuthProfile.html
@@ -0,0 +1,257 @@
+<!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><wicket:message key="source"/></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><span wicket:id="source"/></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 57%
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..5bf4119b60 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,22 @@
# 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
+source=Source
+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..bb47fe6606 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,22 @@
# 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
+source=Origine
+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 57%
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..5bf4119b60 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,22 @@
# 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
+source=Source
+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 57%
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..5bf4119b60 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,22 @@
# 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
+source=Source
+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 57%
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..5bf4119b60 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,22 @@
# 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
+source=Source
+deviceFingerprint=Fingerprint
+recordDate=Record Date
+expirationDate=Expiration Date
diff --git a/client/am/pom.xml b/client/am/pom.xml
index abf0b323e7..b7386df99f 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 ab8db42b80..22d07abea0 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 d8386ad693..8490ed6aea 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
@@ -31,10 +31,10 @@ 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.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.common.lib.SyncopeConstants;
import org.apache.syncope.common.lib.types.IdRepoEntitlement;
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 49ca66bb1e..914c3f36ea 100644
--- a/client/idrepo/enduser/pom.xml
+++ b/client/idrepo/enduser/pom.xml
@@ -294,6 +294,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/main/resources/org/apache/syncope/client/enduser/panels/Sidebar.html
b/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/enduser/panels/Sidebar.html
index 6b62f0746e..5aaf7de965 100644
---
a/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/enduser/panels/Sidebar.html
+++
b/client/idrepo/enduser/src/main/resources/org/apache/syncope/client/enduser/panels/Sidebar.html
@@ -19,7 +19,7 @@ under the License.
-->
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:wicket="http://wicket.apache.org">
<wicket:panel>
- <div class="sidebar-brand bg-red d-flex">
+ <div class="sidebar-brand bg-red d-flex" style="height: 57px;">
<span>
<img src="ui-commons/img/logo-mini.png" alt="Apache Syncope Logo"
class="brand-image" style="max-height: none; opacity: .8;"/>
<span class="brand-text fw-light text-white">Apache Syncope</span>
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..12315eac3b
--- /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 jakarta.validation.constraints.NotNull;
+import jakarta.ws.rs.Consumes;
+import jakarta.ws.rs.DELETE;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.PUT;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.Produces;
+import jakarta.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 5a591fa681..f7cc23f9de 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 59246a9056..e13ccc1caf 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
@@ -21,12 +21,16 @@ package org.apache.syncope.core.logic;
import java.util.List;
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.EntityFactory;
import org.apache.syncope.core.persistence.api.entity.am.AuthProfile;
import org.apache.syncope.core.persistence.api.search.SyncopePage;
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.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.security.access.prepost.PreAuthorize;
@@ -42,9 +46,15 @@ public class AuthProfileLogic extends
AbstractAuthProfileLogic {
super(binder, authProfileDAO, entityFactory);
}
- @PreAuthorize("hasRole('" + AMEntitlement.AUTH_PROFILE_DELETE + "') ")
- public void delete(final String key) {
- authProfileDAO.deleteById(key);
+ @PreAuthorize("hasRole('" + AMEntitlement.AUTH_PROFILE_LIST + "')")
+ @Transactional(readOnly = true)
+ public Page<AuthProfileTO> list(final Pageable pageable) {
+ long count = authProfileDAO.count();
+
+ List<AuthProfileTO> result = authProfileDAO.findAll(pageable).
+ stream().map(binder::getAuthProfileTO).toList();
+
+ return new SyncopePage<>(result, pageable, count);
}
@PreAuthorize("hasRole('" + AMEntitlement.AUTH_PROFILE_READ + "') ")
@@ -55,6 +65,14 @@ public class AuthProfileLogic extends
AbstractAuthProfileLogic {
orElseThrow(() -> new NotFoundException("AuthProfile " + key));
}
+ @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)));
@@ -68,16 +86,25 @@ public class AuthProfileLogic extends
AbstractAuthProfileLogic {
authProfileDAO.save(authProfile);
}
- @PreAuthorize("hasRole('" + AMEntitlement.AUTH_PROFILE_LIST + "')")
- @Transactional(readOnly = true)
- public Page<AuthProfileTO> list(final Pageable pageable) {
- long 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(pageable).
- stream().
- map(binder::getAuthProfileTO).
- toList();
+ update(authProfileTO);
+ }
- return new SyncopePage<>(result, pageable, count);
+ @PreAuthorize("hasRole('" + AMEntitlement.AUTH_PROFILE_DELETE + "') ")
+ public void delete(final String key) {
+ authProfileDAO.deleteById(key);
+ }
+
+ @PreAuthorize("isAuthenticated() and not(hasRole('" +
IdRepoEntitlement.ANONYMOUS + "'))")
+ public void selfDelete() {
+
authProfileDAO.deleteById(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 3ca003d1d7..e419126b1c 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;
@@ -49,6 +50,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;
@@ -87,6 +89,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 ec560c259d..c19e418143 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
@@ -37,8 +37,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) {
+ Page<AuthProfileTO> result = logic.list(PageRequest.of(page < 1 ? 0 :
page - 1, size < 1 ? 1 : size));
+ return buildPagedResult(result);
}
@Override
@@ -61,8 +62,7 @@ public class AuthProfileServiceImpl extends AbstractService
implements AuthProfi
}
@Override
- public PagedResult<AuthProfileTO> list(final int page, final int size) {
- Page<AuthProfileTO> result = logic.list(PageRequest.of(page < 1 ? 0 :
page - 1, size < 1 ? 1 : size));
- return buildPagedResult(result);
+ 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 afdb00afd1..5b99ee44ba 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,9 +18,9 @@
*/
package org.apache.syncope.client.enduser.pages;
-import java.util.Collections;
import java.util.Iterator;
-import java.util.stream.Collectors;
+import java.util.List;
+import java.util.function.Predicate;
import org.apache.commons.lang3.StringUtils;
import org.apache.syncope.client.enduser.SyncopeEnduserSession;
import
org.apache.syncope.client.enduser.markup.html.form.BpmnProcessesAjaxPanel;
@@ -63,27 +63,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.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;
@@ -96,12 +91,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;
@@ -133,20 +128,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).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 5d747c3a76..60d7c77cbd 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
@@ -60,21 +60,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 b3e46d24a0..b6c10c3efb 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 d5824b1bd3..901ccbf10b 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;