Java tutorial
/* * Copyright 2012 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ package com.google.api.client.googleapis.auth.oauth2; import com.google.api.client.auth.openidconnect.IdToken; import com.google.api.client.auth.openidconnect.IdTokenVerifier; import com.google.api.client.http.HttpTransport; import com.google.api.client.json.JsonFactory; import com.google.api.client.util.Beta; import com.google.api.client.util.Clock; import com.google.api.client.util.Preconditions; import java.io.IOException; import java.security.GeneralSecurityException; import java.security.PublicKey; import java.util.Arrays; import java.util.Collection; import java.util.List; /** * {@link Beta} <br/> * Thread-safe Google ID token verifier. * * <p> * Call {@link #verify(IdToken)} to verify a ID token. Use the constructor * {@link #GoogleIdTokenVerifier(HttpTransport, JsonFactory)} for the typical simpler case if your * application has only a single instance of {@link GoogleIdTokenVerifier}. Otherwise, ideally you * should use {@link #GoogleIdTokenVerifier(GooglePublicKeysManager)} with a shared global instance * of the {@link GooglePublicKeysManager} since that way the Google public keys are cached. Sample * usage: * </p> * * <pre> GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(transport, jsonFactory) .setAudience(Arrays.asList("myClientId")) .build(); ... if (!verifier.verify(googleIdToken)) {...} * </pre> * * @since 1.7 */ @Beta public class GoogleIdTokenVerifier extends IdTokenVerifier { /** Google public keys manager. */ private final GooglePublicKeysManager publicKeys; /** * @param transport HTTP transport * @param jsonFactory JSON factory */ public GoogleIdTokenVerifier(HttpTransport transport, JsonFactory jsonFactory) { this(new Builder(transport, jsonFactory)); } /** * @param publicKeys Google public keys manager * * @since 1.17 */ public GoogleIdTokenVerifier(GooglePublicKeysManager publicKeys) { this(new Builder(publicKeys)); } /** * @param builder builder * * @since 1.14 */ protected GoogleIdTokenVerifier(Builder builder) { super(builder); publicKeys = builder.publicKeys; } /** * Returns the Google public keys manager. * * @since 1.17 */ public final GooglePublicKeysManager getPublicKeysManager() { return publicKeys; } /** * Returns the HTTP transport. * * @since 1.14 */ public final HttpTransport getTransport() { return publicKeys.getTransport(); } /** Returns the JSON factory. */ public final JsonFactory getJsonFactory() { return publicKeys.getJsonFactory(); } /** * Returns the public certificates encoded URL. * * @since 1.15 * @deprecated (scheduled to be removed in 1.18) Use {@link #getPublicKeysManager()} and * {@link GooglePublicKeysManager#getPublicCertsEncodedUrl()} instead. */ @Deprecated public final String getPublicCertsEncodedUrl() { return publicKeys.getPublicCertsEncodedUrl(); } /** * Returns the public keys. * * <p> * Upgrade warning: in prior version 1.16 it may return {@code null} and not throw any exceptions, * but starting with version 1.17 it cannot return {@code null} and may throw * {@link GeneralSecurityException} or {@link IOException}. * </p> * * @deprecated (scheduled to be removed in 1.18) Use {@link #getPublicKeysManager()} and * {@link GooglePublicKeysManager#getPublicKeys()} instead. */ @Deprecated public final List<PublicKey> getPublicKeys() throws GeneralSecurityException, IOException { return publicKeys.getPublicKeys(); } /** * Returns the expiration time in milliseconds to be used with {@link Clock#currentTimeMillis()} * or {@code 0} for none. * * @deprecated (scheduled to be removed in 1.18) Use {@link #getPublicKeysManager()} and * {@link GooglePublicKeysManager#getExpirationTimeMilliseconds()} instead. */ @Deprecated public final long getExpirationTimeMilliseconds() { return publicKeys.getExpirationTimeMilliseconds(); } /** * Verifies that the given ID token is valid using the cached public keys. * * It verifies: * * <ul> * <li>The RS256 signature, which uses RSA and SHA-256 based on the public keys downloaded from * the public certificate endpoint.</li> * <li>The current time against the issued at and expiration time (allowing for a 5 minute clock * skew).</li> * <li>The issuer is {@code "accounts.google.com"} or {@code "https://accounts.google.com"}.</li> * </ul> * * @param googleIdToken Google ID token * @return {@code true} if verified successfully or {@code false} if failed */ public boolean verify(GoogleIdToken googleIdToken) throws GeneralSecurityException, IOException { // check the payload if (!super.verify(googleIdToken)) { return false; } // verify signature, try all public keys in turn. for (PublicKey publicKey : publicKeys.getPublicKeys()) { if (googleIdToken.verifySignature(publicKey)) { return true; } } return false; } /** * Verifies that the given ID token is valid using {@link #verify(GoogleIdToken)} and returns the * ID token if succeeded. * * @param idTokenString Google ID token string * @return Google ID token if verified successfully or {@code null} if failed * @since 1.9 */ public GoogleIdToken verify(String idTokenString) throws GeneralSecurityException, IOException { GoogleIdToken idToken = GoogleIdToken.parse(getJsonFactory(), idTokenString); return verify(idToken) ? idToken : null; } /** * Downloads the public keys from the public certificates endpoint at * {@link #getPublicCertsEncodedUrl}. * * <p> * This method is automatically called if the public keys have not yet been initialized or if the * expiration time is very close, so normally this doesn't need to be called. Only call this * method explicitly to force the public keys to be updated. * </p> * * @deprecated (scheduled to be removed in 1.18) Use {@link #getPublicKeysManager()} and * {@link GooglePublicKeysManager#refresh()} instead. */ @Deprecated public GoogleIdTokenVerifier loadPublicCerts() throws GeneralSecurityException, IOException { publicKeys.refresh(); return this; } /** * {@link Beta} <br/> * Builder for {@link GoogleIdTokenVerifier}. * * <p> * Implementation is not thread-safe. * </p> * * @since 1.9 */ @Beta public static class Builder extends IdTokenVerifier.Builder { /** Google public keys manager. */ GooglePublicKeysManager publicKeys; /** * @param transport HTTP transport * @param jsonFactory JSON factory */ public Builder(HttpTransport transport, JsonFactory jsonFactory) { this(new GooglePublicKeysManager(transport, jsonFactory)); } /** * @param publicKeys Google public keys manager * * @since 1.17 */ public Builder(GooglePublicKeysManager publicKeys) { this.publicKeys = Preconditions.checkNotNull(publicKeys); setIssuers(Arrays.asList("accounts.google.com", "https://accounts.google.com")); } /** Builds a new instance of {@link GoogleIdTokenVerifier}. */ @Override public GoogleIdTokenVerifier build() { return new GoogleIdTokenVerifier(this); } /** * Returns the Google public keys manager. * * @since 1.17 */ public final GooglePublicKeysManager getPublicCerts() { return publicKeys; } /** Returns the HTTP transport. */ public final HttpTransport getTransport() { return publicKeys.getTransport(); } /** Returns the JSON factory. */ public final JsonFactory getJsonFactory() { return publicKeys.getJsonFactory(); } /** * Returns the public certificates encoded URL. * * @since 1.15 * @deprecated (scheduled to be removed in 1.18) Use {@link #getPublicCerts()} and * {@link GooglePublicKeysManager#getPublicCertsEncodedUrl()} instead. */ @Deprecated public final String getPublicCertsEncodedUrl() { return publicKeys.getPublicCertsEncodedUrl(); } /** * Sets the public certificates encoded URL. * * <p> * The default value is {@link GoogleOAuthConstants#DEFAULT_PUBLIC_CERTS_ENCODED_URL}. * </p> * * <p> * Overriding is only supported for the purpose of calling the super implementation and changing * the return type, but nothing else. * </p> * * @since 1.15 * @deprecated (scheduled to be removed in 1.18) Use * {@link GooglePublicKeysManager.Builder#setPublicCertsEncodedUrl(String)} instead. */ @Deprecated public Builder setPublicCertsEncodedUrl(String publicKeysEncodedUrl) { // TODO(yanivi): make publicKeys field final when this method is removed publicKeys = new GooglePublicKeysManager.Builder(getTransport(), getJsonFactory()) .setPublicCertsEncodedUrl(publicKeysEncodedUrl).setClock(publicKeys.getClock()).build(); return this; } @Override public Builder setIssuer(String issuer) { return (Builder) super.setIssuer(issuer); } /** * @since 1.21.0 */ @Override public Builder setIssuers(Collection<String> issuers) { return (Builder) super.setIssuers(issuers); } @Override public Builder setAudience(Collection<String> audience) { return (Builder) super.setAudience(audience); } @Override public Builder setAcceptableTimeSkewSeconds(long acceptableTimeSkewSeconds) { return (Builder) super.setAcceptableTimeSkewSeconds(acceptableTimeSkewSeconds); } @Override public Builder setClock(Clock clock) { return (Builder) super.setClock(clock); } } }