mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-09-21 21:25:38 +00:00
bug6099: added writing persistence and replication for LockingAndBanning
This commit is contained in:
+3
-65
@@ -3,10 +3,8 @@ package com.sap.sse.security;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.FutureTask;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@@ -17,7 +15,6 @@ import org.apache.shiro.authz.UnauthorizedException;
|
||||
import org.apache.shiro.realm.AuthorizingRealm;
|
||||
import org.apache.shiro.subject.PrincipalCollection;
|
||||
import org.osgi.framework.BundleContext;
|
||||
import org.osgi.util.tracker.ServiceTracker;
|
||||
|
||||
import com.sap.sse.security.impl.Activator;
|
||||
import com.sap.sse.security.impl.PermissionConverter;
|
||||
@@ -31,6 +28,7 @@ import com.sap.sse.security.shared.UserManagementException;
|
||||
import com.sap.sse.security.shared.WildcardPermission;
|
||||
import com.sap.sse.security.shared.impl.Role;
|
||||
import com.sap.sse.security.shared.impl.User;
|
||||
import com.sap.sse.util.ServiceTrackerFactory;
|
||||
|
||||
/**
|
||||
* This class implements a realm that combines Access Control Lists, Role Based Permission Modeling and
|
||||
@@ -68,74 +66,14 @@ public abstract class AbstractCompositeAuthorizingRealm extends AuthorizingRealm
|
||||
setPermissionResolver(wildcardString->new org.apache.shiro.authz.permission.WildcardPermission(wildcardString, /* caseSensitive */ true));
|
||||
BundleContext context = Activator.getContext();
|
||||
if (context != null) {
|
||||
userStore = createUserStoreFuture(context);
|
||||
accessControlStore = createAccessControlStoreFuture(context);
|
||||
userStore = ServiceTrackerFactory.createServiceFuture(context, UserStore.class);
|
||||
accessControlStore = ServiceTrackerFactory.createServiceFuture(context, AccessControlStore.class);
|
||||
} else {
|
||||
userStore = null;
|
||||
accessControlStore = null;
|
||||
}
|
||||
}
|
||||
|
||||
private Future<UserStore> createUserStoreFuture(BundleContext bundleContext) {
|
||||
final ServiceTracker<UserStore, UserStore> tracker = new ServiceTracker<>(bundleContext, UserStore.class, /* customizer */ null);
|
||||
tracker.open();
|
||||
final FutureTask<UserStore> result = new FutureTask<>(new Callable<UserStore>() {
|
||||
@Override
|
||||
public UserStore call() throws InterruptedException {
|
||||
try {
|
||||
logger.info("Waiting for UserStore service...");
|
||||
UserStore userStore = tracker.waitForService(0);
|
||||
logger.info("Obtained UserStore service "+userStore);
|
||||
return userStore;
|
||||
} catch (InterruptedException e) {
|
||||
logger.log(Level.SEVERE, "Interrupted while waiting for UserStore service", e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
});
|
||||
new Thread("ServiceTracker waiting for UserStore service") {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
result.run();
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.SEVERE, "Exception while waiting for UserStore service", e);
|
||||
}
|
||||
}
|
||||
}.start();
|
||||
return result;
|
||||
}
|
||||
|
||||
private Future<AccessControlStore> createAccessControlStoreFuture(BundleContext bundleContext) {
|
||||
final ServiceTracker<AccessControlStore, AccessControlStore> tracker = new ServiceTracker<>(bundleContext, AccessControlStore.class, /* customizer */ null);
|
||||
tracker.open();
|
||||
final FutureTask<AccessControlStore> result = new FutureTask<>(new Callable<AccessControlStore>() {
|
||||
@Override
|
||||
public AccessControlStore call() throws InterruptedException {
|
||||
try {
|
||||
logger.info("Waiting for AccessControlListStore service...");
|
||||
AccessControlStore accessControlStore = tracker.waitForService(0);
|
||||
logger.info("Obtained AccessControlListStore service "+accessControlStore);
|
||||
return accessControlStore;
|
||||
} catch (InterruptedException e) {
|
||||
logger.log(Level.SEVERE, "Interrupted while waiting for AccessControlListStore service", e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
});
|
||||
new Thread("ServiceTracker waiting for AccessControlListStore service") {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
result.run();
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.SEVERE, "Exception while waiting for AccessControlListStore service", e);
|
||||
}
|
||||
}
|
||||
}.start();
|
||||
return result;
|
||||
}
|
||||
|
||||
protected UserStore getUserStore() {
|
||||
UserStore result;
|
||||
if (testUserStore != null) {
|
||||
|
||||
+38
-5
@@ -1,5 +1,8 @@
|
||||
package com.sap.sse.security;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.apache.shiro.authc.AuthenticationException;
|
||||
@@ -9,11 +12,34 @@ import org.apache.shiro.authc.IncorrectCredentialsException;
|
||||
import org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy;
|
||||
import org.apache.shiro.realm.Realm;
|
||||
|
||||
import com.sap.sse.security.impl.Activator;
|
||||
import com.sap.sse.security.shared.impl.User;
|
||||
import com.sap.sse.util.ServiceTrackerFactory;
|
||||
|
||||
public class AtLeastOneSuccessfulStrategyWithLockingAndBanning extends AtLeastOneSuccessfulStrategy {
|
||||
private static final Logger logger = Logger
|
||||
.getLogger(AtLeastOneSuccessfulStrategyWithLockingAndBanning.class.getName());
|
||||
private static final Logger logger = Logger.getLogger(AtLeastOneSuccessfulStrategyWithLockingAndBanning.class.getName());
|
||||
|
||||
private final Future<SecurityService> securityService;
|
||||
|
||||
public AtLeastOneSuccessfulStrategyWithLockingAndBanning() {
|
||||
if (Activator.getContext() != null) {
|
||||
securityService = ServiceTrackerFactory.createServiceFuture(Activator.getContext(), SecurityService.class);
|
||||
} else {
|
||||
securityService = null;
|
||||
}
|
||||
}
|
||||
|
||||
private SecurityService getSecurityService() {
|
||||
SecurityService result;
|
||||
try {
|
||||
result = securityService == null ? null : securityService.get();
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
logger.log(Level.SEVERE, "Error retrieving security service", e);
|
||||
result = null;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthenticationInfo afterAttempt(Realm realm, AuthenticationToken token, AuthenticationInfo singleRealmInfo,
|
||||
AuthenticationInfo aggregateInfo, Throwable t) throws AuthenticationException {
|
||||
@@ -25,15 +51,22 @@ public class AtLeastOneSuccessfulStrategyWithLockingAndBanning extends AtLeastOn
|
||||
if (t != null) {
|
||||
if (t instanceof IncorrectCredentialsException) {
|
||||
logger.info("failed password authentication for user "+username);
|
||||
user.getLockingAndBanning().failedPasswordAuthentication();
|
||||
final SecurityService mySecurityService = getSecurityService();
|
||||
if (mySecurityService != null) {
|
||||
mySecurityService.failedPasswordAuthentication(user);
|
||||
} else {
|
||||
logger.warning("Account locking due to failed password authentication for user "+username+" not possible; security service not found");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// no exception, so the authentication must have been successful
|
||||
user.getLockingAndBanning().successfulPasswordAuthentication();
|
||||
final SecurityService mySecurityService = getSecurityService();
|
||||
if (mySecurityService != null) {
|
||||
mySecurityService.successfulPasswordAuthentication(user);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.afterAttempt(realm, token, singleRealmInfo, aggregateInfo, t);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -24,13 +24,16 @@ public class BearerTokenRealm extends AbstractCompositeAuthorizingRealm {
|
||||
|
||||
@Override
|
||||
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
|
||||
final AuthenticationInfo result;
|
||||
BearerAuthenticationToken accessToken = (BearerAuthenticationToken) token;
|
||||
final User user = getUserStore().getUserByAccessToken(accessToken.getCredentials());
|
||||
if (user == null) {
|
||||
return null;
|
||||
result = null;
|
||||
} else {
|
||||
// return salted credentials
|
||||
SaltedAuthenticationInfo sai = new SimpleSaltedAuthenticationInfo(user.getName(), accessToken.getCredentials(), /* salt */ null);
|
||||
result = sai;
|
||||
}
|
||||
// return salted credentials
|
||||
SaltedAuthenticationInfo sai = new SimpleSaltedAuthenticationInfo(user.getName(), accessToken.getCredentials(), /* salt */ null);
|
||||
return sai;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -859,4 +859,8 @@ public interface SecurityService extends ReplicableWithObjectInputStream<Replica
|
||||
void setCORSFilterConfigurationAllowedOrigins(String serverName, String... allowedOrigins) throws IllegalArgumentException;
|
||||
|
||||
Pair<Boolean, Set<String>> getCORSFilterConfiguration(String serverName);
|
||||
|
||||
void failedPasswordAuthentication(User user);
|
||||
|
||||
void successfulPasswordAuthentication(User user);
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ public class UsernamePasswordRealm extends AbstractCompositeAuthorizingRealm {
|
||||
|
||||
@Override
|
||||
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
|
||||
UsernamePasswordToken userPassToken = (UsernamePasswordToken) token;
|
||||
final UsernamePasswordToken userPassToken = (UsernamePasswordToken) token;
|
||||
final String username = userPassToken.getUsername();
|
||||
if (username == null) {
|
||||
return null;
|
||||
@@ -41,14 +41,14 @@ public class UsernamePasswordRealm extends AbstractCompositeAuthorizingRealm {
|
||||
// read password hash and salt from db
|
||||
String saltedPassword = null;
|
||||
byte[] salt = null;
|
||||
User user = getUserStore().getUserByName(username);
|
||||
final User user = getUserStore().getUserByName(username);
|
||||
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);
|
||||
final UsernamePasswordAccount upa = (UsernamePasswordAccount) user.getAccount(AccountType.USERNAME_PASSWORD);
|
||||
if (upa == null){
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -120,4 +120,8 @@ public interface ReplicableSecurityService extends SecurityService {
|
||||
Void internalSetCORSFilterConfigurationToWildcard(String serverName);
|
||||
|
||||
Void internalSetCORSFilterConfigurationAllowedOrigins(String serverName, String... allowedOrigins);
|
||||
|
||||
Void internalFailedPasswordAuthentication(String username);
|
||||
|
||||
Void internalSuccessfulPasswordAuthentication(String username);
|
||||
}
|
||||
|
||||
@@ -1170,13 +1170,43 @@ implements ReplicableSecurityService, ClearStateTestSupport {
|
||||
final boolean result = Util.equalsWithNull(hashedOldPassword, account.getSaltedPassword());
|
||||
if (!result) {
|
||||
logger.info("Failed password check for user "+username);
|
||||
user.getLockingAndBanning().failedPasswordAuthentication();
|
||||
apply(s->s.internalFailedPasswordAuthentication(username));
|
||||
} else {
|
||||
user.getLockingAndBanning().successfulPasswordAuthentication();
|
||||
apply(s->s.internalSuccessfulPasswordAuthentication(username));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failedPasswordAuthentication(User user) {
|
||||
apply(s->s.internalFailedPasswordAuthentication(user.getName()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void internalFailedPasswordAuthentication(String username) {
|
||||
final User user = getUserByName(username);
|
||||
if (user != null) {
|
||||
user.getLockingAndBanning().failedPasswordAuthentication();
|
||||
store.updateUser(user);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void successfulPasswordAuthentication(User user) {
|
||||
apply(s->s.internalSuccessfulPasswordAuthentication(user.getName()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void internalSuccessfulPasswordAuthentication(String username) {
|
||||
final User user = getUserByName(username);
|
||||
if (user != null) {
|
||||
user.getLockingAndBanning().successfulPasswordAuthentication();
|
||||
store.updateUser(user);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkPasswordResetSecret(String username, String passwordResetSecret) throws UserManagementException {
|
||||
final User user = store.getUserByName(username);
|
||||
|
||||
Reference in New Issue
Block a user