From b6b84bcad75a10e2777af8ae4df2d28e487b3470 Mon Sep 17 00:00:00 2001 From: Albert Date: Sun, 13 Jan 2019 22:20:22 +0100 Subject: [PATCH 1/2] JWT converter --- oauth2-server-jwt/pom.xml | 27 ++++++++++++ .../convert/JwtAccessTokenConverter.kt | 41 +++++++++++++++++++ .../convert/JwtRefreshTokenConverter.kt | 38 +++++++++++++++++ pom.xml | 1 + 4 files changed, 107 insertions(+) create mode 100644 oauth2-server-jwt/pom.xml create mode 100644 oauth2-server-jwt/src/main/java/nl/myndocs/convert/JwtAccessTokenConverter.kt create mode 100644 oauth2-server-jwt/src/main/java/nl/myndocs/convert/JwtRefreshTokenConverter.kt diff --git a/oauth2-server-jwt/pom.xml b/oauth2-server-jwt/pom.xml new file mode 100644 index 0000000..9ccd3bd --- /dev/null +++ b/oauth2-server-jwt/pom.xml @@ -0,0 +1,27 @@ + + + + kotlin-oauth2-server + nl.myndocs + 0.3.2-SNAPSHOT + + 4.0.0 + + oauth2-server-jwt + + + + nl.myndocs + oauth2-server-core + ${project.version} + provided + + + com.auth0 + java-jwt + 3.5.0 + + + \ No newline at end of file diff --git a/oauth2-server-jwt/src/main/java/nl/myndocs/convert/JwtAccessTokenConverter.kt b/oauth2-server-jwt/src/main/java/nl/myndocs/convert/JwtAccessTokenConverter.kt new file mode 100644 index 0000000..fbf7825 --- /dev/null +++ b/oauth2-server-jwt/src/main/java/nl/myndocs/convert/JwtAccessTokenConverter.kt @@ -0,0 +1,41 @@ +package nl.myndocs.convert + +import com.auth0.jwt.JWT +import com.auth0.jwt.JWTCreator +import com.auth0.jwt.algorithms.Algorithm +import nl.myndocs.oauth2.token.AccessToken +import nl.myndocs.oauth2.token.RefreshToken +import nl.myndocs.oauth2.token.converter.AccessTokenConverter +import java.time.Instant +import java.util.* + +class JwtAccessTokenConverter( + private val algorithm: Algorithm, + private val accessTokenExpireInSeconds: Int = 3600, + private val jwtConfiguration: (JWTCreator.Builder) -> JWTCreator.Builder = { builder -> builder } +) : AccessTokenConverter { + override fun convertToToken(username: String?, clientId: String, requestedScopes: Set, refreshToken: RefreshToken?): AccessToken { + val jwtBuilder = JWT.create() + .withIssuedAt(Date.from(Instant.now())) + .withExpiresAt( + Date.from( + Instant.now() + .plusSeconds(accessTokenExpireInSeconds.toLong()) + ) + ) + .withClaim("client_id", clientId) + .withArrayClaim("scopes", requestedScopes.toTypedArray()) + .let { withBuilder -> if (username != null) withBuilder.withClaim("username", username) else withBuilder } + .let(jwtConfiguration) + + return AccessToken( + jwtBuilder.sign(algorithm), + "bearer", + Instant.now().plusSeconds(accessTokenExpireInSeconds.toLong()), + username, + clientId, + requestedScopes, + refreshToken + ) + } +} \ No newline at end of file diff --git a/oauth2-server-jwt/src/main/java/nl/myndocs/convert/JwtRefreshTokenConverter.kt b/oauth2-server-jwt/src/main/java/nl/myndocs/convert/JwtRefreshTokenConverter.kt new file mode 100644 index 0000000..de6c934 --- /dev/null +++ b/oauth2-server-jwt/src/main/java/nl/myndocs/convert/JwtRefreshTokenConverter.kt @@ -0,0 +1,38 @@ +package nl.myndocs.convert + +import com.auth0.jwt.JWT +import com.auth0.jwt.JWTCreator +import com.auth0.jwt.algorithms.Algorithm +import nl.myndocs.oauth2.token.RefreshToken +import nl.myndocs.oauth2.token.converter.RefreshTokenConverter +import java.time.Instant +import java.util.* + +class JwtRefreshTokenConverter( + private val algorithm: Algorithm, + private val refreshTokenExpireInSeconds: Int = 86400, + private val jwtConfiguration: (JWTCreator.Builder) -> JWTCreator.Builder = { builder -> builder } +) : RefreshTokenConverter { + override fun convertToToken(username: String?, clientId: String, requestedScopes: Set): RefreshToken { + val jwtBuilder = JWT.create() + .withIssuedAt(Date.from(Instant.now())) + .withExpiresAt( + Date.from( + Instant.now() + .plusSeconds(refreshTokenExpireInSeconds.toLong()) + ) + ) + .withClaim("client_id", clientId) + .withArrayClaim("scopes", requestedScopes.toTypedArray()) + .let { withBuilder -> if (username != null) withBuilder.withClaim("username", username) else withBuilder } + .let(jwtConfiguration) + + return RefreshToken( + jwtBuilder.sign(algorithm), + Instant.now().plusSeconds(refreshTokenExpireInSeconds.toLong()), + username, + clientId, + requestedScopes + ) + } +} \ No newline at end of file diff --git a/pom.xml b/pom.xml index d3bd6c0..61c237b 100644 --- a/pom.xml +++ b/pom.xml @@ -25,6 +25,7 @@ oauth2-server-javalin oauth2-server-sparkjava oauth2-server-http4k + oauth2-server-jwt From 8d069603546df644316cc1c408791d5a5e1b4b67 Mon Sep 17 00:00:00 2001 From: Albert Date: Mon, 14 Jan 2019 21:12:50 +0100 Subject: [PATCH 2/2] Use interface instead of callback to have more control --- .../nl/myndocs/convert/DefaultJwtBuilder.kt | 20 ++++++++++++++++ .../convert/JwtAccessTokenConverter.kt | 23 ++++++------------- .../java/nl/myndocs/convert/JwtBuilder.kt | 7 ++++++ .../convert/JwtRefreshTokenConverter.kt | 23 ++++++------------- 4 files changed, 41 insertions(+), 32 deletions(-) create mode 100644 oauth2-server-jwt/src/main/java/nl/myndocs/convert/DefaultJwtBuilder.kt create mode 100644 oauth2-server-jwt/src/main/java/nl/myndocs/convert/JwtBuilder.kt diff --git a/oauth2-server-jwt/src/main/java/nl/myndocs/convert/DefaultJwtBuilder.kt b/oauth2-server-jwt/src/main/java/nl/myndocs/convert/DefaultJwtBuilder.kt new file mode 100644 index 0000000..2b44c1e --- /dev/null +++ b/oauth2-server-jwt/src/main/java/nl/myndocs/convert/DefaultJwtBuilder.kt @@ -0,0 +1,20 @@ +package nl.myndocs.convert + +import com.auth0.jwt.JWT +import java.time.Instant +import java.util.* + +object DefaultJwtBuilder : JwtBuilder { + override fun buildJwt(username: String?, clientId: String, requestedScopes: Set, expiresInSeconds: Long) = + JWT.create() + .withIssuedAt(Date.from(Instant.now())) + .withExpiresAt( + Date.from( + Instant.now() + .plusSeconds(expiresInSeconds) + ) + ) + .withClaim("client_id", clientId) + .withArrayClaim("scopes", requestedScopes.toTypedArray()) + .let { withBuilder -> if (username != null) withBuilder.withClaim("username", username) else withBuilder } +} \ No newline at end of file diff --git a/oauth2-server-jwt/src/main/java/nl/myndocs/convert/JwtAccessTokenConverter.kt b/oauth2-server-jwt/src/main/java/nl/myndocs/convert/JwtAccessTokenConverter.kt index fbf7825..a794724 100644 --- a/oauth2-server-jwt/src/main/java/nl/myndocs/convert/JwtAccessTokenConverter.kt +++ b/oauth2-server-jwt/src/main/java/nl/myndocs/convert/JwtAccessTokenConverter.kt @@ -1,32 +1,23 @@ package nl.myndocs.convert -import com.auth0.jwt.JWT -import com.auth0.jwt.JWTCreator import com.auth0.jwt.algorithms.Algorithm import nl.myndocs.oauth2.token.AccessToken import nl.myndocs.oauth2.token.RefreshToken import nl.myndocs.oauth2.token.converter.AccessTokenConverter import java.time.Instant -import java.util.* class JwtAccessTokenConverter( private val algorithm: Algorithm, private val accessTokenExpireInSeconds: Int = 3600, - private val jwtConfiguration: (JWTCreator.Builder) -> JWTCreator.Builder = { builder -> builder } + private val jwtBuilder: JwtBuilder = DefaultJwtBuilder ) : AccessTokenConverter { override fun convertToToken(username: String?, clientId: String, requestedScopes: Set, refreshToken: RefreshToken?): AccessToken { - val jwtBuilder = JWT.create() - .withIssuedAt(Date.from(Instant.now())) - .withExpiresAt( - Date.from( - Instant.now() - .plusSeconds(accessTokenExpireInSeconds.toLong()) - ) - ) - .withClaim("client_id", clientId) - .withArrayClaim("scopes", requestedScopes.toTypedArray()) - .let { withBuilder -> if (username != null) withBuilder.withClaim("username", username) else withBuilder } - .let(jwtConfiguration) + val jwtBuilder = jwtBuilder.buildJwt( + username, + clientId, + requestedScopes, + accessTokenExpireInSeconds.toLong() + ) return AccessToken( jwtBuilder.sign(algorithm), diff --git a/oauth2-server-jwt/src/main/java/nl/myndocs/convert/JwtBuilder.kt b/oauth2-server-jwt/src/main/java/nl/myndocs/convert/JwtBuilder.kt new file mode 100644 index 0000000..800b09b --- /dev/null +++ b/oauth2-server-jwt/src/main/java/nl/myndocs/convert/JwtBuilder.kt @@ -0,0 +1,7 @@ +package nl.myndocs.convert + +import com.auth0.jwt.JWTCreator + +interface JwtBuilder { + fun buildJwt(username: String?, clientId: String, requestedScopes: Set, expiresInSeconds: Long): JWTCreator.Builder +} \ No newline at end of file diff --git a/oauth2-server-jwt/src/main/java/nl/myndocs/convert/JwtRefreshTokenConverter.kt b/oauth2-server-jwt/src/main/java/nl/myndocs/convert/JwtRefreshTokenConverter.kt index de6c934..e633fb8 100644 --- a/oauth2-server-jwt/src/main/java/nl/myndocs/convert/JwtRefreshTokenConverter.kt +++ b/oauth2-server-jwt/src/main/java/nl/myndocs/convert/JwtRefreshTokenConverter.kt @@ -1,31 +1,22 @@ package nl.myndocs.convert -import com.auth0.jwt.JWT -import com.auth0.jwt.JWTCreator import com.auth0.jwt.algorithms.Algorithm import nl.myndocs.oauth2.token.RefreshToken import nl.myndocs.oauth2.token.converter.RefreshTokenConverter import java.time.Instant -import java.util.* class JwtRefreshTokenConverter( private val algorithm: Algorithm, private val refreshTokenExpireInSeconds: Int = 86400, - private val jwtConfiguration: (JWTCreator.Builder) -> JWTCreator.Builder = { builder -> builder } + private val jwtBuilder: JwtBuilder = DefaultJwtBuilder ) : RefreshTokenConverter { override fun convertToToken(username: String?, clientId: String, requestedScopes: Set): RefreshToken { - val jwtBuilder = JWT.create() - .withIssuedAt(Date.from(Instant.now())) - .withExpiresAt( - Date.from( - Instant.now() - .plusSeconds(refreshTokenExpireInSeconds.toLong()) - ) - ) - .withClaim("client_id", clientId) - .withArrayClaim("scopes", requestedScopes.toTypedArray()) - .let { withBuilder -> if (username != null) withBuilder.withClaim("username", username) else withBuilder } - .let(jwtConfiguration) + val jwtBuilder = jwtBuilder.buildJwt( + username, + clientId, + requestedScopes, + refreshTokenExpireInSeconds.toLong() + ) return RefreshToken( jwtBuilder.sign(algorithm),