com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier.java Source code

Java tutorial

Introduction

Here is the source code for com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier.java

Source

/*
 * 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);
        }
    }
}