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

com.google.api.client.googleapis.auth.oauth2.GoogleCredential Maven / Gradle / Ivy

There is a newer version: 2.7.0
Show newest version
/*
 * Copyright 2011 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.oauth2.BearerToken;
import com.google.api.client.auth.oauth2.ClientParametersAuthentication;
import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.auth.oauth2.CredentialRefreshListener;
import com.google.api.client.auth.oauth2.DataStoreCredentialRefreshListener;
import com.google.api.client.auth.oauth2.TokenRequest;
import com.google.api.client.auth.oauth2.TokenResponse;
import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets.Details;
import com.google.api.client.googleapis.util.Utils;
import com.google.api.client.http.GenericUrl;
import com.google.api.client.http.HttpExecuteInterceptor;
import com.google.api.client.http.HttpRequestInitializer;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.HttpUnsuccessfulResponseHandler;
import com.google.api.client.json.GenericJson;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.JsonObjectParser;
import com.google.api.client.json.webtoken.JsonWebSignature;
import com.google.api.client.json.webtoken.JsonWebToken;
import com.google.api.client.util.Beta;
import com.google.api.client.util.Clock;
import com.google.api.client.util.Joiner;
import com.google.api.client.util.PemReader;
import com.google.api.client.util.PemReader.Section;
import com.google.api.client.util.Preconditions;
import com.google.api.client.util.SecurityUtils;
import com.google.api.client.util.store.DataStoreFactory;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.io.StringReader;
import java.security.GeneralSecurityException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Collection;
import java.util.Collections;

/**
 * Thread-safe Google-specific implementation of the OAuth 2.0 helper for accessing protected
 * resources using an access token, as well as optionally refreshing the access token when it
 * expires using a refresh token.
 *
 * 

There are three modes supported: access token only, refresh token flow, and service account * flow (with or without impersonating a user). * *

If all you have is an access token, you simply pass the {@link TokenResponse} to the * credential using {@link Builder#setFromTokenResponse(TokenResponse)}. Google credential uses * {@link BearerToken#authorizationHeaderAccessMethod()} as the access method. Sample usage: * *

{@code
 * public static GoogleCredential createCredentialWithAccessTokenOnly(TokenResponse tokenResponse) {
 *   return new GoogleCredential().setFromTokenResponse(tokenResponse);
 * }
 * }
* *

If you have a refresh token, it is similar to the case of access token only, but you * additionally need to pass the credential the client secrets using {@link * Builder#setClientSecrets(GoogleClientSecrets)} or {@link Builder#setClientSecrets(String, * String)}. Google credential uses {@link GoogleOAuthConstants#TOKEN_SERVER_URL} as the token * server URL, and {@link ClientParametersAuthentication} with the client ID and secret as the * client authentication. Sample usage: * *

{@code
 * public static GoogleCredential createCredentialWithRefreshToken(
 *     HttpTransport transport, JsonFactory jsonFactory,
 *     GoogleClientSecrets clientSecrets, TokenResponse tokenResponse) {
 *  return new GoogleCredential.Builder().setTransport(transport)
 *                        .setJsonFactory(jsonFactory)
 *                        .setClientSecrets(clientSecrets)
 *                        .build()
 *                        .setFromTokenResponse(tokenResponse);
 * }
 * }
* *

The service * account flow is used when you want to access data owned by your client application. You * download the private key in a {@code .p12} file from the Google APIs Console. Use {@link * Builder#setServiceAccountId(String)}, {@link * Builder#setServiceAccountPrivateKeyFromP12File(File)}, and {@link * Builder#setServiceAccountScopes(Collection)}. Sample usage: * *

{@code
 * public static GoogleCredential createCredentialForServiceAccount(HttpTransport transport,
 *     JsonFactory jsonFactory,
 *     String serviceAccountId, Collection<String> serviceAccountScopes, File p12File)
 *     throws GeneralSecurityException, IOException {
 *   return new GoogleCredential.Builder().setTransport(transport).setJsonFactory(jsonFactory)
 *       .setServiceAccountId(serviceAccountId).setServiceAccountScopes(serviceAccountScopes)
 *       .setServiceAccountPrivateKeyFromP12File(p12File).build();
 * }
 * }
* *

You can also use the service account flow to impersonate a user in a domain that you own. This * is very similar to the service account flow above, but you additionally call {@link * Builder#setServiceAccountUser(String)}. Sample usage: * *

{@code
 * public static GoogleCredential createCredentialForServiceAccountImpersonateUser
 *     (HttpTransport transport, JsonFactory jsonFactory, String serviceAccountId,
 *      Collection<String> serviceAccountScopes, File p12File,
 *      String serviceAccountUser) throws GeneralSecurityException, IOException {
 *   return new GoogleCredential.Builder()
 *       .setTransport(transport)
 *       .setJsonFactory(jsonFactory)
 *       .setServiceAccountId(serviceAccountId)
 *       .setServiceAccountScopes(serviceAccountScopes)
 *       .setServiceAccountPrivateKeyFromP12File(p12File)
 *       .setServiceAccountUser(serviceAccountUser)
 *       .build();
 * }
 * }
* *

If you need to persist the access token in a data store, use {@link DataStoreFactory} and * {@link Builder#addRefreshListener(CredentialRefreshListener)} with {@link * DataStoreCredentialRefreshListener}. * *

If you have a custom request initializer, request execute interceptor, or unsuccessful * response handler, take a look at the sample usage for {@link HttpExecuteInterceptor} and {@link * HttpUnsuccessfulResponseHandler}, which are interfaces that this class also implements. * * @since 1.7 * @author Yaniv Inbar * @deprecated Please use * google-auth-library for handling Application Default Credentials and other non-OAuth2 * based authentication. */ @Deprecated public class GoogleCredential extends Credential { static final String USER_FILE_TYPE = "authorized_user"; static final String SERVICE_ACCOUNT_FILE_TYPE = "service_account"; @Beta private static DefaultCredentialProvider defaultCredentialProvider = new DefaultCredentialProvider(); /** * {@link Beta}
* Returns the Application Default Credentials. * *

Returns the Application Default Credentials which are credentials that identify and * authorize the whole application. This is the built-in service account if running on Google * Compute Engine or the credentials file from the path in the environment variable * GOOGLE_APPLICATION_CREDENTIALS. * * @return the credential instance. * @throws IOException if the credential cannot be created in the current environment. */ @Beta public static GoogleCredential getApplicationDefault() throws IOException { return getApplicationDefault(Utils.getDefaultTransport(), Utils.getDefaultJsonFactory()); } /** * {@link Beta}
* Returns the Application Default Credentials. * *

Returns the Application Default Credentials which are credentials that identify and * authorize the whole application. This is the built-in service account if running on Google * Compute Engine or the credentials file from the path in the environment variable * GOOGLE_APPLICATION_CREDENTIALS. * * @param transport the transport for Http calls. * @param jsonFactory the factory for Json parsing and formatting. * @return the credential instance. * @throws IOException if the credential cannot be created in the current environment. */ @Beta public static GoogleCredential getApplicationDefault( HttpTransport transport, JsonFactory jsonFactory) throws IOException { Preconditions.checkNotNull(transport); Preconditions.checkNotNull(jsonFactory); return defaultCredentialProvider.getDefaultCredential(transport, jsonFactory); } /** * {@link Beta}
* Return a credential defined by a Json file. * * @param credentialStream the stream with the credential definition. * @return the credential defined by the credentialStream. * @throws IOException if the credential cannot be created from the stream. */ @Beta public static GoogleCredential fromStream(InputStream credentialStream) throws IOException { return fromStream(credentialStream, Utils.getDefaultTransport(), Utils.getDefaultJsonFactory()); } /** * {@link Beta}
* Return a credential defined by a Json file. * * @param credentialStream the stream with the credential definition. * @param transport the transport for Http calls. * @param jsonFactory the factory for Json parsing and formatting. * @return the credential defined by the credentialStream. * @throws IOException if the credential cannot be created from the stream. */ @Beta public static GoogleCredential fromStream( InputStream credentialStream, HttpTransport transport, JsonFactory jsonFactory) throws IOException { Preconditions.checkNotNull(credentialStream); Preconditions.checkNotNull(transport); Preconditions.checkNotNull(jsonFactory); JsonObjectParser parser = new JsonObjectParser(jsonFactory); GenericJson fileContents = parser.parseAndClose(credentialStream, OAuth2Utils.UTF_8, GenericJson.class); String fileType = (String) fileContents.get("type"); if (fileType == null) { throw new IOException("Error reading credentials from stream, 'type' field not specified."); } if (USER_FILE_TYPE.equals(fileType)) { return fromStreamUser(fileContents, transport, jsonFactory); } if (SERVICE_ACCOUNT_FILE_TYPE.equals(fileType)) { return fromStreamServiceAccount(fileContents, transport, jsonFactory); } throw new IOException( String.format( "Error reading credentials from stream, 'type' value '%s' not recognized." + " Expecting '%s' or '%s'.", fileType, USER_FILE_TYPE, SERVICE_ACCOUNT_FILE_TYPE)); } /** * Service account ID (typically an e-mail address) or {@code null} if not using the service * account flow. */ private String serviceAccountId; /** * Service account Project ID or {@code null} if not present, either because this is not using the * service account flow, or is using an older version of the service account configuration. */ private String serviceAccountProjectId; /** * Collection of OAuth scopes to use with the service account flow or {@code null} if not using * the service account flow. */ private Collection serviceAccountScopes; /** * Private key to use with the service account flow or {@code null} if not using the service * account flow. */ private PrivateKey serviceAccountPrivateKey; /** * ID of private key to use with the service account flow or {@code null} if not using the service * account flow. */ private String serviceAccountPrivateKeyId; /** * Email address of the user the application is trying to impersonate in the service account flow * or {@code null} for none or if not using the service account flow. */ private String serviceAccountUser; /** * Constructor with the ability to access protected resources, but not refresh tokens. * *

To use with the ability to refresh tokens, use {@link Builder}. */ public GoogleCredential() { this(new Builder()); } /** * @param builder Google credential builder * @since 1.14 */ protected GoogleCredential(Builder builder) { super(builder); if (builder.serviceAccountPrivateKey == null) { Preconditions.checkArgument( builder.serviceAccountId == null && builder.serviceAccountScopes == null && builder.serviceAccountUser == null); } else { serviceAccountId = Preconditions.checkNotNull(builder.serviceAccountId); serviceAccountProjectId = builder.serviceAccountProjectId; serviceAccountScopes = (builder.serviceAccountScopes == null) ? Collections.emptyList() : Collections.unmodifiableCollection(builder.serviceAccountScopes); serviceAccountPrivateKey = builder.serviceAccountPrivateKey; serviceAccountPrivateKeyId = builder.serviceAccountPrivateKeyId; serviceAccountUser = builder.serviceAccountUser; } } @Override public GoogleCredential setAccessToken(String accessToken) { return (GoogleCredential) super.setAccessToken(accessToken); } @Override public GoogleCredential setRefreshToken(String refreshToken) { if (refreshToken != null) { Preconditions.checkArgument( getJsonFactory() != null && getTransport() != null && getClientAuthentication() != null, "Please use the Builder and call setJsonFactory, setTransport and setClientSecrets"); } return (GoogleCredential) super.setRefreshToken(refreshToken); } @Override public GoogleCredential setExpirationTimeMilliseconds(Long expirationTimeMilliseconds) { return (GoogleCredential) super.setExpirationTimeMilliseconds(expirationTimeMilliseconds); } @Override public GoogleCredential setExpiresInSeconds(Long expiresIn) { return (GoogleCredential) super.setExpiresInSeconds(expiresIn); } @Override public GoogleCredential setFromTokenResponse(TokenResponse tokenResponse) { return (GoogleCredential) super.setFromTokenResponse(tokenResponse); } @Override @Beta protected TokenResponse executeRefreshToken() throws IOException { if (serviceAccountPrivateKey == null) { return super.executeRefreshToken(); } // service accounts: no refresh token; instead use private key to request new access token JsonWebSignature.Header header = new JsonWebSignature.Header(); header.setAlgorithm("RS256"); header.setType("JWT"); header.setKeyId(serviceAccountPrivateKeyId); JsonWebToken.Payload payload = new JsonWebToken.Payload(); long currentTime = getClock().currentTimeMillis(); payload.setIssuer(serviceAccountId); payload.setAudience(getTokenServerEncodedUrl()); payload.setIssuedAtTimeSeconds(currentTime / 1000); payload.setExpirationTimeSeconds(currentTime / 1000 + 3600); payload.setSubject(serviceAccountUser); payload.put("scope", Joiner.on(' ').join(serviceAccountScopes)); try { String assertion = JsonWebSignature.signUsingRsaSha256( serviceAccountPrivateKey, getJsonFactory(), header, payload); TokenRequest request = new TokenRequest( getTransport(), getJsonFactory(), new GenericUrl(getTokenServerEncodedUrl()), "urn:ietf:params:oauth:grant-type:jwt-bearer"); request.put("assertion", assertion); return request.execute(); } catch (GeneralSecurityException exception) { IOException e = new IOException(); e.initCause(exception); throw e; } } /** * Returns the service account ID (typically an e-mail address) or {@code null} if not using the * service account flow. */ public final String getServiceAccountId() { return serviceAccountId; } /** * Returns the service account Project ID or {@code null} if not present, either because this is * not using the service account flow, or is using an older version of the service account * configuration. */ public final String getServiceAccountProjectId() { return serviceAccountProjectId; } /** * Returns a collection of OAuth scopes to use with the service account flow or {@code null} if * not using the service account flow. */ public final Collection getServiceAccountScopes() { return serviceAccountScopes; } /** * Returns the space-separated OAuth scopes to use with the service account flow or {@code null} * if not using the service account flow. * * @since 1.15 */ public final String getServiceAccountScopesAsString() { return serviceAccountScopes == null ? null : Joiner.on(' ').join(serviceAccountScopes); } /** * Returns the private key to use with the service account flow or {@code null} if not using the * service account flow. */ public final PrivateKey getServiceAccountPrivateKey() { return serviceAccountPrivateKey; } /** * {@link Beta}
* Returns the ID of the private key to use with the service account flow or {@code null} if not * using the service account flow. */ @Beta public final String getServiceAccountPrivateKeyId() { return serviceAccountPrivateKeyId; } /** * Returns the email address of the user the application is trying to impersonate in the service * account flow or {@code null} for none or if not using the service account flow. */ public final String getServiceAccountUser() { return serviceAccountUser; } /** * {@link Beta}
* Indicates whether the credential requires scopes to be specified by calling createScoped before * use. */ @Beta public boolean createScopedRequired() { if (serviceAccountPrivateKey == null) { return false; } return (serviceAccountScopes == null || serviceAccountScopes.isEmpty()); } /** * {@link Beta}
* For credentials that require scopes, creates a copy of the credential with the specified * scopes. */ @Beta public GoogleCredential createScoped(Collection scopes) { if (serviceAccountPrivateKey == null) { return this; } return toBuilder().setServiceAccountScopes(scopes).build(); } /** * {@link Beta}
* For service accounts that need to delegate to a specific user, create a copy of the credential * with the specified user. */ @Beta public GoogleCredential createDelegated(String user) { if (serviceAccountPrivateKey == null) { return this; } return toBuilder().setServiceAccountUser(user).build(); } /** * {@link Beta}
* Create a builder from this credential. */ @Beta public Builder toBuilder() { Builder builder = new GoogleCredential.Builder() .setServiceAccountPrivateKey(serviceAccountPrivateKey) .setServiceAccountPrivateKeyId(serviceAccountPrivateKeyId) .setServiceAccountId(serviceAccountId) .setServiceAccountProjectId(serviceAccountProjectId) .setServiceAccountUser(serviceAccountUser) .setServiceAccountScopes(serviceAccountScopes) .setTokenServerEncodedUrl(getTokenServerEncodedUrl()) .setTransport(getTransport()) .setJsonFactory(getJsonFactory()) .setClock(getClock()); builder.setClientAuthentication(getClientAuthentication()); return builder; } /** * Google credential builder. * *

Implementation is not thread-safe. */ public static class Builder extends Credential.Builder { /** Service account ID (typically an e-mail address) or {@code null} for none. */ String serviceAccountId; /** Collection of OAuth scopes to use with the service account flow or {@code null} for none. */ Collection serviceAccountScopes; /** Private key to use with the service account flow or {@code null} for none. */ PrivateKey serviceAccountPrivateKey; /** Id of the private key to use with the service account flow or {@code null} for none. */ String serviceAccountPrivateKeyId; /** Project ID associated with the Service Account. */ String serviceAccountProjectId; /** * Email address of the user the application is trying to impersonate in the service account * flow or {@code null} for none. */ String serviceAccountUser; public Builder() { super(BearerToken.authorizationHeaderAccessMethod()); setTokenServerEncodedUrl(GoogleOAuthConstants.TOKEN_SERVER_URL); } @Override public GoogleCredential build() { return new GoogleCredential(this); } @Override public Builder setTransport(HttpTransport transport) { return (Builder) super.setTransport(transport); } @Override public Builder setJsonFactory(JsonFactory jsonFactory) { return (Builder) super.setJsonFactory(jsonFactory); } /** @since 1.9 */ @Override public Builder setClock(Clock clock) { return (Builder) super.setClock(clock); } /** * Sets the client identifier and secret. * *

Overriding is only supported for the purpose of calling the super implementation and * changing the return type, but nothing else. */ public Builder setClientSecrets(String clientId, String clientSecret) { setClientAuthentication(new ClientParametersAuthentication(clientId, clientSecret)); return this; } /** * Sets the client secrets. * *

Overriding is only supported for the purpose of calling the super implementation and * changing the return type, but nothing else. */ public Builder setClientSecrets(GoogleClientSecrets clientSecrets) { Details details = clientSecrets.getDetails(); setClientAuthentication( new ClientParametersAuthentication(details.getClientId(), details.getClientSecret())); return this; } /** Returns the service account ID (typically an e-mail address) or {@code null} for none. */ public final String getServiceAccountId() { return serviceAccountId; } /** * Sets the service account ID (typically an e-mail address) or {@code null} for none. * *

Overriding is only supported for the purpose of calling the super implementation and * changing the return type, but nothing else. */ public Builder setServiceAccountId(String serviceAccountId) { this.serviceAccountId = serviceAccountId; return this; } /** Returns the service account Project ID or {@code null} for none. */ public final String getServiceAccountProjectId() { return serviceAccountProjectId; } /** * Sets the service account Project ID or {@code null} for none. * *

Overriding is only supported for the purpose of calling the super implementation and * changing the return type, but nothing else. */ public Builder setServiceAccountProjectId(String serviceAccountProjectId) { this.serviceAccountProjectId = serviceAccountProjectId; return this; } /** * Returns a collection of OAuth scopes to use with the service account flow or {@code null} for * none. */ public final Collection getServiceAccountScopes() { return serviceAccountScopes; } /** * Sets the space-separated OAuth scopes to use with the service account flow or {@code null} * for none. * *

Overriding is only supported for the purpose of calling the super implementation and * changing the return type, but nothing else. * * @param serviceAccountScopes collection of scopes to be joined by a space separator (or a * single value containing multiple space-separated scopes) * @since 1.15 */ public Builder setServiceAccountScopes(Collection serviceAccountScopes) { this.serviceAccountScopes = serviceAccountScopes; return this; } /** Returns the private key to use with the service account flow or {@code null} for none. */ public final PrivateKey getServiceAccountPrivateKey() { return serviceAccountPrivateKey; } /** * Sets the private key to use with the service account flow or {@code null} for none. * *

Overriding is only supported for the purpose of calling the super implementation and * changing the return type, but nothing else. */ public Builder setServiceAccountPrivateKey(PrivateKey serviceAccountPrivateKey) { this.serviceAccountPrivateKey = serviceAccountPrivateKey; return this; } /** * {@link Beta}
* Returns the id of the private key to use with the service account flow or {@code null} for * none. */ @Beta public final String getServiceAccountPrivateKeyId() { return serviceAccountPrivateKeyId; } /** * {@link Beta}
* Sets the id of the private key to use with the service account flow or {@code null} for none. * *

Overriding is only supported for the purpose of calling the super implementation and * changing the return type, but nothing else. */ @Beta public Builder setServiceAccountPrivateKeyId(String serviceAccountPrivateKeyId) { this.serviceAccountPrivateKeyId = serviceAccountPrivateKeyId; return this; } /** * Sets the private key to use with the service account flow or {@code null} for none. * *

Overriding is only supported for the purpose of calling the super implementation and * changing the return type, but nothing else. * * @param p12File p12 file object */ public Builder setServiceAccountPrivateKeyFromP12File(File p12File) throws GeneralSecurityException, IOException { setServiceAccountPrivateKeyFromP12File(new FileInputStream(p12File)); return this; } /** * Sets the private key to use with the service account flow or {@code null} for none. * *

Overriding is only supported for the purpose of calling the super implementation and * changing the return type, but nothing else. * * @param p12FileInputStream input stream to the p12 file. This file is closed at the end of * this method in a finally block. */ public Builder setServiceAccountPrivateKeyFromP12File(InputStream p12FileInputStream) throws GeneralSecurityException, IOException { serviceAccountPrivateKey = SecurityUtils.loadPrivateKeyFromKeyStore( SecurityUtils.getPkcs12KeyStore(), p12FileInputStream, "notasecret", "privatekey", "notasecret"); return this; } /** * {@link Beta}
* Sets the private key to use with the service account flow or {@code null} for none. * *

Overriding is only supported for the purpose of calling the super implementation and * changing the return type, but nothing else. * * @param pemFile input stream to the PEM file (closed at the end of this method in a finally * block) * @since 1.13 */ @Beta public Builder setServiceAccountPrivateKeyFromPemFile(File pemFile) throws GeneralSecurityException, IOException { byte[] bytes = PemReader.readFirstSectionAndClose(new FileReader(pemFile), "PRIVATE KEY") .getBase64DecodedBytes(); serviceAccountPrivateKey = SecurityUtils.getRsaKeyFactory().generatePrivate(new PKCS8EncodedKeySpec(bytes)); return this; } /** * Returns the email address of the user the application is trying to impersonate in the service * account flow or {@code null} for none. */ public final String getServiceAccountUser() { return serviceAccountUser; } /** * Sets the email address of the user the application is trying to impersonate in the service * account flow or {@code null} for none. * *

Overriding is only supported for the purpose of calling the super implementation and * changing the return type, but nothing else. */ public Builder setServiceAccountUser(String serviceAccountUser) { this.serviceAccountUser = serviceAccountUser; return this; } @Override public Builder setRequestInitializer(HttpRequestInitializer requestInitializer) { return (Builder) super.setRequestInitializer(requestInitializer); } @Override public Builder addRefreshListener(CredentialRefreshListener refreshListener) { return (Builder) super.addRefreshListener(refreshListener); } @Override public Builder setRefreshListeners(Collection refreshListeners) { return (Builder) super.setRefreshListeners(refreshListeners); } @Override public Builder setTokenServerUrl(GenericUrl tokenServerUrl) { return (Builder) super.setTokenServerUrl(tokenServerUrl); } @Override public Builder setTokenServerEncodedUrl(String tokenServerEncodedUrl) { return (Builder) super.setTokenServerEncodedUrl(tokenServerEncodedUrl); } @Override public Builder setClientAuthentication(HttpExecuteInterceptor clientAuthentication) { return (Builder) super.setClientAuthentication(clientAuthentication); } } @Beta private static GoogleCredential fromStreamUser( GenericJson fileContents, HttpTransport transport, JsonFactory jsonFactory) throws IOException { String clientId = (String) fileContents.get("client_id"); String clientSecret = (String) fileContents.get("client_secret"); String refreshToken = (String) fileContents.get("refresh_token"); if (clientId == null || clientSecret == null || refreshToken == null) { throw new IOException( "Error reading user credential from stream, " + " expecting 'client_id', 'client_secret' and 'refresh_token'."); } GoogleCredential credential = new GoogleCredential.Builder() .setClientSecrets(clientId, clientSecret) .setTransport(transport) .setJsonFactory(jsonFactory) .build(); credential.setRefreshToken(refreshToken); // Do a refresh so we can fail early rather than return an unusable credential credential.refreshToken(); return credential; } @Beta private static GoogleCredential fromStreamServiceAccount( GenericJson fileContents, HttpTransport transport, JsonFactory jsonFactory) throws IOException { String clientId = (String) fileContents.get("client_id"); String clientEmail = (String) fileContents.get("client_email"); String privateKeyPem = (String) fileContents.get("private_key"); String privateKeyId = (String) fileContents.get("private_key_id"); if (clientId == null || clientEmail == null || privateKeyPem == null || privateKeyId == null) { throw new IOException( "Error reading service account credential from stream, " + "expecting 'client_id', 'client_email', 'private_key' and 'private_key_id'."); } PrivateKey privateKey = privateKeyFromPkcs8(privateKeyPem); Collection emptyScopes = Collections.emptyList(); Builder credentialBuilder = new GoogleCredential.Builder() .setTransport(transport) .setJsonFactory(jsonFactory) .setServiceAccountId(clientEmail) .setServiceAccountScopes(emptyScopes) .setServiceAccountPrivateKey(privateKey) .setServiceAccountPrivateKeyId(privateKeyId); String tokenUri = (String) fileContents.get("token_uri"); if (tokenUri != null) { credentialBuilder.setTokenServerEncodedUrl(tokenUri); } String projectId = (String) fileContents.get("project_id"); if (projectId != null) { credentialBuilder.setServiceAccountProjectId(projectId); } // Don't do a refresh at this point, as it will always fail before the scopes are added. return credentialBuilder.build(); } @Beta private static PrivateKey privateKeyFromPkcs8(String privateKeyPem) throws IOException { Reader reader = new StringReader(privateKeyPem); Section section = PemReader.readFirstSectionAndClose(reader, "PRIVATE KEY"); if (section == null) { throw new IOException("Invalid PKCS8 data."); } byte[] bytes = section.getBase64DecodedBytes(); PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(bytes); Exception unexpectedException = null; try { KeyFactory keyFactory = SecurityUtils.getRsaKeyFactory(); PrivateKey privateKey = keyFactory.generatePrivate(keySpec); return privateKey; } catch (NoSuchAlgorithmException exception) { unexpectedException = exception; } catch (InvalidKeySpecException exception) { unexpectedException = exception; } throw OAuth2Utils.exceptionWithCause( new IOException("Unexpected exception reading PKCS data"), unexpectedException); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy