Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change Tomcat Valve to servlet Filter #11

Merged
merged 7 commits into from
Nov 21, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 20 additions & 35 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

## Description

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)).
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)).

## Building

Expand All @@ -15,54 +15,39 @@ 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. 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 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.

### Register Valve
Now register the valve in Tomcat configuration file.
In Ubuntu this file is located at: `/var/lib/tomcat8/conf/context.xml`
### Register Filter
Now register the filter in web applications' `web.xml` file by adding something like.

```xml
<Valve className="ca.islandora.syn.valve.SynValve"
pathname="conf/syn-settings.xml" />
<filter>
<filter-name>SynFilter</filter-name>
<filter-class>ca.islandora.syn.valve.SynFilter</filter-class>
<init-param>
<param-name>settings-path</param-name>
<param-value>/var/lib/tomcat8/conf/syn-settings.yml</param-value>
</init-param>
</filter>

<filter-mapping>
<filter-name>SynFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
```

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
<security-constraint>
<web-resource-collection>
<web-resource-name>Fedora4</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>*</role-name>
</auth-constraint>
<user-data-constraint>
<transport-guarantee>NONE</transport-guarantee>
</user-data-constraint>
</security-constraint>
<security-role>
<role-name>islandora</role-name>
</security-role>
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>fcrepo</realm-name>
</login-config>
```
Where the **settings-path** `param-value` is the the location of the settings file.

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.xml) and move it to: `$CATALINA_BASE/conf/syn-settings.xml`.
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.

## Maintainers

* [Jonathan Green](https://github.com/jonathangreen/)
* [Jared Whiklo](https://github.com/whikloj)

## Development

Expand Down
52 changes: 43 additions & 9 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,20 @@ 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')
Expand All @@ -24,15 +38,17 @@ repositories {
}

dependencies {
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
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
}

jacocoTestReport {
Expand All @@ -54,6 +70,13 @@ 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 {
Expand All @@ -62,3 +85,14 @@ 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'
}
}
36 changes: 0 additions & 36 deletions conf/syn-settings.example.xml

This file was deleted.

43 changes: 43 additions & 0 deletions conf/syn-settings.example.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
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
20 changes: 14 additions & 6 deletions src/main/java/ca/islandora/syn/settings/Config.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,37 @@
import java.util.ArrayList;
import java.util.List;

import com.fasterxml.jackson.annotation.JsonSetter;

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

@JsonSetter("site")
public void addSite(final Site site) {
sites.add(site);
this.sites.add(site);
}

public List<Site> getSites() {
return sites;
return this.sites;
}

public int getVersion() {
return this.version;
}

public void setVersion(final int version) {
this.version = version;
}

@JsonSetter("token")
public void addToken(final Token token) {
tokens.add(token);
this.tokens.add(token);
}

public List<Token> getTokens() {
return tokens;
return this.tokens;
}

}
Loading