Skip to content

FirebaseModelDownloader throws 403 error with API Keys that have app restrictions #2647

@kabeer-uber

Description

@kabeer-uber

[REQUIRED] Step 2: Describe your environment

  • Android Studio version: 4.1.3
  • Firebase Component: FirebaseModelDownloader
  • Component version: 23.0.0

[REQUIRED] Step 3: Describe the problem

getModel() with FirebaseModelDownloader throws a 403 error with Google API keys that have android app restrictions.

Steps to reproduce:

Create any project and add android app restrictions, use this API key with the FirebaseModelDownloader project to trigger ML model downlaods

Screen Shot 2021-05-06 at 6 48 29 PM

API keys without android app restrictions work, hence changing to None does not throw a 403 error.

Screen Shot 2021-05-06 at 6 41 50 PM

Relevant Code:

Code culprit is here as we aren't adding X-Android-Package and X-Android-Cert in the headers and adding only API key.

 @NonNull
  public Task<CustomModel> getCustomModelDetails(
      String projectNumber, String modelName, String modelHash) {
    try {
      URL url =
          new URL(String.format(DOWNLOAD_MODEL_REGEX, downloadHost, projectNumber, modelName));
      HttpURLConnection connection = (HttpURLConnection) url.openConnection();
      connection.setConnectTimeout(CONNECTION_TIME_OUT_MS);
      connection.setRequestProperty(ACCEPT_ENCODING_HEADER_KEY, GZIP_CONTENT_ENCODING);
      connection.setRequestProperty(CONTENT_TYPE, APPLICATION_JSON);
      if (modelHash != null && !modelHash.isEmpty()) {
        connection.setRequestProperty(IF_NONE_MATCH_HEADER_KEY, modelHash);
      }

      Task<InstallationTokenResult> installationAuthTokenTask =
          firebaseInstallations.getToken(false);
      return installationAuthTokenTask.continueWithTask(
          executorService,
          (CustomModelTask) -> {
            if (!installationAuthTokenTask.isSuccessful()) {
              ErrorCode errorCode = ErrorCode.MODEL_INFO_DOWNLOAD_CONNECTION_FAILED;
              String errorMessage = "Failed to get model due to authentication error";
              int exceptionCode = FirebaseMlException.UNAUTHENTICATED;
              if (installationAuthTokenTask.getException() != null
                  && (installationAuthTokenTask.getException() instanceof UnknownHostException
                      || installationAuthTokenTask.getException().getCause()
                          instanceof UnknownHostException)) {
                errorCode = ErrorCode.NO_NETWORK_CONNECTION;
                errorMessage = "Failed to retrieve model info due to no internet connection.";
                exceptionCode = FirebaseMlException.NO_NETWORK_CONNECTION;
              }
              eventLogger.logDownloadFailureWithReason(
                  new CustomModel(modelName, modelHash, 0, 0L), false, errorCode.getValue());
              return Tasks.forException(new FirebaseMlException(errorMessage, exceptionCode));
            }

            connection.setRequestProperty(
                INSTALLATIONS_AUTH_TOKEN_HEADER, installationAuthTokenTask.getResult().getToken());
            connection.setRequestProperty(API_KEY_HEADER, apiKey);
            return fetchDownloadDetails(modelName, connection);
          });

    } catch (IOException e) {
      eventLogger.logDownloadFailureWithReason(
          new CustomModel(modelName, modelHash, 0, 0L),
          false,
          ErrorCode.MODEL_INFO_DOWNLOAD_CONNECTION_FAILED.getValue());

      return Tasks.forException(
          new FirebaseMlException(
              "Error reading custom model from download service: " + e.getMessage(),
              FirebaseMlException.INVALID_ARGUMENT));
    }
  }

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions