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() {
+
+ }
+}