From d18078cfaecbd19ddc77201059114021205e354c Mon Sep 17 00:00:00 2001 From: Albert Date: Mon, 14 Jan 2019 21:50:24 +0100 Subject: [PATCH 1/7] new snapshot --- oauth2-server-client-inmemory/pom.xml | 2 +- oauth2-server-core/pom.xml | 2 +- oauth2-server-http4k/pom.xml | 2 +- oauth2-server-identity-inmemory/pom.xml | 2 +- oauth2-server-javalin/pom.xml | 2 +- oauth2-server-json/pom.xml | 2 +- oauth2-server-jwt/pom.xml | 2 +- oauth2-server-ktor/pom.xml | 2 +- oauth2-server-sparkjava/pom.xml | 2 +- oauth2-server-token-store-inmemory/pom.xml | 2 +- pom.xml | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/oauth2-server-client-inmemory/pom.xml b/oauth2-server-client-inmemory/pom.xml index 829a54c..19efe6b 100644 --- a/oauth2-server-client-inmemory/pom.xml +++ b/oauth2-server-client-inmemory/pom.xml @@ -5,7 +5,7 @@ kotlin-oauth2-server nl.myndocs - 0.4.0 + 0.4.1-SNAPSHOT 4.0.0 diff --git a/oauth2-server-core/pom.xml b/oauth2-server-core/pom.xml index fd69de6..d496972 100644 --- a/oauth2-server-core/pom.xml +++ b/oauth2-server-core/pom.xml @@ -5,7 +5,7 @@ kotlin-oauth2-server nl.myndocs - 0.4.0 + 0.4.1-SNAPSHOT 4.0.0 diff --git a/oauth2-server-http4k/pom.xml b/oauth2-server-http4k/pom.xml index 632dbf4..b86f46b 100644 --- a/oauth2-server-http4k/pom.xml +++ b/oauth2-server-http4k/pom.xml @@ -5,7 +5,7 @@ kotlin-oauth2-server nl.myndocs - 0.4.0 + 0.4.1-SNAPSHOT 4.0.0 diff --git a/oauth2-server-identity-inmemory/pom.xml b/oauth2-server-identity-inmemory/pom.xml index c77bcce..aa9bf36 100644 --- a/oauth2-server-identity-inmemory/pom.xml +++ b/oauth2-server-identity-inmemory/pom.xml @@ -5,7 +5,7 @@ kotlin-oauth2-server nl.myndocs - 0.4.0 + 0.4.1-SNAPSHOT 4.0.0 diff --git a/oauth2-server-javalin/pom.xml b/oauth2-server-javalin/pom.xml index 0461baa..8c431a3 100644 --- a/oauth2-server-javalin/pom.xml +++ b/oauth2-server-javalin/pom.xml @@ -5,7 +5,7 @@ kotlin-oauth2-server nl.myndocs - 0.4.0 + 0.4.1-SNAPSHOT 4.0.0 diff --git a/oauth2-server-json/pom.xml b/oauth2-server-json/pom.xml index 3364729..5c23812 100644 --- a/oauth2-server-json/pom.xml +++ b/oauth2-server-json/pom.xml @@ -5,7 +5,7 @@ kotlin-oauth2-server nl.myndocs - 0.4.0 + 0.4.1-SNAPSHOT 4.0.0 diff --git a/oauth2-server-jwt/pom.xml b/oauth2-server-jwt/pom.xml index e873dec..7880e28 100644 --- a/oauth2-server-jwt/pom.xml +++ b/oauth2-server-jwt/pom.xml @@ -5,7 +5,7 @@ kotlin-oauth2-server nl.myndocs - 0.4.0 + 0.4.1-SNAPSHOT 4.0.0 diff --git a/oauth2-server-ktor/pom.xml b/oauth2-server-ktor/pom.xml index 81ee9e2..2f0dd53 100644 --- a/oauth2-server-ktor/pom.xml +++ b/oauth2-server-ktor/pom.xml @@ -5,7 +5,7 @@ kotlin-oauth2-server nl.myndocs - 0.4.0 + 0.4.1-SNAPSHOT 4.0.0 diff --git a/oauth2-server-sparkjava/pom.xml b/oauth2-server-sparkjava/pom.xml index 67287b6..2f74228 100644 --- a/oauth2-server-sparkjava/pom.xml +++ b/oauth2-server-sparkjava/pom.xml @@ -5,7 +5,7 @@ kotlin-oauth2-server nl.myndocs - 0.4.0 + 0.4.1-SNAPSHOT 4.0.0 diff --git a/oauth2-server-token-store-inmemory/pom.xml b/oauth2-server-token-store-inmemory/pom.xml index 6b217a7..acb222d 100644 --- a/oauth2-server-token-store-inmemory/pom.xml +++ b/oauth2-server-token-store-inmemory/pom.xml @@ -5,7 +5,7 @@ kotlin-oauth2-server nl.myndocs - 0.4.0 + 0.4.1-SNAPSHOT 4.0.0 diff --git a/pom.xml b/pom.xml index 551cad7..addb6b4 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ nl.myndocs kotlin-oauth2-server pom - 0.4.0 + 0.4.1-SNAPSHOT 1.3.0 From 36a225bc6852667cc4e254da1b74e82f710f44c9 Mon Sep 17 00:00:00 2001 From: Albert Date: Mon, 14 Jan 2019 21:56:31 +0100 Subject: [PATCH 2/7] Add JWT documentation --- README.md | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/README.md b/README.md index 5b33392..8b2860b 100644 --- a/README.md +++ b/README.md @@ -132,11 +132,46 @@ 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 + + nl.myndocs + oauth2-server-jwt + ${myndocs.oauth.version} + +``` +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 + + nl.myndocs + oauth2-server-jwt + ${myndocs.oauth.version} + +``` +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 From 9dc558e34498ee892e9db3fd86afc89ef67d1459 Mon Sep 17 00:00:00 2001 From: Albert Date: Mon, 14 Jan 2019 21:57:38 +0100 Subject: [PATCH 3/7] Update documentation version --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8b2860b..910389f 100644 --- a/README.md +++ b/README.md @@ -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 - 0.3.1 + 0.4.0 ``` From a2098a573ea1488b74e2f92f40142566c59933ec Mon Sep 17 00:00:00 2001 From: "A. Bos" Date: Sun, 10 Feb 2019 06:44:27 +0100 Subject: [PATCH 4/7] Support metadata on identity (#53) * Support metadata on identity * Allow custom access token response implementation (#54) --- .../oauth2/config/ConfigurationBuilder.kt | 4 +++ .../oauth2/grant/CallRouterAuthorize.kt | 26 +++++++++---------- .../myndocs/oauth2/grant/CallRouterDefault.kt | 26 ++++++------------- .../oauth2/grant/CallRouterRedirect.kt | 4 +-- .../myndocs/oauth2/grant/CallRouterRefresh.kt | 8 +++--- .../nl/myndocs/oauth2/grant/GrantingCall.kt | 2 ++ .../nl/myndocs/oauth2/identity/Identity.kt | 3 ++- .../oauth2/response/AccessTokenResponder.kt | 7 +++++ .../response/DefaultAccessTokenResponder.kt | 15 +++++++++++ .../myndocs/oauth2/response/TokenResponse.kt | 8 ------ .../nl/myndocs/oauth2/token/AccessToken.kt | 3 ++- .../java/nl/myndocs/oauth2/token/CodeToken.kt | 3 ++- .../nl/myndocs/oauth2/token/RefreshToken.kt | 3 ++- .../myndocs/oauth2/token/TokenResponseUtil.kt | 10 ------- .../token/converter/AccessTokenConverter.kt | 3 ++- .../token/converter/CodeTokenConverter.kt | 3 ++- .../token/converter/RefreshTokenConverter.kt | 7 ++--- .../converter/UUIDAccessTokenConverter.kt | 5 ++-- .../token/converter/UUIDCodeTokenConverter.kt | 5 ++-- .../converter/UUIDRefreshTokenConverter.kt | 5 ++-- .../AuthorizationCodeGrantTokenServiceTest.kt | 25 +++++++++++------- .../ClientCredentialsTokenServiceTest.kt | 4 +++ .../oauth2/PasswordGrantTokenServiceTest.kt | 20 ++++++++------ .../RefreshTokenGrantTokenServiceTest.kt | 16 ++++++++---- .../nl/myndocs/convert/DefaultJwtBuilder.kt | 5 ++-- .../convert/JwtAccessTokenConverter.kt | 7 ++--- .../java/nl/myndocs/convert/JwtBuilder.kt | 3 ++- .../convert/JwtRefreshTokenConverter.kt | 7 ++--- 28 files changed, 135 insertions(+), 102 deletions(-) create mode 100644 oauth2-server-core/src/main/java/nl/myndocs/oauth2/response/AccessTokenResponder.kt create mode 100644 oauth2-server-core/src/main/java/nl/myndocs/oauth2/response/DefaultAccessTokenResponder.kt delete mode 100644 oauth2-server-core/src/main/java/nl/myndocs/oauth2/response/TokenResponse.kt delete mode 100644 oauth2-server-core/src/main/java/nl/myndocs/oauth2/token/TokenResponseUtil.kt diff --git a/oauth2-server-core/src/main/java/nl/myndocs/oauth2/config/ConfigurationBuilder.kt b/oauth2-server-core/src/main/java/nl/myndocs/oauth2/config/ConfigurationBuilder.kt index eee7012..b6d8abf 100644 --- a/oauth2-server-core/src/main/java/nl/myndocs/oauth2/config/ConfigurationBuilder.kt +++ b/oauth2-server-core/src/main/java/nl/myndocs/oauth2/config/ConfigurationBuilder.kt @@ -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.* @@ -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 { @@ -70,6 +73,7 @@ object ConfigurationBuilder { configuration.refreshTokenConverter, configuration.codeTokenConverter ) + override val accessTokenResponder = configuration.accessTokenResponder } } return nl.myndocs.oauth2.config.Configuration( diff --git a/oauth2-server-core/src/main/java/nl/myndocs/oauth2/grant/CallRouterAuthorize.kt b/oauth2-server-core/src/main/java/nl/myndocs/oauth2/grant/CallRouterAuthorize.kt index a3c873e..183a3e3 100644 --- a/oauth2-server-core/src/main/java/nl/myndocs/oauth2/grant/CallRouterAuthorize.kt +++ b/oauth2-server-core/src/main/java/nl/myndocs/oauth2/grant/CallRouterAuthorize.kt @@ -5,8 +5,8 @@ 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 /** @@ -14,7 +14,7 @@ import nl.myndocs.oauth2.scope.ScopeParser * @throws InvalidClientException * @throws InvalidScopeException */ -fun GrantingCall.authorize(passwordGrantRequest: PasswordGrantRequest): TokenResponse { +fun GrantingCall.authorize(passwordGrantRequest: PasswordGrantRequest): AccessToken { throwExceptionIfUnverifiedClient(passwordGrantRequest) if (passwordGrantRequest.username == null) { @@ -50,11 +50,11 @@ 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 ) @@ -62,10 +62,10 @@ fun GrantingCall.authorize(passwordGrantRequest: PasswordGrantRequest): TokenRes 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) { @@ -85,11 +85,11 @@ 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 ) @@ -97,10 +97,10 @@ fun GrantingCall.authorize(authorizationCodeRequest: AuthorizationCodeRequest): 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() @@ -110,11 +110,11 @@ 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 ) @@ -122,5 +122,5 @@ fun GrantingCall.authorize(clientCredentialsRequest: ClientCredentialsRequest): tokenStore.storeAccessToken(accessToken) - return accessToken.toTokenResponse() + return accessToken } diff --git a/oauth2-server-core/src/main/java/nl/myndocs/oauth2/grant/CallRouterDefault.kt b/oauth2-server-core/src/main/java/nl/myndocs/oauth2/grant/CallRouterDefault.kt index f2bbe5a..93028bc 100644 --- a/oauth2-server-core/src/main/java/nl/myndocs/oauth2/grant/CallRouterDefault.kt +++ b/oauth2-server-core/src/main/java/nl/myndocs/oauth2/grant/CallRouterDefault.kt @@ -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"], @@ -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") { @@ -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") { @@ -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" @@ -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, @@ -111,11 +108,4 @@ fun GrantingCall.throwExceptionIfUnverifiedClient(clientRequest: ClientRequest) fun GrantingCall.scopesAllowed(clientScopes: Set, requestedScopes: Set): Boolean { return clientScopes.containsAll(requestedScopes) -} - -fun AccessToken.toTokenResponse() = TokenResponse( - accessToken, - tokenType, - expiresIn(), - refreshToken?.refreshToken -) \ No newline at end of file +} \ No newline at end of file diff --git a/oauth2-server-core/src/main/java/nl/myndocs/oauth2/grant/CallRouterRedirect.kt b/oauth2-server-core/src/main/java/nl/myndocs/oauth2/grant/CallRouterRedirect.kt index e6f54f1..625b25f 100644 --- a/oauth2-server-core/src/main/java/nl/myndocs/oauth2/grant/CallRouterRedirect.kt +++ b/oauth2-server-core/src/main/java/nl/myndocs/oauth2/grant/CallRouterRedirect.kt @@ -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 @@ -123,7 +123,7 @@ fun GrantingCall.redirect( validateScopes(clientOf, identityOf, requestedScopes, identityScopeVerifier) val accessToken = converters.accessTokenConverter.convertToToken( - identityOf.username, + identityOf, clientOf.clientId, requestedScopes, null diff --git a/oauth2-server-core/src/main/java/nl/myndocs/oauth2/grant/CallRouterRefresh.kt b/oauth2-server-core/src/main/java/nl/myndocs/oauth2/grant/CallRouterRefresh.kt index 5c4c456..20a4f1d 100644 --- a/oauth2-server-core/src/main/java/nl/myndocs/oauth2/grant/CallRouterRefresh.kt +++ b/oauth2-server-core/src/main/java/nl/myndocs/oauth2/grant/CallRouterRefresh.kt @@ -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) { @@ -29,7 +29,7 @@ fun GrantingCall.refresh(refreshTokenRequest: RefreshTokenRequest): TokenRespons } val accessToken = converters.accessTokenConverter.convertToToken( - refreshToken.username, + refreshToken.identity, refreshToken.clientId, refreshToken.scopes, converters.refreshTokenConverter.convertToToken(refreshToken) @@ -37,5 +37,5 @@ fun GrantingCall.refresh(refreshTokenRequest: RefreshTokenRequest): TokenRespons tokenStore.storeAccessToken(accessToken) - return accessToken.toTokenResponse() + return accessToken } diff --git a/oauth2-server-core/src/main/java/nl/myndocs/oauth2/grant/GrantingCall.kt b/oauth2-server-core/src/main/java/nl/myndocs/oauth2/grant/GrantingCall.kt index b219253..3843a84 100644 --- a/oauth2-server-core/src/main/java/nl/myndocs/oauth2/grant/GrantingCall.kt +++ b/oauth2-server-core/src/main/java/nl/myndocs/oauth2/grant/GrantingCall.kt @@ -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 @@ -12,4 +13,5 @@ interface GrantingCall { val clientService: ClientService val tokenStore: TokenStore val converters: Converters + val accessTokenResponder: AccessTokenResponder } \ No newline at end of file diff --git a/oauth2-server-core/src/main/java/nl/myndocs/oauth2/identity/Identity.kt b/oauth2-server-core/src/main/java/nl/myndocs/oauth2/identity/Identity.kt index 8b5f1fd..8f7261d 100644 --- a/oauth2-server-core/src/main/java/nl/myndocs/oauth2/identity/Identity.kt +++ b/oauth2-server-core/src/main/java/nl/myndocs/oauth2/identity/Identity.kt @@ -1,5 +1,6 @@ package nl.myndocs.oauth2.identity data class Identity( - val username: String + val username: String, + val metadata: Map = mapOf() ) \ No newline at end of file diff --git a/oauth2-server-core/src/main/java/nl/myndocs/oauth2/response/AccessTokenResponder.kt b/oauth2-server-core/src/main/java/nl/myndocs/oauth2/response/AccessTokenResponder.kt new file mode 100644 index 0000000..9b8451f --- /dev/null +++ b/oauth2-server-core/src/main/java/nl/myndocs/oauth2/response/AccessTokenResponder.kt @@ -0,0 +1,7 @@ +package nl.myndocs.oauth2.response + +import nl.myndocs.oauth2.token.AccessToken + +interface AccessTokenResponder { + fun createResponse(accessToken: AccessToken): Map +} \ No newline at end of file diff --git a/oauth2-server-core/src/main/java/nl/myndocs/oauth2/response/DefaultAccessTokenResponder.kt b/oauth2-server-core/src/main/java/nl/myndocs/oauth2/response/DefaultAccessTokenResponder.kt new file mode 100644 index 0000000..b650703 --- /dev/null +++ b/oauth2-server-core/src/main/java/nl/myndocs/oauth2/response/DefaultAccessTokenResponder.kt @@ -0,0 +1,15 @@ +package nl.myndocs.oauth2.response + +import nl.myndocs.oauth2.token.AccessToken + +object DefaultAccessTokenResponder : AccessTokenResponder { + override fun createResponse(accessToken: AccessToken): Map = + with(accessToken) { + mapOf( + "access_token" to this.accessToken, + "token_type" to this.tokenType, + "expires_in" to this.expiresIn(), + "refresh_token" to this.refreshToken?.refreshToken + ) + } +} \ No newline at end of file diff --git a/oauth2-server-core/src/main/java/nl/myndocs/oauth2/response/TokenResponse.kt b/oauth2-server-core/src/main/java/nl/myndocs/oauth2/response/TokenResponse.kt deleted file mode 100644 index 0f8ce0f..0000000 --- a/oauth2-server-core/src/main/java/nl/myndocs/oauth2/response/TokenResponse.kt +++ /dev/null @@ -1,8 +0,0 @@ -package nl.myndocs.oauth2.response - -data class TokenResponse( - val accessToken: String, - val tokenType: String, - val expiresIn: Int, - val refreshToken: String? -) \ No newline at end of file diff --git a/oauth2-server-core/src/main/java/nl/myndocs/oauth2/token/AccessToken.kt b/oauth2-server-core/src/main/java/nl/myndocs/oauth2/token/AccessToken.kt index 81c730c..5895ef0 100644 --- a/oauth2-server-core/src/main/java/nl/myndocs/oauth2/token/AccessToken.kt +++ b/oauth2-server-core/src/main/java/nl/myndocs/oauth2/token/AccessToken.kt @@ -1,12 +1,13 @@ package nl.myndocs.oauth2.token +import nl.myndocs.oauth2.identity.Identity import java.time.Instant data class AccessToken( val accessToken: String, val tokenType: String, override val expireTime: Instant, - val username: String?, + val identity: Identity?, val clientId: String, val scopes: Set, val refreshToken: RefreshToken? diff --git a/oauth2-server-core/src/main/java/nl/myndocs/oauth2/token/CodeToken.kt b/oauth2-server-core/src/main/java/nl/myndocs/oauth2/token/CodeToken.kt index 3df2a29..e7d15a3 100644 --- a/oauth2-server-core/src/main/java/nl/myndocs/oauth2/token/CodeToken.kt +++ b/oauth2-server-core/src/main/java/nl/myndocs/oauth2/token/CodeToken.kt @@ -1,11 +1,12 @@ package nl.myndocs.oauth2.token +import nl.myndocs.oauth2.identity.Identity import java.time.Instant data class CodeToken( val codeToken: String, override val expireTime: Instant, - val username: String, + val identity: Identity, val clientId: String, val redirectUri: String, val scopes: Set diff --git a/oauth2-server-core/src/main/java/nl/myndocs/oauth2/token/RefreshToken.kt b/oauth2-server-core/src/main/java/nl/myndocs/oauth2/token/RefreshToken.kt index e196c31..aea2c18 100644 --- a/oauth2-server-core/src/main/java/nl/myndocs/oauth2/token/RefreshToken.kt +++ b/oauth2-server-core/src/main/java/nl/myndocs/oauth2/token/RefreshToken.kt @@ -1,11 +1,12 @@ package nl.myndocs.oauth2.token +import nl.myndocs.oauth2.identity.Identity import java.time.Instant data class RefreshToken( val refreshToken: String, override val expireTime: Instant, - val username: String?, + val identity: Identity?, val clientId: String, val scopes: Set ) : ExpirableToken \ No newline at end of file diff --git a/oauth2-server-core/src/main/java/nl/myndocs/oauth2/token/TokenResponseUtil.kt b/oauth2-server-core/src/main/java/nl/myndocs/oauth2/token/TokenResponseUtil.kt deleted file mode 100644 index 2aeddae..0000000 --- a/oauth2-server-core/src/main/java/nl/myndocs/oauth2/token/TokenResponseUtil.kt +++ /dev/null @@ -1,10 +0,0 @@ -package nl.myndocs.oauth2.token - -import nl.myndocs.oauth2.response.TokenResponse - -fun TokenResponse.toMap() = mapOf( - "access_token" to this.accessToken, - "token_type" to this.tokenType, - "expires_in" to this.expiresIn, - "refresh_token" to this.refreshToken -) \ No newline at end of file diff --git a/oauth2-server-core/src/main/java/nl/myndocs/oauth2/token/converter/AccessTokenConverter.kt b/oauth2-server-core/src/main/java/nl/myndocs/oauth2/token/converter/AccessTokenConverter.kt index d21120a..1659f97 100644 --- a/oauth2-server-core/src/main/java/nl/myndocs/oauth2/token/converter/AccessTokenConverter.kt +++ b/oauth2-server-core/src/main/java/nl/myndocs/oauth2/token/converter/AccessTokenConverter.kt @@ -1,8 +1,9 @@ package nl.myndocs.oauth2.token.converter +import nl.myndocs.oauth2.identity.Identity import nl.myndocs.oauth2.token.AccessToken import nl.myndocs.oauth2.token.RefreshToken interface AccessTokenConverter { - fun convertToToken(username: String?, clientId: String, requestedScopes: Set, refreshToken: RefreshToken?): AccessToken + fun convertToToken(identity: Identity?, clientId: String, requestedScopes: Set, refreshToken: RefreshToken?): AccessToken } \ No newline at end of file diff --git a/oauth2-server-core/src/main/java/nl/myndocs/oauth2/token/converter/CodeTokenConverter.kt b/oauth2-server-core/src/main/java/nl/myndocs/oauth2/token/converter/CodeTokenConverter.kt index ee18417..02a2701 100644 --- a/oauth2-server-core/src/main/java/nl/myndocs/oauth2/token/converter/CodeTokenConverter.kt +++ b/oauth2-server-core/src/main/java/nl/myndocs/oauth2/token/converter/CodeTokenConverter.kt @@ -1,7 +1,8 @@ package nl.myndocs.oauth2.token.converter +import nl.myndocs.oauth2.identity.Identity import nl.myndocs.oauth2.token.CodeToken interface CodeTokenConverter { - fun convertToToken(username: String, clientId: String, redirectUri: String, requestedScopes: Set): CodeToken + fun convertToToken(identity: Identity, clientId: String, redirectUri: String, requestedScopes: Set): CodeToken } \ No newline at end of file diff --git a/oauth2-server-core/src/main/java/nl/myndocs/oauth2/token/converter/RefreshTokenConverter.kt b/oauth2-server-core/src/main/java/nl/myndocs/oauth2/token/converter/RefreshTokenConverter.kt index 6f9c57c..c05bdcc 100644 --- a/oauth2-server-core/src/main/java/nl/myndocs/oauth2/token/converter/RefreshTokenConverter.kt +++ b/oauth2-server-core/src/main/java/nl/myndocs/oauth2/token/converter/RefreshTokenConverter.kt @@ -1,9 +1,10 @@ package nl.myndocs.oauth2.token.converter +import nl.myndocs.oauth2.identity.Identity import nl.myndocs.oauth2.token.RefreshToken interface RefreshTokenConverter { - fun convertToToken(refreshToken: RefreshToken): RefreshToken = convertToToken(refreshToken.username, refreshToken.clientId, refreshToken.scopes) - - fun convertToToken(username: String?, clientId: String, requestedScopes: Set): RefreshToken + fun convertToToken(refreshToken: RefreshToken): RefreshToken = convertToToken(refreshToken.identity, refreshToken.clientId, refreshToken.scopes) + + fun convertToToken(identity: Identity?, clientId: String, requestedScopes: Set): RefreshToken } \ No newline at end of file diff --git a/oauth2-server-core/src/main/java/nl/myndocs/oauth2/token/converter/UUIDAccessTokenConverter.kt b/oauth2-server-core/src/main/java/nl/myndocs/oauth2/token/converter/UUIDAccessTokenConverter.kt index 5ba0d2a..72d8685 100644 --- a/oauth2-server-core/src/main/java/nl/myndocs/oauth2/token/converter/UUIDAccessTokenConverter.kt +++ b/oauth2-server-core/src/main/java/nl/myndocs/oauth2/token/converter/UUIDAccessTokenConverter.kt @@ -1,5 +1,6 @@ package nl.myndocs.oauth2.token.converter +import nl.myndocs.oauth2.identity.Identity import nl.myndocs.oauth2.token.AccessToken import nl.myndocs.oauth2.token.RefreshToken import java.time.Instant @@ -9,12 +10,12 @@ class UUIDAccessTokenConverter( private val accessTokenExpireInSeconds: Int = 3600 ) : AccessTokenConverter { - override fun convertToToken(username: String?, clientId: String, requestedScopes: Set, refreshToken: RefreshToken?): AccessToken { + override fun convertToToken(identity: Identity?, clientId: String, requestedScopes: Set, refreshToken: RefreshToken?): AccessToken { return AccessToken( UUID.randomUUID().toString(), "bearer", Instant.now().plusSeconds(accessTokenExpireInSeconds.toLong()), - username, + identity, clientId, requestedScopes, refreshToken diff --git a/oauth2-server-core/src/main/java/nl/myndocs/oauth2/token/converter/UUIDCodeTokenConverter.kt b/oauth2-server-core/src/main/java/nl/myndocs/oauth2/token/converter/UUIDCodeTokenConverter.kt index d2da23f..2e542eb 100644 --- a/oauth2-server-core/src/main/java/nl/myndocs/oauth2/token/converter/UUIDCodeTokenConverter.kt +++ b/oauth2-server-core/src/main/java/nl/myndocs/oauth2/token/converter/UUIDCodeTokenConverter.kt @@ -1,5 +1,6 @@ package nl.myndocs.oauth2.token.converter +import nl.myndocs.oauth2.identity.Identity import nl.myndocs.oauth2.token.CodeToken import java.time.Instant import java.util.* @@ -7,11 +8,11 @@ import java.util.* class UUIDCodeTokenConverter( private val codeTokenExpireInSeconds: Int = 300 ) : CodeTokenConverter { - override fun convertToToken(username: String, clientId: String, redirectUri: String, requestedScopes: Set): CodeToken { + override fun convertToToken(identity: Identity, clientId: String, redirectUri: String, requestedScopes: Set): CodeToken { return CodeToken( UUID.randomUUID().toString(), Instant.now().plusSeconds(codeTokenExpireInSeconds.toLong()), - username, + identity, clientId, redirectUri, requestedScopes diff --git a/oauth2-server-core/src/main/java/nl/myndocs/oauth2/token/converter/UUIDRefreshTokenConverter.kt b/oauth2-server-core/src/main/java/nl/myndocs/oauth2/token/converter/UUIDRefreshTokenConverter.kt index 93c9b88..5fc4d4d 100644 --- a/oauth2-server-core/src/main/java/nl/myndocs/oauth2/token/converter/UUIDRefreshTokenConverter.kt +++ b/oauth2-server-core/src/main/java/nl/myndocs/oauth2/token/converter/UUIDRefreshTokenConverter.kt @@ -1,5 +1,6 @@ package nl.myndocs.oauth2.token.converter +import nl.myndocs.oauth2.identity.Identity import nl.myndocs.oauth2.token.RefreshToken import java.time.Instant import java.util.* @@ -7,11 +8,11 @@ import java.util.* class UUIDRefreshTokenConverter( private val refreshTokenExpireInSeconds: Int = 86400 ) : RefreshTokenConverter { - override fun convertToToken(username: String?, clientId: String, requestedScopes: Set): RefreshToken { + override fun convertToToken(identity: Identity?, clientId: String, requestedScopes: Set): RefreshToken { return RefreshToken( UUID.randomUUID().toString(), Instant.now().plusSeconds(refreshTokenExpireInSeconds.toLong()), - username, + identity, clientId, requestedScopes ) diff --git a/oauth2-server-core/src/test/java/nl/myndocs/oauth2/AuthorizationCodeGrantTokenServiceTest.kt b/oauth2-server-core/src/test/java/nl/myndocs/oauth2/AuthorizationCodeGrantTokenServiceTest.kt index dc5cb3f..84b6ab1 100644 --- a/oauth2-server-core/src/test/java/nl/myndocs/oauth2/AuthorizationCodeGrantTokenServiceTest.kt +++ b/oauth2-server-core/src/test/java/nl/myndocs/oauth2/AuthorizationCodeGrantTokenServiceTest.kt @@ -16,6 +16,7 @@ import nl.myndocs.oauth2.identity.Identity import nl.myndocs.oauth2.identity.IdentityService import nl.myndocs.oauth2.request.AuthorizationCodeRequest import nl.myndocs.oauth2.request.CallContext +import nl.myndocs.oauth2.response.AccessTokenResponder import nl.myndocs.oauth2.token.AccessToken import nl.myndocs.oauth2.token.CodeToken import nl.myndocs.oauth2.token.RefreshToken @@ -46,6 +47,8 @@ internal class AuthorizationCodeGrantTokenServiceTest { lateinit var refreshTokenConverter: RefreshTokenConverter @MockK lateinit var codeTokenConverter: CodeTokenConverter + @MockK + lateinit var accessTokenResponder: AccessTokenResponder lateinit var grantingCall: GrantingCall @@ -61,6 +64,7 @@ internal class AuthorizationCodeGrantTokenServiceTest { this@AuthorizationCodeGrantTokenServiceTest.refreshTokenConverter, this@AuthorizationCodeGrantTokenServiceTest.codeTokenConverter ) + override val accessTokenResponder = this@AuthorizationCodeGrantTokenServiceTest.accessTokenResponder } } @@ -69,6 +73,7 @@ internal class AuthorizationCodeGrantTokenServiceTest { val code = "user-foo" val redirectUri = "http://foo.lcoalhost" val username = "user-foo" + val identity = Identity(username) val authorizationCodeRequest = AuthorizationCodeRequest( clientId, @@ -83,17 +88,17 @@ internal class AuthorizationCodeGrantTokenServiceTest { val client = Client(clientId, setOf("scope1", "scope2"), setOf(), setOf(AuthorizedGrantType.AUTHORIZATION_CODE)) val identity = Identity(username) - val codeToken = CodeToken(code, Instant.now(), username, clientId, redirectUri, requestScopes) + val codeToken = CodeToken(code, Instant.now(), identity, clientId, redirectUri, requestScopes) - val refreshToken = RefreshToken("test", Instant.now(), username, clientId, requestScopes) - val accessToken = AccessToken("test", "bearer", Instant.now(), username, clientId, requestScopes, refreshToken) + val refreshToken = RefreshToken("test", Instant.now(), identity, clientId, requestScopes) + val accessToken = AccessToken("test", "bearer", Instant.now(), identity, clientId, requestScopes, refreshToken) every { clientService.clientOf(clientId) } returns client every { clientService.validClient(client, clientSecret) } returns true every { identityService.identityOf(client, username) } returns identity every { tokenStore.consumeCodeToken(code) } returns codeToken - every { refreshTokenConverter.convertToToken(username, clientId, requestScopes) } returns refreshToken - every { accessTokenConverter.convertToToken(username, clientId, requestScopes, refreshToken) } returns accessToken + every { refreshTokenConverter.convertToToken(identity, clientId, requestScopes) } returns refreshToken + every { accessTokenConverter.convertToToken(identity, clientId, requestScopes, refreshToken) } returns accessToken grantingCall.authorize(authorizationCodeRequest) } @@ -160,16 +165,16 @@ internal class AuthorizationCodeGrantTokenServiceTest { val requestScopes = setOf("scope1") val client = Client(clientId, setOf("scope1", "scope2"), setOf(), setOf(AuthorizedGrantType.AUTHORIZATION_CODE)) - val codeToken = CodeToken(code, Instant.now(), username, clientId, wrongRedirectUri, requestScopes) + val codeToken = CodeToken(code, Instant.now(), identity, clientId, wrongRedirectUri, requestScopes) - val refreshToken = RefreshToken("test", Instant.now(), username, clientId, requestScopes) - val accessToken = AccessToken("test", "bearer", Instant.now(), username, clientId, requestScopes, refreshToken) + val refreshToken = RefreshToken("test", Instant.now(), identity, clientId, requestScopes) + val accessToken = AccessToken("test", "bearer", Instant.now(), identity, clientId, requestScopes, refreshToken) every { clientService.clientOf(clientId) } returns client every { clientService.validClient(client, clientSecret) } returns true every { tokenStore.consumeCodeToken(code) } returns codeToken - every { refreshTokenConverter.convertToToken(username, clientId, requestScopes) } returns refreshToken - every { accessTokenConverter.convertToToken(username, clientId, requestScopes, refreshToken) } returns accessToken + every { refreshTokenConverter.convertToToken(identity, clientId, requestScopes) } returns refreshToken + every { accessTokenConverter.convertToToken(identity, clientId, requestScopes, refreshToken) } returns accessToken assertThrows( InvalidGrantException::class.java diff --git a/oauth2-server-core/src/test/java/nl/myndocs/oauth2/ClientCredentialsTokenServiceTest.kt b/oauth2-server-core/src/test/java/nl/myndocs/oauth2/ClientCredentialsTokenServiceTest.kt index 4675402..1f320d5 100644 --- a/oauth2-server-core/src/test/java/nl/myndocs/oauth2/ClientCredentialsTokenServiceTest.kt +++ b/oauth2-server-core/src/test/java/nl/myndocs/oauth2/ClientCredentialsTokenServiceTest.kt @@ -14,6 +14,7 @@ import nl.myndocs.oauth2.grant.authorize import nl.myndocs.oauth2.identity.IdentityService import nl.myndocs.oauth2.request.CallContext import nl.myndocs.oauth2.request.ClientCredentialsRequest +import nl.myndocs.oauth2.response.AccessTokenResponder import nl.myndocs.oauth2.token.AccessToken import nl.myndocs.oauth2.token.RefreshToken import nl.myndocs.oauth2.token.TokenStore @@ -43,6 +44,8 @@ internal class ClientCredentialsTokenServiceTest { lateinit var refreshTokenConverter: RefreshTokenConverter @MockK lateinit var codeTokenConverter: CodeTokenConverter + @MockK + lateinit var accessTokenResponder: AccessTokenResponder lateinit var grantingCall: GrantingCall @@ -58,6 +61,7 @@ internal class ClientCredentialsTokenServiceTest { this@ClientCredentialsTokenServiceTest.refreshTokenConverter, this@ClientCredentialsTokenServiceTest.codeTokenConverter ) + override val accessTokenResponder = this@ClientCredentialsTokenServiceTest.accessTokenResponder } } private val clientId = "client-foo" diff --git a/oauth2-server-core/src/test/java/nl/myndocs/oauth2/PasswordGrantTokenServiceTest.kt b/oauth2-server-core/src/test/java/nl/myndocs/oauth2/PasswordGrantTokenServiceTest.kt index 4259549..fa73a6d 100644 --- a/oauth2-server-core/src/test/java/nl/myndocs/oauth2/PasswordGrantTokenServiceTest.kt +++ b/oauth2-server-core/src/test/java/nl/myndocs/oauth2/PasswordGrantTokenServiceTest.kt @@ -18,6 +18,7 @@ import nl.myndocs.oauth2.identity.Identity import nl.myndocs.oauth2.identity.IdentityService import nl.myndocs.oauth2.request.CallContext import nl.myndocs.oauth2.request.PasswordGrantRequest +import nl.myndocs.oauth2.response.AccessTokenResponder import nl.myndocs.oauth2.token.AccessToken import nl.myndocs.oauth2.token.RefreshToken import nl.myndocs.oauth2.token.TokenStore @@ -47,6 +48,8 @@ internal class PasswordGrantTokenServiceTest { lateinit var refreshTokenConverter: RefreshTokenConverter @MockK lateinit var codeTokenConverter: CodeTokenConverter + @MockK + lateinit var accessTokenResponder: AccessTokenResponder lateinit var grantingCall: GrantingCall @@ -62,6 +65,7 @@ internal class PasswordGrantTokenServiceTest { this@PasswordGrantTokenServiceTest.refreshTokenConverter, this@PasswordGrantTokenServiceTest.codeTokenConverter ) + override val accessTokenResponder = this@PasswordGrantTokenServiceTest.accessTokenResponder } } val clientId = "client-foo" @@ -84,16 +88,16 @@ internal class PasswordGrantTokenServiceTest { val client = Client(clientId, setOf("scope1", "scope2"), setOf(), setOf(AuthorizedGrantType.PASSWORD)) val identity = Identity(username) val requestScopes = setOf("scope1") - val refreshToken = RefreshToken("test", Instant.now(), username, clientId, requestScopes) - val accessToken = AccessToken("test", "bearer", Instant.now(), username, clientId, requestScopes, refreshToken) + val refreshToken = RefreshToken("test", Instant.now(), identity, clientId, requestScopes) + val accessToken = AccessToken("test", "bearer", Instant.now(), identity, clientId, requestScopes, refreshToken) every { clientService.clientOf(clientId) } returns client every { clientService.validClient(client, clientSecret) } returns true every { identityService.identityOf(client, username) } returns identity every { identityService.validCredentials(client, identity, password) } returns true every { identityService.allowedScopes(client, identity, requestScopes) } returns scopes - every { refreshTokenConverter.convertToToken(username, clientId, requestScopes) } returns refreshToken - every { accessTokenConverter.convertToToken(username, clientId, requestScopes, refreshToken) } returns accessToken + every { refreshTokenConverter.convertToToken(identity, clientId, requestScopes) } returns refreshToken + every { accessTokenConverter.convertToToken(identity, clientId, requestScopes, refreshToken) } returns accessToken grantingCall.authorize(passwordGrantRequest) @@ -218,16 +222,16 @@ internal class PasswordGrantTokenServiceTest { val client = Client(clientId, setOf("scope1", "scope2"), setOf(), setOf(AuthorizedGrantType.PASSWORD)) val identity = Identity(username) val requestScopes = setOf("scope1", "scope2") - val refreshToken = RefreshToken("test", Instant.now(), username, clientId, requestScopes) - val accessToken = AccessToken("test", "bearer", Instant.now(), username, clientId, requestScopes, refreshToken) + val refreshToken = RefreshToken("test", Instant.now(), identity, clientId, requestScopes) + val accessToken = AccessToken("test", "bearer", Instant.now(), identity, clientId, requestScopes, refreshToken) every { clientService.clientOf(clientId) } returns client every { clientService.validClient(client, clientSecret) } returns true every { identityService.identityOf(client, username) } returns identity every { identityService.validCredentials(client, identity, password) } returns true every { identityService.allowedScopes(client, identity, requestScopes) } returns requestScopes - every { refreshTokenConverter.convertToToken(username, clientId, requestScopes) } returns refreshToken - every { accessTokenConverter.convertToToken(username, clientId, requestScopes, refreshToken) } returns accessToken + every { refreshTokenConverter.convertToToken(identity, clientId, requestScopes) } returns refreshToken + every { accessTokenConverter.convertToToken(identity, clientId, requestScopes, refreshToken) } returns accessToken grantingCall.authorize(passwordGrantRequest) } diff --git a/oauth2-server-core/src/test/java/nl/myndocs/oauth2/RefreshTokenGrantTokenServiceTest.kt b/oauth2-server-core/src/test/java/nl/myndocs/oauth2/RefreshTokenGrantTokenServiceTest.kt index f8ec5d9..2dce0e9 100644 --- a/oauth2-server-core/src/test/java/nl/myndocs/oauth2/RefreshTokenGrantTokenServiceTest.kt +++ b/oauth2-server-core/src/test/java/nl/myndocs/oauth2/RefreshTokenGrantTokenServiceTest.kt @@ -17,6 +17,7 @@ import nl.myndocs.oauth2.identity.Identity import nl.myndocs.oauth2.identity.IdentityService import nl.myndocs.oauth2.request.CallContext import nl.myndocs.oauth2.request.RefreshTokenRequest +import nl.myndocs.oauth2.response.AccessTokenResponder import nl.myndocs.oauth2.token.AccessToken import nl.myndocs.oauth2.token.RefreshToken import nl.myndocs.oauth2.token.TokenStore @@ -46,6 +47,8 @@ internal class RefreshTokenGrantTokenServiceTest { lateinit var refreshTokenConverter: RefreshTokenConverter @MockK lateinit var codeTokenConverter: CodeTokenConverter + @MockK + lateinit var accessTokenResponder: AccessTokenResponder lateinit var grantingCall: GrantingCall @@ -61,14 +64,17 @@ internal class RefreshTokenGrantTokenServiceTest { this@RefreshTokenGrantTokenServiceTest.refreshTokenConverter, this@RefreshTokenGrantTokenServiceTest.codeTokenConverter ) + override val accessTokenResponder = this@RefreshTokenGrantTokenServiceTest.accessTokenResponder } } + val clientId = "client-foo" val clientSecret = "client-bar" val refreshToken = "refresh-token" val username = "foo-user" val scope = "scope1" val scopes = setOf(scope) + val identity = Identity(username) val refreshTokenRequest = RefreshTokenRequest( clientId, @@ -79,9 +85,9 @@ internal class RefreshTokenGrantTokenServiceTest { @Test fun validRefreshToken() { val client = Client(clientId, setOf("scope1", "scope2"), setOf(), setOf(AuthorizedGrantType.REFRESH_TOKEN)) - val token = RefreshToken("test", Instant.now(), username, clientId, scopes) - val newRefreshToken = RefreshToken("new-test", Instant.now(), username, clientId, scopes) - val accessToken = AccessToken("test", "bearer", Instant.now(), username, clientId, scopes, newRefreshToken) + val token = RefreshToken("test", Instant.now(), identity, clientId, scopes) + val newRefreshToken = RefreshToken("new-test", Instant.now(), identity, clientId, scopes) + val accessToken = AccessToken("test", "bearer", Instant.now(), identity, clientId, scopes, newRefreshToken) val identity = Identity(username) every { clientService.clientOf(clientId) } returns client @@ -89,7 +95,7 @@ internal class RefreshTokenGrantTokenServiceTest { every { tokenStore.refreshToken(refreshToken) } returns token every { identityService.identityOf(client, username) } returns identity every { refreshTokenConverter.convertToToken(token) } returns newRefreshToken - every { accessTokenConverter.convertToToken(username, clientId, scopes, newRefreshToken) } returns accessToken + every { accessTokenConverter.convertToToken(identity, clientId, scopes, newRefreshToken) } returns accessToken grantingCall.refresh(refreshTokenRequest) @@ -138,7 +144,7 @@ internal class RefreshTokenGrantTokenServiceTest { @Test fun storedClientDoesNotMatchRequestedException() { val client = Client(clientId, setOf("scope1", "scope2"), setOf(), setOf(AuthorizedGrantType.REFRESH_TOKEN)) - val token = RefreshToken("test", Instant.now(), username, "wrong-client", scopes) + val token = RefreshToken("test", Instant.now(), identity, "wrong-client", scopes) every { clientService.clientOf(clientId) } returns client every { clientService.validClient(client, clientSecret) } returns true 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 index 2b44c1e..1900341 100644 --- a/oauth2-server-jwt/src/main/java/nl/myndocs/convert/DefaultJwtBuilder.kt +++ b/oauth2-server-jwt/src/main/java/nl/myndocs/convert/DefaultJwtBuilder.kt @@ -1,11 +1,12 @@ package nl.myndocs.convert import com.auth0.jwt.JWT +import nl.myndocs.oauth2.identity.Identity import java.time.Instant import java.util.* object DefaultJwtBuilder : JwtBuilder { - override fun buildJwt(username: String?, clientId: String, requestedScopes: Set, expiresInSeconds: Long) = + override fun buildJwt(identity: Identity?, clientId: String, requestedScopes: Set, expiresInSeconds: Long) = JWT.create() .withIssuedAt(Date.from(Instant.now())) .withExpiresAt( @@ -16,5 +17,5 @@ object DefaultJwtBuilder : JwtBuilder { ) .withClaim("client_id", clientId) .withArrayClaim("scopes", requestedScopes.toTypedArray()) - .let { withBuilder -> if (username != null) withBuilder.withClaim("username", username) else withBuilder } + .let { withBuilder -> if (identity != null) withBuilder.withClaim("username", identity.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 a794724..90fb40b 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,6 +1,7 @@ package nl.myndocs.convert import com.auth0.jwt.algorithms.Algorithm +import nl.myndocs.oauth2.identity.Identity import nl.myndocs.oauth2.token.AccessToken import nl.myndocs.oauth2.token.RefreshToken import nl.myndocs.oauth2.token.converter.AccessTokenConverter @@ -11,9 +12,9 @@ class JwtAccessTokenConverter( private val accessTokenExpireInSeconds: Int = 3600, private val jwtBuilder: JwtBuilder = DefaultJwtBuilder ) : AccessTokenConverter { - override fun convertToToken(username: String?, clientId: String, requestedScopes: Set, refreshToken: RefreshToken?): AccessToken { + override fun convertToToken(identity: Identity?, clientId: String, requestedScopes: Set, refreshToken: RefreshToken?): AccessToken { val jwtBuilder = jwtBuilder.buildJwt( - username, + identity, clientId, requestedScopes, accessTokenExpireInSeconds.toLong() @@ -23,7 +24,7 @@ class JwtAccessTokenConverter( jwtBuilder.sign(algorithm), "bearer", Instant.now().plusSeconds(accessTokenExpireInSeconds.toLong()), - username, + identity, clientId, requestedScopes, refreshToken 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 index 800b09b..b066788 100644 --- a/oauth2-server-jwt/src/main/java/nl/myndocs/convert/JwtBuilder.kt +++ b/oauth2-server-jwt/src/main/java/nl/myndocs/convert/JwtBuilder.kt @@ -1,7 +1,8 @@ package nl.myndocs.convert import com.auth0.jwt.JWTCreator +import nl.myndocs.oauth2.identity.Identity interface JwtBuilder { - fun buildJwt(username: String?, clientId: String, requestedScopes: Set, expiresInSeconds: Long): JWTCreator.Builder + fun buildJwt(identity: Identity?, 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 e633fb8..4864499 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,6 +1,7 @@ package nl.myndocs.convert import com.auth0.jwt.algorithms.Algorithm +import nl.myndocs.oauth2.identity.Identity import nl.myndocs.oauth2.token.RefreshToken import nl.myndocs.oauth2.token.converter.RefreshTokenConverter import java.time.Instant @@ -10,9 +11,9 @@ class JwtRefreshTokenConverter( private val refreshTokenExpireInSeconds: Int = 86400, private val jwtBuilder: JwtBuilder = DefaultJwtBuilder ) : RefreshTokenConverter { - override fun convertToToken(username: String?, clientId: String, requestedScopes: Set): RefreshToken { + override fun convertToToken(identity: Identity?, clientId: String, requestedScopes: Set): RefreshToken { val jwtBuilder = jwtBuilder.buildJwt( - username, + identity, clientId, requestedScopes, refreshTokenExpireInSeconds.toLong() @@ -21,7 +22,7 @@ class JwtRefreshTokenConverter( return RefreshToken( jwtBuilder.sign(algorithm), Instant.now().plusSeconds(refreshTokenExpireInSeconds.toLong()), - username, + identity, clientId, requestedScopes ) From 3c9c1113f0076d443a7ba1d1d6b1ffd883f9477c Mon Sep 17 00:00:00 2001 From: Albert Date: Tue, 12 Feb 2019 10:19:18 +0100 Subject: [PATCH 5/7] 0.5.0 release --- README.md | 4 ++-- oauth2-server-client-inmemory/pom.xml | 2 +- oauth2-server-core/pom.xml | 2 +- oauth2-server-http4k/pom.xml | 2 +- oauth2-server-identity-inmemory/pom.xml | 2 +- oauth2-server-javalin/pom.xml | 2 +- oauth2-server-json/pom.xml | 2 +- oauth2-server-jwt/pom.xml | 2 +- oauth2-server-ktor/pom.xml | 2 +- oauth2-server-sparkjava/pom.xml | 2 +- oauth2-server-token-store-inmemory/pom.xml | 2 +- pom.xml | 2 +- 12 files changed, 13 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 910389f..35e6fef 100644 --- a/README.md +++ b/README.md @@ -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 - 0.4.0 + 0.5.0 ``` @@ -176,4 +176,4 @@ refreshTokenConverter = JwtRefreshTokenConverter( 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) -``` \ No newline at end of file +``` diff --git a/oauth2-server-client-inmemory/pom.xml b/oauth2-server-client-inmemory/pom.xml index 19efe6b..59e990a 100644 --- a/oauth2-server-client-inmemory/pom.xml +++ b/oauth2-server-client-inmemory/pom.xml @@ -5,7 +5,7 @@ kotlin-oauth2-server nl.myndocs - 0.4.1-SNAPSHOT + 0.5.0 4.0.0 diff --git a/oauth2-server-core/pom.xml b/oauth2-server-core/pom.xml index d496972..7135a50 100644 --- a/oauth2-server-core/pom.xml +++ b/oauth2-server-core/pom.xml @@ -5,7 +5,7 @@ kotlin-oauth2-server nl.myndocs - 0.4.1-SNAPSHOT + 0.5.0 4.0.0 diff --git a/oauth2-server-http4k/pom.xml b/oauth2-server-http4k/pom.xml index b86f46b..5db4299 100644 --- a/oauth2-server-http4k/pom.xml +++ b/oauth2-server-http4k/pom.xml @@ -5,7 +5,7 @@ kotlin-oauth2-server nl.myndocs - 0.4.1-SNAPSHOT + 0.5.0 4.0.0 diff --git a/oauth2-server-identity-inmemory/pom.xml b/oauth2-server-identity-inmemory/pom.xml index aa9bf36..b7c3fbb 100644 --- a/oauth2-server-identity-inmemory/pom.xml +++ b/oauth2-server-identity-inmemory/pom.xml @@ -5,7 +5,7 @@ kotlin-oauth2-server nl.myndocs - 0.4.1-SNAPSHOT + 0.5.0 4.0.0 diff --git a/oauth2-server-javalin/pom.xml b/oauth2-server-javalin/pom.xml index 8c431a3..69d44d1 100644 --- a/oauth2-server-javalin/pom.xml +++ b/oauth2-server-javalin/pom.xml @@ -5,7 +5,7 @@ kotlin-oauth2-server nl.myndocs - 0.4.1-SNAPSHOT + 0.5.0 4.0.0 diff --git a/oauth2-server-json/pom.xml b/oauth2-server-json/pom.xml index 5c23812..3fe83b0 100644 --- a/oauth2-server-json/pom.xml +++ b/oauth2-server-json/pom.xml @@ -5,7 +5,7 @@ kotlin-oauth2-server nl.myndocs - 0.4.1-SNAPSHOT + 0.5.0 4.0.0 diff --git a/oauth2-server-jwt/pom.xml b/oauth2-server-jwt/pom.xml index 7880e28..1b29b73 100644 --- a/oauth2-server-jwt/pom.xml +++ b/oauth2-server-jwt/pom.xml @@ -5,7 +5,7 @@ kotlin-oauth2-server nl.myndocs - 0.4.1-SNAPSHOT + 0.5.0 4.0.0 diff --git a/oauth2-server-ktor/pom.xml b/oauth2-server-ktor/pom.xml index 2f0dd53..67ca352 100644 --- a/oauth2-server-ktor/pom.xml +++ b/oauth2-server-ktor/pom.xml @@ -5,7 +5,7 @@ kotlin-oauth2-server nl.myndocs - 0.4.1-SNAPSHOT + 0.5.0 4.0.0 diff --git a/oauth2-server-sparkjava/pom.xml b/oauth2-server-sparkjava/pom.xml index 2f74228..46ff336 100644 --- a/oauth2-server-sparkjava/pom.xml +++ b/oauth2-server-sparkjava/pom.xml @@ -5,7 +5,7 @@ kotlin-oauth2-server nl.myndocs - 0.4.1-SNAPSHOT + 0.5.0 4.0.0 diff --git a/oauth2-server-token-store-inmemory/pom.xml b/oauth2-server-token-store-inmemory/pom.xml index acb222d..cf43d18 100644 --- a/oauth2-server-token-store-inmemory/pom.xml +++ b/oauth2-server-token-store-inmemory/pom.xml @@ -5,7 +5,7 @@ kotlin-oauth2-server nl.myndocs - 0.4.1-SNAPSHOT + 0.5.0 4.0.0 diff --git a/pom.xml b/pom.xml index addb6b4..1f04429 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ nl.myndocs kotlin-oauth2-server pom - 0.4.1-SNAPSHOT + 0.5.0 1.3.0 From af201ce272af46eec11557edd17f72788f1fbd20 Mon Sep 17 00:00:00 2001 From: Albert Date: Tue, 12 Feb 2019 10:38:02 +0100 Subject: [PATCH 6/7] Update mvn --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 8b3e658..d1a794d 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -2,7 +2,7 @@ pipeline { agent any tools { - maven 'mvn-3.5.4' + maven 'mvn-3.6.0' jdk 'jdk-8' } From 7c84ca737cc15d6898142bc6a69aba6c41b682ea Mon Sep 17 00:00:00 2001 From: Albert Date: Tue, 12 Feb 2019 10:44:11 +0100 Subject: [PATCH 7/7] Fix indenting --- Jenkinsfile | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index d1a794d..d552feb 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -2,20 +2,20 @@ pipeline { agent any tools { - maven 'mvn-3.6.0' - 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' + } + } } } \ No newline at end of file