From d83bb878806fadfc6f915476cf473a993bfbb521 Mon Sep 17 00:00:00 2001 From: Micah Stairs Date: Fri, 22 May 2020 10:48:29 -0400 Subject: [PATCH 1/3] Add operation to update SAML provider configs. --- .../firebase/auth/AbstractFirebaseAuth.java | 50 +++++++ .../firebase/auth/FirebaseUserManager.java | 36 +++-- .../firebase/auth/SamlProviderConfig.java | 112 +++++++++++++++ .../google/firebase/auth/FirebaseAuthIT.java | 12 +- .../auth/FirebaseUserManagerTest.java | 132 +++++++++++++++++- .../auth/TenantAwareFirebaseAuthIT.java | 12 +- 6 files changed, 339 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/google/firebase/auth/AbstractFirebaseAuth.java b/src/main/java/com/google/firebase/auth/AbstractFirebaseAuth.java index c4ee36434..1bd243606 100644 --- a/src/main/java/com/google/firebase/auth/AbstractFirebaseAuth.java +++ b/src/main/java/com/google/firebase/auth/AbstractFirebaseAuth.java @@ -992,6 +992,7 @@ protected OidcProviderConfig execute() throws FirebaseAuthException { * @param request A non-null {@link OidcProviderConfig.UpdateRequest} instance. * @return A {@link OidcProviderConfig} instance corresponding to the updated provider config. * @throws NullPointerException if the provided update request is null. + * @throws IllegalArgumentException If the provided update request is invalid. * @throws FirebaseAuthException if an error occurs while updating the provider config. */ public OidcProviderConfig updateOidcProviderConfig( @@ -1006,6 +1007,8 @@ public OidcProviderConfig updateOidcProviderConfig( * @return An {@code ApiFuture} which will complete successfully with a {@link OidcProviderConfig} * instance corresponding to the updated provider config. If an error occurs while updating * the provider config, the future throws a {@link FirebaseAuthException}. + * @throws NullPointerException if the provided update request is null. + * @throws IllegalArgumentException If the provided update request is invalid. */ public ApiFuture updateOidcProviderConfigAsync( @NonNull OidcProviderConfig.UpdateRequest request) { @@ -1016,6 +1019,8 @@ private CallableOperation updateOidcP final OidcProviderConfig.UpdateRequest request) { checkNotDestroyed(); checkNotNull(request, "Update request must not be null."); + checkArgument(!request.getProperties().isEmpty(), + "Update request must have at least one property set."); final FirebaseUserManager userManager = getUserManager(); return new CallableOperation() { @Override @@ -1242,6 +1247,51 @@ protected SamlProviderConfig execute() throws FirebaseAuthException { }; } + /** + * Updates an existing SAML Auth provider config with the attributes contained in the specified + * {@link OidcProviderConfig.UpdateRequest}. + * + * @param request A non-null {@link SamlProviderConfig.UpdateRequest} instance. + * @return A {@link SamlProviderConfig} instance corresponding to the updated provider config. + * @throws NullPointerException if the provided update request is null. + * @throws IllegalArgumentException If the provided update request is invalid. + * @throws FirebaseAuthException if an error occurs while updating the provider config. + */ + public SamlProviderConfig updateSamlProviderConfig( + @NonNull SamlProviderConfig.UpdateRequest request) throws FirebaseAuthException { + return updateSamlProviderConfigOp(request).call(); + } + + /** + * Similar to {@link #updateSamlProviderConfig} but performs the operation asynchronously. + * + * @param request A non-null {@link SamlProviderConfig.UpdateRequest} instance. + * @return An {@code ApiFuture} which will complete successfully with a {@link SamlProviderConfig} + * instance corresponding to the updated provider config. If an error occurs while updating + * the provider config, the future throws a {@link FirebaseAuthException}. + * @throws NullPointerException if the provided update request is null. + * @throws IllegalArgumentException If the provided update request is invalid. + */ + public ApiFuture updateSamlProviderConfigAsync( + @NonNull SamlProviderConfig.UpdateRequest request) { + return updateSamlProviderConfigOp(request).callAsync(firebaseApp); + } + + private CallableOperation updateSamlProviderConfigOp( + final SamlProviderConfig.UpdateRequest request) { + checkNotDestroyed(); + checkNotNull(request, "Update request must not be null."); + checkArgument(!request.getProperties().isEmpty(), + "Update request must have at least one property set."); + final FirebaseUserManager userManager = getUserManager(); + return new CallableOperation() { + @Override + protected SamlProviderConfig execute() throws FirebaseAuthException { + return userManager.updateSamlProviderConfig(request); + } + }; + } + /** * Gets the SAML provider Auth config corresponding to 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 1d57c4156..02ab11325 100644 --- a/src/main/java/com/google/firebase/auth/FirebaseUserManager.java +++ b/src/main/java/com/google/firebase/auth/FirebaseUserManager.java @@ -256,7 +256,7 @@ Tenant updateTenant(Tenant.UpdateRequest request) throws FirebaseAuthException { // CallableOperation. checkArgument(!properties.isEmpty(), "tenant update must have at least one property set"); GenericUrl url = new GenericUrl(tenantMgtBaseUrl + getTenantUrlSuffix(request.getTenantId())); - url.put("updateMask", generateMask(properties)); + url.put("updateMask", Joiner.on(",").join(generateMask(properties))); return sendRequest("PATCH", url, properties, Tenant.class); } @@ -334,16 +334,21 @@ SamlProviderConfig createSamlProviderConfig( OidcProviderConfig updateOidcProviderConfig(OidcProviderConfig.UpdateRequest request) throws FirebaseAuthException { Map properties = request.getProperties(); - // TODO(micahstairs): Move this check so that argument validation happens outside the - // CallableOperation. - checkArgument(!properties.isEmpty(), - "Provider config update must have at least one property set."); GenericUrl url = new GenericUrl(idpConfigMgtBaseUrl + getOidcUrlSuffix(request.getProviderId())); - url.put("updateMask", generateMask(properties)); + url.put("updateMask", Joiner.on(",").join(generateMask(properties))); return sendRequest("PATCH", url, properties, OidcProviderConfig.class); } + SamlProviderConfig updateSamlProviderConfig(SamlProviderConfig.UpdateRequest request) + throws FirebaseAuthException { + Map properties = request.getProperties(); + GenericUrl url = + new GenericUrl(idpConfigMgtBaseUrl + getSamlUrlSuffix(request.getProviderId())); + url.put("updateMask", Joiner.on(",").join(generateMask(properties))); + return sendRequest("PATCH", url, properties, SamlProviderConfig.class); + } + OidcProviderConfig getOidcProviderConfig(String providerId) throws FirebaseAuthException { GenericUrl url = new GenericUrl(idpConfigMgtBaseUrl + getOidcUrlSuffix(providerId)); return sendRequest("GET", url, null, OidcProviderConfig.class); @@ -384,12 +389,19 @@ void deleteSamlProviderConfig(String providerId) throws FirebaseAuthException { sendRequest("DELETE", url, null, GenericJson.class); } - private static String generateMask(Map properties) { - // This implementation does not currently handle the case of nested properties. This is fine - // since we do not currently generate masks for any properties with nested values. When it - // comes time to implement this, we can check if a property has nested properties by checking - // if it is an instance of the Map class. - return Joiner.on(",").join(ImmutableSortedSet.copyOf(properties.keySet())); + private static ImmutableSortedSet generateMask(Map properties) { + ImmutableSortedSet.Builder maskBuilder = ImmutableSortedSet.naturalOrder(); + for (Map.Entry entry : properties.entrySet()) { + if (entry.getValue() instanceof Map) { + ImmutableSortedSet childMask = generateMask((Map) entry.getValue()); + for (String childProperty : childMask) { + maskBuilder.add(entry.getKey() + "." + childProperty); + } + } else { + maskBuilder.add(entry.getKey()); + } + } + return maskBuilder.build(); } private static String getTenantUrlSuffix(String tenantId) { diff --git a/src/main/java/com/google/firebase/auth/SamlProviderConfig.java b/src/main/java/com/google/firebase/auth/SamlProviderConfig.java index e73781f03..c8970cc6d 100644 --- a/src/main/java/com/google/firebase/auth/SamlProviderConfig.java +++ b/src/main/java/com/google/firebase/auth/SamlProviderConfig.java @@ -71,6 +71,16 @@ public String getCallbackUrl() { return (String) spConfig.get("callbackUri"); } + /** + * Returns a new {@link UpdateRequest}, which can be used to update the attributes of this + * provider config. + * + * @return a non-null {@link UpdateRequest} instance. + */ + public UpdateRequest updateRequest() { + return new UpdateRequest(getProviderId()); + } + static void checkSamlProviderId(String providerId) { checkArgument(!Strings.isNullOrEmpty(providerId), "Provider ID must not be null or empty."); checkArgument(providerId.startsWith("saml."), @@ -201,4 +211,106 @@ CreateRequest getThis() { return this; } } + + /** + * A specification class for updating an existing SAML Auth provider. + * + *

An instance of this class can be obtained via a {@link SamlProviderConfig} object, or from + * a provider ID string. Specify the changes to be made to the provider config by calling the + * various setter methods available in this class. + */ + public static final class UpdateRequest extends AbstractUpdateRequest { + /** + * Creates a new {@link UpdateRequest}, which can be used to updates an existing SAML Auth + * provider. + * + *

The returned object should be passed to + * {@link AbstractFirebaseAuth#updateSamlProviderConfig(UpdateRequest)} to update the provider + * information persistently. + * + * @param providerId a non-null, non-empty provider ID string. + * @throws IllegalArgumentException If the provider ID is null or empty, or is not prefixed with + * 'saml.'. + */ + public UpdateRequest(String providerId) { + super(providerId); + checkSamlProviderId(providerId); + } + + /** + * Sets the IDP entity ID for the existing provider. + * + * @param idpEntityId A non-null, non-empty IDP entity ID string. + * @throws IllegalArgumentException If the IDP entity ID is null or empty. + */ + public UpdateRequest setIdpEntityId(String idpEntityId) { + checkArgument(!Strings.isNullOrEmpty(idpEntityId), + "IDP entity ID must not be null or empty."); + ensureNestedMap(properties, "idpConfig").put("idpEntityId", idpEntityId); + return this; + } + + /** + * Sets the SSO URL for the existing provider. + * + * @param ssoUrl A non-null, non-empty SSO URL string. + * @throws IllegalArgumentException If the SSO URL is null or empty, or if the format is + * invalid. + */ + public UpdateRequest setSsoUrl(String ssoUrl) { + checkArgument(!Strings.isNullOrEmpty(ssoUrl), "SSO URL must not be null or empty."); + assertValidUrl(ssoUrl); + ensureNestedMap(properties, "idpConfig").put("ssoUrl", ssoUrl); + return this; + } + + /** + * Adds a x509 certificate to the existing provider. + * + * @param x509Certificate A non-null, non-empty x509 certificate string. + * @throws IllegalArgumentException If the x509 certificate is null or empty. + */ + public UpdateRequest addX509Certificate(String x509Certificate) { + checkArgument(!Strings.isNullOrEmpty(x509Certificate), + "The x509 certificate must not be null or empty."); + Map idpConfigProperties = ensureNestedMap(properties, "idpConfig"); + List x509Certificates = ensureNestedList(idpConfigProperties, "idpCertificates"); + x509Certificates.add(ImmutableMap.of("x509Certificate", x509Certificate)); + return this; + } + + // TODO(micahstairs): Add 'addAllX509Certificates' method. + + /** + * Sets the RP entity ID for the existing provider. + * + * @param rpEntityId A non-null, non-empty RP entity ID string. + * @throws IllegalArgumentException If the RP entity ID is null or empty. + */ + public UpdateRequest setRpEntityId(String rpEntityId) { + checkArgument(!Strings.isNullOrEmpty(rpEntityId), "RP entity ID must not be null or empty."); + ensureNestedMap(properties, "spConfig").put("spEntityId", rpEntityId); + return this; + } + + /** + * Sets the callback URL for the exising provider. + * + * @param callbackUrl A non-null, non-empty callback URL string. + * @throws IllegalArgumentException If the callback URL is null or empty, or if the format is + * invalid. + */ + public UpdateRequest setCallbackUrl(String callbackUrl) { + checkArgument(!Strings.isNullOrEmpty(callbackUrl), "Callback URL must not be null or empty."); + assertValidUrl(callbackUrl); + ensureNestedMap(properties, "spConfig").put("callbackUri", callbackUrl); + return this; + } + + // TODO(micahstairs): Add 'setRequestSigningEnabled' method. + + UpdateRequest getThis() { + return this; + } + } } diff --git a/src/test/java/com/google/firebase/auth/FirebaseAuthIT.java b/src/test/java/com/google/firebase/auth/FirebaseAuthIT.java index a34b7d48a..8832e6481 100644 --- a/src/test/java/com/google/firebase/auth/FirebaseAuthIT.java +++ b/src/test/java/com/google/firebase/auth/FirebaseAuthIT.java @@ -708,7 +708,17 @@ public void testSamlProviderConfigLifecycle() throws Exception { assertEquals("RP_ENTITY_ID", config.getRpEntityId()); assertEquals("https://projectId.firebaseapp.com/__/auth/handler", config.getCallbackUrl()); - // TODO(micahstairs): Once implemented, add tests for updating the SAML provider config. + // Update provider config + SamlProviderConfig.UpdateRequest updateRequest = + new SamlProviderConfig.UpdateRequest(providerId) + .setDisplayName("NewDisplayName") + .setEnabled(false) + .addX509Certificate("certificate"); + config = auth.updateSamlProviderConfigAsync(updateRequest).get(); + assertEquals(providerId, config.getProviderId()); + assertEquals("NewDisplayName", config.getDisplayName()); + assertFalse(config.isEnabled()); + assertEquals(ImmutableList.of("certificate"), config.getX509Certificates()); // Delete provider config temporaryProviderConfig.deleteSamlProviderConfig(providerId); diff --git a/src/test/java/com/google/firebase/auth/FirebaseUserManagerTest.java b/src/test/java/com/google/firebase/auth/FirebaseUserManagerTest.java index 3bbe66f43..6a859dc42 100644 --- a/src/test/java/com/google/firebase/auth/FirebaseUserManagerTest.java +++ b/src/test/java/com/google/firebase/auth/FirebaseUserManagerTest.java @@ -1843,7 +1843,7 @@ public void testCreateSamlProvider() throws Exception { @Test public void testCreateSamlProviderMinimal() throws Exception { TestResponseInterceptor interceptor = initializeAppForUserManagement( - TestUtils.loadResource("oidc.json")); + TestUtils.loadResource("saml.json")); // Only the 'enabled', 'displayName', and 'signRequest' fields can be omitted from a SAML // provider config creation request. SamlProviderConfig.CreateRequest createRequest = @@ -1944,6 +1944,136 @@ public void testTenantAwareCreateSamlProvider() throws Exception { checkUrl(interceptor, "POST", TENANTS_BASE_URL + "/TENANT_ID/inboundSamlConfigs"); } + @Test + public void testUpdateSamlProvider() throws Exception { + TestResponseInterceptor interceptor = initializeAppForUserManagement( + TestUtils.loadResource("saml.json")); + // TODO(micahstairs): Add 'signRequest' to the create request once that field is added to + // SamlProviderConfig. + SamlProviderConfig.UpdateRequest updateRequest = + new SamlProviderConfig.UpdateRequest("saml.provider-id") + .setDisplayName("DISPLAY_NAME") + .setEnabled(true) + .setIdpEntityId("IDP_ENTITY_ID") + .setSsoUrl("https://example.com/login") + .addX509Certificate("certificate1") + .addX509Certificate("certificate2") + .setRpEntityId("RP_ENTITY_ID") + .setCallbackUrl("https://projectId.firebaseapp.com/__/auth/handler"); + + SamlProviderConfig config = FirebaseAuth.getInstance().updateSamlProviderConfig(updateRequest); + + checkSamlProviderConfig(config, "saml.provider-id"); + checkRequestHeaders(interceptor); + checkUrl(interceptor, "PATCH", PROJECT_BASE_URL + "/inboundSamlConfigs/saml.provider-id"); + GenericUrl url = interceptor.getResponse().getRequest().getUrl(); + assertEquals( + "displayName,enabled,idpConfig.idpCertificates,idpConfig.idpEntityId,idpConfig.ssoUrl," + + "spConfig.callbackUri,spConfig.spEntityId", + url.getFirst("updateMask")); + + GenericJson parsed = parseRequestContent(interceptor); + assertEquals("DISPLAY_NAME", parsed.get("displayName")); + assertTrue((boolean) parsed.get("enabled")); + Map idpConfig = (Map) parsed.get("idpConfig"); + assertNotNull(idpConfig); + assertEquals(3, idpConfig.size()); + assertEquals("IDP_ENTITY_ID", idpConfig.get("idpEntityId")); + assertEquals("https://example.com/login", idpConfig.get("ssoUrl")); + List idpCertificates = (List) idpConfig.get("idpCertificates"); + assertNotNull(idpCertificates); + assertEquals(2, idpCertificates.size()); + assertEquals(ImmutableMap.of("x509Certificate", "certificate1"), idpCertificates.get(0)); + assertEquals(ImmutableMap.of("x509Certificate", "certificate2"), idpCertificates.get(1)); + Map spConfig = (Map) parsed.get("spConfig"); + assertNotNull(spConfig); + assertEquals(2, spConfig.size()); + assertEquals("RP_ENTITY_ID", spConfig.get("spEntityId")); + assertEquals("https://projectId.firebaseapp.com/__/auth/handler", spConfig.get("callbackUri")); + } + + @Test + public void testUpdateSamlProviderMinimal() throws Exception { + TestResponseInterceptor interceptor = initializeAppForUserManagement( + TestUtils.loadResource("saml.json")); + SamlProviderConfig.UpdateRequest request = + new SamlProviderConfig.UpdateRequest("saml.provider-id").setDisplayName("DISPLAY_NAME"); + + SamlProviderConfig config = FirebaseAuth.getInstance().updateSamlProviderConfig(request); + + checkSamlProviderConfig(config, "saml.provider-id"); + checkRequestHeaders(interceptor); + checkUrl(interceptor, "PATCH", PROJECT_BASE_URL + "/inboundSamlConfigs/saml.provider-id"); + GenericUrl url = interceptor.getResponse().getRequest().getUrl(); + assertEquals("displayName", url.getFirst("updateMask")); + GenericJson parsed = parseRequestContent(interceptor); + assertEquals(1, parsed.size()); + assertEquals("DISPLAY_NAME", parsed.get("displayName")); + } + + @Test + public void testUpdateSamlProviderConfigNoValues() throws Exception { + TestResponseInterceptor interceptor = initializeAppForUserManagement( + TestUtils.loadResource("saml.json")); + try { + FirebaseAuth.getInstance().updateSamlProviderConfig( + new SamlProviderConfig.UpdateRequest("saml.provider-id")); + fail("No error thrown for empty provider config update"); + } catch (IllegalArgumentException e) { + // expected + } + } + + @Test + public void testUpdateSamlProviderConfigError() throws Exception { + TestResponseInterceptor interceptor = + initializeAppForUserManagementWithStatusCode(404, + "{\"error\": {\"message\": \"INTERNAL_ERROR\"}}"); + SamlProviderConfig.UpdateRequest request = + new SamlProviderConfig.UpdateRequest("saml.provider-id").setDisplayName("DISPLAY_NAME"); + try { + FirebaseAuth.getInstance().updateSamlProviderConfig(request); + fail("No error thrown for invalid response"); + } catch (FirebaseAuthException e) { + assertEquals(FirebaseUserManager.INTERNAL_ERROR, e.getErrorCode()); + } + checkUrl(interceptor, "PATCH", PROJECT_BASE_URL + "/inboundSamlConfigs/saml.provider-id"); + } + + @Test + public void testTenantAwareUpdateSamlProvider() throws Exception { + TestResponseInterceptor interceptor = initializeAppForTenantAwareUserManagement( + "TENANT_ID", + TestUtils.loadResource("saml.json")); + TenantAwareFirebaseAuth tenantAwareAuth = + FirebaseAuth.getInstance().getTenantManager().getAuthForTenant("TENANT_ID"); + SamlProviderConfig.UpdateRequest updateRequest = + new SamlProviderConfig.UpdateRequest("saml.provider-id") + .setDisplayName("DISPLAY_NAME") + .setEnabled(true) + .setIdpEntityId("IDP_ENTITY_ID") + .setSsoUrl("https://example.com/login"); + + SamlProviderConfig config = tenantAwareAuth.updateSamlProviderConfig(updateRequest); + + checkSamlProviderConfig(config, "saml.provider-id"); + checkRequestHeaders(interceptor); + String expectedUrl = TENANTS_BASE_URL + "/TENANT_ID/inboundSamlConfigs/saml.provider-id"; + checkUrl(interceptor, "PATCH", expectedUrl); + GenericUrl url = interceptor.getResponse().getRequest().getUrl(); + assertEquals("displayName,enabled,idpConfig.idpEntityId,idpConfig.ssoUrl", + url.getFirst("updateMask")); + + GenericJson parsed = parseRequestContent(interceptor); + assertEquals("DISPLAY_NAME", parsed.get("displayName")); + assertTrue((boolean) parsed.get("enabled")); + Map idpConfig = (Map) parsed.get("idpConfig"); + assertNotNull(idpConfig); + assertEquals(2, idpConfig.size()); + assertEquals("IDP_ENTITY_ID", idpConfig.get("idpEntityId")); + assertEquals("https://example.com/login", idpConfig.get("ssoUrl")); + } + @Test public void testGetSamlProviderConfig() throws Exception { TestResponseInterceptor interceptor = initializeAppForUserManagement( diff --git a/src/test/java/com/google/firebase/auth/TenantAwareFirebaseAuthIT.java b/src/test/java/com/google/firebase/auth/TenantAwareFirebaseAuthIT.java index 51b5d5461..9e22a84a5 100644 --- a/src/test/java/com/google/firebase/auth/TenantAwareFirebaseAuthIT.java +++ b/src/test/java/com/google/firebase/auth/TenantAwareFirebaseAuthIT.java @@ -369,7 +369,17 @@ public void testSamlProviderConfigLifecycle() throws Exception { assertEquals("RP_ENTITY_ID", config.getRpEntityId()); assertEquals("https://projectId.firebaseapp.com/__/auth/handler", config.getCallbackUrl()); - // TODO(micahstairs): Once implemented, add tests for updating the SAML provider config. + // Update provider config + SamlProviderConfig.UpdateRequest updateRequest = + new SamlProviderConfig.UpdateRequest(providerId) + .setDisplayName("NewDisplayName") + .setEnabled(false) + .addX509Certificate("certificate"); + config = tenantAwareAuth.updateSamlProviderConfigAsync(updateRequest).get(); + assertEquals(providerId, config.getProviderId()); + assertEquals("NewDisplayName", config.getDisplayName()); + assertFalse(config.isEnabled()); + assertEquals(ImmutableList.of("certificate"), config.getX509Certificates()); // Delete provider config temporaryProviderConfig.deleteSamlProviderConfig(providerId); From f29ebc31b2b1219fda7f615602fa1321512559cc Mon Sep 17 00:00:00 2001 From: Micah Stairs Date: Wed, 27 May 2020 14:19:16 -0400 Subject: [PATCH 2/3] Add blank lines to make code less dense. --- .../java/com/google/firebase/auth/FirebaseUserManagerTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/test/java/com/google/firebase/auth/FirebaseUserManagerTest.java b/src/test/java/com/google/firebase/auth/FirebaseUserManagerTest.java index 6a859dc42..1b27d7981 100644 --- a/src/test/java/com/google/firebase/auth/FirebaseUserManagerTest.java +++ b/src/test/java/com/google/firebase/auth/FirebaseUserManagerTest.java @@ -1975,6 +1975,7 @@ public void testUpdateSamlProvider() throws Exception { GenericJson parsed = parseRequestContent(interceptor); assertEquals("DISPLAY_NAME", parsed.get("displayName")); assertTrue((boolean) parsed.get("enabled")); + Map idpConfig = (Map) parsed.get("idpConfig"); assertNotNull(idpConfig); assertEquals(3, idpConfig.size()); @@ -1985,6 +1986,7 @@ public void testUpdateSamlProvider() throws Exception { assertEquals(2, idpCertificates.size()); assertEquals(ImmutableMap.of("x509Certificate", "certificate1"), idpCertificates.get(0)); assertEquals(ImmutableMap.of("x509Certificate", "certificate2"), idpCertificates.get(1)); + Map spConfig = (Map) parsed.get("spConfig"); assertNotNull(spConfig); assertEquals(2, spConfig.size()); From bed8221a2d8ca89a79e74069cddd18068032e4e3 Mon Sep 17 00:00:00 2001 From: Micah Stairs Date: Wed, 27 May 2020 14:34:30 -0400 Subject: [PATCH 3/3] Relax method signature to Set. --- .../java/com/google/firebase/auth/FirebaseUserManager.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/google/firebase/auth/FirebaseUserManager.java b/src/main/java/com/google/firebase/auth/FirebaseUserManager.java index 02ab11325..a6dfb09d2 100644 --- a/src/main/java/com/google/firebase/auth/FirebaseUserManager.java +++ b/src/main/java/com/google/firebase/auth/FirebaseUserManager.java @@ -54,6 +54,7 @@ import java.io.IOException; import java.util.List; import java.util.Map; +import java.util.Set; /** * FirebaseUserManager provides methods for interacting with the Google Identity Toolkit via its @@ -389,11 +390,11 @@ void deleteSamlProviderConfig(String providerId) throws FirebaseAuthException { sendRequest("DELETE", url, null, GenericJson.class); } - private static ImmutableSortedSet generateMask(Map properties) { + private static Set generateMask(Map properties) { ImmutableSortedSet.Builder maskBuilder = ImmutableSortedSet.naturalOrder(); for (Map.Entry entry : properties.entrySet()) { if (entry.getValue() instanceof Map) { - ImmutableSortedSet childMask = generateMask((Map) entry.getValue()); + Set childMask = generateMask((Map) entry.getValue()); for (String childProperty : childMask) { maskBuilder.add(entry.getKey() + "." + childProperty); }