diff --git a/src/main/java/org/caosdb/server/accessControl/SinglePermissionSubject.java b/src/main/java/org/caosdb/server/accessControl/SinglePermissionSubject.java
new file mode 100644
index 0000000000000000000000000000000000000000..2c3a3479420c5f0642e0d42bf53b717ab0219571
--- /dev/null
+++ b/src/main/java/org/caosdb/server/accessControl/SinglePermissionSubject.java
@@ -0,0 +1,210 @@
+package org.caosdb.server.accessControl;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.Callable;
+import org.apache.shiro.authc.AuthenticationException;
+import org.apache.shiro.authc.AuthenticationToken;
+import org.apache.shiro.authz.AuthorizationException;
+import org.apache.shiro.authz.Permission;
+import org.apache.shiro.authz.permission.WildcardPermission;
+import org.apache.shiro.session.Session;
+import org.apache.shiro.subject.ExecutionException;
+import org.apache.shiro.subject.PrincipalCollection;
+import org.apache.shiro.subject.Subject;
+
+public class SinglePermissionSubject implements Subject {
+
+  private WildcardPermission permission;
+
+  public SinglePermissionSubject(String permission) {
+    this.permission = new WildcardPermission(permission);
+  }
+
+  @Override
+  public Object getPrincipal() {
+    throw new UnsupportedOperationException("This method should never be called");
+  }
+
+  @Override
+  public PrincipalCollection getPrincipals() {
+    throw new UnsupportedOperationException("This method should never be called");
+  }
+
+  @Override
+  public boolean isPermitted(String permission) {
+    return this.permission.implies(new WildcardPermission(permission));
+  }
+
+  @Override
+  public boolean isPermitted(Permission permission) {
+    return this.permission.implies(permission);
+  }
+
+  @Override
+  public boolean[] isPermitted(String... permissions) {
+    boolean[] result = new boolean[permissions.length];
+    for (int i = 0; i < result.length; i++) {
+      result[i] = this.permission.implies(new WildcardPermission(permissions[i]));
+    }
+    return result;
+  }
+
+  @Override
+  public boolean[] isPermitted(List<Permission> permissions) {
+    boolean[] result = new boolean[permissions.size()];
+    for (int i = 0; i < result.length; i++) {
+      result[i] = this.permission.implies(permissions.get(i));
+    }
+    return result;
+  }
+
+  @Override
+  public boolean isPermittedAll(String... permissions) {
+    boolean result = true;
+    for (int i = 0; i < permissions.length; i++) {
+      result &= this.permission.implies(new WildcardPermission(permissions[i]));
+    }
+    return result;
+  }
+
+  @Override
+  public boolean isPermittedAll(Collection<Permission> permissions) {
+    Boolean result = true;
+    Iterator<Permission> iterator = permissions.iterator();
+    while (iterator.hasNext()) {
+      result &= this.permission.implies(iterator.next());
+    }
+    return result;
+  }
+
+  @Override
+  public void checkPermission(String permission) throws AuthorizationException {
+    if (!isPermitted(permission)) {
+      throw new AuthenticationException("Not permitted: " + permission);
+    }
+  }
+
+  @Override
+  public void checkPermission(Permission permission) throws AuthorizationException {
+    if (!isPermitted(permission)) {
+      throw new AuthenticationException("Not permitted: " + permission.toString());
+    }
+  }
+
+  @Override
+  public void checkPermissions(String... permissions) throws AuthorizationException {
+    if (!isPermittedAll(permissions)) {
+      throw new AuthenticationException("Not permitted: " + permissions.toString());
+    }
+  }
+
+  @Override
+  public void checkPermissions(Collection<Permission> permissions) throws AuthorizationException {
+    if (!isPermittedAll(permissions)) {
+      throw new AuthenticationException("Not permitted: " + permissions.toString());
+    }
+  }
+
+  @Override
+  public boolean hasRole(String roleIdentifier) {
+    throw new UnsupportedOperationException("This method should never be called");
+  }
+
+  @Override
+  public boolean[] hasRoles(List<String> roleIdentifiers) {
+    throw new UnsupportedOperationException("This method should never be called");
+  }
+
+  @Override
+  public boolean hasAllRoles(Collection<String> roleIdentifiers) {
+    throw new UnsupportedOperationException("This method should never be called");
+  }
+
+  @Override
+  public void checkRole(String roleIdentifier) throws AuthorizationException {
+    throw new UnsupportedOperationException("This method should never be called");
+  }
+
+  @Override
+  public void checkRoles(Collection<String> roleIdentifiers) throws AuthorizationException {
+    throw new UnsupportedOperationException("This method should never be called");
+  }
+
+  @Override
+  public void checkRoles(String... roleIdentifiers) throws AuthorizationException {
+    throw new UnsupportedOperationException("This method should never be called");
+  }
+
+  @Override
+  public void login(AuthenticationToken token) throws AuthenticationException {
+    throw new UnsupportedOperationException("This method should never be called");
+  }
+
+  @Override
+  public boolean isAuthenticated() {
+    throw new UnsupportedOperationException("This method should never be called");
+  }
+
+  @Override
+  public boolean isRemembered() {
+    throw new UnsupportedOperationException("This method should never be called");
+  }
+
+  @Override
+  public Session getSession() {
+    throw new UnsupportedOperationException("This method should never be called");
+  }
+
+  @Override
+  public Session getSession(boolean create) {
+    throw new UnsupportedOperationException("This method should never be called");
+  }
+
+  @Override
+  public void logout() {
+    throw new UnsupportedOperationException("This method should never be called");
+  }
+
+  @Override
+  public <V> V execute(Callable<V> callable) throws ExecutionException {
+    throw new UnsupportedOperationException("This method should never be called");
+  }
+
+  @Override
+  public void execute(Runnable runnable) {
+    throw new UnsupportedOperationException("This method should never be called");
+  }
+
+  @Override
+  public <V> Callable<V> associateWith(Callable<V> callable) {
+    throw new UnsupportedOperationException("This method should never be called");
+  }
+
+  @Override
+  public Runnable associateWith(Runnable runnable) {
+    throw new UnsupportedOperationException("This method should never be called");
+  }
+
+  @Override
+  public void runAs(PrincipalCollection principals)
+      throws NullPointerException, IllegalStateException {
+    throw new UnsupportedOperationException("This method should never be called");
+  }
+
+  @Override
+  public boolean isRunAs() {
+    throw new UnsupportedOperationException("This method should never be called");
+  }
+
+  @Override
+  public PrincipalCollection getPreviousPrincipals() {
+    throw new UnsupportedOperationException("This method should never be called");
+  }
+
+  @Override
+  public PrincipalCollection releaseRunAs() {
+    throw new UnsupportedOperationException("This method should never be called");
+  }
+}
diff --git a/src/main/java/org/caosdb/server/accessControl/UserSources.java b/src/main/java/org/caosdb/server/accessControl/UserSources.java
index bbbb1bcbc75dd817380cc99a73dbce576f067c9d..760c3e901d85c863504d1d2732083656f4502194 100644
--- a/src/main/java/org/caosdb/server/accessControl/UserSources.java
+++ b/src/main/java/org/caosdb/server/accessControl/UserSources.java
@@ -26,6 +26,7 @@ package org.caosdb.server.accessControl;
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.lang.reflect.InvocationTargetException;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Set;
@@ -169,6 +170,10 @@ public class UserSources extends HashMap<String, UserSource> {
    * @return A set of user roles.
    */
   public static Set<String> resolveRoles(String realm, final String username) {
+    if (AnonymousAuthenticationToken.PRINCIPAL.getRealm().equals(realm)
+        && AnonymousAuthenticationToken.PRINCIPAL.getUsername().equals(username)) {
+      return Collections.singleton(Role.ANONYMOUS_ROLE.toString());
+    }
     if (realm == null) {
       realm = guessRealm(username);
     }
@@ -237,7 +242,8 @@ public class UserSources extends HashMap<String, UserSource> {
   }
 
   public static boolean isRoleExisting(final String role) {
-    final RetrieveRoleTransaction t = new RetrieveRoleTransaction(role);
+    final RetrieveRoleTransaction t =
+        new RetrieveRoleTransaction(role, new SinglePermissionSubject("ACM:*:RETRIEVE:*"));
     try {
       t.execute();
       return true;
diff --git a/src/main/java/org/caosdb/server/grpc/AccessControlManagementServiceImpl.java b/src/main/java/org/caosdb/server/grpc/AccessControlManagementServiceImpl.java
index 18dd29a2c6ccd95de74ff530a7d574b14e3b4b52..712258207527bbbcff27d74c5c19220bce857650 100644
--- a/src/main/java/org/caosdb/server/grpc/AccessControlManagementServiceImpl.java
+++ b/src/main/java/org/caosdb/server/grpc/AccessControlManagementServiceImpl.java
@@ -430,6 +430,7 @@ public class AccessControlManagementServiceImpl extends AccessControlManagementS
   public void listUsers(
       ListUsersRequest request, StreamObserver<ListUsersResponse> responseObserver) {
     try {
+      AuthInterceptor.bindSubject();
       final ListUsersResponse response = listUsersTransaction(request);
       responseObserver.onNext(response);
       responseObserver.onCompleted();
@@ -443,6 +444,7 @@ public class AccessControlManagementServiceImpl extends AccessControlManagementS
   public void listRoles(
       ListRolesRequest request, StreamObserver<ListRolesResponse> responseObserver) {
     try {
+      AuthInterceptor.bindSubject();
       final ListRolesResponse response = listRolesTransaction(request);
       responseObserver.onNext(response);
       responseObserver.onCompleted();
@@ -456,6 +458,7 @@ public class AccessControlManagementServiceImpl extends AccessControlManagementS
   public void createSingleRole(
       CreateSingleRoleRequest request, StreamObserver<CreateSingleRoleResponse> responseObserver) {
     try {
+      AuthInterceptor.bindSubject();
       final CreateSingleRoleResponse response = createSingleRoleTransaction(request);
       responseObserver.onNext(response);
       responseObserver.onCompleted();
@@ -470,6 +473,7 @@ public class AccessControlManagementServiceImpl extends AccessControlManagementS
       RetrieveSingleRoleRequest request,
       StreamObserver<RetrieveSingleRoleResponse> responseObserver) {
     try {
+      AuthInterceptor.bindSubject();
       final RetrieveSingleRoleResponse response = retrieveSingleRoleTransaction(request);
       responseObserver.onNext(response);
       responseObserver.onCompleted();
@@ -483,6 +487,7 @@ public class AccessControlManagementServiceImpl extends AccessControlManagementS
   public void createSingleUser(
       CreateSingleUserRequest request, StreamObserver<CreateSingleUserResponse> responseObserver) {
     try {
+      AuthInterceptor.bindSubject();
       final CreateSingleUserResponse response = createSingleUserTransaction(request);
       responseObserver.onNext(response);
       responseObserver.onCompleted();
@@ -496,6 +501,7 @@ public class AccessControlManagementServiceImpl extends AccessControlManagementS
   public void updateSingleUser(
       UpdateSingleUserRequest request, StreamObserver<UpdateSingleUserResponse> responseObserver) {
     try {
+      AuthInterceptor.bindSubject();
       final UpdateSingleUserResponse response = updateSingleUserTransaction(request);
       responseObserver.onNext(response);
       responseObserver.onCompleted();
@@ -510,6 +516,7 @@ public class AccessControlManagementServiceImpl extends AccessControlManagementS
       RetrieveSingleUserRequest request,
       StreamObserver<RetrieveSingleUserResponse> responseObserver) {
     try {
+      AuthInterceptor.bindSubject();
       final RetrieveSingleUserResponse response = retrieveSingleUserTransaction(request);
       responseObserver.onNext(response);
       responseObserver.onCompleted();
@@ -523,6 +530,7 @@ public class AccessControlManagementServiceImpl extends AccessControlManagementS
   public void deleteSingleUser(
       DeleteSingleUserRequest request, StreamObserver<DeleteSingleUserResponse> responseObserver) {
     try {
+      AuthInterceptor.bindSubject();
       final DeleteSingleUserResponse response = deleteSingleUserTransaction(request);
       responseObserver.onNext(response);
       responseObserver.onCompleted();
@@ -536,6 +544,7 @@ public class AccessControlManagementServiceImpl extends AccessControlManagementS
   public void deleteSingleRole(
       DeleteSingleRoleRequest request, StreamObserver<DeleteSingleRoleResponse> responseObserver) {
     try {
+      AuthInterceptor.bindSubject();
       final DeleteSingleRoleResponse response = deleteSingleRoleTransaction(request);
       responseObserver.onNext(response);
       responseObserver.onCompleted();
@@ -549,6 +558,7 @@ public class AccessControlManagementServiceImpl extends AccessControlManagementS
   public void updateSingleRole(
       UpdateSingleRoleRequest request, StreamObserver<UpdateSingleRoleResponse> responseObserver) {
     try {
+      AuthInterceptor.bindSubject();
       final UpdateSingleRoleResponse response = updateSingleRoleTransaction(request);
       responseObserver.onNext(response);
       responseObserver.onCompleted();
@@ -563,6 +573,7 @@ public class AccessControlManagementServiceImpl extends AccessControlManagementS
       ListKnownPermissionsRequest request,
       StreamObserver<ListKnownPermissionsResponse> responseObserver) {
     try {
+      AuthInterceptor.bindSubject();
       final ListKnownPermissionsResponse response = listKnownPermissions(request);
       responseObserver.onNext(response);
       responseObserver.onCompleted();
@@ -573,6 +584,10 @@ public class AccessControlManagementServiceImpl extends AccessControlManagementS
   }
 
   public static void handleException(StreamObserver<?> responseObserver, Exception e) {
+    String description = e.getMessage();
+    if (description == null || description.isBlank()) {
+      description = "Unknown Error. Please Report!";
+    }
     if (e instanceof UnauthorizedException) {
       Subject subject = SecurityUtils.getSubject();
       if (AuthenticationUtils.isAnonymous(subject)) {
@@ -582,17 +597,17 @@ public class AccessControlManagementServiceImpl extends AccessControlManagementS
       } else {
         responseObserver.onError(
             new StatusException(
-                Status.PERMISSION_DENIED.withCause(e).withDescription(e.getMessage())));
+                Status.PERMISSION_DENIED.withCause(e).withDescription(description)));
         return;
       }
     } else if (e == ServerMessages.ROLE_DOES_NOT_EXIST
         || e == ServerMessages.ACCOUNT_DOES_NOT_EXIST) {
       responseObserver.onError(
-          new StatusException(Status.NOT_FOUND.withDescription(e.getMessage()).withCause(e)));
+          new StatusException(Status.NOT_FOUND.withDescription(description).withCause(e)));
       return;
     }
     e.printStackTrace();
     responseObserver.onError(
-        new StatusException(Status.UNKNOWN.withDescription(e.getMessage()).withCause(e)));
+        new StatusException(Status.UNKNOWN.withDescription(description).withCause(e)));
   }
 }
diff --git a/src/main/java/org/caosdb/server/grpc/AuthInterceptor.java b/src/main/java/org/caosdb/server/grpc/AuthInterceptor.java
index b58769d4ba6bff28ea922160a29b9747ff99e992..5d06f05c7e03a3130a9006c4a1a399ddf3df0d27 100644
--- a/src/main/java/org/caosdb/server/grpc/AuthInterceptor.java
+++ b/src/main/java/org/caosdb/server/grpc/AuthInterceptor.java
@@ -39,6 +39,7 @@ import java.util.regex.Pattern;
 import org.apache.shiro.SecurityUtils;
 import org.apache.shiro.authc.AuthenticationException;
 import org.apache.shiro.subject.Subject;
+import org.apache.shiro.util.ThreadContext;
 import org.caosdb.server.CaosDBServer;
 import org.caosdb.server.ServerProperties;
 import org.caosdb.server.accessControl.AnonymousAuthenticationToken;
@@ -72,6 +73,13 @@ public class AuthInterceptor implements ServerInterceptor {
   public static final Predicate<String> SESSION_TOKEN_COOKIE_PREFIX_PREDICATE =
       SESSION_TOKEN_COOKIE_PREFIX_PATTERN.asPredicate();
 
+  @SuppressWarnings("unused")
+  public static Subject bindSubject() {
+    Subject subject = (Subject) SUBJECT_KEY.get();
+    ThreadContext.bind(subject);
+    return subject;
+  }
+
   public final Metadata expiredSessionMetadata() {
     Metadata metadata = new Metadata();
     metadata.put(CookieSetter.SET_COOKIE, CookieSetter.EXPIRED_SESSION_COOKIE);
@@ -102,7 +110,7 @@ public class AuthInterceptor implements ServerInterceptor {
     final String password = split[1];
     final RealmUsernamePasswordToken token =
         new RealmUsernamePasswordToken(UserSources.getDefaultRealm(), username, password);
-    final org.apache.shiro.subject.Subject subject = SecurityUtils.getSubject();
+    final Subject subject = SecurityUtils.getSubject();
     subject.login(token);
     return subject;
   }
@@ -112,6 +120,16 @@ public class AuthInterceptor implements ServerInterceptor {
       final ServerCall<ReqT, RespT> call,
       final Metadata headers,
       final ServerCallHandler<ReqT, RespT> next) {
+    ThreadContext.remove();
+    Subject user = SecurityUtils.getSubject();
+    System.out.println(
+        "interceptCall: "
+            + Long.toString(Thread.currentThread().getId())
+            + " "
+            + Thread.currentThread().getName()
+            + " subject: "
+            + user.toString());
+
     String authentication = headers.get(AUTHENTICATION_HEADER);
     if (authentication == null) {
       authentication = headers.get(AUTHORIZATION_HEADER);
@@ -162,7 +180,7 @@ public class AuthInterceptor implements ServerInterceptor {
       final String tokenString = URLDecodeWithUTF8(sessionTokenCookie.split(";")[0]);
 
       final Subject subject = sessionTokenAuth(tokenString);
-      return updateContext(subject, call, headers, next);
+      return updateContext(subject, call, headers, next, "sessionToken: " + tokenString);
     } catch (final AuthenticationException e) {
       final Status status =
           Status.UNAUTHENTICATED.withDescription(
@@ -192,7 +210,12 @@ public class AuthInterceptor implements ServerInterceptor {
       final ServerCallHandler<ReqT, RespT> next) {
     try {
       final Subject subject = basicAuth(base64);
-      return updateContext(subject, call, headers, next);
+      return updateContext(
+          subject,
+          call,
+          headers,
+          next,
+          "basic: " + base64 + " thread: " + Thread.currentThread().getName());
     } catch (final AuthenticationException e) {
       final Status status =
           Status.UNAUTHENTICATED.withDescription(
@@ -212,7 +235,7 @@ public class AuthInterceptor implements ServerInterceptor {
       final Metadata headers,
       final ServerCallHandler<ReqT, RespT> next) {
     final Subject subject = anonymous();
-    return updateContext(subject, call, headers, next);
+    return updateContext(subject, call, headers, next, "anonymous");
   }
 
   /** Login as anonymous. */
@@ -230,10 +253,11 @@ public class AuthInterceptor implements ServerInterceptor {
       final Subject subject,
       final ServerCall<ReqT, RespT> call,
       final Metadata headers,
-      final ServerCallHandler<ReqT, RespT> next) {
+      final ServerCallHandler<ReqT, RespT> next,
+      final String tag) {
     final Context context = Context.current();
     context.withValue(SUBJECT_KEY, subject);
-    ServerCall<ReqT, RespT> cookieSetter = new CookieSetter<>(call);
+    ServerCall<ReqT, RespT> cookieSetter = new CookieSetter<>(call, subject, tag);
     return Contexts.interceptCall(context, cookieSetter, headers, next);
   }
 }
@@ -245,9 +269,11 @@ final class CookieSetter<ReqT, RespT>
           + "=expired; Path=/; HttpOnly; SameSite=Strict; Max-Age=0";
   public static final Key<String> SET_COOKIE =
       Key.of("Set-Cookie", Metadata.ASCII_STRING_MARSHALLER);
+  private Subject subject;
 
-  protected CookieSetter(ServerCall<ReqT, RespT> delegate) {
+  protected CookieSetter(ServerCall<ReqT, RespT> delegate, Subject subject, String tag) {
     super(delegate);
+    this.subject = subject;
   }
 
   String getSessionTimeoutSeconds() {
@@ -264,10 +290,9 @@ final class CookieSetter<ReqT, RespT>
   };
 
   private void setSessionCookies(Metadata headers) {
-    final Subject subject = SecurityUtils.getSubject();
     // if authenticated as a normal user: generate and set session cookie.
     if (subject.isAuthenticated()
-        && subject.getPrincipal() != AnonymousAuthenticationToken.PRINCIPAL) {
+        && !AnonymousAuthenticationToken.PRINCIPAL.equals(subject.getPrincipal())) {
       final SessionToken sessionToken = SessionToken.generate(subject);
       if (sessionToken != null && sessionToken.isValid()) {
 
@@ -284,6 +309,9 @@ final class CookieSetter<ReqT, RespT>
                   + getSessionTimeoutSeconds());
         }
       }
+    } else if (AnonymousAuthenticationToken.PRINCIPAL.equals(subject.getPrincipal())) {
+      // this is anonymous, do nothing
+      headers.toString();
     } else {
       headers.put(SET_COOKIE, EXPIRED_SESSION_COOKIE);
     }
diff --git a/src/main/java/org/caosdb/server/grpc/EntityTransactionServiceImpl.java b/src/main/java/org/caosdb/server/grpc/EntityTransactionServiceImpl.java
index 9b43a04c19387559f95e05084519974817db852b..8abb284782dad53a8a0c5701f653ad466dee0ece 100644
--- a/src/main/java/org/caosdb/server/grpc/EntityTransactionServiceImpl.java
+++ b/src/main/java/org/caosdb/server/grpc/EntityTransactionServiceImpl.java
@@ -410,6 +410,7 @@ public class EntityTransactionServiceImpl extends EntityTransactionServiceImplBa
       final MultiTransactionRequest request,
       final StreamObserver<MultiTransactionResponse> responseObserver) {
     try {
+      AuthInterceptor.bindSubject();
       final MultiTransactionResponse response = transaction(request);
       responseObserver.onNext(response);
       responseObserver.onCompleted();
@@ -424,6 +425,7 @@ public class EntityTransactionServiceImpl extends EntityTransactionServiceImplBa
       MultiRetrieveEntityACLRequest request,
       StreamObserver<MultiRetrieveEntityACLResponse> responseObserver) {
     try {
+      AuthInterceptor.bindSubject();
       final MultiRetrieveEntityACLResponse response = multiRetrieveEntityACL(request);
       responseObserver.onNext(response);
       responseObserver.onCompleted();
@@ -438,6 +440,7 @@ public class EntityTransactionServiceImpl extends EntityTransactionServiceImplBa
       MultiUpdateEntityACLRequest request,
       StreamObserver<MultiUpdateEntityACLResponse> responseObserver) {
     try {
+      AuthInterceptor.bindSubject();
       final MultiUpdateEntityACLResponse response = multiUpdateEntityACL(request);
       responseObserver.onNext(response);
       responseObserver.onCompleted();
diff --git a/src/main/java/org/caosdb/server/grpc/FileTransmissionServiceImpl.java b/src/main/java/org/caosdb/server/grpc/FileTransmissionServiceImpl.java
index 0b0c4b50e0851f3298a61c02c5e38e08c29b2601..1f549b37a33f26c2f4ecdc5efc1258a3bb602d50 100644
--- a/src/main/java/org/caosdb/server/grpc/FileTransmissionServiceImpl.java
+++ b/src/main/java/org/caosdb/server/grpc/FileTransmissionServiceImpl.java
@@ -45,6 +45,7 @@ public class FileTransmissionServiceImpl extends FileTransmissionServiceImplBase
 
     @Override
     public void onNext(final FileUploadRequest request) {
+      AuthInterceptor.bindSubject();
       final FileChunk chunk = request.getChunk();
       if (chunk.hasFileTransmissionId()) {
         fileUpload =
@@ -104,6 +105,7 @@ public class FileTransmissionServiceImpl extends FileTransmissionServiceImplBase
       final RegisterFileUploadRequest request,
       final StreamObserver<RegisterFileUploadResponse> responseObserver) {
     try {
+      AuthInterceptor.bindSubject();
       final FileTransmission result = fileUploadRegistration.registerFileUpload();
       final Builder builder = RegisterFileUploadResponse.newBuilder();
       builder.setStatus(result.getRegistrationStatus());
@@ -133,6 +135,7 @@ public class FileTransmissionServiceImpl extends FileTransmissionServiceImplBase
       final FileDownloadRequest request,
       final StreamObserver<FileDownloadResponse> responseObserver) {
     try {
+      AuthInterceptor.bindSubject();
       FileDownloadResponse response =
           fileDownloadRegistration.downloadNextChunk(request.getFileTransmissionId());
       responseObserver.onNext(response);
diff --git a/src/main/java/org/caosdb/server/grpc/GeneralInfoServiceImpl.java b/src/main/java/org/caosdb/server/grpc/GeneralInfoServiceImpl.java
index de7b698792f2660848d1bf93196a7dc9174ee703..295ed15b15a144222d17aec20185cf1b5cbb3ab0 100644
--- a/src/main/java/org/caosdb/server/grpc/GeneralInfoServiceImpl.java
+++ b/src/main/java/org/caosdb/server/grpc/GeneralInfoServiceImpl.java
@@ -20,10 +20,10 @@
 
 package org.caosdb.server.grpc;
 
+import io.grpc.Context;
 import io.grpc.stub.StreamObserver;
 import java.util.Collection;
 import java.util.LinkedList;
-import org.apache.shiro.SecurityUtils;
 import org.apache.shiro.authz.AuthorizationInfo;
 import org.apache.shiro.authz.Permission;
 import org.apache.shiro.subject.Subject;
@@ -50,10 +50,7 @@ import org.caosdb.server.permissions.CaosPermission;
  */
 public class GeneralInfoServiceImpl extends GeneralInfoServiceImplBase {
 
-  @Override
-  public void getVersionInfo(
-      final GetVersionInfoRequest request,
-      final StreamObserver<GetVersionInfoResponse> responseObserver) {
+  private GetVersionInfoResponse getVersionInfo(GetVersionInfoRequest request) {
 
     final String version[] =
         CaosDBServer.getServerProperty(ServerProperties.KEY_PROJECT_VERSION).split("[\\.-]", 4);
@@ -71,43 +68,100 @@ public class GeneralInfoServiceImpl extends GeneralInfoServiceImplBase {
             .setPreRelease(pre_release)
             .setBuild(build)
             .build();
-    final GetVersionInfoResponse response =
-        GetVersionInfoResponse.newBuilder().setVersionInfo(versionInfo).build();
-
-    responseObserver.onNext(response);
-    responseObserver.onCompleted();
+    return GetVersionInfoResponse.newBuilder().setVersionInfo(versionInfo).build();
   }
 
   @Override
-  public void getSessionInfo(
-      GetSessionInfoRequest request, StreamObserver<GetSessionInfoResponse> responseObserver) {
-    final GetSessionInfoResponse.Builder response = GetSessionInfoResponse.newBuilder();
-
-    Subject user = SecurityUtils.getSubject();
-    Principal principal = (Principal) user.getPrincipal();
+  public void getVersionInfo(
+      final GetVersionInfoRequest request,
+      final StreamObserver<GetVersionInfoResponse> responseObserver) {
 
-    response.setUsername(principal.getUsername());
-    response.setRealm(principal.getRealm());
+    try {
+      GetVersionInfoResponse response = getVersionInfo(request);
+      responseObserver.onNext(response);
+      responseObserver.onCompleted();
 
-    AuthorizationInfo authorizationInfo = AuthenticationUtils.getAuthorizationInfo(user);
-    Collection<String> roles = authorizationInfo.getRoles();
-    if (roles != null && !roles.isEmpty()) {
-      response.addAllRoles(roles);
+    } catch (final Exception e) {
+      AccessControlManagementServiceImpl.handleException(responseObserver, e);
     }
-    Collection<String> permissions =
-        new LinkedList<String>(authorizationInfo.getStringPermissions());
-    for (Permission p : authorizationInfo.getObjectPermissions()) {
-      if (p instanceof CaosPermission) {
-        permissions.addAll(((CaosPermission) p).getStringPermissions(user));
-      } else {
-        permissions.add(p.toString());
+  }
+
+  private GetSessionInfoResponse getSessionInfo(GetSessionInfoRequest request) {
+
+    Subject subject = AuthInterceptor.bindSubject();
+    System.out.println(
+        "getSessionInfo  (in): "
+            + Long.toString(Thread.currentThread().getId())
+            + " "
+            + Thread.currentThread().getName()
+            + " subject: "
+            + subject.toString());
+    GetSessionInfoResponse.Builder response = GetSessionInfoResponse.newBuilder();
+
+    Principal principal = (Principal) subject.getPrincipal();
+
+    try {
+      response.setUsername(principal.getUsername());
+      response.setRealm(principal.getRealm());
+
+      AuthorizationInfo authorizationInfo = AuthenticationUtils.getAuthorizationInfo(subject);
+      Collection<String> roles = authorizationInfo.getRoles();
+      if (roles != null && !roles.isEmpty()) {
+        response.addAllRoles(roles);
       }
+
+      Collection<String> permissions = new LinkedList<>();
+
+      Collection<String> stringPermissions = authorizationInfo.getStringPermissions();
+      if (stringPermissions != null && !stringPermissions.isEmpty()) {
+        permissions.addAll(stringPermissions);
+      }
+
+      for (Permission p : authorizationInfo.getObjectPermissions()) {
+        if (p instanceof CaosPermission) {
+          permissions.addAll(((CaosPermission) p).getStringPermissions(subject));
+        } else {
+          permissions.add(p.toString());
+        }
+      }
+
+      if (permissions != null && !permissions.isEmpty()) {
+        response.addAllPermissions(permissions);
+      }
+
+      System.out.println(
+          "getSessionInfo (out): "
+              + Long.toString(Thread.currentThread().getId())
+              + " "
+              + Thread.currentThread().getName()
+              + " subject: "
+              + subject.toString());
+      return response.build();
+    } catch (NullPointerException e) {
+      final Context context = Context.current();
+
+      System.out.println(
+          "getSessionInfo (exc): "
+              + Long.toString(Thread.currentThread().getId())
+              + " "
+              + Thread.currentThread().getName()
+              + " subject: "
+              + subject.toString());
+      throw e;
     }
-    if (permissions != null && !permissions.isEmpty()) {
-      response.addAllPermissions(permissions);
-    }
+  }
+
+  @Override
+  public void getSessionInfo(
+      GetSessionInfoRequest request, StreamObserver<GetSessionInfoResponse> responseObserver) {
 
-    responseObserver.onNext(response.build());
-    responseObserver.onCompleted();
+    try {
+      final GetSessionInfoResponse response = getSessionInfo(request);
+      responseObserver.onNext(response);
+      responseObserver.onCompleted();
+
+    } catch (final Exception e) {
+      AccessControlManagementServiceImpl.handleException(responseObserver, e);
+    }
   }
 }
diff --git a/src/main/java/org/caosdb/server/jobs/Job.java b/src/main/java/org/caosdb/server/jobs/Job.java
index 9bca9eb2e1b9a78e9e73a79b5f31161b345f2dc1..675686aa797cd2a00cf7a921a29e81ce144db179 100644
--- a/src/main/java/org/caosdb/server/jobs/Job.java
+++ b/src/main/java/org/caosdb/server/jobs/Job.java
@@ -27,8 +27,6 @@ import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Set;
-import org.apache.shiro.authz.AuthorizationException;
-import org.apache.shiro.authz.Permission;
 import org.apache.shiro.subject.Subject;
 import org.caosdb.server.CaosDBException;
 import org.caosdb.server.database.BackendTransaction;
@@ -300,11 +298,6 @@ public abstract class Job {
     return entity;
   }
 
-  protected final void checkPermission(final EntityInterface entity, final Permission permission)
-      throws AuthorizationException {
-    entity.checkPermission(permission);
-  }
-
   /**
    * Create a Job object with the given parameters.
    *
diff --git a/src/main/java/org/caosdb/server/jobs/core/CheckDatatypePresent.java b/src/main/java/org/caosdb/server/jobs/core/CheckDatatypePresent.java
index 9ea7d4b3867b781ead42a50b23b5a7befff048f9..dd87d5298365a4b95abc52c66c17823c5c52687a 100644
--- a/src/main/java/org/caosdb/server/jobs/core/CheckDatatypePresent.java
+++ b/src/main/java/org/caosdb/server/jobs/core/CheckDatatypePresent.java
@@ -23,6 +23,7 @@
 package org.caosdb.server.jobs.core;
 
 import java.util.List;
+import org.apache.shiro.authz.AuthorizationException;
 import org.caosdb.server.database.exceptions.EntityDoesNotExistException;
 import org.caosdb.server.database.exceptions.EntityWasNotUniqueException;
 import org.caosdb.server.datatype.AbstractCollectionDatatype;
@@ -97,13 +98,15 @@ public final class CheckDatatypePresent extends EntityJob {
         // finally, no data type
         throw ServerMessages.PROPERTY_HAS_NO_DATATYPE;
       }
-
     } catch (final Message m) {
       if (m == ServerMessages.ENTITY_DOES_NOT_EXIST) {
         getEntity().addError(ServerMessages.UNKNOWN_DATATYPE);
       } else {
         getEntity().addError(m);
       }
+    } catch (AuthorizationException exc) {
+      getEntity().addError(ServerMessages.AUTHORIZATION_ERROR);
+      getEntity().addInfo(exc.getMessage());
     } catch (final EntityDoesNotExistException exc) {
       getEntity().addError(ServerMessages.UNKNOWN_DATATYPE);
     } catch (final EntityWasNotUniqueException exc) {
@@ -152,8 +155,8 @@ public final class CheckDatatypePresent extends EntityJob {
     }
   }
 
-  private void assertAllowedToUse(final EntityInterface datatype) throws Message {
-    checkPermission(datatype, EntityPermission.USE_AS_DATA_TYPE);
+  private void assertAllowedToUse(final EntityInterface datatype) {
+    datatype.checkPermission(EntityPermission.USE_AS_DATA_TYPE);
   }
 
   private void checkIfOverride() throws Message {
diff --git a/src/main/java/org/caosdb/server/jobs/core/CheckParValid.java b/src/main/java/org/caosdb/server/jobs/core/CheckParValid.java
index 4e6b097e66bf2e844cad34ae22f45eedf1b6cd67..d3b28bd5f158b767469e6d7fcc3cebe9fa75edb8 100644
--- a/src/main/java/org/caosdb/server/jobs/core/CheckParValid.java
+++ b/src/main/java/org/caosdb/server/jobs/core/CheckParValid.java
@@ -23,6 +23,7 @@
 package org.caosdb.server.jobs.core;
 
 import com.google.common.base.Objects;
+import org.apache.shiro.authz.AuthorizationException;
 import org.caosdb.server.database.exceptions.EntityDoesNotExistException;
 import org.caosdb.server.database.exceptions.EntityWasNotUniqueException;
 import org.caosdb.server.entity.Affiliation;
@@ -118,13 +119,16 @@ public class CheckParValid extends EntityJob {
             }
           }
 
-          addError(parent, ServerMessages.ENTITY_DOES_NOT_EXIST);
+          parent.addError(ServerMessages.ENTITY_DOES_NOT_EXIST);
         } catch (final Message m) {
-          addError(parent, m);
+          parent.addError(m);
+        } catch (AuthorizationException e) {
+          parent.addError(ServerMessages.AUTHORIZATION_ERROR);
+          parent.addInfo(e.getMessage());
         } catch (final EntityDoesNotExistException exc) {
-          addError(parent, ServerMessages.ENTITY_DOES_NOT_EXIST);
+          parent.addError(ServerMessages.ENTITY_DOES_NOT_EXIST);
         } catch (final EntityWasNotUniqueException exc) {
-          addError(parent, ServerMessages.ENTITY_NAME_DUPLICATES);
+          parent.addError(ServerMessages.ENTITY_NAME_DUPLICATES);
         }
       }
     }
@@ -191,12 +195,7 @@ public class CheckParValid extends EntityJob {
     throw ServerMessages.AFFILIATION_ERROR;
   }
 
-  private void assertAllowedToUse(final EntityInterface entity) throws Message {
-    checkPermission(entity, EntityPermission.USE_AS_PARENT);
-  }
-
-  private void addError(final EntityInterface parent, final Message m) {
-    parent.addError(m);
-    parent.setEntityStatus(EntityStatus.UNQUALIFIED);
+  private void assertAllowedToUse(final EntityInterface entity) {
+    entity.checkPermission(EntityPermission.USE_AS_PARENT);
   }
 }
diff --git a/src/main/java/org/caosdb/server/jobs/core/CheckPropValid.java b/src/main/java/org/caosdb/server/jobs/core/CheckPropValid.java
index 112692c89a403366eb9eeb02d32355982a96a236..eeea52b85b9c1629b426660020c7e65f0e4b96ef 100644
--- a/src/main/java/org/caosdb/server/jobs/core/CheckPropValid.java
+++ b/src/main/java/org/caosdb/server/jobs/core/CheckPropValid.java
@@ -138,17 +138,10 @@ public class CheckPropValid extends EntityJob {
 
     // process names
     appendJob(ProcessNameProperties.class);
-    // final ProcessNameProperties processNameProperties = new
-    // ProcessNameProperties();
-    // processNameProperties.init(getMode(), getEntity(), getContainer(),
-    // getTransaction());
-    // getTransaction().getSchedule().add(processNameProperties);
-    // getTransaction().getSchedule().runJob(processNameProperties);
-
   }
 
-  private void assertAllowedToUse(final EntityInterface property) throws Message {
-    checkPermission(property, EntityPermission.USE_AS_PROPERTY);
+  private void assertAllowedToUse(final EntityInterface property) {
+    property.checkPermission(EntityPermission.USE_AS_PROPERTY);
   }
 
   private static void deriveOverrideStatus(final Property child, final EntityInterface parent) {
diff --git a/src/main/java/org/caosdb/server/jobs/core/CheckRefidValid.java b/src/main/java/org/caosdb/server/jobs/core/CheckRefidValid.java
index f19424b127feb3273571a7826bf05382299ea58a..645f87d0b2eb0bfc045eb3d4237a40b702c044a3 100644
--- a/src/main/java/org/caosdb/server/jobs/core/CheckRefidValid.java
+++ b/src/main/java/org/caosdb/server/jobs/core/CheckRefidValid.java
@@ -24,6 +24,7 @@
  */
 package org.caosdb.server.jobs.core;
 
+import org.apache.shiro.authz.AuthorizationException;
 import org.caosdb.server.database.exceptions.EntityDoesNotExistException;
 import org.caosdb.server.database.exceptions.EntityWasNotUniqueException;
 import org.caosdb.server.datatype.CollectionValue;
@@ -71,13 +72,13 @@ public class CheckRefidValid extends EntityJob implements Observer {
       }
     } catch (final Message m) {
       getEntity().addError(m);
-      getEntity().setEntityStatus(EntityStatus.UNQUALIFIED);
+    } catch (AuthorizationException exc) {
+      getEntity().addError(ServerMessages.AUTHORIZATION_ERROR);
+      getEntity().addInfo(exc.getMessage());
     } catch (final EntityDoesNotExistException e) {
       getEntity().addError(ServerMessages.REFERENCED_ENTITY_DOES_NOT_EXIST);
-      getEntity().setEntityStatus(EntityStatus.UNQUALIFIED);
     } catch (final EntityWasNotUniqueException e) {
       getEntity().addError(ServerMessages.REFERENCE_NAME_DUPLICATES);
-      getEntity().setEntityStatus(EntityStatus.UNQUALIFIED);
     }
   }
 
@@ -139,8 +140,8 @@ public class CheckRefidValid extends EntityJob implements Observer {
     }
   }
 
-  private void assertAllowedToUse(final EntityInterface referencedEntity) throws Message {
-    checkPermission(referencedEntity, EntityPermission.USE_AS_REFERENCE);
+  private void assertAllowedToUse(final EntityInterface referencedEntity) {
+    referencedEntity.checkPermission(EntityPermission.USE_AS_REFERENCE);
   }
 
   @Override
diff --git a/src/main/java/org/caosdb/server/resource/AbstractCaosDBServerResource.java b/src/main/java/org/caosdb/server/resource/AbstractCaosDBServerResource.java
index 0fa5b4b405f254fa9e8aa4ab2609eb9da7b3d766..44ebfa22d08c975031f5bf5bfca325d6b706af24 100644
--- a/src/main/java/org/caosdb/server/resource/AbstractCaosDBServerResource.java
+++ b/src/main/java/org/caosdb/server/resource/AbstractCaosDBServerResource.java
@@ -389,6 +389,7 @@ public abstract class AbstractCaosDBServerResource extends ServerResource {
   public Representation handleThrowable(final Throwable t) {
     try {
       getRequest().getAttributes().put("THROWN", t);
+      t.printStackTrace();
       throw t;
     } catch (final AuthenticationException e) {
       return error(ServerMessages.UNAUTHENTICATED, Status.CLIENT_ERROR_UNAUTHORIZED);
diff --git a/src/main/java/org/caosdb/server/resource/RolesResource.java b/src/main/java/org/caosdb/server/resource/RolesResource.java
index a89a731950d09a7edbce0a5f67a3e81287c07b2a..ad1544da3a326f1c16e0b01238985d10e93b0581 100644
--- a/src/main/java/org/caosdb/server/resource/RolesResource.java
+++ b/src/main/java/org/caosdb/server/resource/RolesResource.java
@@ -26,7 +26,6 @@ import java.io.IOException;
 import java.security.NoSuchAlgorithmException;
 import java.sql.SQLException;
 import org.caosdb.server.CaosDBException;
-import org.caosdb.server.accessControl.ACMPermissions;
 import org.caosdb.server.accessControl.Role;
 import org.caosdb.server.database.backend.implementation.MySQL.ConnectionException;
 import org.caosdb.server.entity.Message;
@@ -55,7 +54,6 @@ public class RolesResource extends AbstractCaosDBServerResource {
     if (getRequestedItems().length > 0) {
       final String name = getRequestedItems()[0];
       if (name != null) {
-        getUser().checkPermission(ACMPermissions.PERMISSION_RETRIEVE_ROLE_DESCRIPTION(name));
         final RetrieveRoleTransaction t = new RetrieveRoleTransaction(name);
         try {
           t.execute();
diff --git a/src/main/java/org/caosdb/server/transaction/RetrieveRoleTransaction.java b/src/main/java/org/caosdb/server/transaction/RetrieveRoleTransaction.java
index 1047e1f60143bd6ab3ebbc8ae7c9a7ebb93f2a15..8e92a347f869b2a6a3e6f2be58d9124e6a9442d7 100644
--- a/src/main/java/org/caosdb/server/transaction/RetrieveRoleTransaction.java
+++ b/src/main/java/org/caosdb/server/transaction/RetrieveRoleTransaction.java
@@ -36,15 +36,20 @@ public class RetrieveRoleTransaction extends AccessControlTransaction {
 
   private final String name;
   private Role role;
+  private Subject transactor;
 
-  public RetrieveRoleTransaction(final String name) {
+  public RetrieveRoleTransaction(final String name, Subject transactor) {
+    this.transactor = transactor;
     this.name = name;
   }
 
+  public RetrieveRoleTransaction(final String name) {
+    this(name, SecurityUtils.getSubject());
+  }
+
   @Override
   protected void transaction() throws Exception {
-    Subject currentUser = SecurityUtils.getSubject();
-    if (!currentUser.isPermitted(ACMPermissions.PERMISSION_RETRIEVE_ROLE_DESCRIPTION(this.name))) {
+    if (!transactor.isPermitted(ACMPermissions.PERMISSION_RETRIEVE_ROLE_DESCRIPTION(this.name))) {
       throw new AuthorizationException("You are not permitted to retrieve this role");
     }
     this.role = execute(new RetrieveRole(this.name), getAccess()).getRole();
@@ -55,7 +60,7 @@ public class RetrieveRoleTransaction extends AccessControlTransaction {
       Iterator<ProtoUser> iterator = this.role.users.iterator();
       while (iterator.hasNext()) {
         ProtoUser user = iterator.next();
-        if (!currentUser.isPermitted(
+        if (!transactor.isPermitted(
             ACMPermissions.PERMISSION_RETRIEVE_USER_ROLES(user.realm, user.name))) {
           iterator.remove();
         }