bug6099: interims commit with a first implementation of a user account locking/banning mechanism;

yet missing is writing to persistence and replication
This commit is contained in:
Axel Uhl
2025-03-17 16:30:57 +01:00
parent c542e0d85d
commit 2416b49f89
44 changed files with 278 additions and 63 deletions
@@ -34,6 +34,7 @@ import com.sap.sse.security.shared.UserManagementException;
import com.sap.sse.security.shared.UserRole;
import com.sap.sse.security.shared.UserStoreManagementException;
import com.sap.sse.security.shared.WildcardPermission;
import com.sap.sse.security.shared.impl.LockingAndBanning;
import com.sap.sse.security.shared.impl.Ownership;
import com.sap.sse.security.shared.impl.Role;
import com.sap.sse.security.shared.impl.User;
@@ -853,12 +854,12 @@ public class UserStoreImpl implements UserStore {
}
@Override
public User createUser(String name, String email, Account... accounts)
public User createUser(String name, String email, LockingAndBanning lockingAndBanning, Account... accounts)
throws UserManagementException {
return LockUtil.executeWithWriteLockAndResultExpectException(usersLock, () -> {
checkUsernameUniqueness(name);
final Map<String, UserGroup> tenantsForServer = new ConcurrentHashMap<>();
final User user = new UserImpl(name, email, tenantsForServer, /* user group provider */ this, accounts);
final User user = new UserImpl(name, email, tenantsForServer, /* user group provider */ this, lockingAndBanning, accounts);
logger.info("Creating user: " + user + " with e-mail " + email);
addAndStoreUserInternal(user);
return user;
@@ -18,6 +18,8 @@ import org.bson.types.Binary;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import com.sap.sse.common.Duration;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.Util;
import com.sap.sse.security.interfaces.Social;
import com.sap.sse.security.interfaces.UserImpl;
@@ -35,6 +37,8 @@ import com.sap.sse.security.shared.UserManagementException;
import com.sap.sse.security.shared.UsernamePasswordAccount;
import com.sap.sse.security.shared.WildcardPermission;
import com.sap.sse.security.shared.impl.AccessControlList;
import com.sap.sse.security.shared.impl.LockingAndBanning;
import com.sap.sse.security.shared.impl.LockingAndBanningImpl;
import com.sap.sse.security.shared.impl.Ownership;
import com.sap.sse.security.shared.impl.QualifiedObjectIdentifierImpl;
import com.sap.sse.security.shared.impl.Role;
@@ -280,12 +284,17 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
final String company = (String) userDBObject.get(FieldNames.User.COMPANY.name());
final String localeRaw = (String) userDBObject.get(FieldNames.User.LOCALE.name());
final Locale locale = localeRaw != null ? Locale.forLanguageTag(localeRaw) : null;
Boolean emailValidated = (Boolean) userDBObject.get(FieldNames.User.EMAIL_VALIDATED.name());
String passwordResetSecret = (String) userDBObject.get(FieldNames.User.PASSWORD_RESET_SECRET.name());
String validationSecret = (String) userDBObject.get(FieldNames.User.VALIDATION_SECRET.name());
Set<Role> roles = new HashSet<>();
Set<String> permissions = new HashSet<>();
List<?> rolesO = (List<?>) userDBObject.get(FieldNames.User.ROLE_IDS.name());
final Boolean emailValidated = (Boolean) userDBObject.get(FieldNames.User.EMAIL_VALIDATED.name());
final String passwordResetSecret = (String) userDBObject.get(FieldNames.User.PASSWORD_RESET_SECRET.name());
final String validationSecret = (String) userDBObject.get(FieldNames.User.VALIDATION_SECRET.name());
final Long lockedUntilMillis = userDBObject.getLong(FieldNames.User.LOCKED_UNTIL_MILLIS.name());
final Long nextLockingDurationMillis = userDBObject.getLong(FieldNames.User.LOCKED_UNTIL_MILLIS.name());
final LockingAndBanning lockingAndBanning = new LockingAndBanningImpl(
lockedUntilMillis == null ? TimePoint.BeginningOfTime : TimePoint.of(lockedUntilMillis),
nextLockingDurationMillis == null ? LockingAndBanningImpl.DEFAULT_INITIAL_LOCKING_DELAY : Duration.ofMillis(nextLockingDurationMillis));
final Set<Role> roles = new HashSet<>();
final Set<String> permissions = new HashSet<>();
final List<?> rolesO = (List<?>) userDBObject.get(FieldNames.User.ROLE_IDS.name());
boolean rolesMigrated = false; // if a role needs migration, user needs an update in the DB
if (rolesO != null) {
for (Object o : rolesO) {
@@ -349,7 +358,7 @@ public class DomainObjectFactoryImpl implements DomainObjectFactory {
Map<AccountType, Account> accounts = createAccountMapFromdDBObject(accountsMap);
User result = new UserImpl(username, email, fullName, company, locale,
emailValidated == null ? false : emailValidated, passwordResetSecret, validationSecret, defaultTenant,
accounts.values(), userGroupProvider);
accounts.values(), userGroupProvider, lockingAndBanning);
for (final Role role : roles) {
result.addRole(role);
}
@@ -57,7 +57,9 @@ public class FieldNames {
VALIDATION_SECRET,
DEFAULT_TENANT_SERVER,
DEFAULT_TENANT_GROUP,
SUBSCRIPTIONS;
SUBSCRIPTIONS,
LOCKED_UNTIL_MILLIS,
NEXT_LOCKING_DURATION_MILLIS;
}
public static enum Settings {
@@ -10,6 +10,7 @@ import com.sap.sse.security.shared.HasPermissions;
import com.sap.sse.security.shared.QualifiedObjectIdentifier;
import com.sap.sse.security.shared.UserGroupProvider;
import com.sap.sse.security.shared.WildcardPermission;
import com.sap.sse.security.shared.impl.LockingAndBanning;
import com.sap.sse.security.shared.impl.Role;
import com.sap.sse.security.shared.impl.User;
import com.sap.sse.security.shared.impl.UserGroup;
@@ -239,4 +240,9 @@ public class UserProxy implements User {
public boolean hasActiveSubscription(String planId) {
throw new UnsupportedOperationException();
}
@Override
public LockingAndBanning getLockingAndBanning() {
throw new UnsupportedOperationException();
}
}