Skip to content

Commit 3f39a51

Browse files
authored
Merge pull request #55 from myndocs/release/0.5.0
Release/0.5.0
2 parents 6ad42ac + 7c84ca7 commit 3f39a51

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+195
-127
lines changed

Jenkinsfile

+12-12
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,20 @@ pipeline {
22
agent any
33

44
tools {
5-
maven 'mvn-3.5.4'
6-
jdk 'jdk-8'
5+
maven 'mvn-3.6.0'
6+
jdk 'jdk-8'
77
}
88

99
stages {
10-
stage('Cleanup') {
11-
steps {
12-
sh 'mvn clean'
13-
}
14-
}
15-
stage('Test') {
16-
steps {
17-
sh 'mvn test'
18-
}
19-
}
10+
stage('Cleanup') {
11+
steps {
12+
sh 'mvn clean'
13+
}
14+
}
15+
stage('Test') {
16+
steps {
17+
sh 'mvn test'
18+
}
19+
}
2020
}
2121
}

README.md

+37-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ It encourages to adapt to existing implementations instead the other way around.
1111
First define the version to be used and set it as a property
1212
```xml
1313
<properties>
14-
<myndocs.oauth.version>0.3.1</myndocs.oauth.version>
14+
<myndocs.oauth.version>0.5.0</myndocs.oauth.version>
1515
</properties>
1616
```
1717

@@ -132,13 +132,48 @@ By default `UUIDAccessTokenConverter` is used. With a default time-out of 1 hour
132132
```kotlin
133133
accessTokenConverter = UUIDAccessTokenConverter(1800)
134134
```
135+
136+
To use JWT include the following dependency:
137+
```xml
138+
<dependency>
139+
<groupId>nl.myndocs</groupId>
140+
<artifactId>oauth2-server-jwt</artifactId>
141+
<version>${myndocs.oauth.version}</version>
142+
</dependency>
143+
```
144+
This uses [auth0 jwt](https://github.com/auth0/java-jwt). To configure:
145+
```kotlin
146+
accessTokenConverter = JwtAccessTokenConverter(
147+
algorithm = Algorithm.HMAC256("test123"), // mandatory
148+
accessTokenExpireInSeconds = 1800, // optional default 3600
149+
jwtBuilder = DefaultJwtBuilder // optional uses DefaultJwtBuilder by default
150+
)
151+
```
152+
135153
#### Refresh token converter
136154
By default `UUIDRefreshTokenConverter` is used. With a default time-out of 1 hour. To override the time-out for example to half an hour:
137155
```kotlin
138156
refreshTokenConverter = UUIDRefreshTokenConverter(1800)
139157
```
158+
159+
To use JWT include the following dependency:
160+
```xml
161+
<dependency>
162+
<groupId>nl.myndocs</groupId>
163+
<artifactId>oauth2-server-jwt</artifactId>
164+
<version>${myndocs.oauth.version}</version>
165+
</dependency>
166+
```
167+
This uses [auth0 jwt](https://github.com/auth0/java-jwt). To configure:
168+
```kotlin
169+
refreshTokenConverter = JwtRefreshTokenConverter(
170+
algorithm = Algorithm.HMAC256("test123"), // mandatory
171+
refreshTokenExpireInSeconds = 1800, // optional default 86400
172+
jwtBuilder = DefaultJwtBuilder // optional uses DefaultJwtBuilder by default
173+
)
174+
```
140175
#### Code token converter
141176
By default `UUIDCodeTokenConverter` is used. With a default time-out of 5 minutes. To override the time-out for example 2 minutes:
142177
```kotlin
143178
codeTokenConverter = UUIDCodeTokenConverter(120)
144-
```
179+
```

oauth2-server-client-inmemory/pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<parent>
66
<artifactId>kotlin-oauth2-server</artifactId>
77
<groupId>nl.myndocs</groupId>
8-
<version>0.4.0</version>
8+
<version>0.5.0</version>
99
</parent>
1010
<modelVersion>4.0.0</modelVersion>
1111

oauth2-server-core/pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<parent>
66
<artifactId>kotlin-oauth2-server</artifactId>
77
<groupId>nl.myndocs</groupId>
8-
<version>0.4.0</version>
8+
<version>0.5.0</version>
99
</parent>
1010
<modelVersion>4.0.0</modelVersion>
1111

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

+4
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

+13-13
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

+8-18
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

+2-2
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

+4-4
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

+2
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
}
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
)
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+
}

0 commit comments

Comments
 (0)