diff --git a/cibseven-webclient-core/src/main/java/org/cibseven/webapp/providers/BpmProvider.java b/cibseven-webclient-core/src/main/java/org/cibseven/webapp/providers/BpmProvider.java index c1d3a0192..6bdc46329 100644 --- a/cibseven-webclient-core/src/main/java/org/cibseven/webapp/providers/BpmProvider.java +++ b/cibseven-webclient-core/src/main/java/org/cibseven/webapp/providers/BpmProvider.java @@ -54,6 +54,8 @@ import org.cibseven.webapp.rest.model.Message; import org.cibseven.webapp.rest.model.Metric; import org.cibseven.webapp.rest.model.NewUser; +import org.cibseven.webapp.rest.model.PasswordPolicyRequest; +import org.cibseven.webapp.rest.model.PasswordPolicyResponse; import org.cibseven.webapp.rest.model.Process; import org.cibseven.webapp.rest.model.ProcessDiagram; import org.cibseven.webapp.rest.model.ProcessInstance; @@ -77,6 +79,7 @@ import com.fasterxml.jackson.databind.JsonNode; +import io.jsonwebtoken.security.Password; import jakarta.servlet.http.HttpServletRequest; public interface BpmProvider { @@ -1263,4 +1266,6 @@ Collection findActivitiesProcessDefinitionHistory(Strin */ void createSetupUser(NewUser user, String engine) throws InvalidUserIdException; + PasswordPolicyResponse validatePasswordPolicy(PasswordPolicyRequest request) throws SystemException; + } diff --git a/cibseven-webclient-core/src/main/java/org/cibseven/webapp/providers/IIdentityProvider.java b/cibseven-webclient-core/src/main/java/org/cibseven/webapp/providers/IIdentityProvider.java new file mode 100644 index 000000000..642c69c1f --- /dev/null +++ b/cibseven-webclient-core/src/main/java/org/cibseven/webapp/providers/IIdentityProvider.java @@ -0,0 +1,26 @@ +/* + * Copyright CIB software GmbH and/or licensed to CIB software GmbH + * under one or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information regarding copyright + * ownership. CIB software licenses this file to you under the Apache License, + * Version 2.0; 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.cibseven.webapp.providers; + +import org.cibseven.webapp.exception.SystemException; +import org.cibseven.webapp.rest.model.PasswordPolicyRequest; +import org.cibseven.webapp.rest.model.PasswordPolicyResponse; + +public interface IIdentityProvider { + public PasswordPolicyResponse validatePasswordPolicy(PasswordPolicyRequest request) throws SystemException; + +} diff --git a/cibseven-webclient-core/src/main/java/org/cibseven/webapp/providers/IdentityProvider.java b/cibseven-webclient-core/src/main/java/org/cibseven/webapp/providers/IdentityProvider.java new file mode 100644 index 000000000..bd36bc7b2 --- /dev/null +++ b/cibseven-webclient-core/src/main/java/org/cibseven/webapp/providers/IdentityProvider.java @@ -0,0 +1,52 @@ +/* + * Copyright CIB software GmbH and/or licensed to CIB software GmbH + * under one or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information regarding copyright + * ownership. CIB software licenses this file to you under the Apache License, + * Version 2.0; 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.cibseven.webapp.providers; + +import java.util.ArrayList; +import java.util.Map; + +import org.cibseven.webapp.exception.SystemException; +import org.cibseven.webapp.rest.model.PasswordPolicyRequest; +import org.cibseven.webapp.rest.model.PasswordPolicyResponse; +import org.springframework.stereotype.Component; +import org.springframework.web.client.HttpClientErrorException; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Component +public class IdentityProvider extends SevenProviderBase implements IIdentityProvider { + + public PasswordPolicyResponse validatePasswordPolicy(PasswordPolicyRequest request) + throws SystemException { + String url = getEngineRestUrl() + "/identity/password-policy"; + Map body = Map.of( + "password", request.getPassword(), + "profile", request.getProfile()); + try { + return doPost(url, body, PasswordPolicyResponse.class, null).getBody(); + // when enable-password-policy is switched off the endpoint will return 404, so + // we catch this and return a default response + } catch (SystemException e) { + Throwable cause = e.getCause(); + if (cause instanceof HttpClientErrorException.NotFound) { + return new PasswordPolicyResponse(true, new ArrayList<>()); + } + throw e; + } + } +} diff --git a/cibseven-webclient-core/src/main/java/org/cibseven/webapp/providers/SevenProvider.java b/cibseven-webclient-core/src/main/java/org/cibseven/webapp/providers/SevenProvider.java index ec86fcac1..bffbd31c8 100644 --- a/cibseven-webclient-core/src/main/java/org/cibseven/webapp/providers/SevenProvider.java +++ b/cibseven-webclient-core/src/main/java/org/cibseven/webapp/providers/SevenProvider.java @@ -54,6 +54,8 @@ import org.cibseven.webapp.rest.model.Message; import org.cibseven.webapp.rest.model.Metric; import org.cibseven.webapp.rest.model.NewUser; +import org.cibseven.webapp.rest.model.PasswordPolicyRequest; +import org.cibseven.webapp.rest.model.PasswordPolicyResponse; import org.cibseven.webapp.rest.model.Process; import org.cibseven.webapp.rest.model.ProcessDiagram; import org.cibseven.webapp.rest.model.ProcessInstance; @@ -101,6 +103,7 @@ public class SevenProvider extends SevenProviderBase implements BpmProvider { @Autowired private ITenantProvider tenantProvider; @Autowired private IExternalTaskProvider externalTaskProvider; @Autowired private IEngineProvider engineProvider; + @Autowired private IdentityProvider identityProvider; /* @@ -1330,4 +1333,8 @@ public Boolean requiresSetup(String engine) { public void createSetupUser(NewUser user, String engine) throws InvalidUserIdException { engineProvider.createSetupUser(user, engine); } + @Override + public PasswordPolicyResponse validatePasswordPolicy(PasswordPolicyRequest request) throws SystemException { + return identityProvider.validatePasswordPolicy(request); + } } diff --git a/cibseven-webclient-core/src/main/java/org/cibseven/webapp/rest/SetupService.java b/cibseven-webclient-core/src/main/java/org/cibseven/webapp/rest/SetupService.java index c53adf425..361a97257 100644 --- a/cibseven-webclient-core/src/main/java/org/cibseven/webapp/rest/SetupService.java +++ b/cibseven-webclient-core/src/main/java/org/cibseven/webapp/rest/SetupService.java @@ -18,6 +18,8 @@ import org.cibseven.webapp.providers.BpmProvider; import org.cibseven.webapp.rest.model.NewUser; +import org.cibseven.webapp.rest.model.PasswordPolicyRequest; +import org.cibseven.webapp.rest.model.PasswordPolicyResponse; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; @@ -46,14 +48,14 @@ public class SetupService extends BaseService implements InitializingBean { @Autowired BpmProvider bpmProvider; - + @Value("${cibseven.webclient.user.provider:org.cibseven.webapp.auth.SevenUserProvider}") String userProvider; - - // Initial setup is only available for internal providers, not for external identity + + // Initial setup is only available for internal providers, not for external identity // providers like LDAP, ADFS, or SSO where users are managed externally. private static final String SEVEN_USER_PROVIDER = "org.cibseven.webapp.auth.SevenUserProvider"; - + @Override public void afterPropertiesSet() { } @@ -75,7 +77,7 @@ public void afterPropertiesSet() { @GetMapping("/status") public boolean requiresSetup( @RequestHeader(value = "X-Process-Engine", required = false) String engine) { - // Setup is only applicable when using internal user provider (SevenUserProvider) + // Setup is only applicable when using internal user provider (SevenUserProvider) // For external identity providers (LDAP, ADFS, SSO), users are managed externally if (!SEVEN_USER_PROVIDER.equals(userProvider)) { return false; @@ -105,18 +107,25 @@ public boolean requiresSetup( public ResponseEntity createInitialUser( @RequestBody NewUser newUser, @RequestHeader(value = "X-Process-Engine", required = false) String engine) { - // Setup is only applicable when using internal user provider (SevenUserProvider) + // Setup is only applicable when using internal user provider (SevenUserProvider) if (!SEVEN_USER_PROVIDER.equals(userProvider)) { return ResponseEntity.status(HttpStatus.FORBIDDEN).build(); } if (!bpmProvider.requiresSetup(engine)) { return ResponseEntity.status(HttpStatus.FORBIDDEN).build(); } - + // Create the admin user - backend handles group and authorization setup bpmProvider.createSetupUser(newUser, engine); return ResponseEntity.status(HttpStatus.CREATED).build(); } - + + @PostMapping("/validate-password") + public PasswordPolicyResponse validatePasswordPolicy(@RequestBody PasswordPolicyRequest request) { + + PasswordPolicyResponse response = bpmProvider.validatePasswordPolicy(request); + + return response; + } } diff --git a/cibseven-webclient-core/src/main/java/org/cibseven/webapp/rest/model/PasswordPolicyRequest.java b/cibseven-webclient-core/src/main/java/org/cibseven/webapp/rest/model/PasswordPolicyRequest.java new file mode 100644 index 000000000..cfe18b840 --- /dev/null +++ b/cibseven-webclient-core/src/main/java/org/cibseven/webapp/rest/model/PasswordPolicyRequest.java @@ -0,0 +1,40 @@ +/* + * Copyright CIB software GmbH and/or licensed to CIB software GmbH + * under one or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information regarding copyright + * ownership. CIB software licenses this file to you under the Apache License, + * Version 2.0; 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.cibseven.webapp.rest.model; + +import java.util.List; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +@Getter @Setter @ToString @AllArgsConstructor @NoArgsConstructor +public class PasswordPolicyRequest { + private String password; + private Profile profile; + + @Getter @Setter @ToString @AllArgsConstructor @NoArgsConstructor + public static class Profile { + private String id; + private String firstName; + private String lastName; + private String email; + + } +} \ No newline at end of file diff --git a/cibseven-webclient-core/src/main/java/org/cibseven/webapp/rest/model/PasswordPolicyResponse.java b/cibseven-webclient-core/src/main/java/org/cibseven/webapp/rest/model/PasswordPolicyResponse.java new file mode 100644 index 000000000..11fb3b61f --- /dev/null +++ b/cibseven-webclient-core/src/main/java/org/cibseven/webapp/rest/model/PasswordPolicyResponse.java @@ -0,0 +1,33 @@ +/* + * Copyright CIB software GmbH and/or licensed to CIB software GmbH + * under one or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information regarding copyright + * ownership. CIB software licenses this file to you under the Apache License, + * Version 2.0; 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.cibseven.webapp.rest.model; + +import java.util.List; +import java.util.Map; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +@Getter @Setter @ToString @AllArgsConstructor @NoArgsConstructor +public class PasswordPolicyResponse { + private boolean valid; + private List> rules; + +} \ No newline at end of file diff --git a/frontend/src/assets/translations_de.json b/frontend/src/assets/translations_de.json index 021eb7995..628690186 100644 --- a/frontend/src/assets/translations_de.json +++ b/frontend/src/assets/translations_de.json @@ -1176,14 +1176,14 @@ "policy": { "title": "Passwortrichtlinien", "header": "Ihr Passwort muss die folgenden Kriterien erfüllen: ", - "items": [ - "darf keine Benutzerdaten enthalten (z.B. Benutzer-ID, Vorname, Nachname, E-Mail)", - "Mindestlänge von 10 Zeichen", - "mindestens ein Großbuchstabe", - "mindestens ein Kleinbuchstabe", - "mindestens eine Ziffer", - "mindestens ein Sonderzeichen" - ] + "items": { + "PASSWORD_POLICY_USER_DATA": "darf keine Benutzerdaten enthalten (z.B. Benutzer-ID, Vorname, Nachname, E-Mail)", + "PASSWORD_POLICY_LENGTH": "Mindestlänge von {minLength} Zeichen", + "PASSWORD_POLICY_LOWERCASE": "mindestens {minLowerCase} Kleinbuchstabe(n)", + "PASSWORD_POLICY_UPPERCASE": "mindestens {minUpperCase} Großbuchstabe(n)", + "PASSWORD_POLICY_DIGIT": "mindestens {minDigit} Ziffer(n)", + "PASSWORD_POLICY_SPECIAL": "mindestens {minSpecial} Sonderzeichen" + } }, "recover": { "sendEmail": "Wiederherstellungs-E-Mail senden", @@ -1309,4 +1309,4 @@ "description": "Sie versuchen, auf die Prozess-Engine \"{0}\" zuzugreifen. Diese Engine ist für die Verwendung des integrierten Identitätsdienstes (Datenbank) konfiguriert, hat jedoch keine administrativen Benutzer eingerichtet. Auf dieser Seite können Sie einen ersten Benutzer für den Zugriff auf die Prozess-Engine erstellen." } } -} +} \ No newline at end of file diff --git a/frontend/src/assets/translations_en.json b/frontend/src/assets/translations_en.json index cab4687dd..73b2e1940 100644 --- a/frontend/src/assets/translations_en.json +++ b/frontend/src/assets/translations_en.json @@ -1186,14 +1186,14 @@ "policy": { "title": "Password Policy", "header": "Your password must fulfil the following criteria: ", - "items": [ - "must not contain user data (i.e., user ID, first name, last name, email)", - "minimum length of 10 characters", - "at least one upper case character", - "at least one lower case character", - "at least one digit", - "at least one special character" - ] + "items": { + "PASSWORD_POLICY_USER_DATA": "must not contain user data (i.e., user ID, first name, last name, email)", + "PASSWORD_POLICY_LENGTH": "minimum length of {minLength} characters", + "PASSWORD_POLICY_LOWERCASE": "at least {minLowerCase} lower case character", + "PASSWORD_POLICY_UPPERCASE": "at least {minUpperCase} upper case character", + "PASSWORD_POLICY_DIGIT": "at least {minDigit} digit", + "PASSWORD_POLICY_SPECIAL": "at least {minSpecial} special character" + } } }, "advanced-search": { diff --git a/frontend/src/assets/translations_es.json b/frontend/src/assets/translations_es.json index da08aa7ee..7def2fe43 100644 --- a/frontend/src/assets/translations_es.json +++ b/frontend/src/assets/translations_es.json @@ -1185,14 +1185,14 @@ "policy": { "title": "Política de contraseñas", "header": "Su contraseña debe cumplir los siguientes criterios: ", - "items": [ - "no debe contener datos de usuario (p.ej., ID de usuario, nombre, apellidos, correo electrónico)", - "10 caracteres como mínimo", - "al menos un carácter mayúsculo", - "al menos un carácter minúsculo", - "al menos una cifra", - "al menos un carácter especial" - ] + "items": { + "PASSWORD_POLICY_USER_DATA": "no debe contener datos de usuario (p.ej., ID de usuario, nombre, apellidos, correo electrónico)", + "PASSWORD_POLICY_LENGTH": "mínimo {minLength} caracteres", + "PASSWORD_POLICY_LOWERCASE": "al menos {minLowerCase} carácter minúsculo", + "PASSWORD_POLICY_UPPERCASE": "al menos {minUpperCase} carácter mayúsculo", + "PASSWORD_POLICY_DIGIT": "al menos {minDigit} cifra", + "PASSWORD_POLICY_SPECIAL": "al menos {minSpecial} carácter especial" + } } }, "advanced-search": { diff --git a/frontend/src/assets/translations_ru.json b/frontend/src/assets/translations_ru.json index 9cf72c278..28f9f9790 100644 --- a/frontend/src/assets/translations_ru.json +++ b/frontend/src/assets/translations_ru.json @@ -1185,14 +1185,14 @@ "policy": { "title": "Политика паролей", "header": "Ваш пароль должен соответствовать следующим критериям: ", - "items": [ - "не должно содержать данные пользователя (т. е. идентификатор пользователя, имя, фамилия, адрес электронной почты)", - "минимальная длина 10 символов", - "хотя бы один символ верхнего регистра", - "хотя бы один символ нижнего регистра", - "хотя бы одна цифра", - "хотя бы один специальный символ" - ] + "items": { + "PASSWORD_POLICY_USER_DATA": "не должно содержать данные пользователя (т. е. идентификатор пользователя, имя, фамилия, адрес электронной почты)", + "PASSWORD_POLICY_LENGTH": "минимальная длина {minLength} символов", + "PASSWORD_POLICY_LOWERCASE": "хотя бы {minLowerCase} символ нижнего регистра", + "PASSWORD_POLICY_UPPERCASE": "хотя бы {minUpperCase} символ верхнего регистра", + "PASSWORD_POLICY_DIGIT": "хотя бы {minDigit} цифра", + "PASSWORD_POLICY_SPECIAL": "хотя бы {minSpecial} специальный символ" + } } }, "advanced-search": { diff --git a/frontend/src/assets/translations_ua.json b/frontend/src/assets/translations_ua.json index c40adac95..9a576cd9a 100644 --- a/frontend/src/assets/translations_ua.json +++ b/frontend/src/assets/translations_ua.json @@ -1185,14 +1185,14 @@ "policy": { "title": "Політика паролів", "header": "Ваш пароль має відповідати таким критеріям:", - "items": [ - "не повинен містити дані користувача (ідентифікатор, ім’я, прізвище, email)", - "мінімальна довжина 10 символів", - "щонайменше один символ верхнього регістру", - "щонайменше один символ нижнього регістру", - "щонайменше одна цифра", - "щонайменше один спеціальний символ" - ] + "items": { + "PASSWORD_POLICY_USER_DATA": "не повинен містити дані користувача (ідентифікатор, ім’я, прізвище, email)", + "PASSWORD_POLICY_LENGTH": "мінімальна довжина {minLength} символів", + "PASSWORD_POLICY_LOWERCASE": "щонайменше {minLowerCase} символ нижнього регістру", + "PASSWORD_POLICY_UPPERCASE": "щонайменше {minUpperCase} символ верхнього регістру", + "PASSWORD_POLICY_DIGIT": "щонайменше {minDigit} цифра", + "PASSWORD_POLICY_SPECIAL": "щонайменше {minSpecial} спеціальний символ" + } } }, "advanced-search": { diff --git a/frontend/src/components/admin/CreateUser.vue b/frontend/src/components/admin/CreateUser.vue index 989ea4099..8cc7abbfe 100644 --- a/frontend/src/components/admin/CreateUser.vue +++ b/frontend/src/components/admin/CreateUser.vue @@ -32,15 +32,23 @@ - + +
+
{{ $t('password.policy.title') }}
+
{{ $t('password.policy.header') }}
+
    +
  • + {{ $t('password.policy.items.' + item.placeholder, item.parameter) }} +
  • +
+
{{ $t('errors.PasswordPolicyException') }}
@@ -78,19 +86,12 @@ - -
{{ $t('password.policy.title') }}
-
{{ $t('password.policy.header') }}
-
    -
  • {{ item }}
  • -
-
{{ $t('admin.users.userCreatedMessage', [profile.id]) }}