diff --git a/src/main/java/caosdb/server/accessControl/CaosDBAuthorizingRealm.java b/src/main/java/caosdb/server/accessControl/CaosDBAuthorizingRealm.java
index d715acf9c9cadebf9e5d7dde7b8ab3f3685fe231..be557e49c5aef0bc42f548016549c44dc0202e39 100644
--- a/src/main/java/caosdb/server/accessControl/CaosDBAuthorizingRealm.java
+++ b/src/main/java/caosdb/server/accessControl/CaosDBAuthorizingRealm.java
@@ -68,7 +68,7 @@ public class CaosDBAuthorizingRealm extends AuthorizingRealm {
       authzInfo.addRoles(principalRoles);
     }
 
-    if (authzInfo.getRoles() != null) {
+    if (authzInfo.getRoles() != null && !authzInfo.getRoles().isEmpty()) {
       authzInfo.addObjectPermission(
           role_permission_resolver.resolvePermissionsInRole(authzInfo.getRoles()));
     }
diff --git a/src/main/java/caosdb/server/accessControl/Config.java b/src/main/java/caosdb/server/accessControl/Config.java
new file mode 100644
index 0000000000000000000000000000000000000000..d433a1e90df035e805e46cf5452c1330811ce061
--- /dev/null
+++ b/src/main/java/caosdb/server/accessControl/Config.java
@@ -0,0 +1,86 @@
+package caosdb.server.accessControl;
+
+public class Config {
+  private String[] permissions = {};
+  private String[] roles = {};
+  private String purpose = null;
+  private OneTimeTokenToFile output = null;
+  private int maxAttempts = 1;
+  private int timeout = OneTimeAuthenticationToken.DEFAULT_TIMEOUT_MS;
+  private int attemptsTimeout = OneTimeAuthenticationToken.DEFAULT_ATTEMPTS_TIMEOUT_MS;
+  private String name = AnonymousAuthenticationToken.PRINCIPAL.getUsername();
+
+  public Config() {}
+
+  public String getName() {
+    return name;
+  }
+
+  public void setName(String name) {
+    this.name = name;
+  }
+
+  public int getTimeout() {
+    return timeout;
+  }
+
+  public void setTimeout(int timeout) {
+    this.timeout = timeout;
+  }
+
+  public void setAttemptsTimeoutSeconds(int seconds) {
+    this.setAttemptsTimeout(seconds * 1000);
+  }
+
+  public void setExpiresAfterSeconds(int seconds) {
+    this.setTimeout(seconds * 1000);
+  }
+
+  public void setMaxAttempts(int maxAttempts) {
+    this.maxAttempts = maxAttempts;
+  }
+
+  public int getMaxAttempts() {
+    return maxAttempts;
+  }
+
+  public String[] getPermissions() {
+    return permissions;
+  }
+
+  public String getPurpose() {
+    return purpose;
+  }
+
+  public void setPermissions(String[] permissions) {
+    this.permissions = permissions;
+  }
+
+  public String[] getRoles() {
+    return roles;
+  }
+
+  public void setRoles(String[] roles) {
+    this.roles = roles;
+  }
+
+  public void setPurpose(String purpose) {
+    this.purpose = purpose;
+  }
+
+  public OneTimeTokenToFile getOutput() {
+    return output;
+  }
+
+  public void setOutput(OneTimeTokenToFile output) {
+    this.output = output;
+  }
+
+  public int getAttemptsTimeout() {
+    return attemptsTimeout;
+  }
+
+  public void setAttemptsTimeout(int attemptsTimeout) {
+    this.attemptsTimeout = attemptsTimeout;
+  }
+}
diff --git a/src/main/java/caosdb/server/accessControl/ConsumedInfoCleanupJob.java b/src/main/java/caosdb/server/accessControl/ConsumedInfoCleanupJob.java
index 97652d6f24e74efb1686fe816d0aa83b7b9c2d9f..1f62fa0a8fc72604d885c24123c3d0c17cb49a0a 100644
--- a/src/main/java/caosdb/server/accessControl/ConsumedInfoCleanupJob.java
+++ b/src/main/java/caosdb/server/accessControl/ConsumedInfoCleanupJob.java
@@ -24,6 +24,6 @@ public class ConsumedInfoCleanupJob implements Job {
 
   @Override
   public void execute(JobExecutionContext context) throws JobExecutionException {
-    ConsumedInfo.cleanupConsumedInfo();
+    OneTimeTokenConsumedInfo.cleanupConsumedInfo();
   }
 }
diff --git a/src/main/java/caosdb/server/accessControl/OneTimeAuthenticationToken.java b/src/main/java/caosdb/server/accessControl/OneTimeAuthenticationToken.java
index 886a7ba33e1ec5a528aa2f9cdb787c8f53168d7f..464ae410f353d4c2890386a0d074fc19ed904c83 100644
--- a/src/main/java/caosdb/server/accessControl/OneTimeAuthenticationToken.java
+++ b/src/main/java/caosdb/server/accessControl/OneTimeAuthenticationToken.java
@@ -31,101 +31,14 @@ import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.PrintWriter;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
-import org.apache.shiro.authc.AuthenticationException;
 import org.apache.shiro.subject.Subject;
 import org.eclipse.jetty.util.ajax.JSON;
-import org.quartz.CronScheduleBuilder;
-import org.quartz.Job;
-import org.quartz.JobBuilder;
-import org.quartz.JobDataMap;
-import org.quartz.JobDetail;
-import org.quartz.JobExecutionContext;
-import org.quartz.JobExecutionException;
 import org.quartz.SchedulerException;
-import org.quartz.Trigger;
-import org.quartz.TriggerBuilder;
-
-class ConsumedInfo {
-
-  private static Map<String, ConsumedInfo> consumedOneTimeTokens = new HashMap<>();
-
-  public static void cleanupConsumedInfo() {
-    synchronized (consumedOneTimeTokens) {
-      for (Iterator<Map.Entry<String, ConsumedInfo>> it =
-              consumedOneTimeTokens.entrySet().iterator();
-          it.hasNext(); ) {
-        Map.Entry<String, ConsumedInfo> next = it.next();
-        if (next.getValue().isExpired()) {
-          it.remove();
-        }
-      }
-    }
-  }
-
-  public static void consume(OneTimeAuthenticationToken oneTimeAuthenticationToken) {
-    if (oneTimeAuthenticationToken.isValid()) {
-      String key = ConsumedInfo.getKey(oneTimeAuthenticationToken);
-      ConsumedInfo consumedInfo = null;
-      synchronized (consumedOneTimeTokens) {
-        consumedInfo = consumedOneTimeTokens.get(key);
-        if (consumedInfo == null) {
-          consumedInfo = new ConsumedInfo(oneTimeAuthenticationToken);
-          consumedOneTimeTokens.put(key, consumedInfo);
-        }
-      }
-      consumedInfo.consume();
-    }
-  }
-
-  private OneTimeAuthenticationToken oneTimeAuthenticationToken;
-  private List<Long> attempts = new LinkedList<>();
-
-  public ConsumedInfo(OneTimeAuthenticationToken oneTimeAuthenticationToken) {
-    this.oneTimeAuthenticationToken = oneTimeAuthenticationToken;
-  }
-
-  public static String getKey(OneTimeAuthenticationToken token) {
-    return token.checksum;
-  }
-
-  private int getNoOfAttempts() {
-    return attempts.size();
-  }
-
-  private long getMaxAttempts() {
-    return oneTimeAuthenticationToken.getMaxAttempts();
-  }
-
-  private long getAttemptTimeout() {
-    if (attempts.size() == 0) {
-      return Long.MAX_VALUE;
-    }
-    long firstAttemptTime = attempts.get(0);
-    return firstAttemptTime + oneTimeAuthenticationToken.getAttemptsTimeout();
-  }
-
-  public void consume() {
-    synchronized (attempts) {
-      if (getNoOfAttempts() >= getMaxAttempts()) {
-        throw new AuthenticationException("One-time token was consumed too often.");
-      } else if (getAttemptTimeout() < System.currentTimeMillis()) {
-        throw new AuthenticationException("One-time token attempts timeout expired.");
-      }
-      // TODO log?
-      attempts.add(System.currentTimeMillis());
-    }
-  }
-
-  public boolean isExpired() {
-    return oneTimeAuthenticationToken.isExpired();
-  }
-}
 
 public class OneTimeAuthenticationToken extends SelfValidatingAuthenticationToken {
 
@@ -162,7 +75,7 @@ public class OneTimeAuthenticationToken extends SelfValidatingAuthenticationToke
   }
 
   public void consume() {
-    ConsumedInfo.consume(this);
+    OneTimeTokenConsumedInfo.consume(this);
   }
 
   public OneTimeAuthenticationToken(
@@ -265,151 +178,6 @@ public class OneTimeAuthenticationToken extends SelfValidatingAuthenticationToke
 
   static Map<String, Config> purposes = new HashMap<>();
 
-  public static class Output implements Job {
-    private String file = null;
-    private String schedule = null;
-
-    public Output() {}
-
-    public static void output(OneTimeAuthenticationToken t, String file) throws IOException {
-      try (PrintWriter writer = new PrintWriter(file, "utf-8")) {
-        writer.println(t.toString());
-      }
-    }
-
-    public String getFile() {
-      return file;
-    }
-
-    public void setFile(String file) {
-      this.file = file;
-    }
-
-    public String getSchedule() {
-      return schedule;
-    }
-
-    public void setSchedule(String schedule) {
-      this.schedule = schedule;
-    }
-
-    public void init(Config config) throws IOException, SchedulerException {
-
-      if (this.schedule != null) {
-        generate(config); // test config
-        JobDataMap map = new JobDataMap();
-        map.put("config", config);
-        map.put("file", file);
-        JobDetail outputJob = JobBuilder.newJob(Output.class).setJobData(map).build();
-        Trigger trigger =
-            TriggerBuilder.newTrigger()
-                .withIdentity(config.toString())
-                .withSchedule(CronScheduleBuilder.cronSchedule(this.schedule))
-                .build();
-        CaosDBServer.scheduleJob(outputJob, trigger);
-      } else {
-        output(generate(config), file);
-      }
-    }
-
-    @Override
-    public void execute(JobExecutionContext context) throws JobExecutionException {
-      Config config = (Config) context.getMergedJobDataMap().get("config");
-      String file = context.getMergedJobDataMap().getString("file");
-      try {
-        output(generate(config), file);
-      } catch (IOException e) {
-        // TODO log
-        e.printStackTrace();
-      }
-    }
-  }
-
-  public static class Config {
-    private String[] permissions = {};
-    private String[] roles = {};
-    private String purpose = null;
-    private Output output = null;
-    private int maxAttempts = 1;
-    private int timeout = DEFAULT_TIMEOUT_MS;
-    private int attemptsTimeout = DEFAULT_ATTEMPTS_TIMEOUT_MS;
-    private String name = AnonymousAuthenticationToken.PRINCIPAL.getUsername();
-
-    public Config() {}
-
-    public String getName() {
-      return name;
-    }
-
-    public void setName(String name) {
-      this.name = name;
-    }
-
-    public int getTimeout() {
-      return timeout;
-    }
-
-    public void setTimeout(int timeout) {
-      this.timeout = timeout;
-    }
-
-    public void setAttemptsTimeoutSeconds(int seconds) {
-      this.setAttemptsTimeout(seconds * 1000);
-    }
-
-    public void setExpiresAfterSeconds(int seconds) {
-      this.setTimeout(seconds * 1000);
-    }
-
-    public void setMaxAttempts(int maxAttempts) {
-      this.maxAttempts = maxAttempts;
-    }
-
-    public int getMaxAttempts() {
-      return maxAttempts;
-    }
-
-    public String[] getPermissions() {
-      return permissions;
-    }
-
-    public String getPurpose() {
-      return purpose;
-    }
-
-    public void setPermissions(String[] permissions) {
-      this.permissions = permissions;
-    }
-
-    public String[] getRoles() {
-      return roles;
-    }
-
-    public void setRoles(String[] roles) {
-      this.roles = roles;
-    }
-
-    public void setPurpose(String purpose) {
-      this.purpose = purpose;
-    }
-
-    public Output getOutput() {
-      return output;
-    }
-
-    public void setOutput(Output output) {
-      this.output = output;
-    }
-
-    public int getAttemptsTimeout() {
-      return attemptsTimeout;
-    }
-
-    public void setAttemptsTimeout(int attemptsTimeout) {
-      this.attemptsTimeout = attemptsTimeout;
-    }
-  }
-
   public static Map<String, Config> getPurposeMap() {
     return purposes;
   }
diff --git a/src/main/java/caosdb/server/accessControl/OneTimeTokenConsumedInfo.java b/src/main/java/caosdb/server/accessControl/OneTimeTokenConsumedInfo.java
new file mode 100644
index 0000000000000000000000000000000000000000..a7122c2b28ed38baaf60c8da6b404b1fcf97c349
--- /dev/null
+++ b/src/main/java/caosdb/server/accessControl/OneTimeTokenConsumedInfo.java
@@ -0,0 +1,83 @@
+package caosdb.server.accessControl;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import org.apache.shiro.authc.AuthenticationException;
+
+class OneTimeTokenConsumedInfo {
+
+  private static Map<String, OneTimeTokenConsumedInfo> consumedOneTimeTokens = new HashMap<>();
+
+  public static void cleanupConsumedInfo() {
+    synchronized (consumedOneTimeTokens) {
+      for (Iterator<Map.Entry<String, OneTimeTokenConsumedInfo>> it =
+              consumedOneTimeTokens.entrySet().iterator();
+          it.hasNext(); ) {
+        Map.Entry<String, OneTimeTokenConsumedInfo> next = it.next();
+        if (next.getValue().isExpired()) {
+          it.remove();
+        }
+      }
+    }
+  }
+
+  public static void consume(OneTimeAuthenticationToken oneTimeAuthenticationToken) {
+    if (oneTimeAuthenticationToken.isValid()) {
+      String key = OneTimeTokenConsumedInfo.getKey(oneTimeAuthenticationToken);
+      OneTimeTokenConsumedInfo consumedInfo = null;
+      synchronized (consumedOneTimeTokens) {
+        consumedInfo = consumedOneTimeTokens.get(key);
+        if (consumedInfo == null) {
+          consumedInfo = new OneTimeTokenConsumedInfo(oneTimeAuthenticationToken);
+          consumedOneTimeTokens.put(key, consumedInfo);
+        }
+      }
+      consumedInfo.consume();
+    }
+  }
+
+  private OneTimeAuthenticationToken oneTimeAuthenticationToken;
+  private List<Long> attempts = new LinkedList<>();
+
+  public OneTimeTokenConsumedInfo(OneTimeAuthenticationToken oneTimeAuthenticationToken) {
+    this.oneTimeAuthenticationToken = oneTimeAuthenticationToken;
+  }
+
+  public static String getKey(OneTimeAuthenticationToken token) {
+    return token.checksum;
+  }
+
+  private int getNoOfAttempts() {
+    return attempts.size();
+  }
+
+  private long getMaxAttempts() {
+    return oneTimeAuthenticationToken.getMaxAttempts();
+  }
+
+  private long getAttemptTimeout() {
+    if (attempts.size() == 0) {
+      return Long.MAX_VALUE;
+    }
+    long firstAttemptTime = attempts.get(0);
+    return firstAttemptTime + oneTimeAuthenticationToken.getAttemptsTimeout();
+  }
+
+  public void consume() {
+    synchronized (attempts) {
+      if (getNoOfAttempts() >= getMaxAttempts()) {
+        throw new AuthenticationException("One-time token was consumed too often.");
+      } else if (getAttemptTimeout() < System.currentTimeMillis()) {
+        throw new AuthenticationException("One-time token attempts timeout expired.");
+      }
+      attempts.add(System.currentTimeMillis());
+    }
+  }
+
+  public boolean isExpired() {
+    return oneTimeAuthenticationToken.isExpired();
+  }
+}
diff --git a/src/main/java/caosdb/server/accessControl/OneTimeTokenRealm.java b/src/main/java/caosdb/server/accessControl/OneTimeTokenRealm.java
deleted file mode 100644
index 1f7d4da4a45a75368fc0d76ae35ad06ad80da92e..0000000000000000000000000000000000000000
--- a/src/main/java/caosdb/server/accessControl/OneTimeTokenRealm.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/// *
-// * ** header v3.0
-// * This file is a part of the CaosDB Project.
-// *
-// * Copyright (C) 2018 Research Group Biomedical Physics,
-// * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
-// *
-// * This program is free software: you can redistribute it and/or modify
-// * it under the terms of the GNU Affero General Public License as
-// * published by the Free Software Foundation, either version 3 of the
-// * License, or (at your option) any later version.
-// *
-// * This program is distributed in the hope that it will be useful,
-// * but WITHOUT ANY WARRANTY; without even the implied warranty of
-// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// * GNU Affero General Public License for more details.
-// *
-// * You should have received a copy of the GNU Affero General Public License
-// * along with this program. If not, see <https://www.gnu.org/licenses/>.
-// *
-// * ** end header
-// */
-// package caosdb.server.accessControl;
-//
-// import caosdb.server.accessControl.CaosDBAuthorizingRealm.PermissionAuthenticationInfo;
-// import org.apache.shiro.authc.AuthenticationException;
-// import org.apache.shiro.authc.AuthenticationInfo;
-// import org.apache.shiro.authc.AuthenticationToken;
-// import org.apache.shiro.authc.credential.AllowAllCredentialsMatcher;
-//
-// public class OneTimeTokenRealm extends SessionTokenRealm {
-//
-//  @Override
-//  protected AuthenticationInfo doGetAuthenticationInfo(final AuthenticationToken token)
-//      throws AuthenticationException {
-//
-//    final AuthenticationInfo info = super.doGetAuthenticationInfo(token);
-//    if (info != null) {
-//      return new PermissionAuthenticationInfo(
-//          info.getPrincipals(),
-//          ((OneTimeAuthenticationToken) token).getPermissions(),
-//          ((OneTimeAuthenticationToken) token).getRoles());
-//    }
-//
-//    return null;
-//  }
-//
-//  public OneTimeTokenRealm() {
-//    setAuthenticationTokenClass(OneTimeAuthenticationToken.class);
-//    setCredentialsMatcher(new AllowAllCredentialsMatcher());
-//    setCachingEnabled(false);
-//    setAuthenticationCachingEnabled(false);
-//    // setAuthorizationCachingEnabled(false);
-//  }
-// }
diff --git a/src/main/java/caosdb/server/accessControl/OneTimeTokenToFile.java b/src/main/java/caosdb/server/accessControl/OneTimeTokenToFile.java
new file mode 100644
index 0000000000000000000000000000000000000000..ea56899a827289e1b9b440ca67a26e414d50221a
--- /dev/null
+++ b/src/main/java/caosdb/server/accessControl/OneTimeTokenToFile.java
@@ -0,0 +1,75 @@
+package caosdb.server.accessControl;
+
+import caosdb.server.CaosDBServer;
+import java.io.IOException;
+import java.io.PrintWriter;
+import org.quartz.CronScheduleBuilder;
+import org.quartz.Job;
+import org.quartz.JobBuilder;
+import org.quartz.JobDataMap;
+import org.quartz.JobDetail;
+import org.quartz.JobExecutionContext;
+import org.quartz.JobExecutionException;
+import org.quartz.SchedulerException;
+import org.quartz.Trigger;
+import org.quartz.TriggerBuilder;
+
+public class OneTimeTokenToFile implements Job {
+  private String file = null;
+  private String schedule = null;
+
+  public OneTimeTokenToFile() {}
+
+  public static void output(OneTimeAuthenticationToken t, String file) throws IOException {
+    try (PrintWriter writer = new PrintWriter(file, "utf-8")) {
+      writer.println(t.toString());
+    }
+  }
+
+  public String getFile() {
+    return file;
+  }
+
+  public void setFile(String file) {
+    this.file = file;
+  }
+
+  public String getSchedule() {
+    return schedule;
+  }
+
+  public void setSchedule(String schedule) {
+    this.schedule = schedule;
+  }
+
+  public void init(Config config) throws IOException, SchedulerException {
+
+    if (this.schedule != null) {
+      OneTimeAuthenticationToken.generate(config); // test config
+      JobDataMap map = new JobDataMap();
+      map.put("config", config);
+      map.put("file", file);
+      JobDetail outputJob = JobBuilder.newJob(OneTimeTokenToFile.class).setJobData(map).build();
+      Trigger trigger =
+          TriggerBuilder.newTrigger()
+              .withIdentity(config.toString())
+              .withSchedule(CronScheduleBuilder.cronSchedule(this.schedule))
+              .build();
+      CaosDBServer.scheduleJob(outputJob, trigger);
+    } else {
+      output(OneTimeAuthenticationToken.generate(config), file);
+    }
+  }
+
+  @Override
+  public void execute(JobExecutionContext context) throws JobExecutionException {
+    Config config = (Config) context.getMergedJobDataMap().get("config");
+    String file = context.getMergedJobDataMap().getString("file");
+    try {
+      output(OneTimeAuthenticationToken.generate(config), file);
+    } catch (IOException e) {
+      // TODO log
+      e.printStackTrace();
+    }
+  }
+}
diff --git a/src/test/java/caosdb/server/authentication/AuthTokenTest.java b/src/test/java/caosdb/server/authentication/AuthTokenTest.java
index 088d8d0e8de1e062ce02f674d5ac56ff902e5631..b8b1da51cc78202f2e487662bc6a8260df4fa61b 100644
--- a/src/test/java/caosdb/server/authentication/AuthTokenTest.java
+++ b/src/test/java/caosdb/server/authentication/AuthTokenTest.java
@@ -29,8 +29,8 @@ import caosdb.server.CaosDBServer;
 import caosdb.server.ServerProperties;
 import caosdb.server.accessControl.AnonymousAuthenticationToken;
 import caosdb.server.accessControl.AuthenticationUtils;
+import caosdb.server.accessControl.Config;
 import caosdb.server.accessControl.OneTimeAuthenticationToken;
-import caosdb.server.accessControl.OneTimeAuthenticationToken.Config;
 import caosdb.server.accessControl.Principal;
 import caosdb.server.accessControl.SelfValidatingAuthenticationToken;
 import caosdb.server.accessControl.SessionToken;
diff --git a/src/test/java/caosdb/server/permissions/EntityACLTest.java b/src/test/java/caosdb/server/permissions/EntityACLTest.java
index d62cb625c8319e676614bf6770eea2f9794daaee..1953896719c5cf5eb202cf48c186a8192c4136db 100644
--- a/src/test/java/caosdb/server/permissions/EntityACLTest.java
+++ b/src/test/java/caosdb/server/permissions/EntityACLTest.java
@@ -24,17 +24,9 @@ package caosdb.server.permissions;
 
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
-
-import caosdb.server.CaosDBServer;
-import caosdb.server.accessControl.AnonymousAuthenticationToken;
-import caosdb.server.accessControl.AuthenticationUtils;
-import caosdb.server.accessControl.OneTimeAuthenticationToken;
-import caosdb.server.accessControl.OneTimeAuthenticationToken.Config;
-import caosdb.server.resource.AbstractCaosDBServerResource;
-import caosdb.server.resource.AbstractCaosDBServerResource.XMLParser;
-import caosdb.server.utils.Utils;
 import java.io.IOException;
 import java.util.BitSet;
+import java.util.HashSet;
 import java.util.LinkedList;
 import org.apache.shiro.SecurityUtils;
 import org.apache.shiro.subject.Subject;
@@ -43,6 +35,21 @@ import org.jdom2.JDOMException;
 import org.junit.Assert;
 import org.junit.BeforeClass;
 import org.junit.Test;
+import caosdb.server.CaosDBServer;
+import caosdb.server.accessControl.AnonymousAuthenticationToken;
+import caosdb.server.accessControl.AuthenticationUtils;
+import caosdb.server.accessControl.Config;
+import caosdb.server.accessControl.OneTimeAuthenticationToken;
+import caosdb.server.accessControl.Role;
+import caosdb.server.database.BackendTransaction;
+import caosdb.server.database.access.Access;
+import caosdb.server.database.backend.interfaces.RetrievePermissionRulesImpl;
+import caosdb.server.database.backend.interfaces.RetrieveRoleImpl;
+import caosdb.server.database.exceptions.TransactionException;
+import caosdb.server.database.misc.TransactionBenchmark;
+import caosdb.server.resource.AbstractCaosDBServerResource;
+import caosdb.server.resource.AbstractCaosDBServerResource.XMLParser;
+import caosdb.server.utils.Utils;
 
 public class EntityACLTest {
 
@@ -54,11 +61,53 @@ public class EntityACLTest {
     return value;
   }
 
+  /** a no-op mock-up which resolved all rules to an empty set of permissions. */
+  public static class RetrievePermissionRulesMockup implements RetrievePermissionRulesImpl {
+
+    public RetrievePermissionRulesMockup(Access a) {}
+
+    @Override
+    public void setTransactionBenchmark(TransactionBenchmark b) {}
+
+    @Override
+    public TransactionBenchmark getBenchmark() {
+      return null;
+    }
+
+    @Override
+    public HashSet<PermissionRule> retrievePermissionRule(String role) throws TransactionException {
+      return new HashSet<>();
+    }
+  }
+
+  /** a mock-up which returns null */
+  public static class RetrieveRoleMockup implements RetrieveRoleImpl {
+
+    public RetrieveRoleMockup(Access a) {}
+
+    @Override
+    public void setTransactionBenchmark(TransactionBenchmark b) {}
+
+    @Override
+    public TransactionBenchmark getBenchmark() {
+      return null;
+    }
+
+    @Override
+    public Role retrieve(String role) throws TransactionException {
+      return null;
+    }
+  }
+
   @BeforeClass
   public static void init() throws IOException {
     CaosDBServer.initServerProperties();
     CaosDBServer.initShiro();
     assertNotNull(EntityACL.GLOBAL_PERMISSIONS);
+
+    BackendTransaction.setImpl(
+        RetrievePermissionRulesImpl.class, RetrievePermissionRulesMockup.class);
+    BackendTransaction.setImpl(RetrieveRoleImpl.class, RetrieveRoleMockup.class);
   }
 
   @Test
diff --git a/src/test/java/caosdb/server/resource/TestAbstractCaosDBServerResource.java b/src/test/java/caosdb/server/resource/TestAbstractCaosDBServerResource.java
index 81baabd4797842f1cbbc61f990d6ea580553de85..e9a7cffc66e4c18551ea3375a87489e2b15dc279 100644
--- a/src/test/java/caosdb/server/resource/TestAbstractCaosDBServerResource.java
+++ b/src/test/java/caosdb/server/resource/TestAbstractCaosDBServerResource.java
@@ -2,18 +2,12 @@ package caosdb.server.resource;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
-
-import caosdb.server.CaosDBException;
-import caosdb.server.CaosDBServer;
-import caosdb.server.ServerProperties;
-import caosdb.server.accessControl.AnonymousAuthenticationToken;
-import caosdb.server.accessControl.AnonymousRealm;
-import caosdb.server.database.backend.implementation.MySQL.ConnectionException;
 import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Paths;
 import java.security.NoSuchAlgorithmException;
 import java.sql.SQLException;
+import java.util.HashSet;
 import org.apache.shiro.mgt.DefaultSecurityManager;
 import org.apache.shiro.subject.Subject;
 import org.apache.shiro.subject.support.DelegatingSubject;
@@ -24,14 +18,70 @@ import org.junit.Test;
 import org.junit.rules.TemporaryFolder;
 import org.restlet.data.Reference;
 import org.restlet.representation.Representation;
+import caosdb.server.CaosDBException;
+import caosdb.server.CaosDBServer;
+import caosdb.server.ServerProperties;
+import caosdb.server.accessControl.AnonymousAuthenticationToken;
+import caosdb.server.accessControl.AnonymousRealm;
+import caosdb.server.accessControl.Role;
+import caosdb.server.database.BackendTransaction;
+import caosdb.server.database.access.Access;
+import caosdb.server.database.backend.implementation.MySQL.ConnectionException;
+import caosdb.server.database.backend.interfaces.RetrievePermissionRulesImpl;
+import caosdb.server.database.backend.interfaces.RetrieveRoleImpl;
+import caosdb.server.database.exceptions.TransactionException;
+import caosdb.server.database.misc.TransactionBenchmark;
+import caosdb.server.permissions.PermissionRule;
 
 public class TestAbstractCaosDBServerResource {
 
   @Rule public TemporaryFolder tempFolder = new TemporaryFolder();
 
+  /** a no-op mock-up which resolved all rules to an empty set of permissions. */
+  public static class RetrievePermissionRulesMockup implements RetrievePermissionRulesImpl {
+
+    public RetrievePermissionRulesMockup(Access a) {}
+
+    @Override
+    public void setTransactionBenchmark(TransactionBenchmark b) {}
+
+    @Override
+    public TransactionBenchmark getBenchmark() {
+      return null;
+    }
+
+    @Override
+    public HashSet<PermissionRule> retrievePermissionRule(String role) throws TransactionException {
+      return new HashSet<>();
+    }
+  }
+
+  /** a no-op mock-up which returns null */
+  public static class RetrieveRoleMockup implements RetrieveRoleImpl {
+
+    public RetrieveRoleMockup(Access a) {}
+
+    @Override
+    public void setTransactionBenchmark(TransactionBenchmark b) {}
+
+    @Override
+    public TransactionBenchmark getBenchmark() {
+      return null;
+    }
+
+    @Override
+    public Role retrieve(String role) throws TransactionException {
+      return null;
+    }
+  }
+
   @BeforeClass
   public static void initServerProperties() throws IOException {
     CaosDBServer.initServerProperties();
+
+    BackendTransaction.setImpl(
+        RetrievePermissionRulesImpl.class, RetrievePermissionRulesMockup.class);
+    BackendTransaction.setImpl(RetrieveRoleImpl.class, RetrieveRoleMockup.class);
   }
 
   @Test
diff --git a/src/test/java/caosdb/server/utils/WebinterfaceUtilsTest.java b/src/test/java/caosdb/server/utils/WebinterfaceUtilsTest.java
index 22dc38c7636ba26060cc58d14f5d4cf5b5774400..075c8d998acdfc7f897f9429de468034a4dc022e 100644
--- a/src/test/java/caosdb/server/utils/WebinterfaceUtilsTest.java
+++ b/src/test/java/caosdb/server/utils/WebinterfaceUtilsTest.java
@@ -29,7 +29,9 @@ public class WebinterfaceUtilsTest {
     String ref = utils.getWebinterfaceURI("sub");
     String contextRoot = CaosDBServer.getServerProperty(ServerProperties.KEY_CONTEXT_ROOT);
     contextRoot =
-        contextRoot != null ? "/" + contextRoot.replaceFirst("^/", "").replaceFirst("/$", "") : "";
+        contextRoot != null && contextRoot.length() > 0
+            ? "/" + contextRoot.replaceFirst("^/", "").replaceFirst("/$", "")
+            : "";
 
     assertEquals("https://host:2345" + contextRoot + "/webinterface/" + buildNumber + "/sub", ref);
   }