|
18 | 18 | // [START iap_validate_jwt] |
19 | 19 |
|
20 | 20 | import com.google.api.client.http.HttpRequest; |
21 | | -import com.google.common.base.Preconditions; |
22 | | -import com.nimbusds.jose.JWSHeader; |
23 | | -import com.nimbusds.jose.JWSVerifier; |
24 | | -import com.nimbusds.jose.crypto.ECDSAVerifier; |
25 | | -import com.nimbusds.jose.jwk.ECKey; |
26 | | -import com.nimbusds.jose.jwk.JWK; |
27 | | -import com.nimbusds.jose.jwk.JWKSet; |
28 | | -import com.nimbusds.jwt.JWTClaimsSet; |
29 | | -import com.nimbusds.jwt.SignedJWT; |
30 | | -import java.net.URL; |
31 | | -import java.security.interfaces.ECPublicKey; |
32 | | -import java.time.Clock; |
33 | | -import java.time.Instant; |
34 | | -import java.util.Date; |
35 | | -import java.util.HashMap; |
36 | | -import java.util.Map; |
| 21 | +import com.google.api.client.json.webtoken.JsonWebToken; |
| 22 | +import com.google.auth.oauth2.TokenVerifier; |
37 | 23 |
|
38 | 24 | /** Verify IAP authorization JWT token in incoming request. */ |
39 | 25 | public class VerifyIapRequestHeader { |
40 | 26 |
|
41 | | - private static final String PUBLIC_KEY_VERIFICATION_URL = |
42 | | - "https://www.gstatic.com/iap/verify/public_key-jwk"; |
43 | | - |
44 | 27 | private static final String IAP_ISSUER_URL = "https://cloud.google.com/iap"; |
45 | 28 |
|
46 | | - // using a simple cache with no eviction for this sample |
47 | | - private final Map<String, JWK> keyCache = new HashMap<>(); |
48 | | - |
49 | | - private static Clock clock = Clock.systemUTC(); |
50 | | - |
51 | | - private ECPublicKey getKey(String kid, String alg) throws Exception { |
52 | | - JWK jwk = keyCache.get(kid); |
53 | | - if (jwk == null) { |
54 | | - // update cache loading jwk public key data from url |
55 | | - JWKSet jwkSet = JWKSet.load(new URL(PUBLIC_KEY_VERIFICATION_URL)); |
56 | | - for (JWK key : jwkSet.getKeys()) { |
57 | | - keyCache.put(key.getKeyID(), key); |
58 | | - } |
59 | | - jwk = keyCache.get(kid); |
60 | | - } |
61 | | - // confirm that algorithm matches |
62 | | - if (jwk != null && jwk.getAlgorithm().getName().equals(alg)) { |
63 | | - return ECKey.parse(jwk.toJSONString()).toECPublicKey(); |
64 | | - } |
65 | | - return null; |
66 | | - } |
67 | | - |
68 | 29 | // Verify jwt tokens addressed to IAP protected resources on App Engine. |
69 | 30 | // The project *number* for your Google Cloud project via 'gcloud projects describe $PROJECT_ID' |
70 | 31 | // The project *number* can also be retrieved from the Project Info card in Cloud Console. |
@@ -96,38 +57,21 @@ boolean verifyJwtForComputeEngine( |
96 | 57 | Long.toUnsignedString(projectNumber), Long.toUnsignedString(backendServiceId))); |
97 | 58 | } |
98 | 59 |
|
99 | | - private boolean verifyJwt(String jwtToken, String expectedAudience) throws Exception { |
100 | | - |
101 | | - // parse signed token into header / claims |
102 | | - SignedJWT signedJwt = SignedJWT.parse(jwtToken); |
103 | | - JWSHeader jwsHeader = signedJwt.getHeader(); |
104 | | - |
105 | | - // header must have algorithm("alg") and "kid" |
106 | | - Preconditions.checkNotNull(jwsHeader.getAlgorithm()); |
107 | | - Preconditions.checkNotNull(jwsHeader.getKeyID()); |
108 | | - |
109 | | - JWTClaimsSet claims = signedJwt.getJWTClaimsSet(); |
110 | | - |
111 | | - // claims must have audience, issuer |
112 | | - Preconditions.checkArgument(claims.getAudience().contains(expectedAudience)); |
113 | | - Preconditions.checkArgument(claims.getIssuer().equals(IAP_ISSUER_URL)); |
114 | | - |
115 | | - // claim must have issued at time in the past |
116 | | - Date currentTime = Date.from(Instant.now(clock)); |
117 | | - Preconditions.checkArgument(claims.getIssueTime().before(currentTime)); |
118 | | - // claim must have expiration time in the future |
119 | | - Preconditions.checkArgument(claims.getExpirationTime().after(currentTime)); |
120 | | - |
121 | | - // must have subject, email |
122 | | - Preconditions.checkNotNull(claims.getSubject()); |
123 | | - Preconditions.checkNotNull(claims.getClaim("email")); |
124 | | - |
125 | | - // verify using public key : lookup with key id, algorithm name provided |
126 | | - ECPublicKey publicKey = getKey(jwsHeader.getKeyID(), jwsHeader.getAlgorithm().getName()); |
127 | | - |
128 | | - Preconditions.checkNotNull(publicKey); |
129 | | - JWSVerifier jwsVerifier = new ECDSAVerifier(publicKey); |
130 | | - return signedJwt.verify(jwsVerifier); |
| 60 | + private boolean verifyJwt(String jwtToken, String expectedAudience) { |
| 61 | + TokenVerifier tokenVerifier = TokenVerifier.newBuilder() |
| 62 | + .setAudience(expectedAudience) |
| 63 | + .setIssuer(IAP_ISSUER_URL) |
| 64 | + .build(); |
| 65 | + try { |
| 66 | + JsonWebToken jsonWebToken = tokenVerifier.verify(jwtToken); |
| 67 | + |
| 68 | + // Verify that the token contain subject and email claims |
| 69 | + JsonWebToken.Payload payload = jsonWebToken.getPayload(); |
| 70 | + return payload.getSubject() != null && payload.get("email") != null; |
| 71 | + } catch (TokenVerifier.VerificationException e) { |
| 72 | + System.out.println(e.getMessage()); |
| 73 | + return false; |
| 74 | + } |
131 | 75 | } |
132 | 76 | } |
133 | 77 | // [END iap_validate_jwt] |
0 commit comments