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.1
Show newest version
/*
 * Copyright (c) 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: *

* *
  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: *

* *
  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: *

* *
  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: *

* *
  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 */ 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; /** * 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); serviceAccountScopes = 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 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 new GoogleCredential.Builder() .setServiceAccountPrivateKey(serviceAccountPrivateKey) .setServiceAccountPrivateKeyId(serviceAccountPrivateKeyId) .setServiceAccountId(serviceAccountId) .setServiceAccountUser(serviceAccountUser) .setServiceAccountScopes(scopes) .setTokenServerEncodedUrl(getTokenServerEncodedUrl()) .setTransport(getTransport()) .setJsonFactory(getJsonFactory()) .setClock(getClock()) .build(); } /** * 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; /** * 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 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 input stream to the p12 file (closed at the end of this method in a finally * block) */ public Builder setServiceAccountPrivateKeyFromP12File(File p12File) throws GeneralSecurityException, IOException { serviceAccountPrivateKey = SecurityUtils.loadPrivateKeyFromKeyStore( SecurityUtils.getPkcs12KeyStore(), new FileInputStream(p12File), "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); } // 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 - 2025 Weber Informatics LLC | Privacy Policy