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
@@ -26,6 +26,8 @@ securityManager.subjectDAO = $subjectDAO
securityManager.sessionManager.globalSessionTimeout = 31536000000
cacheManager = com.sap.sse.security.SessionCacheManager
securityManager.cacheManager = $cacheManager
authenticationStrategy = com.sap.sse.security.AtLeastOneSuccessfulStrategyWithLockingAndBanning
securityManager.authenticator.authenticationStrategy = $authenticationStrategy
# Support for anonymous user permissions
webSubjectFactoryWithAnonymousPrincipalSupport=com.sap.sse.security.WebSubjectFactoryWithAnonymousPrincipalSupport
@@ -22,6 +22,8 @@ securityManager.sessionManager.sessionDAO = $sessionDAO
securityManager.sessionManager.globalSessionTimeout = 31536000000
cacheManager = com.sap.sse.security.SessionCacheManager
securityManager.cacheManager = $cacheManager
authenticationStrategy = com.sap.sse.security.AtLeastOneSuccessfulStrategyWithLockingAndBanning
securityManager.authenticator.authenticationStrategy = $authenticationStrategy
subjectDAO = com.sap.sse.security.NoSessionStorageForUnauthenticatedSessionsSessionDAO
securityManager.subjectDAO = $subjectDAO
@@ -26,6 +26,8 @@ securityManager.subjectDAO = $subjectDAO
securityManager.sessionManager.globalSessionTimeout = 31536000000
cacheManager = com.sap.sse.security.SessionCacheManager
securityManager.cacheManager = $cacheManager
authenticationStrategy = com.sap.sse.security.AtLeastOneSuccessfulStrategyWithLockingAndBanning
securityManager.authenticator.authenticationStrategy = $authenticationStrategy
# Support for anonymous user permissions
webSubjectFactoryWithAnonymousPrincipalSupport=com.sap.sse.security.WebSubjectFactoryWithAnonymousPrincipalSupport
@@ -51,6 +51,7 @@ import com.sap.sse.security.SecurityService;
import com.sap.sse.security.interfaces.UserStore;
import com.sap.sse.security.shared.UserGroupManagementException;
import com.sap.sse.security.shared.UserManagementException;
import com.sap.sse.security.shared.impl.LockingAndBanningImpl;
import com.sap.sse.security.shared.impl.User;
import com.sap.sse.security.shared.impl.UserGroup;
import com.sap.sse.security.userstore.mongodb.UserStoreImpl;
@@ -110,7 +111,7 @@ public class OfflineSerializationTest extends AbstractSerializationTest {
UserStore userStore = new UserStoreImpl("defaultTenant");
userStore.clear();
UserGroup defaultTenant = userStore.createUserGroup(UUID.randomUUID(), "admin"+SecurityService.TENANT_SUFFIX);
User user = userStore.createUser("admin", "");
User user = userStore.createUser("admin", "", new LockingAndBanningImpl());
defaultTenant.add(user);
userStore.updateUserGroup(defaultTenant);
user.getDefaultTenantMap().put("testserver", defaultTenant);
@@ -22,6 +22,8 @@ securityManager.sessionManager.sessionDAO = $sessionDAO
securityManager.sessionManager.globalSessionTimeout = 31536000000
cacheManager = com.sap.sse.security.SessionCacheManager
securityManager.cacheManager = $cacheManager
authenticationStrategy = com.sap.sse.security.AtLeastOneSuccessfulStrategyWithLockingAndBanning
securityManager.authenticator.authenticationStrategy = $authenticationStrategy
subjectDAO = com.sap.sse.security.NoSessionStorageForUnauthenticatedSessionsSessionDAO
securityManager.subjectDAO = $subjectDAO
@@ -26,6 +26,8 @@ securityManager.subjectDAO = $subjectDAO
securityManager.sessionManager.globalSessionTimeout = 31536000000
cacheManager = com.sap.sse.security.SessionCacheManager
securityManager.cacheManager = $cacheManager
authenticationStrategy = com.sap.sse.security.AtLeastOneSuccessfulStrategyWithLockingAndBanning
securityManager.authenticator.authenticationStrategy = $authenticationStrategy
# Support for anonymous user permissions
webSubjectFactoryWithAnonymousPrincipalSupport=com.sap.sse.security.WebSubjectFactoryWithAnonymousPrincipalSupport
@@ -26,6 +26,8 @@ securityManager.subjectDAO = $subjectDAO
securityManager.sessionManager.globalSessionTimeout = 31536000000
cacheManager = com.sap.sse.security.SessionCacheManager
securityManager.cacheManager = $cacheManager
authenticationStrategy = com.sap.sse.security.AtLeastOneSuccessfulStrategyWithLockingAndBanning
securityManager.authenticator.authenticationStrategy = $authenticationStrategy
# Support for anonymous user permissions
webSubjectFactoryWithAnonymousPrincipalSupport=com.sap.sse.security.WebSubjectFactoryWithAnonymousPrincipalSupport
@@ -24,6 +24,8 @@ securityManager.sessionManager.sessionDAO = $sessionDAO
securityManager.sessionManager.globalSessionTimeout = 31536000000
cacheManager = com.sap.sse.security.SessionCacheManager
securityManager.cacheManager = $cacheManager
authenticationStrategy = com.sap.sse.security.AtLeastOneSuccessfulStrategyWithLockingAndBanning
securityManager.authenticator.authenticationStrategy = $authenticationStrategy
subjectDAO = com.sap.sse.security.NoSessionStorageForUnauthenticatedSessionsSessionDAO
securityManager.subjectDAO = $subjectDAO
@@ -26,6 +26,8 @@ securityManager.subjectDAO = $subjectDAO
securityManager.sessionManager.globalSessionTimeout = 31536000000
cacheManager = com.sap.sse.security.SessionCacheManager
securityManager.cacheManager = $cacheManager
authenticationStrategy = com.sap.sse.security.AtLeastOneSuccessfulStrategyWithLockingAndBanning
securityManager.authenticator.authenticationStrategy = $authenticationStrategy
# Support for anonymous user permissions
webSubjectFactoryWithAnonymousPrincipalSupport=com.sap.sse.security.WebSubjectFactoryWithAnonymousPrincipalSupport
@@ -32,6 +32,8 @@ securityManager.sessionManager.sessionDAO = $sessionDAO
securityManager.sessionManager.globalSessionTimeout = 31536000000
cacheManager = com.sap.sse.security.SessionCacheManager
securityManager.cacheManager = $cacheManager
authenticationStrategy = com.sap.sse.security.AtLeastOneSuccessfulStrategyWithLockingAndBanning
securityManager.authenticator.authenticationStrategy = $authenticationStrategy
# Authentication Filter Configurations
# ------------------------------------
@@ -53,6 +53,7 @@ import com.sap.sse.rest.StreamingOutputUtil;
import com.sap.sse.security.SecurityService;
import com.sap.sse.security.interfaces.UserImpl;
import com.sap.sse.security.shared.Account;
import com.sap.sse.security.shared.impl.LockingAndBanningImpl;
import com.sap.sse.security.shared.impl.User;
public class RegattasResourceTest extends AbstractJaxRsApiTest {
@@ -159,7 +160,7 @@ public class RegattasResourceTest extends AbstractJaxRsApiTest {
public void testCompetitorRegistrationByAdmin() throws Exception {
doReturn(securityService).when(regattasResource).getService(SecurityService.class);
doReturn(true).when(securityService).hasCurrentUserUpdatePermission(Mockito.any());
User user = new UserImpl("admin", "noreply@sapsailing.com", null, new ArrayList<Account>(0), null);
User user = new UserImpl("admin", "noreply@sapsailing.com", null, new ArrayList<Account>(0), null, new LockingAndBanningImpl());
setUser(user);
when(securityService.getCurrentUser()).thenReturn(user);
Response response = regattasResource.createAndAddCompetitor(closedRegattaName, boatClassName, null, "GER",
@@ -217,7 +218,7 @@ public class RegattasResourceTest extends AbstractJaxRsApiTest {
@Test
public void testCompetitorRegistrationAuthenticatedOnOpenRegatta() throws Exception {
doReturn(securityService).when(regattasResource).getService(SecurityService.class);
User user = new UserImpl("max", "noreply@sapsailing.com", null, new ArrayList<Account>(0), null);
User user = new UserImpl("max", "noreply@sapsailing.com", null, new ArrayList<Account>(0), null, new LockingAndBanningImpl());
setUser(user);
Regatta regatta = racingEventService.getRegattaByName(openRegattaName);
Response response = regattasResource.createAndAddCompetitor(openRegattaName, boatClassName, null, "GER", "#F00",
@@ -26,6 +26,8 @@ securityManager.subjectDAO = $subjectDAO
securityManager.sessionManager.globalSessionTimeout = 31536000000
cacheManager = com.sap.sse.security.SessionCacheManager
securityManager.cacheManager = $cacheManager
authenticationStrategy = com.sap.sse.security.AtLeastOneSuccessfulStrategyWithLockingAndBanning
securityManager.authenticator.authenticationStrategy = $authenticationStrategy
# Support for anonymous user permissions
webSubjectFactoryWithAnonymousPrincipalSupport=com.sap.sse.security.WebSubjectFactoryWithAnonymousPrincipalSupport
@@ -1,9 +1,9 @@
package com.sap.sailing.server.replication.test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotSame;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
@@ -65,6 +65,7 @@ import com.sap.sse.replication.FullyInitializedReplicableTracker;
import com.sap.sse.security.SecurityService;
import com.sap.sse.security.interfaces.UserImpl;
import com.sap.sse.security.shared.WithQualifiedObjectIdentifier;
import com.sap.sse.security.shared.impl.LockingAndBanningImpl;
import com.sap.sse.security.shared.impl.SecuredSecurityTypes.PublicReadableActions;
import com.sap.sse.security.shared.impl.SecuredSecurityTypes.ServerActions;
import com.sap.sse.security.shared.impl.User;
@@ -254,7 +255,7 @@ public class MediaReplicationTest extends AbstractServerReplicationTest {
public void testMasterDataImportForMediaTracks() throws MalformedURLException, IOException, InterruptedException,
ClassNotFoundException {
UserGroupImpl defaultTenant = new UserGroupImpl(new UUID(0, 1), "defaultTenant");
User currentUser = new UserImpl("test", "email@test", Collections.emptyMap(), null);
User currentUser = new UserImpl("test", "email@test", Collections.emptyMap(), null, new LockingAndBanningImpl());
SecurityService securityService = Mockito.mock(SecurityService.class);
Mockito.doReturn(defaultTenant).when(securityService).getServerGroup();
Mockito.doReturn(currentUser).when(securityService).getCurrentUser();
@@ -26,6 +26,8 @@ securityManager.subjectDAO = $subjectDAO
securityManager.sessionManager.globalSessionTimeout = 31536000000
cacheManager = com.sap.sse.security.SessionCacheManager
securityManager.cacheManager = $cacheManager
authenticationStrategy = com.sap.sse.security.AtLeastOneSuccessfulStrategyWithLockingAndBanning
securityManager.authenticator.authenticationStrategy = $authenticationStrategy
# Support for anonymous user permissions
webSubjectFactoryWithAnonymousPrincipalSupport=com.sap.sse.security.WebSubjectFactoryWithAnonymousPrincipalSupport
@@ -26,6 +26,8 @@ securityManager.subjectDAO = $subjectDAO
securityManager.sessionManager.globalSessionTimeout = 31536000000
cacheManager = com.sap.sse.security.SessionCacheManager
securityManager.cacheManager = $cacheManager
authenticationStrategy = com.sap.sse.security.AtLeastOneSuccessfulStrategyWithLockingAndBanning
securityManager.authenticator.authenticationStrategy = $authenticationStrategy
# Support for anonymous user permissions
webSubjectFactoryWithAnonymousPrincipalSupport=com.sap.sse.security.WebSubjectFactoryWithAnonymousPrincipalSupport
@@ -26,6 +26,8 @@ securityManager.subjectDAO = $subjectDAO
securityManager.sessionManager.globalSessionTimeout = 31536000000
cacheManager = com.sap.sse.security.SessionCacheManager
securityManager.cacheManager = $cacheManager
authenticationStrategy = com.sap.sse.security.AtLeastOneSuccessfulStrategyWithLockingAndBanning
securityManager.authenticator.authenticationStrategy = $authenticationStrategy
# Support for anonymous user permissions
webSubjectFactoryWithAnonymousPrincipalSupport=com.sap.sse.security.WebSubjectFactoryWithAnonymousPrincipalSupport
@@ -26,6 +26,8 @@ securityManager.subjectDAO = $subjectDAO
securityManager.sessionManager.globalSessionTimeout = 31536000000
cacheManager = com.sap.sse.security.SessionCacheManager
securityManager.cacheManager = $cacheManager
authenticationStrategy = com.sap.sse.security.AtLeastOneSuccessfulStrategyWithLockingAndBanning
securityManager.authenticator.authenticationStrategy = $authenticationStrategy
# Support for anonymous user permissions
webSubjectFactoryWithAnonymousPrincipalSupport=com.sap.sse.security.WebSubjectFactoryWithAnonymousPrincipalSupport
@@ -26,6 +26,8 @@ securityManager.subjectDAO = $subjectDAO
securityManager.sessionManager.globalSessionTimeout = 31536000000
cacheManager = com.sap.sse.security.SessionCacheManager
securityManager.cacheManager = $cacheManager
authenticationStrategy = com.sap.sse.security.AtLeastOneSuccessfulStrategyWithLockingAndBanning
securityManager.authenticator.authenticationStrategy = $authenticationStrategy
# Support for anonymous user permissions
webSubjectFactoryWithAnonymousPrincipalSupport=com.sap.sse.security.WebSubjectFactoryWithAnonymousPrincipalSupport
@@ -6,6 +6,7 @@ import java.util.UUID;
import com.sap.sse.common.Named;
import com.sap.sse.common.Util.Pair;
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.SecuredSecurityTypes;
@@ -59,7 +60,7 @@ public interface BasicUserStore extends UserGroupProvider, Named {
User getUserByAccessToken(String accessToken);
User createUser(String name, String email, Account... accounts)
User createUser(String name, String email, LockingAndBanning lockingAndBanning, Account... accounts)
throws UserManagementException;
void addUser(User user) throws UserManagementException;
@@ -0,0 +1,26 @@
package com.sap.sse.security.shared.impl;
import java.io.Serializable;
/**
* Holds information about a user's log-on history which is then used to decide whether the user account should be
* locked temporarily or permanently for certain forms of authentication.
* <p>
*
* For example, failed password authentication requests shall be logged by the realm using calls to
* {@link #failedPasswordAuthentication()}, successful ones with {@link #successfulPasswordAuthentication()}. Using the
* {@link #isPasswordAuthenticationLocked()} method, a realm can determine if the user account to which this object
* belongs shall currently accept password authentication.
* <p>
*
* A possible strategy for an implementation could be to add an increasing delay for each failed password
* authentication, but reduce or clear the delay after a successful password authentication.
*
* @author Axel Uhl (d043530)
*
*/
public interface LockingAndBanning extends Serializable {
void failedPasswordAuthentication();
void successfulPasswordAuthentication();
boolean isPasswordAuthenticationLocked();
}
@@ -0,0 +1,63 @@
package com.sap.sse.security.shared.impl;
import com.sap.sse.common.Duration;
import com.sap.sse.common.TimePoint;
public class LockingAndBanningImpl implements LockingAndBanning {
private static final long serialVersionUID = 3547356744366236677L;
public static final Duration DEFAULT_INITIAL_LOCKING_DELAY = Duration.ONE_SECOND;
/**
* An always valid time point which may be in the past. If it is in the future,
* {@link #isPasswordAuthenticationLocked()} will return {@code true}.
*/
private TimePoint lockedUntil;
/**
* An always valid, non-zero duration that indicates for how long into the future the {@link #lockedUntil} time
* point will be set in case a {@link #failedPasswordAuthentication() failed password authentication} is notified.
*/
private Duration nextLockingDelay;
/**
* Creates an instance that is unlocked and has a "last locking delay" of one second
*/
public LockingAndBanningImpl() {
this(TimePoint.BeginningOfTime, DEFAULT_INITIAL_LOCKING_DELAY);
}
public LockingAndBanningImpl(TimePoint lockedUntil, Duration nextLockingDelay) {
super();
this.lockedUntil = lockedUntil;
this.nextLockingDelay = nextLockingDelay;
}
/**
* Locks for the {@link #nextLockingDelay} and doubles the delay for the next failed attempt.
*/
@Override
public void failedPasswordAuthentication() {
lockedUntil = TimePoint.now().plus(nextLockingDelay);
nextLockingDelay = nextLockingDelay.times(2);
}
@Override
public void successfulPasswordAuthentication() {
nextLockingDelay = DEFAULT_INITIAL_LOCKING_DELAY;
lockedUntil = TimePoint.BeginningOfTime;
}
@Override
public boolean isPasswordAuthenticationLocked() {
return TimePoint.now().before(lockedUntil);
}
public TimePoint getLockedUntil() {
return lockedUntil;
}
public Duration getLastLockingDelay() {
return nextLockingDelay;
}
}
@@ -7,11 +7,11 @@ import com.sap.sse.common.Named;
import com.sap.sse.common.WithID;
import com.sap.sse.security.shared.Account;
import com.sap.sse.security.shared.Account.AccountType;
import com.sap.sse.security.shared.subscription.Subscription;
import com.sap.sse.security.shared.RoleDefinition;
import com.sap.sse.security.shared.SecurityUser;
import com.sap.sse.security.shared.UserGroupProvider;
import com.sap.sse.security.shared.WildcardPermission;
import com.sap.sse.security.shared.subscription.Subscription;
/**
* The {@link Named#getName() name} is the ID for this user; usually a nickname or short name. Implements the
@@ -124,4 +124,6 @@ public interface User extends SecurityUser<RoleDefinition, Role, UserGroup> {
Subscription getSubscriptionByPlan(String planId);
Subscription getSubscriptionById(String subscriptionId);
LockingAndBanning getLockingAndBanning();
}
@@ -24,6 +24,7 @@ import com.sap.sse.security.shared.Account.AccountType;
import com.sap.sse.security.shared.RoleDefinition;
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.Ownership;
import com.sap.sse.security.shared.impl.Role;
import com.sap.sse.security.shared.impl.SecurityUserImpl;
@@ -99,23 +100,26 @@ public class UserImpl extends SecurityUserImpl<RoleDefinition, Role, UserGroup,
private List<Role> roleListForSerialization;
private Subscription[] subscriptions;
private final LockingAndBanning lockingAndBanning;
public UserImpl(String name, String email, Map<String, UserGroup> defaultTenantForServer,
UserGroupProvider userGroupProvider, Account... accounts) {
this(name, email, defaultTenantForServer, Arrays.asList(accounts), userGroupProvider);
UserGroupProvider userGroupProvider, LockingAndBanning lockingAndBanning, Account... accounts) {
this(name, email, defaultTenantForServer, Arrays.asList(accounts), userGroupProvider, lockingAndBanning);
}
public UserImpl(String name, String email, Map<String, UserGroup> defaultTenantForServer,
Collection<Account> accounts, UserGroupProvider userGroupProvider) {
Collection<Account> accounts, UserGroupProvider userGroupProvider, LockingAndBanning lockingAndBanning) {
this(name, email, /* fullName */ null, /* company */ null, /* locale */ null, /* is email validated */ false,
/* password reset secret */ null, /* validation secret */ null, defaultTenantForServer, accounts,
userGroupProvider);
userGroupProvider, lockingAndBanning);
}
public UserImpl(String name, String email, String fullName, String company, Locale locale, Boolean emailValidated,
String passwordResetSecret, String validationSecret, Map<String, UserGroup> defaultTenantForServer,
Collection<Account> accounts, UserGroupProvider userGroupProvider) {
Collection<Account> accounts, UserGroupProvider userGroupProvider, LockingAndBanning lockingAndBanning) {
super(name);
this.lockingAndBanning = lockingAndBanning;
this.defaultTenantForServer = defaultTenantForServer;
this.fullName = fullName;
this.company = company;
@@ -463,4 +467,9 @@ public class UserImpl extends SecurityUserImpl<RoleDefinition, Role, UserGroup,
}
return false;
}
@Override
public LockingAndBanning getLockingAndBanning() {
return lockingAndBanning;
}
}
@@ -12,6 +12,7 @@ import org.junit.Test;
import com.sap.sse.security.SecurityService;
import com.sap.sse.security.interfaces.UserImpl;
import com.sap.sse.security.shared.impl.LockingAndBanningImpl;
import com.sap.sse.security.shared.impl.User;
import com.sap.sse.security.shared.impl.UserGroup;
import com.sap.sse.security.shared.impl.UserGroupImpl;
@@ -50,7 +51,7 @@ public class TestGroupIdentity {
final UUID uuid2 = UUID.randomUUID();
final String username = "user";
final UserGroup g1 = new UserGroupImpl(uuid1, username+SecurityService.TENANT_SUFFIX);
final User user = new UserImpl(username, /* email */ null, (Map<String, UserGroup>) /* defaultTenantForServer */ null, /* userGroupProvider */ null);
final User user = new UserImpl(username, /* email */ null, (Map<String, UserGroup>) /* defaultTenantForServer */ null, /* userGroupProvider */ null, new LockingAndBanningImpl());
g1.add(user);
final UserGroup g2 = new UserGroupImpl(uuid2, username+SecurityService.TENANT_SUFFIX);
assertFalse(SecurityStoreMerger.considerGroupsIdentical(g1, g2, Collections.emptyMap()));
@@ -62,10 +63,10 @@ public class TestGroupIdentity {
final UUID uuid2 = UUID.randomUUID();
final String username = "user";
final UserGroup g1 = new UserGroupImpl(uuid1, username+SecurityService.TENANT_SUFFIX);
final User user1 = new UserImpl(username, /* email */ null, (Map<String, UserGroup>) /* defaultTenantForServer */ null, /* userGroupProvider */ null);
final User user1 = new UserImpl(username, /* email */ null, (Map<String, UserGroup>) /* defaultTenantForServer */ null, /* userGroupProvider */ null, new LockingAndBanningImpl());
g1.add(user1);
final UserGroup g2 = new UserGroupImpl(uuid2, username+SecurityService.TENANT_SUFFIX);
final User user2 = new UserImpl(username, /* email */ null, (Map<String, UserGroup>) /* defaultTenantForServer */ null, /* userGroupProvider */ null);
final User user2 = new UserImpl(username, /* email */ null, (Map<String, UserGroup>) /* defaultTenantForServer */ null, /* userGroupProvider */ null, new LockingAndBanningImpl());
g2.add(user2);
final Map<User, User> userMap = new HashMap<>();
userMap.put(user2, user1); // user2 assumed to get merged with user1
@@ -23,12 +23,13 @@ import com.sap.sse.mongodb.MongoDBService;
import com.sap.sse.security.interfaces.AccessControlStore;
import com.sap.sse.security.interfaces.UserImpl;
import com.sap.sse.security.interfaces.UserStore;
import com.sap.sse.security.shared.UserStoreManagementException;
import com.sap.sse.security.shared.QualifiedObjectIdentifier;
import com.sap.sse.security.shared.RoleDefinition;
import com.sap.sse.security.shared.TypeRelativeObjectIdentifier;
import com.sap.sse.security.shared.UserGroupManagementException;
import com.sap.sse.security.shared.UserStoreManagementException;
import com.sap.sse.security.shared.WildcardPermission;
import com.sap.sse.security.shared.impl.LockingAndBanningImpl;
import com.sap.sse.security.shared.impl.QualifiedObjectIdentifierImpl;
import com.sap.sse.security.shared.impl.User;
import com.sap.sse.security.shared.impl.UserGroup;
@@ -68,7 +69,7 @@ public class AccessControlStoreTest {
Map<String, UserGroup> defaultTenantForUser = new HashMap<>();
defaultTenantForUser.put("dummyServer", adminTenant);
testOwner = new UserImpl("admin", "admin@sapsailing.com", defaultTenantForUser,
/* userGroupProvider */ null);
/* userGroupProvider */ null, new LockingAndBanningImpl());
}
private void newStores() {
@@ -1,12 +1,12 @@
package com.sap.sse.security.test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.hamcrest.MatcherAssert.assertThat;
import java.net.UnknownHostException;
import java.util.Arrays;
@@ -34,16 +34,17 @@ import com.sap.sse.security.impl.SecurityServiceImpl;
import com.sap.sse.security.interfaces.AccessControlStore;
import com.sap.sse.security.shared.AdminRole;
import com.sap.sse.security.shared.HasPermissions;
import com.sap.sse.security.shared.UserStoreManagementException;
import com.sap.sse.security.shared.PermissionChecker;
import com.sap.sse.security.shared.QualifiedObjectIdentifier;
import com.sap.sse.security.shared.RoleDefinition;
import com.sap.sse.security.shared.TypeRelativeObjectIdentifier;
import com.sap.sse.security.shared.UserGroupManagementException;
import com.sap.sse.security.shared.UserManagementException;
import com.sap.sse.security.shared.UserStoreManagementException;
import com.sap.sse.security.shared.WildcardPermission;
import com.sap.sse.security.shared.WithQualifiedObjectIdentifier;
import com.sap.sse.security.shared.impl.AccessControlList;
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;
@@ -241,7 +242,7 @@ public class LoginTest {
@Test
public void rolesTest() throws UserStoreManagementException {
userStore.createUser("me", "me@sap.com");
userStore.createUser("me", "me@sap.com", new LockingAndBanningImpl());
RoleDefinition testRoleDefinition = userStore.createRoleDefinition(UUID.randomUUID(), "testRole",
Collections.emptySet());
final Role testRole = new Role(testRoleDefinition, true);
@@ -253,7 +254,7 @@ public class LoginTest {
@Test
public void roleWithQualifiersTest() throws UserStoreManagementException {
UserGroupImpl userDefaultTenant = userStore.createUserGroup(UUID.randomUUID(), "me-tenant");
User meUser = userStore.createUser("me", "me@sap.com");
User meUser = userStore.createUser("me", "me@sap.com", new LockingAndBanningImpl());
RoleDefinition testRoleDefinition = userStore.createRoleDefinition(UUID.randomUUID(), "testRole",
Collections.emptySet());
final Role testRole = new Role(testRoleDefinition, userDefaultTenant, meUser, true);
@@ -267,7 +268,7 @@ public class LoginTest {
@Test
public void permissionsTest() throws UserStoreManagementException {
userStore.createUser("me", "me@sap.com");
userStore.createUser("me", "me@sap.com", new LockingAndBanningImpl());
userStore.addPermissionForUser("me", new WildcardPermission("a:b:c"));
UserStoreImpl store2 = createAndLoadUserStore();
User allUser = userStore.getUserByName(SecurityService.ALL_USERNAME);
@@ -39,6 +39,7 @@ import com.sap.sse.security.shared.UserManagementException;
import com.sap.sse.security.shared.WildcardPermission;
import com.sap.sse.security.shared.impl.AccessControlList;
import com.sap.sse.security.shared.impl.HasPermissionsImpl;
import com.sap.sse.security.shared.impl.LockingAndBanningImpl;
import com.sap.sse.security.shared.impl.Ownership;
import com.sap.sse.security.shared.impl.Role;
import com.sap.sse.security.shared.impl.User;
@@ -93,7 +94,7 @@ public class PermissionCheckerTest {
userStore.deleteUser("jonas");
}
userTenant = userStore.createUserGroup(userTenantId, "jonas-tenant");
user = userStore.createUser("jonas", "jonas@dann.io");
user = userStore.createUser("jonas", "jonas@dann.io", new LockingAndBanningImpl());
userTenant.add(user);
userStore.updateUserGroup(userTenant);
ownership = new Ownership(user, userTenant);
@@ -11,6 +11,7 @@ import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
@@ -24,13 +25,12 @@ import com.sap.sse.security.interfaces.UserImpl;
import com.sap.sse.security.interfaces.UserStore;
import com.sap.sse.security.shared.UserGroupManagementException;
import com.sap.sse.security.shared.UserManagementException;
import com.sap.sse.security.shared.impl.LockingAndBanningImpl;
import com.sap.sse.security.shared.impl.User;
import com.sap.sse.security.shared.impl.UserGroup;
import com.sap.sse.security.userstore.mongodb.UserStoreImpl;
import com.sap.sse.security.userstore.mongodb.impl.CollectionNames;
import org.junit.Assert;
public class PreferenceObjectBasedNotificationSetTest {
private static final String A = "a";
@@ -191,7 +191,7 @@ public class PreferenceObjectBasedNotificationSetTest {
@Test
public void userWithNonVerifiedEmailIsSkippedTest() throws UserManagementException, UserGroupManagementException {
store.createUser(user1, mail);
store.createUser(user1, mail, new LockingAndBanningImpl());
store.registerPreferenceConverter(prefKey, prefConverter);
store.setPreferenceObject(user1, prefKey, values1);
PreferenceObjectBasedNotificationSetImpl notificationSet = new PreferenceObjectBasedNotificationSetImpl(prefKey, store);
@@ -238,7 +238,7 @@ public class PreferenceObjectBasedNotificationSetTest {
*/
@Test
public void deleteUserWithMappingTest() throws UserManagementException, UserGroupManagementException {
store.createUser(user1, mail);
store.createUser(user1, mail, new LockingAndBanningImpl());
store.registerPreferenceConverter(prefKey, prefConverter);
store.setPreferenceObject(user1, prefKey, values1);
PreferenceObjectBasedNotificationSetImpl notificationSet = new PreferenceObjectBasedNotificationSetImpl(prefKey, store);
@@ -250,7 +250,7 @@ public class PreferenceObjectBasedNotificationSetTest {
@Test
public void removePreferenceConverterTest() throws UserManagementException, UserGroupManagementException {
store.createUser(user1, mail);
store.createUser(user1, mail, new LockingAndBanningImpl());
store.registerPreferenceConverter(prefKey, prefConverter);
store.setPreferenceObject(user1, prefKey, values1);
PreferenceObjectBasedNotificationSetImpl notificationSet = new PreferenceObjectBasedNotificationSetImpl(prefKey, store);
@@ -272,9 +272,9 @@ public class PreferenceObjectBasedNotificationSetTest {
UserGroup defaultTenantForSingleServer = store.createUserGroup(UUID.randomUUID(), username + "-tenant");
Map<String, UserGroup> defaultTenantForServer = new ConcurrentHashMap<>();
defaultTenantForServer.put(serverName, defaultTenantForSingleServer);
store.createUser(username, email);
store.createUser(username, email, new LockingAndBanningImpl());
store.updateUser(new UserImpl(username, email, null, null, null, true, null, null, defaultTenantForServer,
Collections.emptySet(), /* userGroupProvider */ null));
Collections.emptySet(), /* userGroupProvider */ null, new LockingAndBanningImpl()));
}
private static class PreferenceObjectBasedNotificationSetImpl extends PreferenceObjectBasedNotificationSet<HashSet<String>, String> {
@@ -26,6 +26,7 @@ import com.sap.sse.security.shared.UserStoreManagementException;
import com.sap.sse.security.shared.WildcardPermission;
import com.sap.sse.security.shared.impl.AccessControlList;
import com.sap.sse.security.shared.impl.HasPermissionsImpl;
import com.sap.sse.security.shared.impl.LockingAndBanningImpl;
import com.sap.sse.security.shared.impl.Ownership;
import com.sap.sse.security.shared.impl.Role;
import com.sap.sse.security.shared.impl.SecuredSecurityTypes;
@@ -64,8 +65,8 @@ public class PrivilegeEscalationTest {
PersistenceFactory.INSTANCE.getDefaultMongoObjectFactory(), TEST_DEFAULT_TENANT);
userStore.ensureDefaultRolesExist();
userStore.loadAndMigrateUsers();
user = userStore.createUser(USER_USERNAME, null);
user2 = userStore.createUser(USER2_USERNAME, null);
user = userStore.createUser(USER_USERNAME, null, new LockingAndBanningImpl());
user2 = userStore.createUser(USER2_USERNAME, null, new LockingAndBanningImpl());
userGroup = userStore.createUserGroup(USER_GROUP_UUID, USER_USERNAME+"-tenant");
userGroup.add(user);
userGroup.add(user2);
@@ -12,6 +12,7 @@ import com.sap.sse.security.interfaces.UserStore;
import com.sap.sse.security.shared.RoleDefinition;
import com.sap.sse.security.shared.UserManagementException;
import com.sap.sse.security.shared.UserStoreManagementException;
import com.sap.sse.security.shared.impl.LockingAndBanningImpl;
import com.sap.sse.security.shared.impl.Role;
import com.sap.sse.security.shared.impl.User;
import com.sap.sse.security.shared.impl.UserGroup;
@@ -36,7 +37,7 @@ public class RoleDefinitionsTest {
@Before
public void doBefore() throws UserStoreManagementException {
userStore.clear();
user = userStore.createUser(username, email);
user = userStore.createUser(username, email, new LockingAndBanningImpl());
roleDefinition = userStore.createRoleDefinition(testRoleUUID, TEST_ROLE, Collections.emptySet());
userGroup = userStore.createUserGroup(testGroupUUID, groupName);
}
@@ -13,6 +13,7 @@ import com.sap.sse.mongodb.MongoDBConfiguration;
import com.sap.sse.mongodb.MongoDBService;
import com.sap.sse.security.shared.UserGroupManagementException;
import com.sap.sse.security.shared.UserManagementException;
import com.sap.sse.security.shared.impl.LockingAndBanningImpl;
import com.sap.sse.security.userstore.mongodb.UserStoreImpl;
import com.sap.sse.security.userstore.mongodb.impl.CollectionNames;
@@ -114,7 +115,7 @@ public class UserPreferenceObjectAndConverterTest {
*/
@Test
public void deleteUserWithPreferenceObjectTest() throws UserManagementException, UserGroupManagementException {
store.createUser(user1, email);
store.createUser(user1, email, new LockingAndBanningImpl());
store.registerPreferenceConverter(prefKey1, prefConverter);
store.setPreferenceObject(user1, prefKey1, pref1);
store.deleteUser(user1);
@@ -123,7 +124,7 @@ public class UserPreferenceObjectAndConverterTest {
@Test
public void removeConverterTest() throws UserManagementException, UserGroupManagementException {
store.createUser(user1, email);
store.createUser(user1, email, new LockingAndBanningImpl());
store.registerPreferenceConverter(prefKey1, prefConverter);
store.setPreference(user1, prefKey1, serializedPref1);
store.removePreferenceConverter(prefKey1);
@@ -9,6 +9,7 @@ import org.junit.Test;
import com.sap.sse.security.interfaces.UserStore;
import com.sap.sse.security.shared.UserGroupManagementException;
import com.sap.sse.security.shared.UserManagementException;
import com.sap.sse.security.shared.impl.LockingAndBanningImpl;
import com.sap.sse.security.userstore.mongodb.UserStoreImpl;
public class UserStoreTest {
@@ -25,7 +26,7 @@ public class UserStoreTest {
@Before
public void setUp() throws UserManagementException, UserGroupManagementException {
userStore.createUser(username, email);
userStore.createUser(username, email, new LockingAndBanningImpl());
userStore.setAccessToken(username, accessToken);
userStore.setPreference(username, prefKey, prefValue);
}
@@ -28,12 +28,13 @@ import com.sap.sse.mongodb.MongoDBConfiguration;
import com.sap.sse.mongodb.MongoDBService;
import com.sap.sse.security.interfaces.UserImpl;
import com.sap.sse.security.interfaces.UserStore;
import com.sap.sse.security.shared.UserStoreManagementException;
import com.sap.sse.security.shared.RoleDefinition;
import com.sap.sse.security.shared.RoleDefinitionImpl;
import com.sap.sse.security.shared.SecurityUser;
import com.sap.sse.security.shared.UserGroupManagementException;
import com.sap.sse.security.shared.UserManagementException;
import com.sap.sse.security.shared.UserStoreManagementException;
import com.sap.sse.security.shared.impl.LockingAndBanningImpl;
import com.sap.sse.security.shared.impl.Ownership;
import com.sap.sse.security.shared.impl.Role;
import com.sap.sse.security.shared.impl.User;
@@ -91,7 +92,7 @@ public class UserStoreWithPersistenceTest {
@Test
public void testCreateUser() throws UserManagementException {
store.createUser(username, email);
store.createUser(username, email, new LockingAndBanningImpl());
assertNotNull(store.getUserByName(username));
assertNotNull(store.getUserByEmail(email));
@@ -102,12 +103,12 @@ public class UserStoreWithPersistenceTest {
@Test
public void testMasterdataIsSaved() throws UserStoreManagementException {
store.createUser(username, email);
store.createUser(username, email, new LockingAndBanningImpl());
UserGroupImpl defaultTenant = createUserGroup();
HashMap<String, UserGroup> defaultTenantForServers = new HashMap<>();
defaultTenantForServers.put(serverName, defaultTenant);
store.updateUser(new UserImpl(username, email, fullName, company, Locale.GERMAN, false, null, null,
defaultTenantForServers, Collections.emptySet(), /* userGroupProvider */ null));
defaultTenantForServers, Collections.emptySet(), /* userGroupProvider */ null, new LockingAndBanningImpl()));
newStore();
User savedUser = store.getUserByName(username);
assertEquals(username, savedUser.getName());
@@ -122,7 +123,7 @@ public class UserStoreWithPersistenceTest {
*/
@Test
public void testDeleteUser() throws UserManagementException {
store.createUser(username, email);
store.createUser(username, email, new LockingAndBanningImpl());
store.deleteUser(username);
assertNull(store.getUserByName(username));
assertNull(store.getUserByEmail(email));
@@ -134,7 +135,7 @@ public class UserStoreWithPersistenceTest {
@Test
public void testSetPreferences() throws UserManagementException {
store.createUser(username, email);
store.createUser(username, email, new LockingAndBanningImpl());
store.setPreference(username, prefKey, prefValue);
assertEquals(prefValue, store.getPreference(username, prefKey));
newStore();
@@ -143,7 +144,7 @@ public class UserStoreWithPersistenceTest {
@Test
public void testUnsetPreferences() throws UserManagementException {
store.createUser(username, email);
store.createUser(username, email, new LockingAndBanningImpl());
store.setPreference(username, prefKey, prefValue);
store.unsetPreference(username, prefKey);
assertNull(store.getPreference(username, prefKey));
@@ -156,7 +157,7 @@ public class UserStoreWithPersistenceTest {
*/
@Test
public void testDeleteUserWithPreferences() throws UserManagementException {
store.createUser(username, email);
store.createUser(username, email, new LockingAndBanningImpl());
store.setPreference(username, prefKey, prefValue);
store.deleteUser(username);
assertNull(store.getPreference(username, prefKey));
@@ -166,7 +167,7 @@ public class UserStoreWithPersistenceTest {
@Test
public void testCreateUserGroup() throws UserGroupManagementException, UserManagementException {
final User user = store.createUser(username, email);
final User user = store.createUser(username, email, new LockingAndBanningImpl());
UserGroupImpl createUserGroup = createUserGroup();
createUserGroup.add(user);
store.updateUserGroup(createUserGroup);
@@ -195,7 +196,7 @@ public class UserStoreWithPersistenceTest {
@Test
public void testTenantUsers() throws UserManagementException, UserGroupManagementException {
UserGroupImpl defaultTenant = createUserGroup();
final User user = store.createUser(username, email);
final User user = store.createUser(username, email, new LockingAndBanningImpl());
defaultTenant.add(user);
store.updateUserGroup(defaultTenant);
user.getDefaultTenantMap().put(serverName, defaultTenant);
@@ -217,7 +218,7 @@ public class UserStoreWithPersistenceTest {
@Test
public void testUserGroups() throws UserManagementException, UserGroupManagementException {
final User user = store.createUser(username, email);
final User user = store.createUser(username, email, new LockingAndBanningImpl());
final String GROUP_NAME = "group";
final UserGroupImpl group = store.createUserGroup(UUID.randomUUID(), GROUP_NAME);
group.add(user);
@@ -241,7 +242,7 @@ public class UserStoreWithPersistenceTest {
@Test
public void testGetExistingQualificationsForRoleDefinition()
throws UserManagementException, UserGroupManagementException {
User user = store.createUser("def", "d@test.de");
User user = store.createUser("def", "d@test.de", new LockingAndBanningImpl());
RoleDefinitionImpl roleDefinition = new RoleDefinitionImpl(UUID.randomUUID(), "My-Test-Role");
store.createRoleDefinition(roleDefinition.getId(), roleDefinition.getName(), new ArrayList<>());
UserGroupImpl userGroup = store.createUserGroup(UUID.randomUUID(), "Test-Usergroup");
@@ -24,6 +24,8 @@ securityManager.sessionManager.sessionDAO = $sessionDAO
securityManager.sessionManager.globalSessionTimeout = 31536000000
cacheManager = com.sap.sse.security.SessionCacheManager
securityManager.cacheManager = $cacheManager
authenticationStrategy = com.sap.sse.security.AtLeastOneSuccessfulStrategyWithLockingAndBanning
securityManager.authenticator.authenticationStrategy = $authenticationStrategy
subjectDAO = com.sap.sse.security.NoSessionStorageForUnauthenticatedSessionsSessionDAO
securityManager.subjectDAO = $subjectDAO
@@ -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();
}
}
@@ -26,6 +26,8 @@ securityManager.subjectDAO = $subjectDAO
securityManager.sessionManager.globalSessionTimeout = 31536000000
cacheManager = com.sap.sse.security.SessionCacheManager
securityManager.cacheManager = $cacheManager
authenticationStrategy = com.sap.sse.security.AtLeastOneSuccessfulStrategyWithLockingAndBanning
securityManager.authenticator.authenticationStrategy = $authenticationStrategy
# Support for anonymous user permissions
webSubjectFactoryWithAnonymousPrincipalSupport=com.sap.sse.security.WebSubjectFactoryWithAnonymousPrincipalSupport
@@ -0,0 +1,39 @@
package com.sap.sse.security;
import java.util.logging.Logger;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy;
import org.apache.shiro.realm.Realm;
import com.sap.sse.security.shared.impl.User;
public class AtLeastOneSuccessfulStrategyWithLockingAndBanning extends AtLeastOneSuccessfulStrategy {
private static final Logger logger = Logger
.getLogger(AtLeastOneSuccessfulStrategyWithLockingAndBanning.class.getName());
@Override
public AuthenticationInfo afterAttempt(Realm realm, AuthenticationToken token, AuthenticationInfo singleRealmInfo,
AuthenticationInfo aggregateInfo, Throwable t) throws AuthenticationException {
if (token != null && token.getPrincipal() != null && realm instanceof UsernamePasswordRealm) {
final UsernamePasswordRealm upRealm = (UsernamePasswordRealm) realm;
final String username = token.getPrincipal().toString();
final User user = upRealm.getUserStore().getUserByName(username);
if (user != null) {
if (t != null) {
if (t instanceof IncorrectCredentialsException) {
logger.info("failed password authentication for user "+username);
user.getLockingAndBanning().failedPasswordAuthentication();
}
} else {
// no exception, so the authentication must have been successful
user.getLockingAndBanning().successfulPasswordAuthentication();
}
}
}
return super.afterAttempt(realm, token, singleRealmInfo, aggregateInfo, t);
}
}
@@ -40,6 +40,7 @@ import com.sap.sse.security.interfaces.SocialSettingsKeys;
import com.sap.sse.security.shared.SocialUserAccount;
import com.sap.sse.security.shared.UserGroupManagementException;
import com.sap.sse.security.shared.UserManagementException;
import com.sap.sse.security.shared.impl.LockingAndBanningImpl;
import com.sap.sse.security.shared.impl.User;
import com.sap.sse.security.shared.impl.UserGroup;
@@ -188,7 +189,7 @@ public class OAuthRealm extends AbstractCompositeAuthorizingRealm {
try {
UserGroup tenant = getUserStore().createUserGroup(UUID.randomUUID(), socialname + SecurityService.TENANT_SUFFIX);
getAccessControlStore().setOwnership(tenant.getIdentifier(), user, tenant, tenant.getName());
user = getUserStore().createUser(socialname, socialUser.getProperty(Social.EMAIL.name()), socialUser);
user = getUserStore().createUser(socialname, socialUser.getProperty(Social.EMAIL.name()), new LockingAndBanningImpl(), socialUser);
tenant.add(user);
getUserStore().updateUserGroup(tenant);
} catch (UserManagementException | UserGroupManagementException e) {
@@ -3,6 +3,7 @@ package com.sap.sse.security;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SaltedAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
@@ -12,7 +13,6 @@ import com.sap.sse.security.interfaces.SimpleSaltedAuthenticationInfo;
import com.sap.sse.security.shared.UsernamePasswordAccount;
public class UsernamePasswordRealm extends AbstractCompositeAuthorizingRealm {
public UsernamePasswordRealm() {
super();
setAuthenticationTokenClass(UsernamePasswordToken.class);
@@ -45,6 +45,9 @@ public class UsernamePasswordRealm extends AbstractCompositeAuthorizingRealm {
if (user == null) {
return null;
}
if (user.getLockingAndBanning().isPasswordAuthenticationLocked()) {
throw new LockedAccountException("Password authentication for user "+username+" is currently locked");
}
UsernamePasswordAccount upa = (UsernamePasswordAccount) user.getAccount(AccountType.USERNAME_PASSWORD);
if (upa == null){
return null;
@@ -61,6 +64,4 @@ public class UsernamePasswordRealm extends AbstractCompositeAuthorizingRealm {
SaltedAuthenticationInfo sai = new SimpleSaltedAuthenticationInfo(username, saltedPassword, salt);
return sai;
}
}
@@ -171,6 +171,7 @@ import com.sap.sse.security.shared.UsernamePasswordAccount;
import com.sap.sse.security.shared.WildcardPermission;
import com.sap.sse.security.shared.WithQualifiedObjectIdentifier;
import com.sap.sse.security.shared.impl.AccessControlList;
import com.sap.sse.security.shared.impl.LockingAndBanningImpl;
import com.sap.sse.security.shared.impl.Ownership;
import com.sap.sse.security.shared.impl.PermissionAndRoleAssociation;
import com.sap.sse.security.shared.impl.Role;
@@ -1097,7 +1098,7 @@ implements ReplicableSecurityService, ClearStateTestSupport {
@Override
public User internalCreateUser(String username, String email, Account... accounts) throws UserManagementException {
final User result = store.createUser(username, email, accounts); // TODO: get the principal as owner
final User result = store.createUser(username, email, new LockingAndBanningImpl(), accounts); // TODO: get the principal as owner
return result;
}
@@ -1161,11 +1162,17 @@ implements ReplicableSecurityService, ClearStateTestSupport {
if (user == null) {
throw new UserManagementException(UserManagementException.USER_DOES_NOT_EXIST);
}
if (user.getLockingAndBanning().isPasswordAuthenticationLocked()) {
throw new UserManagementException("Password authentication is locked for user "+username);
}
final UsernamePasswordAccount account = (UsernamePasswordAccount) user.getAccount(AccountType.USERNAME_PASSWORD);
String hashedOldPassword = hashPassword(password, account.getSalt());
final boolean result = Util.equalsWithNull(hashedOldPassword, account.getSaltedPassword());
if (!result) {
logger.info("Failed password check for user "+username);
user.getLockingAndBanning().failedPasswordAuthentication();
} else {
user.getLockingAndBanning().successfulPasswordAuthentication();
}
return result;
}
@@ -26,6 +26,8 @@ securityManager.subjectDAO = $subjectDAO
securityManager.sessionManager.globalSessionTimeout = 31536000000
cacheManager = com.sap.sse.security.SessionCacheManager
securityManager.cacheManager = $cacheManager
authenticationStrategy = com.sap.sse.security.AtLeastOneSuccessfulStrategyWithLockingAndBanning
securityManager.authenticator.authenticationStrategy = $authenticationStrategy
# Support for anonymous user permissions
webSubjectFactoryWithAnonymousPrincipalSupport=com.sap.sse.security.WebSubjectFactoryWithAnonymousPrincipalSupport