Skip to content

Commit

Permalink
Merge pull request #1 from RADAR-base/release-0.2.0
Browse files Browse the repository at this point in the history
Release 0.2.0
  • Loading branch information
blootsvoets authored Oct 7, 2019
2 parents 5e60979 + ed73c83 commit 3a4eb31
Show file tree
Hide file tree
Showing 58 changed files with 983 additions and 548 deletions.
79 changes: 50 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# radar-auth-jersey
# radar-jersey

Library to facilitate OAuth 2.0 integration with a Jersey-based REST API.
Library to facilitate using with a Jersey-based REST API. This includes OAuth 2.0 integration, exception handling and resource configuration.

# Usage

Expand All @@ -11,17 +11,18 @@ repositories {
}
dependencies {
api("org.radarbase:radar-auth-jersey:0.1.0")
api("org.radarbase:radar-jersey:0.2.0")
}
```

Any path or resource that should be authenticated against the ManagementPortal, should be annotated with `@Authenticated`. Specific authorization can be checked by adding a `@NeedsPermission` annotation. An `Auth` object can be injected to get app-specific information. Examples:
Any path or resource that should be authenticated against the ManagementPortal, should be annotated with `@Authenticated`. Specific authorization can be checked by adding a `@NeedsPermission` annotation. An `Auth` object can be injected to get app-specific information. For reliable injection, constructor or method injection, not class parameter injection. Examples:

```kotlin
@Path("/projects")
@Authenticated
class Users(@Context projectService: ProjectService) {

class Users(
@Context projectService: MyProjectService
) {
@GET
@NeedsPermission(PROJECT, READ)
fun getProjects(@Context auth: Auth): List<Project> {
Expand All @@ -45,34 +46,54 @@ class Users(@Context projectService: ProjectService) {
}
```

These APIs are activated by adding `JerseyResourceEnhancer` implementations to your resource definition:
These APIs are activated by adding an `EnhancerFactory` implementation to your resource definition:
```kotlin
val authConfig = AuthConfig(
managementPortalUrl = "http://...",
jwtResourceName = "res_MyResource")

val enhancers = listOf(
RadarJerseyResourceEnhancer(authConfig)
ManagementPortalResourceEnhancer())

val resourceConfig = ResourceConfig()
enhancers.forEach { resourceConfig.packages(*it.packages) }

resourceConfig.register(object : AbstractBinder() {
override fun configure() {
bind(MyProjectService::class.java)
.to(ProjectService::class.java)
.`in`(Singleton::class.java)

enhancers.forEach { it.enhance(this) }
class MyEnhancerFactory(private val config: MyConfigClass): EnhancerFactory {
override fun createEnhancers() = listOf(
// My own resource configuration
MyResourceEnhancer(),
// RADAR OAuth2 enhancement
RadarJerseyResourceEnhancer(AuthConfig(
managementPortalUrl = "http://...",
jwtResourceName = "res_MyResource")),
// Use ManagementPortal OAuth implementation
ManagementPortalResourceEnhancer(),
// HttpApplicationException handling
HttpExceptionResourceEnhancer(),
// General error handling (WebApplicationException and any other Exception)
GeneralExceptionResourceEnhancer())

class MyResourceEnhancer: JerseyResourceEnhancer {
override fun enhanceBinder(binder: AbstractBinder) {
binder.bind(config)
.to(MyConfigClass::class.java)

binder.bind(MyProjectService::class.java)
.to(ProjectService::class.java)
.`in`(Singleton::class.java)

binder.bind(MyProjectService::class.java)
.to(MyProjectService::class.java)
.`in`(Singleton::class.java)
}
}
})
}
```
Ensure that a class implementing `org.radarbase.jersey.auth.ProjectService` is added to the binder.

Ensure that a class implementing `org.radarbase.auth.jersey.ProjectService` is added to the binder.
This factory can then be specified in your main method, by adding it to your `MyConfigClass` definition:
```kotlin
fun main(args: Array<String>) {
val config: MyConfigClass = ConfigLoader.loadConfig("my-config-name.yml", args)
val resources = ConfigLoader.loadResources(config.resourceConfig, config)
val server = GrizzlyServer(config.baseUri, resources, config.isJmxEnabled)
// Listen until JVM shutdown
server.listen()
}
```

## Error handling

This package adds some error handling. Specifically, `org.radarbase.auth.jersey.exception.HttpApplicationException` can be used and extended to serve detailed error messages with customized logging and HTML templating. They can be thrown from any resource.
This package adds some error handling. Specifically, `org.radarbase.jersey.exception.HttpApplicationException` and its subclasses can be used and extended to serve detailed error messages with customized logging and HTML templating. They can be thrown from any resource.

To serve custom HTML error messages for error codes 400 to 599, add a Mustache template to the classpath in directory `org/radarbase/auth/jersey/exception/<code>.html`. You can use special cases `4xx.html` and `5xx.html` as a catch-all template. The templates can use variables `status` for the HTTP status code, `code` for short-hand code for the specific error, and an optional `detailedMessage` for a human-readable message.
To serve custom HTML error messages for error codes 400 to 599, add a Mustache template to the classpath in directory `org/radarbase/jersey/exception/mapper/<code>.html`. You can use special cases `4xx.html` and `5xx.html` as a catch-all template. The templates can use variables `status` for the HTTP status code, `code` for short-hand code for the specific error, and an optional `detailedMessage` for a human-readable message.
180 changes: 32 additions & 148 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
plugins {
id 'org.jetbrains.kotlin.jvm' version '1.3.41'
id 'com.jfrog.bintray' version '1.8.4'
id 'maven-publish'
id 'org.jetbrains.kotlin.jvm' version '1.3.50'
id 'com.jfrog.bintray' version '1.8.4' apply false
}

description = 'Library for authentication and authorization with the RADAR platform using Jersey'
description = 'Library for Jersey authorization, exception handling and configuration with the RADAR platform'
group = 'org.radarbase'
version = '0.1.0'
version = '0.2.0'

ext {
githubRepoName = 'RADAR-base/ManagementPortal'
githubUrl = 'https://github.com/RADAR-base/ManagementPortal'
githubRepoName = 'RADAR-base/radar-jersey'
githubUrl = "https://github.com/${githubRepoName}.git".toString()
issueUrl = "https://github.com/$githubRepoName/issues".toString()
website = 'http://radar-base.org'

Expand Down Expand Up @@ -40,25 +39,34 @@ dependencies {

api("com.fasterxml.jackson.core:jackson-databind:$jacksonVersion")

implementation("org.glassfish.jersey.containers:jersey-container-grizzly2-http:$jerseyVersion")
implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:$jacksonVersion")

// exception template rendering
implementation 'com.github.spullara.mustache.java:compiler:0.9.6'

implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
implementation "org.slf4j:slf4j-api:1.7.26"

testImplementation("org.junit.jupiter:junit-jupiter:5.5.2")
testImplementation 'org.hamcrest:hamcrest-all:1.3'
testImplementation("com.squareup.okhttp3:okhttp:$okhttpVersion")
implementation("org.glassfish.jersey.inject:jersey-hk2:$jerseyVersion")

testImplementation("org.glassfish.grizzly:grizzly-http-server:${grizzlyVersion}")
runtimeOnly("org.glassfish.jersey.media:jersey-media-json-jackson:$jerseyVersion")

testImplementation("org.glassfish.jersey.containers:jersey-container-grizzly2-http:${jerseyVersion}")
testImplementation("org.glassfish.jersey.containers:jersey-container-grizzly2-servlet:${jerseyVersion}")
testImplementation("org.glassfish.jersey.inject:jersey-hk2:${jerseyVersion}")
testRuntimeOnly("org.glassfish.jersey.media:jersey-media-json-jackson:${jerseyVersion}")
runtimeOnly("com.fasterxml.jackson.module:jackson-module-kotlin:$jacksonVersion")
runtimeOnly("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:$jacksonVersion")
runtimeOnly("com.fasterxml.jackson.datatype:jackson-datatype-jdk8:$jacksonVersion")

testRuntimeOnly 'javax.xml.bind:jaxb-api:2.2.11'
testRuntimeOnly 'com.sun.xml.bind:jaxb-core:2.2.11'
testRuntimeOnly 'com.sun.xml.bind:jaxb-impl:2.2.11'
testRuntimeOnly 'javax.activation:activation:1.1.1'
runtimeOnly 'javax.xml.bind:jaxb-api:2.2.11'
runtimeOnly 'com.sun.xml.bind:jaxb-core:2.2.11'
runtimeOnly 'com.sun.xml.bind:jaxb-impl:2.2.11'
runtimeOnly 'javax.activation:activation:1.1.1'

testRuntimeOnly("org.glassfish.grizzly:grizzly-http-server:$grizzlyVersion")
testRuntimeOnly("org.glassfish.jersey.containers:jersey-container-grizzly2-servlet:$jerseyVersion")

testImplementation("org.junit.jupiter:junit-jupiter:5.5.2")
testImplementation 'org.hamcrest:hamcrest-all:1.3'
testImplementation("com.squareup.okhttp3:okhttp:$okhttpVersion")

testRuntime 'org.slf4j:slf4j-simple:1.7.26'
}
Expand All @@ -67,141 +75,17 @@ tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
kotlinOptions.jvmTarget = "11"
}

repositories {
mavenCentral()
}

test {
useJUnitPlatform()
testLogging {
events "passed", "skipped", "failed"
exceptionFormat "full"
showStandardStreams = true
}
}

def sharedManifest = manifest {
attributes("Implementation-Title": project.name,
"Implementation-Version": version)
}

jar {
// archiveBaseName.set(project.name)
manifest.from sharedManifest
}

// custom tasks for creating source/javadoc jars
task sourcesJar(type: Jar, dependsOn: classes) {
archiveClassifier.set('sources')
from sourceSets.main.allSource
manifest.from sharedManifest
}

task javadocJar(type: Jar, dependsOn: javadoc) {
archiveClassifier.set('javadoc')
from javadoc.destinationDir
manifest.from sharedManifest
}

// add javadoc/source jar tasks as artifacts
artifacts {
archives sourcesJar, javadocJar
}

ext.nexusRepoBase = 'https://repo.thehyve.nl/content/repositories'

publishing {
publications {
mavenJar(MavenPublication) {
from components.java
artifact sourcesJar
artifact javadocJar

pom {
name = project.name
description = project.description
url = githubUrl
licenses {
license {
name = 'The Apache Software License, Version 2.0'
url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
distribution = 'repo'
}
}
developers {
developer {
id = 'dennyverbeeck'
name = 'Denny Verbeeck'
email = '[email protected]'
organization = 'Janssen R&D'
}
developer {
id = 'blootsvoets'
name = 'Joris Borgdorff'
email = '[email protected]'
organization = 'The Hyve'
}
developer {
id = 'nivemaham'
name = 'Nivethika Mahasivam'
email = '[email protected]'
organization = 'The Hyve'
}
}
issueManagement {
system = 'GitHub'
url = githubUrl + '/issues'
}
organization {
name = 'RADAR-base'
url = website
}
scm {
connection = 'scm:git:' + githubUrl
url = githubUrl
}
}

}
}
repositories {
maven {
def releasesRepoUrl = "$nexusRepoBase/releases"
def snapshotsRepoUrl = "$nexusRepoBase/snapshots"
url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl
credentials {
username = project.hasProperty('nexusUser') ? project.property('nexusUser') : System.getenv('NEXUS_USER')
password = project.hasProperty('nexusPassword') ? project.property('nexusPassword') : System.getenv('NEXUS_PASSWORD')
}
}
}
}

bintray {
user project.hasProperty('bintrayUser') ? project.property('bintrayUser') : System.getenv('BINTRAY_USER')
key project.hasProperty('bintrayApiKey') ? project.property('bintrayApiKey') : System.getenv('BINTRAY_API_KEY')
override false
publications 'mavenJar'
pkg {
repo = project.group
name = project.name
userOrg = 'radar-base'
desc = project.description
licenses = ['Apache-2.0']
websiteUrl = website
issueTrackerUrl = issueUrl
vcsUrl = githubUrl
githubRepo = githubRepoName
githubReleaseNotesFile = 'README.md'
version {
name = project.version
desc = project.description
vcsTag = System.getenv('TRAVIS_TAG')
released = new Date()
}
}
}

bintrayUpload.dependsOn 'assemble'

wrapper {
gradleVersion = "5.6.2"
}
}

apply from: "gradle/publishing.gradle"
Loading

0 comments on commit 3a4eb31

Please sign in to comment.