Skip to content
Snippets Groups Projects
Verified Commit 1343a94e authored by Timm Fitschen's avatar Timm Fitschen
Browse files

More permission checks for transitions

parent 875b74f5
No related branches found
No related tags found
3 merge requests!21Release v0.4.0,!7F fsm,!6Draft: F acm permissions2
package org.caosdb.server.jobs.core;
import java.util.Map;
import org.apache.shiro.authz.AuthorizationException;
import org.caosdb.server.entity.DeleteEntity;
import org.caosdb.server.entity.Message;
......@@ -18,6 +19,9 @@ import org.caosdb.server.utils.ServerMessages;
@JobAnnotation(time = JobExecutionTime.POST_CHECK, transaction = WriteTransaction.class)
public class CheckStateTransition extends EntityStateJob {
private static final String PERMISSION_STATE_FORCE_FINAL = "STATE:FORCE:FINAL";
private static final String PERMISSION_STATE_UNASSIGN = "STATE:UNASSIGN:";
private static final String PERMISSION_STATE_ASSIGN = "STATE:ASSIGN:";
private static final Message TRANSITION_NOT_ALLOWED =
new Message(MessageType.Error, "Transition not allowed.");
private static final Message INITIAL_STATE_NOT_ALLOWED =
......@@ -29,7 +33,7 @@ public class CheckStateTransition extends EntityStateJob {
* The forceFinalState flag is especially useful if you want to delete entities in the middle of
* the state machine's usual state cycle.
*/
private static final String FORCE_FINAL_STATE = "forceFinalState";
private static final String FLAG_FORCE_FINAL_STATE = "forceFinalState";
@Override
protected void run() {
......@@ -131,14 +135,13 @@ public class CheckStateTransition extends EntityStateJob {
*/
private void checkFinalState(State oldState) throws Message {
if (!oldState.isFinal()) {
if ("true".equalsIgnoreCase(getTransaction().getContainer().getFlags().get(FORCE_FINAL_STATE))
|| "true".equalsIgnoreCase(getEntity().getFlag(FORCE_FINAL_STATE))) {
// TODO permissions
return;
if (isForceFinal()) {
getUser().checkPermission(PERMISSION_STATE_FORCE_FINAL);
} else {
throw FINAL_STATE_NOT_ALLOWED;
}
throw FINAL_STATE_NOT_ALLOWED;
}
// TODO permissions
getUser().checkPermission(PERMISSION_STATE_UNASSIGN + oldState.getStateModelName());
}
/**
......@@ -151,6 +154,13 @@ public class CheckStateTransition extends EntityStateJob {
if (!newState.isInitial()) {
throw INITIAL_STATE_NOT_ALLOWED;
}
// TODO permissions
getUser().checkPermission(PERMISSION_STATE_ASSIGN + newState.getStateModelName());
}
private boolean isForceFinal() {
Map<String, String> containerFlags = getTransaction().getContainer().getFlags();
return (containerFlags != null
&& "true".equalsIgnoreCase(containerFlags.get(FLAG_FORCE_FINAL_STATE)))
|| "true".equalsIgnoreCase(getEntity().getFlag(FLAG_FORCE_FINAL_STATE));
}
}
......@@ -2,8 +2,9 @@ package org.caosdb.server.jobs.core;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
......@@ -17,6 +18,7 @@ import org.caosdb.server.datatype.IndexedSingleValue;
import org.caosdb.server.datatype.ReferenceDatatype;
import org.caosdb.server.datatype.ReferenceDatatype2;
import org.caosdb.server.datatype.ReferenceValue;
import org.caosdb.server.datatype.TextDatatype;
import org.caosdb.server.entity.ClientMessage;
import org.caosdb.server.entity.EntityInterface;
import org.caosdb.server.entity.Message;
......@@ -74,6 +76,8 @@ public abstract class EntityStateJob extends EntityJob {
public static final String STATE_ATTRIBUTE_NAME = "name";
public static final String STATE_ATTRIBUTE_DESCRIPTION = "description";
public static final String STATE_ATTRIBUTE_ID = "id";
public static final String ENTITY_STATE_ROLE_MARKER = "?STATE?";
public static final String PERMISSION_STATE_TRANSION = "STATE:TRANSITION:";
public static final Message STATE_MODEL_NOT_FOUND =
new Message(MessageType.Error, "StateModel not found.");
......@@ -103,12 +107,24 @@ public abstract class EntityStateJob extends EntityJob {
private String description;
private State fromState;
private State toState;
private Map<String, String> transitionProperties;
public Transition(EntityInterface transition) throws Message {
this.name = transition.getName();
this.description = transition.getDescription();
this.fromState = getFromState(transition);
this.toState = getToState(transition);
this.transitionProperties = getTransitionProperties(transition);
}
private Map<String, String> getTransitionProperties(EntityInterface transition) {
Map<String, String> result = new LinkedHashMap<>();
for (Property p : transition.getProperties()) {
if (p.getDatatype() instanceof TextDatatype) {
result.put(p.getName(), p.getValue().toString());
}
}
return result;
}
private State getToState(EntityInterface transition) throws Message {
......@@ -185,18 +201,30 @@ public abstract class EntityStateJob extends EntityJob {
public Element toElement() {
Element result = new Element(TRANSITION_XML_TAG);
if (this.name != null) result.setAttribute(TRANSITION_ATTRIBUTE_NAME, this.name);
if (this.description != null)
if (this.transitionProperties != null) {
this.transitionProperties.forEach(
(String key, String value) -> {
result.setAttribute(key, value);
});
}
if (this.name != null) {
result.setAttribute(TRANSITION_ATTRIBUTE_NAME, this.name);
}
if (this.description != null) {
result.setAttribute(TRANSITION_ATTRIBUTE_DESCRIPTION, this.description);
}
Element to = new Element(TO_XML_TAG);
to.setAttribute(STATE_ATTRIBUTE_NAME, this.toState.stateName);
if (this.toState.stateDescription != null) {
to.setAttribute(STATE_ATTRIBUTE_DESCRIPTION, this.toState.stateDescription);
}
Element from = new Element(FROM_XML_TAG);
from.setAttribute(STATE_ATTRIBUTE_NAME, this.fromState.stateName);
return result.addContent(from).addContent(to);
}
public boolean isPermitted(Subject user) {
return user.isPermitted("STATE:TRANSITION:" + this.name);
return user.isPermitted(PERMISSION_STATE_TRANSION + this.name);
}
}
......@@ -229,6 +257,7 @@ public abstract class EntityStateJob extends EntityJob {
private String stateDescription = null;
private Integer stateId = null;
private EntityACL stateACL = null;
private Map<String, String> stateProperties;
public State(String stateName, String stateModelName) throws Message {
this.stateName = stateName;
......@@ -243,12 +272,23 @@ public abstract class EntityStateJob extends EntityJob {
this.stateModelEntity = stateModelEntity;
this.stateModelName = stateModelEntity.getName();
this.stateACL = createStateACL(stateEntity.getEntityACL());
this.stateProperties = createStateProperties(stateEntity);
}
private Map<String, String> createStateProperties(EntityInterface stateEntity) {
Map<String, String> result = new LinkedHashMap<>();
for (Property p : stateEntity.getProperties()) {
if (p.getDatatype() instanceof TextDatatype) {
result.put(p.getName(), p.getValue().toString());
}
}
return result;
}
private EntityACL createStateACL(EntityACL entityACL) {
LinkedList<EntityACI> rules = new LinkedList<>();
for (EntityACI aci : entityACL.getRules()) {
if (aci.getResponsibleAgent().toString().startsWith("?STATE?")) {
if (aci.getResponsibleAgent().toString().startsWith(ENTITY_STATE_ROLE_MARKER)) {
int end = aci.getResponsibleAgent().toString().length() - 1;
String role = aci.getResponsibleAgent().toString().substring(7, end);
rules.add(
......@@ -289,6 +329,15 @@ public abstract class EntityStateJob extends EntityJob {
@Override
public void addToElement(Element ret) {
Element e = new Element(STATE_XML_TAG);
if (this.stateProperties == null && this.stateEntity != null) {
this.stateProperties = createStateProperties(this.stateEntity);
}
if (this.stateProperties != null && this.stateProperties.size() > 0) {
this.stateProperties.forEach(
(String key, String value) -> {
e.setAttribute(key, value);
});
}
if (this.stateModelName != null) {
e.setAttribute(STATE_ATTRIBUTE_MODEL, this.stateModelName);
}
......@@ -318,7 +367,7 @@ public abstract class EntityStateJob extends EntityJob {
ret.addContent(e);
}
private String getStateModelName() {
public String getStateModelName() {
return this.stateModelName;
}
......@@ -452,7 +501,7 @@ public abstract class EntityStateJob extends EntityJob {
* @throws Message if the transitions could ne be created.
*/
private Set<Transition> createTransitions(Property p) throws Message {
Set<Transition> result = new HashSet<>();
Set<Transition> result = new LinkedHashSet<>();
try {
if (!(p.getDatatype() instanceof AbstractCollectionDatatype)) {
return result;
......@@ -486,7 +535,7 @@ public abstract class EntityStateJob extends EntityJob {
private Set<State> getStates(Set<Transition> transitions, StateModel stateModel)
throws Message {
Iterator<Transition> it = transitions.iterator();
Set<State> result = new HashSet<>();
Set<State> result = new LinkedHashSet<>();
while (it.hasNext()) {
Transition t = it.next();
result.add(t.getFromState());
......@@ -657,7 +706,7 @@ public abstract class EntityStateJob extends EntityJob {
EntityInterface stateEntity = cache.get("state" + Integer.toString(refid.getId()));
boolean cached = true;
if (stateEntity == null || !cached) {
stateEntity = retrieveValidSparseEntityById(refid.getId(), null);
stateEntity = retrieveValidEntity(refid.getId());
cache.put("state" + Integer.toString(refid.getId()), stateEntity);
}
......
......@@ -76,7 +76,9 @@ public class InitEntityStateJobs extends EntityStateJob implements Observer {
oldState = null;
if (states.size() == 1) {
oldState = states.get(0);
((UpdateEntity) getEntity()).getOriginal().setEntityACL(getEntity().getEntityACL());
if (newState != null) {
((UpdateEntity) getEntity()).getOriginal().setEntityACL(getEntity().getEntityACL());
}
}
if (!Objects.equals(newState, oldState)) {
getEntity().acceptObserver(this);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment