From 90927fa2b1e5c9a49422d57ca26a1b21fed5153c Mon Sep 17 00:00:00 2001 From: dseurotech Date: Fri, 12 Jul 2024 10:52:43 +0200 Subject: [PATCH] :art: fixing the mess about password length resolution Signed-off-by: dseurotech --- .../shiro/AccountPasswordLengthProvider.java | 24 ++++++ .../AccountPasswordLengthProviderImpl.java | 63 +++++++++++++++ .../shiro/CredentialServiceImpl.java | 70 +++++++++-------- .../credential/shiro/PasswordValidator.java | 3 +- .../shiro/PasswordValidatorImpl.java | 40 ++-------- .../shiro/AuthenticationModule.java | 77 ++++--------------- ...entialServiceConfigurationManagerImpl.java | 45 +++-------- ...tialServiceConfigurationManagerModule.java | 66 ++++++++++++++++ ...java => SystemPasswordLengthProvider.java} | 9 +-- .../SystemPasswordLengthProviderImpl.java | 60 +++++++++++++++ .../test/SecurityLocatorConfiguration.java | 11 ++- .../user/test/UserLocatorConfiguration.java | 3 +- 12 files changed, 299 insertions(+), 172 deletions(-) create mode 100644 service/security/shiro/src/main/java/org/eclipse/kapua/service/authentication/credential/shiro/AccountPasswordLengthProvider.java create mode 100644 service/security/shiro/src/main/java/org/eclipse/kapua/service/authentication/credential/shiro/AccountPasswordLengthProviderImpl.java create mode 100644 service/security/shiro/src/main/java/org/eclipse/kapua/service/authentication/shiro/CredentialServiceConfigurationManagerModule.java rename service/security/shiro/src/main/java/org/eclipse/kapua/service/authentication/shiro/{CredentialServiceConfigurationManager.java => SystemPasswordLengthProvider.java} (66%) create mode 100644 service/security/shiro/src/main/java/org/eclipse/kapua/service/authentication/shiro/SystemPasswordLengthProviderImpl.java diff --git a/service/security/shiro/src/main/java/org/eclipse/kapua/service/authentication/credential/shiro/AccountPasswordLengthProvider.java b/service/security/shiro/src/main/java/org/eclipse/kapua/service/authentication/credential/shiro/AccountPasswordLengthProvider.java new file mode 100644 index 00000000000..f0051d44f52 --- /dev/null +++ b/service/security/shiro/src/main/java/org/eclipse/kapua/service/authentication/credential/shiro/AccountPasswordLengthProvider.java @@ -0,0 +1,24 @@ +/******************************************************************************* + * Copyright (c) 2016, 2022 Eurotech and/or its affiliates and others + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Eurotech - initial API and implementation + *******************************************************************************/ +package org.eclipse.kapua.service.authentication.credential.shiro; + +import org.eclipse.kapua.KapuaException; +import org.eclipse.kapua.model.id.KapuaId; +import org.eclipse.kapua.storage.TxContext; + +public interface AccountPasswordLengthProvider { + + int getMinimumPasswordLength(TxContext txContext, KapuaId scopeId) throws KapuaException; + + int getMaximumPasswordLength(TxContext txContext, KapuaId scopeId) throws KapuaException; +} diff --git a/service/security/shiro/src/main/java/org/eclipse/kapua/service/authentication/credential/shiro/AccountPasswordLengthProviderImpl.java b/service/security/shiro/src/main/java/org/eclipse/kapua/service/authentication/credential/shiro/AccountPasswordLengthProviderImpl.java new file mode 100644 index 00000000000..ac58efd31db --- /dev/null +++ b/service/security/shiro/src/main/java/org/eclipse/kapua/service/authentication/credential/shiro/AccountPasswordLengthProviderImpl.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright (c) 2016, 2022 Eurotech and/or its affiliates and others + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Eurotech - initial API and implementation + *******************************************************************************/ +package org.eclipse.kapua.service.authentication.credential.shiro; + +import java.util.Map; + +import org.eclipse.kapua.KapuaException; +import org.eclipse.kapua.commons.configuration.ServiceConfigurationManager; +import org.eclipse.kapua.commons.util.ArgumentValidator; +import org.eclipse.kapua.model.id.KapuaId; +import org.eclipse.kapua.service.authentication.shiro.SystemPasswordLengthProvider; +import org.eclipse.kapua.storage.TxContext; + +public class AccountPasswordLengthProviderImpl implements AccountPasswordLengthProvider { + + private final SystemPasswordLengthProvider systemPasswordLengthProvider; + private final ServiceConfigurationManager credentialServiceConfigurationManager; + public static final String PASSWORD_MIN_LENGTH_ACCOUNT_CONFIG_KEY = "password.minLength"; + + public AccountPasswordLengthProviderImpl(SystemPasswordLengthProvider systemPasswordLengthProvider, ServiceConfigurationManager credentialServiceConfigurationManager) { + this.systemPasswordLengthProvider = systemPasswordLengthProvider; + this.credentialServiceConfigurationManager = credentialServiceConfigurationManager; + } + + @Override + public int getMinimumPasswordLength(TxContext txContext, KapuaId scopeId) throws KapuaException { + // Argument Validation + ArgumentValidator.notNull(scopeId, "scopeId"); + + // Check access + // None + + // Get system minimum password length + int minPasswordLength = systemPasswordLengthProvider.getSystemMinimumPasswordLength(); + + if (!KapuaId.ANY.equals(scopeId)) { + Object minPasswordLengthAccountConfigValue = getConfigValues(txContext, scopeId).get(PASSWORD_MIN_LENGTH_ACCOUNT_CONFIG_KEY); + if (minPasswordLengthAccountConfigValue != null) { + minPasswordLength = Integer.parseInt(minPasswordLengthAccountConfigValue.toString()); + } + } + return minPasswordLength; + } + + @Override + public int getMaximumPasswordLength(TxContext txContext, KapuaId scopeId) throws KapuaException { + return systemPasswordLengthProvider.getSystemMaximumPasswordLength(); + } + + private Map getConfigValues(TxContext tx, KapuaId scopeId) throws KapuaException { + return credentialServiceConfigurationManager.getConfigValues(tx, scopeId, true); + } +} diff --git a/service/security/shiro/src/main/java/org/eclipse/kapua/service/authentication/credential/shiro/CredentialServiceImpl.java b/service/security/shiro/src/main/java/org/eclipse/kapua/service/authentication/credential/shiro/CredentialServiceImpl.java index af1afb4e30e..cbe720d9ab9 100644 --- a/service/security/shiro/src/main/java/org/eclipse/kapua/service/authentication/credential/shiro/CredentialServiceImpl.java +++ b/service/security/shiro/src/main/java/org/eclipse/kapua/service/authentication/credential/shiro/CredentialServiceImpl.java @@ -12,12 +12,19 @@ *******************************************************************************/ package org.eclipse.kapua.service.authentication.credential.shiro; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.util.concurrent.atomic.AtomicReference; + +import javax.inject.Singleton; + import org.apache.shiro.codec.Base64; import org.eclipse.kapua.KapuaEntityNotFoundException; import org.eclipse.kapua.KapuaException; import org.eclipse.kapua.KapuaIllegalArgumentException; import org.eclipse.kapua.KapuaRuntimeException; import org.eclipse.kapua.commons.configuration.KapuaConfigurableServiceBase; +import org.eclipse.kapua.commons.configuration.ServiceConfigurationManager; import org.eclipse.kapua.commons.model.domains.Domains; import org.eclipse.kapua.commons.util.ArgumentValidator; import org.eclipse.kapua.event.ServiceEvent; @@ -39,7 +46,6 @@ import org.eclipse.kapua.service.authentication.credential.CredentialService; import org.eclipse.kapua.service.authentication.credential.CredentialType; import org.eclipse.kapua.service.authentication.exception.DuplicatedPasswordCredentialException; -import org.eclipse.kapua.service.authentication.shiro.CredentialServiceConfigurationManager; import org.eclipse.kapua.service.authentication.shiro.setting.KapuaAuthenticationSetting; import org.eclipse.kapua.service.authentication.shiro.setting.KapuaAuthenticationSettingKeys; import org.eclipse.kapua.service.authentication.user.PasswordResetRequest; @@ -49,11 +55,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.inject.Singleton; -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; -import java.util.concurrent.atomic.AtomicReference; - /** * {@link CredentialService} implementation. * @@ -69,11 +70,12 @@ public class CredentialServiceImpl extends KapuaConfigurableServiceBase implemen private final CredentialFactory credentialFactory; private final KapuaAuthenticationSetting kapuaAuthenticationSetting; private final CredentialMapper credentialMapper; + private final AccountPasswordLengthProvider accountPasswordLengthProvider; private final PasswordValidator passwordValidator; private final PasswordResetter passwordResetter; public CredentialServiceImpl( - CredentialServiceConfigurationManager serviceConfigurationManager, + ServiceConfigurationManager serviceConfigurationManager, AuthorizationService authorizationService, PermissionFactory permissionFactory, TxManager txManager, @@ -82,11 +84,13 @@ public CredentialServiceImpl( CredentialMapper credentialMapper, PasswordValidator passwordValidator, KapuaAuthenticationSetting kapuaAuthenticationSetting, + AccountPasswordLengthProvider accountPasswordLengthProvider, PasswordResetter passwordResetter) { super(txManager, serviceConfigurationManager, Domains.CREDENTIAL, authorizationService, permissionFactory); this.credentialRepository = credentialRepository; this.credentialFactory = credentialFactory; this.kapuaAuthenticationSetting = kapuaAuthenticationSetting; + this.accountPasswordLengthProvider = accountPasswordLengthProvider; this.passwordResetter = passwordResetter; try { random = SecureRandom.getInstance("SHA1PRNG"); @@ -134,31 +138,31 @@ public Credential create(CredentialCreator credentialCreatorer) // Do create // Do pre persist magic on key values switch (credentialCreator.getCredentialType()) { - case API_KEY: // Generate new api key - int preLength = kapuaAuthenticationSetting.getInt(KapuaAuthenticationSettingKeys.AUTHENTICATION_CREDENTIAL_APIKEY_PRE_LENGTH); - int keyLength = kapuaAuthenticationSetting.getInt(KapuaAuthenticationSettingKeys.AUTHENTICATION_CREDENTIAL_APIKEY_KEY_LENGTH); - - byte[] bPre = new byte[preLength]; - random.nextBytes(bPre); - String pre = Base64.encodeToString(bPre).substring(0, preLength); - - byte[] bKey = new byte[keyLength]; - random.nextBytes(bKey); - String key = Base64.encodeToString(bKey); - - fullKey.set(pre + key); - - credentialCreator = new CredentialCreatorImpl(credentialCreator.getScopeId(), - credentialCreator.getUserId(), - credentialCreator.getCredentialType(), - fullKey.get(), - credentialCreator.getCredentialStatus(), - credentialCreator.getExpirationDate()); - break; - case PASSWORD: - default: - // Don't do anything special - break; + case API_KEY: // Generate new api key + int preLength = kapuaAuthenticationSetting.getInt(KapuaAuthenticationSettingKeys.AUTHENTICATION_CREDENTIAL_APIKEY_PRE_LENGTH); + int keyLength = kapuaAuthenticationSetting.getInt(KapuaAuthenticationSettingKeys.AUTHENTICATION_CREDENTIAL_APIKEY_KEY_LENGTH); + + byte[] bPre = new byte[preLength]; + random.nextBytes(bPre); + String pre = Base64.encodeToString(bPre).substring(0, preLength); + + byte[] bKey = new byte[keyLength]; + random.nextBytes(bKey); + String key = Base64.encodeToString(bKey); + + fullKey.set(pre + key); + + credentialCreator = new CredentialCreatorImpl(credentialCreator.getScopeId(), + credentialCreator.getUserId(), + credentialCreator.getCredentialType(), + fullKey.get(), + credentialCreator.getCredentialStatus(), + credentialCreator.getExpirationDate()); + break; + case PASSWORD: + default: + // Don't do anything special + break; } // Create Credential Credential newCredential = credentialMapper.map(credentialCreator); @@ -325,7 +329,7 @@ public void unlock(KapuaId scopeId, KapuaId credentialId) throws KapuaException @Override public int getMinimumPasswordLength(KapuaId scopeId) throws KapuaException { - return txManager.execute(tx -> passwordValidator.getMinimumPasswordLength(tx, scopeId)); + return txManager.execute(tx -> accountPasswordLengthProvider.getMinimumPasswordLength(tx, scopeId)); } private long countExistingCredentials(CredentialType credentialType, KapuaId scopeId, KapuaId userId) throws KapuaException { diff --git a/service/security/shiro/src/main/java/org/eclipse/kapua/service/authentication/credential/shiro/PasswordValidator.java b/service/security/shiro/src/main/java/org/eclipse/kapua/service/authentication/credential/shiro/PasswordValidator.java index 32fb8ad05fc..19ee76692e4 100644 --- a/service/security/shiro/src/main/java/org/eclipse/kapua/service/authentication/credential/shiro/PasswordValidator.java +++ b/service/security/shiro/src/main/java/org/eclipse/kapua/service/authentication/credential/shiro/PasswordValidator.java @@ -17,7 +17,6 @@ import org.eclipse.kapua.storage.TxContext; public interface PasswordValidator { - void validatePassword(TxContext txContext, KapuaId scopeId, String plainPassword) throws KapuaException; - int getMinimumPasswordLength(TxContext txContext, KapuaId scopeId) throws KapuaException; + void validatePassword(TxContext txContext, KapuaId scopeId, String plainPassword) throws KapuaException; } diff --git a/service/security/shiro/src/main/java/org/eclipse/kapua/service/authentication/credential/shiro/PasswordValidatorImpl.java b/service/security/shiro/src/main/java/org/eclipse/kapua/service/authentication/credential/shiro/PasswordValidatorImpl.java index 30e8248270d..ef4b93bb2b7 100644 --- a/service/security/shiro/src/main/java/org/eclipse/kapua/service/authentication/credential/shiro/PasswordValidatorImpl.java +++ b/service/security/shiro/src/main/java/org/eclipse/kapua/service/authentication/credential/shiro/PasswordValidatorImpl.java @@ -17,18 +17,14 @@ import org.eclipse.kapua.commons.util.CommonsValidationRegex; import org.eclipse.kapua.model.id.KapuaId; import org.eclipse.kapua.service.authentication.exception.PasswordLengthException; -import org.eclipse.kapua.service.authentication.shiro.CredentialServiceConfigurationManager; -import org.eclipse.kapua.service.authentication.shiro.CredentialServiceConfigurationManagerImpl; import org.eclipse.kapua.storage.TxContext; -import java.util.Map; - public class PasswordValidatorImpl implements PasswordValidator { - private final CredentialServiceConfigurationManager credentialServiceConfigurationManager; + private final AccountPasswordLengthProvider accountPasswordLengthProvider; - public PasswordValidatorImpl(CredentialServiceConfigurationManager credentialServiceConfigurationManager) { - this.credentialServiceConfigurationManager = credentialServiceConfigurationManager; + public PasswordValidatorImpl(AccountPasswordLengthProvider accountPasswordLengthProvider) { + this.accountPasswordLengthProvider = accountPasswordLengthProvider; } @Override @@ -38,35 +34,13 @@ public void validatePassword(TxContext txContext, KapuaId scopeId, String plainP ArgumentValidator.notEmptyOrNull(plainPassword, "plainPassword"); // Validate Password length - int minPasswordLength = getMinimumPasswordLength(txContext, scopeId); - if (plainPassword.length() < minPasswordLength || plainPassword.length() > CredentialServiceConfigurationManagerImpl.SYSTEM_MAXIMUM_PASSWORD_LENGTH) { - throw new PasswordLengthException(minPasswordLength, CredentialServiceConfigurationManagerImpl.SYSTEM_MAXIMUM_PASSWORD_LENGTH); + int minPasswordLength = accountPasswordLengthProvider.getMinimumPasswordLength(txContext, scopeId); + int maxPasswordLenght = accountPasswordLengthProvider.getMaximumPasswordLength(txContext, scopeId); + if (plainPassword.length() < minPasswordLength || plainPassword.length() > maxPasswordLenght) { + throw new PasswordLengthException(minPasswordLength, maxPasswordLenght); } // Validate Password regex ArgumentValidator.match(plainPassword, CommonsValidationRegex.PASSWORD_REGEXP, "plainPassword"); } - @Override - public int getMinimumPasswordLength(TxContext txContext, KapuaId scopeId) throws KapuaException { - // Argument Validation - ArgumentValidator.notNull(scopeId, "scopeId"); - - // Check access - // None - - // Get system minimum password length - int minPasswordLength = credentialServiceConfigurationManager.getSystemMinimumPasswordLength(); - - if (!KapuaId.ANY.equals(scopeId)) { - Object minPasswordLengthAccountConfigValue = getConfigValues(txContext, scopeId).get(CredentialServiceConfigurationManagerImpl.PASSWORD_MIN_LENGTH_ACCOUNT_CONFIG_KEY); - if (minPasswordLengthAccountConfigValue != null) { - minPasswordLength = Integer.parseInt(minPasswordLengthAccountConfigValue.toString()); - } - } - return minPasswordLength; - } - - private Map getConfigValues(TxContext tx, KapuaId scopeId) throws KapuaException { - return credentialServiceConfigurationManager.getConfigValues(tx, scopeId, true); - } } diff --git a/service/security/shiro/src/main/java/org/eclipse/kapua/service/authentication/shiro/AuthenticationModule.java b/service/security/shiro/src/main/java/org/eclipse/kapua/service/authentication/shiro/AuthenticationModule.java index 75163cb39b1..ad13a65565c 100644 --- a/service/security/shiro/src/main/java/org/eclipse/kapua/service/authentication/shiro/AuthenticationModule.java +++ b/service/security/shiro/src/main/java/org/eclipse/kapua/service/authentication/shiro/AuthenticationModule.java @@ -15,21 +15,15 @@ import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.util.Map; -import java.util.Optional; import javax.inject.Named; import javax.inject.Singleton; -import org.eclipse.kapua.KapuaException; import org.eclipse.kapua.KapuaRuntimeException; -import org.eclipse.kapua.commons.configuration.CachingServiceConfigRepository; -import org.eclipse.kapua.commons.configuration.RootUserTester; -import org.eclipse.kapua.commons.configuration.ServiceConfigImplJpaRepository; -import org.eclipse.kapua.commons.configuration.ServiceConfigurationManagerCachingWrapper; +import org.eclipse.kapua.commons.configuration.ServiceConfigurationManager; import org.eclipse.kapua.commons.core.AbstractKapuaModule; import org.eclipse.kapua.commons.core.ServiceModule; import org.eclipse.kapua.commons.event.ServiceEventHouseKeeperFactoryImpl; -import org.eclipse.kapua.commons.jpa.EntityCacheFactory; import org.eclipse.kapua.commons.jpa.KapuaJpaRepositoryConfiguration; import org.eclipse.kapua.commons.jpa.KapuaJpaTxManagerFactory; import org.eclipse.kapua.commons.model.domains.Domains; @@ -37,14 +31,11 @@ import org.eclipse.kapua.commons.service.event.store.api.EventStoreRecordRepository; import org.eclipse.kapua.commons.service.event.store.internal.EventStoreServiceImpl; import org.eclipse.kapua.commons.util.qr.QRCodeBuilder; -import org.eclipse.kapua.commons.util.xml.XmlUtil; import org.eclipse.kapua.event.ServiceEventBus; import org.eclipse.kapua.event.ServiceEventBusException; -import org.eclipse.kapua.model.config.metatype.KapuaTocd; import org.eclipse.kapua.model.domain.Actions; import org.eclipse.kapua.model.domain.Domain; import org.eclipse.kapua.model.domain.DomainEntry; -import org.eclipse.kapua.model.id.KapuaId; import org.eclipse.kapua.service.account.AccountService; import org.eclipse.kapua.service.authentication.AuthenticationService; import org.eclipse.kapua.service.authentication.CredentialsFactory; @@ -64,6 +55,8 @@ import org.eclipse.kapua.service.authentication.credential.mfa.shiro.ScratchCodeFactoryImpl; import org.eclipse.kapua.service.authentication.credential.mfa.shiro.ScratchCodeImplJpaRepository; import org.eclipse.kapua.service.authentication.credential.mfa.shiro.ScratchCodeServiceImpl; +import org.eclipse.kapua.service.authentication.credential.shiro.AccountPasswordLengthProvider; +import org.eclipse.kapua.service.authentication.credential.shiro.AccountPasswordLengthProviderImpl; import org.eclipse.kapua.service.authentication.credential.shiro.CredentialFactoryImpl; import org.eclipse.kapua.service.authentication.credential.shiro.CredentialImplJpaRepository; import org.eclipse.kapua.service.authentication.credential.shiro.CredentialMapper; @@ -95,7 +88,6 @@ import org.eclipse.kapua.service.authorization.AuthorizationService; import org.eclipse.kapua.service.authorization.permission.PermissionFactory; import org.eclipse.kapua.service.user.UserService; -import org.eclipse.kapua.storage.TxContext; import com.google.inject.Provides; import com.google.inject.multibindings.ProvidesIntoSet; @@ -115,6 +107,7 @@ protected void configureModule() { bind(MfaAuthenticator.class).to(MfaAuthenticatorImpl.class).in(Singleton.class); bind(KapuaCryptoSetting.class).in(Singleton.class); bind(CacheMetric.class).in(Singleton.class); + bind(SystemPasswordLengthProvider.class).to(SystemPasswordLengthProviderImpl.class).in(Singleton.class); } @Provides @@ -192,8 +185,16 @@ public CredentialsHandler accessTokenCredentialsHandler() { @Provides @Singleton - PasswordValidator passwordValidator(CredentialServiceConfigurationManager credentialServiceConfigurationManager) { - return new PasswordValidatorImpl(credentialServiceConfigurationManager); + PasswordValidator passwordValidator( + AccountPasswordLengthProvider accountPasswordLengthProvider) { + return new PasswordValidatorImpl(accountPasswordLengthProvider); + } + + @Provides + @Singleton + AccountPasswordLengthProvider accountPasswordLengthProvider(SystemPasswordLengthProvider systemPasswordLengthProvider, + Map, ServiceConfigurationManager> serviceConfigurationManagersByServiceClass) { + return new AccountPasswordLengthProviderImpl(systemPasswordLengthProvider, serviceConfigurationManagersByServiceClass.get(CredentialService.class)); } @Provides @@ -286,13 +287,14 @@ public ScratchCodeRepository scratchCodeRepository(KapuaJpaRepositoryConfigurati @Provides @Singleton public CredentialService credentialService( - CredentialServiceConfigurationManager serviceConfigurationManager, + ServiceConfigurationManager serviceConfigurationManager, AuthorizationService authorizationService, PermissionFactory permissionFactory, CredentialRepository credentialRepository, CredentialFactory credentialFactory, KapuaJpaTxManagerFactory jpaTxManagerFactory, CredentialMapper credentialMapper, + AccountPasswordLengthProvider accountPasswordLengthProvider, PasswordValidator passwordValidator, KapuaAuthenticationSetting kapuaAuthenticationSetting, PasswordResetter passwordResetter) { @@ -305,6 +307,7 @@ public CredentialService credentialService( credentialMapper, passwordValidator, kapuaAuthenticationSetting, + accountPasswordLengthProvider, passwordResetter); } @@ -314,50 +317,4 @@ CredentialRepository credentialRepository(KapuaJpaRepositoryConfiguration jpaRep return new CredentialImplJpaRepository(jpaRepoConfig); } - @Provides - @Singleton - public CredentialServiceConfigurationManager credentialServiceConfigurationManager( - RootUserTester rootUserTester, - KapuaJpaRepositoryConfiguration jpaRepoConfig, - KapuaAuthenticationSetting kapuaAuthenticationSetting, - EntityCacheFactory entityCacheFactory, - XmlUtil xmlUtil) { - final CredentialServiceConfigurationManagerImpl credentialServiceConfigurationManager = new CredentialServiceConfigurationManagerImpl( - new CachingServiceConfigRepository( - new ServiceConfigImplJpaRepository(jpaRepoConfig), - entityCacheFactory.createCache("AbstractKapuaConfigurableServiceCacheId") - ), - rootUserTester, - kapuaAuthenticationSetting, - xmlUtil); - - final ServiceConfigurationManagerCachingWrapper cached = new ServiceConfigurationManagerCachingWrapper(credentialServiceConfigurationManager); - return new CredentialServiceConfigurationManager() { - - @Override - public int getSystemMinimumPasswordLength() { - return credentialServiceConfigurationManager.getSystemMinimumPasswordLength(); - } - - @Override - public void checkAllowedEntities(TxContext txContext, KapuaId scopeId, String entityType) throws KapuaException { - cached.checkAllowedEntities(txContext, scopeId, entityType); - } - - @Override - public void setConfigValues(TxContext txContext, KapuaId scopeId, Optional parentId, Map values) throws KapuaException { - cached.setConfigValues(txContext, scopeId, parentId, values); - } - - @Override - public Map getConfigValues(TxContext txContext, KapuaId scopeId, boolean excludeDisabled) throws KapuaException { - return cached.getConfigValues(txContext, scopeId, excludeDisabled); - } - - @Override - public KapuaTocd getConfigMetadata(TxContext txContext, KapuaId scopeId, boolean excludeDisabled) throws KapuaException { - return cached.getConfigMetadata(txContext, scopeId, excludeDisabled); - } - }; - } } diff --git a/service/security/shiro/src/main/java/org/eclipse/kapua/service/authentication/shiro/CredentialServiceConfigurationManagerImpl.java b/service/security/shiro/src/main/java/org/eclipse/kapua/service/authentication/shiro/CredentialServiceConfigurationManagerImpl.java index 8840fb16928..6ffb8cff5e0 100644 --- a/service/security/shiro/src/main/java/org/eclipse/kapua/service/authentication/shiro/CredentialServiceConfigurationManagerImpl.java +++ b/service/security/shiro/src/main/java/org/eclipse/kapua/service/authentication/shiro/CredentialServiceConfigurationManagerImpl.java @@ -13,34 +13,32 @@ package org.eclipse.kapua.service.authentication.shiro; import java.util.Map; -import java.util.NoSuchElementException; import java.util.Optional; import org.eclipse.kapua.KapuaException; import org.eclipse.kapua.KapuaIllegalArgumentException; import org.eclipse.kapua.commons.configuration.RootUserTester; import org.eclipse.kapua.commons.configuration.ServiceConfigRepository; +import org.eclipse.kapua.commons.configuration.ServiceConfigurationManager; import org.eclipse.kapua.commons.configuration.ServiceConfigurationManagerImpl; import org.eclipse.kapua.commons.util.xml.XmlUtil; import org.eclipse.kapua.model.config.metatype.KapuaTocd; import org.eclipse.kapua.model.id.KapuaId; import org.eclipse.kapua.service.authentication.credential.CredentialService; +import org.eclipse.kapua.service.authentication.credential.shiro.AccountPasswordLengthProviderImpl; import org.eclipse.kapua.service.authentication.shiro.setting.KapuaAuthenticationSetting; -import org.eclipse.kapua.service.authentication.shiro.setting.KapuaAuthenticationSettingKeys; import org.eclipse.kapua.storage.TxContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class CredentialServiceConfigurationManagerImpl extends ServiceConfigurationManagerImpl implements CredentialServiceConfigurationManager { +public class CredentialServiceConfigurationManagerImpl extends ServiceConfigurationManagerImpl implements ServiceConfigurationManager { private static final Logger LOGGER = LoggerFactory.getLogger(CredentialServiceConfigurationManagerImpl.class); - private final int systemMinimumPasswordLength; - public static final int SYSTEM_MAXIMUM_PASSWORD_LENGTH = 255; - public static final String PASSWORD_MIN_LENGTH_ACCOUNT_CONFIG_KEY = "password.minLength"; - private final KapuaAuthenticationSetting kapuaAuthenticationSetting; + private final SystemPasswordLengthProvider systemPasswordLengthProvider; public CredentialServiceConfigurationManagerImpl( ServiceConfigRepository serviceConfigRepository, + SystemPasswordLengthProvider systemPasswordLengthProvider, RootUserTester rootUserTester, KapuaAuthenticationSetting kapuaAuthenticationSetting, XmlUtil xmlUtil) { @@ -48,42 +46,19 @@ public CredentialServiceConfigurationManagerImpl( serviceConfigRepository, rootUserTester, xmlUtil); - this.kapuaAuthenticationSetting = kapuaAuthenticationSetting; - systemMinimumPasswordLength = fixMinimumPasswordLength(); + this.systemPasswordLengthProvider = systemPasswordLengthProvider; } @Override protected boolean validateNewConfigValuesCoherence(TxContext txContext, KapuaTocd ocd, Map updatedProps, KapuaId scopeId, Optional parentId) throws KapuaException { - if (updatedProps.get(PASSWORD_MIN_LENGTH_ACCOUNT_CONFIG_KEY) != null) { + if (updatedProps.get(AccountPasswordLengthProviderImpl.PASSWORD_MIN_LENGTH_ACCOUNT_CONFIG_KEY) != null) { // If we're going to set a new limit, check that it's not less than system limit - int newPasswordLimit = Integer.parseInt(updatedProps.get(PASSWORD_MIN_LENGTH_ACCOUNT_CONFIG_KEY).toString()); - if (newPasswordLimit < systemMinimumPasswordLength || newPasswordLimit > SYSTEM_MAXIMUM_PASSWORD_LENGTH) { - throw new KapuaIllegalArgumentException(PASSWORD_MIN_LENGTH_ACCOUNT_CONFIG_KEY, String.valueOf(newPasswordLimit)); + int newPasswordLimit = Integer.parseInt(updatedProps.get(AccountPasswordLengthProviderImpl.PASSWORD_MIN_LENGTH_ACCOUNT_CONFIG_KEY).toString()); + if (newPasswordLimit < systemPasswordLengthProvider.getSystemMinimumPasswordLength() || newPasswordLimit > systemPasswordLengthProvider.getSystemMaximumPasswordLength()) { + throw new KapuaIllegalArgumentException(AccountPasswordLengthProviderImpl.PASSWORD_MIN_LENGTH_ACCOUNT_CONFIG_KEY, String.valueOf(newPasswordLimit)); } } return true; } - private int fixMinimumPasswordLength() { - final int systemMinimumPasswordLength; - //TODO: Why is this logic in a constructor? - int minPasswordLengthConfigValue; - try { - minPasswordLengthConfigValue = kapuaAuthenticationSetting.getInt(KapuaAuthenticationSettingKeys.AUTHENTICATION_CREDENTIAL_USERPASS_PASSWORD_MINLENGTH); - } catch (NoSuchElementException ex) { - LOGGER.warn("Minimum password length not set, 12 characters minimum will be enforced"); - minPasswordLengthConfigValue = 12; - } - if (minPasswordLengthConfigValue < 12) { - LOGGER.warn("Minimum password length too short, 12 characters minimum will be enforced"); - minPasswordLengthConfigValue = 12; - } - systemMinimumPasswordLength = minPasswordLengthConfigValue; - return systemMinimumPasswordLength; - } - - @Override - public int getSystemMinimumPasswordLength() { - return systemMinimumPasswordLength; - } } \ No newline at end of file diff --git a/service/security/shiro/src/main/java/org/eclipse/kapua/service/authentication/shiro/CredentialServiceConfigurationManagerModule.java b/service/security/shiro/src/main/java/org/eclipse/kapua/service/authentication/shiro/CredentialServiceConfigurationManagerModule.java new file mode 100644 index 00000000000..019ccebd606 --- /dev/null +++ b/service/security/shiro/src/main/java/org/eclipse/kapua/service/authentication/shiro/CredentialServiceConfigurationManagerModule.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * Copyright (c) 2021, 2022 Eurotech and/or its affiliates and others + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Eurotech - initial API and implementation + *******************************************************************************/ +package org.eclipse.kapua.service.authentication.shiro; + +import javax.inject.Singleton; + +import org.eclipse.kapua.commons.configuration.CachingServiceConfigRepository; +import org.eclipse.kapua.commons.configuration.RootUserTester; +import org.eclipse.kapua.commons.configuration.ServiceConfigImplJpaRepository; +import org.eclipse.kapua.commons.configuration.ServiceConfigurationManager; +import org.eclipse.kapua.commons.configuration.ServiceConfigurationManagerCachingWrapper; +import org.eclipse.kapua.commons.core.AbstractKapuaModule; +import org.eclipse.kapua.commons.jpa.EntityCacheFactory; +import org.eclipse.kapua.commons.jpa.KapuaJpaRepositoryConfiguration; +import org.eclipse.kapua.commons.util.xml.XmlUtil; +import org.eclipse.kapua.service.authentication.credential.CredentialService; +import org.eclipse.kapua.service.authentication.shiro.setting.KapuaAuthenticationSetting; + +import com.google.inject.Module; +import com.google.inject.multibindings.ClassMapKey; +import com.google.inject.multibindings.ProvidesIntoMap; + +/** + * This module provides the ServiceConfigurationManager for the CredentialService. + *

+ * Unfortunately Guice does not support overriding for Map binder entries, therefore if you need to change the behaviour of this ServiceConfigurationManager, just skip this module and define the new + * instance in a separate one + */ +public class CredentialServiceConfigurationManagerModule extends AbstractKapuaModule implements Module { + + @Override + protected void configureModule() { + } + + @ProvidesIntoMap + @ClassMapKey(CredentialService.class) + @Singleton + public ServiceConfigurationManager credentialServiceConfigurationManager( + RootUserTester rootUserTester, + SystemPasswordLengthProvider systemPasswordLengthProvider, + KapuaJpaRepositoryConfiguration jpaRepoConfig, + KapuaAuthenticationSetting kapuaAuthenticationSetting, + EntityCacheFactory entityCacheFactory, + XmlUtil xmlUtil) { + return new ServiceConfigurationManagerCachingWrapper( + new CredentialServiceConfigurationManagerImpl( + new CachingServiceConfigRepository( + new ServiceConfigImplJpaRepository(jpaRepoConfig), + entityCacheFactory.createCache("AbstractKapuaConfigurableServiceCacheId") + ), + systemPasswordLengthProvider, + rootUserTester, + kapuaAuthenticationSetting, + xmlUtil)); + } +} diff --git a/service/security/shiro/src/main/java/org/eclipse/kapua/service/authentication/shiro/CredentialServiceConfigurationManager.java b/service/security/shiro/src/main/java/org/eclipse/kapua/service/authentication/shiro/SystemPasswordLengthProvider.java similarity index 66% rename from service/security/shiro/src/main/java/org/eclipse/kapua/service/authentication/shiro/CredentialServiceConfigurationManager.java rename to service/security/shiro/src/main/java/org/eclipse/kapua/service/authentication/shiro/SystemPasswordLengthProvider.java index 6fa65c5ab15..dc46edf513c 100644 --- a/service/security/shiro/src/main/java/org/eclipse/kapua/service/authentication/shiro/CredentialServiceConfigurationManager.java +++ b/service/security/shiro/src/main/java/org/eclipse/kapua/service/authentication/shiro/SystemPasswordLengthProvider.java @@ -12,12 +12,9 @@ *******************************************************************************/ package org.eclipse.kapua.service.authentication.shiro; -import org.eclipse.kapua.commons.configuration.ServiceConfigurationManager; +public interface SystemPasswordLengthProvider { -public interface CredentialServiceConfigurationManager extends ServiceConfigurationManager { - - /** - * The minimum password length specified for the whole system. If not defined, assume 12; if defined and less than 12, assume 12. - */ int getSystemMinimumPasswordLength(); + + int getSystemMaximumPasswordLength(); } diff --git a/service/security/shiro/src/main/java/org/eclipse/kapua/service/authentication/shiro/SystemPasswordLengthProviderImpl.java b/service/security/shiro/src/main/java/org/eclipse/kapua/service/authentication/shiro/SystemPasswordLengthProviderImpl.java new file mode 100644 index 00000000000..373fbc5c305 --- /dev/null +++ b/service/security/shiro/src/main/java/org/eclipse/kapua/service/authentication/shiro/SystemPasswordLengthProviderImpl.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright (c) 2016, 2022 Eurotech and/or its affiliates and others + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Eurotech - initial API and implementation + *******************************************************************************/ +package org.eclipse.kapua.service.authentication.shiro; + +import java.util.NoSuchElementException; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import org.eclipse.kapua.service.authentication.shiro.setting.KapuaAuthenticationSetting; +import org.eclipse.kapua.service.authentication.shiro.setting.KapuaAuthenticationSettingKeys; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@Singleton +public class SystemPasswordLengthProviderImpl implements SystemPasswordLengthProvider { + + private final KapuaAuthenticationSetting kapuaAuthenticationSetting; + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + private static final int SYSTEM_MAXIMUM_PASSWORD_LENGTH = 255; + + @Inject + public SystemPasswordLengthProviderImpl(KapuaAuthenticationSetting kapuaAuthenticationSetting) { + this.kapuaAuthenticationSetting = kapuaAuthenticationSetting; + } + + @Override + /** + * The minimum password length specified for the whole system. If not defined, assume 12; if defined and less than 12, assume 12. + */ + public int getSystemMinimumPasswordLength() { + int minPasswordLengthConfigValue; + try { + minPasswordLengthConfigValue = kapuaAuthenticationSetting.getInt(KapuaAuthenticationSettingKeys.AUTHENTICATION_CREDENTIAL_USERPASS_PASSWORD_MINLENGTH); + } catch (NoSuchElementException ex) { + logger.warn("Minimum password length not set, 12 characters minimum will be enforced"); + minPasswordLengthConfigValue = 12; + } + if (minPasswordLengthConfigValue < 12) { + logger.warn("Minimum password length too short, 12 characters minimum will be enforced"); + minPasswordLengthConfigValue = 12; + } + return minPasswordLengthConfigValue; + } + + @Override + public int getSystemMaximumPasswordLength() { + return SYSTEM_MAXIMUM_PASSWORD_LENGTH; + } +} diff --git a/service/security/test/src/test/java/org/eclipse/kapua/service/security/test/SecurityLocatorConfiguration.java b/service/security/test/src/test/java/org/eclipse/kapua/service/security/test/SecurityLocatorConfiguration.java index 7edc2e64063..6a5a1803b67 100644 --- a/service/security/test/src/test/java/org/eclipse/kapua/service/security/test/SecurityLocatorConfiguration.java +++ b/service/security/test/src/test/java/org/eclipse/kapua/service/security/test/SecurityLocatorConfiguration.java @@ -41,6 +41,7 @@ import org.eclipse.kapua.qa.common.TestJAXBContextProvider; import org.eclipse.kapua.service.authentication.credential.CredentialFactory; import org.eclipse.kapua.service.authentication.credential.CredentialService; +import org.eclipse.kapua.service.authentication.credential.shiro.AccountPasswordLengthProviderImpl; import org.eclipse.kapua.service.authentication.credential.shiro.CredentialFactoryImpl; import org.eclipse.kapua.service.authentication.credential.shiro.CredentialImplJpaRepository; import org.eclipse.kapua.service.authentication.credential.shiro.CredentialMapperImpl; @@ -50,6 +51,7 @@ import org.eclipse.kapua.service.authentication.exception.KapuaAuthenticationErrorCodes; import org.eclipse.kapua.service.authentication.mfa.MfaAuthenticator; import org.eclipse.kapua.service.authentication.shiro.CredentialServiceConfigurationManagerImpl; +import org.eclipse.kapua.service.authentication.shiro.SystemPasswordLengthProviderImpl; import org.eclipse.kapua.service.authentication.shiro.mfa.MfaAuthenticatorImpl; import org.eclipse.kapua.service.authentication.shiro.setting.KapuaAuthenticationSetting; import org.eclipse.kapua.service.authentication.shiro.setting.KapuaCryptoSetting; @@ -165,11 +167,15 @@ protected void configure() { bind(GroupFactory.class).toInstance(new GroupFactoryImpl()); final CredentialFactoryImpl credentialFactory = new CredentialFactoryImpl(); bind(CredentialFactory.class).toInstance(credentialFactory); + final SystemPasswordLengthProviderImpl systemMinimumPasswordLengthProvider = new SystemPasswordLengthProviderImpl(new KapuaAuthenticationSetting()); final CredentialServiceConfigurationManagerImpl credentialServiceConfigurationManager = new CredentialServiceConfigurationManagerImpl( new ServiceConfigImplJpaRepository(jpaRepoConfig), + systemMinimumPasswordLengthProvider, Mockito.mock(RootUserTester.class), new KapuaAuthenticationSetting(), new XmlUtil(new TestJAXBContextProvider())); + final AccountPasswordLengthProviderImpl accountPasswordLengthProvider = new AccountPasswordLengthProviderImpl(systemMinimumPasswordLengthProvider, + credentialServiceConfigurationManager); try { bind(CredentialService.class).toInstance(new CredentialServiceImpl( credentialServiceConfigurationManager, @@ -179,11 +185,12 @@ protected void configure() { new CredentialImplJpaRepository(jpaRepoConfig), credentialFactory, new CredentialMapperImpl(credentialFactory, new KapuaAuthenticationSetting(), new AuthenticationUtils(SecureRandom.getInstance("SHA1PRNG"), new KapuaCryptoSetting())), - new PasswordValidatorImpl(credentialServiceConfigurationManager), new KapuaAuthenticationSetting(), + new PasswordValidatorImpl(accountPasswordLengthProvider), new KapuaAuthenticationSetting(), + accountPasswordLengthProvider, new PasswordResetterImpl(credentialFactory, new CredentialImplJpaRepository(new KapuaJpaRepositoryConfiguration()), new CredentialMapperImpl(credentialFactory, new KapuaAuthenticationSetting(), authenticationUtils(new KapuaCryptoSetting())), - new PasswordValidatorImpl(credentialServiceConfigurationManager)))); + new PasswordValidatorImpl(accountPasswordLengthProvider)))); } catch (NoSuchAlgorithmException e) { throw new RuntimeException(e); } diff --git a/service/user/test/src/test/java/org/eclipse/kapua/service/user/test/UserLocatorConfiguration.java b/service/user/test/src/test/java/org/eclipse/kapua/service/user/test/UserLocatorConfiguration.java index b2d0d2f95f3..01ced94dd45 100644 --- a/service/user/test/src/test/java/org/eclipse/kapua/service/user/test/UserLocatorConfiguration.java +++ b/service/user/test/src/test/java/org/eclipse/kapua/service/user/test/UserLocatorConfiguration.java @@ -117,7 +117,8 @@ protected void configure() { bind(RootUserTester.class).toInstance(mockRootUserTester); final UserRepository userRepository = Mockito.mock(UserRepository.class); final KapuaJpaRepositoryConfiguration jpaRepoConfig = new KapuaJpaRepositoryConfiguration(); - final ResourceLimitedServiceConfigurationManagerImpl userConfigurationManager = new ResourceLimitedServiceConfigurationManagerImpl(UserService.class.getName(), + final ResourceLimitedServiceConfigurationManagerImpl userConfigurationManager = new ResourceLimitedServiceConfigurationManagerImpl( + UserService.class.getName(), new ServiceConfigImplJpaRepository(jpaRepoConfig), Mockito.mock(RootUserTester.class), accountRelativeFinder,