Skip to content

Commit

Permalink
Merge pull request #55 from myndocs/release/0.5.0
Browse files Browse the repository at this point in the history
Release/0.5.0
  • Loading branch information
adhesivee committed Feb 12, 2019
2 parents 6ad42ac + 7c84ca7 commit 3f39a51
Show file tree
Hide file tree
Showing 41 changed files with 195 additions and 127 deletions.
24 changes: 12 additions & 12 deletions Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,20 @@ pipeline {
agent any

tools {
maven 'mvn-3.5.4'
jdk 'jdk-8'
maven 'mvn-3.6.0'
jdk 'jdk-8'
}

stages {
stage('Cleanup') {
steps {
sh 'mvn clean'
}
}
stage('Test') {
steps {
sh 'mvn test'
}
}
stage('Cleanup') {
steps {
sh 'mvn clean'
}
}
stage('Test') {
steps {
sh 'mvn test'
}
}
}
}
39 changes: 37 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ It encourages to adapt to existing implementations instead the other way around.
First define the version to be used and set it as a property
```xml
<properties>
<myndocs.oauth.version>0.3.1</myndocs.oauth.version>
<myndocs.oauth.version>0.5.0</myndocs.oauth.version>
</properties>
```

Expand Down Expand Up @@ -132,13 +132,48 @@ By default `UUIDAccessTokenConverter` is used. With a default time-out of 1 hour
```kotlin
accessTokenConverter = UUIDAccessTokenConverter(1800)
```

To use JWT include the following dependency:
```xml
<dependency>
<groupId>nl.myndocs</groupId>
<artifactId>oauth2-server-jwt</artifactId>
<version>${myndocs.oauth.version}</version>
</dependency>
```
This uses [auth0 jwt](https://github.com/auth0/java-jwt). To configure:
```kotlin
accessTokenConverter = JwtAccessTokenConverter(
algorithm = Algorithm.HMAC256("test123"), // mandatory
accessTokenExpireInSeconds = 1800, // optional default 3600
jwtBuilder = DefaultJwtBuilder // optional uses DefaultJwtBuilder by default
)
```

#### Refresh token converter
By default `UUIDRefreshTokenConverter` is used. With a default time-out of 1 hour. To override the time-out for example to half an hour:
```kotlin
refreshTokenConverter = UUIDRefreshTokenConverter(1800)
```

To use JWT include the following dependency:
```xml
<dependency>
<groupId>nl.myndocs</groupId>
<artifactId>oauth2-server-jwt</artifactId>
<version>${myndocs.oauth.version}</version>
</dependency>
```
This uses [auth0 jwt](https://github.com/auth0/java-jwt). To configure:
```kotlin
refreshTokenConverter = JwtRefreshTokenConverter(
algorithm = Algorithm.HMAC256("test123"), // mandatory
refreshTokenExpireInSeconds = 1800, // optional default 86400
jwtBuilder = DefaultJwtBuilder // optional uses DefaultJwtBuilder by default
)
```
#### Code token converter
By default `UUIDCodeTokenConverter` is used. With a default time-out of 5 minutes. To override the time-out for example 2 minutes:
```kotlin
codeTokenConverter = UUIDCodeTokenConverter(120)
```
```
2 changes: 1 addition & 1 deletion oauth2-server-client-inmemory/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<artifactId>kotlin-oauth2-server</artifactId>
<groupId>nl.myndocs</groupId>
<version>0.4.0</version>
<version>0.5.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>

Expand Down
2 changes: 1 addition & 1 deletion oauth2-server-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<artifactId>kotlin-oauth2-server</artifactId>
<groupId>nl.myndocs</groupId>
<version>0.4.0</version>
<version>0.5.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import nl.myndocs.oauth2.identity.IdentityService
import nl.myndocs.oauth2.identity.TokenInfo
import nl.myndocs.oauth2.request.CallContext
import nl.myndocs.oauth2.request.auth.BasicAuthorizer
import nl.myndocs.oauth2.response.AccessTokenResponder
import nl.myndocs.oauth2.response.DefaultAccessTokenResponder
import nl.myndocs.oauth2.token.TokenStore
import nl.myndocs.oauth2.token.converter.*

Expand Down Expand Up @@ -53,6 +55,7 @@ object ConfigurationBuilder {
var accessTokenConverter: AccessTokenConverter = UUIDAccessTokenConverter()
var refreshTokenConverter: RefreshTokenConverter = UUIDRefreshTokenConverter()
var codeTokenConverter: CodeTokenConverter = UUIDCodeTokenConverter()
var accessTokenResponder: AccessTokenResponder = DefaultAccessTokenResponder
}

fun build(configurer: Configuration.() -> Unit): nl.myndocs.oauth2.config.Configuration {
Expand All @@ -70,6 +73,7 @@ object ConfigurationBuilder {
configuration.refreshTokenConverter,
configuration.codeTokenConverter
)
override val accessTokenResponder = configuration.accessTokenResponder
}
}
return nl.myndocs.oauth2.config.Configuration(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,16 @@ import nl.myndocs.oauth2.exception.*
import nl.myndocs.oauth2.request.AuthorizationCodeRequest
import nl.myndocs.oauth2.request.ClientCredentialsRequest
import nl.myndocs.oauth2.request.PasswordGrantRequest
import nl.myndocs.oauth2.response.TokenResponse
import nl.myndocs.oauth2.scope.ScopeParser
import nl.myndocs.oauth2.token.AccessToken


/**
* @throws InvalidIdentityException
* @throws InvalidClientException
* @throws InvalidScopeException
*/
fun GrantingCall.authorize(passwordGrantRequest: PasswordGrantRequest): TokenResponse {
fun GrantingCall.authorize(passwordGrantRequest: PasswordGrantRequest): AccessToken {
throwExceptionIfUnverifiedClient(passwordGrantRequest)

if (passwordGrantRequest.username == null) {
Expand Down Expand Up @@ -50,22 +50,22 @@ fun GrantingCall.authorize(passwordGrantRequest: PasswordGrantRequest): TokenRes
validateScopes(requestedClient, requestedIdentity, requestedScopes)

val accessToken = converters.accessTokenConverter.convertToToken(
requestedIdentity.username,
requestedIdentity,
requestedClient.clientId,
requestedScopes,
converters.refreshTokenConverter.convertToToken(
requestedIdentity.username,
requestedIdentity,
requestedClient.clientId,
requestedScopes
)
)

tokenStore.storeAccessToken(accessToken)

return accessToken.toTokenResponse()
return accessToken
}

fun GrantingCall.authorize(authorizationCodeRequest: AuthorizationCodeRequest): TokenResponse {
fun GrantingCall.authorize(authorizationCodeRequest: AuthorizationCodeRequest): AccessToken {
throwExceptionIfUnverifiedClient(authorizationCodeRequest)

if (authorizationCodeRequest.code == null) {
Expand All @@ -85,22 +85,22 @@ fun GrantingCall.authorize(authorizationCodeRequest: AuthorizationCodeRequest):
}

val accessToken = converters.accessTokenConverter.convertToToken(
consumeCodeToken.username,
consumeCodeToken.identity,
consumeCodeToken.clientId,
consumeCodeToken.scopes,
converters.refreshTokenConverter.convertToToken(
consumeCodeToken.username,
consumeCodeToken.identity,
consumeCodeToken.clientId,
consumeCodeToken.scopes
)
)

tokenStore.storeAccessToken(accessToken)

return accessToken.toTokenResponse()
return accessToken
}

fun GrantingCall.authorize(clientCredentialsRequest: ClientCredentialsRequest): TokenResponse {
fun GrantingCall.authorize(clientCredentialsRequest: ClientCredentialsRequest): AccessToken {
throwExceptionIfUnverifiedClient(clientCredentialsRequest)

val requestedClient = clientService.clientOf(clientCredentialsRequest.clientId!!) ?: throw InvalidClientException()
Expand All @@ -110,17 +110,17 @@ fun GrantingCall.authorize(clientCredentialsRequest: ClientCredentialsRequest):
?: requestedClient.clientScopes

val accessToken = converters.accessTokenConverter.convertToToken(
username = null,
identity = null,
clientId = clientCredentialsRequest.clientId,
requestedScopes = scopes,
refreshToken = converters.refreshTokenConverter.convertToToken(
username = null,
identity = null,
clientId = clientCredentialsRequest.clientId,
requestedScopes = scopes
)
)

tokenStore.storeAccessToken(accessToken)

return accessToken.toTokenResponse()
return accessToken
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,9 @@ import nl.myndocs.oauth2.exception.InvalidScopeException
import nl.myndocs.oauth2.identity.Identity
import nl.myndocs.oauth2.identity.TokenInfo
import nl.myndocs.oauth2.request.*
import nl.myndocs.oauth2.response.TokenResponse
import nl.myndocs.oauth2.token.AccessToken
import nl.myndocs.oauth2.token.toMap

fun GrantingCall.grantPassword() = granter("password") {
val tokenResponse = authorize(
val accessToken = authorize(
PasswordGrantRequest(
callContext.formParameters["client_id"],
callContext.formParameters["client_secret"],
Expand All @@ -24,17 +21,17 @@ fun GrantingCall.grantPassword() = granter("password") {
)
)

callContext.respondJson(tokenResponse.toMap())
callContext.respondJson(accessTokenResponder.createResponse(accessToken))
}

fun GrantingCall.grantClientCredentials() = granter("client_credentials") {
val tokenResponse = authorize(ClientCredentialsRequest(
val accessToken = authorize(ClientCredentialsRequest(
callContext.formParameters["client_id"],
callContext.formParameters["client_secret"],
callContext.formParameters["scope"]
))

callContext.respondJson(tokenResponse.toMap())
callContext.respondJson(accessTokenResponder.createResponse(accessToken))
}

fun GrantingCall.grantRefreshToken() = granter("refresh_token") {
Expand All @@ -46,7 +43,7 @@ fun GrantingCall.grantRefreshToken() = granter("refresh_token") {
)
)

callContext.respondJson(accessToken.toMap())
callContext.respondJson(accessTokenResponder.createResponse(accessToken))
}

fun GrantingCall.grantAuthorizationCode() = granter("authorization_code") {
Expand All @@ -59,7 +56,7 @@ fun GrantingCall.grantAuthorizationCode() = granter("authorization_code") {
)
)

callContext.respondJson(accessToken.toMap())
callContext.respondJson(accessTokenResponder.createResponse(accessToken))
}

internal val INVALID_REQUEST_FIELD_MESSAGE = "'%s' field is missing"
Expand All @@ -86,7 +83,7 @@ fun GrantingCall.validateScopes(
fun GrantingCall.tokenInfo(accessToken: String): TokenInfo {
val storedAccessToken = tokenStore.accessToken(accessToken) ?: throw InvalidGrantException()
val client = clientService.clientOf(storedAccessToken.clientId) ?: throw InvalidClientException()
val identity = storedAccessToken.username?.let { identityService.identityOf(client, it) }
val identity = storedAccessToken.identity?.let { identityService.identityOf(client, it.username) }

return TokenInfo(
identity,
Expand All @@ -111,11 +108,4 @@ fun GrantingCall.throwExceptionIfUnverifiedClient(clientRequest: ClientRequest)

fun GrantingCall.scopesAllowed(clientScopes: Set<String>, requestedScopes: Set<String>): Boolean {
return clientScopes.containsAll(requestedScopes)
}

fun AccessToken.toTokenResponse() = TokenResponse(
accessToken,
tokenType,
expiresIn(),
refreshToken?.refreshToken
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ fun GrantingCall.redirect(
validateScopes(clientOf, identityOf, requestedScopes, identityScopeVerifier)

val codeToken = converters.codeTokenConverter.convertToToken(
identityOf.username,
identityOf,
clientOf.clientId,
redirect.redirectUri,
requestedScopes
Expand Down Expand Up @@ -123,7 +123,7 @@ fun GrantingCall.redirect(
validateScopes(clientOf, identityOf, requestedScopes, identityScopeVerifier)

val accessToken = converters.accessTokenConverter.convertToToken(
identityOf.username,
identityOf,
clientOf.clientId,
requestedScopes,
null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import nl.myndocs.oauth2.exception.InvalidClientException
import nl.myndocs.oauth2.exception.InvalidGrantException
import nl.myndocs.oauth2.exception.InvalidRequestException
import nl.myndocs.oauth2.request.RefreshTokenRequest
import nl.myndocs.oauth2.response.TokenResponse
import nl.myndocs.oauth2.token.AccessToken


fun GrantingCall.refresh(refreshTokenRequest: RefreshTokenRequest): TokenResponse {
fun GrantingCall.refresh(refreshTokenRequest: RefreshTokenRequest): AccessToken {
throwExceptionIfUnverifiedClient(refreshTokenRequest)

if (refreshTokenRequest.refreshToken == null) {
Expand All @@ -29,13 +29,13 @@ fun GrantingCall.refresh(refreshTokenRequest: RefreshTokenRequest): TokenRespons
}

val accessToken = converters.accessTokenConverter.convertToToken(
refreshToken.username,
refreshToken.identity,
refreshToken.clientId,
refreshToken.scopes,
converters.refreshTokenConverter.convertToToken(refreshToken)
)

tokenStore.storeAccessToken(accessToken)

return accessToken.toTokenResponse()
return accessToken
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package nl.myndocs.oauth2.grant
import nl.myndocs.oauth2.client.ClientService
import nl.myndocs.oauth2.identity.IdentityService
import nl.myndocs.oauth2.request.CallContext
import nl.myndocs.oauth2.response.AccessTokenResponder
import nl.myndocs.oauth2.token.TokenStore
import nl.myndocs.oauth2.token.converter.Converters

Expand All @@ -12,4 +13,5 @@ interface GrantingCall {
val clientService: ClientService
val tokenStore: TokenStore
val converters: Converters
val accessTokenResponder: AccessTokenResponder
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package nl.myndocs.oauth2.identity

data class Identity(
val username: String
val username: String,
val metadata: Map<String, Any> = mapOf()
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package nl.myndocs.oauth2.response

import nl.myndocs.oauth2.token.AccessToken

interface AccessTokenResponder {
fun createResponse(accessToken: AccessToken): Map<String, Any?>
}
Loading

0 comments on commit 3f39a51

Please sign in to comment.