diff --git a/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889).launch b/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889).launch
index eeecd5c8aaa..2b75c45e0cc 100644
--- a/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889).launch
+++ b/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889).launch
@@ -18,7 +18,7 @@
-
+
diff --git a/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889, Cached MTB).launch b/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889, Cached MTB).launch
index 988b0078371..fa713e19392 100644
--- a/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889, Cached MTB).launch
+++ b/java/com.sap.sailing.server/SailingServer (No Proxy, Jetty on 8889, Cached MTB).launch
@@ -19,7 +19,7 @@
-
+
diff --git a/java/com.sap.sailing.server/SailingServer (Proxy, Jetty on 8889).launch b/java/com.sap.sailing.server/SailingServer (Proxy, Jetty on 8889).launch
index 67f953e4d72..7c96bd6a9b4 100644
--- a/java/com.sap.sailing.server/SailingServer (Proxy, Jetty on 8889).launch
+++ b/java/com.sap.sailing.server/SailingServer (Proxy, Jetty on 8889).launch
@@ -18,7 +18,7 @@
-
+
diff --git a/java/com.sap.sse.replication/src/com/sap/sse/replication/Replicable.java b/java/com.sap.sse.replication/src/com/sap/sse/replication/Replicable.java
index 6edf84ab50b..9900da8a626 100755
--- a/java/com.sap.sse.replication/src/com/sap/sse/replication/Replicable.java
+++ b/java/com.sap.sse.replication/src/com/sap/sse/replication/Replicable.java
@@ -83,8 +83,11 @@ public interface Replicable> extends With
/**
* Before {@link #initiallyFillFrom(ObjectInputStream) initially loading a replica's state from a master instance},
- * the replica's old state needs to be "detached". This method clears all top-level data structures and stops all
- * tracking currently going on.
+ * the replica's old state needs to be "detached". This method clears all top-level in-memory data structures and stops all
+ * tracking currently going on. It may choose to leave any persistent content unchanged as the persistence layer is in
+ * an undefined state on a replica anyhow. This seems like the safer bet, particularly in case of an accidental
+ * mis-configuration of the replica's DB connection parameters which may lead to an inadvertent overwriting of the
+ * master's DB contents.
*
* The reason this operation needs to be callable separate from {@link #initiallyFillFrom(ObjectInputStream)} is that
* it needs to happen before subscribing to the operation feed received from the master instance through the message bus
diff --git a/java/com.sap.sse.security.ui/src/main/resources/shiro.ini b/java/com.sap.sse.security.ui/src/main/resources/shiro.ini
index 7c0466025e0..8e7d14f8c4b 100755
--- a/java/com.sap.sse.security.ui/src/main/resources/shiro.ini
+++ b/java/com.sap.sse.security.ui/src/main/resources/shiro.ini
@@ -1,10 +1,4 @@
-
[main]
-#shiro.loginUrl = /security/ui/Login.html
-#shiro.successUrl = /UserManagement.html
-# Use Built-in Chache Manager
-
-
credentialsMatcher = org.apache.shiro.authc.credential.Sha256CredentialsMatcher
# base64 encoding, not hex in this example:
credentialsMatcher.storedCredentialsHexEncoded = false
@@ -19,8 +13,6 @@ securityManager.realms = $upRealm, $oauthRealm
sessionManager = com.sap.sse.security.SecurityWebSessionManager
securityManager.sessionManager = $sessionManager
-#globalCookie = com.sap.sse.security.GlobalCookie
-#securityManager.sessionManager.sessionIdCookie = $globalCookie
authc = com.sap.sse.security.CustomFilter
authc.loginUrl = /security/ui/Login.html
@@ -32,8 +24,6 @@ securityManager.sessionManager.sessionDAO = $sessionDAO
cacheManager = com.sap.sse.security.SessionCacheManager
securityManager.cacheManager = $cacheManager
-#securityManager.sessionMode = native
-
[urls]
/Login.html = anon
/UserManagement.html = authc,roles[admin]
diff --git a/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java b/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java
index 4917c55bb69..5f9697bc2c6 100644
--- a/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java
+++ b/java/com.sap.sse.security.userstore.mongodb/src/com/sap/sse/security/userstore/mongodb/UserStoreImpl.java
@@ -1,7 +1,7 @@
package com.sap.sse.security.userstore.mongodb;
import java.util.ArrayList;
-import java.util.Collection;
+import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
@@ -73,6 +73,34 @@ public class UserStoreImpl implements UserStore {
}
}
+ @Override
+ public void clear() {
+ preferences.clear();
+ emailForUsername.clear();
+ settings.clear();
+ settingTypes.clear();
+ users.clear();
+ usersByEmail.clear();
+ }
+
+ @Override
+ public void replaceContentsFrom(UserStore newUserStore) {
+ clear();
+ for (User user : newUserStore.getUsers()) {
+ users.put(user.getName(), user);
+ addToUsersByEmail(user);
+ for (Entry userPref : newUserStore.getAllPreferences(user.getName()).entrySet()) {
+ setPreference(user.getName(), userPref.getKey(), userPref.getValue());
+ }
+ }
+ for (Entry setting : newUserStore.getAllSettings().entrySet()) {
+ settings.put(setting.getKey(), setting.getValue());
+ }
+ for (Entry> settingType : newUserStore.getAllSettingTypes().entrySet()) {
+ settingTypes.put(settingType.getKey(), settingType.getValue());
+ }
+ }
+
private void addToUsersByEmail(User u) {
if (u.getEmail() != null && !u.getEmail().isEmpty()) {
Set set = usersByEmail.get(u.getEmail());
@@ -141,7 +169,7 @@ public class UserStoreImpl implements UserStore {
}
@Override
- public Collection getUserCollection() {
+ public Iterable getUsers() {
return new ArrayList(users.values());
}
@@ -290,6 +318,18 @@ public class UserStoreImpl implements UserStore {
return result;
}
+ @Override
+ public Map getAllPreferences(String username) {
+ final Map userPrefs = preferences.get(username);
+ final Map result;
+ if (userPrefs == null) {
+ result = Collections.emptyMap();
+ } else {
+ result = Collections.unmodifiableMap(userPrefs);
+ }
+ return result;
+ }
+
@Override
public Map getAllSettings() {
return settings;
@@ -299,17 +339,4 @@ public class UserStoreImpl implements UserStore {
public Map> getAllSettingTypes() {
return settingTypes;
}
-
- @Override
- public void clear() {
- preferences.clear();
- emailForUsername.clear();
- settings.clear();
- settingTypes.clear();
- users.clear();
- usersByEmail.clear();
- mongoObjectFactory.clearAllPreferences();
- mongoObjectFactory.clearAllUsers();
- mongoObjectFactory.clearAllSettings();
- }
}
diff --git a/java/com.sap.sse.security/src/com/sap/sse/security/SecurityService.java b/java/com.sap.sse.security/src/com/sap/sse/security/SecurityService.java
index ba281c2ad33..cc3b00857ab 100644
--- a/java/com.sap.sse.security/src/com/sap/sse/security/SecurityService.java
+++ b/java/com.sap.sse.security/src/com/sap/sse/security/SecurityService.java
@@ -1,6 +1,5 @@
package com.sap.sse.security;
-import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
@@ -22,7 +21,7 @@ public interface SecurityService extends ReplicableWithObjectInputStream getUserList();
+ Iterable getUserList();
User getUserByName(String username);
diff --git a/java/com.sap.sse.security/src/com/sap/sse/security/SessionCacheManager.java b/java/com.sap.sse.security/src/com/sap/sse/security/SessionCacheManager.java
index b3c314a4e0b..40a933a83e8 100644
--- a/java/com.sap.sse.security/src/com/sap/sse/security/SessionCacheManager.java
+++ b/java/com.sap.sse.security/src/com/sap/sse/security/SessionCacheManager.java
@@ -3,15 +3,16 @@ package com.sap.sse.security;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.apache.shiro.cache.CacheManager;
+import org.apache.shiro.mgt.SecurityManager;
import com.sap.sse.security.impl.Activator;
import com.sap.sse.security.impl.ReplicableSecurityService;
-import com.sap.sse.security.impl.ReplicatingCache;
/**
- * Obtains the singleton cache manager instance from the singleton {@link SecurityService} instance. The cache manager
- * returned will replicate all modifying operations to the {@link SecurityService} in any replica listening. Using an instance
- * of this class as the cache manager in your Shiro configuration as in
+ * A {@link CacheManager} implementation that can be used in a shiro.ini configuration for a
+ * {@link SecurityManager}. {@link SecurityService#getCacheManager() Obtains} the singleton cache manager instance from
+ * the singleton {@link SecurityService} instance. Using an instance of this class as the cache manager in your
+ * Shiro configuration as in
*
*
* sessionDAO = org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO
@@ -25,16 +26,19 @@ import com.sap.sse.security.impl.ReplicatingCache;
*
* @see SecurityService#getCacheManager()
*
- * @author Benjamin Ebling
+ * @author Benjamin Ebling, Axel Uhl
*
*/
public class SessionCacheManager implements CacheManager {
@Override
public Cache getCache(String name) throws CacheException {
final ReplicableSecurityService securityService = (ReplicableSecurityService) Activator.getSecurityService();
+ final Cache result;
if (securityService == null) {
- return null;
+ result = null;
+ } else {
+ result = securityService.getCacheManager().getCache(name);
}
- return new ReplicatingCache(securityService, name, securityService.getCacheManager().getCache(name));
+ return result;
}
}
diff --git a/java/com.sap.sse.security/src/com/sap/sse/security/UserStore.java b/java/com.sap.sse.security/src/com/sap/sse/security/UserStore.java
index db5dad1e539..b1d15c87ce5 100644
--- a/java/com.sap.sse.security/src/com/sap/sse/security/UserStore.java
+++ b/java/com.sap.sse.security/src/com/sap/sse/security/UserStore.java
@@ -1,6 +1,5 @@
package com.sap.sse.security;
-import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
@@ -10,7 +9,7 @@ import com.sap.sse.security.shared.Account;
import com.sap.sse.security.shared.UserManagementException;
public interface UserStore extends Named {
- Collection getUserCollection();
+ Iterable getUsers();
User getUserByName(String name);
@@ -38,6 +37,11 @@ public interface UserStore extends Named {
void setPreference(String username, String key, String value);
+ /**
+ * Always returns a valid map which may be empty.
+ */
+ Map getAllPreferences(String username);
+
void unsetPreference(String username, String key);
String getPreference(String username, String key);
@@ -62,12 +66,20 @@ public interface UserStore extends Named {
T getSetting(String key, Class clazz);
Map getAllSettings();
-
+
Map> getAllSettingTypes();
/**
- * Removes all users and all their preferences and all settings from this store. Use with due care.
+ * Removes all users and all their preferences and all settings from this store's in-memory representation.
+ * For safety reasons and because a replica's DB state is undefined anyhow, leaves persistent content in place.
+ * Use with due care.
*/
void clear();
+ /**
+ * Replaces all existing contents by those provided by the newUserStore. This has no impact on the persistent
+ * representation of this store and is meant for use on a replica only; the replica's database state is undefined.
+ */
+ void replaceContentsFrom(UserStore newUserStore);
+
}
diff --git a/java/com.sap.sse.security/src/com/sap/sse/security/impl/ReplicatingCache.java b/java/com.sap.sse.security/src/com/sap/sse/security/impl/ReplicatingCache.java
index 91cf6710349..b13177bb20d 100755
--- a/java/com.sap.sse.security/src/com/sap/sse/security/impl/ReplicatingCache.java
+++ b/java/com.sap.sse.security/src/com/sap/sse/security/impl/ReplicatingCache.java
@@ -1,6 +1,7 @@
package com.sap.sse.security.impl;
import java.util.Collection;
+import java.util.Map;
import java.util.Set;
import org.apache.shiro.cache.Cache;
@@ -19,9 +20,9 @@ public class ReplicatingCache implements Cache, Named {
private static final long serialVersionUID = 6628512191363526330L;
private final ReplicableSecurityService securityService;
private final String name;
- private final Cache cache;
+ private final Map cache;
- public ReplicatingCache(ReplicableSecurityService securityService, String name, Cache cache) {
+ public ReplicatingCache(ReplicableSecurityService securityService, String name, Map cache) {
super();
this.securityService = securityService;
this.name = name;
@@ -72,7 +73,7 @@ public class ReplicatingCache implements Cache, Named {
@Override
public Set keys() {
- return cache.keys();
+ return cache.keySet();
}
@Override
diff --git a/java/com.sap.sse.security/src/com/sap/sse/security/impl/ReplicatingCacheManager.java b/java/com.sap.sse.security/src/com/sap/sse/security/impl/ReplicatingCacheManager.java
new file mode 100755
index 00000000000..80dfd967529
--- /dev/null
+++ b/java/com.sap.sse.security/src/com/sap/sse/security/impl/ReplicatingCacheManager.java
@@ -0,0 +1,46 @@
+package com.sap.sse.security.impl;
+
+import java.io.Serializable;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.shiro.cache.Cache;
+import org.apache.shiro.cache.CacheException;
+import org.apache.shiro.cache.CacheManager;
+
+/**
+ * Wraps a {@link CacheManager} and makes all modifying operations replicate their changes. This happens by wrapping
+ * all {@link Cache}s by an object that intercepts the writing operations, producing replicating operations.
+ *
+ * @author Axel Uhl (D043530)
+ *
+ */
+public class ReplicatingCacheManager implements CacheManager, Serializable {
+ private static final long serialVersionUID = -8035346668009900228L;
+ private ConcurrentHashMap> caches;
+
+ public ReplicatingCacheManager() {
+ this.caches = new ConcurrentHashMap<>();
+ }
+
+ @Override
+ public Cache getCache(String name) throws CacheException {
+ final ReplicableSecurityService securityService = (ReplicableSecurityService) Activator.getSecurityService();
+ if (securityService == null) {
+ return null;
+ }
+ ConcurrentHashMap