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

com.google.firebase.auth.internal.CryptoSigners Maven / Gradle / Ivy

Go to download

This is the official Firebase Admin Java SDK. Build extraordinary native JVM apps in minutes with Firebase. The Firebase platform can power your app’s backend, user authentication, static hosting, and more.

There is a newer version: 9.4.1
Show newest version
package com.google.firebase.auth.internal;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;

import com.google.api.client.http.GenericUrl;
import com.google.api.client.http.HttpRequest;
import com.google.api.client.http.HttpRequestFactory;
import com.google.api.client.http.HttpResponse;
import com.google.api.client.http.HttpResponseInterceptor;
import com.google.api.client.http.json.JsonHttpContent;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.JsonObjectParser;
import com.google.api.client.util.Key;
import com.google.api.client.util.StringUtils;
import com.google.auth.ServiceAccountSigner;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.auth.oauth2.ServiceAccountCredentials;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
import com.google.common.io.BaseEncoding;
import com.google.common.io.ByteStreams;
import com.google.firebase.FirebaseApp;
import com.google.firebase.FirebaseOptions;
import com.google.firebase.ImplFirebaseTrampolines;
import com.google.firebase.internal.FirebaseRequestInitializer;
import com.google.firebase.internal.NonNull;
import java.io.IOException;
import java.util.Map;

/**
 * A set of {@link CryptoSigner} implementations and utilities for interacting with them.
 */
class CryptoSigners {

  private static final String METADATA_SERVICE_URL =
      "http://metadata/computeMetadata/v1/instance/service-accounts/default/email";

  /**
   * A {@link CryptoSigner} implementation that uses service account credentials or equivalent
   * crypto-capable credentials for signing data.
   */
  static class ServiceAccountCryptoSigner implements CryptoSigner {

    private final ServiceAccountSigner signer;

    ServiceAccountCryptoSigner(@NonNull ServiceAccountSigner signer) {
      this.signer = checkNotNull(signer);
    }

    @Override
    public byte[] sign(byte[] payload) {
      return signer.sign(payload);
    }

    @Override
    public String getAccount() {
      return signer.getAccount();
    }
  }

  /**
   * @ {@link CryptoSigner} implementation that uses the
   * 
   * Google IAM service to sign data.
   */
  static class IAMCryptoSigner implements CryptoSigner {

    private static final String IAM_SIGN_BLOB_URL =
        "https://iam.googleapis.com/v1/projects/-/serviceAccounts/%s:signBlob";

    private final HttpRequestFactory requestFactory;
    private final JsonFactory jsonFactory;
    private final String serviceAccount;
    private HttpResponseInterceptor interceptor;

    IAMCryptoSigner(
        @NonNull HttpRequestFactory requestFactory,
        @NonNull JsonFactory jsonFactory,
        @NonNull String serviceAccount) {
      this.requestFactory = checkNotNull(requestFactory);
      this.jsonFactory = checkNotNull(jsonFactory);
      checkArgument(!Strings.isNullOrEmpty(serviceAccount));
      this.serviceAccount = serviceAccount;
    }

    void setInterceptor(HttpResponseInterceptor interceptor) {
      this.interceptor = interceptor;
    }

    @Override
    public byte[] sign(byte[] payload) throws IOException {
      String encodedUrl = String.format(IAM_SIGN_BLOB_URL, serviceAccount);
      HttpResponse response = null;
      String encodedPayload = BaseEncoding.base64().encode(payload);
      Map content = ImmutableMap.of("bytesToSign", encodedPayload);
      try {
        HttpRequest request = requestFactory.buildPostRequest(new GenericUrl(encodedUrl),
            new JsonHttpContent(jsonFactory, content));
        request.setParser(new JsonObjectParser(jsonFactory));
        request.setResponseInterceptor(interceptor);
        response = request.execute();
        SignBlobResponse parsed = response.parseAs(SignBlobResponse.class);
        return BaseEncoding.base64().decode(parsed.signature);
      } finally {
        if (response != null) {
          try {
            response.disconnect();
          } catch (IOException ignored) {
            // Ignored
          }
        }
      }
    }

    @Override
    public String getAccount() {
      return serviceAccount;
    }
  }

  public static class SignBlobResponse {
    @Key("signature")
    private String signature;
  }

  /**
   * Initializes a {@link CryptoSigner} instance for the given Firebase app. Follows the protocol
   * documented at go/firebase-admin-sign.
   */
  static CryptoSigner getCryptoSigner(FirebaseApp firebaseApp) throws IOException {
    GoogleCredentials credentials = ImplFirebaseTrampolines.getCredentials(firebaseApp);

    // If the SDK was initialized with a service account, use it to sign bytes.
    if (credentials instanceof ServiceAccountCredentials) {
      return new ServiceAccountCryptoSigner((ServiceAccountCredentials) credentials);
    }

    FirebaseOptions options = firebaseApp.getOptions();
    HttpRequestFactory requestFactory = options.getHttpTransport().createRequestFactory(
        new FirebaseRequestInitializer(firebaseApp));
    JsonFactory jsonFactory = options.getJsonFactory();

    // If the SDK was initialized with a service account email, use it with the IAM service
    // to sign bytes.
    String serviceAccountId = options.getServiceAccountId();
    if (!Strings.isNullOrEmpty(serviceAccountId)) {
      return new IAMCryptoSigner(requestFactory, jsonFactory, serviceAccountId);
    }

    // If the SDK was initialized with some other credential type that supports signing
    // (e.g. GAE credentials), use it to sign bytes.
    if (credentials instanceof ServiceAccountSigner) {
      return new ServiceAccountCryptoSigner((ServiceAccountSigner) credentials);
    }

    // Attempt to discover a service account email from the local Metadata service. Use it
    // with the IAM service to sign bytes.
    HttpRequest request = requestFactory.buildGetRequest(new GenericUrl(METADATA_SERVICE_URL));
    request.getHeaders().set("Metadata-Flavor", "Google");
    HttpResponse response = request.execute();
    try {
      byte[] output = ByteStreams.toByteArray(response.getContent());
      serviceAccountId = StringUtils.newStringUtf8(output).trim();
      return new IAMCryptoSigner(requestFactory, jsonFactory, serviceAccountId);
    } finally {
      response.disconnect();
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy