diff --git a/README.md b/README.md
index c048898..d22750c 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@
## Description
-A ServletFilter that authenticates the JWT tokens created by Islandora in order to provide sessionless Authentication for Fedora4. Named after the Norse goddess [Syn](https://en.wikipedia.org/wiki/Syn_(goddess)).
+A valve for Tomcat8 that authenticates the JWT tokens created by Islandora in order to provide sessionless Authentication for Fedora4. Named after the Norse goddess [Syn](https://en.wikipedia.org/wiki/Syn_(goddess)).
## Building
@@ -15,39 +15,54 @@ This project requires Java 8 and can be built with [Gradle](https://gradle.org).
## Installing
### Copy Syn JAR
-Copy the JAR that was built above from `build/libs/islandora-syn-X.X.X-all.jar` and place into `$TOMCAT_HOME/lib` directory or the individual webapps `WEB-INF/lib` directory. Can be found in Ubuntu at: `/var/lib/tomcat8/lib/`. Note that this JAR is built to contain all the dependancies.
+Copy the JAR that was built above from `build/libs/islandora-syn-X.X.X-all.jar` and place into `$TOMCAT_HOME/lib` directory. Can be found in Ubuntu at: `/var/lib/tomcat8/lib/`. Note that this JAR is built to contain all the dependancies.
-### Register Filter
-Now register the filter in web applications' `web.xml` file by adding something like.
+### Register Valve
+Now register the valve in Tomcat configuration file.
+In Ubuntu this file is located at: `/var/lib/tomcat8/conf/context.xml`
```xml
-
- SynFilter
- ca.islandora.syn.valve.SynFilter
-
- settings-path
- /var/lib/tomcat8/conf/syn-settings.yml
-
-
-
-
- SynFilter
- /*
-
+
```
-Where the **settings-path** `param-value` is the the location of the settings file.
+where:
+* ***pathname***: The location of the settings file. Defaults to `$CATALINA_BASE/conf/syn-settings.xml`.
+
+### Enable `security-contraint`
+The valve checks if requested url is under **security contraints**. So, valve will activate only if the Fedora4 *web.xml* file contains something like:
+
+```xml
+
+
+ Fedora4
+ /*
+
+
+ *
+
+
+ NONE
+
+
+
+ islandora
+
+
+ BASIC
+ fcrepo
+
+```
On ubuntu this file can be found at:
`/var/lib/tomcat8/webapps/fcrepo/WEB-INF/web.xml`
### Setup Syn Configuration
-Modify the [example configuration](./conf/syn-settings.example.yaml) and move it to: `$CATALINA_BASE/conf/syn-settings.xml`. Then use this path when configuring the application's filter `init-param`s.
+Modify the [example configuration](./conf/syn-settings.example.xml) and move it to: `$CATALINA_BASE/conf/syn-settings.xml`.
## Maintainers
* [Jonathan Green](https://github.com/jonathangreen/)
-* [Jared Whiklo](https://github.com/whikloj)
## Development
diff --git a/build.gradle b/build.gradle
index d99d80d..3cfd8e1 100644
--- a/build.gradle
+++ b/build.gradle
@@ -7,27 +7,13 @@ apply plugin: 'jacoco'
apply plugin: 'com.github.johnrengelman.shadow'
def projectName = 'islandora-syn'
-def projectVersion = '0.1.0'
+def projectVersion = '0.3.0'
sourceCompatibility = 1.8
targetCompatibility = 1.8
def tomcatVersion = '8.0.28'
-ext {
-
- versions = [
- bcprov : '1.56',
- jackson : '2.9.2',
- javaJwt : '3.1.0',
- junit : '4.12',
- logback : '1.0.13',
- mockito : '2.7.14',
- servlet : '3.0.1',
- slf4j : '1.7.12'
- ]
-}
-
checkstyle {
configFile = rootProject.file('gradle/checkstyle/checkstyle.xml')
configProperties.checkstyleConfigDir = rootProject.file('gradle/checkstyle')
@@ -38,17 +24,15 @@ repositories {
}
dependencies {
- compile group: 'com.auth0', name: 'java-jwt', version: versions.javaJwt
- compile group: 'org.bouncycastle', name: 'bcprov-jdk15on', version: versions.bcprov
- compile group: 'org.slf4j', name: 'slf4j-api', version: versions.slf4j
- compile group: 'javax.servlet', name: 'javax.servlet-api', version: versions.servlet
- compile group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: versions.jackson
- compile group: 'com.fasterxml.jackson.dataformat', name: 'jackson-dataformat-yaml', version: versions.jackson
-
- testRuntime group: 'ch.qos.logback', name: 'logback-classic', version: versions.logback
-
- testCompile group: 'junit', name: 'junit', version: versions.junit
- testCompile group: 'org.mockito', name: 'mockito-core', version: versions.mockito
+ compile group: 'com.auth0', name: 'java-jwt', version:'3.1.0'
+ compile group: 'org.bouncycastle', name: 'bcprov-jdk15on', version:'1.56'
+ compileOnly group: 'org.apache.tomcat', name: 'tomcat-catalina', version:tomcatVersion
+ compileOnly group: 'org.apache.tomcat', name: 'tomcat-coyote', version:tomcatVersion
+
+ testCompile group: 'junit', name: 'junit', version:'4.12'
+ testCompile group: 'org.mockito', name: 'mockito-core', version:'2.7.14'
+ testCompile group: 'org.apache.tomcat', name: 'tomcat-catalina', version:tomcatVersion
+ testCompile group: 'org.apache.tomcat', name: 'tomcat-coyote', version:tomcatVersion
}
jacocoTestReport {
@@ -70,13 +54,6 @@ buildscript {
jar {
baseName = projectName
version = projectVersion
- manifest {
- attributes("Implementation-Title": baseName,
- "Implementation-Version": version,
- "Implementation-Vendor": "Islandora",
- "Class-Path": configurations.compile.collect { it.getName() }.join(' '))
- }
-
}
shadowJar {
@@ -85,14 +62,3 @@ shadowJar {
}
assemble.dependsOn(shadowJar);
-
-test {
- testLogging {
- // Make sure output from
- // standard out or error is shown
- // in Gradle output.
- // showStandardStreams = true
- //events 'standard_out'
- exceptionFormat = 'full'
- }
-}
\ No newline at end of file
diff --git a/conf/syn-settings.example.xml b/conf/syn-settings.example.xml
new file mode 100644
index 0000000..3cbd328
--- /dev/null
+++ b/conf/syn-settings.example.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+my secret key
+
+
+
+
+
+
+
+
+
+
+
+
+
+ my super secret token
+
+
+
diff --git a/conf/syn-settings.example.yaml b/conf/syn-settings.example.yaml
deleted file mode 100644
index a1ea934..0000000
--- a/conf/syn-settings.example.yaml
+++ /dev/null
@@ -1,43 +0,0 @@
-version: 1
-# Sites can be specified with a Key inline, or with a reference to a key
-# stored in a file. Both are shown in examples below.
-#
-# The encoding parameter depends on what algorithm is chosen.
-# HS256, HS384, HS512 support: plain and base64.
-# RS256, RS384, RS512 support: PEM.
-
-# A site with an inline key
-site:
- url: http://test.com
- algorithm: HS256
- encoding: plain
- key: my secret key
-
-# A site with a key stored in a file
-site:
- url: http://test2.com
- algorithm: HS256
- encoding: base64
- path: /somewhere/on/filesystem.key
-
-# A site that allows all GET/HEAD requests
-site:
- url: http://test3.com
- algorithm: HS256
- encoding: plain
- anonymous: true
-
-# This is how you specify a default site, which will be chosen if no
-# other site matches the JWT url claim
-site:
- algorithm: RS256
- encoding: PEM
- path: /somewhere/on/filesystem.key
- default: true
-
-# This lets you specify a master token for testing. This should be used with care, as it gives anyone
-# with this token unlimited access to your repository.
-token:
- user: test
- roles: role1,role2,role3
- value: my super secret token
diff --git a/src/main/java/ca/islandora/syn/settings/Config.java b/src/main/java/ca/islandora/syn/settings/Config.java
index b96a38b..de74243 100644
--- a/src/main/java/ca/islandora/syn/settings/Config.java
+++ b/src/main/java/ca/islandora/syn/settings/Config.java
@@ -3,37 +3,29 @@
import java.util.ArrayList;
import java.util.List;
-import com.fasterxml.jackson.annotation.JsonSetter;
-
public class Config {
private int version = -1;
- private final List sites = new ArrayList<>();
- private final List tokens = new ArrayList<>();
+ private List sites = new ArrayList<>();
+ private List tokens = new ArrayList<>();
- @JsonSetter("site")
public void addSite(final Site site) {
- this.sites.add(site);
+ sites.add(site);
}
-
public List getSites() {
- return this.sites;
+ return sites;
}
public int getVersion() {
return this.version;
}
-
public void setVersion(final int version) {
this.version = version;
}
- @JsonSetter("token")
public void addToken(final Token token) {
- this.tokens.add(token);
+ tokens.add(token);
}
-
public List getTokens() {
- return this.tokens;
+ return tokens;
}
-
}
diff --git a/src/main/java/ca/islandora/syn/settings/SettingsParser.java b/src/main/java/ca/islandora/syn/settings/SettingsParser.java
index fa28ba8..92e25b5 100644
--- a/src/main/java/ca/islandora/syn/settings/SettingsParser.java
+++ b/src/main/java/ca/islandora/syn/settings/SettingsParser.java
@@ -1,11 +1,10 @@
package ca.islandora.syn.settings;
-import static org.slf4j.LoggerFactory.getLogger;
-
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
+import java.io.InputStream;
import java.io.Reader;
import java.io.StringReader;
import java.nio.file.Files;
@@ -18,88 +17,66 @@
import java.util.Map;
import java.util.stream.Collectors;
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.util.digester.Digester;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemReader;
-import org.slf4j.Logger;
+import org.xml.sax.SAXException;
import com.auth0.jwt.algorithms.Algorithm;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
public final class SettingsParser {
- private static Logger log = getLogger(Site.class);
-
- private enum AlgorithmType {
- INVALID, RSA, HMAC
- }
-
- private static final int VALID_VERSION = 1;
-
- private Config loadedSites;
-
- private final static ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
-
- /**
- * Constructor.
- *
- * @param settings
- * A Reader object with the configuration in it.
- * @throws Exception
- * On loading/parsing or version of configuration.
- */
- public SettingsParser(final Reader settings) {
- try {
- loadedSites = mapper.readValue(settings, Config.class);
- } catch (final Exception e) {
- log.error("Error loading settings file.", e);
- throw new SettingsParserException("Error parsing settings file.", e);
- }
-
- if (loadedSites.getVersion() != VALID_VERSION) {
- log.error("Incorrect config version. Aborting.");
- throw new SettingsParserException("Incorrect config version. Aborting.");
+ private static Digester digester = null;
+ private static Log log = LogFactory.getLog(Site.class);
+ private enum AlgorithmType {INVALID, RSA, HMAC}
+
+ private SettingsParser() { }
+
+ private static Digester getDigester() {
+ if (digester == null) {
+ digester = new Digester();
+ digester.setValidating(false);
+ digester.addObjectCreate("config", "ca.islandora.syn.settings.Config");
+ digester.addSetProperties("config");
+ digester.addObjectCreate("config/site", "ca.islandora.syn.settings.Site");
+ digester.addSetProperties("config/site");
+ digester.addCallMethod("config/site", "setKey", 0);
+ digester.addSetNext("config/site", "addSite", "ca.islandora.syn.settings.Site");
+ digester.addObjectCreate("config/token", "ca.islandora.syn.settings.Token");
+ digester.addSetProperties("config/token");
+ digester.addCallMethod("config/token", "setToken", 0);
+ digester.addSetNext("config/token", "addToken", "ca.islandora.syn.settings.Token");
}
+ return digester;
}
- /**
- * Static creator.
- *
- * @param settings
- * A Reader object with the configuration on it.
- * @return The SettingsParser.
- * @throws Exception
- * On loading/parsing or version of configuration.
- */
- public static SettingsParser create(final Reader settings) {
- return new SettingsParser(settings);
- }
- /**
- * Determine the type of key algorithm.
- *
- * @param algorithm
- * The algorithm name.
- * @return an algorithm.
- */
private static AlgorithmType getSiteAlgorithmType(final String algorithm) {
- if (algorithm.toUpperCase().startsWith("RS")) {
+ if (algorithm.equalsIgnoreCase("RS256")) {
+ return AlgorithmType.RSA;
+ } else if (algorithm.equalsIgnoreCase("RS384")) {
return AlgorithmType.RSA;
- } else if (algorithm.toUpperCase().startsWith("HS")) {
+ } else if (algorithm.equalsIgnoreCase("RS512")) {
+ return AlgorithmType.RSA;
+ }
+
+ if (algorithm.equalsIgnoreCase("HS256")) {
+ return AlgorithmType.HMAC;
+ } else if (algorithm.equalsIgnoreCase("HS384")) {
+ return AlgorithmType.HMAC;
+ } else if (algorithm.equalsIgnoreCase("HS512")) {
return AlgorithmType.HMAC;
} else {
return AlgorithmType.INVALID;
}
}
- /**
- * Validate the site's key path.
- *
- * @param site
- * The site to act on.
- * @return true if key exists.
- */
- private static boolean validatePath(final Site site) {
- final File file = new File(site.getPath());
+ private static boolean validateExpandPath(final Site site) {
+ File file = new File(site.getPath());
+ if (!file.isAbsolute()) {
+ file = new File(System.getProperty("catalina.base"), site.getPath());
+ }
if (!file.exists() || !file.canRead()) {
log.error("Path does not exist:" + site.getPath() + ". Site ignored.");
return false;
@@ -108,23 +85,16 @@ private static boolean validatePath(final Site site) {
return true;
}
- /**
- * Parse a RSA encoded key and return the algorithm for verifying.
- *
- * @param site
- * The site to get the key for.
- * @return A RSA algorithm for the site's key.
- */
private static Algorithm getRsaAlgorithm(final Site site) {
Reader publicKeyReader = null;
RSAPublicKey publicKey = null;
- if (site.getKey() != null) {
+ if (!site.getKey().equalsIgnoreCase("")) {
publicKeyReader = new StringReader(site.getKey());
} else if (site.getPath() != null) {
try {
publicKeyReader = new FileReader(site.getPath());
- } catch (final FileNotFoundException e) {
+ } catch (FileNotFoundException e) {
log.error("Private key file not found.");
}
}
@@ -142,7 +112,7 @@ private static Algorithm getRsaAlgorithm(final Site site) {
publicKey = (RSAPublicKey) factory.generatePublic(pubKeySpec);
pemReader.close();
publicKeyReader.close();
- } catch (final Exception e) {
+ } catch (Exception e) {
log.error("Error loading public key.");
return null;
}
@@ -163,23 +133,16 @@ private static Algorithm getRsaAlgorithm(final Site site) {
}
}
- /**
- * Parse a HMAC encoded key and return the algorithm for verifying.
- *
- * @param site
- * The site to get the key for.
- * @return A HMAC algorithm for the site's key.
- */
private static Algorithm getHmacAlgorithm(final Site site) {
- final byte[] secret;
+ byte[] secret;
byte[] secretRaw = null;
- if (site.getKey() != null) {
+ if (!site.getKey().equalsIgnoreCase("")) {
secretRaw = site.getKey().trim().getBytes();
} else if (site.getPath() != null) {
try {
secretRaw = Files.readAllBytes(Paths.get(site.getPath()));
- } catch (final IOException e) {
+ } catch (IOException e) {
log.error("Unable to get secret from file.", e);
}
}
@@ -191,7 +154,7 @@ private static Algorithm getHmacAlgorithm(final Site site) {
if (site.getEncoding().equalsIgnoreCase("base64")) {
try {
secret = Base64.getDecoder().decode(secretRaw);
- } catch (final Exception e) {
+ } catch (Exception e) {
log.error("Base64 decode error. Skipping site.", e);
return null;
}
@@ -212,20 +175,34 @@ private static Algorithm getHmacAlgorithm(final Site site) {
}
}
- /**
- * Get site keys from loaded Config.
- *
- * @return Map of URLs (or null) and parsed keys for verification.
- */
- public Map getSiteAlgorithms() {
+ private static Config getSites(final InputStream settings) {
+ Config sites;
+
+ try {
+ sites = getSitesObject(settings);
+ } catch (Exception e) {
+ log.error("Error loading settings file.", e);
+ return null;
+ }
+
+ if (sites.getVersion() != 1) {
+ log.error("Incorrect XML version. Aborting.");
+ return null;
+ }
+
+ return sites;
+ }
+
+ public static Map getSiteAlgorithms(final InputStream settings) {
final Map algorithms = new HashMap<>();
- if (loadedSites == null) {
+ final Config sites = getSites(settings);
+ if (sites == null) {
return algorithms;
}
boolean defaultSet = false;
- for (final Site site : loadedSites.getSites()) {
+ for (Site site : sites.getSites()) {
final boolean pathDefined = site.getPath() != null && !site.getPath().equalsIgnoreCase("");
final boolean keyDefined = site.getKey() != null && !site.getKey().equalsIgnoreCase("");
@@ -236,20 +213,20 @@ public Map getSiteAlgorithms() {
}
if (site.getPath() != null) {
- if (!validatePath(site)) {
+ if (!validateExpandPath(site)) {
continue;
}
}
// Check that the algorithm type is valid.
final AlgorithmType algorithmType = getSiteAlgorithmType(site.getAlgorithm());
- final Algorithm algorithm;
+ Algorithm algorithm;
if (algorithmType == AlgorithmType.HMAC) {
algorithm = getHmacAlgorithm(site);
} else if (algorithmType == AlgorithmType.RSA) {
algorithm = getRsaAlgorithm(site);
} else {
- log.error("Invalid algorithm selection: " + site.getAlgorithm() + ". Site ignored.");
+ log.error("Invalid algorithm selection: " + site.getAlgorithm() + ". Site ignored." );
continue;
}
@@ -275,18 +252,14 @@ public Map getSiteAlgorithms() {
return algorithms;
}
- /**
- * Get static tokens from the loaded Config.
- *
- * @return Map of token value and Token object.
- */
- public Map getSiteStaticTokens() {
- if (loadedSites == null) {
+ public static Map getSiteStaticTokens(final InputStream settings) {
+ final Config sites = getSites(settings);
+ if (sites == null) {
return new HashMap();
}
- final Map tokens = loadedSites.getTokens().stream().filter(x -> !x.getValue().isEmpty())
- .collect(Collectors.toMap(Token::getValue, t -> t));
+ final Map tokens = sites.getTokens().stream().filter(x -> !x.getToken().isEmpty())
+ .collect(Collectors.toMap(Token::getToken, t -> t));
return tokens;
}
@@ -294,28 +267,25 @@ public Map getSiteStaticTokens() {
/**
* Build a list of site urls that allow anonymous GET requests.
*
- * @return Map of all URLs (or null for default) and boolean if they allow
- * anonymous.
+ * @param settings the path to the syn-settings file
+ * @return list of site urls.
*/
- public Map getSiteAllowAnonymous() {
- if (loadedSites == null) {
+ public static Map getSiteAllowAnonymous(final InputStream settings) {
+ final Config sites = getSites(settings);
+ if (sites == null) {
return new HashMap();
}
- final Map anonymousAllowed = loadedSites.getSites().stream().filter(s -> !s.getDefault())
- .collect(Collectors.toMap(Site::getUrl, Site::getAnonymous));
- loadedSites.getSites().stream().filter(Site::getDefault).findFirst()
- .ifPresent(s -> anonymousAllowed.put("default", s.getAnonymous()));
+ final Map anonymousAllowed = sites.getSites().stream().filter(s -> !s.getDefault())
+ .collect(Collectors.toMap(Site::getUrl, Site::getAnonymous));
+ sites.getSites().stream().filter(Site::getDefault).findFirst()
+ .ifPresent(s -> anonymousAllowed.put("default", s.getAnonymous()));
return anonymousAllowed;
}
- /**
- * Getter for loaded Config object.
- *
- * @return
- */
- public Config getConfig() {
- return loadedSites;
+ static Config getSitesObject(final InputStream settings)
+ throws IOException, SAXException {
+ return (Config) getDigester().parse(settings);
}
}
diff --git a/src/main/java/ca/islandora/syn/settings/SettingsParserException.java b/src/main/java/ca/islandora/syn/settings/SettingsParserException.java
deleted file mode 100644
index a61556c..0000000
--- a/src/main/java/ca/islandora/syn/settings/SettingsParserException.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package ca.islandora.syn.settings;
-
-/**
- * Exception while parsing the settings YAML file.
- *
- * @author whikloj
- * @since 2018-01-17
- */
-public class SettingsParserException extends RuntimeException {
-
- private static final long serialVersionUID = 1L;
-
- /**
- * Constructor
- *
- * @param message
- * Exception message
- */
- public SettingsParserException(final String message) {
- super(message);
- }
-
- /**
- * Constructor
- *
- * @param message
- * Exception message
- * @param e
- * Wrapped Exception
- */
- public SettingsParserException(final String message, final Throwable e) {
- super(message, e);
- }
-
-}
diff --git a/src/main/java/ca/islandora/syn/settings/Site.java b/src/main/java/ca/islandora/syn/settings/Site.java
index 4cf7f19..1524282 100644
--- a/src/main/java/ca/islandora/syn/settings/Site.java
+++ b/src/main/java/ca/islandora/syn/settings/Site.java
@@ -12,7 +12,6 @@ public class Site {
public String getUrl() {
return this.url;
}
-
public void setUrl(final String url) {
this.url = url;
}
@@ -20,7 +19,6 @@ public void setUrl(final String url) {
public String getAlgorithm() {
return this.algorithm;
}
-
public void setAlgorithm(final String algorithm) {
this.algorithm = algorithm;
}
@@ -28,7 +26,6 @@ public void setAlgorithm(final String algorithm) {
public String getKey() {
return this.key;
}
-
public void setKey(final String key) {
this.key = key;
}
@@ -36,7 +33,6 @@ public void setKey(final String key) {
public String getPath() {
return this.path;
}
-
public void setPath(final String path) {
this.path = path;
}
@@ -44,7 +40,6 @@ public void setPath(final String path) {
public String getEncoding() {
return this.encoding;
}
-
public void setEncoding(final String encoding) {
this.encoding = encoding;
}
@@ -52,7 +47,6 @@ public void setEncoding(final String encoding) {
public boolean getDefault() {
return this.defaultItem;
}
-
public void setDefault(final boolean defaultItem) {
this.defaultItem = defaultItem;
}
@@ -69,8 +63,7 @@ public boolean getAnonymous() {
/**
* Set allow GET requests with a token that match this site.
*
- * @param allowAnonGet
- * boolean whether to allow these requests.
+ * @param allowAnonGet boolean whether to allow these requests.
*/
public void setAnonymous(final boolean allowAnonGet) {
this.allowAnonymous = allowAnonGet;
diff --git a/src/main/java/ca/islandora/syn/settings/Token.java b/src/main/java/ca/islandora/syn/settings/Token.java
index 630c6d1..3548d72 100644
--- a/src/main/java/ca/islandora/syn/settings/Token.java
+++ b/src/main/java/ca/islandora/syn/settings/Token.java
@@ -6,8 +6,8 @@
public class Token {
private String user = "islandoraAdmin";
- private final List roles = new ArrayList<>();
- private String value = "";
+ private List roles = new ArrayList<>();
+ private String token = "";
public String getUser() {
return user;
@@ -25,15 +25,15 @@ public void setRoles(final String roles) {
this.roles.clear();
if (!roles.isEmpty()) {
final String[] parts = roles.split(",");
- Collections.addAll(this.roles, parts);
+ Collections.addAll(this.roles,parts);
}
}
- public String getValue() {
- return value;
+ public String getToken() {
+ return token;
}
- public void setValue(final String token) {
- this.value = token.trim();
+ public void setToken(final String token) {
+ this.token = token.trim();
}
}
\ No newline at end of file
diff --git a/src/main/java/ca/islandora/syn/token/InvalidTokenException.java b/src/main/java/ca/islandora/syn/token/InvalidTokenException.java
deleted file mode 100644
index bdbde41..0000000
--- a/src/main/java/ca/islandora/syn/token/InvalidTokenException.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package ca.islandora.syn.token;
-
-/**
- *
- * @author whikloj
- *
- */
-public class InvalidTokenException extends RuntimeException {
-
- /**
- *
- */
- private static final long serialVersionUID = 1L;
-
- /**
- * Constructor
- *
- * @param message
- * Exception message
- */
- public InvalidTokenException(final String message) {
- super(message);
- }
-
- /**
- * Constructor
- *
- * @param message
- * Exception message
- * @param e
- * Wrapped Exception
- */
- public InvalidTokenException(final String message, final Throwable e) {
- super(message, e);
- }
-}
diff --git a/src/main/java/ca/islandora/syn/token/Verifier.java b/src/main/java/ca/islandora/syn/token/Verifier.java
index f4d5d5e..97fe054 100644
--- a/src/main/java/ca/islandora/syn/token/Verifier.java
+++ b/src/main/java/ca/islandora/syn/token/Verifier.java
@@ -1,60 +1,62 @@
package ca.islandora.syn.token;
-import static org.slf4j.LoggerFactory.getLogger;
-
-import java.util.Arrays;
import java.util.List;
-import java.util.Map;
-
-import org.slf4j.Logger;
-
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.JWTVerificationException;
-import com.auth0.jwt.interfaces.Claim;
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
public class Verifier {
- private static final Logger log = getLogger(Verifier.class);
+ private static final Log log = LogFactory.getLog(Verifier.class);
private String token;
private JWT jwt;
- private Verifier() {
- }
+ private Verifier() { }
public static Verifier create(final String token) {
final Verifier verifier = new Verifier();
- final List requiredClaims = Arrays.asList("sub", "iss", "webid", "roles", "exp", "iat");
verifier.token = token;
try {
verifier.jwt = JWT.decode(token);
- final Map claims = verifier.jwt.getClaims();
- for (final String claim : requiredClaims) {
- if (claims.get(claim) == null) {
- log.info("Token missing required claim ({})", claim);
- throw new InvalidTokenException(
- String.format("Token missing required claim ({})", claim));
- }
+ if (verifier.jwt.getClaim("uid").isNull()) {
+ return null;
+ }
+ if (verifier.jwt.getClaim("url").isNull()) {
+ return null;
}
- } catch (final JWTDecodeException exception) {
+ if (verifier.jwt.getClaim("name").isNull()) {
+ return null;
+ }
+ if (verifier.jwt.getClaim("roles").isNull()) {
+ return null;
+ }
+ if (verifier.jwt.getExpiresAt() == null) {
+ return null;
+ }
+ if (verifier.jwt.getIssuedAt() == null) {
+ return null;
+ }
+ } catch (JWTDecodeException exception) {
log.error("Error decoding token: " + token, exception);
- throw new InvalidTokenException("Error decoding token: " + token, exception);
+ return null;
}
return verifier;
}
public int getUid() {
- return this.jwt.getClaim("webid").asInt();
+ return this.jwt.getClaim("uid").asInt();
}
public String getUrl() {
- return this.jwt.getClaim("iss").asString();
+ return this.jwt.getClaim("url").asString();
}
public String getName() {
- return this.jwt.getClaim("sub").asString();
+ return this.jwt.getClaim("name").asString();
}
public List getRoles() {
@@ -65,11 +67,10 @@ public boolean verify(final Algorithm algorithm) {
final JWTVerifier verifier = JWT.require(algorithm).build();
try {
verifier.verify(this.token);
- } catch (final JWTVerificationException exception) {
+ } catch (JWTVerificationException exception) {
return false;
}
return true;
}
-
}
diff --git a/src/main/java/ca/islandora/syn/valve/SynFilter.java b/src/main/java/ca/islandora/syn/valve/SynFilter.java
deleted file mode 100644
index a5dd0d5..0000000
--- a/src/main/java/ca/islandora/syn/valve/SynFilter.java
+++ /dev/null
@@ -1,242 +0,0 @@
-package ca.islandora.syn.valve;
-
-import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN;
-import static javax.servlet.http.HttpServletResponse.SC_UNAUTHORIZED;
-import static org.slf4j.LoggerFactory.getLogger;
-
-import java.io.File;
-import java.io.FileReader;
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.regex.Pattern;
-
-import javax.servlet.Filter;
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletRequestWrapper;
-import javax.servlet.http.HttpServletResponse;
-
-import org.slf4j.Logger;
-
-import com.auth0.jwt.algorithms.Algorithm;
-
-import ca.islandora.syn.settings.SettingsParser;
-import ca.islandora.syn.settings.Token;
-import ca.islandora.syn.token.InvalidTokenException;
-import ca.islandora.syn.token.Verifier;
-
-/**
- * The JWT testing filter
- *
- * @author jonathangreen
- * @author whikloj
- *
- */
-public class SynFilter implements Filter {
-
- private static final Logger LOGGER = getLogger(SynFilter.class);
-
- public static final String UNAUTHORIZED_MSG = "Token authentication failed.";
- public static final String FORBIDDEN_MSG = "Token authentication failed.";
-
- private static String settingsPath;
- private static Map algorithmMap;
- private static Map staticTokenMap;
- private static Map anonymousMap;
-
- /**
- * Constructor
- */
- public SynFilter() {
-
- }
-
- @Override
- public void init(final FilterConfig config) throws ServletException {
- settingsPath = config.getInitParameter("settings-path");
- if (settingsPath == null) {
- throw new ServletException("settings-path init parameter must have location of syn-settings.yml file.");
- }
- // Validate the existence of our database file
- final File file = new File(settingsPath);
- if (!file.exists() || !file.canRead()) {
- LOGGER.error("Unable to load Syn configuration from path: " + settingsPath);
- throw new ServletException("Unable to load Syn configuration from path: " + settingsPath);
- }
-
- // Load the contents of the database file
- try (final FileReader settings = new FileReader(file)) {
- final SettingsParser parser = SettingsParser.create(settings);
- algorithmMap = parser.getSiteAlgorithms();
- staticTokenMap = parser.getSiteStaticTokens();
- anonymousMap = parser.getSiteAllowAnonymous();
- } catch (final Exception e) {
- throw new ServletException("Error parsing Syn configuration", e);
- }
- }
-
- @Override
- public void destroy() {
- }
-
- @Override
- public void doFilter(final ServletRequest servRequest, final ServletResponse servResponse, final FilterChain chain)
- throws IOException, ServletException {
- final HttpServletRequest request = (HttpServletRequest) servRequest;
- final HttpServletResponse response = (HttpServletResponse) servResponse;
-
- String token = request.getHeader("Authorization");
- if (token == null) {
- LOGGER.info("Request did not contain any token.");
- // Only check for anonymous access if there is no token.
- if ((request.getMethod().equalsIgnoreCase("GET") ||
- request.getMethod().equals("HEAD")) &&
- allowGetRequests(buildUrlRegex(request))) {
- chain.doFilter(setAnonymousRoles(request), response);
- return;
- }
- response.sendError(SC_UNAUTHORIZED, UNAUTHORIZED_MSG);
- return;
- }
-
- final String[] tokenParts = token.split(" ");
- if (tokenParts.length != 2 || !tokenParts[0].equalsIgnoreCase("bearer")) {
- LOGGER.info("Token was malformed. Token: " + token);
- response.sendError(SC_UNAUTHORIZED, UNAUTHORIZED_MSG);
- return;
- }
-
- // strip bearer off of the token
- token = tokenParts[1];
-
- // check if we have a static token that matches
- if (staticTokenMap.containsKey(token)) {
- LOGGER.info("Site verified using static token.");
- chain.doFilter(setUserRolesFromStaticToken(request, staticTokenMap.get(token)), response);
- return;
- }
-
- final Verifier verifier;
- try {
- verifier = Verifier.create(token);
- } catch (final InvalidTokenException e) {
- response.sendError(SC_UNAUTHORIZED, FORBIDDEN_MSG);
- return;
- }
-
- final String url = verifier.getUrl();
- Algorithm algorithm = null;
- if (algorithmMap.containsKey(url)) {
- algorithm = algorithmMap.get(url);
- } else if (algorithmMap.containsKey(null)) {
- algorithm = algorithmMap.get(null);
- }
-
- if (algorithm == null) {
- LOGGER.info("No key found for site: " + url + ".");
- response.sendError(SC_UNAUTHORIZED, UNAUTHORIZED_MSG);
- return;
- }
-
- if (verifier.verify(algorithm)) {
- LOGGER.info("Site verified: " + url);
- chain.doFilter(setUserRolesFromToken(request, verifier), response);
- return;
- } else {
- LOGGER.info("Token failed signature verification: " + url);
- response.sendError(SC_FORBIDDEN, FORBIDDEN_MSG);
- return;
- }
-
- }
-
- /**
- * Create fake principal with anonymous credentials.
- *
- * @param request
- * The original incoming request.
- * @return A wrapper with created credentials.
- */
- private HttpServletRequestWrapper setAnonymousRoles(final HttpServletRequest request) {
- final String host = request.getScheme() + "://" + request.getServerName()
- + (request.getServerPort() != 80 ? ":" + request.getServerPort() : "");
- final List roles = Arrays.asList("anonymous", "islandora", host);
- final String name = "anonymous";
- return new SynRequestWrapper(name, roles, request);
- }
-
- /**
- * Create fake principal with credentials from static token.
- *
- * @param request
- * The original incoming request.
- * @return A wrapper with created credentials.
- */
- private HttpServletRequestWrapper setUserRolesFromStaticToken(final HttpServletRequest request, final Token token) {
- final List roles = token.getRoles();
- roles.add("islandora");
- final String name = token.getUser();
- return new SynRequestWrapper(name, roles, request);
- }
-
- /**
- * Create fake principal with credentials from JWT.
- *
- * @param request
- * The original incoming request.
- * @return A wrapper with created credentials.
- */
- private HttpServletRequestWrapper setUserRolesFromToken(final HttpServletRequest request, final Verifier verifier) {
- final List roles = verifier.getRoles();
- roles.add("islandora");
- roles.add(verifier.getUrl());
- final String name = verifier.getName();
- return new SynRequestWrapper(name, roles, request);
- }
-
- /**
- * Do the logic of allowing GET/HEAD requests.
- *
- * @param hostRegex
- * A regular expression built of the hostname.
- * @return whether to allow GET requests without authentication.
- */
- private boolean allowGetRequests(final String hostRegex) {
- // If there is a matching site URI, return its value
- for (final Entry site : anonymousMap.entrySet()) {
- if (Pattern.matches(hostRegex, site.getKey())) {
- return site.getValue();
- }
- }
- // Else if there is a default, return its value.
- if (anonymousMap.containsKey("default")) {
- LOGGER.debug(
- String.format(
- "Using default anonymous ({}) for GET/HEAD requests",
- anonymousMap.get("default")));
- return anonymousMap.get("default");
- }
- // Else disallow anonymous.
- return false;
- }
-
- /**
- * Build a regular expression from the current scheme, hostname and port for
- * matching against the site urls.
- *
- * @param request
- * The current request.
- * @return The regular expression.
- */
- private static String buildUrlRegex(final HttpServletRequest request) {
- return "^" + request.getScheme() + "://" + Pattern.quote(request.getServerName()) +
- "(?::" + request.getServerPort() + ")" + (request.getServerPort() == 80 ? "?" : "") + "/?$";
- }
-}
diff --git a/src/main/java/ca/islandora/syn/valve/SynRequestWrapper.java b/src/main/java/ca/islandora/syn/valve/SynRequestWrapper.java
deleted file mode 100644
index 2fbf16b..0000000
--- a/src/main/java/ca/islandora/syn/valve/SynRequestWrapper.java
+++ /dev/null
@@ -1,52 +0,0 @@
-package ca.islandora.syn.valve;
-
-import java.security.Principal;
-import java.util.List;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletRequestWrapper;
-
-/**
- * Request wrapper to use JWT provided name and roles.
- *
- * @author whikloj
- * @since 2018-01-16
- */
-public class SynRequestWrapper extends HttpServletRequestWrapper {
- private final String user;
- private List roles;
- private final HttpServletRequest realRequest;
-
- /**
- * Constructor
- *
- * @param user
- * The username for the Principal.
- * @param roles
- * List of roles to include the Principal in.
- * @param request
- * The original request.
- */
- public SynRequestWrapper(final String user, final List roles, final HttpServletRequest request) {
- super(request);
- this.user = user;
- this.realRequest = request;
- this.roles = roles;
- }
-
- @Override
- public boolean isUserInRole(final String role) {
- return roles.contains(role);
- }
-
- @Override
- public Principal getUserPrincipal() {
- // make an anonymous implementation to just return our user
- return new Principal() {
- @Override
- public String getName() {
- return user;
- }
- };
- }
-}
diff --git a/src/main/java/ca/islandora/syn/valve/SynValve.java b/src/main/java/ca/islandora/syn/valve/SynValve.java
new file mode 100644
index 0000000..6d0158a
--- /dev/null
+++ b/src/main/java/ca/islandora/syn/valve/SynValve.java
@@ -0,0 +1,213 @@
+package ca.islandora.syn.valve;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.connector.Request;
+import org.apache.catalina.connector.Response;
+import org.apache.catalina.realm.GenericPrincipal;
+import org.apache.catalina.valves.ValveBase;
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.util.descriptor.web.SecurityConstraint;
+
+import com.auth0.jwt.algorithms.Algorithm;
+
+import ca.islandora.syn.settings.SettingsParser;
+import ca.islandora.syn.settings.Token;
+import ca.islandora.syn.token.Verifier;
+
+public class SynValve extends ValveBase {
+
+ private String pathname = "conf/syn-settings.xml";
+ private static final Log log = LogFactory.getLog(SynValve.class);
+ private Map algorithmMap = null;
+ private Map staticTokenMap = null;
+
+ private Map anonymousGetMap = null;
+
+ @Override
+ public void invoke(final Request request, final Response response)
+ throws IOException, ServletException {
+
+ final SecurityConstraint[] constraints = this.container.getRealm()
+ .findSecurityConstraints(request, request.getContext());
+
+ if ((constraints == null
+ && !request.getContext().getPreemptiveAuthentication())
+ || !hasAuthConstraint(constraints)) {
+ this.getNext().invoke(request, response);
+ } else {
+ handleAuthentication(request, response);
+ }
+ }
+
+ private boolean hasAuthConstraint(final SecurityConstraint[] constraints) {
+ boolean authConstraint = true;
+ for (SecurityConstraint securityConstraint : constraints) {
+ authConstraint &= securityConstraint.getAuthConstraint();
+ }
+ return authConstraint;
+ }
+
+ private boolean doAuthentication(final Request request) {
+ String token = request.getHeader("Authorization");
+ if (token == null) {
+ log.info("Request did not contain any token.");
+ return false;
+ }
+
+ final String[] tokenParts = token.split(" ");
+ if (tokenParts.length != 2 || !tokenParts[0].equalsIgnoreCase("bearer")) {
+ log.info("Token was malformed. Token: " + token);
+ return false;
+ }
+
+ // strip bearer off of the token
+ token = tokenParts[1];
+
+ // check if we have a static token that matches
+ if (this.staticTokenMap.containsKey(token)) {
+ log.info("Site verified using static token.");
+ setUserRolesFromStaticToken(request, this.staticTokenMap.get(token));
+ request.setAuthType("SYN");
+ return true;
+ }
+
+ final Verifier verifier = Verifier.create(token);
+ if (verifier == null) {
+ log.info("Token rejected for not containing correct claims.");
+ return false;
+ }
+
+ final String url = verifier.getUrl();
+ Algorithm algorithm = null;
+ if (algorithmMap.containsKey(url)) {
+ algorithm = algorithmMap.get(url);
+ } else if (algorithmMap.containsKey(null)) {
+ algorithm = algorithmMap.get(null);
+ }
+
+ if (algorithm == null) {
+ log.info("No key found for site: " + url + ".");
+ return false;
+ }
+
+ if (verifier.verify(algorithm)) {
+ log.info("Site verified: " + url);
+ setUserRolesFromToken(request, verifier);
+ request.setAuthType("SYN");
+ return true;
+ } else {
+ log.info("Token failed signature verification: " + url);
+ return false;
+ }
+ }
+
+ private void setAnonymousRoles(final Request request) {
+ final List roles = new ArrayList();
+ roles.add("anonymous");
+ roles.add("islandora");
+ final String name = "anonymous";
+ final GenericPrincipal principal = new GenericPrincipal(name, null, roles);
+ request.setUserPrincipal(principal);
+ }
+
+ private void setUserRolesFromStaticToken(final Request request, final Token token) {
+ final List roles = token.getRoles();
+ roles.add("islandora");
+ final String name = token.getUser();
+ final GenericPrincipal principal = new GenericPrincipal(name, null, roles);
+ request.setUserPrincipal(principal);
+ }
+
+ private void setUserRolesFromToken(final Request request, final Verifier verifier) {
+ final List roles = verifier.getRoles();
+ roles.add("islandora");
+ roles.add(verifier.getUrl());
+ final String name = verifier.getName();
+ final GenericPrincipal principal = new GenericPrincipal(name, null, roles);
+ request.setUserPrincipal(principal);
+ }
+
+ private void handleAuthentication(final Request request, final Response response)
+ throws IOException, ServletException {
+ if ((request.getMethod().equalsIgnoreCase("GET") ||
+ request.getMethod().equals("HEAD")) &&
+ allowGetRequests(request.getHost().toString())) {
+ // Skip authentication
+ setAnonymousRoles(request);
+ this.getNext().invoke(request, response);
+ } else if (doAuthentication(request)) {
+ this.getNext().invoke(request, response);
+ } else {
+ response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Token authentication failed.");
+ }
+ }
+
+ /**
+ * Do the logic of allowing GET/HEAD requests.
+ *
+ * @param requestURI the site being requested
+ * @return whether to allow GET requests without authentication.
+ */
+ private boolean allowGetRequests(final String requestURI) {
+ // If there is a matching site URI, return its value
+ if (anonymousGetMap.containsKey(requestURI)) {
+ log.debug(
+ String.format(
+ "Using site anonymous ({}) for GET/HEAD requests, site {}",
+ anonymousGetMap.get(requestURI),
+ requestURI));
+ return anonymousGetMap.get(requestURI);
+ // Else if there is a default, return its value.
+ } else if (anonymousGetMap.containsKey("default")) {
+ log.debug(
+ String.format(
+ "Using default anonymous ({}) for GET/HEAD requests, host {}",
+ anonymousGetMap.get("default"),
+ requestURI));
+ return anonymousGetMap.get("default");
+ }
+ // Else disallow anonymous.
+ return false;
+ }
+
+ public String getPathname() {
+ return pathname;
+ }
+ public void setPathname(final String pathname) {
+ this.pathname = pathname;
+ }
+
+ @Override
+ public synchronized void startInternal() throws LifecycleException {
+ // Perform normal superclass initialization
+ super.startInternal();
+ // Validate the existence of our database file
+ File file = new File(pathname);
+ if (!file.isAbsolute()) {
+ file = new File(System.getProperty("catalina.base"), pathname);
+ }
+ if (!file.exists() || !file.canRead()) {
+ throw new LifecycleException("Unable to load XML Configuration from Path: " + pathname);
+ }
+
+ // Load the contents of the database file
+ try {
+ this.algorithmMap = SettingsParser.getSiteAlgorithms(new FileInputStream(file));
+ this.staticTokenMap = SettingsParser.getSiteStaticTokens(new FileInputStream(file));
+ this.anonymousGetMap = SettingsParser.getSiteAllowAnonymous(new FileInputStream(file));
+ } catch (Exception e) {
+ throw new LifecycleException("Error parsing XML Configuration", e);
+ }
+ }
+}
diff --git a/src/test/java/ca/islandora/syn/settings/SettingsParserAlgorithmsTest.java b/src/test/java/ca/islandora/syn/settings/SettingsParserAlgorithmsTest.java
index a6f37e5..d33d112 100644
--- a/src/test/java/ca/islandora/syn/settings/SettingsParserAlgorithmsTest.java
+++ b/src/test/java/ca/islandora/syn/settings/SettingsParserAlgorithmsTest.java
@@ -1,10 +1,10 @@
package ca.islandora.syn.settings;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
+import java.io.ByteArrayInputStream;
import java.io.File;
-import java.io.StringReader;
+import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Map;
@@ -20,21 +20,19 @@ public class SettingsParserAlgorithmsTest {
public TemporaryFolder temporaryFolder = new TemporaryFolder();
private void testOneSiteHmacInlineKey(final String algorithm) throws Exception {
- final String testYaml = String.join("\n",
- "---",
- "version: 1",
- "site:",
- " url: http://test.com",
- " algorithm: " + algorithm,
- " encoding: plain",
- " key: test data");
-
- try (final StringReader stream = new StringReader(testYaml)) {
- final Map algorithms = SettingsParser.create(stream).getSiteAlgorithms();
- assertEquals(1, algorithms.size());
- assertEquals(true, algorithms.containsKey("http://test.com"));
- assertEquals(algorithm, algorithms.get("http://test.com").getName());
- }
+ final String testXml = String.join("\n"
+ , ""
+ , " "
+ , " test data"
+ , " "
+ , ""
+ );
+
+ final InputStream stream = new ByteArrayInputStream(testXml.getBytes());
+ final Map algorithms = SettingsParser.getSiteAlgorithms(stream);
+ assertEquals(1, algorithms.size());
+ assertEquals(true, algorithms.containsKey("http://test.com"));
+ assertEquals(algorithm, algorithms.get("http://test.com").getName());
}
@Test
@@ -45,109 +43,80 @@ public void testOneSiteAllHmacInlineKey() throws Exception {
}
@Test
- public void testUnsupportedAlgorithm() throws Exception {
- final String testYaml = String.join("\n",
- "---",
- "version: 1",
- "site:",
- " url: http://test.com",
- " algorithm: AES128",
- " encoding: plain",
- " key: test data");
-
- try (final StringReader stream = new StringReader(testYaml)) {
- final Map algorithms = SettingsParser.create(stream).getSiteAlgorithms();
- assertEquals(0, algorithms.size());
- assertFalse(algorithms.containsKey("http://test.com"));
- }
- }
-
- @Test(expected = SettingsParserException.class)
public void testInvalidSitesVersion() throws Exception {
- final String testYaml = String.join("\n",
- "---",
- "version: 2",
- "site:",
- " url: http://test.com",
- " algorithm: HS384",
- " encoding: plain",
- " key: test data");
-
- try (final StringReader stream = new StringReader(testYaml)) {
- SettingsParser.create(stream).getSiteAlgorithms();
- }
+ final String testXml = String.join("\n"
+ , ""
+ , " "
+ , " test data"
+ , " "
+ , ""
+ );
+
+ final InputStream stream = new ByteArrayInputStream(testXml.getBytes());
+ final Map algorithms = SettingsParser.getSiteAlgorithms(stream);
+ assertEquals(0, algorithms.size());
}
@Test
public void testOneSiteHmacBase64() throws Exception {
- final String testYaml = String.join("\n",
- "---",
- "version: 1",
- "site:",
- " url: http://test.com",
- " algorithm: HS256",
- " encoding: base64",
- " key: am9uYXRoYW4gaXMgYXdlc29tZQ==");
-
- try (final StringReader stream = new StringReader(testYaml)) {
- final Map algorithms = SettingsParser.create(stream).getSiteAlgorithms();
- assertEquals(1, algorithms.size());
- }
+ final String testXml = String.join("\n"
+ , ""
+ , " "
+ , " am9uYXRoYW4gaXMgYXdlc29tZQ=="
+ , " "
+ , ""
+ );
+
+ final InputStream stream = new ByteArrayInputStream(testXml.getBytes());
+ final Map algorithms = SettingsParser.getSiteAlgorithms(stream);
+ assertEquals(1, algorithms.size());
}
@Test
public void testOneSiteHmacInvalidBase64() throws Exception {
- final String testYaml = String.join("\n",
- "---",
- "version: 1",
- "site:",
- " url: http://test.com",
- " algorithm: HS256",
- " encoding: base64",
- " key: this is invalid base64");
-
- try (final StringReader stream = new StringReader(testYaml)) {
- final Map algorithms = SettingsParser.create(stream).getSiteAlgorithms();
- assertEquals(0, algorithms.size());
- }
+ final String testXml = String.join("\n"
+ , ""
+ , " "
+ , " this is invalid base64"
+ , " "
+ , ""
+ );
+
+ final InputStream stream = new ByteArrayInputStream(testXml.getBytes());
+ final Map algorithms = SettingsParser.getSiteAlgorithms(stream);
+ assertEquals(0, algorithms.size());
}
@Test
public void testOneSiteHmacInvalidEncoding() throws Exception {
- final String testYaml = String.join("\n",
- "---",
- "version: 1",
- "site:",
- " url: http://test.com",
- " algorithm: HS256",
- " encoding: badalgorithm",
- " key: this is invalid base64");
-
- try (final StringReader stream = new StringReader(testYaml)) {
- final Map algorithms = SettingsParser.create(stream).getSiteAlgorithms();
- assertEquals(0, algorithms.size());
- }
+ final String testXml = String.join("\n"
+ , ""
+ , " "
+ , " this is invalid base64"
+ , " "
+ , ""
+ );
+
+ final InputStream stream = new ByteArrayInputStream(testXml.getBytes());
+ final Map algorithms = SettingsParser.getSiteAlgorithms(stream);
+ assertEquals(0, algorithms.size());
}
private void testOneSiteHmacFileKey(final String algorithm) throws Exception {
final File key = temporaryFolder.newFile();
final String path = key.getAbsolutePath();
- final String testYaml = String.join("\n",
- "---",
- "version: 1",
- "site:",
- " url: http://test.com",
- " algorithm: " + algorithm,
- " encoding: plain",
- " path: " + path);
-
- try (final StringReader stream = new StringReader(testYaml)) {
- final Map algorithms = SettingsParser.create(stream).getSiteAlgorithms();
- assertEquals(1, algorithms.size());
- assertEquals(true, algorithms.containsKey("http://test.com"));
- assertEquals(algorithm, algorithms.get("http://test.com").getName());
- }
+ final String testXml = String.join("\n"
+ , ""
+ , " "
+ , ""
+ );
+
+ final InputStream stream = new ByteArrayInputStream(testXml.getBytes());
+ final Map algorithms = SettingsParser.getSiteAlgorithms(stream);
+ assertEquals(1, algorithms.size());
+ assertEquals(true, algorithms.containsKey("http://test.com"));
+ assertEquals(algorithm, algorithms.get("http://test.com").getName());
}
@Test
@@ -159,110 +128,94 @@ public void testOneSiteAllHmacFileKey() throws Exception {
@Test
public void testSiteBothInlineAndPath() throws Exception {
- final String testYaml = String.join("\n",
- "---",
- "version: 1",
- "site:",
- " url: http://test.com",
- " algorithm: HS384",
- " encoding: plain",
- " path: foo",
- " key: test data");
-
- try (final StringReader stream = new StringReader(testYaml)) {
- final Map algorithms = SettingsParser.create(stream).getSiteAlgorithms();
- assertEquals(0, algorithms.size());
- }
+ final String testXml = String.join("\n"
+ , ""
+ , " "
+ , " test data"
+ , " "
+ , ""
+ );
+
+ final InputStream stream = new ByteArrayInputStream(testXml.getBytes());
+ final Map algorithms = SettingsParser.getSiteAlgorithms(stream);
+ assertEquals(0, algorithms.size());
}
@Test
public void testSiteNeitherInlineAndPath() throws Exception {
- final String testYaml = String.join("\n",
- "---",
- "version: 1",
- "site:",
- " url: http://test.com",
- " algorithm: HS384",
- " encoding: plain");
-
- try (final StringReader stream = new StringReader(testYaml)) {
- final Map algorithms = SettingsParser.create(stream).getSiteAlgorithms();
- assertEquals(0, algorithms.size());
- }
+ final String testXml = String.join("\n"
+ , ""
+ , " "
+ , ""
+ );
+
+ final InputStream stream = new ByteArrayInputStream(testXml.getBytes());
+ final Map algorithms = SettingsParser.getSiteAlgorithms(stream);
+ assertEquals(0, algorithms.size());
}
@Test
public void testSiteInvalidPath() throws Exception {
- final String testYaml = String.join("\n",
- "---",
- "version: 1",
- "site:",
- " url: http://test.com",
- " algorithm: HS384",
- " encoding: plain",
- " path: foo");
-
- try (final StringReader stream = new StringReader(testYaml)) {
- final Map algorithms = SettingsParser.create(stream).getSiteAlgorithms();
- assertEquals(0, algorithms.size());
- }
+ final String testXml = String.join("\n"
+ , ""
+ , " "
+ , ""
+ );
+
+ final InputStream stream = new ByteArrayInputStream(testXml.getBytes());
+ final Map algorithms = SettingsParser.getSiteAlgorithms(stream);
+ assertEquals(0, algorithms.size());
}
@Test
public void testSiteNoUrlDefault() throws Exception {
- final String testYaml = String.join("\n",
- "---",
- "version: 1",
- "site:",
- " algorithm: HS256",
- " encoding: plain",
- " default: true",
- " key: test data");
-
- try (final StringReader stream = new StringReader(testYaml)) {
- final Map algorithms = SettingsParser.create(stream).getSiteAlgorithms();
- assertEquals(1, algorithms.size());
- }
+ final String testXml = String.join("\n"
+ , ""
+ , " "
+ , " test data"
+ , " "
+ , ""
+ );
+
+ final InputStream stream = new ByteArrayInputStream(testXml.getBytes());
+ final Map algorithms = SettingsParser.getSiteAlgorithms(stream);
+ assertEquals(1, algorithms.size());
}
@Test
public void testSiteNoUrl() throws Exception {
- final String testYaml = String.join("\n",
- "---",
- "version: 1",
- "site:",
- " algorithm: HS256",
- " encoding: plain",
- " key: test data");
-
- try (final StringReader stream = new StringReader(testYaml)) {
- final Map algorithms = SettingsParser.create(stream).getSiteAlgorithms();
- assertEquals(0, algorithms.size());
- }
+ final String testXml = String.join("\n"
+ , ""
+ , " "
+ , " test data"
+ , " "
+ , ""
+ );
+
+ final InputStream stream = new ByteArrayInputStream(testXml.getBytes());
+ final Map algorithms = SettingsParser.getSiteAlgorithms(stream);
+ assertEquals(0, algorithms.size());
}
private void testOneSiteRsaInlineKey(final String algorithm) throws Exception {
- final String testYaml = String.join("\n",
- "---",
- "version: 1",
- "site:",
- " url: http://test.com",
- " algorithm: " + algorithm,
- " encoding: PEM",
- " key: |",
- " -----BEGIN PUBLIC KEY-----",
- " MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDEVO4MNlZG+iGYhoJd/cBpfMd9",
- " YnKsntF+zhQs8lCbBabgY8kNoXVIEeOm4WPJ+W53gLDAIg6BNrZqxk9z1TLD6Dmz",
- " t176OLYkNoTI9LNf6z4wuBenrlQ/H5UnYl6h5QoOdVpNAgEjkDcdTSOE1lqFLIle",
- " KOT4nEF7MBGyOSP3KQIDAQAB",
- " -----END PUBLIC KEY-----");
-
- try (final StringReader stream = new StringReader(testYaml)) {
- final Map algorithms = SettingsParser.create(stream).getSiteAlgorithms();
- assertEquals(1, algorithms.size());
- assertEquals(true, algorithms.containsKey("http://test.com"));
- assertEquals(algorithm, algorithms.get("http://test.com").getName());
- }
+ final String testXml = String.join("\n"
+ , ""
+ , " "
+ , "-----BEGIN PUBLIC KEY-----"
+ , "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDEVO4MNlZG+iGYhoJd/cBpfMd9"
+ , "YnKsntF+zhQs8lCbBabgY8kNoXVIEeOm4WPJ+W53gLDAIg6BNrZqxk9z1TLD6Dmz"
+ , "t176OLYkNoTI9LNf6z4wuBenrlQ/H5UnYl6h5QoOdVpNAgEjkDcdTSOE1lqFLIle"
+ , "KOT4nEF7MBGyOSP3KQIDAQAB"
+ , "-----END PUBLIC KEY-----"
+ , " "
+ , ""
+ );
+
+ final InputStream stream = new ByteArrayInputStream(testXml.getBytes());
+ final Map algorithms = SettingsParser.getSiteAlgorithms(stream);
+ assertEquals(1, algorithms.size());
+ assertEquals(true, algorithms.containsKey("http://test.com"));
+ assertEquals(algorithm, algorithms.get("http://test.com").getName());
}
@Test
@@ -276,29 +229,28 @@ private void testOneSiteRsaFileKey(final String algorithm) throws Exception {
final File keyFile = temporaryFolder.newFile();
final String path = keyFile.getAbsolutePath();
- final String pemPublicKey = String.join("\n", "-----BEGIN PUBLIC KEY-----",
- "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDEVO4MNlZG+iGYhoJd/cBpfMd9",
- "YnKsntF+zhQs8lCbBabgY8kNoXVIEeOm4WPJ+W53gLDAIg6BNrZqxk9z1TLD6Dmz",
- "t176OLYkNoTI9LNf6z4wuBenrlQ/H5UnYl6h5QoOdVpNAgEjkDcdTSOE1lqFLIle", "KOT4nEF7MBGyOSP3KQIDAQAB",
- "-----END PUBLIC KEY-----");
+ final String pemPublicKey = String.join("\n"
+ , "-----BEGIN PUBLIC KEY-----"
+ , "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDEVO4MNlZG+iGYhoJd/cBpfMd9"
+ , "YnKsntF+zhQs8lCbBabgY8kNoXVIEeOm4WPJ+W53gLDAIg6BNrZqxk9z1TLD6Dmz"
+ , "t176OLYkNoTI9LNf6z4wuBenrlQ/H5UnYl6h5QoOdVpNAgEjkDcdTSOE1lqFLIle"
+ , "KOT4nEF7MBGyOSP3KQIDAQAB"
+ , "-----END PUBLIC KEY-----"
+ );
Files.write(Paths.get(path), pemPublicKey.getBytes());
- final String testYaml = String.join("\n",
- "---",
- "version: 1",
- "site:",
- " url: http://test.com",
- " algorithm: " + algorithm,
- " encoding: PEM",
- " path: " + path);
-
- try (final StringReader stream = new StringReader(testYaml)) {
- final Map algorithms = SettingsParser.create(stream).getSiteAlgorithms();
- assertEquals(1, algorithms.size());
- assertEquals(true, algorithms.containsKey("http://test.com"));
- assertEquals(algorithm, algorithms.get("http://test.com").getName());
- }
+ final String testXml = String.join("\n"
+ , ""
+ , " "
+ , ""
+ );
+
+ final InputStream stream = new ByteArrayInputStream(testXml.getBytes());
+ final Map algorithms = SettingsParser.getSiteAlgorithms(stream);
+ assertEquals(1, algorithms.size());
+ assertEquals(true, algorithms.containsKey("http://test.com"));
+ assertEquals(algorithm, algorithms.get("http://test.com").getName());
}
@Test
@@ -310,52 +262,45 @@ public void testOneSiteAllRsaFileKey() throws Exception {
@Test
public void testOneSiteAllRsaInvalidEncoding() throws Exception {
- final String testYaml = String.join("\n",
- "---",
- "version: 1",
- "site:",
- " url: http://test.com",
- " algorithm: RS256",
- " encoding: PEM",
- " key: |",
- " -----BEGIN PUBLIC KEY-----");
-
- try (final StringReader stream = new StringReader(testYaml)) {
- final Map algorithms = SettingsParser.create(stream).getSiteAlgorithms();
- assertEquals(0, algorithms.size());
- }
+ final String testXml = String.join("\n"
+ , ""
+ , " "
+ , "-----BEGIN PUBLIC KEY-----"
+ , " "
+ , ""
+ );
+
+ final InputStream stream = new ByteArrayInputStream(testXml.getBytes());
+ final Map algorithms = SettingsParser.getSiteAlgorithms(stream);
+ assertEquals(0, algorithms.size());
}
+
@Test
public void testMultipleDefaults() throws Exception {
final File keyFile = temporaryFolder.newFile();
final String path = keyFile.getAbsolutePath();
- final String pemPublicKey = String.join("\n", "-----BEGIN PUBLIC KEY-----",
- "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDEVO4MNlZG+iGYhoJd/cBpfMd9",
- "YnKsntF+zhQs8lCbBabgY8kNoXVIEeOm4WPJ+W53gLDAIg6BNrZqxk9z1TLD6Dmz",
- "t176OLYkNoTI9LNf6z4wuBenrlQ/H5UnYl6h5QoOdVpNAgEjkDcdTSOE1lqFLIle", "KOT4nEF7MBGyOSP3KQIDAQAB",
- "-----END PUBLIC KEY-----");
+ final String pemPublicKey = String.join("\n"
+ , "-----BEGIN PUBLIC KEY-----"
+ , "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDEVO4MNlZG+iGYhoJd/cBpfMd9"
+ , "YnKsntF+zhQs8lCbBabgY8kNoXVIEeOm4WPJ+W53gLDAIg6BNrZqxk9z1TLD6Dmz"
+ , "t176OLYkNoTI9LNf6z4wuBenrlQ/H5UnYl6h5QoOdVpNAgEjkDcdTSOE1lqFLIle"
+ , "KOT4nEF7MBGyOSP3KQIDAQAB"
+ , "-----END PUBLIC KEY-----"
+ );
Files.write(Paths.get(path), pemPublicKey.getBytes());
- final String testYaml = String.join("\n",
- "---",
- "version: 1",
- "site:",
- " algorithm: RS384",
- " path: " + path,
- " encoding: PEM",
- " default: true",
- "site:",
- " algorithm: HS256",
- " path: " + path,
- " encoding: plain",
- " default: true");
- try (final StringReader stream = new StringReader(testYaml)) {
- final Map algorithms = SettingsParser.create(stream).getSiteAlgorithms();
- assertEquals(1, algorithms.size());
- }
+ final String testXml = String.join("\n"
+ , ""
+ , " "
+ , " "
+ , ""
+ );
+ final InputStream stream = new ByteArrayInputStream(testXml.getBytes());
+ final Map algorithms = SettingsParser.getSiteAlgorithms(stream);
+ assertEquals(1, algorithms.size());
}
@Test
@@ -363,25 +308,24 @@ public void testInvalidAlgorithm() throws Exception {
final File keyFile = temporaryFolder.newFile();
final String path = keyFile.getAbsolutePath();
- final String pemPublicKey = String.join("\n", "-----BEGIN PUBLIC KEY-----",
- "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDEVO4MNlZG+iGYhoJd/cBpfMd9",
- "YnKsntF+zhQs8lCbBabgY8kNoXVIEeOm4WPJ+W53gLDAIg6BNrZqxk9z1TLD6Dmz",
- "t176OLYkNoTI9LNf6z4wuBenrlQ/H5UnYl6h5QoOdVpNAgEjkDcdTSOE1lqFLIle", "KOT4nEF7MBGyOSP3KQIDAQAB",
- "-----END PUBLIC KEY-----");
+ final String pemPublicKey = String.join("\n"
+ , "-----BEGIN PUBLIC KEY-----"
+ , "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDEVO4MNlZG+iGYhoJd/cBpfMd9"
+ , "YnKsntF+zhQs8lCbBabgY8kNoXVIEeOm4WPJ+W53gLDAIg6BNrZqxk9z1TLD6Dmz"
+ , "t176OLYkNoTI9LNf6z4wuBenrlQ/H5UnYl6h5QoOdVpNAgEjkDcdTSOE1lqFLIle"
+ , "KOT4nEF7MBGyOSP3KQIDAQAB"
+ , "-----END PUBLIC KEY-----"
+ );
Files.write(Paths.get(path), pemPublicKey.getBytes());
- final String testYaml = String.join("\n",
- "---",
- "version: 1",
- "site:",
- " algorithm: RSA384",
- " path: " + path,
- " encoding: PEM",
- " default: true");
- try (final StringReader stream = new StringReader(testYaml)) {
- final Map algorithms = SettingsParser.create(stream).getSiteAlgorithms();
- assertEquals(0, algorithms.size());
- }
+ final String testXml = String.join("\n"
+ , ""
+ , " "
+ , ""
+ );
+ final InputStream stream = new ByteArrayInputStream(testXml.getBytes());
+ final Map algorithms = SettingsParser.getSiteAlgorithms(stream);
+ assertEquals(0, algorithms.size());
}
}
diff --git a/src/test/java/ca/islandora/syn/settings/SettingsParserAnonymousTest.java b/src/test/java/ca/islandora/syn/settings/SettingsParserAnonymousTest.java
index 917beb0..9c7d321 100644
--- a/src/test/java/ca/islandora/syn/settings/SettingsParserAnonymousTest.java
+++ b/src/test/java/ca/islandora/syn/settings/SettingsParserAnonymousTest.java
@@ -2,7 +2,8 @@
import static org.junit.Assert.assertEquals;
-import java.io.StringReader;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
import java.util.Map;
import org.junit.Test;
@@ -11,84 +12,65 @@ public class SettingsParserAnonymousTest {
@Test
public void testSiteAnonymousOn() throws Exception {
- final String testYaml = String.join("\n",
- "---",
- "version: 1",
- "site:",
- " url: http://test.com",
- " algorithm: RS256",
- " encoding: plain",
- " anonymous: true",
- " key: test data");
+ final String testXml = String.join("\n"
+ , ""
+ , " "
+ , " test data"
+ , " "
+ , ""
+ );
- try (final StringReader stream = new StringReader(testYaml)) {
- final Map anonymous = SettingsParser.create(stream).getSiteAllowAnonymous();
- assertEquals(1, anonymous.size());
- assertEquals(true, anonymous.containsKey("http://test.com"));
- assertEquals(true, anonymous.get("http://test.com"));
- }
+ final InputStream stream = new ByteArrayInputStream(testXml.getBytes());
+ final Map anonymous = SettingsParser.getSiteAllowAnonymous(stream);
+ assertEquals(1, anonymous.size());
+ assertEquals(true, anonymous.containsKey("http://test.com"));
+ assertEquals(true, anonymous.get("http://test.com"));
}
@Test
public void testSiteMultipleAnonymousTest() throws Exception {
- final String testYaml = String.join("\n",
- "---",
- "version: 1",
- "site:",
- " url: http://test.com",
- " algorithm: RS256",
- " encoding: plain",
- " anonymous: true",
- " key: test data",
- "site:",
- " url: http://test2.com",
- " algorithm: RS256",
- " encoding: plain",
- " anonymous: false",
- " key: test data");
+ final String testXml = String.join("\n"
+ , ""
+ , " "
+ , " test data"
+ , " "
+ , " "
+ , " test data"
+ , " "
+ , ""
+ );
- try (final StringReader stream = new StringReader(testYaml)) {
- final Map anonymous = SettingsParser.create(stream).getSiteAllowAnonymous();
- assertEquals(2, anonymous.size());
- assertEquals(true, anonymous.containsKey("http://test.com"));
- assertEquals(true, anonymous.get("http://test.com"));
- assertEquals(true, anonymous.containsKey("http://test2.com"));
- assertEquals(false, anonymous.get("http://test2.com"));
- }
+ final InputStream stream = new ByteArrayInputStream(testXml.getBytes());
+ final Map anonymous = SettingsParser.getSiteAllowAnonymous(stream);
+ assertEquals(2, anonymous.size());
+ assertEquals(true, anonymous.containsKey("http://test.com"));
+ assertEquals(true, anonymous.get("http://test.com"));
+ assertEquals(true, anonymous.containsKey("http://test2.com"));
+ assertEquals(false, anonymous.get("http://test2.com"));
}
@Test
public void testDefaultMultipleAnonymousTest() throws Exception {
- final String testYaml = String.join("\n",
- "---",
- "version: 1",
- "site:",
- " url: http://test.com",
- " algorithm: RS256",
- " encoding: plain",
- " anonymous: true",
- " key: test data",
- "site:",
- " url: http://test2.com",
- " algorithm: RS256",
- " encoding: plain",
- " anonymous: false",
- " key: test data",
- "site:",
- " algorithm: RS256",
- " encoding: plain",
- " anonymous: true",
- " default: true");
+ final String testXml = String.join("\n"
+ , ""
+ , " "
+ , " test data"
+ , " "
+ , " "
+ , " test data"
+ , " "
+ , " "
+ , ""
+ );
- try (final StringReader stream = new StringReader(testYaml)) {
- final Map anonymous = SettingsParser.create(stream).getSiteAllowAnonymous();
- assertEquals(3, anonymous.size());
- assertEquals(true, anonymous.containsKey("http://test.com"));
- assertEquals(true, anonymous.get("http://test.com"));
- assertEquals(true, anonymous.containsKey("http://test2.com"));
- assertEquals(false, anonymous.get("http://test2.com"));
- assertEquals(true, anonymous.containsKey("default"));
- assertEquals(true, anonymous.get("default"));
- }
+ final InputStream stream = new ByteArrayInputStream(testXml.getBytes());
+ final Map anonymous = SettingsParser.getSiteAllowAnonymous(stream);
+ assertEquals(3, anonymous.size());
+ assertEquals(true, anonymous.containsKey("http://test.com"));
+ assertEquals(true, anonymous.get("http://test.com"));
+ assertEquals(true, anonymous.containsKey("http://test2.com"));
+ assertEquals(false, anonymous.get("http://test2.com"));
+ assertEquals(true, anonymous.containsKey("default"));
+ assertEquals(true, anonymous.get("default"));
}
}
diff --git a/src/test/java/ca/islandora/syn/settings/SettingsParserDigestTest.java b/src/test/java/ca/islandora/syn/settings/SettingsParserDigestTest.java
index cfc3486..77daec8 100644
--- a/src/test/java/ca/islandora/syn/settings/SettingsParserDigestTest.java
+++ b/src/test/java/ca/islandora/syn/settings/SettingsParserDigestTest.java
@@ -5,7 +5,8 @@
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
-import java.io.StringReader;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
import org.junit.Test;
@@ -13,141 +14,127 @@ public class SettingsParserDigestTest {
@Test
public void testOneSitePath() throws Exception {
- final String testYaml = String.join("\n",
- "---",
- "version: 1",
- "site:",
- " url: http://test.com",
- " algorithm: RS384",
- " path: test/path.key",
- " encoding: PEM");
-
- try (final StringReader stream = new StringReader(testYaml)) {
- final Config settings = SettingsParser.create(stream).getConfig();
- assertEquals(1, settings.getVersion());
- assertEquals(1, settings.getSites().size());
-
- final Site site = settings.getSites().get(0);
- assertEquals("RS384", site.getAlgorithm());
- assertEquals("http://test.com", site.getUrl());
- assertEquals("test/path.key", site.getPath());
- assertEquals("PEM", site.getEncoding());
- assertNull(site.getKey());
- assertFalse(site.getDefault());
- }
+ final String testXml = String.join("\n"
+ , ""
+ , " "
+ , ""
+ );
+
+ final InputStream stream = new ByteArrayInputStream(testXml.getBytes());
+ final Config settings = SettingsParser.getSitesObject(stream);
+ assertEquals(12, settings.getVersion());
+ assertEquals(1, settings.getSites().size());
+
+ final Site site = settings.getSites().get(0);
+ assertEquals("RS384", site.getAlgorithm());
+ assertEquals("http://test.com", site.getUrl());
+ assertEquals("test/path.key", site.getPath());
+ assertEquals("PEM", site.getEncoding());
+ assertEquals("", site.getKey());
+ assertFalse(site.getDefault());
}
@Test
public void testOneSiteKey() throws Exception {
- final String testYaml = String.join("\n",
- "---",
- "version: 1",
- "site:",
- " url: http://test.com",
- " algorithm: RS384",
- " encoding: PEM",
- " default: true",
- " key: |",
- " multiline",
- " key");
-
- try (final StringReader stream = new StringReader(testYaml)) {
- final Config settings = SettingsParser.create(stream).getConfig();
- assertEquals(1, settings.getVersion());
- assertEquals(1, settings.getSites().size());
-
- final Site site = settings.getSites().get(0);
- assertEquals("RS384", site.getAlgorithm());
- assertEquals("http://test.com", site.getUrl());
- assertNull(site.getPath());
- assertEquals("PEM", site.getEncoding());
- assertEquals("multiline\nkey", site.getKey());
- assertTrue(site.getDefault());
- }
+ final String testXml = String.join("\n"
+ , ""
+ , " "
+ , "multiline"
+ , "key"
+ , " "
+ , ""
+ );
+
+ final InputStream stream = new ByteArrayInputStream(testXml.getBytes());
+ final Config settings = SettingsParser.getSitesObject(stream);
+ assertEquals(-1, settings.getVersion());
+ assertEquals(1, settings.getSites().size());
+
+ final Site site = settings.getSites().get(0);
+ assertEquals("RS384", site.getAlgorithm());
+ assertEquals("http://test.com", site.getUrl());
+ assertNull(site.getPath());
+ assertEquals("PEM", site.getEncoding());
+ assertEquals("multiline\nkey", site.getKey());
+ assertTrue(site.getDefault());
}
@Test
public void testTwoSites() throws Exception {
- final String testYaml = String.join("\n",
- "---",
- "version: 1",
- "site:",
- "site:");
-
- try (final StringReader stream = new StringReader(testYaml)) {
- final Config settings = SettingsParser.create(stream).getConfig();
- assertEquals(2, settings.getSites().size());
- }
+ final String testXml = String.join("\n"
+ , ""
+ , " "
+ , " "
+ , ""
+ );
+
+ final InputStream stream = new ByteArrayInputStream(testXml.getBytes());
+ final Config settings = SettingsParser.getSitesObject(stream);
+ assertEquals(2, settings.getSites().size());
}
- @Test(expected = SettingsParserException.class)
+ @Test
public void testOneSiteUnexpectedAttribute() throws Exception {
- final String testYaml = String.join("\n",
- "---",
- "version: 1",
- "site:",
- " unexpected: woh");
-
- try (final StringReader stream = new StringReader(testYaml)) {
- final Config settings = SettingsParser.create(stream).getConfig();
- assertEquals(1, settings.getSites().size());
- }
+ final String testXml = String.join("\n"
+ , ""
+ , " "
+ , ""
+ );
+
+ final InputStream stream = new ByteArrayInputStream(testXml.getBytes());
+ final Config settings = SettingsParser.getSitesObject(stream);
+ assertEquals(1, settings.getSites().size());
}
+ @Test
+ public void testOneSiteUnexpectedTag() throws Exception {
+ final String testXml = String.join("\n"
+ , ""
+ , " "
+ , ""
+ );
+
+ final InputStream stream = new ByteArrayInputStream(testXml.getBytes());
+ final Config settings = SettingsParser.getSitesObject(stream);
+ assertEquals(0, settings.getSites().size())
+; }
+
@Test
public void testValidAnonymousTrue() throws Exception {
- final String testYaml = String.join("\n",
- "---",
- "version: 1",
- "site:",
- " url: http://test.com",
- " algorithm: RS384",
- " encoding: PEM",
- " default: true",
- " anonymous: true");
-
- try (final StringReader stream = new StringReader(testYaml)) {
- final Config settings = SettingsParser.create(stream).getConfig();
- final Site sites = settings.getSites().get(0);
- assertTrue("Did not set anonymous property", sites.getAnonymous());
- }
+ final String testXml = "\n" +
+ " \n" +
+ "";
+
+ final InputStream stream = new ByteArrayInputStream(testXml.getBytes());
+ final Config settings = SettingsParser.getSitesObject(stream);
+ final Site sites = settings.getSites().get(0);
+ assertTrue("Did not set anonymous property", sites.getAnonymous());
}
@Test
public void testValidAnonymousFalse() throws Exception {
- final String testYaml = String.join("\n",
- "---",
- "version: 1",
- "site:",
- " url: http://test.com",
- " algorithm: RS384",
- " encoding: PEM",
- " default: true",
- " anonymous: false");
-
- try (final StringReader stream = new StringReader(testYaml)) {
- final Config settings = SettingsParser.create(stream).getConfig();
- final Site sites = settings.getSites().get(0);
- assertFalse("Did not set anonymous property", sites.getAnonymous());
- }
+ final String testXml = "\n" +
+ " \n" +
+ "";
+
+ final InputStream stream = new ByteArrayInputStream(testXml.getBytes());
+ final Config settings = SettingsParser.getSitesObject(stream);
+ final Site sites = settings.getSites().get(0);
+ assertFalse("Did not set anonymous property", sites.getAnonymous());
}
- @Test(expected = SettingsParserException.class)
+ @Test
public void testInvalidAnonymous() throws Exception {
- final String testYaml = String.join("\n",
- "---",
- "version: 1",
- "site:",
- " url: http://test.com",
- " algorithm: RS384",
- " encoding: PEM",
- " default: true",
- " anonymous: whatever");
-
- try (final StringReader stream = new StringReader(testYaml)) {
- final Config settings = SettingsParser.create(stream).getConfig();
- final Site sites = settings.getSites().get(0);
- assertFalse("Did not set anonymous property", sites.getAnonymous());
- }
+ final String testXml = "\n" +
+ " \n" +
+ "";
+
+ final InputStream stream = new ByteArrayInputStream(testXml.getBytes());
+ final Config settings = SettingsParser.getSitesObject(stream);
+ final Site sites = settings.getSites().get(0);
+ assertFalse("Did not set anonymous property", sites.getAnonymous());
}
}
diff --git a/src/test/java/ca/islandora/syn/settings/SettingsParserTokenTest.java b/src/test/java/ca/islandora/syn/settings/SettingsParserTokenTest.java
index 3c75e6a..85f1513 100644
--- a/src/test/java/ca/islandora/syn/settings/SettingsParserTokenTest.java
+++ b/src/test/java/ca/islandora/syn/settings/SettingsParserTokenTest.java
@@ -1,79 +1,82 @@
package ca.islandora.syn.settings;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
-import java.io.StringReader;
+import org.junit.Test;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
import java.util.Map;
-import org.junit.Test;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
public class SettingsParserTokenTest {
- @Test(expected = SettingsParserException.class)
+ @Test
public void testInvalidVersion() throws Exception {
- final String testYaml = String.join("\n",
- "---",
- "version: 2",
- "token:",
- " value: c00lpazzward");
+ final String testXml = String.join("\n"
+ , ""
+ , " "
+ , " c00lpazzward"
+ , " "
+ , ""
+ );
- try (final StringReader stream = new StringReader(testYaml)) {
- SettingsParser.create(stream).getSiteStaticTokens();
- }
+ final InputStream stream = new ByteArrayInputStream(testXml.getBytes());
+ final Map tokens = SettingsParser.getSiteStaticTokens(stream);
+ assertEquals(0, tokens.size());
}
@Test
public void testTokenNoParams() throws Exception {
- final String testYaml = String.join("\n",
- "---",
- "version: 1",
- "token:",
- " value: c00lpazzward");
+ final String testXml = String.join("\n"
+ , ""
+ , " "
+ , " c00lpazzward"
+ , " "
+ , ""
+ );
- try (final StringReader stream = new StringReader(testYaml)) {
- final Map tokens = SettingsParser.create(stream).getSiteStaticTokens();
- final Token token = tokens.get("c00lpazzward");
- assertEquals(1, tokens.size());
- assertEquals("c00lpazzward", token.getValue());
- assertEquals("islandoraAdmin", token.getUser());
- assertEquals(0, token.getRoles().size());
- }
+ final InputStream stream = new ByteArrayInputStream(testXml.getBytes());
+ final Map tokens = SettingsParser.getSiteStaticTokens(stream);
+ final Token token = tokens.get("c00lpazzward");
+ assertEquals(1, tokens.size());
+ assertEquals("c00lpazzward", token.getToken());
+ assertEquals("islandoraAdmin", token.getUser());
+ assertEquals(0, token.getRoles().size());
}
@Test
public void testTokenUser() throws Exception {
- final String testYaml = String.join("\n",
- "---",
- "version: 1",
- "token:",
- " user: denis",
- " value: c00lpazzward");
+ final String testXml = String.join("\n"
+ , ""
+ , " "
+ , " c00lpazzward"
+ , " "
+ , ""
+ );
- try (final StringReader stream = new StringReader(testYaml)) {
- final Map tokens = SettingsParser.create(stream).getSiteStaticTokens();
- final Token token = tokens.get("c00lpazzward");
- assertEquals(1, tokens.size());
- assertEquals("denis", token.getUser());
- }
+ final InputStream stream = new ByteArrayInputStream(testXml.getBytes());
+ final Map tokens = SettingsParser.getSiteStaticTokens(stream);
+ final Token token = tokens.get("c00lpazzward");
+ assertEquals(1, tokens.size());
+ assertEquals("denis", token.getUser());
}
@Test
public void testTokenRole() throws Exception {
- final String testYaml = String.join("\n",
- "---",
- "version: 1",
- "token:",
- " roles: role1,role2,role3",
- " value: c00lpazzward");
+ final String testXml = String.join("\n"
+ , ""
+ , " "
+ , " c00lpazzward"
+ , " "
+ , ""
+ );
- try (final StringReader stream = new StringReader(testYaml)) {
- final Map tokens = SettingsParser.create(stream).getSiteStaticTokens();
- final Token token = tokens.get("c00lpazzward");
- assertEquals(1, tokens.size());
- assertEquals(3, token.getRoles().size());
- assertTrue(token.getRoles().contains("role1"));
- assertTrue(token.getRoles().contains("role2"));
- assertTrue(token.getRoles().contains("role3"));
- }
+ final InputStream stream = new ByteArrayInputStream(testXml.getBytes());
+ final Map tokens = SettingsParser.getSiteStaticTokens(stream);
+ final Token token = tokens.get("c00lpazzward");
+ assertEquals(1, tokens.size());
+ assertEquals(3, token.getRoles().size());
+ assertTrue(token.getRoles().contains("role1"));
+ assertTrue(token.getRoles().contains("role2"));
+ assertTrue(token.getRoles().contains("role3"));
}
}
diff --git a/src/test/java/ca/islandora/syn/settings/SitesTest.java b/src/test/java/ca/islandora/syn/settings/SitesTest.java
index e102e06..22ca6da 100644
--- a/src/test/java/ca/islandora/syn/settings/SitesTest.java
+++ b/src/test/java/ca/islandora/syn/settings/SitesTest.java
@@ -1,8 +1,7 @@
package ca.islandora.syn.settings;
-import static org.junit.Assert.assertEquals;
-
import org.junit.Test;
+import static org.junit.Assert.assertEquals;
public class SitesTest {
@@ -11,7 +10,7 @@ public void TestJwtSites() {
final Config sites = new Config();
assertEquals(-1, sites.getVersion());
sites.setVersion(2);
- assertEquals(2, sites.getVersion());
+ assertEquals(2,sites.getVersion());
assertEquals(0, sites.getSites().size());
final Site site = new Site();
diff --git a/src/test/java/ca/islandora/syn/settings/TokenTest.java b/src/test/java/ca/islandora/syn/settings/TokenTest.java
index 53c3604..5f6647a 100644
--- a/src/test/java/ca/islandora/syn/settings/TokenTest.java
+++ b/src/test/java/ca/islandora/syn/settings/TokenTest.java
@@ -1,11 +1,11 @@
package ca.islandora.syn.settings;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-
import org.junit.Before;
import org.junit.Test;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
public class TokenTest {
Token token;
@@ -40,11 +40,11 @@ public void testTokenRoles() {
@Test
public void testTokenToken() {
- assertTrue(this.token.getValue().isEmpty());
+ assertTrue(this.token.getToken().isEmpty());
final String testVal = "test";
- this.token.setValue(testVal);
- assertEquals(testVal, this.token.getValue());
- this.token.setValue(" " + testVal);
- assertEquals(testVal, this.token.getValue());
+ this.token.setToken(testVal);
+ assertEquals(testVal, this.token.getToken());
+ this.token.setToken(" " + testVal);
+ assertEquals(testVal, this.token.getToken());
}
}
diff --git a/src/test/java/ca/islandora/syn/token/VerifierTest.java b/src/test/java/ca/islandora/syn/token/VerifierTest.java
index 7d519b7..9933556 100644
--- a/src/test/java/ca/islandora/syn/token/VerifierTest.java
+++ b/src/test/java/ca/islandora/syn/token/VerifierTest.java
@@ -35,14 +35,13 @@ public void setUp() {
@Test
public void testClaimsWithoutVerify() {
token = JWT.create()
- .withArrayClaim("roles", new String[] { "Role1", "Role2" })
- .withClaim("webid", 1)
- .withClaim("sub", "admin")
- .withClaim("iss", "http://test.com")
+ .withArrayClaim("roles", new String[]{"Role1", "Role2"})
+ .withClaim("uid", 1)
+ .withClaim("name", "admin")
+ .withClaim("url", "http://test.com")
.withIssuedAt(Date.from(LocalDateTime.now().toInstant(offset)))
.withExpiresAt(Date.from(LocalDateTime.now().plusHours(2).toInstant(offset)))
.sign(Algorithm.none());
-
final Verifier verifier = Verifier.create(token);
assertEquals(1, verifier.getUid());
assertEquals("admin", verifier.getName());
@@ -53,16 +52,17 @@ public void testClaimsWithoutVerify() {
assertEquals("Role2", roles.get(1));
}
- @Test(expected = InvalidTokenException.class)
+ @Test
public void testClaimsMissing() {
token = JWT.create()
- .withClaim("sub", "admin")
- .withClaim("iss", "http://test.com")
+ .withClaim("name", "admin")
+ .withClaim("url", "http://test.com")
.sign(Algorithm.none());
- Verifier.create(token);
+ final Verifier verifier = Verifier.create(token);
+ assertNull(verifier);
}
- @Test(expected = InvalidTokenException.class)
+ @Test
public void testClaimsBad() {
token = "gibberish";
final Verifier verifier = Verifier.create(token);
@@ -72,10 +72,10 @@ public void testClaimsBad() {
@Test
public void testClaimsAndVerifyHmac() throws Exception {
token = JWT.create()
- .withArrayClaim("roles", new String[] { "Role1", "Role2" })
- .withClaim("webid", 1)
- .withClaim("sub", "admin")
- .withClaim("iss", "http://test.com")
+ .withArrayClaim("roles", new String[]{"Role1", "Role2"})
+ .withClaim("uid", 1)
+ .withClaim("name", "admin")
+ .withClaim("url", "http://test.com")
.withIssuedAt(Date.from(LocalDateTime.now().toInstant(offset)))
.withExpiresAt(Date.from(LocalDateTime.now().plusHours(2).toInstant(offset)))
.sign(Algorithm.HMAC256("secret"));
@@ -101,10 +101,10 @@ public void testClaimsAndVerifyRsa() throws Exception {
final RSAKey publicKey = (RSAKey) pair.getPublic();
token = JWT.create()
- .withArrayClaim("roles", new String[] { "Role1", "Role2" })
- .withClaim("webid", 1)
- .withClaim("sub", "admin")
- .withClaim("iss", "http://test.com")
+ .withArrayClaim("roles", new String[]{"Role1", "Role2"})
+ .withClaim("uid", 1)
+ .withClaim("name", "admin")
+ .withClaim("url", "http://test.com")
.withIssuedAt(Date.from(LocalDateTime.now().toInstant(offset)))
.withExpiresAt(Date.from(LocalDateTime.now().plusHours(2).toInstant(offset)))
.sign(Algorithm.RSA512(privateKey));
@@ -125,10 +125,10 @@ public void testClaimsAndVerifyRsa() throws Exception {
@Test
public void testClaimsAndVerifyHmacBadIssueDate() throws Exception {
token = JWT.create()
- .withArrayClaim("roles", new String[] { "Role1", "Role2" })
- .withClaim("webid", 1)
- .withClaim("sub", "admin")
- .withClaim("iss", "http://test.com")
+ .withArrayClaim("roles", new String[]{"Role1", "Role2"})
+ .withClaim("uid", 1)
+ .withClaim("name", "admin")
+ .withClaim("url", "http://test.com")
.withIssuedAt(Date.from(LocalDateTime.now().toInstant(offset)))
.withExpiresAt(Date.from(LocalDateTime.now().minusHours(2).toInstant(offset)))
.sign(Algorithm.HMAC256("secret"));
diff --git a/src/test/java/ca/islandora/syn/valves/SynFilterTest.java b/src/test/java/ca/islandora/syn/valves/SynFilterTest.java
deleted file mode 100644
index 52db131..0000000
--- a/src/test/java/ca/islandora/syn/valves/SynFilterTest.java
+++ /dev/null
@@ -1,623 +0,0 @@
-package ca.islandora.syn.valves;
-
-import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN;
-import static javax.servlet.http.HttpServletResponse.SC_UNAUTHORIZED;
-import static junit.framework.TestCase.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import java.io.File;
-import java.nio.file.Files;
-import java.nio.file.Paths;
-import java.time.Instant;
-import java.time.LocalDateTime;
-import java.time.ZoneId;
-import java.time.ZoneOffset;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Date;
-import java.util.List;
-
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnitRunner;
-
-import com.auth0.jwt.JWT;
-import com.auth0.jwt.algorithms.Algorithm;
-
-import ca.islandora.syn.valve.SynFilter;
-
-@RunWith(MockitoJUnitRunner.class)
-public class SynFilterTest {
-
- private SynFilter synFilter;
-
- private File settings;
-
- @Mock
- private FilterChain chain;
-
- @Mock
- private FilterConfig config;
-
- @Mock
- private HttpServletRequest request;
-
- @Mock
- private HttpServletResponse response;
-
- @Rule
- public TemporaryFolder temporaryFolder = new TemporaryFolder();
-
- private static ZoneOffset offset;
-
- private ArgumentCaptor requestCaptor;
- private ArgumentCaptor responseCaptor;
-
- @Before
- public void setUp() throws Exception {
- settings = temporaryFolder.newFile();
- createSettings(settings);
-
- when(config.getInitParameter("settings-path")).thenReturn(settings.getAbsolutePath());
-
- synFilter = createFilter();
-
- when(request.getScheme()).thenReturn("http");
- when(request.getServerPort()).thenReturn(80);
-
- offset = ZoneId.systemDefault().getRules().getOffset(Instant.now());
-
- requestCaptor = ArgumentCaptor.forClass(HttpServletRequest.class);
- responseCaptor = ArgumentCaptor.forClass(HttpServletResponse.class);
- }
-
- private SynFilter createFilter() throws ServletException {
- final SynFilter synFilter = new SynFilter();
- synFilter.init(config);
- return synFilter;
- }
-
- @Test(expected = ServletException.class)
- public void missingInitParameter() throws Exception {
- when(config.getInitParameter("settings-path")).thenReturn(null);
- synFilter = createFilter();
- }
-
- @Test(expected = ServletException.class)
- public void absoluteSettingsDoesNotExist() throws Exception {
- when(config.getInitParameter("settings-path")).thenReturn("/tmp/fileIsFake");
- synFilter = createFilter();
- }
-
- @Test(expected = ServletException.class)
- public void relativeSettingsDoesNotExist() throws Exception {
- when(config.getInitParameter("settings-path")).thenReturn("fileIsFake");
- synFilter = createFilter();
- }
-
- @Test(expected = ServletException.class)
- public void settingsParseFail() throws Exception {
- final String testYaml = String.join("\n",
- "---",
- "version: bad",
- "site:",
- " url: http://test.com",
- " algorithm: HS256",
- " encoding: plain",
- " anonymous: false",
- " key: secret");
- Files.write(Paths.get(this.settings.getAbsolutePath()), testYaml.getBytes());
-
- synFilter = createFilter();
- }
-
- @Test
- public void shouldPassAuth() throws Exception {
- final String host = "http://test.com";
- final String username = "adminuser";
- final String[] roles = new String[] { "role1", "role2", "role3" };
- final ArrayList finalRoles = new ArrayList(Arrays.asList(roles));
- finalRoles.add("islandora");
- finalRoles.add(host);
-
- final String token = "Bearer " + JWT
- .create()
- .withClaim("webid", 1)
- .withClaim("sub", username)
- .withClaim("iss", host)
- .withArrayClaim("roles", roles)
- .withIssuedAt(Date.from(LocalDateTime.now().toInstant(offset)))
- .withExpiresAt(Date.from(LocalDateTime.now().plusHours(2).toInstant(offset)))
- .sign(Algorithm.HMAC256("secret"));
-
- when(request.getHeader("Authorization")).thenReturn(token);
-
- synFilter.doFilter(request, response, chain);
-
- verify(chain).doFilter(requestCaptor.capture(), responseCaptor.capture());
-
- assertEquals(username, requestCaptor.getValue().getUserPrincipal().getName());
-
- finalRoles.forEach(role -> assertTrue(requestCaptor.getValue().isUserInRole(role)));
-
- }
-
- @Test
- public void shouldPassAuthToken() throws Exception {
- final String defaultUser = "islandoraAdmin";
- final String token = "Bearer 1337";
-
- when(request.getHeader("Authorization"))
- .thenReturn(token);
-
- synFilter.doFilter(request, response, chain);
-
- verify(chain).doFilter(requestCaptor.capture(), responseCaptor.capture());
-
- assertEquals(defaultUser, requestCaptor.getValue().getUserPrincipal().getName());
- assertTrue(requestCaptor.getValue().isUserInRole("islandora"));
- }
-
- @Test
- public void shouldFailAuthBecauseOfTokenNotSet() throws Exception {
- when(request.getMethod()).thenReturn("GET");
- when(request.getServerName()).thenReturn("test.com");
-
- synFilter.doFilter(request, response, chain);
-
- verify(request).getHeader("Authorization");
- verify(response).sendError(SC_UNAUTHORIZED, SynFilter.UNAUTHORIZED_MSG);
- }
-
- @Test
- public void shouldFailAuthBecauseOfTokenInvalid1() throws Exception {
- when(request.getHeader("Authorization"))
- .thenReturn("garbage");
-
- synFilter.doFilter(request, response, chain);
-
- verify(request).getHeader("Authorization");
- verify(response).sendError(SC_UNAUTHORIZED, SynFilter.UNAUTHORIZED_MSG);
- }
-
- @Test
- public void shouldFailAuthBecauseOfTokenInvalid2() throws Exception {
- when(request.getHeader("Authorization"))
- .thenReturn("killer bandit foo");
-
- synFilter.doFilter(request, response, chain);
-
- verify(request).getHeader("Authorization");
- verify(response).sendError(SC_UNAUTHORIZED, SynFilter.UNAUTHORIZED_MSG);
- }
-
- @Test
- public void shouldFailTokenMissingUid() throws Exception {
- final String host = "http://test.com";
- final String username = "adminuser";
- final String[] roles = new String[] { "role1", "role2", "role3" };
- final ArrayList finalRoles = new ArrayList(Arrays.asList(roles));
- finalRoles.add("islandora");
- finalRoles.add(host);
-
- final String token = JWT
- .create()
- .withClaim("sub", username)
- .withClaim("iss", host)
- .withArrayClaim("roles", roles)
- .withIssuedAt(Date.from(LocalDateTime.now().toInstant(offset)))
- .withExpiresAt(Date.from(LocalDateTime.now().plusHours(2).toInstant(offset)))
- .sign(Algorithm.HMAC256("secret"));
-
- when(request.getHeader("Authorization"))
- .thenReturn("Bearer " + token);
-
- synFilter.doFilter(request, response, chain);
-
- verify(request).getHeader("Authorization");
- verify(response).sendError(SC_UNAUTHORIZED, SynFilter.UNAUTHORIZED_MSG);
- }
-
- @Test
- public void shouldPassAuthDefaultSite() throws Exception {
- final String host = "http://test2.com";
- final String username = "normalUser";
- final List finalRoles = Arrays.asList("islandora", host);
-
- final String token = JWT
- .create()
- .withClaim("webid", 1)
- .withClaim("sub", username)
- .withClaim("iss", host)
- .withArrayClaim("roles", new String[] {})
- .withIssuedAt(Date.from(LocalDateTime.now().toInstant(offset)))
- .withExpiresAt(Date.from(LocalDateTime.now().plusHours(2).toInstant(offset)))
- .sign(Algorithm.HMAC256("secret2"));
-
- when(request.getHeader("Authorization"))
- .thenReturn("Bearer " + token);
-
- synFilter.doFilter(request, response, chain);
- verify(chain).doFilter(requestCaptor.capture(), responseCaptor.capture());
-
- verify(request).getHeader("Authorization");
- assertEquals(username, requestCaptor.getValue().getUserPrincipal().getName());
-
- finalRoles.forEach(role -> assertTrue(requestCaptor.getValue().isUserInRole(role)));
- }
-
- @Test
- public void shouldFailAuthBecauseNoSiteMatch() throws Exception {
- final String host = "http://test-no-match.com";
- final String username = "normalUser";
- final String token = JWT
- .create()
- .withClaim("webid", 1)
- .withClaim("sub", username)
- .withClaim("iss", host)
- .withArrayClaim("roles", new String[] {})
- .withIssuedAt(Date.from(LocalDateTime.now().toInstant(offset)))
- .withExpiresAt(Date.from(LocalDateTime.now().plusHours(2).toInstant(offset)))
- .sign(Algorithm.HMAC256("secret"));
-
- when(request.getHeader("Authorization"))
- .thenReturn("Bearer " + token);
-
- final String testYaml = String.join("\n",
- "---",
- "version: 1",
- "site:",
- " url: http://test.com",
- " algorithm: HS256",
- " encoding: plain",
- " anonymous: false",
- " key: secret");
- Files.write(Paths.get(this.settings.getAbsolutePath()), testYaml.getBytes());
-
- // Recreate because the settings file has changed so we need to run init again.
- synFilter = createFilter();
- synFilter.doFilter(request, response, chain);
-
- verify(request).getHeader("Authorization");
- verify(response).sendError(SC_UNAUTHORIZED, SynFilter.UNAUTHORIZED_MSG);
- }
-
- @Test
- public void allowAuthWithToken() throws Exception {
- final String host = "http://anon-test.com";
- final String username = "Bob";
- final List finalRoles = Arrays.asList("islandora", host);
- final String token = JWT
- .create()
- .withClaim("webid", 1)
- .withClaim("sub", username)
- .withClaim("iss", host)
- .withArrayClaim("roles", new String[] {})
- .withIssuedAt(Date.from(LocalDateTime.now().toInstant(offset)))
- .withExpiresAt(Date.from(LocalDateTime.now().plusHours(2).toInstant(offset)))
- .sign(Algorithm.HMAC256("secretFool"));
-
- when(request.getHeader("Authorization"))
- .thenReturn("Bearer " + token);
-
- final String testYaml = String.join("\n",
- "---",
- "version: 1",
- "site:",
- " url: " + host,
- " algorithm: HS256",
- " encoding: plain",
- " anonymous: false",
- " key: secretFool");
- Files.write(Paths.get(this.settings.getAbsolutePath()), testYaml.getBytes());
-
- synFilter = createFilter();
-
- synFilter.doFilter(request, response, chain);
- verify(chain).doFilter(requestCaptor.capture(), responseCaptor.capture());
-
- assertEquals(username, requestCaptor.getValue().getUserPrincipal().getName());
- verify(request).getHeader("Authorization");
-
- finalRoles.forEach(role -> assertTrue(requestCaptor.getValue().isUserInRole(role)));
- }
-
- @Test
- public void allowGetWithoutToken() throws Exception {
- final String servername = "anon-test.com";
- final String host = "http://" + servername;
- final String username = "anonymous";
- final List finalRoles = Arrays.asList("islandora", "anonymous", host);
-
- when(request.getMethod()).thenReturn("GET");
- when(request.getServerName()).thenReturn(servername);
-
- final String testYaml = String.join("\n",
- "---",
- "version: 1",
- "site:",
- " url: " + host,
- " algorithm: HS256",
- " encoding: plain",
- " anonymous: true",
- " key: secretFool");
- Files.write(Paths.get(this.settings.getAbsolutePath()), testYaml.getBytes());
-
- synFilter = createFilter();
- synFilter.doFilter(request, response, chain);
-
- verify(chain).doFilter(requestCaptor.capture(), responseCaptor.capture());
-
- assertEquals(username, requestCaptor.getValue().getUserPrincipal().getName());
- finalRoles.forEach(role -> assertTrue(requestCaptor.getValue().isUserInRole(role)));
- }
-
- @Test
- public void allowHeadWithoutToken() throws Exception {
- final String servername = "anon-test.com";
- final String host = "http://" + servername;
- final String username = "anonymous";
- final List finalRoles = Arrays.asList("islandora", "anonymous", host);
-
- when(request.getMethod()).thenReturn("HEAD");
- when(request.getServerName()).thenReturn(servername);
-
- final String testYaml = String.join("\n",
- "---",
- "version: 1",
- "site:",
- " url: " + host,
- " algorithm: HS256",
- " encoding: plain",
- " anonymous: true",
- " key: secretFool");
- Files.write(Paths.get(this.settings.getAbsolutePath()), testYaml.getBytes());
-
- synFilter = createFilter();
- synFilter.doFilter(request, response, chain);
-
- verify(chain).doFilter(requestCaptor.capture(), responseCaptor.capture());
-
- assertEquals(username, requestCaptor.getValue().getUserPrincipal().getName());
- finalRoles.forEach(role -> assertTrue(requestCaptor.getValue().isUserInRole(role)));
- }
-
- @Test
- public void disallowGetWithoutToken() throws Exception {
- final String servername = "anon-test.com";
- final String nohost = "http://other-site.com";
-
- when(request.getMethod()).thenReturn("GET");
- when(request.getServerName()).thenReturn(servername);
-
- final String testYaml = String.join("\n",
- "---",
- "version: 1",
- "site:",
- " url: " + nohost,
- " algorithm: HS256",
- " encoding: plain",
- " key: secretFool");
- Files.write(Paths.get(this.settings.getAbsolutePath()), testYaml.getBytes());
-
- synFilter = createFilter();
- synFilter.doFilter(request, response, chain);
-
- verify(request).getHeader("Authorization");
- verify(response).sendError(SC_UNAUTHORIZED, SynFilter.UNAUTHORIZED_MSG);
- }
-
- @Test
- public void overrideDefaultAllow() throws Exception {
- final String servername = "anon-test.com";
- final String host = "http://" + servername;
- final String username = "normalUser123";
- final List finalRoles = Arrays.asList("islandora", host);
- final String token = JWT
- .create()
- .withClaim("webid", 1)
- .withClaim("sub", username)
- .withClaim("iss", host)
- .withArrayClaim("roles", new String[] {})
- .withIssuedAt(Date.from(LocalDateTime.now().toInstant(offset)))
- .withExpiresAt(Date.from(LocalDateTime.now().plusHours(2).toInstant(offset)))
- .sign(Algorithm.HMAC256("secretFool"));
-
- when(request.getHeader("Authorization"))
- .thenReturn("Bearer " + token);
-
- final String testYaml = String.join("\n",
- "---",
- "version: 1",
- "site:",
- " url: " + host,
- " algorithm: HS256",
- " encoding: plain",
- " anonymous: false",
- " key: secretFool",
- "site:",
- " algorithm: RS256",
- " encoding: plain",
- " anonymous: true",
- " default: true");
- Files.write(Paths.get(this.settings.getAbsolutePath()), testYaml.getBytes());
-
- synFilter = createFilter();
- synFilter.doFilter(request, response, chain);
-
- verify(chain).doFilter(requestCaptor.capture(), responseCaptor.capture());
-
- assertEquals(username, requestCaptor.getValue().getUserPrincipal().getName());
- finalRoles.forEach(role -> assertTrue(requestCaptor.getValue().isUserInRole(role)));
- }
-
- @Test
- public void overrideDefaultAllowAndFail() throws Exception {
- final String servername = "anon-test.com";
- final String host = "http://" + servername;
- final String username = "normalUser123";
- final String token = JWT
- .create()
- .withClaim("webid", 1)
- .withClaim("sub", username)
- .withClaim("iss", host)
- .withArrayClaim("roles", new String[] {})
- .withIssuedAt(Date.from(LocalDateTime.now().toInstant(offset)))
- .withExpiresAt(Date.from(LocalDateTime.now().plusHours(2).toInstant(offset)))
- .sign(Algorithm.HMAC256("whatIsIt"));
-
- when(request.getHeader("Authorization"))
- .thenReturn("Bearer " + token);
-
- final String testYaml = String.join("\n",
- "---",
- "version: 1",
- "site:",
- " url: " + host,
- " algorithm: HS256",
- " encoding: plain",
- " anonymous: false",
- " key: secretFool",
- "site:",
- " algorithm: RS256",
- " encoding: plain",
- " anonymous: true",
- " default: true");
- Files.write(Paths.get(this.settings.getAbsolutePath()), testYaml.getBytes());
-
- synFilter = createFilter();
- synFilter.doFilter(request, response, chain);
-
- verify(request).getHeader("Authorization");
- verify(response).sendError(SC_FORBIDDEN, SynFilter.FORBIDDEN_MSG);
- }
-
- @Test
- public void overrideDefaultDeny() throws Exception {
- final String servername = "anon-test.com";
- final String host = "http://" + servername;
- final String username = "anonymous";
- final List finalRoles = Arrays.asList("islandora", "anonymous", host);
-
- when(request.getMethod()).thenReturn("GET");
- when(request.getServerName()).thenReturn(servername);
-
- final String testYaml = String.join("\n",
- "---",
- "version: 1",
- "site:",
- " url: " + host,
- " algorithm: HS256",
- " encoding: plain",
- " anonymous: true",
- " key: secretFool",
- "site:",
- " algorithm: RS256",
- " encoding: plain",
- " anonymous: false",
- " default: true");
- Files.write(Paths.get(this.settings.getAbsolutePath()), testYaml.getBytes());
-
- synFilter = createFilter();
- synFilter.doFilter(request, response, chain);
-
- verify(chain).doFilter(requestCaptor.capture(), responseCaptor.capture());
-
- assertEquals(username, requestCaptor.getValue().getUserPrincipal().getName());
- finalRoles.forEach(role -> assertTrue(requestCaptor.getValue().isUserInRole(role)));
- }
-
- @Test
- public void defaultAndSiteAllowed() throws Exception {
- final String servername = "anon-test.com";
- final String host = "http://" + servername;
- final String username = "anonymous";
- final List finalRoles = Arrays.asList("islandora", "anonymous", host);
-
- when(request.getMethod()).thenReturn("GET");
- when(request.getServerName()).thenReturn(servername);
-
- final String testYaml = String.join("\n",
- "---",
- "version: 1",
- "site:",
- " algorithm: RS256",
- " encoding: plain",
- " anonymous: true",
- " default: true");
- Files.write(Paths.get(this.settings.getAbsolutePath()), testYaml.getBytes());
-
- synFilter = createFilter();
- synFilter.doFilter(request, response, chain);
-
- verify(chain).doFilter(requestCaptor.capture(), responseCaptor.capture());
-
- assertEquals(username, requestCaptor.getValue().getUserPrincipal().getName());
- finalRoles.forEach(role -> assertTrue(requestCaptor.getValue().isUserInRole(role)));
- }
-
- @Test
- public void shouldFailSignatureVerification() throws Exception {
- final String host = "http://test.com";
- final String token = JWT
- .create()
- .withClaim("webid", 1)
- .withClaim("sub", "normalUser")
- .withClaim("iss", host)
- .withArrayClaim("roles", new String[] {})
- .withIssuedAt(Date.from(LocalDateTime.now().toInstant(offset)))
- .withExpiresAt(Date.from(LocalDateTime.now().plusHours(2).toInstant(offset)))
- .sign(Algorithm.HMAC256("secret"));
-
- when(request.getHeader("Authorization"))
- .thenReturn("Bearer " + token + "s");
-
- final String testYaml = String.join("\n",
- "---",
- "version: 1",
- "site:",
- " url: " + host,
- " algorithm: HS256",
- " encoding: plain");
- Files.write(Paths.get(this.settings.getAbsolutePath()), testYaml.getBytes());
-
- synFilter = createFilter();
- synFilter.doFilter(request, response, chain);
-
- verify(request).getHeader("Authorization");
- verify(response).sendError(SC_UNAUTHORIZED, SynFilter.UNAUTHORIZED_MSG);
- }
-
- private void createSettings(final File settingsFile) throws Exception {
- final String testYaml = String.join("\n",
- "---",
- "version: 1",
- "site:",
- " url: http://test.com",
- " algorithm: HS256",
- " encoding: plain",
- " key: secret",
- "site:",
- " algorithm: HS256",
- " encoding: plain",
- " default: true",
- " key: secret2",
- "token:",
- " value: 1337");
- Files.write(Paths.get(settingsFile.getAbsolutePath()), testYaml.getBytes());
- }
-
-}
diff --git a/src/test/java/ca/islandora/syn/valves/SynValveTest.java b/src/test/java/ca/islandora/syn/valves/SynValveTest.java
new file mode 100644
index 0000000..c94d5f4
--- /dev/null
+++ b/src/test/java/ca/islandora/syn/valves/SynValveTest.java
@@ -0,0 +1,643 @@
+package ca.islandora.syn.valves;
+
+import static junit.framework.TestCase.assertEquals;
+import static junit.framework.TestCase.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+
+import org.apache.catalina.Container;
+import org.apache.catalina.Context;
+import org.apache.catalina.Host;
+import org.apache.catalina.Realm;
+import org.apache.catalina.Valve;
+import org.apache.catalina.connector.Request;
+import org.apache.catalina.connector.Response;
+import org.apache.catalina.realm.GenericPrincipal;
+import org.apache.tomcat.util.descriptor.web.SecurityConstraint;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import com.auth0.jwt.JWT;
+import com.auth0.jwt.algorithms.Algorithm;
+
+import ca.islandora.syn.valve.SynValve;
+
+@RunWith(MockitoJUnitRunner.class)
+public class SynValveTest {
+ private SynValve synValve;
+ private File settings;
+
+ @Mock
+ private Container container;
+
+ @Mock
+ private Realm realm;
+
+ @Mock
+ private Context context;
+
+ @Mock
+ private Request request;
+
+ @Mock
+ private Response response;
+
+ @Mock
+ private Valve nextValve;
+
+ @Rule
+ public TemporaryFolder temporaryFolder = new TemporaryFolder();
+
+ @Mock
+ private Host mockHost;
+
+ private static ZoneOffset offset;
+
+ @Before
+ public void setUp() throws Exception {
+ settings = temporaryFolder.newFile();
+ createSettings(settings);
+
+ synValve = new SynValve();
+ synValve.setPathname(settings.getAbsolutePath());
+ synValve.setContainer(container);
+ synValve.setNext(nextValve);
+
+ when(container.getRealm()).thenReturn(realm);
+ when(request.getContext()).thenReturn(context);
+ when(request.getMethod()).thenReturn("POST");
+ offset = ZoneId.systemDefault().getRules().getOffset(Instant.now());
+ }
+
+ @Test
+ public void shouldInvokeNextValveWithoutAuth() throws Exception {
+ when(realm.findSecurityConstraints(request, request.getContext()))
+ .thenReturn(null);
+
+ synValve.start();
+ synValve.invoke(request, response);
+
+ verify(nextValve).invoke(request, response);
+ }
+
+ @Test
+ public void shouldPassAuth() throws Exception {
+ final ArgumentCaptor argument = ArgumentCaptor.forClass(GenericPrincipal.class);
+ final String host = "http://test.com";
+
+ final String token = "Bearer " + JWT
+ .create()
+ .withClaim("uid", 1)
+ .withClaim("name", "adminuser")
+ .withClaim("url", host)
+ .withArrayClaim("roles", new String[] {"role1", "role2", "role3"})
+ .withIssuedAt(Date.from(LocalDateTime.now().toInstant(offset)))
+ .withExpiresAt(Date.from(LocalDateTime.now().plusHours(2).toInstant(offset)))
+ .sign(Algorithm.HMAC256("secret"));
+
+ final SecurityConstraint securityConstraint = new SecurityConstraint();
+ securityConstraint.setAuthConstraint(true);
+ when(realm.findSecurityConstraints(request, request.getContext()))
+ .thenReturn(new SecurityConstraint[] { securityConstraint });
+ when(request.getHeader("Authorization"))
+ .thenReturn(token);
+
+ synValve.start();
+ synValve.invoke(request, response);
+
+ final InOrder inOrder = inOrder(request, nextValve);
+ inOrder.verify(request).getHeader("Authorization");
+ inOrder.verify(request).setUserPrincipal(argument.capture());
+ inOrder.verify(request).setAuthType("SYN");
+ inOrder.verify(nextValve).invoke(request, response);
+
+ assertEquals("adminuser", argument.getValue().getName());
+ final List roles = Arrays.asList(argument.getValue().getRoles());
+ assertEquals(5, roles.size());
+ assertTrue(roles.contains("role1"));
+ assertTrue(roles.contains("role2"));
+ assertTrue(roles.contains("role3"));
+ assertTrue(roles.contains("islandora"));
+ assertTrue(roles.contains("http://test.com"));
+ assertNull(argument.getValue().getPassword());
+ }
+
+ @Test
+ public void shouldPassAuthToken() throws Exception {
+ final ArgumentCaptor argument = ArgumentCaptor.forClass(GenericPrincipal.class);
+ final String token = "Bearer 1337";
+ final SecurityConstraint securityConstraint = new SecurityConstraint();
+ securityConstraint.setAuthConstraint(true);
+ when(realm.findSecurityConstraints(request, request.getContext()))
+ .thenReturn(new SecurityConstraint[] { securityConstraint });
+ when(request.getHeader("Authorization"))
+ .thenReturn(token);
+
+ synValve.start();
+ synValve.invoke(request, response);
+
+ final InOrder inOrder = inOrder(request, nextValve);
+ inOrder.verify(request).getHeader("Authorization");
+ inOrder.verify(request).setUserPrincipal(argument.capture());
+ inOrder.verify(request).setAuthType("SYN");
+ inOrder.verify(nextValve).invoke(request, response);
+
+ assertEquals("islandoraAdmin", argument.getValue().getName());
+ final List roles = Arrays.asList(argument.getValue().getRoles());
+ assertEquals(1, roles.size());
+ assertTrue(roles.contains("islandora"));
+ assertNull(argument.getValue().getPassword());
+ }
+
+ @Test
+ public void shouldFailAuthBecauseOfTokenNotSet() throws Exception {
+ final SecurityConstraint securityConstraint = new SecurityConstraint();
+ securityConstraint.setAuthConstraint(true);
+ when(realm.findSecurityConstraints(request, request.getContext()))
+ .thenReturn(new SecurityConstraint[] { securityConstraint });
+
+ synValve.start();
+ synValve.invoke(request, response);
+
+ verify(request).getHeader("Authorization");
+ verify(response).sendError(401, "Token authentication failed.");
+ }
+
+ @Test
+ public void shouldFailAuthBecauseOfTokenInvalid1() throws Exception {
+ final SecurityConstraint securityConstraint = new SecurityConstraint();
+ securityConstraint.setAuthConstraint(true);
+ when(realm.findSecurityConstraints(request, request.getContext()))
+ .thenReturn(new SecurityConstraint[] { securityConstraint });
+ when(request.getHeader("Authorization"))
+ .thenReturn("garbage");
+
+ synValve.start();
+ synValve.invoke(request, response);
+
+ verify(request).getHeader("Authorization");
+ verify(response).sendError(401, "Token authentication failed.");
+ }
+
+ @Test
+ public void shouldFailAuthBecauseOfTokenInvalid2() throws Exception {
+ final SecurityConstraint securityConstraint = new SecurityConstraint();
+ securityConstraint.setAuthConstraint(true);
+ when(realm.findSecurityConstraints(request, request.getContext()))
+ .thenReturn(new SecurityConstraint[] { securityConstraint });
+ when(request.getHeader("Authorization"))
+ .thenReturn("killer bandit foo");
+
+ synValve.start();
+ synValve.invoke(request, response);
+
+ verify(request).getHeader("Authorization");
+ verify(response).sendError(401, "Token authentication failed.");
+ }
+
+ @Test
+ public void shouldFailTokenMissingUid() throws Exception {
+ final String host = "http://test.com";
+ final String token = JWT
+ .create()
+ .withClaim("name", "adminuser")
+ .withClaim("url", host)
+ .withArrayClaim("roles", new String[] {"role1", "role2", "role3"})
+ .withIssuedAt(Date.from(LocalDateTime.now().toInstant(offset)))
+ .withExpiresAt(Date.from(LocalDateTime.now().plusHours(2).toInstant(offset)))
+ .sign(Algorithm.HMAC256("secret"));
+
+ final SecurityConstraint securityConstraint = new SecurityConstraint();
+ securityConstraint.setAuthConstraint(true);
+ when(realm.findSecurityConstraints(request, request.getContext()))
+ .thenReturn(new SecurityConstraint[] { securityConstraint });
+ when(request.getHeader("Authorization"))
+ .thenReturn("Bearer " + token);
+
+ synValve.start();
+ synValve.invoke(request, response);
+
+ verify(request).getHeader("Authorization");
+ verify(response).sendError(401, "Token authentication failed.");
+ }
+
+ @Test
+ public void shouldPassAuthDefaultSite() throws Exception {
+ final String host = "http://test2.com";
+ final String token = JWT
+ .create()
+ .withClaim("uid", 1)
+ .withClaim("name", "normalUser")
+ .withClaim("url", host)
+ .withArrayClaim("roles", new String[] {})
+ .withIssuedAt(Date.from(LocalDateTime.now().toInstant(offset)))
+ .withExpiresAt(Date.from(LocalDateTime.now().plusHours(2).toInstant(offset)))
+ .sign(Algorithm.HMAC256("secret2"));
+
+ final ArgumentCaptor argument = ArgumentCaptor.forClass(GenericPrincipal.class);
+
+ final SecurityConstraint securityConstraint = new SecurityConstraint();
+ securityConstraint.setAuthConstraint(true);
+ when(realm.findSecurityConstraints(request, request.getContext()))
+ .thenReturn(new SecurityConstraint[] { securityConstraint });
+ when(request.getHeader("Authorization"))
+ .thenReturn("Bearer " + token);
+
+ synValve.start();
+ synValve.invoke(request, response);
+
+ final InOrder inOrder = inOrder(request, nextValve);
+ inOrder.verify(request).getHeader("Authorization");
+ inOrder.verify(request).setUserPrincipal(argument.capture());
+ inOrder.verify(request).setAuthType("SYN");
+ inOrder.verify(nextValve).invoke(request, response);
+
+ assertEquals("normalUser", argument.getValue().getName());
+ final List roles = Arrays.asList(argument.getValue().getRoles());
+ assertEquals(2, roles.size());
+ assertTrue(roles.contains("islandora"));
+ assertTrue(roles.contains("http://test2.com"));
+ assertNull(argument.getValue().getPassword());
+ }
+
+ @Test
+ public void shouldFailAuthBecauseNoSiteMatch() throws Exception {
+ final String host = "http://test-no-match.com";
+ final String token = JWT
+ .create()
+ .withClaim("uid", 1)
+ .withClaim("name", "normalUser")
+ .withClaim("url", host)
+ .withArrayClaim("roles", new String[] {})
+ .withIssuedAt(Date.from(LocalDateTime.now().toInstant(offset)))
+ .withExpiresAt(Date.from(LocalDateTime.now().plusHours(2).toInstant(offset)))
+ .sign(Algorithm.HMAC256("secret"));
+
+ final SecurityConstraint securityConstraint = new SecurityConstraint();
+ securityConstraint.setAuthConstraint(true);
+ when(realm.findSecurityConstraints(request, request.getContext()))
+ .thenReturn(new SecurityConstraint[] { securityConstraint });
+ when(request.getHeader("Authorization"))
+ .thenReturn("Bearer " + token);
+
+ final String testXml = String.join("\n"
+ , ""
+ , " "
+ , "secret"
+ , " "
+ , ""
+ );
+ Files.write(Paths.get(this.settings.getAbsolutePath()), testXml.getBytes());
+
+ synValve.start();
+ synValve.invoke(request, response);
+
+ verify(request).getHeader("Authorization");
+ verify(response).sendError(401, "Token authentication failed.");
+ }
+
+ @Test
+ public void allowAuthWithToken() throws Exception {
+ final String host = "http://anon-test.com";
+ final String token = JWT
+ .create()
+ .withClaim("uid", 1)
+ .withClaim("name", "normalUser")
+ .withClaim("url", host)
+ .withArrayClaim("roles", new String[] {})
+ .withIssuedAt(Date.from(LocalDateTime.now().toInstant(offset)))
+ .withExpiresAt(Date.from(LocalDateTime.now().plusHours(2).toInstant(offset)))
+ .sign(Algorithm.HMAC256("secretFool"));
+
+ final SecurityConstraint securityConstraint = new SecurityConstraint();
+ securityConstraint.setAuthConstraint(true);
+ when(realm.findSecurityConstraints(request, request.getContext()))
+ .thenReturn(new SecurityConstraint[] { securityConstraint });
+ when(request.getHeader("Authorization"))
+ .thenReturn("Bearer " + token);
+
+ final ArgumentCaptor argument = ArgumentCaptor.forClass(GenericPrincipal.class);
+
+ final String testXml = String.join("\n"
+ , ""
+ , " "
+ , "secretFool"
+ , " "
+ , ""
+ );
+ Files.write(Paths.get(this.settings.getAbsolutePath()), testXml.getBytes());
+
+ synValve.start();
+ synValve.invoke(request, response);
+
+ final InOrder inOrder = inOrder(request, nextValve);
+ inOrder.verify(request).getHeader("Authorization");
+ inOrder.verify(request).setUserPrincipal(argument.capture());
+ inOrder.verify(request).setAuthType("SYN");
+ inOrder.verify(nextValve).invoke(request, response);
+
+ assertEquals("normalUser", argument.getValue().getName());
+ final List roles = Arrays.asList(argument.getValue().getRoles());
+ assertEquals(2, roles.size());
+ assertTrue(roles.contains("islandora"));
+ assertTrue(roles.contains(host));
+ assertNull(argument.getValue().getPassword());
+ }
+
+ @Test
+ public void allowGetWithoutToken() throws Exception {
+ final String host = "http://anon-test.com";
+ final SecurityConstraint securityConstraint = new SecurityConstraint();
+ securityConstraint.setAuthConstraint(true);
+ when(realm.findSecurityConstraints(request, request.getContext()))
+ .thenReturn(new SecurityConstraint[] { securityConstraint });
+ when(request.getMethod()).thenReturn("GET");
+ when(mockHost.toString()).thenReturn(host);
+ when(request.getHost()).thenReturn(mockHost);
+
+ final ArgumentCaptor argument = ArgumentCaptor.forClass(GenericPrincipal.class);
+
+ final String testXml = String.join("\n"
+ , ""
+ , " "
+ , "secretFool"
+ , " "
+ , ""
+ );
+ Files.write(Paths.get(this.settings.getAbsolutePath()), testXml.getBytes());
+
+ synValve.start();
+ synValve.invoke(request, response);
+
+ final InOrder inOrder = inOrder(request, nextValve);
+ inOrder.verify(request).setUserPrincipal(argument.capture());
+ inOrder.verify(nextValve).invoke(request, response);
+
+ assertEquals("anonymous", argument.getValue().getName());
+ final List roles = Arrays.asList(argument.getValue().getRoles());
+ assertEquals(2, roles.size());
+ assertTrue(roles.contains("anonymous"));
+ assertTrue(roles.contains("islandora"));
+ assertNull(argument.getValue().getPassword());
+ }
+
+ @Test
+ public void allowHeadWithoutToken() throws Exception {
+ final String host = "http://anon-test.com";
+ final SecurityConstraint securityConstraint = new SecurityConstraint();
+ securityConstraint.setAuthConstraint(true);
+ when(realm.findSecurityConstraints(request, request.getContext()))
+ .thenReturn(new SecurityConstraint[] { securityConstraint });
+ when(request.getMethod()).thenReturn("HEAD");
+ when(mockHost.toString()).thenReturn(host);
+ when(request.getHost()).thenReturn(mockHost);
+
+ final ArgumentCaptor argument = ArgumentCaptor.forClass(GenericPrincipal.class);
+
+ final String testXml = String.join("\n"
+ , ""
+ , " "
+ , "secretFool"
+ , " "
+ , ""
+ );
+ Files.write(Paths.get(this.settings.getAbsolutePath()), testXml.getBytes());
+
+ synValve.start();
+ synValve.invoke(request, response);
+
+ final InOrder inOrder = inOrder(request, nextValve);
+ inOrder.verify(request).setUserPrincipal(argument.capture());
+ inOrder.verify(nextValve).invoke(request, response);
+
+ assertEquals("anonymous", argument.getValue().getName());
+ final List roles = Arrays.asList(argument.getValue().getRoles());
+ assertEquals(2, roles.size());
+ assertTrue(roles.contains("anonymous"));
+ assertTrue(roles.contains("islandora"));
+ assertNull(argument.getValue().getPassword());
+ }
+
+ @Test
+ public void disallowGetWithoutToken() throws Exception {
+ final String host = "http://anon-test.com";
+ final String nohost = "http://other-site.com";
+ final SecurityConstraint securityConstraint = new SecurityConstraint();
+ securityConstraint.setAuthConstraint(true);
+ when(realm.findSecurityConstraints(request, request.getContext()))
+ .thenReturn(new SecurityConstraint[] { securityConstraint });
+ when(request.getMethod()).thenReturn("GET");
+ when(mockHost.toString()).thenReturn(host);
+ when(request.getHost()).thenReturn(mockHost);
+
+ final String testXml = String.join("\n"
+ , ""
+ , " "
+ , "secretFool"
+ , " "
+ , ""
+ );
+ Files.write(Paths.get(this.settings.getAbsolutePath()), testXml.getBytes());
+
+ synValve.start();
+ synValve.invoke(request, response);
+
+ verify(request).getHeader("Authorization");
+ verify(response).sendError(401, "Token authentication failed.");
+ }
+
+ @Test
+ public void overrideDefaultAllow() throws Exception {
+ final String host = "http://anon-test.com";
+ final String token = JWT
+ .create()
+ .withClaim("uid", 1)
+ .withClaim("name", "normalUser")
+ .withClaim("url", host)
+ .withArrayClaim("roles", new String[] {})
+ .withIssuedAt(Date.from(LocalDateTime.now().toInstant(offset)))
+ .withExpiresAt(Date.from(LocalDateTime.now().plusHours(2).toInstant(offset)))
+ .sign(Algorithm.HMAC256("secretFool"));
+ final SecurityConstraint securityConstraint = new SecurityConstraint();
+ securityConstraint.setAuthConstraint(true);
+ when(realm.findSecurityConstraints(request, request.getContext()))
+ .thenReturn(new SecurityConstraint[] { securityConstraint });
+ when(request.getHeader("Authorization"))
+ .thenReturn("Bearer " + token);
+ when(request.getMethod()).thenReturn("GET");
+ when(mockHost.toString()).thenReturn(host);
+ when(request.getHost()).thenReturn(mockHost);
+
+ final ArgumentCaptor argument = ArgumentCaptor.forClass(GenericPrincipal.class);
+
+ final String testXml = String.join("\n"
+ , ""
+ , " "
+ , "secretFool"
+ , " "
+ , " "
+ , ""
+ );
+ Files.write(Paths.get(this.settings.getAbsolutePath()), testXml.getBytes());
+
+ synValve.start();
+ synValve.invoke(request, response);
+
+ final InOrder inOrder = inOrder(request, nextValve);
+ inOrder.verify(request).setUserPrincipal(argument.capture());
+ inOrder.verify(nextValve).invoke(request, response);
+
+ assertEquals("normalUser", argument.getValue().getName());
+ final List roles = Arrays.asList(argument.getValue().getRoles());
+ assertEquals(2, roles.size());
+ assertTrue(roles.contains("islandora"));
+ assertTrue(roles.contains(host));
+ assertNull(argument.getValue().getPassword());
+ }
+
+ @Test
+ public void overrideDefaultDeny() throws Exception {
+ final String host = "http://anon-test.com";
+ final SecurityConstraint securityConstraint = new SecurityConstraint();
+ securityConstraint.setAuthConstraint(true);
+ when(realm.findSecurityConstraints(request, request.getContext()))
+ .thenReturn(new SecurityConstraint[] { securityConstraint });
+ when(request.getMethod()).thenReturn("GET");
+ when(mockHost.toString()).thenReturn(host);
+ when(request.getHost()).thenReturn(mockHost);
+
+ final ArgumentCaptor argument = ArgumentCaptor.forClass(GenericPrincipal.class);
+
+ final String testXml = String.join("\n"
+ , ""
+ , " "
+ , "secretFool"
+ , " "
+ , " "
+ , ""
+ );
+ Files.write(Paths.get(this.settings.getAbsolutePath()), testXml.getBytes());
+
+ synValve.start();
+ synValve.invoke(request, response);
+
+ final InOrder inOrder = inOrder(request, nextValve);
+ inOrder.verify(request).setUserPrincipal(argument.capture());
+ inOrder.verify(nextValve).invoke(request, response);
+
+ assertEquals("anonymous", argument.getValue().getName());
+ final List roles = Arrays.asList(argument.getValue().getRoles());
+ assertEquals(2, roles.size());
+ assertTrue(roles.contains("anonymous"));
+ assertTrue(roles.contains("islandora"));
+ assertNull(argument.getValue().getPassword());
+ }
+
+ @Test
+ public void defaultAndSiteAllowed() throws Exception {
+ final String host = "http://anon-test.com";
+ final SecurityConstraint securityConstraint = new SecurityConstraint();
+ securityConstraint.setAuthConstraint(true);
+ when(realm.findSecurityConstraints(request, request.getContext()))
+ .thenReturn(new SecurityConstraint[] { securityConstraint });
+ when(request.getMethod()).thenReturn("GET");
+ when(mockHost.toString()).thenReturn(host);
+ when(request.getHost()).thenReturn(mockHost);
+
+ final ArgumentCaptor argument = ArgumentCaptor.forClass(GenericPrincipal.class);
+
+ final String testXml = String.join("\n"
+ , ""
+ , " "
+ , ""
+ );
+ Files.write(Paths.get(this.settings.getAbsolutePath()), testXml.getBytes());
+
+ synValve.start();
+ synValve.invoke(request, response);
+
+ final InOrder inOrder = inOrder(request, nextValve);
+ inOrder.verify(request).setUserPrincipal(argument.capture());
+ inOrder.verify(nextValve).invoke(request, response);
+
+ assertEquals("anonymous", argument.getValue().getName());
+ final List roles = Arrays.asList(argument.getValue().getRoles());
+ assertEquals(2, roles.size());
+ assertTrue(roles.contains("anonymous"));
+ assertTrue(roles.contains("islandora"));
+ assertNull(argument.getValue().getPassword());
+ }
+
+ @Test
+ public void shouldFailSignatureVerification() throws Exception {
+ final String host = "http://test.com";
+ final String token = JWT
+ .create()
+ .withClaim("uid", 1)
+ .withClaim("name", "normalUser")
+ .withClaim("url", host)
+ .withArrayClaim("roles", new String[] {})
+ .withIssuedAt(Date.from(LocalDateTime.now().toInstant(offset)))
+ .withExpiresAt(Date.from(LocalDateTime.now().plusHours(2).toInstant(offset)))
+ .sign(Algorithm.HMAC256("secret"));
+
+ final SecurityConstraint securityConstraint = new SecurityConstraint();
+ securityConstraint.setAuthConstraint(true);
+ when(realm.findSecurityConstraints(request, request.getContext()))
+ .thenReturn(new SecurityConstraint[] { securityConstraint });
+ when(request.getHeader("Authorization"))
+ .thenReturn("Bearer " + token + "s");
+
+ final String testXml = String.join("\n"
+ , ""
+ , " "
+ , "secret"
+ , " "
+ , ""
+ );
+ Files.write(Paths.get(this.settings.getAbsolutePath()), testXml.getBytes());
+
+ synValve.start();
+ synValve.invoke(request, response);
+
+ verify(request).getHeader("Authorization");
+ verify(response).sendError(401, "Token authentication failed.");
+ }
+
+ private void createSettings(final File settingsFile) throws Exception {
+ final String testXml = String.join("\n"
+ , ""
+ , " "
+ , "secret"
+ , " "
+ , " "
+ , "secret2"
+ , " "
+ , " "
+ , "1337"
+ , " "
+ , ""
+ );
+ Files.write(Paths.get(settingsFile.getAbsolutePath()), testXml.getBytes());
+ }
+}
diff --git a/src/test/resources/exampleSettings.yaml b/src/test/resources/exampleSettings.yaml
deleted file mode 100644
index f014962..0000000
--- a/src/test/resources/exampleSettings.yaml
+++ /dev/null
@@ -1,4 +0,0 @@
-version: 1
-token:
- user: bob
- value: bobsPassword
\ No newline at end of file