Skip to content

Commit a2098a5

Browse files
authored
Support metadata on identity (#53)
* Support metadata on identity * Allow custom access token response implementation (#54)
1 parent 9dc558e commit a2098a5

28 files changed

+135
-102
lines changed

oauth2-server-core/src/main/java/nl/myndocs/oauth2/config/ConfigurationBuilder.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import nl.myndocs.oauth2.identity.IdentityService
88
import nl.myndocs.oauth2.identity.TokenInfo
99
import nl.myndocs.oauth2.request.CallContext
1010
import nl.myndocs.oauth2.request.auth.BasicAuthorizer
11+
import nl.myndocs.oauth2.response.AccessTokenResponder
12+
import nl.myndocs.oauth2.response.DefaultAccessTokenResponder
1113
import nl.myndocs.oauth2.token.TokenStore
1214
import nl.myndocs.oauth2.token.converter.*
1315

@@ -53,6 +55,7 @@ object ConfigurationBuilder {
5355
var accessTokenConverter: AccessTokenConverter = UUIDAccessTokenConverter()
5456
var refreshTokenConverter: RefreshTokenConverter = UUIDRefreshTokenConverter()
5557
var codeTokenConverter: CodeTokenConverter = UUIDCodeTokenConverter()
58+
var accessTokenResponder: AccessTokenResponder = DefaultAccessTokenResponder
5659
}
5760

5861
fun build(configurer: Configuration.() -> Unit): nl.myndocs.oauth2.config.Configuration {
@@ -70,6 +73,7 @@ object ConfigurationBuilder {
7073
configuration.refreshTokenConverter,
7174
configuration.codeTokenConverter
7275
)
76+
override val accessTokenResponder = configuration.accessTokenResponder
7377
}
7478
}
7579
return nl.myndocs.oauth2.config.Configuration(

oauth2-server-core/src/main/java/nl/myndocs/oauth2/grant/CallRouterAuthorize.kt

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,16 @@ import nl.myndocs.oauth2.exception.*
55
import nl.myndocs.oauth2.request.AuthorizationCodeRequest
66
import nl.myndocs.oauth2.request.ClientCredentialsRequest
77
import nl.myndocs.oauth2.request.PasswordGrantRequest
8-
import nl.myndocs.oauth2.response.TokenResponse
98
import nl.myndocs.oauth2.scope.ScopeParser
9+
import nl.myndocs.oauth2.token.AccessToken
1010

1111

1212
/**
1313
* @throws InvalidIdentityException
1414
* @throws InvalidClientException
1515
* @throws InvalidScopeException
1616
*/
17-
fun GrantingCall.authorize(passwordGrantRequest: PasswordGrantRequest): TokenResponse {
17+
fun GrantingCall.authorize(passwordGrantRequest: PasswordGrantRequest): AccessToken {
1818
throwExceptionIfUnverifiedClient(passwordGrantRequest)
1919

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

5252
val accessToken = converters.accessTokenConverter.convertToToken(
53-
requestedIdentity.username,
53+
requestedIdentity,
5454
requestedClient.clientId,
5555
requestedScopes,
5656
converters.refreshTokenConverter.convertToToken(
57-
requestedIdentity.username,
57+
requestedIdentity,
5858
requestedClient.clientId,
5959
requestedScopes
6060
)
6161
)
6262

6363
tokenStore.storeAccessToken(accessToken)
6464

65-
return accessToken.toTokenResponse()
65+
return accessToken
6666
}
6767

68-
fun GrantingCall.authorize(authorizationCodeRequest: AuthorizationCodeRequest): TokenResponse {
68+
fun GrantingCall.authorize(authorizationCodeRequest: AuthorizationCodeRequest): AccessToken {
6969
throwExceptionIfUnverifiedClient(authorizationCodeRequest)
7070

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

8787
val accessToken = converters.accessTokenConverter.convertToToken(
88-
consumeCodeToken.username,
88+
consumeCodeToken.identity,
8989
consumeCodeToken.clientId,
9090
consumeCodeToken.scopes,
9191
converters.refreshTokenConverter.convertToToken(
92-
consumeCodeToken.username,
92+
consumeCodeToken.identity,
9393
consumeCodeToken.clientId,
9494
consumeCodeToken.scopes
9595
)
9696
)
9797

9898
tokenStore.storeAccessToken(accessToken)
9999

100-
return accessToken.toTokenResponse()
100+
return accessToken
101101
}
102102

103-
fun GrantingCall.authorize(clientCredentialsRequest: ClientCredentialsRequest): TokenResponse {
103+
fun GrantingCall.authorize(clientCredentialsRequest: ClientCredentialsRequest): AccessToken {
104104
throwExceptionIfUnverifiedClient(clientCredentialsRequest)
105105

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

112112
val accessToken = converters.accessTokenConverter.convertToToken(
113-
username = null,
113+
identity = null,
114114
clientId = clientCredentialsRequest.clientId,
115115
requestedScopes = scopes,
116116
refreshToken = converters.refreshTokenConverter.convertToToken(
117-
username = null,
117+
identity = null,
118118
clientId = clientCredentialsRequest.clientId,
119119
requestedScopes = scopes
120120
)
121121
)
122122

123123
tokenStore.storeAccessToken(accessToken)
124124

125-
return accessToken.toTokenResponse()
125+
return accessToken
126126
}

oauth2-server-core/src/main/java/nl/myndocs/oauth2/grant/CallRouterDefault.kt

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,9 @@ import nl.myndocs.oauth2.exception.InvalidScopeException
99
import nl.myndocs.oauth2.identity.Identity
1010
import nl.myndocs.oauth2.identity.TokenInfo
1111
import nl.myndocs.oauth2.request.*
12-
import nl.myndocs.oauth2.response.TokenResponse
13-
import nl.myndocs.oauth2.token.AccessToken
14-
import nl.myndocs.oauth2.token.toMap
1512

1613
fun GrantingCall.grantPassword() = granter("password") {
17-
val tokenResponse = authorize(
14+
val accessToken = authorize(
1815
PasswordGrantRequest(
1916
callContext.formParameters["client_id"],
2017
callContext.formParameters["client_secret"],
@@ -24,17 +21,17 @@ fun GrantingCall.grantPassword() = granter("password") {
2421
)
2522
)
2623

27-
callContext.respondJson(tokenResponse.toMap())
24+
callContext.respondJson(accessTokenResponder.createResponse(accessToken))
2825
}
2926

3027
fun GrantingCall.grantClientCredentials() = granter("client_credentials") {
31-
val tokenResponse = authorize(ClientCredentialsRequest(
28+
val accessToken = authorize(ClientCredentialsRequest(
3229
callContext.formParameters["client_id"],
3330
callContext.formParameters["client_secret"],
3431
callContext.formParameters["scope"]
3532
))
3633

37-
callContext.respondJson(tokenResponse.toMap())
34+
callContext.respondJson(accessTokenResponder.createResponse(accessToken))
3835
}
3936

4037
fun GrantingCall.grantRefreshToken() = granter("refresh_token") {
@@ -46,7 +43,7 @@ fun GrantingCall.grantRefreshToken() = granter("refresh_token") {
4643
)
4744
)
4845

49-
callContext.respondJson(accessToken.toMap())
46+
callContext.respondJson(accessTokenResponder.createResponse(accessToken))
5047
}
5148

5249
fun GrantingCall.grantAuthorizationCode() = granter("authorization_code") {
@@ -59,7 +56,7 @@ fun GrantingCall.grantAuthorizationCode() = granter("authorization_code") {
5956
)
6057
)
6158

62-
callContext.respondJson(accessToken.toMap())
59+
callContext.respondJson(accessTokenResponder.createResponse(accessToken))
6360
}
6461

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

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

112109
fun GrantingCall.scopesAllowed(clientScopes: Set<String>, requestedScopes: Set<String>): Boolean {
113110
return clientScopes.containsAll(requestedScopes)
114-
}
115-
116-
fun AccessToken.toTokenResponse() = TokenResponse(
117-
accessToken,
118-
tokenType,
119-
expiresIn(),
120-
refreshToken?.refreshToken
121-
)
111+
}

oauth2-server-core/src/main/java/nl/myndocs/oauth2/grant/CallRouterRedirect.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ fun GrantingCall.redirect(
6363
validateScopes(clientOf, identityOf, requestedScopes, identityScopeVerifier)
6464

6565
val codeToken = converters.codeTokenConverter.convertToToken(
66-
identityOf.username,
66+
identityOf,
6767
clientOf.clientId,
6868
redirect.redirectUri,
6969
requestedScopes
@@ -123,7 +123,7 @@ fun GrantingCall.redirect(
123123
validateScopes(clientOf, identityOf, requestedScopes, identityScopeVerifier)
124124

125125
val accessToken = converters.accessTokenConverter.convertToToken(
126-
identityOf.username,
126+
identityOf,
127127
clientOf.clientId,
128128
requestedScopes,
129129
null

oauth2-server-core/src/main/java/nl/myndocs/oauth2/grant/CallRouterRefresh.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ import nl.myndocs.oauth2.exception.InvalidClientException
55
import nl.myndocs.oauth2.exception.InvalidGrantException
66
import nl.myndocs.oauth2.exception.InvalidRequestException
77
import nl.myndocs.oauth2.request.RefreshTokenRequest
8-
import nl.myndocs.oauth2.response.TokenResponse
8+
import nl.myndocs.oauth2.token.AccessToken
99

1010

11-
fun GrantingCall.refresh(refreshTokenRequest: RefreshTokenRequest): TokenResponse {
11+
fun GrantingCall.refresh(refreshTokenRequest: RefreshTokenRequest): AccessToken {
1212
throwExceptionIfUnverifiedClient(refreshTokenRequest)
1313

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

3131
val accessToken = converters.accessTokenConverter.convertToToken(
32-
refreshToken.username,
32+
refreshToken.identity,
3333
refreshToken.clientId,
3434
refreshToken.scopes,
3535
converters.refreshTokenConverter.convertToToken(refreshToken)
3636
)
3737

3838
tokenStore.storeAccessToken(accessToken)
3939

40-
return accessToken.toTokenResponse()
40+
return accessToken
4141
}

oauth2-server-core/src/main/java/nl/myndocs/oauth2/grant/GrantingCall.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package nl.myndocs.oauth2.grant
33
import nl.myndocs.oauth2.client.ClientService
44
import nl.myndocs.oauth2.identity.IdentityService
55
import nl.myndocs.oauth2.request.CallContext
6+
import nl.myndocs.oauth2.response.AccessTokenResponder
67
import nl.myndocs.oauth2.token.TokenStore
78
import nl.myndocs.oauth2.token.converter.Converters
89

@@ -12,4 +13,5 @@ interface GrantingCall {
1213
val clientService: ClientService
1314
val tokenStore: TokenStore
1415
val converters: Converters
16+
val accessTokenResponder: AccessTokenResponder
1517
}
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package nl.myndocs.oauth2.identity
22

33
data class Identity(
4-
val username: String
4+
val username: String,
5+
val metadata: Map<String, Any> = mapOf()
56
)
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package nl.myndocs.oauth2.response
2+
3+
import nl.myndocs.oauth2.token.AccessToken
4+
5+
interface AccessTokenResponder {
6+
fun createResponse(accessToken: AccessToken): Map<String, Any?>
7+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package nl.myndocs.oauth2.response
2+
3+
import nl.myndocs.oauth2.token.AccessToken
4+
5+
object DefaultAccessTokenResponder : AccessTokenResponder {
6+
override fun createResponse(accessToken: AccessToken): Map<String, Any?> =
7+
with(accessToken) {
8+
mapOf(
9+
"access_token" to this.accessToken,
10+
"token_type" to this.tokenType,
11+
"expires_in" to this.expiresIn(),
12+
"refresh_token" to this.refreshToken?.refreshToken
13+
)
14+
}
15+
}

oauth2-server-core/src/main/java/nl/myndocs/oauth2/response/TokenResponse.kt

Lines changed: 0 additions & 8 deletions
This file was deleted.

0 commit comments

Comments
 (0)