From abd50f52b54dcab7ee5ca81869dc7be93494be70 Mon Sep 17 00:00:00 2001 From: Boubaker Khanfir Date: Sun, 27 Aug 2023 10:08:26 +0100 Subject: [PATCH 1/2] feat: Allow to store Registration Settings from UI - MEED-1645 - Meeds-io/MIPs#63 This change will introduce a new Service for Registration and Platform Security Settings. This service will determine how a User can sign up into the platform and what is its default permissions. --- .../constant/UserRegistrationType.java | 26 +++ .../security/model/RegistrationSetting.java | 39 ++++ .../rest/RegistrationSettingRest.java | 71 ++++++ .../service/SecuritySettingService.java | 174 ++++++++++++++ .../service/SettingSecurityServieTest.java | 221 ++++++++++++++++++ .../portal/test/InitContainer1TestSuite.java | 3 + ....portal.component.portal-configuration.xml | 8 + .../exoplatform/web/login/LoginHandler.java | 12 + .../web/register/ExternalRegisterHandler.java | 170 ++++++-------- .../web/register/RegisterHandler.java | 12 +- .../register/RegisterUIParamsExtension.java | 17 +- .../register/ExternalRegisterHandlerTest.java | 31 ++- .../conf/common/onboarding-configuration.xml | 6 - .../conf/common/security-configuration.xml | 18 +- .../webapp/WEB-INF/conf/configuration.xml | 1 + .../conf/portal/controller-configuration.xml | 7 - 16 files changed, 667 insertions(+), 149 deletions(-) create mode 100644 component/portal/src/main/java/io/meeds/portal/security/constant/UserRegistrationType.java create mode 100644 component/portal/src/main/java/io/meeds/portal/security/model/RegistrationSetting.java create mode 100644 component/portal/src/main/java/io/meeds/portal/security/rest/RegistrationSettingRest.java create mode 100644 component/portal/src/main/java/io/meeds/portal/security/service/SecuritySettingService.java create mode 100644 component/portal/src/test/java/io/meeds/portal/security/service/SettingSecurityServieTest.java diff --git a/component/portal/src/main/java/io/meeds/portal/security/constant/UserRegistrationType.java b/component/portal/src/main/java/io/meeds/portal/security/constant/UserRegistrationType.java new file mode 100644 index 0000000000..446de0cfd8 --- /dev/null +++ b/component/portal/src/main/java/io/meeds/portal/security/constant/UserRegistrationType.java @@ -0,0 +1,26 @@ +/** + * This file is part of the Meeds project (https://meeds.io/). + * + * Copyright (C) 2020 - 2023 Meeds Association contact@meeds.io + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package io.meeds.portal.security.constant; + +public enum UserRegistrationType { + + OPEN, RESTRICTED; + +} diff --git a/component/portal/src/main/java/io/meeds/portal/security/model/RegistrationSetting.java b/component/portal/src/main/java/io/meeds/portal/security/model/RegistrationSetting.java new file mode 100644 index 0000000000..4f0a5d150d --- /dev/null +++ b/component/portal/src/main/java/io/meeds/portal/security/model/RegistrationSetting.java @@ -0,0 +1,39 @@ +/** + * This file is part of the Meeds project (https://meeds.io/). + * + * Copyright (C) 2020 - 2023 Meeds Association contact@meeds.io + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package io.meeds.portal.security.model; + +import io.meeds.portal.security.constant.UserRegistrationType; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class RegistrationSetting { + + private UserRegistrationType type; + + private boolean externalUser; + + private String[] extraGroupIds; + +} diff --git a/component/portal/src/main/java/io/meeds/portal/security/rest/RegistrationSettingRest.java b/component/portal/src/main/java/io/meeds/portal/security/rest/RegistrationSettingRest.java new file mode 100644 index 0000000000..fbda58a1fd --- /dev/null +++ b/component/portal/src/main/java/io/meeds/portal/security/rest/RegistrationSettingRest.java @@ -0,0 +1,71 @@ +/** + * This file is part of the Meeds project (https://meeds.io/). + * + * Copyright (C) 2020 - 2023 Meeds Association contact@meeds.io + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package io.meeds.portal.security.rest; + +import javax.annotation.security.RolesAllowed; +import javax.ws.rs.Consumes; +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 javax.ws.rs.core.Response; + +import org.exoplatform.services.rest.resource.ResourceContainer; + +import io.meeds.portal.security.model.RegistrationSetting; +import io.meeds.portal.security.service.SecuritySettingService; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; + +@Path("/registration/settings") +@Tag(name = "/registration/settings", description = "Managing user registraion settings and flow") +public class RegistrationSettingRest implements ResourceContainer { + + private SecuritySettingService securitySettingService; + + public RegistrationSettingRest(SecuritySettingService securitySettingService) { + this.securitySettingService = securitySettingService; + } + + @GET + @Produces(MediaType.APPLICATION_JSON) + @RolesAllowed("administrators") + @Operation(summary = "Get user registraion settings", description = "Get user registraion settings", method = "GET") + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Request fulfilled") }) + public Response getRegistrationSetting() { + RegistrationSetting registrationSetting = securitySettingService.getRegistrationSetting(); + return Response.ok(registrationSetting).build(); + } + + @PUT + @RolesAllowed("administrators") + @Consumes(MediaType.APPLICATION_JSON) + @Operation(summary = "Update user registraion settings and flow", description = "Update user registraion settings and flow", method = "PUT") + @ApiResponses(value = { @ApiResponse(responseCode = "204", description = "Request fulfilled") }) + public Response updateRegistrationSetting(RegistrationSetting registrationSetting) { + securitySettingService.saveRegistrationSetting(registrationSetting); + return Response.noContent().build(); + } + +} diff --git a/component/portal/src/main/java/io/meeds/portal/security/service/SecuritySettingService.java b/component/portal/src/main/java/io/meeds/portal/security/service/SecuritySettingService.java new file mode 100644 index 0000000000..7433e98a6c --- /dev/null +++ b/component/portal/src/main/java/io/meeds/portal/security/service/SecuritySettingService.java @@ -0,0 +1,174 @@ +/** + * This file is part of the Meeds project (https://meeds.io/). + * + * Copyright (C) 2020 - 2023 Meeds Association contact@meeds.io + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package io.meeds.portal.security.service; + +import static io.meeds.portal.security.constant.UserRegistrationType.OPEN; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.apache.commons.lang.StringUtils; + +import org.exoplatform.commons.api.settings.SettingService; +import org.exoplatform.commons.api.settings.SettingValue; +import org.exoplatform.commons.api.settings.data.Context; +import org.exoplatform.commons.api.settings.data.Scope; + +import io.meeds.portal.security.constant.UserRegistrationType; +import io.meeds.portal.security.model.RegistrationSetting; + +public class SecuritySettingService { + + protected static final String INTERNAL_USERS_GROUP = "/platform/users"; + + protected static final String EXTERNAL_USERS_GROUP = "/platform/externals"; + + protected static final Context SECURITY_CONTEXT = Context.GLOBAL.id("SECURITY"); + + protected static final Scope SECURITY_SCOPE = Scope.APPLICATION.id("SECURITY"); + + protected static final String REGISTRATION_TYPE_PARAM = "REGISTRATION_TYPE"; + + protected static final String REGISTRATION_EXTERNAL_USER_PARAM = "REGISTRATION_EXTERNAL_USER"; + + protected static final String REGISTRATION_EXTRA_GROUPS_PARAM = "REGISTRATION_EXTRA_GROUPS"; + + protected static final String EXTRA_GROUPS_SEPARATOR = ","; + + protected static final UserRegistrationType DEFAULT_REGISTRATION_TYPE = + UserRegistrationType.valueOf(System.getProperty("meeds.security.registration.type", + OPEN.name())); + + protected static final boolean DEFAULT_REGISTRATION_EXTERNAL_USER = + Boolean.parseBoolean(System.getProperty("meeds.security.registration.externalUser", + "false")); + + protected static final String[] DEFAULT_REGISTRATION_EXTRA_GROUPS = + Arrays.stream(System.getProperty("meeds.security.registration.extraGroups", + "") + .trim() + .split(EXTRA_GROUPS_SEPARATOR)) + .filter(StringUtils::isNotBlank) + .distinct() + .toArray(String[]::new); + + private RegistrationSetting registrationSetting; + + private SettingService settingService; + + public SecuritySettingService(SettingService settingService) { + this.settingService = settingService; + } + + public RegistrationSetting getRegistrationSetting() { + if (registrationSetting == null) { + registrationSetting = new RegistrationSetting(getRegistrationType(), + isRegistrationExternalUser(), + getRegistrationExtraGroupIds()); + } + return registrationSetting; + } + + public void saveRegistrationSetting(RegistrationSetting registrationSetting) { + saveRegistrationType(registrationSetting.getType()); + saveRegistrationExternalUser(registrationSetting.isExternalUser()); + saveRegistrationExtraGroupIds(registrationSetting.getExtraGroupIds()); + } + + public String[] getRegistrationGroupIds() { + List registrationExtraGroupIds = new ArrayList<>(Arrays.asList(getRegistrationExtraGroupIds())); + if (isRegistrationExternalUser()) { + registrationExtraGroupIds.add(EXTERNAL_USERS_GROUP); + } else { + registrationExtraGroupIds.add(INTERNAL_USERS_GROUP); + } + return registrationExtraGroupIds.stream().filter(StringUtils::isNotBlank).distinct().toList().toArray(new String[0]); + } + + public UserRegistrationType getRegistrationType() { + SettingValue settingValue = settingService.get(SECURITY_CONTEXT, SECURITY_SCOPE, REGISTRATION_TYPE_PARAM); + if (settingValue == null || settingValue.getValue() == null) { + return DEFAULT_REGISTRATION_TYPE; + } else { + return UserRegistrationType.valueOf(settingValue.getValue().toString()); + } + } + + public void saveRegistrationType(UserRegistrationType registrationType) { + try { + if (registrationType == null) { + registrationType = DEFAULT_REGISTRATION_TYPE; + } + settingService.set(SECURITY_CONTEXT, + SECURITY_SCOPE, + REGISTRATION_TYPE_PARAM, + SettingValue.create(registrationType.toString())); + } finally { + registrationSetting = null; + } + } + + public boolean isRegistrationExternalUser() { + SettingValue settingValue = settingService.get(SECURITY_CONTEXT, SECURITY_SCOPE, REGISTRATION_EXTERNAL_USER_PARAM); + if (settingValue == null || settingValue.getValue() == null) { + return DEFAULT_REGISTRATION_EXTERNAL_USER; + } else { + return Boolean.parseBoolean(settingValue.getValue().toString()); + } + } + + public void saveRegistrationExternalUser(boolean externalUser) { + try { + settingService.set(SECURITY_CONTEXT, + SECURITY_SCOPE, + REGISTRATION_EXTERNAL_USER_PARAM, + SettingValue.create(String.valueOf(externalUser))); + } finally { + registrationSetting = null; + } + } + + public String[] getRegistrationExtraGroupIds() { + SettingValue settingValue = settingService.get(SECURITY_CONTEXT, SECURITY_SCOPE, REGISTRATION_EXTRA_GROUPS_PARAM); + if (settingValue == null || settingValue.getValue() == null) { + return DEFAULT_REGISTRATION_EXTRA_GROUPS; + } else { + return Arrays.stream(settingValue.getValue().toString().split(EXTRA_GROUPS_SEPARATOR)) + .filter(StringUtils::isNotBlank) + .distinct() + .toArray(String[]::new); + } + } + + public void saveRegistrationExtraGroupIds(String[] groupIds) { + try { + if (groupIds == null) { + groupIds = DEFAULT_REGISTRATION_EXTRA_GROUPS; + } + settingService.set(SECURITY_CONTEXT, + SECURITY_SCOPE, + REGISTRATION_EXTRA_GROUPS_PARAM, + SettingValue.create(StringUtils.join(groupIds, EXTRA_GROUPS_SEPARATOR))); + } finally { + registrationSetting = null; + } + } + +} diff --git a/component/portal/src/test/java/io/meeds/portal/security/service/SettingSecurityServieTest.java b/component/portal/src/test/java/io/meeds/portal/security/service/SettingSecurityServieTest.java new file mode 100644 index 0000000000..69a1b7bc41 --- /dev/null +++ b/component/portal/src/test/java/io/meeds/portal/security/service/SettingSecurityServieTest.java @@ -0,0 +1,221 @@ +/** + * This file is part of the Meeds project (https://meeds.io/). + * + * Copyright (C) 2020 - 2023 Meeds Association contact@meeds.io + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package io.meeds.portal.security.service; + +import static io.meeds.portal.security.service.SecuritySettingService.DEFAULT_REGISTRATION_EXTERNAL_USER; +import static io.meeds.portal.security.service.SecuritySettingService.DEFAULT_REGISTRATION_EXTRA_GROUPS; +import static io.meeds.portal.security.service.SecuritySettingService.DEFAULT_REGISTRATION_TYPE; +import static io.meeds.portal.security.service.SecuritySettingService.EXTERNAL_USERS_GROUP; +import static io.meeds.portal.security.service.SecuritySettingService.EXTRA_GROUPS_SEPARATOR; +import static io.meeds.portal.security.service.SecuritySettingService.INTERNAL_USERS_GROUP; +import static io.meeds.portal.security.service.SecuritySettingService.REGISTRATION_EXTERNAL_USER_PARAM; +import static io.meeds.portal.security.service.SecuritySettingService.REGISTRATION_EXTRA_GROUPS_PARAM; +import static io.meeds.portal.security.service.SecuritySettingService.REGISTRATION_TYPE_PARAM; +import static io.meeds.portal.security.service.SecuritySettingService.SECURITY_CONTEXT; +import static io.meeds.portal.security.service.SecuritySettingService.SECURITY_SCOPE; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.Arrays; + +import org.apache.commons.codec.binary.StringUtils; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +import org.exoplatform.commons.api.settings.SettingService; +import org.exoplatform.commons.api.settings.SettingValue; + +import io.meeds.portal.security.constant.UserRegistrationType; +import io.meeds.portal.security.model.RegistrationSetting; + +@RunWith(MockitoJUnitRunner.class) +@SuppressWarnings({ "unchecked", "rawtypes" }) +public class SettingSecurityServieTest { + + @Mock + private SettingService settingService; + + private SecuritySettingService securitySettingService; + + @Before + public void setUp() { + securitySettingService = new SecuritySettingService(settingService); + } + + @Test + public void testGetRegistrationSetting() { + RegistrationSetting registrationSetting = securitySettingService.getRegistrationSetting(); + assertNotNull(registrationSetting); // NOSONAR + assertEquals(DEFAULT_REGISTRATION_TYPE, registrationSetting.getType()); + assertEquals(Arrays.asList(DEFAULT_REGISTRATION_EXTRA_GROUPS), Arrays.asList(registrationSetting.getExtraGroupIds())); + assertEquals(DEFAULT_REGISTRATION_EXTERNAL_USER, registrationSetting.isExternalUser()); + } + + @Test + public void testSaveRegistrationSetting() { + securitySettingService.saveRegistrationSetting(new RegistrationSetting()); + verify(settingService, times(3)).set(eq(SECURITY_CONTEXT), eq(SECURITY_SCOPE), anyString(), any()); + } + + @Test + public void testGetRegistrationGroupIds() { + String[] registrationGroupIds = securitySettingService.getRegistrationGroupIds(); + assertNotNull(registrationGroupIds); + assertEquals(1, registrationGroupIds.length); + assertEquals(INTERNAL_USERS_GROUP, registrationGroupIds[0]); + + when(settingService.get(eq(SECURITY_CONTEXT), + eq(SECURITY_SCOPE), + eq(REGISTRATION_EXTERNAL_USER_PARAM))).thenReturn((SettingValue) SettingValue.create(true)); + + registrationGroupIds = securitySettingService.getRegistrationGroupIds(); + assertNotNull(registrationGroupIds); + assertEquals(1, registrationGroupIds.length); + assertEquals(EXTERNAL_USERS_GROUP, registrationGroupIds[0]); + + when(settingService.get(eq(SECURITY_CONTEXT), + eq(SECURITY_SCOPE), + eq(REGISTRATION_EXTERNAL_USER_PARAM))).thenReturn((SettingValue) SettingValue.create(false)); + + registrationGroupIds = securitySettingService.getRegistrationGroupIds(); + assertNotNull(registrationGroupIds); + assertEquals(1, registrationGroupIds.length); + assertEquals(INTERNAL_USERS_GROUP, registrationGroupIds[0]); + } + + @Test + public void testGetRegistrationType() { + UserRegistrationType registrationType = securitySettingService.getRegistrationType(); + assertNotNull(registrationType); + assertEquals(DEFAULT_REGISTRATION_TYPE, registrationType); + + when(settingService.get(eq(SECURITY_CONTEXT), + eq(SECURITY_SCOPE), + eq(REGISTRATION_TYPE_PARAM))).thenReturn((SettingValue) SettingValue.create(UserRegistrationType.OPEN.name())); + + registrationType = securitySettingService.getRegistrationType(); + assertNotNull(registrationType); + assertEquals(UserRegistrationType.OPEN, registrationType); + + when(settingService.get(eq(SECURITY_CONTEXT), + eq(SECURITY_SCOPE), + eq(REGISTRATION_TYPE_PARAM))).thenReturn((SettingValue) SettingValue.create(UserRegistrationType.RESTRICTED.name())); + + registrationType = securitySettingService.getRegistrationType(); + assertNotNull(registrationType); + assertEquals(UserRegistrationType.RESTRICTED, registrationType); + } + + @Test + public void testSaveRegistrationType() { + securitySettingService.saveRegistrationType(UserRegistrationType.OPEN); + verify(settingService, + times(1)).set(eq(SECURITY_CONTEXT), + eq(SECURITY_SCOPE), + eq(REGISTRATION_TYPE_PARAM), + argThat(args -> StringUtils.equals(args.getValue().toString(), UserRegistrationType.OPEN.name()))); + securitySettingService.saveRegistrationType(UserRegistrationType.RESTRICTED); + verify(settingService, + times(1)).set(eq(SECURITY_CONTEXT), + eq(SECURITY_SCOPE), + eq(REGISTRATION_TYPE_PARAM), + argThat(args -> StringUtils.equals(args.getValue().toString(), UserRegistrationType.RESTRICTED.name()))); + } + + @Test + public void testIsRegistrationExternalUser() { + assertEquals(DEFAULT_REGISTRATION_EXTERNAL_USER, securitySettingService.isRegistrationExternalUser()); + + when(settingService.get(eq(SECURITY_CONTEXT), + eq(SECURITY_SCOPE), + eq(REGISTRATION_EXTERNAL_USER_PARAM))).thenReturn((SettingValue) SettingValue.create(true)); + assertTrue(securitySettingService.isRegistrationExternalUser()); + + when(settingService.get(eq(SECURITY_CONTEXT), + eq(SECURITY_SCOPE), + eq(REGISTRATION_EXTERNAL_USER_PARAM))).thenReturn((SettingValue) SettingValue.create(false)); + assertFalse(securitySettingService.isRegistrationExternalUser()); + } + + @Test + public void testSaveRegistrationExternalUser() { + securitySettingService.saveRegistrationExternalUser(true); + verify(settingService, times(1)).set(eq(SECURITY_CONTEXT), + eq(SECURITY_SCOPE), + eq(REGISTRATION_EXTERNAL_USER_PARAM), + argThat(args -> StringUtils.equals(args.getValue().toString(), "true"))); + securitySettingService.saveRegistrationExternalUser(false); + verify(settingService, times(1)).set(eq(SECURITY_CONTEXT), + eq(SECURITY_SCOPE), + eq(REGISTRATION_EXTERNAL_USER_PARAM), + argThat(args -> StringUtils.equals(args.getValue().toString(), "false"))); + } + + @Test + public void testGetRegistrationExtraGroupIds() { + assertEquals(Arrays.asList(INTERNAL_USERS_GROUP), Arrays.asList(securitySettingService.getRegistrationGroupIds())); + + when(settingService.get(eq(SECURITY_CONTEXT), + eq(SECURITY_SCOPE), + eq(REGISTRATION_EXTRA_GROUPS_PARAM))).thenReturn((SettingValue) SettingValue.create("")); + String[] registrationGroupIds = securitySettingService.getRegistrationGroupIds(); + assertNotNull(registrationGroupIds); + assertEquals(1, registrationGroupIds.length); + assertEquals(INTERNAL_USERS_GROUP, registrationGroupIds[0]); + + when(settingService.get(eq(SECURITY_CONTEXT), + eq(SECURITY_SCOPE), + eq(REGISTRATION_EXTRA_GROUPS_PARAM))).thenReturn((SettingValue) SettingValue.create("group1,group2")); + registrationGroupIds = securitySettingService.getRegistrationGroupIds(); + assertNotNull(registrationGroupIds); + assertEquals(3, registrationGroupIds.length); + assertEquals("group1", registrationGroupIds[0]); + assertEquals("group2", registrationGroupIds[1]); + assertEquals(INTERNAL_USERS_GROUP, registrationGroupIds[2]); + } + + @Test + public void testSaveRegistrationExtraGroupIds() { + securitySettingService.saveRegistrationExtraGroupIds(new String[0]); + verify(settingService, times(1)).set(eq(SECURITY_CONTEXT), + eq(SECURITY_SCOPE), + eq(REGISTRATION_EXTRA_GROUPS_PARAM), + argThat(args -> StringUtils.equals(args.getValue().toString(), ""))); + securitySettingService.saveRegistrationExtraGroupIds(new String[] { "/group1", "/group2" }); + verify(settingService, times(1)).set(eq(SECURITY_CONTEXT), + eq(SECURITY_SCOPE), + eq(REGISTRATION_EXTRA_GROUPS_PARAM), + argThat(args -> StringUtils.equals(args.getValue().toString(), + "/group1" + EXTRA_GROUPS_SEPARATOR + "/group2"))); + } + +} diff --git a/component/portal/src/test/java/org/exoplatform/portal/test/InitContainer1TestSuite.java b/component/portal/src/test/java/org/exoplatform/portal/test/InitContainer1TestSuite.java index 0fd3d959c9..03e453ab90 100644 --- a/component/portal/src/test/java/org/exoplatform/portal/test/InitContainer1TestSuite.java +++ b/component/portal/src/test/java/org/exoplatform/portal/test/InitContainer1TestSuite.java @@ -57,11 +57,14 @@ import org.exoplatform.portal.tree.list.TestListTree; import org.exoplatform.settings.rest.SettingResourceTest; +import io.meeds.portal.security.service.SettingSecurityServieTest; + @RunWith(Suite.class) @SuiteClasses({ + SettingSecurityServieTest.class, AccountSetupServiceTest.class, BrandingServiceImplTest.class, DefaultGroupVisibilityPluginTest.class, diff --git a/component/portal/src/test/resources/conf/exo.portal.component.portal-configuration.xml b/component/portal/src/test/resources/conf/exo.portal.component.portal-configuration.xml index f6b6e00c53..330b2ab2f1 100644 --- a/component/portal/src/test/resources/conf/exo.portal.component.portal-configuration.xml +++ b/component/portal/src/test/resources/conf/exo.portal.component.portal-configuration.xml @@ -320,6 +320,14 @@ + + io.meeds.portal.security.service.SecuritySettingService + + + + io.meeds.portal.security.rest.RegistrationSettingRest + + org.exoplatform.services.organization.OrganizationService diff --git a/component/web/security/src/main/java/org/exoplatform/web/login/LoginHandler.java b/component/web/security/src/main/java/org/exoplatform/web/login/LoginHandler.java index 4a9c95c6a6..10966c0a8f 100644 --- a/component/web/security/src/main/java/org/exoplatform/web/login/LoginHandler.java +++ b/component/web/security/src/main/java/org/exoplatform/web/login/LoginHandler.java @@ -59,11 +59,15 @@ import org.exoplatform.web.application.JspBasedWebHandler; import org.exoplatform.web.application.javascript.JavascriptConfigService; import org.exoplatform.web.login.recovery.PasswordRecoveryService; +import org.exoplatform.web.register.RegisterHandler; import org.exoplatform.web.security.AuthenticationRegistry; import org.exoplatform.web.security.security.AbstractTokenService; import org.exoplatform.web.security.security.CookieTokenService; import org.exoplatform.web.security.sso.SSOHelper; +import io.meeds.portal.security.constant.UserRegistrationType; +import io.meeds.portal.security.service.SecuritySettingService; + public class LoginHandler extends JspBasedWebHandler { public static final String LOGIN_EXTENSION_NAME = "LoginExtension"; @@ -88,6 +92,8 @@ public class LoginHandler extends JspBasedWebHandler { private OrganizationService organizationService; + private SecuritySettingService securitySettingService; + private PasswordRecoveryService passwordRecoveryService; private SSOHelper ssoHelper; @@ -102,6 +108,7 @@ public LoginHandler(PortalContainer container, // NOSONAR AuthenticationRegistry authenticationRegistry, LocaleConfigService localeConfigService, BrandingService brandingService, + SecuritySettingService securitySettingService, JavascriptConfigService javascriptConfigService, SkinService skinService, SSOHelper ssoHelper, @@ -109,6 +116,7 @@ public LoginHandler(PortalContainer container, // NOSONAR super(localeConfigService, brandingService, javascriptConfigService, skinService); this.container = container; this.organizationService = organizationService; + this.securitySettingService = securitySettingService; this.authenticationRegistry = authenticationRegistry; this.passwordRecoveryService = passwordRecoveryService; this.ssoHelper = ssoHelper; @@ -413,6 +421,10 @@ private void extendUIParameters(ControllerContext controllerContext, LoginStatus } }); } + // Force disabling Register Form when the platform access is restricted + if (securitySettingService.getRegistrationType() == UserRegistrationType.RESTRICTED) { + params.put(RegisterHandler.REGISTER_ENABLED, false); + } } catch (Exception e) { LOG.warn("Error while computing Login UI parameters", e); } diff --git a/component/web/security/src/main/java/org/exoplatform/web/register/ExternalRegisterHandler.java b/component/web/security/src/main/java/org/exoplatform/web/register/ExternalRegisterHandler.java index cbb0c72bd4..230157fcea 100644 --- a/component/web/security/src/main/java/org/exoplatform/web/register/ExternalRegisterHandler.java +++ b/component/web/security/src/main/java/org/exoplatform/web/register/ExternalRegisterHandler.java @@ -50,7 +50,6 @@ import org.exoplatform.commons.utils.ListAccess; import org.exoplatform.container.PortalContainer; import org.exoplatform.container.component.RequestLifeCycle; -import org.exoplatform.container.xml.InitParams; import org.exoplatform.portal.branding.BrandingService; import org.exoplatform.portal.resource.SkinService; import org.exoplatform.portal.rest.UserFieldValidator; @@ -72,6 +71,8 @@ import org.exoplatform.web.login.recovery.PasswordRecoveryService; import org.exoplatform.web.security.security.RemindPasswordTokenService; +import io.meeds.portal.security.service.SecuritySettingService; + import nl.captcha.Captcha; import nl.captcha.servlet.CaptchaServletUtil; import nl.captcha.text.producer.DefaultTextProducer; @@ -79,91 +80,85 @@ public class ExternalRegisterHandler extends JspBasedWebHandler { - public static final String REQUIRE_EMAIL_VALIDATION = "requireEmailValidation"; - - private static final String ADMINISTRATORS_GROUP = "/platform/administrators"; + public static final String REQUIRE_EMAIL_VALIDATION = "requireEmailValidation"; - private static final Log LOG = - ExoLogger.getLogger(ExternalRegisterHandler.class); + private static final String ADMINISTRATORS_GROUP = "/platform/administrators"; - private static final QualifiedName SERVER_CAPTCHA = QualifiedName.create("gtn", "serveCaptcha"); + private static final Log LOG = ExoLogger.getLogger(ExternalRegisterHandler.class); - private static final String REGISTERED_USER_MEMBERSHIPS_INIT_PARAMS = "registeredUserMemberships"; + private static final QualifiedName SERVER_CAPTCHA = QualifiedName.create("gtn", "serveCaptcha"); - public static final String USERNAME_PARAM = "username"; + public static final String USERNAME_PARAM = "username"; - public static final String EMAIL_PARAM = "email"; + public static final String EMAIL_PARAM = "email"; - public static final String LASTNAME_PARAM = "lastName"; + public static final String LASTNAME_PARAM = "lastName"; - public static final String FIRSTNAME_PARAM = "firstName"; + public static final String FIRSTNAME_PARAM = "firstName"; - public static final String PASSWORD_PARAM = "password"; + public static final String PASSWORD_PARAM = "password"; - public static final String PASSWORD_CONFIRM_PARAM = "password2"; + public static final String PASSWORD_CONFIRM_PARAM = "password2"; - public static final UserFieldValidator PASSWORD_VALIDATOR = + public static final UserFieldValidator PASSWORD_VALIDATOR = new UserFieldValidator(PASSWORD_PARAM, false, false, 8, 255); - public static final UserFieldValidator LASTNAME_VALIDATOR = + public static final UserFieldValidator LASTNAME_VALIDATOR = new UserFieldValidator(LASTNAME_PARAM, false, true); - public static final UserFieldValidator FIRSTNAME_VALIDATOR = + public static final UserFieldValidator FIRSTNAME_VALIDATOR = new UserFieldValidator(FIRSTNAME_PARAM, false, true); - public static final UserFieldValidator EMAIL_VALIDATOR = - new UserFieldValidator(EMAIL_PARAM, false, false); - - public static final String NAME = "external-registration"; + public static final UserFieldValidator EMAIL_VALIDATOR = new UserFieldValidator(EMAIL_PARAM, false, false); - public static final QualifiedName TOKEN = QualifiedName.create("gtn", "token"); + public static final String NAME = "external-registration"; - public static final QualifiedName LANG = QualifiedName.create("gtn", "lang"); + public static final QualifiedName TOKEN = QualifiedName.create("gtn", "token"); - public static final QualifiedName INIT_URL = QualifiedName.create("gtn", "initURL"); + public static final QualifiedName LANG = QualifiedName.create("gtn", "lang"); - public static final String REQ_PARAM_ACTION = "action"; + public static final QualifiedName INIT_URL = QualifiedName.create("gtn", "initURL"); - public static final String EXTERNALS_GROUP = "/platform/externals"; + public static final String REQ_PARAM_ACTION = "action"; - public static final String LOGIN = "/login"; + public static final String LOGIN = "/login"; - public static final String USERS_GROUP = "/platform/users"; + public static final String USERS_GROUP = "/platform/users"; - public static final String CAPTCHA_PARAM = "captcha"; + public static final String CAPTCHA_PARAM = "captcha"; - public static final String ACTION_PARAM = "action"; + public static final String ACTION_PARAM = "action"; - public static final String VALIDATE_EXTERNAL_EMAIL_ACTION = "validateEmail"; + public static final String VALIDATE_EXTERNAL_EMAIL_ACTION = "validateEmail"; - public static final String SAVE_EXTERNAL_ACTION = "saveExternal"; + public static final String SAVE_EXTERNAL_ACTION = "saveExternal"; - public static final String EXPIRED_ACTION_NAME = "expired"; + public static final String EXPIRED_ACTION_NAME = "expired"; - public static final String SUCCESS_MESSAGE_PARAM = "success"; + public static final String SUCCESS_MESSAGE_PARAM = "success"; - public static final String ERROR_MESSAGE_PARAM = "error"; + public static final String ERROR_MESSAGE_PARAM = "error"; - public static final String ALREADY_AUTHENTICATED_MESSAGE_PARAM = "authenticated"; + public static final String ALREADY_AUTHENTICATED_MESSAGE_PARAM = "authenticated"; - public static final String EMAIL_VERIFICATION_SENT = "emailVerificationSent"; + public static final String EMAIL_VERIFICATION_SENT = "emailVerificationSent"; - public static final String TOKEN_ID_PARAM = "tokenId"; + public static final String TOKEN_ID_PARAM = "tokenId"; - public static final int CAPTCHA_WIDTH = 200; + public static final int CAPTCHA_WIDTH = 200; - public static final int CAPTCHA_HEIGHT = 50; + public static final int CAPTCHA_HEIGHT = 50; - public static final String EXTERNAL_REGISTRATION_JSP_PATH = - "/WEB-INF/jsp/externalRegistration/init_account.jsp"; // NOSONAR + public static final String EXTERNAL_REGISTRATION_JSP_PATH = + "/WEB-INF/jsp/externalRegistration/init_account.jsp"; // NOSONAR - private static final String MEMBER = "member"; + private static final String MEMBER = "member"; - public static final String USERNAME_REQUEST_PARAM = "username"; + public static final String USERNAME_REQUEST_PARAM = "username"; - public static final String PASSWORD_REQUEST_PARAM = "password"; + public static final String PASSWORD_REQUEST_PARAM = "password"; - public static final String INITIAL_URI_PARAM = "initialURI"; + public static final String INITIAL_URI_PARAM = "initialURI"; private PortalContainer container; @@ -177,7 +172,7 @@ public class ExternalRegisterHandler extends JspBasedWebHandler { private OrganizationService organizationService; - private List registeredUserMemberships; + private SecuritySettingService securitySettingService; public ExternalRegisterHandler(PortalContainer container, // NOSONAR RemindPasswordTokenService remindPasswordTokenService, @@ -186,9 +181,9 @@ public ExternalRegisterHandler(PortalContainer container, // NOSONAR OrganizationService organizationService, LocaleConfigService localeConfigService, BrandingService brandingService, + SecuritySettingService securitySettingService, JavascriptConfigService javascriptConfigService, - SkinService skinService, - InitParams params) { + SkinService skinService) { super(localeConfigService, brandingService, javascriptConfigService, skinService); this.container = container; this.servletContext = container.getPortalContext(); @@ -196,17 +191,7 @@ public ExternalRegisterHandler(PortalContainer container, // NOSONAR this.passwordRecoveryService = passwordRecoveryService; this.resourceBundleService = resourceBundleService; this.organizationService = organizationService; - if (params != null && params.containsKey(REGISTERED_USER_MEMBERSHIPS_INIT_PARAMS)) { - registeredUserMemberships = - Arrays.asList(params.getValueParam(REGISTERED_USER_MEMBERSHIPS_INIT_PARAMS).getValue().split(",")) - .stream() - .map(StringUtils::trim) - .filter(StringUtils::isNotBlank) - .toList(); - } - if (CollectionUtils.isEmpty(registeredUserMemberships)) { - registeredUserMemberships = Collections.singletonList(EXTERNALS_GROUP); - } + this.securitySettingService = securitySettingService; } @Override @@ -239,10 +224,7 @@ public boolean execute(ControllerContext controllerContext) throws Exception {// String username = getStoredCredentials(token, requestAction); if (username == null) { // Token expired - return dispatch(controllerContext, - request, - response, - Collections.singletonMap(ACTION_PARAM, EXPIRED_ACTION_NAME)); + return dispatch(controllerContext, request, response, Collections.singletonMap(ACTION_PARAM, EXPIRED_ACTION_NAME)); } if (VALIDATE_EXTERNAL_EMAIL_ACTION.equalsIgnoreCase(requestAction)) { @@ -254,9 +236,7 @@ public boolean execute(ControllerContext controllerContext) throws Exception {// } else if (SAVE_EXTERNAL_ACTION.equalsIgnoreCase(requestAction)) { if (findUser(username) != null) { // User already exists - redirectToLoginPage(request, - response, - username); + redirectToLoginPage(request, response, username); return true; } String requestUsername = request.getParameter(USERNAME_PARAM); @@ -293,7 +273,13 @@ && isValidUserFullName(firstName, lastName, parameters, locale)) { user.setEmail(requestEmail); user.setPassword(password); String data = generateUserDetailCredential(user); - passwordRecoveryService.sendAccountVerificationEmail(data, requestUsername, firstName, lastName, requestEmail, locale, getBaseUrl(request)); + passwordRecoveryService.sendAccountVerificationEmail(data, + requestUsername, + firstName, + lastName, + requestEmail, + locale, + getBaseUrl(request)); parameters.put(SUCCESS_MESSAGE_PARAM, EMAIL_VERIFICATION_SENT); session.setAttribute(REQUIRE_EMAIL_VALIDATION, "false"); } @@ -332,10 +318,7 @@ private String getStoredCredentials(String token, String requestAction) { } } - private boolean isValidUserFullName(String firstName, - String lastName, - Map parameters, - Locale locale) { + private boolean isValidUserFullName(String firstName, String lastName, Map parameters, Locale locale) { String errorMessage = FIRSTNAME_VALIDATOR.validate(locale, firstName); if (StringUtils.isBlank(errorMessage)) { errorMessage = LASTNAME_VALIDATOR.validate(locale, lastName); @@ -357,10 +340,10 @@ private boolean isValidUserAndPassword(String tokenUsernameOrEmail, // NOSONAR ResourceBundle bundle, Locale locale) { boolean isEmailToken = StringUtils.contains(tokenUsernameOrEmail, "@"); - boolean notSameUser = StringUtils.isBlank(tokenUsernameOrEmail) - || (StringUtils.isBlank(username) && StringUtils.isBlank(email)) - || (isEmailToken && !StringUtils.equals(tokenUsernameOrEmail, email)) - || (!isEmailToken && !StringUtils.equals(tokenUsernameOrEmail, username)); + boolean notSameUser = + StringUtils.isBlank(tokenUsernameOrEmail) || (StringUtils.isBlank(username) && StringUtils.isBlank(email)) + || (isEmailToken && !StringUtils.equals(tokenUsernameOrEmail, email)) + || (!isEmailToken && !StringUtils.equals(tokenUsernameOrEmail, username)); if (notSameUser) { String errorMessage = bundle.getString("gatein.forgotPassword.usernameChanged"); errorMessage = errorMessage.replace("{0}", tokenUsernameOrEmail); @@ -405,25 +388,20 @@ private String createUser(User user) throws Exception { Collection memberships = organizationService.getMembershipHandler() .findMembershipsByUserAndGroup(login, ADMINISTRATORS_GROUP); + boolean isAdministrator = CollectionUtils.isNotEmpty(memberships); - if (!isAdministrator) { - // Avoid incoherence by indicating an admin user - // As external + if (!isAdministrator || securitySettingService.isRegistrationExternalUser()) { + // Avoid incoherence by indicating an admin user As external deleteFromInternalUsersGroup(login); } MembershipType memberMembershipType = organizationService.getMembershipTypeHandler().findMembershipType(MEMBER); - for (String groupId : registeredUserMemberships) { + for (String groupId : securitySettingService.getRegistrationGroupIds()) { Group group = organizationService.getGroupHandler().findGroupById(groupId); if (group == null) { LOG.warn("Group with id {} wasn't found, the newly registered user will not be added into it", groupId); - } else if (!isAdministrator || !StringUtils.equals(groupId, EXTERNALS_GROUP)) { - // Avoid incoherence by indicating an admin user As external - organizationService.getMembershipHandler() - .linkMembership(user, - group, - memberMembershipType, - true); + } else if (organizationService.getMembershipHandler().findMembershipByUserGroupAndType(login, groupId, MEMBER) == null) { + organizationService.getMembershipHandler().linkMembership(user, group, memberMembershipType, true); } } return login; @@ -474,7 +452,8 @@ private boolean dispatch(ControllerContext controllerContext, return true; } - private void redirectToLoginPage(HttpServletRequest request, HttpServletResponse response, + private void redirectToLoginPage(HttpServletRequest request, + HttpServletResponse response, String initialUri) throws IOException { // Invalidate the Captcha request.getSession().removeAttribute(NAME); @@ -569,7 +548,10 @@ private String unAccent(String src) { return Normalizer.normalize(src, Normalizer.Form.NFD).replaceAll("[^\\p{ASCII}]", "").replace("'", ""); } - private void wrapForAutomaticLogin(HttpServletRequest request, HttpServletResponse response, String initialUri, String username, + private void wrapForAutomaticLogin(HttpServletRequest request, + HttpServletResponse response, + String initialUri, + String username, String password) throws ServletException, IOException { restartTransaction(); HttpServletRequestWrapper wrappedRequestForLogin = wrapRequestForLogin(request, username, password, initialUri); @@ -623,7 +605,8 @@ private void restartTransaction() { } private String generateUserDetailCredential(User user) { - return user.getUserName() + "::" + user.getFirstName() + "::" + user.getLastName() + "::" + user.getEmail()+"::"+user.getPassword(); + return user.getUserName() + "::" + user.getFirstName() + "::" + user.getLastName() + "::" + user.getEmail() + "::" + + user.getPassword(); } private User generateUserFromCredential(String data) { @@ -633,9 +616,10 @@ private User generateUserFromCredential(String data) { user.setLastName(dataParts[2]); user.setEmail(dataParts[3]); - //password could contains '::' - //to extract it, we must not simply get last part, as we could be a not complete password. - String firstPart = dataParts[0]+"::" + dataParts[1] + "::" + dataParts[2] + "::" + dataParts[3]+"::"; + // password could contains '::' + // to extract it, we must not simply get last part, as we could be a not + // complete password. + String firstPart = dataParts[0] + "::" + dataParts[1] + "::" + dataParts[2] + "::" + dataParts[3] + "::"; String password = data.substring(firstPart.length()); user.setPassword(password); return user; diff --git a/component/web/security/src/main/java/org/exoplatform/web/register/RegisterHandler.java b/component/web/security/src/main/java/org/exoplatform/web/register/RegisterHandler.java index 4b5a606bf6..3f3dd20af7 100644 --- a/component/web/security/src/main/java/org/exoplatform/web/register/RegisterHandler.java +++ b/component/web/security/src/main/java/org/exoplatform/web/register/RegisterHandler.java @@ -85,8 +85,7 @@ public class RegisterHandler extends JspBasedWebHandler { public static final String CAPTCHA_PARAM = "captcha"; - public static final UserFieldValidator EMAIL_VALIDATOR = - new UserFieldValidator(EMAIL_PARAM, false, false); + public static final UserFieldValidator EMAIL_VALIDATOR = new UserFieldValidator(EMAIL_PARAM, false, false); public static final String ONBOARDING_EMAIL_SENT_MESSAGE = "onboardingEmailSent"; @@ -106,12 +105,12 @@ public class RegisterHandler extends JspBasedWebHandler { private ResourceBundleService resourceBundleService; + private RegisterUIParamsExtension registerUIParamsExtension; + private ServletContext servletContext; private String registerJspPath; - private boolean enabled; - public RegisterHandler(PortalContainer container, // NOSONAR ResourceBundleService resourceBundleService, PasswordRecoveryService passwordRecoveryService, @@ -127,7 +126,7 @@ public RegisterHandler(PortalContainer container, // NOSONAR this.passwordRecoveryService = passwordRecoveryService; this.organizationService = organizationService; this.resourceBundleService = resourceBundleService; - this.enabled = registerUIParamsExtension != null && registerUIParamsExtension.isRegisterEnabled(); + this.registerUIParamsExtension = registerUIParamsExtension; this.servletContext = container.getPortalContext(); if (params != null && params.containsKey(REGISTER_JSP_PATH_PARAM)) { this.registerJspPath = params.getValueParam(REGISTER_JSP_PATH_PARAM).getValue(); @@ -154,8 +153,7 @@ public boolean execute(ControllerContext controllerContext) throws Exception { return false; } - if (!enabled) { - LOG.warn("An hack tentative for user registration was detected"); + if (!registerUIParamsExtension.isRegisterEnabled()) { response.setStatus(401); return true; } diff --git a/component/web/security/src/main/java/org/exoplatform/web/register/RegisterUIParamsExtension.java b/component/web/security/src/main/java/org/exoplatform/web/register/RegisterUIParamsExtension.java index b8df1e8736..f1c9ece1ca 100644 --- a/component/web/security/src/main/java/org/exoplatform/web/register/RegisterUIParamsExtension.java +++ b/component/web/security/src/main/java/org/exoplatform/web/register/RegisterUIParamsExtension.java @@ -22,11 +22,13 @@ import java.util.List; import java.util.Map; -import org.exoplatform.container.xml.InitParams; import org.exoplatform.web.ControllerContext; import org.exoplatform.web.login.LoginHandler; import org.exoplatform.web.login.UIParamsExtension; +import io.meeds.portal.security.constant.UserRegistrationType; +import io.meeds.portal.security.service.SecuritySettingService; + public class RegisterUIParamsExtension implements UIParamsExtension { public static final String ONBOARDING_ENABLED_PARAM = "enabled"; @@ -36,12 +38,10 @@ public class RegisterUIParamsExtension implements UIParamsExtension { private static final List EXTENSION_NAMES = Arrays.asList(RegisterHandler.REGISTER_EXTENSION_NAME, LoginHandler.LOGIN_EXTENSION_NAME); - private boolean registerEnabled; + private SecuritySettingService securitySettingService; - public RegisterUIParamsExtension(InitParams params) { - if (params != null && params.containsKey(ONBOARDING_ENABLED_PARAM)) { - this.registerEnabled = Boolean.parseBoolean(params.getValueParam(ONBOARDING_ENABLED_PARAM).getValue()); - } + public RegisterUIParamsExtension(SecuritySettingService securitySettingService) { + this.securitySettingService = securitySettingService; } @Override @@ -51,7 +51,7 @@ public List getExtensionNames() { @Override public Map extendParameters(ControllerContext controllerContext, String extensionName) { - if (this.registerEnabled) { + if (isRegisterEnabled()) { Map params = new HashMap<>(); params.put(RegisterHandler.REGISTER_ENABLED, true); params.put(ONBOARDING_REGISTER_ENABLED, true); @@ -61,6 +61,7 @@ public Map extendParameters(ControllerContext controllerContext, } public boolean isRegisterEnabled() { - return registerEnabled; + return this.securitySettingService.getRegistrationType() == UserRegistrationType.OPEN; } + } diff --git a/component/web/security/src/test/java/org/exoplatform/web/register/ExternalRegisterHandlerTest.java b/component/web/security/src/test/java/org/exoplatform/web/register/ExternalRegisterHandlerTest.java index b2c951a699..7a22aa9dcf 100644 --- a/component/web/security/src/test/java/org/exoplatform/web/register/ExternalRegisterHandlerTest.java +++ b/component/web/security/src/test/java/org/exoplatform/web/register/ExternalRegisterHandlerTest.java @@ -92,6 +92,8 @@ import org.exoplatform.web.security.security.CookieTokenService; import org.exoplatform.web.security.security.RemindPasswordTokenService; +import io.meeds.portal.security.service.SecuritySettingService; + import nl.captcha.Captcha; @RunWith(MockitoJUnitRunner.class) @@ -156,6 +158,9 @@ public class ExternalRegisterHandlerTest { @Mock private WebAppController controller; + @Mock + private SecuritySettingService securitySettingService; + @Mock private Router router; @@ -221,8 +226,8 @@ public void setUp() throws Exception { when(organizationService.getGroupHandler()).thenReturn(groupHandler); when(organizationService.getMembershipTypeHandler()).thenReturn(membershipTypeHandler); when(organizationService.getMembershipHandler()).thenReturn(membershipHandler); - when(passwordRecoveryService.verifyToken(TOKEN_VALUE, - CookieTokenService.EXTERNAL_REGISTRATION_TOKEN)).thenReturn(EMAIL); + when(securitySettingService.getRegistrationGroupIds()).thenReturn(new String[] { "/platform/external" }); + when(passwordRecoveryService.verifyToken(TOKEN_VALUE, CookieTokenService.EXTERNAL_REGISTRATION_TOKEN)).thenReturn(EMAIL); externalRegisterHandler = new ExternalRegisterHandler(container, remindPasswordTokenService, @@ -231,12 +236,11 @@ public void setUp() throws Exception { organizationService, localeConfigService, brandingService, + securitySettingService, javascriptConfigService, - skinService, - params) { + skinService) { @Override - protected void extendApplicationParameters(JSONObject applicationParameters, - Map additionalParameters) { + protected void extendApplicationParameters(JSONObject applicationParameters, Map additionalParameters) { ExternalRegisterHandlerTest.this.applicationParameters = additionalParameters; super.extendApplicationParameters(applicationParameters, additionalParameters); } @@ -463,10 +467,10 @@ public void testRedirectToLoginWhenValid() throws Exception { @Test public void testRedirectToRegistrationWhenValid() throws Exception { prepareResetPasswordContext(); - + String password = "pass1234"; String passwordConfirm = password; - + when(request.getParameter(ACTION_PARAM)).thenReturn(SAVE_EXTERNAL_ACTION); when(request.getParameter(EMAIL_PARAM)).thenReturn(EMAIL); when(request.getParameter(FIRSTNAME_PARAM)).thenReturn(FIRSTNAME); @@ -476,24 +480,19 @@ public void testRedirectToRegistrationWhenValid() throws Exception { when(session.getAttribute(REQUIRE_EMAIL_VALIDATION)).thenReturn("true"); when(userHandler.createUserInstance(any())).thenAnswer(invocation -> new UserImpl(invocation.getArgument(0))); - + externalRegisterHandler.execute(controllerContext); assertNotNull(applicationParameters); assertEquals(EMAIL_VERIFICATION_SENT, applicationParameters.get(SUCCESS_MESSAGE_PARAM)); - verify(passwordRecoveryService, - times(1)).sendAccountVerificationEmail(any(), any(), any(), any(), any(), any(), any()); + verify(passwordRecoveryService, times(1)).sendAccountVerificationEmail(any(), any(), any(), any(), any(), any(), any()); } private void prepareResetPasswordContext() { Map parameters = new HashMap<>(); parameters.put(TOKEN, TOKEN_VALUE); - controllerContext = new ControllerContext(controller, - router, - request, - response, - parameters); + controllerContext = new ControllerContext(controller, router, request, response, parameters); } } diff --git a/web/portal/src/main/webapp/WEB-INF/conf/common/onboarding-configuration.xml b/web/portal/src/main/webapp/WEB-INF/conf/common/onboarding-configuration.xml index 98959634f3..335298a1e1 100644 --- a/web/portal/src/main/webapp/WEB-INF/conf/common/onboarding-configuration.xml +++ b/web/portal/src/main/webapp/WEB-INF/conf/common/onboarding-configuration.xml @@ -23,12 +23,6 @@ org.exoplatform.web.register.RegisterUIParamsExtension - - - enabled - ${meeds.register.onboarding.enabled:false} - - \ No newline at end of file diff --git a/web/portal/src/main/webapp/WEB-INF/conf/common/security-configuration.xml b/web/portal/src/main/webapp/WEB-INF/conf/common/security-configuration.xml index 31e036ead8..46479e5a8b 100644 --- a/web/portal/src/main/webapp/WEB-INF/conf/common/security-configuration.xml +++ b/web/portal/src/main/webapp/WEB-INF/conf/common/security-configuration.xml @@ -24,19 +24,13 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.exoplatform.org/xml/ns/kernel_1_2.xsd http://www.exoplatform.org/xml/ns/kernel_1_2.xsd" xmlns="http://www.exoplatform.org/xml/ns/kernel_1_2.xsd"> + + + io.meeds.portal.security.service.SecuritySettingService + + - org.exoplatform.services.security.SecurityService - org.exoplatform.services.security.impl.SecurityServiceImpl - - - security.authentication - sso - - - security.sso-authentication - cas - - + io.meeds.portal.security.rest.RegistrationSettingRest diff --git a/web/portal/src/main/webapp/WEB-INF/conf/configuration.xml b/web/portal/src/main/webapp/WEB-INF/conf/configuration.xml index a101280422..d317077516 100644 --- a/web/portal/src/main/webapp/WEB-INF/conf/configuration.xml +++ b/web/portal/src/main/webapp/WEB-INF/conf/configuration.xml @@ -26,6 +26,7 @@ xmlns="http://www.exoplatform.org/xml/ns/kernel_1_2.xsd"> war:/conf/common/common-configuration.xml war:/conf/common/resource-compressor-configuration.xml + war:/conf/common/security-configuration.xml war:/conf/common/account-setup-configuration.xml war:/conf/common/portlet-container-configuration.xml war:/conf/common/autologin-configuration.xml diff --git a/web/portal/src/main/webapp/WEB-INF/conf/portal/controller-configuration.xml b/web/portal/src/main/webapp/WEB-INF/conf/portal/controller-configuration.xml index db81b53df4..dd1df210d1 100644 --- a/web/portal/src/main/webapp/WEB-INF/conf/portal/controller-configuration.xml +++ b/web/portal/src/main/webapp/WEB-INF/conf/portal/controller-configuration.xml @@ -157,13 +157,6 @@ ExternalRegistrationHandler register org.exoplatform.web.register.ExternalRegisterHandler - - - registeredUserMemberships - Comma seperated list of groups to add for newly registered users - ${meeds.register.onboarding.memberships:/platform/externals} - - UploadHandler From c6062af4e5826e2195fb9e176e4e3b199e62eb7b Mon Sep 17 00:00:00 2001 From: Boubaker Khanfir Date: Thu, 7 Sep 2023 08:36:45 +0100 Subject: [PATCH 2/2] fix: Rename Default Registration properties and make it case insensitive - Meeds-io/MIPs#63 --- .../service/SecuritySettingService.java | 21 ++++++------------- .../service/SettingSecurityServieTest.java | 4 ++-- 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/component/portal/src/main/java/io/meeds/portal/security/service/SecuritySettingService.java b/component/portal/src/main/java/io/meeds/portal/security/service/SecuritySettingService.java index 7433e98a6c..bea053f8ba 100644 --- a/component/portal/src/main/java/io/meeds/portal/security/service/SecuritySettingService.java +++ b/component/portal/src/main/java/io/meeds/portal/security/service/SecuritySettingService.java @@ -53,21 +53,12 @@ public class SecuritySettingService { protected static final String EXTRA_GROUPS_SEPARATOR = ","; protected static final UserRegistrationType DEFAULT_REGISTRATION_TYPE = - UserRegistrationType.valueOf(System.getProperty("meeds.security.registration.type", - OPEN.name())); + UserRegistrationType.valueOf(System.getProperty("meeds.settings.access.type.default", + OPEN.name()).toUpperCase()); protected static final boolean DEFAULT_REGISTRATION_EXTERNAL_USER = - Boolean.parseBoolean(System.getProperty("meeds.security.registration.externalUser", - "false")); - - protected static final String[] DEFAULT_REGISTRATION_EXTRA_GROUPS = - Arrays.stream(System.getProperty("meeds.security.registration.extraGroups", - "") - .trim() - .split(EXTRA_GROUPS_SEPARATOR)) - .filter(StringUtils::isNotBlank) - .distinct() - .toArray(String[]::new); + Boolean.parseBoolean(System.getProperty("meeds.settings.access.externalUsers", + "false").toLowerCase()); private RegistrationSetting registrationSetting; @@ -148,7 +139,7 @@ public void saveRegistrationExternalUser(boolean externalUser) { public String[] getRegistrationExtraGroupIds() { SettingValue settingValue = settingService.get(SECURITY_CONTEXT, SECURITY_SCOPE, REGISTRATION_EXTRA_GROUPS_PARAM); if (settingValue == null || settingValue.getValue() == null) { - return DEFAULT_REGISTRATION_EXTRA_GROUPS; + return new String[0]; } else { return Arrays.stream(settingValue.getValue().toString().split(EXTRA_GROUPS_SEPARATOR)) .filter(StringUtils::isNotBlank) @@ -160,7 +151,7 @@ public String[] getRegistrationExtraGroupIds() { public void saveRegistrationExtraGroupIds(String[] groupIds) { try { if (groupIds == null) { - groupIds = DEFAULT_REGISTRATION_EXTRA_GROUPS; + groupIds = new String[0]; } settingService.set(SECURITY_CONTEXT, SECURITY_SCOPE, diff --git a/component/portal/src/test/java/io/meeds/portal/security/service/SettingSecurityServieTest.java b/component/portal/src/test/java/io/meeds/portal/security/service/SettingSecurityServieTest.java index 69a1b7bc41..b3c3f7cfd4 100644 --- a/component/portal/src/test/java/io/meeds/portal/security/service/SettingSecurityServieTest.java +++ b/component/portal/src/test/java/io/meeds/portal/security/service/SettingSecurityServieTest.java @@ -20,7 +20,6 @@ package io.meeds.portal.security.service; import static io.meeds.portal.security.service.SecuritySettingService.DEFAULT_REGISTRATION_EXTERNAL_USER; -import static io.meeds.portal.security.service.SecuritySettingService.DEFAULT_REGISTRATION_EXTRA_GROUPS; import static io.meeds.portal.security.service.SecuritySettingService.DEFAULT_REGISTRATION_TYPE; import static io.meeds.portal.security.service.SecuritySettingService.EXTERNAL_USERS_GROUP; import static io.meeds.portal.security.service.SecuritySettingService.EXTRA_GROUPS_SEPARATOR; @@ -76,8 +75,9 @@ public void testGetRegistrationSetting() { RegistrationSetting registrationSetting = securitySettingService.getRegistrationSetting(); assertNotNull(registrationSetting); // NOSONAR assertEquals(DEFAULT_REGISTRATION_TYPE, registrationSetting.getType()); - assertEquals(Arrays.asList(DEFAULT_REGISTRATION_EXTRA_GROUPS), Arrays.asList(registrationSetting.getExtraGroupIds())); assertEquals(DEFAULT_REGISTRATION_EXTERNAL_USER, registrationSetting.isExternalUser()); + assertNotNull(registrationSetting.getExtraGroupIds()); + assertEquals(0, registrationSetting.getExtraGroupIds().length); } @Test