1
1
package com .avast .grpc .jwt .keycloak .server ;
2
2
3
3
import com .avast .grpc .jwt .server .JwtTokenParser ;
4
- import com .fasterxml .jackson .databind .ObjectMapper ;
5
4
import com .google .common .base .Strings ;
6
- import java .net . URL ;
7
- import java .security . PublicKey ;
5
+ import java .util . concurrent . CompletableFuture ;
6
+ import java .util . concurrent . CompletionException ;
8
7
import org .keycloak .TokenVerifier ;
9
8
import org .keycloak .common .VerificationException ;
10
9
import org .keycloak .constants .ServiceUrlConstants ;
11
- import org .keycloak .jose .jwk .JSONWebKeySet ;
12
- import org .keycloak .jose .jwk .JWK ;
13
- import org .keycloak .jose .jwk .JWKParser ;
14
10
import org .keycloak .representations .AccessToken ;
15
11
import org .keycloak .util .TokenUtil ;
16
12
17
13
public class KeycloakJwtTokenParser implements JwtTokenParser <AccessToken > {
18
14
19
- protected final PublicKey publicKey ;
15
+ protected final KeycloakPublicKeyProvider publicKeyProvider ;
20
16
protected final TokenVerifier .Predicate <AccessToken >[] checks ;
21
17
protected String expectedAudience ;
22
18
protected String expectedIssuedFor ;
23
19
24
- protected KeycloakJwtTokenParser (String serverUrl , String realm , PublicKey publicKey ) {
25
- this .publicKey = publicKey ;
20
+ public KeycloakJwtTokenParser (
21
+ String serverUrl , String realm , KeycloakPublicKeyProvider publicKeyProvider ) {
22
+ this .publicKeyProvider = publicKeyProvider ;
26
23
String realmUrl =
27
24
serverUrl + ServiceUrlConstants .REALM_INFO_PATH .replace ("{realm-name}" , realm );
28
25
this .checks =
@@ -35,20 +32,36 @@ protected KeycloakJwtTokenParser(String serverUrl, String realm, PublicKey publi
35
32
}
36
33
37
34
@ Override
38
- public AccessToken parseToValid (String jwtToken ) throws VerificationException {
39
- TokenVerifier <AccessToken > verifier = createTokenVerifier (jwtToken );
40
- return verifier .verify ().getToken ();
35
+ public CompletableFuture <AccessToken > parseToValid (String jwtToken ) {
36
+ TokenVerifier <AccessToken > verifier ;
37
+ try {
38
+ verifier = createTokenVerifier (jwtToken );
39
+ } catch (VerificationException e ) {
40
+ CompletableFuture <AccessToken > r = new CompletableFuture <>();
41
+ r .completeExceptionally (e );
42
+ return r ;
43
+ }
44
+ return CompletableFuture .supplyAsync (
45
+ () -> {
46
+ try {
47
+ return verifier .verify ().getToken ();
48
+ } catch (VerificationException e ) {
49
+ throw new CompletionException (e );
50
+ }
51
+ });
41
52
}
42
53
43
- protected TokenVerifier <AccessToken > createTokenVerifier (String jwtToken ) {
54
+ protected TokenVerifier <AccessToken > createTokenVerifier (String jwtToken )
55
+ throws VerificationException {
44
56
TokenVerifier <AccessToken > verifier =
45
- TokenVerifier .create (jwtToken , AccessToken .class ).withChecks (checks ). publicKey ( publicKey ) ;
57
+ TokenVerifier .create (jwtToken , AccessToken .class ).withChecks (checks );
46
58
if (!Strings .isNullOrEmpty (expectedAudience )) {
47
59
verifier = verifier .audience (expectedAudience );
48
60
}
49
61
if (!Strings .isNullOrEmpty (expectedIssuedFor )) {
50
62
verifier = verifier .issuedFor (expectedIssuedFor );
51
63
}
64
+ verifier .publicKey (publicKeyProvider .get (verifier .getHeader ().getKeyId ()));
52
65
return verifier ;
53
66
}
54
67
@@ -61,20 +74,4 @@ public KeycloakJwtTokenParser withExpectedIssuedFor(String expectedIssuedFor) {
61
74
this .expectedIssuedFor = expectedIssuedFor ;
62
75
return this ;
63
76
}
64
-
65
- public static KeycloakJwtTokenParser create (String serverUrl , String realm ) {
66
- try {
67
- ObjectMapper om = new ObjectMapper ();
68
- String jwksUrl = serverUrl + ServiceUrlConstants .JWKS_URL .replace ("{realm-name}" , realm );
69
- JSONWebKeySet jwks = om .readValue (new URL (jwksUrl ).openStream (), JSONWebKeySet .class );
70
- if (jwks .getKeys ().length == 0 ) {
71
- throw new RuntimeException ("No keys found" );
72
- }
73
- JWK jwk = jwks .getKeys ()[0 ];
74
- PublicKey publicKey = JWKParser .create (jwk ).toPublicKey ();
75
- return new KeycloakJwtTokenParser (serverUrl , realm , publicKey );
76
- } catch (Exception e ) {
77
- throw new RuntimeException ("Exception when obtaining public key from " + serverUrl , e );
78
- }
79
- }
80
77
}
0 commit comments