Skip to content

Commit 5484ab1

Browse files
committed
Add API to look up users by federated ID.
1 parent d01b062 commit 5484ab1

File tree

4 files changed

+208
-23
lines changed

4 files changed

+208
-23
lines changed

src/main/java/com/google/firebase/auth/FirebaseAuth.java

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -605,6 +605,56 @@ protected UserRecord execute() throws FirebaseAuthException {
605605
};
606606
}
607607

608+
/**
609+
* Gets the user data corresponding to the specified user federated identifier.
610+
*
611+
* @param providerUid The user identifier with the given provider.
612+
* @param providerId Identifier for the given federated provider, for example,
613+
* "google.com" for the Google provider.
614+
* @return A {@link UserRecord} instance.
615+
* @throws IllegalArgumentException If the providerUid is null or empty, or if
616+
* the providerId is null, empty, or does not belong to a federated provider.
617+
* @throws FirebaseAuthException If an error occurs while retrieving user data.
618+
*/
619+
public UserRecord getUserByFederatedId(
620+
@NonNull String providerUid, @NonNull String providerId) throws FirebaseAuthException {
621+
return getUserByFederatedIdOp(providerUid, providerId).call();
622+
}
623+
624+
/**
625+
* Gets the user data corresponding to the specified user federated identifier.
626+
*
627+
* @param providerUid The user identifier with the given provider.
628+
* @param providerId Identifer for the given federated provider, for example,
629+
* "google.com" for the Google provider.
630+
* @return An {@code ApiFuture} which will complete successfully with a {@link UserRecord}
631+
* instance. If an error occurs while retrieving user data or if the uid and provider ID
632+
* do not correspond to a user, the future throws a {@link FirebaseAuthException}.
633+
* @throws IllegalArgumentException If the providerUid is null or empty, or if
634+
* the provider ID is null, empty, or does not belong to a federated provider.
635+
*/
636+
public ApiFuture<UserRecord> getUserByFederatedIdAsync(
637+
@NonNull String providerUid, @NonNull String providerId) {
638+
return getUserByFederatedIdOp(providerUid, providerId).callAsync(firebaseApp);
639+
}
640+
641+
private CallableOperation<UserRecord, FirebaseAuthException> getUserByFederatedIdOp(
642+
final String providerUid, final String providerId) {
643+
checkNotDestroyed();
644+
checkArgument(!Strings.isNullOrEmpty(providerUid), "providerUid must not be null or empty");
645+
checkArgument(!Strings.isNullOrEmpty(providerId), "providerId must not be null or empty");
646+
checkArgument(!providerId.equals("phone")
647+
&& !providerId.equals("password")
648+
&& !providerId.equals("anonymous"), "providerId must belong to a federated provider");
649+
final FirebaseUserManager userManager = getUserManager();
650+
return new CallableOperation<UserRecord, FirebaseAuthException>() {
651+
@Override
652+
protected UserRecord execute() throws FirebaseAuthException {
653+
return userManager.getUserByFederatedId(providerUid, providerId);
654+
}
655+
};
656+
}
657+
608658
/**
609659
* Gets a page of users starting from the specified {@code pageToken}. Page size will be
610660
* limited to 1000 users.

src/main/java/com/google/firebase/auth/FirebaseUserManager.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,23 @@ UserRecord getUserByPhoneNumber(String phoneNumber) throws FirebaseAuthException
164164
return new UserRecord(response.getUsers().get(0), jsonFactory);
165165
}
166166

167+
UserRecord getUserByFederatedId(
168+
String providerUid, String providerId) throws FirebaseAuthException {
169+
final Map<String, Object> payload = ImmutableMap.<String, Object>of(
170+
"federatedUserId", ImmutableList.of(
171+
ImmutableMap.<String, Object>builder()
172+
.put("rawId", providerUid).put("providerId", providerId).build()));
173+
174+
GetAccountInfoResponse response = post(
175+
"/accounts:lookup", payload, GetAccountInfoResponse.class);
176+
if (response == null || response.getUsers() == null || response.getUsers().isEmpty()) {
177+
throw new FirebaseAuthException(USER_NOT_FOUND_ERROR,
178+
"No user record found for providerUid " + providerUid
179+
+ " and federated provider ID " + providerId);
180+
}
181+
return new UserRecord(response.getUsers().get(0), jsonFactory);
182+
}
183+
167184
String createUser(CreateRequest request) throws FirebaseAuthException {
168185
GenericJson response = post(
169186
"/accounts", request.getProperties(), GenericJson.class);

src/test/java/com/google/firebase/auth/FirebaseAuthIT.java

Lines changed: 131 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
import com.google.firebase.auth.UserRecord.CreateRequest;
5050
import com.google.firebase.auth.UserRecord.UpdateRequest;
5151
import com.google.firebase.auth.hash.Scrypt;
52+
import com.google.firebase.internal.Nullable;
5253
import com.google.firebase.testing.IntegrationTestUtils;
5354
import java.io.IOException;
5455
import java.net.URLDecoder;
@@ -140,37 +141,98 @@ public void testDeleteNonExistingUser() throws Exception {
140141
@Test
141142
public void testCreateUserWithParams() throws Exception {
142143
RandomUser randomUser = RandomUser.create();
143-
String phone = randomPhoneNumber();
144-
CreateRequest user = new CreateRequest()
145-
.setUid(randomUser.uid)
146-
.setEmail(randomUser.email)
147-
.setPhoneNumber(phone)
148-
.setDisplayName("Random User")
149-
.setPhotoUrl("https://example.com/photo.png")
150-
.setEmailVerified(true)
151-
.setPassword("password");
152-
153-
UserRecord userRecord = auth.createUserAsync(user).get();
144+
String randomPhoneNumber = randomPhoneNumber();
154145
try {
155-
assertEquals(randomUser.uid, userRecord.getUid());
156-
assertEquals("Random User", userRecord.getDisplayName());
157-
assertEquals(randomUser.email, userRecord.getEmail());
158-
assertEquals(phone, userRecord.getPhoneNumber());
159-
assertEquals("https://example.com/photo.png", userRecord.getPhotoUrl());
160-
assertTrue(userRecord.isEmailVerified());
161-
assertFalse(userRecord.isDisabled());
162-
163-
assertEquals(2, userRecord.getProviderData().length);
146+
UserRecord user = createUser(randomUser.uid, randomPhoneNumber, randomUser.email);
147+
assertEquals(randomUser.uid, user.getUid());
148+
assertEquals("Random User", user.getDisplayName());
149+
assertEquals(randomUser.email, user.getEmail());
150+
assertEquals(randomPhoneNumber, user.getPhoneNumber());
151+
assertEquals("https://example.com/photo.png", user.getPhotoUrl());
152+
assertTrue(user.isEmailVerified());
153+
assertFalse(user.isDisabled());
154+
155+
assertEquals(2, user.getProviderData().length);
164156
List<String> providers = new ArrayList<>();
165-
for (UserInfo provider : userRecord.getProviderData()) {
157+
for (UserInfo provider : user.getProviderData()) {
166158
providers.add(provider.getProviderId());
167159
}
168160
assertTrue(providers.contains("password"));
169161
assertTrue(providers.contains("phone"));
170162

171-
checkRecreate(randomUser.uid);
163+
checkRecreate(user.getUid());
172164
} finally {
173-
auth.deleteUserAsync(userRecord.getUid()).get();
165+
auth.deleteUserAsync(randomUser.uid).get();
166+
}
167+
}
168+
169+
@Test
170+
public void testLookupUserByPhone() throws Exception {
171+
RandomUser randomUser1 = RandomUser.create();
172+
String phoneNumber1 = null;
173+
RandomUser randomUser2 = RandomUser.create();
174+
String randomPhoneNumber2 = randomPhoneNumber();
175+
RandomUser randomUser3 = RandomUser.create();
176+
String randomPhoneNumber3 = randomPhoneNumber();
177+
try {
178+
UserRecord user1 = createUser(
179+
randomUser1.uid, /* phoneNumber= */ null, randomUser1.email);
180+
UserRecord user2 = createUser(
181+
randomUser2.uid, randomPhoneNumber2, randomUser2.email);
182+
UserImportResult user3 = importUser(
183+
randomUser3.uid, randomPhoneNumber3, randomUser3.email, "google.com");
184+
185+
UserRecord lookedUpRecord = auth.getUserByPhoneNumberAsync(randomPhoneNumber2).get();
186+
assertEquals(lookedUpRecord.getUid(), randomUser2.uid);
187+
188+
lookedUpRecord = auth.getUserByPhoneNumberAsync(randomPhoneNumber3).get();
189+
assertEquals(lookedUpRecord.getUid(), randomUser3.uid);
190+
} finally {
191+
auth.deleteUserAsync(randomUser1.uid).get();
192+
auth.deleteUserAsync(randomUser2.uid).get();
193+
auth.deleteUserAsync(randomUser3.uid).get();
194+
}
195+
}
196+
197+
@Test
198+
public void testLookupUserByFederatedId() throws Exception {
199+
RandomUser randomUser1 = RandomUser.create();
200+
String phoneNumber1 = null;
201+
RandomUser randomUser2 = RandomUser.create();
202+
String randomPhoneNumber2 = randomPhoneNumber();
203+
RandomUser randomUser3 = RandomUser.create();
204+
String randomPhoneNumber3 = randomPhoneNumber();
205+
try {
206+
UserRecord user1 = createUser(
207+
randomUser1.uid, /* phoneNumber= */ null, randomUser1.email);
208+
UserRecord user2 = createUser(
209+
randomUser2.uid, randomPhoneNumber2, randomUser2.email);
210+
UserImportResult user3 = importUser(
211+
randomUser3.uid, randomPhoneNumber3, randomUser3.email, "google.com");
212+
213+
UserRecord lookedUpRecord = auth.getUserByFederatedIdAsync(
214+
randomUser3.uid + "_google.com", "google.com").get();
215+
assertEquals(lookedUpRecord.getUid(), randomUser3.uid);
216+
assertEquals(2, lookedUpRecord.getProviderData().length);
217+
List<String> providers = new ArrayList<>();
218+
for (UserInfo provider : lookedUpRecord.getProviderData()) {
219+
providers.add(provider.getProviderId());
220+
}
221+
assertTrue(providers.contains("phone"));
222+
assertTrue(providers.contains("google.com"));
223+
224+
try {
225+
// Verify that lookup by federated identifier does not accept "phone".
226+
lookedUpRecord = auth.getUserByFederatedIdAsync(
227+
randomPhoneNumber3, "phone").get();
228+
fail("No error thrown for non-federated provider");
229+
} catch (IllegalArgumentException ignored) {
230+
// expected
231+
}
232+
} finally {
233+
auth.deleteUserAsync(randomUser1.uid).get();
234+
auth.deleteUserAsync(randomUser2.uid).get();
235+
auth.deleteUserAsync(randomUser3.uid).get();
174236
}
175237
}
176238

@@ -590,6 +652,52 @@ public void testGenerateSignInWithEmailLink() throws Exception {
590652
}
591653
}
592654

655+
private UserRecord createUser(
656+
String uid,
657+
@Nullable String phoneNumber,
658+
@Nullable String email) throws Exception {
659+
RandomUser randomUser = RandomUser.create();
660+
CreateRequest user = new CreateRequest()
661+
.setUid(uid)
662+
.setDisplayName("Random User")
663+
.setPhotoUrl("https://example.com/photo.png")
664+
.setPassword("password");
665+
if (phoneNumber != null) {
666+
user.setPhoneNumber(phoneNumber);
667+
}
668+
if (email != null) {
669+
user.setEmail(email);
670+
user.setEmailVerified(true);
671+
}
672+
return auth.createUserAsync(user).get();
673+
}
674+
675+
private UserImportResult importUser(
676+
String uid,
677+
@Nullable String phoneNumber,
678+
@Nullable String email,
679+
String providerId) throws Exception {
680+
ImportUserRecord.Builder builder = ImportUserRecord.builder()
681+
.setUid(uid)
682+
.setDisabled(false)
683+
.setUserMetadata(
684+
new UserMetadata(/* creationTimestamp= */ 20L, /* lastSignInTimestamp= */ 20L))
685+
.addUserProvider(
686+
UserProvider.builder()
687+
.setProviderId(providerId)
688+
.setUid(uid + "_" + providerId)
689+
.build());
690+
if (phoneNumber != null) {
691+
builder.setPhoneNumber(phoneNumber);
692+
}
693+
if (email != null) {
694+
builder.setEmail(email);
695+
builder.setEmailVerified(true);
696+
}
697+
ImportUserRecord user = builder.build();
698+
return auth.importUsersAsync(ImmutableList.of(user)).get();
699+
}
700+
593701
private Map<String, String> parseLinkParameters(String link) throws Exception {
594702
Map<String, String> result = new HashMap<>();
595703
int queryBegin = link.indexOf('?');

src/test/java/com/google/firebase/snippets/FirebaseAuthSnippets.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,16 @@ public static void getUserByPhoneNumber(
8585
// [END get_user_by_phone]
8686
}
8787

88+
public static void getUserByFederatedId(
89+
String providerUid, String providerId) throws FirebaseAuthException {
90+
// [START get_user_by_federated_id]
91+
UserRecord userRecord = FirebaseAuth.getInstance().getUserByFederatedId(
92+
providerUid, providerId);
93+
// See the UserRecord reference doc for the contents of userRecord.
94+
System.out.println("Successfully fetched user data: " + userRecord.getUid());
95+
// [END get_user_by_federated_id]
96+
}
97+
8898
public static void createUser() throws FirebaseAuthException {
8999
// [START create_user]
90100
CreateRequest request = new CreateRequest()

0 commit comments

Comments
 (0)