Skip to content

Commit 8fd9669

Browse files
authored
refactor: use new verify token functionality from google-auth-library (#2986)
* refactor: use new verify token functionality from google-auth-library * fix: restore check for subject and email * docs: clarify comment about subject/email claims * fix: print verification exception message to stdout
1 parent 743ec3c commit 8fd9669

File tree

2 files changed

+17
-78
lines changed

2 files changed

+17
-78
lines changed

iap/pom.xml

-5
Original file line numberDiff line numberDiff line change
@@ -60,11 +60,6 @@
6060
<artifactId>google-auth-library-oauth2-http</artifactId>
6161
<version>0.21.0</version>
6262
</dependency>
63-
<dependency>
64-
<groupId>com.nimbusds</groupId>
65-
<artifactId>nimbus-jose-jwt</artifactId>
66-
<version>8.19</version>
67-
</dependency>
6863
<!-- [END dependencies] -->
6964

7065
<!-- Test dependencies -->

iap/src/main/java/com/example/iap/VerifyIapRequestHeader.java

+17-73
Original file line numberDiff line numberDiff line change
@@ -18,53 +18,14 @@
1818
// [START iap_validate_jwt]
1919

2020
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;
3723

3824
/** Verify IAP authorization JWT token in incoming request. */
3925
public class VerifyIapRequestHeader {
4026

41-
private static final String PUBLIC_KEY_VERIFICATION_URL =
42-
"https://www.gstatic.com/iap/verify/public_key-jwk";
43-
4427
private static final String IAP_ISSUER_URL = "https://cloud.google.com/iap";
4528

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-
6829
// Verify jwt tokens addressed to IAP protected resources on App Engine.
6930
// The project *number* for your Google Cloud project via 'gcloud projects describe $PROJECT_ID'
7031
// The project *number* can also be retrieved from the Project Info card in Cloud Console.
@@ -96,38 +57,21 @@ boolean verifyJwtForComputeEngine(
9657
Long.toUnsignedString(projectNumber), Long.toUnsignedString(backendServiceId)));
9758
}
9859

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+
}
13175
}
13276
}
13377
// [END iap_validate_jwt]

0 commit comments

Comments
 (0)