Repository: firebase/firebase-admin-java
Pull request #401 (2020-04-30 16:10:37)

Add operation to get OIDC provider configs.
This adds an operation to get OIDC provider configs (can be done using either the tenant-aware or standard Firebase client).

This work is part of adding multi-tenancy support (see issue #332).


Patch:
diff --git a/src/main/java/com/google/firebase/auth/AbstractFirebaseAuth.java b/src/main/java/com/google/firebase/auth/AbstractFirebaseAuth.java
index cde7a90..a7bf99d 100644
--- a/src/main/java/com/google/firebase/auth/AbstractFirebaseAuth.java
+++ b/src/main/java/com/google/firebase/auth/AbstractFirebaseAuth.java
@@ -978,6 +978,46 @@ public abstract class AbstractFirebaseAuth {
     };
   }
 
+  /**
+   * Gets the provider OIDC Auth config corresponding to the specified provider ID.
+   *
+   * @param providerId A provider ID string.
+   * @return An {@link OidcProviderConfig} instance.
+   * @throws IllegalArgumentException If the provider ID string is null or empty.
+   * @throws FirebaseAuthException If an error occurs while retrieving the provider config.
+   */
+  public OidcProviderConfig getOidcProviderConfig(@NonNull String providerId)
+      throws FirebaseAuthException {
+    return getOidcProviderConfigOp(providerId).call();
+  }
+
+  /**
+   * Similar to {@link #getOidcProviderConfig(String)} but performs the operation asynchronously.
+   *
+   * @param providerId A provider ID string.
+   * @return An {@code ApiFuture} which will complete successfully with an
+   *     {@link OidcProviderConfig} instance. If an error occurs while retrieving the provider
+   *     config or if the specified provider ID does not exist, the future throws a
+   *     {@link FirebaseAuthException}.
+   * @throws IllegalArgumentException If the provider ID string is null or empty.
+   */
+  public ApiFuture<OidcProviderConfig> getOidcProviderConfigAsync(@NonNull String providerId) {
+    return getOidcProviderConfigOp(providerId).callAsync(firebaseApp);
+  }
+
+  private CallableOperation<OidcProviderConfig, FirebaseAuthException>
+      getOidcProviderConfigOp(final String providerId) {
+    checkNotDestroyed();
+    checkArgument(!Strings.isNullOrEmpty(providerId), "provider ID must not be null or empty");
+    final FirebaseUserManager userManager = getUserManager();
+    return new CallableOperation<OidcProviderConfig, FirebaseAuthException>() {
+      @Override
+      protected OidcProviderConfig execute() throws FirebaseAuthException {
+        return userManager.getOidcProviderConfig(providerId);
+      }
+    };
+  }
+
   /**
    * Deletes the provider config identified by the specified provider ID.
    *
diff --git a/src/main/java/com/google/firebase/auth/FirebaseUserManager.java b/src/main/java/com/google/firebase/auth/FirebaseUserManager.java
index 0c031a8..80918f5 100644
--- a/src/main/java/com/google/firebase/auth/FirebaseUserManager.java
+++ b/src/main/java/com/google/firebase/auth/FirebaseUserManager.java
@@ -65,7 +65,7 @@ import java.util.Map;
  */
 class FirebaseUserManager {
 
-  static final String CONFIGURATION_NOT_FOUND = "configuration-not-found";
+  static final String CONFIGURATION_NOT_FOUND_ERROR = "configuration-not-found";
   static final String TENANT_ID_MISMATCH_ERROR = "tenant-id-mismatch";
   static final String TENANT_NOT_FOUND_ERROR = "tenant-not-found";
   static final String USER_NOT_FOUND_ERROR = "user-not-found";
@@ -75,7 +75,7 @@ class FirebaseUserManager {
   // SDK error codes defined at: https://firebase.google.com/docs/auth/admin/errors
   private static final Map<String, String> ERROR_CODES = ImmutableMap.<String, String>builder()
       .put("CLAIMS_TOO_LARGE", "claims-too-large")
-      .put("CONFIGURATION_NOT_FOUND", CONFIGURATION_NOT_FOUND)
+      .put("CONFIGURATION_NOT_FOUND", CONFIGURATION_NOT_FOUND_ERROR)
       .put("INSUFFICIENT_PERMISSION", "insufficient-permission")
       .put("DUPLICATE_EMAIL", "email-already-exists")
       .put("DUPLICATE_LOCAL_ID", "uid-already-exists")
@@ -330,6 +330,11 @@ class FirebaseUserManager {
     return sendRequest("POST", url, request.getProperties(), OidcProviderConfig.class);
   }
 
+  OidcProviderConfig getOidcProviderConfig(String providerId) throws FirebaseAuthException {
+    GenericUrl url = new GenericUrl(idpConfigMgtBaseUrl + "/oauthIdpConfigs/" + providerId);
+    return sendRequest("GET", url, null, OidcProviderConfig.class);
+  }
+
   void deleteProviderConfig(String providerId) throws FirebaseAuthException {
     GenericUrl url = new GenericUrl(idpConfigMgtBaseUrl + "/oauthIdpConfigs/" + providerId);
     sendRequest("DELETE", url, null, GenericJson.class);


Test patch:
diff --git a/src/test/java/com/google/firebase/auth/FirebaseAuthIT.java b/src/test/java/com/google/firebase/auth/FirebaseAuthIT.java
index 98168da..bfc8485 100644
--- a/src/test/java/com/google/firebase/auth/FirebaseAuthIT.java
+++ b/src/test/java/com/google/firebase/auth/FirebaseAuthIT.java
@@ -976,17 +976,27 @@ public class FirebaseAuthIT {
     assertEquals("ClientId", config.getClientId());
     assertEquals("https://oidc.com/issuer", config.getIssuer());
 
-    // TODO(micahstairs): Test getOidcProviderConfig and updateProviderConfig operations.
+    try {
+      // Get config provider
+      config = auth.getOidcProviderConfigAsync(providerId).get();
+      assertEquals(providerId, config.getProviderId());
+      assertEquals("DisplayName", config.getDisplayName());
+      assertEquals("ClientId", config.getClientId());
+      assertEquals("https://oidc.com/issuer", config.getIssuer());
+
+      // TODO(micahstairs): Test updateProviderConfig operation
 
-    // Delete config provider
-    auth.deleteProviderConfigAsync(providerId).get();
-    // TODO(micahstairs): Once getOidcProviderConfig operation is implemented, add a check here to
-    // double-check that the config provider was deleted.
+    } finally {
+      // Delete config provider
+      auth.deleteProviderConfigAsync(providerId).get();
+    }
+
+    assertOidcProviderConfigDoesNotExist(auth, providerId);
   }
 
   @Test
   public void testTenantAwareOidcProviderConfigLifecycle() throws Exception {
-    // Create tenant to use.
+    // Create tenant to use
     TenantManager tenantManager = auth.getTenantManager();
     Tenant.CreateRequest tenantCreateRequest =
         new Tenant.CreateRequest().setDisplayName("DisplayName");
@@ -1010,12 +1020,22 @@ public class FirebaseAuthIT {
       assertEquals("ClientId", config.getClientId());
       assertEquals("https://oidc.com/issuer", config.getIssuer());
 
-      // TODO(micahstairs): Test getOidcProviderConfig and updateProviderConfig operations.
+      try {
+        // Get config provider
+        config = tenantAwareAuth.getOidcProviderConfigAsync(providerId).get();
+        assertEquals(providerId, config.getProviderId());
+        assertEquals("DisplayName", config.getDisplayName());
+        assertEquals("ClientId", config.getClientId());
+        assertEquals("https://oidc.com/issuer", config.getIssuer());
+
+        // TODO(micahstairs): Test updateProviderConfig operation
+
+      } finally {
+        // Delete config provider
+        tenantAwareAuth.deleteProviderConfigAsync(providerId).get();
+      }
 
-      // Delete config provider
-      tenantAwareAuth.deleteProviderConfigAsync(providerId).get();
-      // TODO(micahstairs): Once getOidcProviderConfig operation is implemented, add a check here to
-      // double-check that the config provider was deleted.
+      assertOidcProviderConfigDoesNotExist(tenantAwareAuth, providerId);
     } finally {
       // Delete tenant.
       tenantManager.deleteTenantAsync(tenantId).get();
@@ -1152,6 +1172,19 @@ public class FirebaseAuthIT {
     }
   }
 
+
+  private static void assertOidcProviderConfigDoesNotExist(
+      AbstractFirebaseAuth firebaseAuth, String providerId) throws Exception {
+    try {
+      firebaseAuth.getOidcProviderConfigAsync(providerId).get();
+      fail("No error thrown for getting a deleted provider config");
+    } catch (ExecutionException e) {
+      assertTrue(e.getCause() instanceof FirebaseAuthException);
+      assertEquals(FirebaseUserManager.CONFIGURATION_NOT_FOUND_ERROR,
+          ((FirebaseAuthException) e.getCause()).getErrorCode());
+    }
+  }
+
   private static void assertUserDoesNotExist(AbstractFirebaseAuth firebaseAuth, String uid)
       throws Exception {
     try {
diff --git a/src/test/java/com/google/firebase/auth/FirebaseUserManagerTest.java b/src/test/java/com/google/firebase/auth/FirebaseUserManagerTest.java
index 13b77f8..de672ef 100644
--- a/src/test/java/com/google/firebase/auth/FirebaseUserManagerTest.java
+++ b/src/test/java/com/google/firebase/auth/FirebaseUserManagerTest.java
@@ -1491,6 +1491,49 @@ public class FirebaseUserManagerTest {
     checkUrl(interceptor, "POST", TENANTS_BASE_URL + "/TENANT_ID/oauthIdpConfigs");
   }
 
+  @Test
+  public void testGetOidcProviderConfig() throws Exception {
+    TestResponseInterceptor interceptor = initializeAppForUserManagement(
+        TestUtils.loadResource("oidc.json"));
+
+    OidcProviderConfig config =
+        FirebaseAuth.getInstance().getOidcProviderConfig("oidc.provider-id");
+
+    checkOidcProviderConfig(config);
+    checkRequestHeaders(interceptor);
+    checkUrl(interceptor, "GET", PROJECT_BASE_URL + "/oauthIdpConfigs/oidc.provider-id");
+  }
+
+  @Test
+  public void testGetOidcProviderConfigWithNotFoundError() throws Exception {
+    TestResponseInterceptor interceptor =
+        initializeAppForUserManagementWithStatusCode(404,
+            "{\"error\": {\"message\": \"CONFIGURATION_NOT_FOUND\"}}");
+    try {
+      FirebaseAuth.getInstance().getOidcProviderConfig("oidc.provider-id");
+      fail("No error thrown for invalid response");
+    } catch (FirebaseAuthException e) {
+      assertEquals(FirebaseUserManager.CONFIGURATION_NOT_FOUND_ERROR, e.getErrorCode());
+    }
+    checkUrl(interceptor, "GET", PROJECT_BASE_URL + "/oauthIdpConfigs/oidc.provider-id");
+  }
+
+  @Test
+  public void testGetTenantAwareOidcProviderConfig() throws Exception {
+    TestResponseInterceptor interceptor = initializeAppForTenantAwareUserManagement(
+        "TENANT_ID",
+        TestUtils.loadResource("oidc.json"));
+    TenantAwareFirebaseAuth tenantAwareAuth =
+        FirebaseAuth.getInstance().getTenantManager().getAuthForTenant("TENANT_ID");
+
+    OidcProviderConfig config = tenantAwareAuth.getOidcProviderConfig("oidc.provider-id");
+
+    checkOidcProviderConfig(config);
+    checkRequestHeaders(interceptor);
+    checkUrl(interceptor, "GET", TENANTS_BASE_URL + "/TENANT_ID/oauthIdpConfigs/oidc.provider-id");
+  }
+
+
   @Test
   public void testDeleteProviderConfig() throws Exception {
     TestResponseInterceptor interceptor = initializeAppForUserManagement("{}");
@@ -1510,7 +1553,7 @@ public class FirebaseUserManagerTest {
       FirebaseAuth.getInstance().deleteProviderConfig("UNKNOWN");
       fail("No error thrown for invalid response");
     } catch (FirebaseAuthException e) {
-      assertEquals(FirebaseUserManager.CONFIGURATION_NOT_FOUND, e.getErrorCode());
+      assertEquals(FirebaseUserManager.CONFIGURATION_NOT_FOUND_ERROR, e.getErrorCode());
     }
     checkUrl(interceptor, "DELETE", PROJECT_BASE_URL + "/oauthIdpConfigs/UNKNOWN");
   }