Skip to content

Commit

Permalink
🎨 fixing the mess about password length resolution
Browse files Browse the repository at this point in the history
Signed-off-by: dseurotech <[email protected]>
  • Loading branch information
dseurotech committed Jul 12, 2024
1 parent 72c8f63 commit 90927fa
Show file tree
Hide file tree
Showing 12 changed files with 299 additions and 172 deletions.
Original file line number Diff line number Diff line change
@@ -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;
}
Original file line number Diff line number Diff line change
@@ -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<String, Object> getConfigValues(TxContext tx, KapuaId scopeId) throws KapuaException {
return credentialServiceConfigurationManager.getConfigValues(tx, scopeId, true);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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.
*
Expand All @@ -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,
Expand All @@ -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");
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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<String, Object> getConfigValues(TxContext tx, KapuaId scopeId) throws KapuaException {
return credentialServiceConfigurationManager.getConfigValues(tx, scopeId, true);
}
}
Loading

0 comments on commit 90927fa

Please sign in to comment.