diff --git a/Goobi/.classpath b/Goobi/.classpath
index dced35abd..04ccc545e 100644
--- a/Goobi/.classpath
+++ b/Goobi/.classpath
@@ -160,6 +160,7 @@
+
diff --git a/Goobi/.gitignore b/Goobi/.gitignore
index 6426b00b9..133b1b6b8 100644
--- a/Goobi/.gitignore
+++ b/Goobi/.gitignore
@@ -12,3 +12,4 @@
/goobi-jar/
/goobi-war/
/target/
+/module-war/
diff --git a/Goobi/src/de/sub/goobi/config/ConfigurationHelper.java b/Goobi/src/de/sub/goobi/config/ConfigurationHelper.java
index 1d5bb4e3b..8b98851b1 100644
--- a/Goobi/src/de/sub/goobi/config/ConfigurationHelper.java
+++ b/Goobi/src/de/sub/goobi/config/ConfigurationHelper.java
@@ -320,6 +320,10 @@ public int getBatchMaxSize() {
return getLocalInt("batchMaxSize", 100);
}
+ public String getJwtSecret() {
+ return getLocalString("jwtSecret", null);
+ }
+
public boolean useS3() {
return getLocalBoolean("useS3", false);
}
@@ -525,8 +529,7 @@ public boolean isMetsEditorShowOCRButton() {
public boolean isMetsEditorShowMetadataPopup() {
return getLocalBoolean("MetsEditorShowMetadataPopup", true);
}
-
-
+
public String getFormatOfMetsBackup() {
return getLocalString("formatOfMetaBackups");
}
@@ -683,17 +686,17 @@ public List getMetsEditorImageSizes() {
return getLocalList("MetsEditorImageSize");
}
-
+
public List getMetsEditorImageTileSizes() {
return getLocalList("MetsEditorImageTileSize");
}
-
+
public List getMetsEditorImageTileScales() {
return getLocalList("MetsEditorImageTileScale");
}
-
+
public boolean getMetsEditorUseImageTiles() {
return getLocalBoolean("MetsEditorUseImageTiles", true);
diff --git a/Goobi/src/de/sub/goobi/helper/JwtHelper.java b/Goobi/src/de/sub/goobi/helper/JwtHelper.java
new file mode 100644
index 000000000..91c70bb21
--- /dev/null
+++ b/Goobi/src/de/sub/goobi/helper/JwtHelper.java
@@ -0,0 +1,66 @@
+package de.sub.goobi.helper;
+
+import java.util.Date;
+
+import javax.naming.ConfigurationException;
+
+import org.goobi.beans.Step;
+import org.joda.time.DateTime;
+
+import com.auth0.jwt.JWT;
+import com.auth0.jwt.JWTVerifier;
+import com.auth0.jwt.algorithms.Algorithm;
+import com.auth0.jwt.exceptions.JWTVerificationException;
+import com.auth0.jwt.interfaces.DecodedJWT;
+
+import de.sub.goobi.config.ConfigurationHelper;
+import lombok.extern.log4j.Log4j;
+
+@Log4j
+public class JwtHelper {
+ public static String createChangeStepToken(Step step) throws ConfigurationException {
+ String secret = ConfigurationHelper.getInstance().getJwtSecret();
+ if (secret == null) {
+ throw new ConfigurationException(
+ "Could not get JWT secret from configuration. Please configure the key 'jwtSecret' in the file goobi_config.properties");
+ }
+ Algorithm algorithm = Algorithm.HMAC256("secret");
+ Date expiryDate = new DateTime().plusHours(37).toDate();
+ String token = JWT.create()
+ .withIssuer("Goobi")
+ .withClaim("stepId", step.getId())
+ .withClaim("changeStepAllowed", true)
+ .withExpiresAt(expiryDate)
+ .sign(algorithm);
+ return token;
+ }
+
+ public static boolean verifyChangeStepToken(String token, Integer stepId) throws ConfigurationException {
+ String secret = ConfigurationHelper.getInstance().getJwtSecret();
+ if (secret == null) {
+ throw new ConfigurationException(
+ "Could not get JWT secret from configuration. Please configure the key 'jwtSecret' in the file goobi_config.properties");
+ }
+ try {
+ Algorithm algorithm = Algorithm.HMAC256("secret");
+ JWTVerifier verifier = JWT.require(algorithm)
+ .withIssuer("Goobi")
+ .build();
+ DecodedJWT jwt = verifier.verify(token);
+ Integer claimId = jwt.getClaim("stepId").asInt();
+ if (claimId == null || !stepId.equals(claimId)) {
+ log.debug("token rejected: step IDs do not match");
+ return false;
+ }
+ Boolean changeStepAllowed = jwt.getClaim("changeStepAllowed").asBoolean();
+ if (changeStepAllowed == null || !changeStepAllowed) {
+ log.debug("token rejected: changing the step not allowed");
+ return false;
+ }
+ } catch (JWTVerificationException exception) {
+ //Invalid signature/claims
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/Goobi/src/de/sub/goobi/helper/VariableReplacer.java b/Goobi/src/de/sub/goobi/helper/VariableReplacer.java
index 4d2b359f1..7fc806d1a 100644
--- a/Goobi/src/de/sub/goobi/helper/VariableReplacer.java
+++ b/Goobi/src/de/sub/goobi/helper/VariableReplacer.java
@@ -35,6 +35,8 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import javax.naming.ConfigurationException;
+
import org.apache.commons.lang.SystemUtils;
import org.apache.commons.lang.text.StrTokenizer;
import org.apache.log4j.Logger;
@@ -94,6 +96,7 @@ private enum MetadataLevel {
private static Pattern pMetaFile = Pattern.compile("\\$?(:?\\(|\\{)metaFile(:?\\}|\\))");
private static Pattern pStepId = Pattern.compile("\\$?(:?\\(|\\{)stepid(:?\\}|\\))");
private static Pattern pStepName = Pattern.compile("\\$?(:?\\(|\\{)stepname(:?\\}|\\))");
+ private static Pattern pChangeStepToken = Pattern.compile("\\\\$?(:?\\\\(|\\\\{)changesteptoken(:?\\\\}|\\\\))");
DigitalDocument dd;
Prefs prefs;
@@ -258,6 +261,16 @@ public String replace(String inString) {
inString = pStepId.matcher(inString).replaceAll(stepId);
inString = pStepName.matcher(inString).replaceAll(stepname);
+
+ Matcher tokenMatcher = pChangeStepToken.matcher(inString);
+ if (tokenMatcher.find()) {
+ try {
+ String token = JwtHelper.createChangeStepToken(step);
+ inString = tokenMatcher.replaceAll(token);
+ } catch (ConfigurationException e) {
+ logger.error(e);
+ }
+ }
}
// replace WerkstueckEigenschaft, usage: (product.PROPERTYTITLE)
diff --git a/Goobi/webapp/WEB-INF/lib/java-jwt-3.4.1.jar b/Goobi/webapp/WEB-INF/lib/java-jwt-3.4.1.jar
new file mode 100644
index 000000000..aa26a594e
Binary files /dev/null and b/Goobi/webapp/WEB-INF/lib/java-jwt-3.4.1.jar differ