Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 1 addition & 6 deletions iap/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,7 @@
<dependency>
<groupId>com.google.auth</groupId>
<artifactId>google-auth-library-oauth2-http</artifactId>
<version>0.20.0</version>
</dependency>
<dependency>
<groupId>com.nimbusds</groupId>
<artifactId>nimbus-jose-jwt</artifactId>
<version>8.19</version>
<version>0.21.0</version>
</dependency>
<!-- [END dependencies] -->

Expand Down
89 changes: 16 additions & 73 deletions iap/src/main/java/com/example/iap/VerifyIapRequestHeader.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,53 +18,14 @@
// [START iap_validate_jwt]

import com.google.api.client.http.HttpRequest;
import com.google.common.base.Preconditions;
import com.nimbusds.jose.JWSHeader;
import com.nimbusds.jose.JWSVerifier;
import com.nimbusds.jose.crypto.ECDSAVerifier;
import com.nimbusds.jose.jwk.ECKey;
import com.nimbusds.jose.jwk.JWK;
import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.SignedJWT;
import java.net.URL;
import java.security.interfaces.ECPublicKey;
import java.time.Clock;
import java.time.Instant;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import com.google.api.client.json.webtoken.JsonWebToken;
import com.google.auth.oauth2.TokenVerifier;

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

private static final String PUBLIC_KEY_VERIFICATION_URL =
"https://www.gstatic.com/iap/verify/public_key-jwk";

private static final String IAP_ISSUER_URL = "https://cloud.google.com/iap";

// using a simple cache with no eviction for this sample
private final Map<String, JWK> keyCache = new HashMap<>();

private static Clock clock = Clock.systemUTC();

private ECPublicKey getKey(String kid, String alg) throws Exception {
JWK jwk = keyCache.get(kid);
if (jwk == null) {
// update cache loading jwk public key data from url
JWKSet jwkSet = JWKSet.load(new URL(PUBLIC_KEY_VERIFICATION_URL));
for (JWK key : jwkSet.getKeys()) {
keyCache.put(key.getKeyID(), key);
}
jwk = keyCache.get(kid);
}
// confirm that algorithm matches
if (jwk != null && jwk.getAlgorithm().getName().equals(alg)) {
return ECKey.parse(jwk.toJSONString()).toECPublicKey();
}
return null;
}

// Verify jwt tokens addressed to IAP protected resources on App Engine.
// The project *number* for your Google Cloud project via 'gcloud projects describe $PROJECT_ID'
// The project *number* can also be retrieved from the Project Info card in Cloud Console.
Expand Down Expand Up @@ -96,38 +57,20 @@ boolean verifyJwtForComputeEngine(
Long.toUnsignedString(projectNumber), Long.toUnsignedString(backendServiceId)));
}

private boolean verifyJwt(String jwtToken, String expectedAudience) throws Exception {

// parse signed token into header / claims
SignedJWT signedJwt = SignedJWT.parse(jwtToken);
JWSHeader jwsHeader = signedJwt.getHeader();

// header must have algorithm("alg") and "kid"
Preconditions.checkNotNull(jwsHeader.getAlgorithm());
Preconditions.checkNotNull(jwsHeader.getKeyID());

JWTClaimsSet claims = signedJwt.getJWTClaimsSet();

// claims must have audience, issuer
Preconditions.checkArgument(claims.getAudience().contains(expectedAudience));
Preconditions.checkArgument(claims.getIssuer().equals(IAP_ISSUER_URL));

// claim must have issued at time in the past
Date currentTime = Date.from(Instant.now(clock));
Preconditions.checkArgument(claims.getIssueTime().before(currentTime));
// claim must have expiration time in the future
Preconditions.checkArgument(claims.getExpirationTime().after(currentTime));

// must have subject, email
Preconditions.checkNotNull(claims.getSubject());
Preconditions.checkNotNull(claims.getClaim("email"));

// verify using public key : lookup with key id, algorithm name provided
ECPublicKey publicKey = getKey(jwsHeader.getKeyID(), jwsHeader.getAlgorithm().getName());

Preconditions.checkNotNull(publicKey);
JWSVerifier jwsVerifier = new ECDSAVerifier(publicKey);
return signedJwt.verify(jwsVerifier);
private boolean verifyJwt(String jwtToken, String expectedAudience) {
TokenVerifier tokenVerifier = TokenVerifier.newBuilder()
.setAudience(expectedAudience)
.setIssuer(IAP_ISSUER_URL)
.build();
try {
JsonWebToken jsonWebToken = tokenVerifier.verify(jwtToken);

// Verify that the token contain subject and email claims
JsonWebToken.Payload payload = jsonWebToken.getPayload();
return payload.getSubject() != null && payload.get("email") != null;
} catch (TokenVerifier.VerificationException e) {
return false;
}
}
}
// [END iap_validate_jwt]