All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.auth.oauth2.DefaultCredentialsProvider Maven / Gradle / Ivy

There is a newer version: 1.30.0
Show newest version
/*
 * Copyright 2015, Google Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *    * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *    * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *
 *    * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package com.google.auth.oauth2;

import com.google.auth.http.HttpTransportFactory;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.AccessControlException;
import java.util.Collections;
import java.util.Locale;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Provides the Application Default Credential from the environment.
 *
 * 

An instance represents the per-process state used to get and cache the credential and allows * overriding the state and environment for testing purposes. */ class DefaultCredentialsProvider { static final DefaultCredentialsProvider DEFAULT = new DefaultCredentialsProvider(); static final String CREDENTIAL_ENV_VAR = "GOOGLE_APPLICATION_CREDENTIALS"; static final String QUOTA_PROJECT_ENV_VAR = "GOOGLE_CLOUD_QUOTA_PROJECT"; static final String WELL_KNOWN_CREDENTIALS_FILE = "application_default_credentials.json"; static final String CLOUDSDK_CONFIG_DIRECTORY = "gcloud"; static final String APP_ENGINE_SIGNAL_CLASS = "com.google.appengine.api.utils.SystemProperty"; static final String CLOUD_SHELL_ENV_VAR = "DEVSHELL_CLIENT_PORT"; static final String SKIP_APP_ENGINE_ENV_VAR = "GOOGLE_APPLICATION_CREDENTIALS_SKIP_APP_ENGINE"; static final String SPECIFICATION_VERSION = System.getProperty("java.specification.version"); static final String GAE_RUNTIME_VERSION = System.getProperty("com.google.appengine.runtime.version"); static final String RUNTIME_JETTY_LOGGER = System.getProperty("org.eclipse.jetty.util.log.class"); static final Logger LOGGER = Logger.getLogger(DefaultCredentialsProvider.class.getName()); static final String NO_GCE_CHECK_ENV_VAR = "NO_GCE_CHECK"; static final String GCE_METADATA_HOST_ENV_VAR = "GCE_METADATA_HOST"; static final String CLOUDSDK_CLIENT_ID = "764086051850-6qr4p6gpi6hn506pt8ejuq83di341hur.apps.googleusercontent.com"; static final String CLOUDSDK_CREDENTIALS_WARNING = "You are authenticating using user credentials. " + "For production, we recommend using service account credentials.\n\n" + "To learn more about service account credentials, see " + "http://cloud.google.com/docs/authentication/external/set-up-adc-on-cloud"; static final String CLOUDSDK_MISSING_CREDENTIALS = "Your default credentials were not found. To set up Application Default Credentials " + "for your environment, see " + "https://cloud.google.com/docs/authentication/external/set-up-adc."; public static final String SUPPRESS_GCLOUD_CREDS_WARNING_ENV_VAR = "SUPPRESS_GCLOUD_CREDS_WARNING"; // These variables should only be accessed inside a synchronized block private GoogleCredentials cachedCredentials = null; private boolean checkedAppEngine = false; private boolean checkedComputeEngine = false; DefaultCredentialsProvider() {} /** * Returns the Application Default Credentials. * *

Returns the Application Default Credentials which are used to identify and authorize the * whole application. The following are searched (in order) to find the Application Default * Credentials: * *

    *
  1. Credentials file pointed to by the {@code GOOGLE_APPLICATION_CREDENTIALS} environment * variable *
  2. Credentials provided by the Google Cloud SDK {@code gcloud auth application-default * login} command *
  3. Google App Engine built-in credentials *
  4. Google Cloud Shell built-in credentials *
  5. Google Compute Engine built-in credentials *
* * @param transportFactory HTTP transport factory, creates the transport used to get access * tokens. * @return the credentials instance. * @throws IOException if the credentials cannot be created in the current environment. */ final GoogleCredentials getDefaultCredentials(HttpTransportFactory transportFactory) throws IOException { synchronized (this) { if (cachedCredentials == null) { cachedCredentials = getDefaultCredentialsUnsynchronized(transportFactory); } if (cachedCredentials != null) { return cachedCredentials; } } throw new IOException(CLOUDSDK_MISSING_CREDENTIALS); } private final GoogleCredentials getDefaultCredentialsUnsynchronized( HttpTransportFactory transportFactory) throws IOException { // First try the environment variable GoogleCredentials credentials = null; String credentialsPath = getEnv(CREDENTIAL_ENV_VAR); if (credentialsPath != null && credentialsPath.length() > 0) { LOGGER.log( Level.FINE, String.format("Attempting to load credentials from file: %s", credentialsPath)); InputStream credentialsStream = null; try { File credentialsFile = new File(credentialsPath); if (!isFile(credentialsFile)) { // Path will be put in the message from the catch block below throw new IOException("File does not exist."); } credentialsStream = readStream(credentialsFile); credentials = GoogleCredentials.fromStream(credentialsStream, transportFactory); } catch (IOException e) { // Although it is also the cause, the message of the caught exception can have very // important information for diagnosing errors, so include its message in the // outer exception message also. throw new IOException( String.format( "Error reading credential file from environment variable %s, value '%s': %s", CREDENTIAL_ENV_VAR, credentialsPath, e.getMessage()), e); } catch (AccessControlException expected) { // Exception querying file system is expected on App-Engine } finally { if (credentialsStream != null) { credentialsStream.close(); } } } // Then try the well-known file if (credentials == null) { File wellKnownFileLocation = getWellKnownCredentialsFile(); InputStream credentialsStream = null; try { if (isFile(wellKnownFileLocation)) { LOGGER.log( Level.FINE, String.format( "Attempting to load credentials from well known file: %s", wellKnownFileLocation.getCanonicalPath())); credentialsStream = readStream(wellKnownFileLocation); credentials = GoogleCredentials.fromStream(credentialsStream, transportFactory); } } catch (IOException e) { throw new IOException( String.format( "Error reading credential file from location %s: %s", wellKnownFileLocation, e.getMessage())); } catch (AccessControlException expected) { // Exception querying file system is expected on App-Engine } finally { if (credentialsStream != null) { credentialsStream.close(); } } warnAboutProblematicCredentials(credentials); } // Then try GAE 7 standard environment if (credentials == null && isOnGAEStandard7() && !skipAppEngineCredentialsCheck()) { LOGGER.log(Level.FINE, "Attempting to load credentials from GAE 7 Standard"); credentials = tryGetAppEngineCredential(); } // Then try Cloud Shell. This must be done BEFORE checking // Compute Engine, as Cloud Shell runs on GCE VMs. if (credentials == null) { LOGGER.log(Level.FINE, "Attempting to load credentials from Cloud Shell"); credentials = tryGetCloudShellCredentials(); } // Then try Compute Engine and GAE 8 standard environment if (credentials == null) { LOGGER.log(Level.FINE, "Attempting to load credentials from GCE"); credentials = tryGetComputeCredentials(transportFactory); } if (credentials != null) { String quotaFromEnv = getEnv(QUOTA_PROJECT_ENV_VAR); if (quotaFromEnv != null && quotaFromEnv.trim().length() > 0) { credentials = credentials.createWithQuotaProject(quotaFromEnv); } } return credentials; } private final File getWellKnownCredentialsFile() { return GoogleAuthUtils.getWellKnownCredentialsFile(this); } private void warnAboutProblematicCredentials(GoogleCredentials credentials) { if (credentials instanceof UserCredentials && !Boolean.parseBoolean(getEnv(SUPPRESS_GCLOUD_CREDS_WARNING_ENV_VAR)) && ComputeEngineCredentials.checkStaticGceDetection(this)) { LOGGER.log(Level.WARNING, CLOUDSDK_CREDENTIALS_WARNING); } } private boolean runningOnAppEngine() { Class systemPropertyClass = null; try { systemPropertyClass = forName(APP_ENGINE_SIGNAL_CLASS); } catch (ClassNotFoundException expected) { // SystemProperty will always be present on App Engine. return false; } Exception cause; Field environmentField; try { environmentField = systemPropertyClass.getField("environment"); Object environmentValue = environmentField.get(null); Class environmentType = environmentField.getType(); Method valueMethod = environmentType.getMethod("value"); Object environmentValueValue = valueMethod.invoke(environmentValue); return (environmentValueValue != null); } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException | NoSuchMethodException | InvocationTargetException exception) { cause = exception; } throw new RuntimeException( String.format( "Unexpected error trying to determine if runnning on Google App Engine: %s", cause.getMessage()), cause); } private GoogleCredentials tryGetCloudShellCredentials() { String port = getEnv(CLOUD_SHELL_ENV_VAR); if (port != null) { return CloudShellCredentials.create(Integer.parseInt(port)); } else { return null; } } private GoogleCredentials tryGetAppEngineCredential() throws IOException { // Checking for App Engine requires a class load, so check only once if (checkedAppEngine) { return null; } boolean onAppEngine = runningOnAppEngine(); checkedAppEngine = true; if (!onAppEngine) { return null; } return new AppEngineCredentials( Collections.emptyList(), Collections.emptyList()); } private final GoogleCredentials tryGetComputeCredentials(HttpTransportFactory transportFactory) { // Checking compute engine requires a round-trip, so check only once if (checkedComputeEngine) { return null; } boolean runningOnComputeEngine = ComputeEngineCredentials.isOnGce(transportFactory, this); checkedComputeEngine = true; if (runningOnComputeEngine) { return ComputeEngineCredentials.newBuilder() .setHttpTransportFactory(transportFactory) .build(); } return null; } // Skip app engine check if environment variable // GOOGLE_APPLICATION_CREDENTIALS_SKIP_APP_ENGINE = 1 or true private boolean skipAppEngineCredentialsCheck() { boolean skip = false; // do not skip by default String value = getEnv(SKIP_APP_ENGINE_ENV_VAR); if (value != null) { skip = value.equalsIgnoreCase("true") || value.equals("1"); } return skip; } protected boolean isOnGAEStandard7() { return GAE_RUNTIME_VERSION != null && (SPECIFICATION_VERSION.equals("1.7") || RUNTIME_JETTY_LOGGER == null); } String getOsName() { return getProperty("os.name", "").toLowerCase(Locale.US); } /* * Start of methods to allow overriding in the test code to isolate from the environment. */ Class forName(String className) throws ClassNotFoundException { return Class.forName(className); } String getEnv(String name) { return System.getenv(name); } String getProperty(String property, String def) { return System.getProperty(property, def); } boolean isFile(File file) { return file.isFile(); } InputStream readStream(File file) throws FileNotFoundException { return new FileInputStream(file); } /* * End of methods to allow overriding in the test code to isolate from the environment. */ }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy