Skip to content

Commit

Permalink
Alter Valve to send roles via Http header (#14)
Browse files Browse the repository at this point in the history
  • Loading branch information
whikloj authored and dannylamb committed Dec 18, 2018
1 parent c3fd5ac commit 81503ab
Show file tree
Hide file tree
Showing 12 changed files with 455 additions and 185 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ On ubuntu this file can be found at:
### Setup Syn Configuration
Modify the [example configuration](./conf/syn-settings.example.xml) and move it to: `$CATALINA_BASE/conf/syn-settings.xml`.

### Header principals
Additional roles are passed to Fedora via a HTTP header, this is configured via the `header` attribute to the `<config>` element in the syn-settings.xml.example file. You must also configure Fedora to read this header via its HeaderProvider.

## Maintainers

* [Jonathan Green](https://github.com/jonathangreen/)
Expand Down
2 changes: 1 addition & 1 deletion conf/syn-settings.example.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<config version='1'>
<config version='1' header="X-Islandora-Roles">
<!--
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.
Expand Down
13 changes: 11 additions & 2 deletions src/main/java/ca/islandora/syn/settings/Config.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@

public class Config {
private int version = -1;
private List<Site> sites = new ArrayList<>();
private List<Token> tokens = new ArrayList<>();
private String header = "";
private final List<Site> sites = new ArrayList<>();
private final List<Token> tokens = new ArrayList<>();

public void addSite(final Site site) {
sites.add(site);
Expand All @@ -28,4 +29,12 @@ public void addToken(final Token token) {
public List<Token> getTokens() {
return tokens;
}

public void setHeader(final String header) {
this.header = header;
}

public String getHeader() {
return this.header;
}
}
53 changes: 36 additions & 17 deletions src/main/java/ca/islandora/syn/settings/SettingsParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ private static Algorithm getRsaAlgorithm(final Site site) {
} else if (site.getPath() != null) {
try {
publicKeyReader = new FileReader(site.getPath());
} catch (FileNotFoundException e) {
} catch (final FileNotFoundException e) {
log.error("Private key file not found.");
}
}
Expand All @@ -112,7 +112,7 @@ private static Algorithm getRsaAlgorithm(final Site site) {
publicKey = (RSAPublicKey) factory.generatePublic(pubKeySpec);
pemReader.close();
publicKeyReader.close();
} catch (Exception e) {
} catch (final Exception e) {
log.error("Error loading public key.");
return null;
}
Expand All @@ -134,15 +134,15 @@ private static Algorithm getRsaAlgorithm(final Site site) {
}

private static Algorithm getHmacAlgorithm(final Site site) {
byte[] secret;
final byte[] secret;
byte[] secretRaw = null;

if (!site.getKey().equalsIgnoreCase("")) {
secretRaw = site.getKey().trim().getBytes();
} else if (site.getPath() != null) {
try {
secretRaw = Files.readAllBytes(Paths.get(site.getPath()));
} catch (IOException e) {
} catch (final IOException e) {
log.error("Unable to get secret from file.", e);
}
}
Expand All @@ -154,7 +154,7 @@ private static Algorithm getHmacAlgorithm(final Site site) {
if (site.getEncoding().equalsIgnoreCase("base64")) {
try {
secret = Base64.getDecoder().decode(secretRaw);
} catch (Exception e) {
} catch (final Exception e) {
log.error("Base64 decode error. Skipping site.", e);
return null;
}
Expand All @@ -175,12 +175,19 @@ private static Algorithm getHmacAlgorithm(final Site site) {
}
}

private static Config getSites(final InputStream settings) {
Config sites;
/**
* Parse a configuration file and return a Config object
*
* @param settings
* The configuration file stream
* @return the config object
*/
public static Config getSites(final InputStream settings) {
final Config sites;

try {
sites = getSitesObject(settings);
} catch (Exception e) {
} catch (final Exception e) {
log.error("Error loading settings file.", e);
return null;
}
Expand All @@ -193,16 +200,22 @@ private static Config getSites(final InputStream settings) {
return sites;
}

public static Map<String, Algorithm> getSiteAlgorithms(final InputStream settings) {
/**
* Get algorithms for sites
*
* @param sites
* configuration with sites
* @return map of site url (or null for default) and algorithm
*/
public static Map<String, Algorithm> getSiteAlgorithms(final Config sites) {
final Map<String, Algorithm> algorithms = new HashMap<>();
final Config sites = getSites(settings);
if (sites == null) {
return algorithms;
}

boolean defaultSet = false;

for (Site site : sites.getSites()) {
for (final Site site : sites.getSites()) {
final boolean pathDefined = site.getPath() != null && !site.getPath().equalsIgnoreCase("");
final boolean keyDefined = site.getKey() != null && !site.getKey().equalsIgnoreCase("");

Expand All @@ -220,7 +233,7 @@ public static Map<String, Algorithm> getSiteAlgorithms(final InputStream setting

// Check that the algorithm type is valid.
final AlgorithmType algorithmType = getSiteAlgorithmType(site.getAlgorithm());
Algorithm algorithm;
final Algorithm algorithm;
if (algorithmType == AlgorithmType.HMAC) {
algorithm = getHmacAlgorithm(site);
} else if (algorithmType == AlgorithmType.RSA) {
Expand Down Expand Up @@ -252,8 +265,14 @@ public static Map<String, Algorithm> getSiteAlgorithms(final InputStream setting
return algorithms;
}

public static Map<String, Token> getSiteStaticTokens(final InputStream settings) {
final Config sites = getSites(settings);
/**
* Get the site static tokens from a set of sites in the configuration
*
* @param sites
* the configured sites
* @return map of token string and token object
*/
public static Map<String, Token> getSiteStaticTokens(final Config sites) {
if (sites == null) {
return new HashMap<String, Token>();
}
Expand All @@ -267,11 +286,11 @@ public static Map<String, Token> getSiteStaticTokens(final InputStream settings)
/**
* Build a list of site urls that allow anonymous GET requests.
*
* @param settings the path to the syn-settings file
* @param sites
* a config object with the site information
* @return list of site urls.
*/
public static Map<String, Boolean> getSiteAllowAnonymous(final InputStream settings) {
final Config sites = getSites(settings);
public static Map<String, Boolean> getSiteAllowAnonymous(final Config sites) {
if (sites == null) {
return new HashMap<String, Boolean>();
}
Expand Down
39 changes: 17 additions & 22 deletions src/main/java/ca/islandora/syn/token/Verifier.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
package ca.islandora.syn.token;

import java.util.Arrays;
import java.util.List;
import java.util.Map;

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;

Expand All @@ -19,44 +24,34 @@ private Verifier() { }

public static Verifier create(final String token) {
final Verifier verifier = new Verifier();
final List<String> requiredClaims = Arrays.asList("sub", "iss", "webid", "roles", "exp", "iat");
verifier.token = token;
try {
verifier.jwt = JWT.decode(token);
if (verifier.jwt.getClaim("uid").isNull()) {
return null;
}
if (verifier.jwt.getClaim("url").isNull()) {
return null;
}
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;
final Map<String, Claim> claims = verifier.jwt.getClaims();
for (final String claim : requiredClaims) {
if (claims.get(claim) == null) {
log.debug(String.format("Token missing required claim ({})", claim));
return null;
}
}
} catch (JWTDecodeException exception) {
} catch (final JWTDecodeException exception) {
log.error("Error decoding token: " + token, exception);
return null;
}
return verifier;
}

public int getUid() {
return this.jwt.getClaim("uid").asInt();
return this.jwt.getClaim("webid").asInt();
}

public String getUrl() {
return this.jwt.getClaim("url").asString();
return this.jwt.getClaim("iss").asString();
}

public String getName() {
return this.jwt.getClaim("name").asString();
return this.jwt.getClaim("sub").asString();
}

public List<String> getRoles() {
Expand All @@ -67,7 +62,7 @@ public boolean verify(final Algorithm algorithm) {
final JWTVerifier verifier = JWT.require(algorithm).build();
try {
verifier.verify(this.token);
} catch (JWTVerificationException exception) {
} catch (final JWTVerificationException exception) {
return false;
}

Expand Down
Loading

0 comments on commit 81503ab

Please sign in to comment.