access control classes
diff --git a/src/main/java/de/ids_mannheim/korap/config/AuthCodeInfo.java b/src/main/java/de/ids_mannheim/korap/config/AuthCodeInfo.java
new file mode 100644
index 0000000..28b53ae
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/config/AuthCodeInfo.java
@@ -0,0 +1,31 @@
+package de.ids_mannheim.korap.config;
+
+import lombok.Data;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+* @author hanl
+* @date 13/05/2015
+*/
+@Data
+public class AuthCodeInfo {
+    private String clientId;
+    private String scopes;
+    private Integer userId;
+    private Boolean status;
+    private String code;
+    private List<String> tokens;
+
+    public AuthCodeInfo() {
+        this.setStatus(true);
+        this.tokens = new ArrayList<>();
+    }
+
+    public AuthCodeInfo(String clientid, String authcode) {
+        this();
+        this.clientId = clientid;
+        this.code = authcode;
+    }
+}
diff --git a/src/main/java/de/ids_mannheim/korap/config/ClientInfo.java b/src/main/java/de/ids_mannheim/korap/config/ClientInfo.java
new file mode 100644
index 0000000..5eab5b9
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/config/ClientInfo.java
@@ -0,0 +1,38 @@
+package de.ids_mannheim.korap.config;
+
+import lombok.Data;
+
+/**
+ * @author hanl
+ * @date 22/01/2014
+ */
+@Data
+public class ClientInfo {
+
+    private Integer id;
+    private String client_id;
+    private String application_name;
+    private boolean confidential;
+    private String client_secret;
+    // fixme: keep type?
+    private String client_type;
+    private String url;
+    private String redirect_uri;
+
+    public ClientInfo(String client_id, String client_secret) {
+        this.client_id = client_id;
+        this.client_secret = client_secret;
+    }
+
+    public String toJSON() {
+        return "client_id: " + client_id + "\n" +
+                "application_name: " + application_name + "\n" +
+                "url: " + url + "\n" +
+                "redirect_uri: " + redirect_uri + "\n";
+    }
+
+    //todo:
+    public static ClientInfo fromJSON(String json) {
+        return null;
+    }
+}
diff --git a/src/main/java/de/ids_mannheim/korap/exceptions/BaseException.java b/src/main/java/de/ids_mannheim/korap/exceptions/BaseException.java
deleted file mode 100644
index 66e1197..0000000
--- a/src/main/java/de/ids_mannheim/korap/exceptions/BaseException.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package de.ids_mannheim.korap.exceptions;
-
-import de.ids_mannheim.korap.auditing.AuditRecord;
-import lombok.Getter;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Serves as base exception to allow auditing the exception.
- * By extending the exception, different types of exceptions and ways of handling the audits can be created
- * (database, service, etc.)
- *
- * @author hanl
- * @date 29/01/2014
- */
-@Getter
-public abstract class BaseException extends Exception {
-
-    protected List<AuditRecord> records = new ArrayList<>();
-    private Integer statusCode;
-    private String entity;
-
-    public BaseException(int code) {
-        this.statusCode = code;
-    }
-
-    public BaseException(int status, String message, String entity) {
-        super(message);
-        this.statusCode = status;
-        this.entity = entity;
-    }
-
-    public BaseException(int status, String entity) {
-        this(status);
-        this.entity = entity;
-    }
-
-    public BaseException(Throwable cause, int status) {
-        super(cause);
-        this.statusCode = status;
-
-    }
-
-    public BaseException(String message, Throwable cause, int status) {
-        super(message, cause);
-        this.statusCode = status;
-    }
-
-}
diff --git a/src/main/java/de/ids_mannheim/korap/security/Parameter.java b/src/main/java/de/ids_mannheim/korap/security/Parameter.java
new file mode 100644
index 0000000..4c21542
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/security/Parameter.java
@@ -0,0 +1,45 @@
+package de.ids_mannheim.korap.security;
+
+import de.ids_mannheim.korap.resources.KustvaktResource;
+import de.ids_mannheim.korap.user.User;
+import lombok.Getter;
+
+/**
+ * @author hanl@ids-mannheim.de
+ * @date 09/11/13
+ */
+@Getter
+public class Parameter extends KustvaktResource {
+
+    private String value;
+    private SecurityPolicy policy;
+    private boolean equality;
+
+    public Parameter(String identifier, String value, boolean equality,
+            User user) {
+        super();
+        super.setName(identifier.toLowerCase());
+        this.value = value;
+        this.equality = equality;
+        super.setOwner(user.getId());
+    }
+
+    @Override
+    public void merge(KustvaktResource resource) {
+    }
+
+    @Override
+    public void checkNull() {
+    }
+
+    public String getValue() {
+        if (policy == null)
+            return null;
+        return value;
+    }
+
+    public void setPolicy(SecurityPolicy policy) {
+        this.policy = policy;
+    }
+
+}
diff --git a/src/main/java/de/ids_mannheim/korap/security/PermissionsBuffer.java b/src/main/java/de/ids_mannheim/korap/security/PermissionsBuffer.java
new file mode 100644
index 0000000..a9a88df
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/security/PermissionsBuffer.java
@@ -0,0 +1,160 @@
+package de.ids_mannheim.korap.security;
+
+import de.ids_mannheim.korap.resources.Permissions;
+
+import java.nio.ByteBuffer;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * User: hanl
+ * Date: 11/5/13
+ * Time: 1:05 PM
+ */
+public class PermissionsBuffer {
+
+    private byte[] bytes;
+
+    public PermissionsBuffer() {
+        this((short) 0);
+    }
+
+    public PermissionsBuffer(short perm) {
+        setByte(perm);
+    }
+
+    private void setByte(short perm) {
+        ByteBuffer b = ByteBuffer.allocate(2);
+        b.putShort(perm);
+        bytes = b.array();
+    }
+
+    public PermissionsBuffer(byte... bytes) {
+        this.bytes = bytes;
+    }
+
+    public boolean containsPermission(Permissions.PERMISSIONS p) {
+        return containsPByte(Permissions.getByte(p));
+    }
+
+    public boolean containsPByte(byte perm) {
+        return (bytes[1] & perm) == perm;
+    }
+
+    public int addPermission(int b) {
+        short r = (short) (bytes[1] & b);
+        if ((bytes[1] & b) != b)
+            bytes[1] += (b - r);
+        else
+            return -1;
+        return 0;
+    }
+
+    public void retain(int compare) {
+        short f = (short) (bytes[1] & compare);
+        ByteBuffer b = ByteBuffer.allocate(2);
+        b.putShort(f);
+        bytes = b.array();
+    }
+
+    public void addPermissions(Permissions.PERMISSIONS... perm) {
+        if (perm.length > 0) {
+            for (Permissions.PERMISSIONS p : perm)
+                addPermission(Permissions.getByte(p));
+        }
+    }
+
+    public void removePermission(Permissions.PERMISSIONS perm) {
+        this.removePermission(Permissions.getByte(perm));
+    }
+
+
+    public int removePermission(int b) {
+        if ((bytes[1] & b) != 0)
+            bytes[1] -= b;
+        else
+            return -1;
+        return 0;
+    }
+
+    @Deprecated
+    public int addOverride(int b) {
+        if ((bytes[0] & b) == 0)
+            bytes[0] += b;
+        else
+            return -1;
+        return 0;
+    }
+
+    public int removeOverride(int b) {
+        if ((bytes[0] & b) != 0)
+            bytes[0] -= b;
+        else
+            return -1;
+        return 0;
+    }
+
+    @Deprecated
+    public boolean isOverridable(int b) {
+        return (bytes[0] & b) != 0;
+    }
+
+    public boolean leftShift(byte perm) {
+//        return pbyte & (perm << 1);
+        System.out.println("pbyte is: " + bytes[1]);
+        System.out.println("bitswise operation, left shift " + (perm << 1));
+        return false;
+    }
+
+    @Override
+    public boolean equals(Object perm) {
+        if (perm instanceof Byte)
+            return (bytes[1] & (byte) perm) == bytes[1];
+        else if (perm instanceof PermissionsBuffer) {
+            PermissionsBuffer b = (PermissionsBuffer) perm;
+            return (bytes[1] & b.bytes[1]) == bytes[1];
+        }
+        return false;
+    }
+
+    public short getBytes() {
+        ByteBuffer b = ByteBuffer.wrap(bytes);
+        return b.getShort();
+    }
+
+    public Byte getPbyte() {
+        return this.bytes[1];
+    }
+
+    public Set<Permissions.PERMISSIONS> getPermissions() {
+        Set<Permissions.PERMISSIONS> pe = new HashSet<>();
+        if (containsPByte(Permissions.READ))
+            pe.add(Permissions.PERMISSIONS.READ);
+        if (containsPByte(Permissions.WRITE))
+            pe.add(Permissions.PERMISSIONS.WRITE);
+        if (containsPByte(Permissions.DELETE))
+            pe.add(Permissions.PERMISSIONS.DELETE);
+        if (containsPByte(Permissions.CREATE_POLICY))
+            pe.add(Permissions.PERMISSIONS.CREATE_POLICY);
+        if (containsPByte(Permissions.MODIFY_POLICY))
+            pe.add(Permissions.PERMISSIONS.MODIFY_POLICY);
+        if (containsPByte(Permissions.DELETE_POLICY))
+            pe.add(Permissions.PERMISSIONS.DELETE_POLICY);
+        return pe;
+    }
+
+
+    public byte getOverride() {
+        return this.bytes[0];
+    }
+
+    public String toBinary() {
+        StringBuilder sb = new StringBuilder(bytes.length * Byte.SIZE);
+        for (int i = 0; i < Byte.SIZE * bytes.length; i++) {
+            sb.append((bytes[i / Byte.SIZE] << i % Byte.SIZE & 0x80) == 0 ? '0' : '1');
+        }
+        return sb.toString();
+    }
+
+
+}
diff --git a/src/main/java/de/ids_mannheim/korap/security/PolicyCondition.java b/src/main/java/de/ids_mannheim/korap/security/PolicyCondition.java
new file mode 100644
index 0000000..324ee8b
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/security/PolicyCondition.java
@@ -0,0 +1,102 @@
+package de.ids_mannheim.korap.security;
+
+import de.ids_mannheim.korap.user.Attributes;
+import lombok.Getter;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * User: hanl
+ * Date: 10/29/13
+ * Time: 4:30 PM
+ */
+@Getter
+public class PolicyCondition implements Comparable<PolicyCondition> {
+
+    private static Map<String, Object> stats = new HashMap<>();
+
+    static {
+        stats.put(Attributes.SYM_USE, -1);
+        stats.put(Attributes.COMMERCIAL, false);
+        //fixme: doesnt query only and export infer the same thing?
+        stats.put(Attributes.QUERY_ONLY, false);
+        stats.put(Attributes.EXPORT, false);
+        stats.put(Attributes.LICENCE, null);
+        stats.put(Attributes.RANGE, null);
+        //fixme: range is valuable in this context, but time span should remain in the policy context!
+        stats.put(Attributes.TIME_SPANS, null);
+    }
+
+    //todo: loadSubTypes these from database or configuration --> use id reference, rather than variable declaration
+
+    //todo: old regex for format gr(2323):  "(^[^\\(]+)\\((.*)\\)"
+    //    private static final Pattern p = Pattern.compile("\\((.*)\\)");
+    private final String specifier;
+    private String description;
+    private static final String EX_PRE = "ex:";
+    private Map<String, Object> flags;
+
+    public PolicyCondition(String target) {
+        // pattern to map extensionally created groups
+        this.specifier = target;
+        this.flags = new HashMap<>(stats);
+    }
+
+    public PolicyCondition() {
+        this(EX_PRE + createGroupName());
+    }
+
+    @Deprecated
+    //todo: do this in crypto bean!
+    private static String createGroupName() {
+        //        return Base64.encodeBase64String(SecureRGenerator
+        //                .getNextSecureRandom(64));
+        return "<new group name>";
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public void setFlag(String key, Object value) {
+        Object f = this.flags.get(key);
+        if (f != null && f.getClass().equals(value.getClass()))
+            this.flags.put(key, value);
+    }
+
+    public String getSpecifier() {
+        return this.specifier;
+    }
+
+    public boolean isExtensional() {
+        return getSpecifier().startsWith(EX_PRE);
+    }
+
+    @Override
+    public String toString() {
+        return "(" + this.specifier + ")";
+    }
+
+    @Override
+    public int compareTo(PolicyCondition o) {
+        return this.getSpecifier().compareTo(o.getSpecifier());
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o)
+            return true;
+        if (o == null || getClass() != o.getClass())
+            return false;
+
+        PolicyCondition that = (PolicyCondition) o;
+        return specifier.equals(that.specifier);
+    }
+
+    @Override
+    public int hashCode() {
+        return specifier.hashCode();
+    }
+
+}
diff --git a/src/main/java/de/ids_mannheim/korap/security/PolicyContext.java b/src/main/java/de/ids_mannheim/korap/security/PolicyContext.java
new file mode 100644
index 0000000..c4f41ca
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/security/PolicyContext.java
@@ -0,0 +1,75 @@
+package de.ids_mannheim.korap.security;
+
+import de.ids_mannheim.korap.utils.IPNetMask;
+import de.ids_mannheim.korap.utils.TimeUtils;
+import lombok.Getter;
+
+import java.net.UnknownHostException;
+
+/**
+ * @author hanl
+ * @date 09/01/2014
+ */
+@Getter
+public class PolicyContext {
+
+    // refers to a specific ip location
+    private String ipmask = "";
+    // this context is not like an environmental property (e.g. morning hours/ evening hours), but specifies absolute time
+    // parameters (e.g. from 10.04.2014 9:00 till 14..04.2014 active for testing).
+    // if the containing parameter do not meet, the policy will be deactivated. if no parameter where specified, the policy
+    // remains active
+    // specifies a start time for the policy to be activated
+    private long start = 0L;
+    // specifies a time up to which the policy stays active
+    private long end = 0L;
+
+
+    public PolicyContext() {
+        start = TimeUtils.getNow().getMillis();
+    }
+
+    public PolicyContext setIPMask(String ip) {
+        this.ipmask = ip;
+        return this;
+    }
+
+    public PolicyContext setExpirationTime(long limit) {
+        this.end = limit;
+        return this;
+    }
+
+    public PolicyContext setEnableTime(long start) {
+        this.start = start;
+        return this;
+    }
+
+    protected boolean isActive(String ipaddress) {
+        if (ipaddress == null)
+            return false;
+        if (noMask())
+            return true;
+        IPNetMask mask;
+        try {
+            mask = IPNetMask.getIPMask(this.ipmask);
+            boolean f = mask.matches(ipaddress);
+            return f;
+        } catch (UnknownHostException e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    protected boolean noMask() {
+        return ipmask == null || ipmask.isEmpty();
+    }
+
+    @Override
+    public String toString() {
+        return "PolicyContext{" +
+                ", ipmask='" + ipmask + '\'' +
+                ", start=" + start +
+                ", end=" + end +
+                '}';
+    }
+}
diff --git a/src/main/java/de/ids_mannheim/korap/security/SecurityPolicy.java b/src/main/java/de/ids_mannheim/korap/security/SecurityPolicy.java
new file mode 100644
index 0000000..5247b4a
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/security/SecurityPolicy.java
@@ -0,0 +1,269 @@
+package de.ids_mannheim.korap.security;
+
+import de.ids_mannheim.korap.resources.KustvaktResource;
+import de.ids_mannheim.korap.resources.Permissions;
+import de.ids_mannheim.korap.user.User;
+import lombok.Getter;
+
+import java.util.*;
+
+/**
+ * User: hanl
+ * Date: 10/8/13
+ * Time: 5:26 PM
+ */
+
+// default is deny, but deny policies are allowed, when specifying a subset that would otherwise be allowed!
+// must be implemented as a resolution mechanism, that automatically creates this kind of policy strategy (allow > deny)
+
+public class SecurityPolicy {
+
+    private int id = 0;
+    // a settingattribute id for instance,
+    // which specifies the attribute to be protected by this policy
+    private String target;
+    private List<PolicyCondition> conditions;
+    private Set<Integer> removedidx;
+    private Set<Integer> addedidx;
+    private PermissionsBuffer permissions;
+    private PolicyContext ctx;
+    private Integer creator;
+
+    public SecurityPolicy() {
+        this.setID(-1);
+        this.ctx = new PolicyContext();
+        this.conditions = new ArrayList<>();
+        this.removedidx = new HashSet<>();
+        this.addedidx = new HashSet<>();
+        this.permissions = new PermissionsBuffer();
+    }
+
+    public SecurityPolicy(Integer id) {
+        this();
+        this.setID(id);
+    }
+
+    public SecurityPolicy setID(Integer id) {
+        this.id = id;
+        return this;
+    }
+
+    public Integer getID() {
+        return this.id;
+    }
+
+    public Integer getCreator() {
+        return this.creator;
+    }
+
+    public PolicyContext getContext() {
+        return this.ctx;
+    }
+
+    public SecurityPolicy setTarget(KustvaktResource resource) {
+        this.target = resource.getPersistentID();
+        return this;
+    }
+
+    public SecurityPolicy setTarget(String target) {
+        this.target = target;
+        return this;
+    }
+
+    public String getTarget() {
+        return this.target;
+    }
+
+    public SecurityPolicy setPOSIX(String posix) {
+        this.permissions = new PermissionsBuffer(Short.valueOf(posix));
+        return this;
+    }
+
+    public SecurityPolicy setCreator(Integer creator) {
+        this.creator = creator;
+        return this;
+    }
+
+    // todo ???????
+    @Deprecated
+    public SecurityPolicy setOverride(Permissions.PERMISSIONS... perms) {
+        for (Permissions.PERMISSIONS p : perms)
+            this.permissions.addOverride(Permissions.getByte(p));
+        return this;
+    }
+
+    public SecurityPolicy setContext(PolicyContext ctx) {
+        this.ctx = ctx;
+        return this;
+    }
+
+    private boolean hasContext() {
+        return !ctx.noMask();
+    }
+
+    //todo:
+    public boolean isActive(User user) {
+        System.out.println("THE POLICY " + this.toString());
+        System.out.println("DOES THIS HAVE CONTEXT? " + this.hasContext());
+        //        String host = (String) user.getField(Attributes.HOST);
+        //        System.out.println("HOST IS " + host);
+        //        System.out.println("is active? " + ctx.isActive(host));
+        //        if (this.hasContext())
+        //            return ctx.isActive(host);
+        return !this.hasContext();
+    }
+
+    public List<String> getConditionList() {
+        List<String> c = new LinkedList<>();
+        Collections.sort(conditions);
+        for (PolicyCondition p : conditions)
+            c.add(p.getSpecifier());
+        return c;
+    }
+
+    public String getConditionString() {
+        if (conditions.isEmpty())
+            return "";
+
+        Collections.sort(conditions);
+        StringBuffer b = new StringBuffer();
+        for (PolicyCondition c : conditions) {
+            b.append(c);
+            b.append(";");
+        }
+        b.deleteCharAt(b.lastIndexOf(";"));
+        return b.toString();
+    }
+
+    public List<PolicyCondition> getConditions() {
+        return this.conditions;
+    }
+
+    public SecurityPolicy setConditions(PolicyCondition... constraints) {
+        this.conditions.clear();
+        this.removedidx.clear();
+        this.addedidx.clear();
+        for (int idx = 0; idx < constraints.length; idx++) {
+            this.conditions.add(idx, constraints[idx]);
+            this.addedidx.add(idx);
+        }
+        return this;
+    }
+
+    public SecurityPolicy removeCondition(PolicyCondition constraint) {
+        this.removedidx.add(this.conditions.indexOf(constraint));
+        return this;
+    }
+
+    public SecurityPolicy addCondition(PolicyCondition constraint) {
+        if (this.conditions.add(constraint))
+            this.addedidx.add(this.conditions.indexOf(constraint));
+        return this;
+    }
+
+    public boolean contains(PolicyCondition constraint) {
+        return conditions.contains(constraint);
+    }
+
+    public Collection<Integer> getRemoved() {
+        return this.removedidx;
+    }
+
+    public Collection<Integer> getAdded() {
+        return this.addedidx;
+    }
+
+    public void clear() {
+        // clear remove, add, conditions list!
+        for (Integer remove : this.removedidx)
+            this.conditions.remove(remove);
+        this.removedidx.clear();
+        this.addedidx.clear();
+    }
+
+    public boolean hasPermission(Permissions.PERMISSIONS perm) {
+        return permissions != null && permissions.containsPermission(perm);
+    }
+
+    /**
+     * function to add a permission byte to the collection.
+     *
+     * @param perms
+     * @return
+     */
+    public SecurityPolicy addPermission(Permissions.PERMISSIONS... perms) {
+        permissions.addPermissions(perms);
+        return this;
+    }
+
+    public boolean equalsPermission(Permissions.PERMISSIONS... perms) {
+        PermissionsBuffer b = new PermissionsBuffer();
+        b.addPermissions(perms);
+        return permissions != null && permissions.getPbyte()
+                .equals(b.getPbyte());
+    }
+
+    public void removePermission(Permissions.PERMISSIONS perm) {
+        if (permissions != null)
+            permissions.removePermission(perm);
+    }
+
+    public Byte getPermissionByte() {
+        return permissions.getPbyte();
+    }
+
+    @Override
+    public String toString() {
+        final StringBuffer sb = new StringBuffer("SecurityPolicy{");
+        sb.append("id=").append(id);
+        sb.append(", target='").append(target).append('\'');
+        sb.append(", conditions=").append(conditions);
+        sb.append(", permissions=").append(getPermissions());
+        sb.append('}');
+        return sb.toString();
+    }
+
+    public Set<Permissions.PERMISSIONS> getPermissions() {
+        return permissions.getPermissions();
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o)
+            return true;
+        if (o == null || getClass() != o.getClass())
+            return false;
+
+        SecurityPolicy policy = (SecurityPolicy) o;
+
+        if (id != policy.id)
+            return false;
+        if (target != policy.target)
+            return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = id;
+        result = 31 * result + target.hashCode();
+        return result;
+    }
+
+    @Getter
+    public static class OwnerPolicy extends SecurityPolicy {
+        private final Integer owner;
+
+        public OwnerPolicy(String target, Integer owner) {
+            this.owner = owner;
+            super.setTarget(target);
+        }
+
+        @Override
+        public String toString() {
+            return "OwnerPolicy(" + super.getTarget() + "," + owner + ")";
+        }
+
+    }
+}
diff --git a/src/main/java/de/ids_mannheim/korap/security/ac/ConditionManagement.java b/src/main/java/de/ids_mannheim/korap/security/ac/ConditionManagement.java
new file mode 100644
index 0000000..d403b69
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/security/ac/ConditionManagement.java
@@ -0,0 +1,111 @@
+package de.ids_mannheim.korap.security.ac;
+
+import de.ids_mannheim.korap.config.BeanConfiguration;
+import de.ids_mannheim.korap.exceptions.EmptyResultException;
+import de.ids_mannheim.korap.exceptions.KustvaktException;
+import de.ids_mannheim.korap.exceptions.NotAuthorizedException;
+import de.ids_mannheim.korap.interfaces.PolicyHandlerIface;
+import de.ids_mannheim.korap.resources.KustvaktResource;
+import de.ids_mannheim.korap.resources.Permissions;
+import de.ids_mannheim.korap.security.PolicyCondition;
+import de.ids_mannheim.korap.user.User;
+import de.ids_mannheim.korap.utils.KustvaktLogger;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.*;
+
+/**
+ * @author hanl
+ * @date 04/03/2014
+ */
+public class ConditionManagement {
+
+    private static final Logger errorLogger = LoggerFactory
+            .getLogger(KustvaktLogger.ERROR_LOG);
+    private static final Logger secErrorLogger = LoggerFactory
+            .getLogger(KustvaktLogger.SECURITY_LOG);
+    private User user;
+    private PolicyHandlerIface policydao;
+
+    public ConditionManagement(User user) {
+        this.user = user;
+        this.policydao = BeanConfiguration.getBeans().getPolicyDbProvider();
+
+    }
+
+    /**
+     * adds a user to an existing group
+     *
+     * @param usernames
+     * @param condition
+     * @param admin
+     */
+    // todo: conflict resolution
+    // fixme: not applicable to korap system roles
+    // only works if there is a policy with that condition and permission set, if not, create one!
+    public void addUser(List<String> usernames, PolicyCondition condition,
+            boolean admin) throws NotAuthorizedException, KustvaktException {
+        if (policydao.matchCondition(this.user, condition.getSpecifier(), true)
+                == 1) {
+            policydao.addToCondition(usernames, condition, admin);
+        }else
+            secErrorLogger.error("Users could not be added to condition '{}'",
+                    condition.getSpecifier());
+    }
+
+    public void addUser(String username, PolicyCondition condition,
+            boolean admin) throws NotAuthorizedException, KustvaktException {
+        addUser(Arrays.asList(username), condition, admin);
+    }
+
+    public void removeUser(List<String> users, PolicyCondition condition)
+            throws KustvaktException {
+        if (policydao.matchCondition(this.user, condition.getSpecifier(), true)
+                == 1) {
+            policydao.removeFromCondition(users, condition);
+        }
+    }
+
+    public Set<String> getMembers(PolicyCondition condition) {
+        try {
+            if (policydao
+                    .matchCondition(this.user, condition.getSpecifier(), true)
+                    == 1) {
+                return new HashSet<>(
+                        policydao.getUsersFromCondition(condition));
+            }
+        }catch (KustvaktException e) {
+            return Collections.emptySet();
+        }
+        return Collections.emptySet();
+    }
+
+    @Deprecated
+    public void addUser(KustvaktResource resource, String user,
+            Permissions.PERMISSIONS... pps)
+            throws NotAuthorizedException, KustvaktException,
+            EmptyResultException {
+        addUser(resource, Arrays.asList(user), pps);
+    }
+
+    @Deprecated
+    public void addUser(KustvaktResource resource, List<String> users,
+            Permissions.PERMISSIONS... pps)
+            throws NotAuthorizedException, KustvaktException,
+            EmptyResultException {
+        SecurityManager policies = SecurityManager
+                .findbyId(resource.getId(), this.user);
+        PolicyCondition c = policies.getExtensional(pps);
+        if (c != null)
+            this.addUser(users, c, false);
+        else {
+            PolicyCondition ex = new PolicyCondition();
+            new PolicyBuilder(this.user).setResources(resource)
+                    .addCondition(ex.getSpecifier()).setPermissions(pps)
+                    .create();
+            this.addUser(users, ex, false);
+        }
+    }
+
+}
diff --git a/src/main/java/de/ids_mannheim/korap/security/ac/PolicyBuilder.java b/src/main/java/de/ids_mannheim/korap/security/ac/PolicyBuilder.java
new file mode 100644
index 0000000..47faa2e
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/security/ac/PolicyBuilder.java
@@ -0,0 +1,168 @@
+package de.ids_mannheim.korap.security.ac;
+
+import de.ids_mannheim.korap.exceptions.KustvaktException;
+import de.ids_mannheim.korap.exceptions.NotAuthorizedException;
+import de.ids_mannheim.korap.exceptions.StatusCodes;
+import de.ids_mannheim.korap.resources.KustvaktResource;
+import de.ids_mannheim.korap.resources.Permissions;
+import de.ids_mannheim.korap.resources.Relation;
+import de.ids_mannheim.korap.security.PolicyCondition;
+import de.ids_mannheim.korap.security.PolicyContext;
+import de.ids_mannheim.korap.security.SecurityPolicy;
+import de.ids_mannheim.korap.user.User;
+
+/**
+ * @author hanl
+ * @date 14/04/2014
+ */
+
+// todo: also be able to create or edit relations
+public class PolicyBuilder {
+
+    private User user;
+    private KustvaktResource[] resources;
+    private KustvaktResource[] parents;
+    private Permissions.PERMISSIONS[] permissions;
+    private PolicyCondition[] conditions;
+    //    private Map<String, ParameterSettingsHandler> settings;
+    private Relation rel = null;
+    private PolicyContext context;
+
+    public PolicyBuilder(User user) {
+        this.user = user;
+    }
+
+    public PolicyBuilder setResources(KustvaktResource... targets) {
+        this.resources = targets;
+        this.parents = new KustvaktResource[targets.length];
+        return this;
+    }
+
+    /**
+     * set the parents for the resources. Order is relevant, since the relation parent - resource is handled
+     * via the index within the array. Parent relation is limited to depth 1!
+     * In case of a skipped parent resource relation within the array, set 'null'
+     *
+     * @param parents
+     * @return
+     */
+    public PolicyBuilder setParents(KustvaktResource... parents) {
+        for (int idx = 0; idx < parents.length; idx++)
+            this.parents[idx] = parents[idx];
+        return this;
+    }
+
+    public PolicyBuilder setContext(PolicyContext context) {
+        this.context = context;
+        return this;
+    }
+
+    public PolicyBuilder setContext(long start, long end) {
+        if (this.context == null)
+            this.context = new PolicyContext();
+        this.context.setEnableTime(start);
+        this.context.setExpirationTime(end);
+        return this;
+    }
+
+    public PolicyBuilder setLocation(String iprange) {
+        if (this.context == null)
+            this.context = new PolicyContext();
+        this.context.setIPMask(iprange);
+        return this;
+    }
+
+    public PolicyBuilder setPermissions(
+            Permissions.PERMISSIONS... permissions) {
+        this.permissions = permissions;
+        return this;
+    }
+
+    public PolicyBuilder setConditions(String... conditions) {
+        this.conditions = new PolicyCondition[conditions.length];
+        for (int idx = 0; idx < conditions.length; idx++)
+            this.conditions[idx] = new PolicyCondition(conditions[idx]);
+        return this;
+    }
+
+    public PolicyBuilder setConditions(PolicyCondition... conditions) {
+        this.conditions = new PolicyCondition[conditions.length];
+        for (int idx = 0; idx < conditions.length; idx++)
+            this.conditions[idx] = conditions[idx];
+        return this;
+    }
+
+    public PolicyBuilder setRelation(Relation rel) {
+        this.rel = rel;
+        return this;
+    }
+
+    public PolicyBuilder addCondition(String condition) {
+        if (this.rel == null)
+            setRelation(Relation.AND);
+        return setConditions(condition);
+    }
+
+    public void create() throws NotAuthorizedException, KustvaktException {
+        this.doIt();
+    }
+
+    // for and relations there is no way of setting parameters conjoined with the policy
+    private void doIt() throws KustvaktException, NotAuthorizedException {
+        if (this.resources == null)
+            throw new KustvaktException(user.getId(),
+                    StatusCodes.ILLEGAL_ARGUMENT, "resource must be set",
+                    "resource");
+        if (this.permissions == null)
+            throw new KustvaktException(user.getId(),
+                    StatusCodes.ILLEGAL_ARGUMENT, "permissions must be set",
+                    "permission");
+        if (this.conditions == null)
+            throw new KustvaktException(user.getId(),
+                    StatusCodes.ILLEGAL_ARGUMENT, "conditions must be set",
+                    "condition");
+        if (this.rel == null)
+            this.rel = Relation.AND;
+
+        for (int idx = 0; idx < this.resources.length; idx++) {
+            resources[idx].setParentID(parents[idx].getPersistentID());
+            SecurityManager manager = SecurityManager
+                    .register(resources[idx], user);
+
+            if (rel.equals(Relation.AND)) {
+                SecurityPolicy policy = new SecurityPolicy()
+                        .setConditions(this.conditions)
+                        .setTarget(resources[idx]).addPermission(permissions)
+                        .setCreator(this.user.getId());
+
+                if (this.context != null)
+                    policy.setContext(this.context);
+
+                manager.addPolicy(policy);
+
+            }else if (rel.equals(Relation.OR)) {
+                for (PolicyCondition c : this.conditions) {
+                    SecurityPolicy policy = new SecurityPolicy().addCondition(c)
+                            .setTarget(resources[idx])
+                            .addPermission(permissions)
+                            .setCreator(this.user.getId());
+
+                    if (this.context != null)
+                        policy.setContext(this.context);
+
+                    //                    if (this.settings != null) {
+                    //                        ParameterSettingsHandler settings = this.settings
+                    //                                .get(c.getSpecifier());
+                    //                        if (settings != null) {
+                    //                            // fixme: context setting overlap!
+                    //                            policy.setContext(settings.getContext());
+                    //                            manager.addPolicy(policy, settings.getParameters());
+                    //                            continue;
+                    //                        }
+                    //                    }
+                    manager.addPolicy(policy);
+                }
+            }
+        }
+    }
+}
diff --git a/src/main/java/de/ids_mannheim/korap/security/ac/PolicyEvaluator.java b/src/main/java/de/ids_mannheim/korap/security/ac/PolicyEvaluator.java
new file mode 100644
index 0000000..4cd79d5
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/security/ac/PolicyEvaluator.java
@@ -0,0 +1,148 @@
+package de.ids_mannheim.korap.security.ac;
+
+import de.ids_mannheim.korap.exceptions.NotAuthorizedException;
+import de.ids_mannheim.korap.exceptions.StatusCodes;
+import de.ids_mannheim.korap.resources.KustvaktResource;
+import de.ids_mannheim.korap.resources.Permissions;
+import de.ids_mannheim.korap.security.PermissionsBuffer;
+import de.ids_mannheim.korap.security.SecurityPolicy;
+import de.ids_mannheim.korap.user.KorAPUser;
+import de.ids_mannheim.korap.user.User;
+import edu.emory.mathcs.backport.java.util.Collections;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Created by hanl on 5/22/14.
+ */
+public class PolicyEvaluator {
+
+    private final User user;
+    private final List<SecurityPolicy>[] policies;
+    private String resourceID;
+    private PermissionsBuffer permissions;
+    private boolean processed;
+    private int relationError = -1;
+    private Map<String, Object> flags;
+
+
+    public PolicyEvaluator(User user, List<SecurityPolicy>[] policies) {
+        this.user = user;
+        this.policies = policies;
+        this.permissions = new PermissionsBuffer();
+        this.flags = new HashMap<>();
+    }
+
+    private PolicyEvaluator(User user, KustvaktResource resource) {
+        this.user = user;
+        this.resourceID = resource.getPersistentID();
+        this.permissions = new PermissionsBuffer();
+        this.flags = new HashMap<>();
+        this.policies = null;
+    }
+
+    public String getResourceID() {
+        if (this.resourceID == null && policies[0] != null
+                && policies[0].get(0) != null)
+            this.resourceID = policies[0].get(0).getTarget();
+        return this.resourceID;
+    }
+
+
+    private List<SecurityPolicy> evaluate(List<SecurityPolicy>[] policies,
+                                          Permissions.PERMISSIONS perm) throws NotAuthorizedException {
+        //fixme: what happens in case a parent relation does not allow changing a resource, but the owner of child per default
+        // receives all rights? --> test casing
+        if (isOwner()) return policies[0];
+        if (!processed && policies != null) {
+            for (int i = policies.length - 1; i >= 0; i--) {
+                int idx = 0;
+                if (policies[i] != null) {
+                    int ow = getOwner(policies[i]);
+                    for (int internal = 0; internal < policies[i].size(); internal++) {
+                        SecurityPolicy s = policies[i].get(internal);
+                        if (i == policies.length - 1) {
+                            if (ow == user.getId())
+                                this.permissions.addPermission(127);
+                            else if (!(s instanceof SecurityPolicy.OwnerPolicy))
+                                this.permissions.addPermission(s.getPermissionByte());
+                        } else {
+                            if (ow == user.getId())
+                                this.permissions.retain(127);
+                            else if (!(s instanceof SecurityPolicy.OwnerPolicy))
+                                this.permissions.retain(s.getPermissionByte());
+                        }
+                        idx++;
+                    }
+                }
+                if (idx == 0) {
+                    relationError = i;
+                    throw new NotAuthorizedException(StatusCodes.PERMISSION_DENIED, this.getResourceID());
+                }
+            }
+            this.processed = true;
+            System.out.println("FINAL BYTE :" + this.permissions.getPbyte());
+            if (this.permissions.containsPermission(perm))
+                return policies[0];
+        } else if (processed && relationError == -1
+                && this.permissions.containsPermission(perm))
+            return this.policies[0];
+
+        return Collections.emptyList();
+    }
+
+    /**
+     * checks read permission
+     *
+     * @return
+     */
+    public boolean isAllowed() {
+        return isAllowed(Permissions.PERMISSIONS.READ);
+    }
+
+    public boolean isAllowed(Permissions.PERMISSIONS perm) {
+        try {
+            return !evaluate(this.policies, perm).isEmpty();
+        } catch (NotAuthorizedException e) {
+            return false;
+        }
+    }
+
+    public boolean isOwner() {
+        return policies != null && this.user.getId() != null && getOwner(this.policies[0]) == this.user.getId();
+    }
+
+    private int getOwner(List<SecurityPolicy> policies) {
+        if (policies != null && policies.get(0) != null
+                && policies.get(0) instanceof SecurityPolicy.OwnerPolicy) {
+            return ((SecurityPolicy.OwnerPolicy) policies.get(0)).getOwner();
+        }
+        return -1;
+    }
+
+    public static PolicyEvaluator setFlags(User user, KustvaktResource resource) {
+        PolicyEvaluator e = new PolicyEvaluator(user, resource);
+        e.setFlag("managed", resource.getOwner() == KorAPUser.ADMINISTRATOR_ID);
+        e.setFlag("shared", false);
+        return e;
+    }
+
+    public <V> V getFlag(String key, V value) {
+        return (V) this.flags.get(key);
+    }
+
+    private <V> void setFlag(String key, V value) {
+        this.flags.put(key, value);
+    }
+
+    public boolean isManaged() {
+        return getOwner(this.policies[0]) == KorAPUser.ADMINISTRATOR_ID;
+    }
+
+    public boolean isShared() {
+        return !isManaged() && !isOwner();
+    }
+
+}
diff --git a/src/main/java/de/ids_mannheim/korap/security/ac/ResourceFinder.java b/src/main/java/de/ids_mannheim/korap/security/ac/ResourceFinder.java
new file mode 100755
index 0000000..ed0462b
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/security/ac/ResourceFinder.java
@@ -0,0 +1,119 @@
+package de.ids_mannheim.korap.security.ac;
+
+import de.ids_mannheim.korap.exceptions.KustvaktException;
+import de.ids_mannheim.korap.interfaces.PolicyHandlerIface;
+import de.ids_mannheim.korap.interfaces.ResourceOperationIface;
+import de.ids_mannheim.korap.resources.KustvaktResource;
+import de.ids_mannheim.korap.resources.Permissions;
+import de.ids_mannheim.korap.resources.ResourceFactory;
+import de.ids_mannheim.korap.security.PermissionsBuffer;
+import de.ids_mannheim.korap.user.User;
+import de.ids_mannheim.korap.utils.KustvaktLogger;
+import org.slf4j.Logger;
+
+import java.util.*;
+
+/**
+ * Created by hanl on 3/20/14.
+ */
+public class ResourceFinder {
+
+    private static final Logger log = KustvaktLogger.initiate(ResourceFinder.class);
+    private static PolicyHandlerIface policydao;
+
+    private List<KustvaktResource.Container> containers;
+    private User user;
+
+    private ResourceFinder(User user) {
+        this.containers = new ArrayList<>();
+        this.user = user;
+    }
+
+    public static final void setProviders(PolicyHandlerIface policyHandler, ResourceHandler handler) {
+        ResourceFinder.policydao = policyHandler;
+//        ResourceFinder.handler = handler;
+    }
+
+    public static <T extends KustvaktResource> Set<T> search(String path, boolean asParent,
+                                                          User user, Class<T> clazz, Permissions.PERMISSIONS... perms)
+            throws KustvaktException {
+        ResourceFinder cat = init(path, asParent, user, clazz, perms);
+        return cat.getResources();
+    }
+
+    private static <T extends KustvaktResource> ResourceFinder init(String path, boolean asParent,
+                                                                User user, Class<T> clazz, Permissions.PERMISSIONS... perms) throws
+            KustvaktException {
+        ResourceFinder cat = new ResourceFinder(user);
+        PermissionsBuffer buffer = new PermissionsBuffer();
+        if (perms.length == 0)
+            buffer.addPermissions(Permissions.PERMISSIONS.READ);
+        buffer.addPermissions(perms);
+        cat.retrievePolicies(path, buffer.getPbyte(), clazz, asParent);
+        return cat;
+    }
+
+    //todo: needs to be much faster!
+    public static <T extends KustvaktResource> ResourceFinder init(User user, Class<T> clazz)
+            throws KustvaktException {
+        return init(null, true, user, clazz, Permissions.PERMISSIONS.READ);
+    }
+
+    public static <T extends KustvaktResource> Set<T> search(String name, boolean asParent, User user, String type)
+            throws KustvaktException {
+        return (Set<T>) search(name, asParent, user, ResourceFactory
+                .getResourceClass(type), Permissions.PERMISSIONS.READ);
+    }
+
+    // todo: should this be working?
+    public static <T extends KustvaktResource> Set<T> search(User user, Class<T> clazz)
+            throws KustvaktException {
+        return search(null, true, user, clazz, Permissions.PERMISSIONS.READ);
+    }
+
+    private void retrievePolicies(String path, Byte b, Class type, boolean parent) throws
+            KustvaktException {
+        if (user == null | type == null)
+            return;
+        if (parent)
+            this.containers = policydao.getDescending(path, user, b, type);
+        else
+            this.containers = policydao.getAscending(path, user, b, type);
+    }
+
+
+    public <T extends KustvaktResource> Set<T> getResources() {
+        return evaluateResources();
+    }
+
+    private <T extends KustvaktResource> Set<T> evaluateResources() {
+        Set<T> resources = new HashSet<>();
+        if (this.containers != null) {
+            for (KustvaktResource.Container c : this.containers) {
+                ResourceOperationIface<T> iface = SecurityManager.getHandlers().get(c.getType());
+                if (iface == null)
+                    iface = SecurityManager.getHandlers().get(KustvaktResource.class);
+
+                try {
+                    T resource = (T) iface.findbyId(c.getPersistentID(), this.user);
+                    PolicyEvaluator e = PolicyEvaluator.setFlags(user, resource);
+                    resource.setManaged(e.getFlag("managed", false));
+                    resources.add(resource);
+                } catch (KustvaktException e) {
+                    // don't handle connection error or no handler registered!
+                    KustvaktLogger.ERROR_LOGGER.error("Error while retrieving containers '{}' ", this.containers);
+                    return Collections.emptySet();
+                }
+            }
+        }
+        return resources;
+    }
+
+    public Set<String> getIds() {
+        Set<String> resources = new HashSet<>();
+        for (KustvaktResource.Container c : this.containers)
+            resources.add(c.getPersistentID());
+        return resources;
+    }
+
+}
diff --git a/src/main/java/de/ids_mannheim/korap/security/ac/ResourceHandler.java b/src/main/java/de/ids_mannheim/korap/security/ac/ResourceHandler.java
new file mode 100644
index 0000000..9e4b152
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/security/ac/ResourceHandler.java
@@ -0,0 +1,165 @@
+package de.ids_mannheim.korap.security.ac;
+
+import de.ids_mannheim.korap.exceptions.EmptyResultException;
+import de.ids_mannheim.korap.exceptions.KustvaktException;
+import de.ids_mannheim.korap.exceptions.NotAuthorizedException;
+import de.ids_mannheim.korap.exceptions.StatusCodes;
+import de.ids_mannheim.korap.resources.KustvaktResource;
+import de.ids_mannheim.korap.resources.Permissions;
+import de.ids_mannheim.korap.resources.ResourceFactory;
+import de.ids_mannheim.korap.user.User;
+import de.ids_mannheim.korap.utils.KustvaktLogger;
+import net.sf.ehcache.CacheManager;
+import net.sf.ehcache.Element;
+import org.slf4j.Logger;
+
+import java.util.Collection;
+
+/**
+ * @author hanl
+ * @date 23/03/2014
+ */
+
+@SuppressWarnings("all")
+public class ResourceHandler {
+
+    private static Logger log = KustvaktLogger.initiate(ResourceHandler.class);
+
+    public ResourceHandler() {
+    }
+
+    public <T extends KustvaktResource> T getCache(Object id, Class<T> clazz) {
+        Element e = CacheManager.getInstance().getCache("resources")
+                .get(id);
+        if (e != null)
+            return (T) e.getObjectValue();
+        else
+            return null;
+    }
+
+    public <R extends KustvaktResource> void cache(R resource) {
+        CacheManager.getInstance().getCache("resources")
+                .put(new Element(resource.getPersistentID(), resource));
+    }
+
+    /**
+     * @param id
+     * @param user
+     * @return
+     * @throws KustvaktException         if there is no handler registered, resource might still be valid,
+     *                                only Notauthorized exception will cause a parsing error here
+     * @throws NotAuthorizedException
+     */
+    public <T extends KustvaktResource> T findbyIntId(Integer id, User user)
+            throws KustvaktException, NotAuthorizedException {
+        SecurityManager<T> p;
+        try {
+            p = SecurityManager.findbyId(id, user);
+        } catch (EmptyResultException e) {
+            throw new NotAuthorizedException(StatusCodes.PERMISSION_DENIED);
+        }
+
+        return p.getResource();
+    }
+
+    public <T extends KustvaktResource> T findbyStrId(String persistent_id,
+            User user, String type)
+            throws KustvaktException, NotAuthorizedException {
+        T cache = (T) getCache(persistent_id, ResourceFactory
+                .getResourceClass(type));
+        if (cache != null)
+            return cache;
+        else
+            return (T) findbyStrId(persistent_id, user,
+                    ResourceFactory.getResourceClass(type));
+    }
+
+    public <T extends KustvaktResource> T findbyStrId(String persistent_id,
+            User user, Class<T> type)
+            throws KustvaktException, NotAuthorizedException {
+        T cache = (T) getCache(persistent_id, type);
+        if (cache != null)
+            return cache;
+        else {
+            SecurityManager<T> p;
+            try {
+                p = SecurityManager.findbyId(persistent_id, user, type);
+            } catch (EmptyResultException e) {
+                throw new NotAuthorizedException(StatusCodes.EMPTY_RESULTS, persistent_id);
+            }
+            return p.getResource();
+        }
+    }
+
+    public <T extends KustvaktResource> Collection<T> findbyPath(String path, Class type, User user)
+            throws KustvaktException, NotAuthorizedException {
+        return ResourceFinder.search(path, false, user, type);
+    }
+
+
+    public <T extends KustvaktResource> void updateResources(User user, T... resources)
+            throws KustvaktException, NotAuthorizedException {
+        // fixme: what if update fails? then i have a root policy lingering for a resource that is not available?!
+        // fixme: transaction management
+
+        for (T resource : resources) {
+            SecurityManager policies;
+            try {
+                policies = SecurityManager.init(resource.getPersistentID(), user, Permissions.PERMISSIONS.WRITE);
+            } catch (EmptyResultException e) {
+                return;
+            }
+            policies.updateResource(resource);
+        }
+    }
+
+    public <T extends KustvaktResource> void storeResources(User user, T... resources)
+            throws KustvaktException, NotAuthorizedException {
+        for (T resource : resources)
+            SecurityManager.register(resource, user);
+    }
+
+    @Deprecated
+    public <T extends KustvaktResource> void deleteResources(User user, String... ids)
+            throws KustvaktException, NotAuthorizedException {
+        for (String id : ids) {
+            SecurityManager policies;
+            try {
+                policies = SecurityManager.init(id, user,
+                        Permissions.PERMISSIONS.DELETE);
+            } catch (EmptyResultException e) {
+                return;
+            }
+            policies.deleteResource();
+        }
+    }
+
+    public <T extends KustvaktResource> void deleteResources(User user, T... resources)
+            throws KustvaktException, NotAuthorizedException {
+        for (T r : resources) {
+            SecurityManager policies;
+            try {
+                policies = SecurityManager.findbyId(r.getPersistentID(), user, r.getClass(),
+                        Permissions.PERMISSIONS.DELETE);
+            } catch (EmptyResultException e) {
+                return;
+            }
+            policies.deleteResource();
+        }
+    }
+
+    @Deprecated
+    public <T extends KustvaktResource> void deleteResources(User user, Integer... ids)
+            throws KustvaktException, NotAuthorizedException {
+        for (Integer id : ids) {
+            SecurityManager policies;
+            try {
+                policies = SecurityManager.findbyId(id, user,
+                        Permissions.PERMISSIONS.DELETE);
+            } catch (EmptyResultException e) {
+                return;
+            }
+            policies.deleteResource();
+        }
+    }
+}
diff --git a/src/main/java/de/ids_mannheim/korap/security/ac/SecurityManager.java b/src/main/java/de/ids_mannheim/korap/security/ac/SecurityManager.java
new file mode 100644
index 0000000..6dd88a3
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/security/ac/SecurityManager.java
@@ -0,0 +1,490 @@
+package de.ids_mannheim.korap.security.ac;
+
+import de.ids_mannheim.korap.exceptions.EmptyResultException;
+import de.ids_mannheim.korap.exceptions.KustvaktException;
+import de.ids_mannheim.korap.exceptions.NotAuthorizedException;
+import de.ids_mannheim.korap.exceptions.StatusCodes;
+import de.ids_mannheim.korap.interfaces.EncryptionIface;
+import de.ids_mannheim.korap.interfaces.PolicyHandlerIface;
+import de.ids_mannheim.korap.interfaces.ResourceOperationIface;
+import de.ids_mannheim.korap.resources.KustvaktResource;
+import de.ids_mannheim.korap.resources.Permissions;
+import de.ids_mannheim.korap.security.Parameter;
+import de.ids_mannheim.korap.security.PermissionsBuffer;
+import de.ids_mannheim.korap.security.PolicyCondition;
+import de.ids_mannheim.korap.security.SecurityPolicy;
+import de.ids_mannheim.korap.user.User;
+import de.ids_mannheim.korap.utils.KustvaktLogger;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.*;
+
+/**
+ * should only be used if a resource is uniquely identifiable by either three methods: id, name or path!
+ * In any other case, use categorypolicies to retrieve policies of a certain type
+ *
+ * @author hanl
+ * @date 15/01/2014
+ */
+
+// todo: add auditing mechanism to this!
+@SuppressWarnings("all")
+public class SecurityManager<T extends KustvaktResource> {
+
+    private static final Logger secLogger = LoggerFactory
+            .getLogger(KustvaktLogger.SECURITY_LOG);
+    private static final Logger errorLogger = LoggerFactory
+            .getLogger(KustvaktLogger.ERROR_LOG);
+    private static PolicyHandlerIface policydao;
+    private static Map<Class<? extends KustvaktResource>, ResourceOperationIface> handlers;
+    private static EncryptionIface crypto;
+
+    private List<SecurityPolicy>[] policies;
+    private User user;
+
+    private boolean wException;
+    private PolicyEvaluator evaluator;
+    private T resource;
+
+    private SecurityManager(User user) {
+        this.policies = new List[1];
+        this.policies[0] = new ArrayList<>();
+        this.wException = true;
+        this.user = user;
+    }
+
+    public static final void setProviders(PolicyHandlerIface policyHandler,
+            EncryptionIface crypto, List<ResourceOperationIface> ifaces) {
+        SecurityManager.policydao = policyHandler;
+        SecurityManager.crypto = crypto;
+        SecurityManager.handlers = new HashMap<>();
+        secLogger.info("Registering handlers: {}", Arrays.asList(ifaces));
+        for (ResourceOperationIface iface : ifaces)
+            handlers.put(iface.getType(), iface);
+    }
+
+    public static Map<Class<? extends KustvaktResource>, ResourceOperationIface> getHandlers() {
+        return handlers;
+    }
+
+    /**
+     * only allowed if the resource is uniquely identifiable by the name, if not, use path or id!
+     * Shortcut so resource values do not need to be retrieved afterwards!
+     *
+     * @param name
+     * @param user
+     * @param type
+     * @return
+     * @throws EmptyResultException
+     * @throws KustvaktException
+     */
+    public static SecurityManager findbyId(String id, User user, Class type,
+            Permissions.PERMISSIONS... perms)
+            throws EmptyResultException, KustvaktException,
+            NotAuthorizedException {
+        SecurityManager p = new SecurityManager(user);
+        p.findPolicies(id, false, perms);
+        p.resource = p.findResource(type);
+        return p;
+    }
+
+    public static SecurityManager findbyId(String id, User user,
+            Permissions.PERMISSIONS... perms)
+            throws NotAuthorizedException, KustvaktException,
+            EmptyResultException {
+        SecurityManager p = new SecurityManager(user);
+        p.findPolicies(id, false, perms);
+        p.resource = p.findResource(null);
+        return p;
+    }
+
+    public static SecurityManager findbyId(Integer id, User user,
+            Permissions.PERMISSIONS... perms)
+            throws EmptyResultException, KustvaktException,
+            NotAuthorizedException {
+        SecurityManager p = new SecurityManager(user);
+        p.findPolicies(id, false, perms);
+        p.resource = p.findResource(null);
+        return p;
+    }
+
+    public static SecurityManager findbyPath(String path, User user,
+            Permissions.PERMISSIONS... perms)
+            throws NotAuthorizedException, EmptyResultException {
+        SecurityManager manager = new SecurityManager(user);
+        manager.findPolicies(path, true, perms);
+        //fixme: need a match count. if match not unique, exception. also, does parent -child relation match hold up here?
+        return manager;
+    }
+
+    public static SecurityManager init(String id, User user,
+            Permissions.PERMISSIONS... perms)
+            throws NotAuthorizedException, EmptyResultException {
+        SecurityManager p = new SecurityManager(user);
+        p.findPolicies(id, false, perms);
+        return p;
+    }
+
+    /**
+     * enables retrieval for read access only!
+     *
+     * @return
+     * @throws NotAuthorizedException
+     */
+    public T getResource() throws NotAuthorizedException {
+        if (evaluator.isAllowed(Permissions.PERMISSIONS.READ)) {
+            return this.resource;
+        }else {
+            secLogger
+                    .error("Reading the resource '{}' is not allowed for user '{}'",
+                            this.resource.getPersistentID(),
+                            this.user.getUsername());
+            throw new NotAuthorizedException(StatusCodes.PERMISSION_DENIED,
+                    evaluator.getResourceID());
+        }
+    }
+
+    public void updateResource(T resource)
+            throws NotAuthorizedException, KustvaktException {
+        if (evaluator.isAllowed(Permissions.PERMISSIONS.WRITE)) {
+            ResourceOperationIface iface = handlers.get(resource.getClass());
+            if (iface != null)
+                iface.updateResource(resource, this.user);
+            else
+                handlers.get(KustvaktResource.class)
+                        .updateResource(resource, this.user);
+        }else {
+            secLogger
+                    .error("Updating the resource '{}' is not allowed for user '{}'",
+                            this.resource.getPersistentID(),
+                            this.user.getUsername());
+            throw new NotAuthorizedException(StatusCodes.PERMISSION_DENIED,
+                    this.evaluator.getResourceID());
+        }
+
+    }
+
+    /**
+     * @throws NotAuthorizedException
+     * @throws KustvaktException
+     */
+    // todo: delete only works with find, not with init constructor!resource
+    public void deleteResource() throws NotAuthorizedException,
+            KustvaktException {
+        if (evaluator.isAllowed(Permissions.PERMISSIONS.DELETE)) {
+            ResourceOperationIface iface = handlers
+                    .get(this.resource.getClass());
+            if (iface != null)
+                iface.deleteResource(this.evaluator.getResourceID(), this.user);
+            else
+                handlers.get(KustvaktResource.class)
+                        .deleteResource(this.evaluator.getResourceID(),
+                                this.user);
+            //            this.policydao.deleteResourcePolicies(this.evaluator.getResourceID(), this.user);
+        }else
+            throw new NotAuthorizedException(StatusCodes.PERMISSION_DENIED,
+                    this.evaluator.getResourceID());
+    }
+
+
+    // todo: type should be deprecated and return type of policies should be containers!
+    private boolean findPolicies(Object id, boolean path,
+            Permissions.PERMISSIONS... perms)
+            throws NotAuthorizedException, EmptyResultException {
+        PermissionsBuffer b = new PermissionsBuffer();
+        if (perms.length == 0)
+            b.addPermission(Permissions.READ);
+        else
+            b.addPermissions(perms);
+        if (id instanceof String && !path)
+            this.policies = policydao
+                    .getPolicies((String) id, this.user, b.getPbyte());
+        if (id instanceof String && path)
+            this.policies = policydao
+                    .findPolicies((String) id, this.user, b.getPbyte());
+        if (id instanceof Integer)
+            this.policies = policydao
+                    .getPolicies((Integer) id, this.user, b.getPbyte());
+        this.evaluator = new PolicyEvaluator(this.user, this.policies);
+
+        if (this.policies == null) {
+            KustvaktLogger.SECURITY_LOGGER
+                    .error("No policies found for resource id '{}' for user '{}'",
+                            id, user.getId());
+            throw new EmptyResultException(String.valueOf(id));
+        }
+        return true;
+    }
+
+    private T findResource(Class type)
+            throws NotAuthorizedException, KustvaktException {
+        if (!evaluator.isAllowed()) {
+            KustvaktLogger.SECURITY_LOGGER
+                    .error("Permission denied for resource id '{}' for user '{}'",
+                            this.evaluator.getResourceID(), user.getId());
+            throw new NotAuthorizedException(StatusCodes.PERMISSION_DENIED,
+                    this.evaluator.getResourceID());
+        }
+
+        ResourceOperationIface iface = handlers.get(type);
+        if (iface == null)
+            iface = handlers.get(KustvaktResource.class);
+        T resource = (T) iface
+                .findbyId(this.evaluator.getResourceID(), this.user);
+        resource.setManaged(this.evaluator.isManaged());
+        resource.setShared(this.evaluator.isShared());
+        return resource;
+    }
+
+    private boolean checkResource(String persistentID, User user)
+            throws KustvaktException {
+        ResourceOperationIface iface = handlers.get(KustvaktResource.class);
+        return iface.findbyId(persistentID, user) != null;
+    }
+
+    public static SecurityManager register(KustvaktResource resource, User user)
+            throws KustvaktException, NotAuthorizedException {
+        SecurityManager p = new SecurityManager(user);
+        if (!user.isDemo()) {
+            if (resource.getParentID() != null) {
+                try {
+                    // the owner has all rights per default, in order to be able derivate from a parent resource, he needs all permissions as well
+                    // this is mostly for convenvience and database consistency, since a request query would result in not authorized, based on missing parent relation dependencies
+                    // --> in order not to have a resource owner that is denied access due to missing parent relation dependency
+                    SecurityManager.findbyId(resource.getParentID(), user,
+                            Permissions.PERMISSIONS.CREATE_POLICY,
+                            Permissions.PERMISSIONS.MODIFY_POLICY,
+                            Permissions.PERMISSIONS.DELETE_POLICY,
+                            Permissions.PERMISSIONS.READ_POLICY,
+                            Permissions.PERMISSIONS.READ,
+                            Permissions.PERMISSIONS.WRITE,
+                            Permissions.PERMISSIONS.DELETE);
+                }catch (EmptyResultException e) {
+                    KustvaktLogger.SECURITY_LOGGER
+                            .error("No policies found for parent '{}' for user '{}'",
+                                    resource.getParentID(), user.getId());
+                    throw new KustvaktException(StatusCodes.EMPTY_RESULTS);
+                }
+            }
+            boolean newid = false;
+            // create persistent identifier for the resource
+            if (resource.getPersistentID() == null || resource.getPersistentID()
+                    .isEmpty()) {
+                resource.setPersistentID(p.crypto.createID());
+                newid = true;
+            }
+
+            if (newid | !p.checkResource(resource.getPersistentID(), user)) {
+                resource.setOwner(user.getId());
+
+                KustvaktLogger.SECURITY_LOGGER
+                        .trace("Creating Access Control structure for resource '"
+                                + resource.getPersistentID() + "@" + resource
+                                .getId() + "'");
+                // storing resource is called twice. first when this is register and later in idsbootstrap to create cstorage entry. how to unify this?
+                ResourceOperationIface iface = p.handlers
+                        .get(resource.getClass());
+                if (iface != null)
+                    resource.setId(iface.storeResource(resource, user));
+                else
+                    // retrieve default handler for resource!
+                    resource.setId(p.handlers.get(KustvaktResource.class)
+                            .storeResource(resource, user));
+            }
+            p.resource = resource;
+            try {
+                p.findPolicies(resource.getId(), false,
+                        Permissions.PERMISSIONS.CREATE_POLICY,
+                        Permissions.PERMISSIONS.READ_POLICY,
+                        Permissions.PERMISSIONS.MODIFY_POLICY);
+            }catch (EmptyResultException e) {
+                KustvaktLogger.SECURITY_LOGGER
+                        .error("No policies found for '{}' for user '{}'",
+                                resource.getPersistentID(), user.getId());
+                throw new KustvaktException(user.getId(),StatusCodes.POLICY_CREATE_ERROR,
+                        "Resource could not be registered",
+                        resource.toString());
+            }
+        }
+        return p;
+    }
+
+    @Deprecated
+    public List<SecurityPolicy> getPoliciesList(int i) {
+        if (i < this.policies.length)
+            return this.policies[i];
+        return Collections.emptyList();
+    }
+
+    // fixme: make protected
+    public SecurityPolicy getPolicy(Integer id) {
+        for (SecurityPolicy p : this.policies[0])
+            if (p.getID() == id)
+                return p;
+        return null;
+    }
+
+    // fixme: make protected
+    public PolicyCondition getExtensional(Permissions.PERMISSIONS... pps) {
+        for (SecurityPolicy p : this.policies[0]) {
+            if (p.equalsPermission(pps)) {
+                for (PolicyCondition c : p.getConditions()) {
+                    if (c.isExtensional())
+                        return c;
+                }
+            }
+        }
+        return null;
+    }
+
+    private boolean matchTarget(String target) {
+        return this.resource.getPersistentID() != null && (
+                this.resource.getPersistentID() == target);
+    }
+
+    public void addPolicy(SecurityPolicy policy, Parameter... params)
+            throws KustvaktException, NotAuthorizedException {
+        if (policy.getConditions().isEmpty()) {
+            KustvaktLogger.SECURITY_LOGGER
+                    .error("No conditions set for '{}' for user '{}'",
+                            policy.toString(), this.user.getId());
+            throw new NotAuthorizedException(StatusCodes.ILLEGAL_ARGUMENT,
+                    policy.getTarget());
+        }
+
+        if (this.policies[0] == null) {
+            KustvaktLogger.SECURITY_LOGGER
+                    .error("No policies found for '{}' for user '{}'",
+                            this.evaluator.getResourceID(), this.user.getId());
+            throw new NotAuthorizedException(StatusCodes.UNSUPPORTED_OPERATION,
+                    policy.getTarget());
+        }
+
+        if (contains(policy)) {
+            modifyPolicy(policy);
+            return;
+        }
+
+        if (evaluator.isAllowed(Permissions.PERMISSIONS.CREATE_POLICY)) {
+            policydao.createPolicy(policy, this.user);
+        }else if (wException) {
+            KustvaktLogger.SECURITY_LOGGER
+                    .error("Permission Denied (CREATE_POLICY) on '{}' for user '{}'",
+                            this.evaluator.getResourceID(), this.user.getId());
+            throw new NotAuthorizedException(StatusCodes.PERMISSION_DENIED,
+                    policy.getTarget());
+        }
+
+        if (params != null && params.length > 0) {
+            for (Parameter p : params) {
+                p.setPolicy(policy);
+                policydao.createParamBinding(p);
+            }
+        }
+        this.policies[0].add(policy);
+    }
+
+    public void deletePolicies() throws NotAuthorizedException,
+            KustvaktException {
+        for (SecurityPolicy p : new ArrayList<>(this.policies[0]))
+            deletePolicy(p);
+    }
+
+    public void retainPolicies(List<SecurityPolicy> policies)
+            throws NotAuthorizedException, KustvaktException {
+        for (SecurityPolicy p : new ArrayList<>(this.policies[0])) {
+            if (!policies.contains(p))
+                this.deletePolicy(p);
+        }
+    }
+
+    public void deletePolicy(SecurityPolicy policy)
+            throws KustvaktException, NotAuthorizedException {
+        // todo: get rid of this: use sql to match policy id and target according to evaluator!
+        if (!matchTarget(policy.getTarget()))
+            // adjust message
+            throw new NotAuthorizedException(StatusCodes.ILLEGAL_ARGUMENT,
+                    this.evaluator.getResourceID());
+
+        if (this.policies[0] == null) {
+            KustvaktLogger.SECURITY_LOGGER
+                    .error("No policies found (DELETE_POLICY) on '{}' for '{}'",
+                            this.evaluator.getResourceID(), this.user.getId());
+            throw new KustvaktException(user.getId(),StatusCodes.NO_POLICIES,
+                    "no policy desicion possible",
+                    this.evaluator.getResourceID());
+        }
+        if (contains(policy) && (evaluator
+                .isAllowed(Permissions.PERMISSIONS.DELETE_POLICY))) {
+            policydao.deletePolicy(policy, this.user);
+        }else if (wException) {
+            KustvaktLogger.SECURITY_LOGGER
+                    .error("Permission Denied (DELETE_POLICY) on '{}' for '{}'",
+                            this.evaluator.getResourceID(), this.user.getId());
+            throw new NotAuthorizedException(StatusCodes.PERMISSION_DENIED,
+                    "no policy desicion possible",
+                    this.evaluator.getResourceID());
+        }
+        policydao.removeParamBinding(policy);
+
+        this.policies[0].remove(policy);
+    }
+
+    public void modifyPolicy(SecurityPolicy policy)
+            throws KustvaktException, NotAuthorizedException {
+        if (!matchTarget(policy.getTarget()))
+            throw new NotAuthorizedException(StatusCodes.ILLEGAL_ARGUMENT);
+
+        if (this.policies[0] == null) {
+            KustvaktLogger.SECURITY_LOGGER
+                    .error("Operation not possible (MODIFY_POLICY) on '{}' for '{}'",
+                            this.evaluator.getResourceID(), this.user.getId());
+            throw new KustvaktException(user.getId(),StatusCodes.NO_POLICIES,
+                    "no policy desicion possible",
+                    this.evaluator.getResourceID());
+        }
+
+        if (contains(policy) && (evaluator
+                .isAllowed(Permissions.PERMISSIONS.MODIFY_POLICY))) {
+            policydao.updatePolicy(policy, this.user);
+        }else if (wException) {
+            KustvaktLogger.SECURITY_LOGGER
+                    .error("Permission Denied (DELETE_POLICY) on '{}' for '{}'",
+                            this.evaluator.getResourceID(), this.user.getId());
+            throw new NotAuthorizedException(StatusCodes.PERMISSION_DENIED,
+                    this.evaluator.getResourceID());
+        }
+        this.policies = policydao
+                .getPolicies((int) this.resource.getId(), this.user, null);
+    }
+
+    /**
+     * standard function for READ access on the resource
+     *
+     * @return boolean is action allowed for resource
+     */
+    public boolean isAllowed() {
+        return evaluator.isAllowed();
+    }
+
+    public boolean isAllowed(Permissions.PERMISSIONS... perm) {
+        return evaluator.isAllowed();
+    }
+
+    /**
+     * checks if that exact object already exists (compares name,
+     * conditional parameter)
+     *
+     * @param policy
+     * @return
+     */
+    public boolean contains(SecurityPolicy policy) {
+        try {
+            return policydao.checkPolicy(policy, this.user) == 1;
+        }catch (KustvaktException e) {
+            return false;
+        }
+    }
+
+}
diff --git a/src/main/java/de/ids_mannheim/korap/security/auth/APIAuthentication.java b/src/main/java/de/ids_mannheim/korap/security/auth/APIAuthentication.java
index df9f1b8..13e383d 100644
--- a/src/main/java/de/ids_mannheim/korap/security/auth/APIAuthentication.java
+++ b/src/main/java/de/ids_mannheim/korap/security/auth/APIAuthentication.java
@@ -11,7 +11,6 @@
 import de.ids_mannheim.korap.user.TokenContext;
 import de.ids_mannheim.korap.user.User;
 import de.ids_mannheim.korap.utils.StringUtils;
-import lombok.AccessLevel;
 import net.sf.ehcache.CacheManager;
 import net.sf.ehcache.Element;
 import org.springframework.cache.annotation.CacheEvict;
@@ -50,7 +49,8 @@
     @Override
     public TokenContext createUserSession(User user, Map<String, Object> attr)
             throws KustvaktException {
-        TokenContext c = new TokenContext(user.getUsername());
+        TokenContext c = new TokenContext();
+        c.setUsername(user.getUsername());
         SignedJWT jwt = signedToken.createJWT(user, attr);
         try {
             c.setExpirationTime(jwt.getJWTClaimsSet().getExpirationTimeClaim());
@@ -77,7 +77,6 @@
         return null;
     }
 
-
     @Override
     public String getIdentifier() {
         return Attributes.API_AUTHENTICATION;
diff --git a/src/main/java/de/ids_mannheim/korap/security/auth/BasicHttpAuth.java b/src/main/java/de/ids_mannheim/korap/security/auth/BasicHttpAuth.java
index 07e8ace..01f1913 100644
--- a/src/main/java/de/ids_mannheim/korap/security/auth/BasicHttpAuth.java
+++ b/src/main/java/de/ids_mannheim/korap/security/auth/BasicHttpAuth.java
@@ -39,7 +39,8 @@
         authToken = StringUtils.stripTokenType(authToken);
         String[] values = decode(authToken);
         if (values != null) {
-            TokenContext c = new TokenContext(values[0]);
+            TokenContext c = new TokenContext();
+            c.setUsername(values[0]);
             c.setTokenType(Attributes.BASIC_AUTHENTICATION);
             c.setSecureRequired(true);
             c.setToken(authToken);
diff --git a/src/main/java/de/ids_mannheim/korap/security/auth/OpenIDconnectAuthentication.java b/src/main/java/de/ids_mannheim/korap/security/auth/OpenIDconnectAuthentication.java
index cae5e2d..0a23e72 100644
--- a/src/main/java/de/ids_mannheim/korap/security/auth/OpenIDconnectAuthentication.java
+++ b/src/main/java/de/ids_mannheim/korap/security/auth/OpenIDconnectAuthentication.java
@@ -46,10 +46,14 @@
     @Override
     public TokenContext createUserSession(User user, Map<String, Object> attr)
             throws KustvaktException {
-        JWTSigner signer = new JWTSigner(
-                ((String) attr.get(Attributes.CLIENT_SECRET)).getBytes(),
+        String cl_secret = (String) attr.get(Attributes.CLIENT_SECRET);
+        if (cl_secret == null)
+            throw new KustvaktException(StatusCodes.REQUEST_INVALID);
+
+        JWTSigner signer = new JWTSigner(cl_secret.getBytes(),
                 config.getIssuer(), config.getTokenTTL());
-        TokenContext c = new TokenContext(user.getUsername());
+        TokenContext c = new TokenContext();
+        c.setUsername(user.getUsername());
         SignedJWT jwt = signer.createJWT(user, attr);
         try {
             c.setExpirationTime(jwt.getJWTClaimsSet().getExpirationTimeClaim());
diff --git a/src/main/java/de/ids_mannheim/korap/security/auth/SessionAuthentication.java b/src/main/java/de/ids_mannheim/korap/security/auth/SessionAuthentication.java
index 99ebd89..8bed26c 100644
--- a/src/main/java/de/ids_mannheim/korap/security/auth/SessionAuthentication.java
+++ b/src/main/java/de/ids_mannheim/korap/security/auth/SessionAuthentication.java
@@ -63,7 +63,7 @@
                 .getExpiration(now.getMillis(), config.getExpiration());
         String token = crypto
                 .createToken(true, user.getUsername(), now.getMillis());
-        TokenContext ctx = new TokenContext(user.getUsername());
+        TokenContext ctx = new TokenContext();
         ctx.setUsername(user.getUsername());
         ctx.setTokenType(Attributes.SESSION_AUTHENTICATION);
         ctx.setToken(token);
diff --git a/src/main/java/de/ids_mannheim/korap/web/KustvaktLightServer.java b/src/main/java/de/ids_mannheim/korap/web/KustvaktBaseServer.java
similarity index 95%
rename from src/main/java/de/ids_mannheim/korap/web/KustvaktLightServer.java
rename to src/main/java/de/ids_mannheim/korap/web/KustvaktBaseServer.java
index 65f21c3..1e97bd8 100644
--- a/src/main/java/de/ids_mannheim/korap/web/KustvaktLightServer.java
+++ b/src/main/java/de/ids_mannheim/korap/web/KustvaktBaseServer.java
@@ -1,6 +1,7 @@
 package de.ids_mannheim.korap.web;
 
 import com.sun.jersey.api.core.PackagesResourceConfig;
+import com.sun.jersey.api.core.ResourceConfig;
 import com.sun.jersey.spi.container.servlet.ServletContainer;
 import de.ids_mannheim.korap.config.BeanConfiguration;
 import lombok.Getter;
@@ -17,7 +18,7 @@
  * @author hanl
  * @date 01/06/2015
  */
-public class KustvaktLightServer {
+public class KustvaktBaseServer {
 
     public static void main(String[] args) throws Exception {
         KustvaktArgs kargs = readAttributes(args);
@@ -28,7 +29,7 @@
             BeanConfiguration.loadClasspathContext();
 
         kargs.setRootClasses(
-                new String[] { "de.ids_mannheim.korap.web.service" });
+                new String[] { "de.ids_mannheim.korap.web.service.light" });
         startServer(kargs);
     }
 
@@ -69,11 +70,12 @@
             connector.setMaxIdleTime(60000);
 
             // http://stackoverflow.com/questions/9670363/how-do-i-programmatically-configure-jersey-to-use-jackson-for-json-deserializa
-            final PackagesResourceConfig prc = new PackagesResourceConfig(
+            final ResourceConfig rc = new PackagesResourceConfig(
                     kargs.rootClasses);
+
             // from http://stackoverflow.com/questions/7421574/embedded-jetty-with-jersey-or-resteasy
             contextHandler
-                    .addServlet(new ServletHolder(new ServletContainer(prc)),
+                    .addServlet(new ServletHolder(new ServletContainer(rc)),
                             "/api/*");
 
             server.setHandler(contextHandler);
diff --git a/src/main/java/de/ids_mannheim/korap/web/filter/BlockingFilter.java b/src/main/java/de/ids_mannheim/korap/web/filter/BlockingFilter.java
new file mode 100644
index 0000000..70670bb
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/web/filter/BlockingFilter.java
@@ -0,0 +1,38 @@
+package de.ids_mannheim.korap.web.filter;
+
+import com.sun.jersey.spi.container.ContainerRequest;
+import com.sun.jersey.spi.container.ContainerRequestFilter;
+import com.sun.jersey.spi.container.ContainerResponseFilter;
+import com.sun.jersey.spi.container.ResourceFilter;
+import de.ids_mannheim.korap.web.utils.KustvaktResponseHandler;
+
+import javax.ws.rs.ext.Provider;
+
+/**
+ * @author hanl
+ * @date 11/12/2014
+ * <p/>
+ * endpoint filter to block access to an endpoint, in case no anonymous access should be allowed!
+ */
+@Provider
+public class BlockingFilter implements ContainerRequestFilter, ResourceFilter {
+
+    @Override
+    public ContainerRequest filter(ContainerRequest request) {
+        String authentication = request
+                .getHeaderValue(ContainerRequest.AUTHORIZATION);
+        if (authentication == null || authentication.isEmpty())
+            throw KustvaktResponseHandler.throwAuthenticationException();
+        return request;
+    }
+
+    @Override
+    public ContainerRequestFilter getRequestFilter() {
+        return this;
+    }
+
+    @Override
+    public ContainerResponseFilter getResponseFilter() {
+        return null;
+    }
+}
diff --git a/src/test/java/de/ids_mannheim/korap/web/service/AuthServiceTest.java b/src/test/java/de/ids_mannheim/korap/web/service/AuthServiceTest.java
new file mode 100644
index 0000000..2a4486e
--- /dev/null
+++ b/src/test/java/de/ids_mannheim/korap/web/service/AuthServiceTest.java
@@ -0,0 +1,8 @@
+package de.ids_mannheim.korap.web.service;
+
+/**
+ * @author hanl
+ * @date 24/09/2015
+ */
+public class AuthServiceTest {
+}
diff --git a/src/test/java/de/ids_mannheim/korap/web/service/OAuth2EndpointTest.java b/src/test/java/de/ids_mannheim/korap/web/service/OAuth2EndpointTest.java
new file mode 100644
index 0000000..19bb99e
--- /dev/null
+++ b/src/test/java/de/ids_mannheim/korap/web/service/OAuth2EndpointTest.java
@@ -0,0 +1,8 @@
+package de.ids_mannheim.korap.web.service;
+
+/**
+ * @author hanl
+ * @date 23/09/2015
+ */
+public class OAuth2EndpointTest {
+}
diff --git a/src/test/java/de/ids_mannheim/korap/web/service/OAuth2HandlerTest.java b/src/test/java/de/ids_mannheim/korap/web/service/OAuth2HandlerTest.java
new file mode 100644
index 0000000..eadced8
--- /dev/null
+++ b/src/test/java/de/ids_mannheim/korap/web/service/OAuth2HandlerTest.java
@@ -0,0 +1,101 @@
+package de.ids_mannheim.korap.web.service;
+
+import de.ids_mannheim.korap.config.AuthCodeInfo;
+import de.ids_mannheim.korap.config.BeanConfiguration;
+import de.ids_mannheim.korap.config.ClientInfo;
+import de.ids_mannheim.korap.exceptions.KustvaktException;
+import de.ids_mannheim.korap.ext.config.BeanHelperExtension;
+import de.ids_mannheim.korap.ext.security.oauth2.OAuth2Handler;
+import de.ids_mannheim.korap.interfaces.EncryptionIface;
+import de.ids_mannheim.korap.user.*;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * @author hanl
+ * @date 13/05/2015
+ */
+
+//works
+public class OAuth2HandlerTest {
+
+    private static ClientInfo info;
+    private static OAuth2Handler handler;
+    private static EncryptionIface crypto;
+    private static final String SCOPE = "search preferences queries account";
+    private static final KorAPUser user = User.UserFactory.getUser("test_user");
+
+    @BeforeClass
+    public static void setup() throws KustvaktException {
+        BeanConfiguration.loadClasspathContext("classpath-config.xml");
+        BeanConfiguration.setCustomBeansHolder(new BeanHelperExtension());
+        handler = new OAuth2Handler(
+                BeanConfiguration.getBeans().getPersistenceClient());
+        crypto = BeanConfiguration.getBeans().getEncryption();
+        info = new ClientInfo(crypto.createID(), crypto.createToken());
+        info.setConfidential(true);
+        //todo: support for subdomains?!
+        info.setUrl("http://localhost:8080/api/v0.1");
+        info.setRedirect_uri("testwebsite/login");
+
+        user.setPassword("testPassword123");
+        BeanConfiguration.getBeans().getUserDBHandler().createAccount(user);
+        handler.registerClient(info, user);
+    }
+
+    @AfterClass
+    public static void drop() throws KustvaktException {
+        handler.removeClient(info, user);
+        BeanConfiguration.getBeans().getUserDBHandler()
+                .deleteAccount(user.getId());
+    }
+
+    @Test
+    public void testStoreAuthorizationCodeThrowsNoException()
+            throws KustvaktException {
+        String auth_code = crypto.createToken();
+        AuthCodeInfo codeInfo = new AuthCodeInfo(info.getClient_id(),
+                auth_code);
+        codeInfo.setScopes(SCOPE);
+
+        handler.authorize(codeInfo, user);
+        codeInfo = handler.getAuthorization(auth_code);
+        Assert.assertNotNull("client is null!", codeInfo);
+    }
+
+    @Test
+    public void testAuthorizationCodeRemoveThrowsNoException()
+            throws KustvaktException {
+        String auth_code = crypto.createToken();
+        AuthCodeInfo codeInfo = new AuthCodeInfo(info.getClient_id(),
+                auth_code);
+        codeInfo.setScopes(SCOPE);
+
+        handler.authorize(codeInfo, user);
+        String t = crypto.createToken();
+        handler.addToken(codeInfo.getCode(), t, 7200);
+
+        TokenContext ctx = handler.getContext(t);
+        Assert.assertNotNull("context is null", ctx);
+
+        AuthCodeInfo c2 = handler.getAuthorization(codeInfo.getCode());
+        Assert.assertNull("clearing authorization failed", c2);
+    }
+
+    @Test
+    public void testStoreAccessCodeViaAuthCodeThrowsNoException() {
+
+    }
+
+    @Test
+    public void testDeleteAccessCodesByUserDeleteCascade() {
+
+    }
+
+    @Test
+    public void testAccessTokenbyUserDeleteCascade() {
+
+    }
+}