diff --git a/CHANGELOG.md b/CHANGELOG.md
index 625a619037d4b6281f7a80d93d16501092522305..c68bd28e8b50fbac0650284984bd21cdb03daa1f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -19,6 +19,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ### Security
 
+* [caosdb-deploy#225](https://gitlab.indiscale.com/caosdb/src/caosdb-deploy/-/issues/225) - Denied Edit permission leads to retrieve permission.
+
 ## [v0.6.0] - 2021-11-17
 (Timm Fitschen)
 
diff --git a/pom.xml b/pom.xml
index d495e32de4989c90febb4e40dc731f0ff86a0d01..609971c4ac73fac467ed0ff11fde92708bd080ad 100644
--- a/pom.xml
+++ b/pom.xml
@@ -73,7 +73,7 @@
     <dependency>
       <groupId>org.apache.shiro</groupId>
       <artifactId>shiro-core</artifactId>
-      <version>1.5.3</version>
+      <version>1.8.0</version>
     </dependency>
     <dependency>
       <groupId>junit</groupId>
diff --git a/src/main/java/org/caosdb/server/CaosDBServer.java b/src/main/java/org/caosdb/server/CaosDBServer.java
index 17bb1e500ed5aeffec25cf9aa2535150ceb40b4c..b445749d68fafaeac74cc398912769acd6841a8b 100644
--- a/src/main/java/org/caosdb/server/CaosDBServer.java
+++ b/src/main/java/org/caosdb/server/CaosDBServer.java
@@ -326,6 +326,8 @@ public class CaosDBServer extends Application {
 
         // ChecksumUpdater
         ChecksumUpdater.start();
+
+        ThreadContext.remove();
       }
     } else {
       logger.info("NO BACKEND");
@@ -566,9 +568,9 @@ public class CaosDBServer extends Application {
               setSessionCookies(response);
 
             } finally {
-              // remove subject from this thread so that we can reuse the
-              // thread.
-              ThreadContext.unbindSubject();
+              // remove subject and all other session data from this thread so
+              // that we can reuse the thread.
+              ThreadContext.remove();
             }
           }
 
diff --git a/src/main/java/org/caosdb/server/jobs/Job.java b/src/main/java/org/caosdb/server/jobs/Job.java
index 2de6b08537d82504bb989a4cf661f89ff473e4c2..9bca9eb2e1b9a78e9e73a79b5f31161b345f2dc1 100644
--- a/src/main/java/org/caosdb/server/jobs/Job.java
+++ b/src/main/java/org/caosdb/server/jobs/Job.java
@@ -27,7 +27,7 @@ import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Set;
-import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.authz.AuthorizationException;
 import org.apache.shiro.authz.Permission;
 import org.apache.shiro.subject.Subject;
 import org.caosdb.server.CaosDBException;
@@ -301,10 +301,8 @@ public abstract class Job {
   }
 
   protected final void checkPermission(final EntityInterface entity, final Permission permission)
-      throws Message {
-    if (!entity.getEntityACL().isPermitted(SecurityUtils.getSubject(), permission)) {
-      throw ServerMessages.AUTHORIZATION_ERROR;
-    }
+      throws AuthorizationException {
+    entity.checkPermission(permission);
   }
 
   /**
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 390deedde211c0931eca1c3677ac5ff9c8ee9d8f..eeea52b85b9c1629b426660020c7e65f0e4b96ef 100644
--- a/src/main/java/org/caosdb/server/jobs/core/CheckPropValid.java
+++ b/src/main/java/org/caosdb/server/jobs/core/CheckPropValid.java
@@ -25,6 +25,7 @@ package org.caosdb.server.jobs.core;
 import static org.caosdb.server.utils.ServerMessages.ENTITY_DOES_NOT_EXIST;
 
 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.EntityInterface;
@@ -124,32 +125,23 @@ public class CheckPropValid extends EntityJob {
           }
         }
       } catch (final Message m) {
-        addError(property, m);
+        property.addError(m);
+      } catch (AuthorizationException e) {
+        property.addError(ServerMessages.AUTHORIZATION_ERROR);
+        property.addInfo(e.getMessage());
       } catch (final EntityDoesNotExistException e) {
-        addError(property, ENTITY_DOES_NOT_EXIST);
+        property.addError(ENTITY_DOES_NOT_EXIST);
       } catch (final EntityWasNotUniqueException e) {
-        addError(property, ServerMessages.ENTITY_NAME_DUPLICATES);
+        property.addError(ServerMessages.ENTITY_NAME_DUPLICATES);
       }
     }
 
     // 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 addError(final EntityInterface property, final Message m) {
-    property.addError(m);
-    property.setEntityStatus(EntityStatus.UNQUALIFIED);
+  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/permissions/EntityACI.java b/src/main/java/org/caosdb/server/permissions/EntityACI.java
index ccc889decafc941484432c99bf48908c21dff209..34d713eb69179cf7e88103cca2dd901077ffc092 100644
--- a/src/main/java/org/caosdb/server/permissions/EntityACI.java
+++ b/src/main/java/org/caosdb/server/permissions/EntityACI.java
@@ -1,9 +1,10 @@
 /*
- * ** 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
+ * Copyright (C) 2021 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2021 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -18,11 +19,12 @@
  * 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 org.caosdb.server.permissions;
 
 import java.util.HashMap;
+import java.util.Set;
 
 public final class EntityACI {
 
@@ -72,4 +74,16 @@ public final class EntityACI {
     map.put("bitSet", getBitSet());
     return map;
   }
+
+  public boolean isGrant() {
+    return EntityACL.isAllowance(bitSet);
+  }
+
+  public boolean isPriority() {
+    return EntityACL.isPriorityBitSet(bitSet);
+  }
+
+  public Set<EntityPermission> getPermission() {
+    return EntityACL.getPermissionsFromBitSet(bitSet);
+  }
 }
diff --git a/src/main/java/org/caosdb/server/permissions/EntityACL.java b/src/main/java/org/caosdb/server/permissions/EntityACL.java
index cfa436d59ae25971a08d4314a7f668a70cf75bbf..ce76cf5283847ad0e17886daa80b06548541c030 100644
--- a/src/main/java/org/caosdb/server/permissions/EntityACL.java
+++ b/src/main/java/org/caosdb/server/permissions/EntityACL.java
@@ -191,7 +191,9 @@ public class EntityACL {
   public static final List<ResponsibleAgent> getOwners(final Collection<EntityACI> acl) {
     final List<ResponsibleAgent> owners = new ArrayList<>();
     for (final EntityACI aci : acl) {
-      if (isOwnerBitSet(aci.getBitSet()) && !aci.getResponsibleAgent().equals(OWNER_ROLE)) {
+      if (aci.isGrant()
+          && isOwnerBitSet(aci.getBitSet())
+          && !aci.getResponsibleAgent().equals(OWNER_ROLE)) {
         owners.add(aci.getResponsibleAgent());
       }
     }
diff --git a/src/test/java/org/caosdb/server/permissions/EntityACLTest.java b/src/test/java/org/caosdb/server/permissions/EntityACLTest.java
index 1787c902f48124d692f8c53e4a73ed04564dfe8f..28b4322333f771a3480e4d386b7e77fb2977590b 100644
--- a/src/test/java/org/caosdb/server/permissions/EntityACLTest.java
+++ b/src/test/java/org/caosdb/server/permissions/EntityACLTest.java
@@ -23,6 +23,7 @@
 package org.caosdb.server.permissions;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
@@ -30,6 +31,7 @@ import java.io.IOException;
 import java.util.BitSet;
 import java.util.HashSet;
 import java.util.LinkedList;
+import java.util.Set;
 import org.apache.shiro.SecurityUtils;
 import org.apache.shiro.subject.Subject;
 import org.caosdb.server.CaosDBServer;
@@ -395,4 +397,37 @@ public class EntityACLTest {
       assertTrue(EntityACL.isPriorityBitSet(aci.getBitSet()));
     }
   }
+
+  @Test
+  public void testOwnership() {
+    EntityACLFactory f = new EntityACLFactory();
+    f.grant(
+        org.caosdb.server.permissions.Role.create("the_owner"), false, EntityPermission.EDIT_ACL);
+    f.deny(
+        org.caosdb.server.permissions.Role.create("someone_else"),
+        false,
+        EntityPermission.EDIT_ACL);
+    EntityACL acl = f.create();
+    assertEquals(1, acl.getOwners().size());
+    assertEquals("the_owner", acl.getOwners().get(0).toString());
+  }
+
+  @Test
+  public void testPermissionsFor() {
+    EntityACLFactory f = new EntityACLFactory();
+    f.deny(org.caosdb.server.permissions.Role.ANONYMOUS_ROLE, false, EntityPermission.EDIT_ACL);
+    f.grant(org.caosdb.server.permissions.Role.OWNER_ROLE, false, "*");
+    EntityACL acl = f.create();
+
+    Subject anonymous = SecurityUtils.getSubject();
+    anonymous.login(AnonymousAuthenticationToken.getInstance());
+    assertTrue(AuthenticationUtils.isAnonymous(anonymous));
+
+    assertNotNull(acl);
+    assertTrue(acl.getOwners().isEmpty());
+    final Set<EntityPermission> permissionsFor =
+        EntityACL.getPermissionsFor(anonymous, acl.getRules());
+
+    assertFalse(permissionsFor.contains(EntityPermission.RETRIEVE_ENTITY));
+  }
 }