diff --git a/src/main/java/com/google/firebase/auth/FirebaseUserManager.java b/src/main/java/com/google/firebase/auth/FirebaseUserManager.java index ec1cbe62e..23867e39a 100644 --- a/src/main/java/com/google/firebase/auth/FirebaseUserManager.java +++ b/src/main/java/com/google/firebase/auth/FirebaseUserManager.java @@ -262,15 +262,15 @@ void deleteTenant(String tenantId) throws FirebaseAuthException { ListTenantsResponse listTenants(int maxResults, String pageToken) throws FirebaseAuthException { - ImmutableMap.Builder builder = ImmutableMap.builder() - .put("pageSize", maxResults); + ImmutableMap.Builder builder = + ImmutableMap.builder().put("pageSize", maxResults); if (pageToken != null) { checkArgument(!pageToken.equals( ListTenantsPage.END_OF_LIST), "invalid end of list page token"); builder.put("pageToken", pageToken); } - GenericUrl url = new GenericUrl(tenantMgtBaseUrl + "/tenants:list"); + GenericUrl url = new GenericUrl(tenantMgtBaseUrl + "/tenants"); url.putAll(builder.build()); ListTenantsResponse response = sendRequest("GET", url, null, ListTenantsResponse.class); if (response == null) { @@ -329,9 +329,13 @@ private T sendRequest( HttpResponse response = null; try { HttpContent httpContent = content != null ? new JsonHttpContent(jsonFactory, content) : null; - HttpRequest request = requestFactory.buildRequest(method, url, httpContent); + HttpRequest request = + requestFactory.buildRequest(method.equals("PATCH") ? "POST" : method, url, httpContent); request.setParser(new JsonObjectParser(jsonFactory)); request.getHeaders().set(CLIENT_VERSION_HEADER, clientVersion); + if (method.equals("PATCH")) { + request.getHeaders().set("X-HTTP-Method-Override", "PATCH"); + } request.setResponseInterceptor(interceptor); response = request.execute(); return response.parseAs(clazz); diff --git a/src/main/java/com/google/firebase/auth/Tenant.java b/src/main/java/com/google/firebase/auth/Tenant.java index 6e489721a..6641a0493 100644 --- a/src/main/java/com/google/firebase/auth/Tenant.java +++ b/src/main/java/com/google/firebase/auth/Tenant.java @@ -31,9 +31,12 @@ */ public final class Tenant { - @Key("name") + // Lazily initialized from 'resourceName'. private String tenantId; + @Key("name") + private String resourceName; + @Key("displayName") private String displayName; @@ -44,6 +47,9 @@ public final class Tenant { private boolean emailLinkSignInEnabled; public String getTenantId() { + if (tenantId == null) { + tenantId = resourceName.substring(resourceName.lastIndexOf("/") + 1); + } return tenantId; } diff --git a/src/main/java/com/google/firebase/auth/TenantManager.java b/src/main/java/com/google/firebase/auth/TenantManager.java index 54abbe879..c4e54d4a3 100644 --- a/src/main/java/com/google/firebase/auth/TenantManager.java +++ b/src/main/java/com/google/firebase/auth/TenantManager.java @@ -178,6 +178,19 @@ public ApiFuture createTenantAsync(@NonNull CreateRequest request) { return createTenantOp(request).callAsync(firebaseApp); } + private CallableOperation createTenantOp( + final CreateRequest request) { + // TODO(micahstairs): Add a check to make sure the app has not been destroyed yet. + checkNotNull(request, "create request must not be null"); + return new CallableOperation() { + @Override + protected Tenant execute() throws FirebaseAuthException { + return userManager.createTenant(request); + } + }; + } + + /** * Updates an existing user account with the attributes contained in the specified {@link * UpdateRequest}. @@ -215,18 +228,6 @@ protected Tenant execute() throws FirebaseAuthException { }; } - private CallableOperation createTenantOp( - final CreateRequest request) { - // TODO(micahstairs): Add a check to make sure the app has not been destroyed yet. - checkNotNull(request, "create request must not be null"); - return new CallableOperation() { - @Override - protected Tenant execute() throws FirebaseAuthException { - return userManager.createTenant(request); - } - }; - } - /** * Deletes the tenant identified by the specified tenant ID. * diff --git a/src/test/java/com/google/firebase/auth/FirebaseAuthIT.java b/src/test/java/com/google/firebase/auth/FirebaseAuthIT.java index 6a8361d0d..d6a41d40f 100644 --- a/src/test/java/com/google/firebase/auth/FirebaseAuthIT.java +++ b/src/test/java/com/google/firebase/auth/FirebaseAuthIT.java @@ -46,8 +46,6 @@ import com.google.firebase.FirebaseApp; import com.google.firebase.FirebaseOptions; import com.google.firebase.ImplFirebaseTrampolines; -import com.google.firebase.auth.UserRecord.CreateRequest; -import com.google.firebase.auth.UserRecord.UpdateRequest; import com.google.firebase.auth.hash.Scrypt; import com.google.firebase.testing.IntegrationTestUtils; import java.io.IOException; @@ -116,7 +114,7 @@ public void testGetNonExistingUserByEmail() throws Exception { @Test public void testUpdateNonExistingUser() throws Exception { try { - auth.updateUserAsync(new UpdateRequest("non.existing")).get(); + auth.updateUserAsync(new UserRecord.UpdateRequest("non.existing")).get(); fail("No error thrown for non existing uid"); } catch (ExecutionException e) { assertTrue(e.getCause() instanceof FirebaseAuthException); @@ -141,7 +139,7 @@ public void testDeleteNonExistingUser() throws Exception { public void testCreateUserWithParams() throws Exception { RandomUser randomUser = RandomUser.create(); String phone = randomPhoneNumber(); - CreateRequest user = new CreateRequest() + UserRecord.CreateRequest user = new UserRecord.CreateRequest() .setUid(randomUser.uid) .setEmail(randomUser.email) .setPhoneNumber(phone) @@ -168,7 +166,7 @@ public void testCreateUserWithParams() throws Exception { assertTrue(providers.contains("password")); assertTrue(providers.contains("phone")); - checkRecreate(randomUser.uid); + checkRecreateUser(randomUser.uid); } finally { auth.deleteUserAsync(userRecord.getUid()).get(); } @@ -177,7 +175,7 @@ public void testCreateUserWithParams() throws Exception { @Test public void testUserLifecycle() throws Exception { // Create user - UserRecord userRecord = auth.createUserAsync(new CreateRequest()).get(); + UserRecord userRecord = auth.createUserAsync(new UserRecord.CreateRequest()).get(); String uid = userRecord.getUid(); // Get user @@ -197,7 +195,7 @@ public void testUserLifecycle() throws Exception { // Update user RandomUser randomUser = RandomUser.create(); String phone = randomPhoneNumber(); - UpdateRequest request = userRecord.updateRequest() + UserRecord.UpdateRequest request = userRecord.updateRequest() .setDisplayName("Updated Name") .setEmail(randomUser.email) .setPhoneNumber(phone) @@ -240,7 +238,7 @@ public void testUserLifecycle() throws Exception { auth.deleteUserAsync(userRecord.getUid()).get(); try { auth.getUserAsync(userRecord.getUid()).get(); - fail("No error thrown for deleted user"); + fail("No error thrown for getting a deleted user"); } catch (ExecutionException e) { assertTrue(e.getCause() instanceof FirebaseAuthException); assertEquals(FirebaseUserManager.USER_NOT_FOUND_ERROR, @@ -253,9 +251,11 @@ public void testListUsers() throws Exception { final List uids = new ArrayList<>(); try { - uids.add(auth.createUserAsync(new CreateRequest().setPassword("password")).get().getUid()); - uids.add(auth.createUserAsync(new CreateRequest().setPassword("password")).get().getUid()); - uids.add(auth.createUserAsync(new CreateRequest().setPassword("password")).get().getUid()); + for (int i = 0; i < 3; i++) { + UserRecord.CreateRequest createRequest = + new UserRecord.CreateRequest().setPassword("password"); + uids.add(auth.createUserAsync(createRequest).get().getUid()); + } // Test list by batches final AtomicInteger collected = new AtomicInteger(0); @@ -320,9 +320,121 @@ public void onSuccess(ListUsersPage result) { } } + @Test + public void testTenantLifecycle() throws Exception { + TenantManager tenantManager = auth.getTenantManager(); + + // Create tenant + Tenant.CreateRequest createRequest = new Tenant.CreateRequest().setDisplayName("DisplayName"); + Tenant tenant = tenantManager.createTenantAsync(createRequest).get(); + assertEquals("DisplayName", tenant.getDisplayName()); + assertFalse(tenant.isPasswordSignInAllowed()); + assertFalse(tenant.isEmailLinkSignInEnabled()); + String tenantId = tenant.getTenantId(); + + // Get tenant + tenant = tenantManager.getTenantAsync(tenantId).get(); + assertEquals(tenantId, tenant.getTenantId()); + assertEquals("DisplayName", tenant.getDisplayName()); + assertFalse(tenant.isPasswordSignInAllowed()); + assertFalse(tenant.isEmailLinkSignInEnabled()); + + // Update tenant + Tenant.UpdateRequest updateRequest = tenant.updateRequest() + .setDisplayName("UpdatedName") + .setPasswordSignInAllowed(true) + .setEmailLinkSignInEnabled(true); + tenant = tenantManager.updateTenantAsync(updateRequest).get(); + assertEquals(tenantId, tenant.getTenantId()); + assertEquals("UpdatedName", tenant.getDisplayName()); + assertTrue(tenant.isPasswordSignInAllowed()); + assertTrue(tenant.isEmailLinkSignInEnabled()); + + // Delete tenant + tenantManager.deleteTenantAsync(tenant.getTenantId()).get(); + try { + tenantManager.getTenantAsync(tenant.getTenantId()).get(); + fail("No error thrown for getting a deleted tenant"); + } catch (ExecutionException e) { + assertTrue(e.getCause() instanceof FirebaseAuthException); + assertEquals(FirebaseUserManager.TENANT_NOT_FOUND_ERROR, + ((FirebaseAuthException) e.getCause()).getErrorCode()); + } + } + + @Test + public void testListTenants() throws Exception { + TenantManager tenantManager = auth.getTenantManager(); + final List tenantIds = new ArrayList<>(); + + try { + for (int i = 0; i < 3; i++) { + Tenant.CreateRequest createRequest = + new Tenant.CreateRequest().setDisplayName("DisplayName" + i); + tenantIds.add(tenantManager.createTenantAsync(createRequest).get().getTenantId()); + } + + // Test list by batches + final AtomicInteger collected = new AtomicInteger(0); + ListTenantsPage page = tenantManager.listTenantsAsync(null).get(); + while (page != null) { + for (Tenant tenant : page.getValues()) { + if (tenantIds.contains(tenant.getTenantId())) { + collected.incrementAndGet(); + assertNotNull(tenant.getDisplayName()); + } + } + page = page.getNextPage(); + } + assertEquals(tenantIds.size(), collected.get()); + + // Test iterate all + collected.set(0); + page = tenantManager.listTenantsAsync(null).get(); + for (Tenant tenant : page.iterateAll()) { + if (tenantIds.contains(tenant.getTenantId())) { + collected.incrementAndGet(); + assertNotNull(tenant.getDisplayName()); + } + } + assertEquals(tenantIds.size(), collected.get()); + + // Test iterate async + collected.set(0); + final Semaphore semaphore = new Semaphore(0); + final AtomicReference error = new AtomicReference<>(); + ApiFuture pageFuture = tenantManager.listTenantsAsync(null); + ApiFutures.addCallback(pageFuture, new ApiFutureCallback() { + @Override + public void onFailure(Throwable t) { + error.set(t); + semaphore.release(); + } + + @Override + public void onSuccess(ListTenantsPage result) { + for (Tenant tenant : result.iterateAll()) { + if (tenantIds.contains(tenant.getTenantId())) { + collected.incrementAndGet(); + assertNotNull(tenant.getDisplayName()); + } + } + semaphore.release(); + } + }, MoreExecutors.directExecutor()); + semaphore.acquire(); + assertEquals(tenantIds.size(), collected.get()); + assertNull(error.get()); + } finally { + for (String tenantId : tenantIds) { + tenantManager.deleteTenantAsync(tenantId).get(); + } + } + } + @Test public void testCustomClaims() throws Exception { - UserRecord userRecord = auth.createUserAsync(new CreateRequest()).get(); + UserRecord userRecord = auth.createUserAsync(new UserRecord.CreateRequest()).get(); String uid = userRecord.getUid(); try { @@ -413,7 +525,7 @@ public void testVerifyIdToken() throws Exception { } idToken = signInWithCustomToken(customToken); decoded = auth.verifyIdTokenAsync(idToken, true).get(); - assertEquals("user2", decoded.getUid()); + assertEquals("user2", decoded.getUid()); auth.deleteUserAsync("user2"); } @@ -524,7 +636,7 @@ public void testImportUsersWithPassword() throws Exception { @Test public void testGeneratePasswordResetLink() throws Exception { RandomUser user = RandomUser.create(); - auth.createUser(new CreateRequest() + auth.createUser(new UserRecord.CreateRequest() .setUid(user.uid) .setEmail(user.email) .setEmailVerified(false) @@ -549,7 +661,7 @@ public void testGeneratePasswordResetLink() throws Exception { @Test public void testGenerateEmailVerificationResetLink() throws Exception { RandomUser user = RandomUser.create(); - auth.createUser(new CreateRequest() + auth.createUser(new UserRecord.CreateRequest() .setUid(user.uid) .setEmail(user.email) .setEmailVerified(false) @@ -572,7 +684,7 @@ public void testGenerateEmailVerificationResetLink() throws Exception { @Test public void testGenerateSignInWithEmailLink() throws Exception { RandomUser user = RandomUser.create(); - auth.createUser(new CreateRequest() + auth.createUser(new UserRecord.CreateRequest() .setUid(user.uid) .setEmail(user.email) .setEmailVerified(false) @@ -686,9 +798,9 @@ private String signInWithEmailLink( } } - private void checkRecreate(String uid) throws Exception { + private void checkRecreateUser(String uid) throws Exception { try { - auth.createUserAsync(new CreateRequest().setUid(uid)).get(); + auth.createUserAsync(new UserRecord.CreateRequest().setUid(uid)).get(); fail("No error thrown for creating user with existing ID"); } catch (ExecutionException e) { assertTrue(e.getCause() instanceof FirebaseAuthException); diff --git a/src/test/java/com/google/firebase/auth/FirebaseUserManagerTest.java b/src/test/java/com/google/firebase/auth/FirebaseUserManagerTest.java index 47227b33c..a9b888167 100644 --- a/src/test/java/com/google/firebase/auth/FirebaseUserManagerTest.java +++ b/src/test/java/com/google/firebase/auth/FirebaseUserManagerTest.java @@ -458,7 +458,7 @@ public void testListTenants() throws Exception { checkTenant(tenants.get(1), "TENANT_2"); assertEquals("", page.getNextPageToken()); checkRequestHeaders(interceptor); - checkUrl(interceptor, "GET", TENANTS_BASE_URL + ":list"); + checkUrl(interceptor, "GET", TENANTS_BASE_URL); GenericUrl url = interceptor.getResponse().getRequest().getUrl(); assertEquals(999, url.getFirst("pageSize")); assertNull(url.getFirst("pageToken")); @@ -477,7 +477,7 @@ public void testListTenantsWithPageToken() throws Exception { checkTenant(tenants.get(1), "TENANT_2"); assertEquals("", page.getNextPageToken()); checkRequestHeaders(interceptor); - checkUrl(interceptor, "GET", TENANTS_BASE_URL + ":list"); + checkUrl(interceptor, "GET", TENANTS_BASE_URL); GenericUrl url = interceptor.getResponse().getRequest().getUrl(); assertEquals(999, url.getFirst("pageSize")); assertEquals("token", url.getFirst("pageToken")); @@ -1469,7 +1469,13 @@ private static void checkRequestHeaders(TestResponseInterceptor interceptor) { private static void checkUrl(TestResponseInterceptor interceptor, String method, String url) { HttpRequest request = interceptor.getResponse().getRequest(); - assertEquals(method, request.getRequestMethod()); + if (method.equals("PATCH")) { + assertEquals("PATCH", + request.getHeaders().getFirstHeaderStringValue("X-HTTP-Method-Override")); + assertEquals("POST", request.getRequestMethod()); + } else { + assertEquals(method, request.getRequestMethod()); + } assertEquals(url, request.getUrl().toString().split("\\?")[0]); } diff --git a/src/test/java/com/google/firebase/auth/TenantTest.java b/src/test/java/com/google/firebase/auth/TenantTest.java index 1fc796dd1..a0d271991 100644 --- a/src/test/java/com/google/firebase/auth/TenantTest.java +++ b/src/test/java/com/google/firebase/auth/TenantTest.java @@ -34,7 +34,7 @@ public class TenantTest { private static final String TENANT_JSON_STRING = "{" - + "\"name\":\"TENANT_ID\"," + + "\"name\":\"projects/project-id/resource/TENANT_ID\"," + "\"displayName\":\"DISPLAY_NAME\"," + "\"allowPasswordSignup\":true," + "\"enableEmailLinkSignin\":false"