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

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

There is a newer version: 1.30.1
Show newest version
/*
 * Copyright 2021 Google LLC
 *
 * 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 LLC 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.api.client.http.GenericUrl;
import com.google.api.client.http.HttpHeaders;
import com.google.api.client.http.HttpRequest;
import com.google.api.client.http.HttpResponse;
import com.google.api.client.json.GenericJson;
import com.google.api.client.json.JsonObjectParser;
import com.google.auth.oauth2.IdentityPoolCredentials.IdentityPoolCredentialSource.CredentialFormatType;
import com.google.common.io.CharStreams;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import javax.annotation.Nullable;

/**
 * Url-sourced and file-sourced external account credentials.
 *
 * 

By default, attempts to exchange the external credential for a GCP access token. */ public class IdentityPoolCredentials extends ExternalAccountCredentials { /** * The IdentityPool credential source. Dictates the retrieval method of the external credential, * which can either be through a metadata server or a local file. */ static class IdentityPoolCredentialSource extends ExternalAccountCredentials.CredentialSource { enum IdentityPoolCredentialSourceType { FILE, URL } enum CredentialFormatType { TEXT, JSON } private IdentityPoolCredentialSourceType credentialSourceType; private CredentialFormatType credentialFormatType; private String credentialLocation; @Nullable private String subjectTokenFieldName; @Nullable private Map headers; /** * The source of the 3P credential. * *

If this is a file based 3P credential, the credentials file can be retrieved using the * `file` key. * *

If this is URL-based 3p credential, the metadata server URL can be retrieved using the * `url` key. * *

The third party credential can be provided in different formats, such as text or JSON. The * format can be specified using the `format` header, which returns a map with keys `type` and * `subject_token_field_name`. If the `type` is json, the `subject_token_field_name` must be * provided. If no format is provided, we expect the token to be in the raw text format. * *

Optional headers can be present, and should be keyed by `headers`. */ IdentityPoolCredentialSource(Map credentialSourceMap) { super(credentialSourceMap); if (credentialSourceMap.containsKey("file") && credentialSourceMap.containsKey("url")) { throw new IllegalArgumentException( "Only one credential source type can be set, either file or url."); } if (credentialSourceMap.containsKey("file")) { credentialLocation = (String) credentialSourceMap.get("file"); credentialSourceType = IdentityPoolCredentialSourceType.FILE; } else if (credentialSourceMap.containsKey("url")) { credentialLocation = (String) credentialSourceMap.get("url"); credentialSourceType = IdentityPoolCredentialSourceType.URL; } else { throw new IllegalArgumentException( "Missing credential source file location or URL. At least one must be specified."); } Map headersMap = (Map) credentialSourceMap.get("headers"); if (headersMap != null && !headersMap.isEmpty()) { headers = new HashMap<>(); headers.putAll(headersMap); } // If the format is not provided, we expect the token to be in the raw text format. credentialFormatType = CredentialFormatType.TEXT; Map formatMap = (Map) credentialSourceMap.get("format"); if (formatMap != null && formatMap.containsKey("type")) { String type = formatMap.get("type"); if (type != null && "json".equals(type.toLowerCase(Locale.US))) { // For JSON, the subject_token field name must be provided. if (!formatMap.containsKey("subject_token_field_name")) { throw new IllegalArgumentException( "When specifying a JSON credential type, the subject_token_field_name must be set."); } credentialFormatType = CredentialFormatType.JSON; subjectTokenFieldName = formatMap.get("subject_token_field_name"); } else if (type != null && "text".equals(type.toLowerCase(Locale.US))) { credentialFormatType = CredentialFormatType.TEXT; } else { throw new IllegalArgumentException( String.format("Invalid credential source format type: %s.", type)); } } } private boolean hasHeaders() { return headers != null && !headers.isEmpty(); } } private final IdentityPoolCredentialSource identityPoolCredentialSource; /** Internal constructor. See {@link Builder}. */ IdentityPoolCredentials(Builder builder) { super(builder); this.identityPoolCredentialSource = (IdentityPoolCredentialSource) builder.credentialSource; } @Override public AccessToken refreshAccessToken() throws IOException { String credential = retrieveSubjectToken(); StsTokenExchangeRequest.Builder stsTokenExchangeRequest = StsTokenExchangeRequest.newBuilder(credential, getSubjectTokenType()) .setAudience(getAudience()); Collection scopes = getScopes(); if (scopes != null && !scopes.isEmpty()) { stsTokenExchangeRequest.setScopes(new ArrayList<>(scopes)); } return exchangeExternalCredentialForAccessToken(stsTokenExchangeRequest.build()); } @Override public String retrieveSubjectToken() throws IOException { if (identityPoolCredentialSource.credentialSourceType == IdentityPoolCredentialSource.IdentityPoolCredentialSourceType.FILE) { return retrieveSubjectTokenFromCredentialFile(); } return getSubjectTokenFromMetadataServer(); } private String retrieveSubjectTokenFromCredentialFile() throws IOException { String credentialFilePath = identityPoolCredentialSource.credentialLocation; if (!Files.exists(Paths.get(credentialFilePath), LinkOption.NOFOLLOW_LINKS)) { throw new IOException( String.format( "Invalid credential location. The file at %s does not exist.", credentialFilePath)); } try { return parseToken(new FileInputStream(new File(credentialFilePath))); } catch (IOException e) { throw new IOException( "Error when attempting to read the subject token from the credential file.", e); } } private String parseToken(InputStream inputStream) throws IOException { if (identityPoolCredentialSource.credentialFormatType == CredentialFormatType.TEXT) { BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)); return CharStreams.toString(reader); } JsonObjectParser parser = new JsonObjectParser(OAuth2Utils.JSON_FACTORY); GenericJson fileContents = parser.parseAndClose(inputStream, StandardCharsets.UTF_8, GenericJson.class); if (!fileContents.containsKey(identityPoolCredentialSource.subjectTokenFieldName)) { throw new IOException("Invalid subject token field name. No subject token was found."); } return (String) fileContents.get(identityPoolCredentialSource.subjectTokenFieldName); } private String getSubjectTokenFromMetadataServer() throws IOException { HttpRequest request = transportFactory .create() .createRequestFactory() .buildGetRequest(new GenericUrl(identityPoolCredentialSource.credentialLocation)); request.setParser(new JsonObjectParser(OAuth2Utils.JSON_FACTORY)); if (identityPoolCredentialSource.hasHeaders()) { HttpHeaders headers = new HttpHeaders(); headers.putAll(identityPoolCredentialSource.headers); request.setHeaders(headers); } try { HttpResponse response = request.execute(); return parseToken(response.getContent()); } catch (IOException e) { throw new IOException( String.format("Error getting subject token from metadata server: %s", e.getMessage()), e); } } /** Clones the IdentityPoolCredentials with the specified scopes. */ @Override public IdentityPoolCredentials createScoped(Collection newScopes) { return new IdentityPoolCredentials( (IdentityPoolCredentials.Builder) newBuilder(this).setScopes(newScopes)); } public static Builder newBuilder() { return new Builder(); } public static Builder newBuilder(IdentityPoolCredentials identityPoolCredentials) { return new Builder(identityPoolCredentials); } public static class Builder extends ExternalAccountCredentials.Builder { Builder() {} Builder(IdentityPoolCredentials credentials) { super(credentials); } public Builder setWorkforcePoolUserProject(String workforcePoolUserProject) { super.setWorkforcePoolUserProject(workforcePoolUserProject); return this; } @Override public IdentityPoolCredentials build() { return new IdentityPoolCredentials(this); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy