Skip to content

Commit 0f69aca

Browse files
committed
Implement getUserByProviderUid.
1 parent d672e23 commit 0f69aca

File tree

4 files changed

+216
-5
lines changed

4 files changed

+216
-5
lines changed

FirebaseAdmin/FirebaseAdmin.IntegrationTests/FirebaseAuthTest.cs

+18-1
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,15 @@ public async Task UserLifecycle()
225225
user = await FirebaseAuth.DefaultInstance.GetUserByEmailAsync(randomUser.Email);
226226
Assert.Equal(uid, user.Uid);
227227

228-
// Disable user and remove properties
228+
// Get user by phone provider uid
229+
user = await FirebaseAuth.DefaultInstance.GetUserByProviderUidAsync("phone", randomUser.PhoneNumber);
230+
Assert.Equal(uid, user.Uid);
231+
232+
// Get user by email provider uid
233+
user = await FirebaseAuth.DefaultInstance.GetUserByProviderUidAsync("email", randomUser.Email);
234+
Assert.Equal(uid, user.Uid);
235+
236+
// Disable user and remove properties
229237
var disableArgs = new UserRecordArgs()
230238
{
231239
Uid = uid,
@@ -276,6 +284,15 @@ public async Task GetUserNonExistingEmail()
276284
Assert.Equal(AuthErrorCode.UserNotFound, exception.AuthErrorCode);
277285
}
278286

287+
[Fact]
288+
public async Task GetUserNonExistingProviderUid()
289+
{
290+
var exception = await Assert.ThrowsAsync<FirebaseAuthException>(
291+
async () => await FirebaseAuth.DefaultInstance.GetUserByProviderUidAsync("google.com", "non_existing_user"));
292+
293+
Assert.Equal(AuthErrorCode.UserNotFound, exception.AuthErrorCode);
294+
}
295+
279296
[Fact]
280297
public async Task UpdateUserNonExistingUid()
281298
{

FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseUserManagerTest.cs

+103
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,109 @@ public async Task GetUserByPhoneNumberEmpty()
326326
await Assert.ThrowsAsync<ArgumentException>(() => auth.GetUserByPhoneNumberAsync(string.Empty));
327327
}
328328

329+
[Fact]
330+
public async Task GetUserByProviderUid()
331+
{
332+
var handler = new MockMessageHandler()
333+
{
334+
Response = GetUserResponse,
335+
};
336+
var auth = this.CreateFirebaseAuth(handler);
337+
338+
var userRecord = await auth.GetUserByProviderUidAsync("google.com", "google_uid");
339+
340+
Assert.Equal("user1", userRecord.Uid);
341+
Assert.Null(userRecord.DisplayName);
342+
Assert.Null(userRecord.Email);
343+
Assert.Null(userRecord.PhoneNumber);
344+
Assert.Null(userRecord.PhotoUrl);
345+
Assert.Equal("firebase", userRecord.ProviderId);
346+
Assert.False(userRecord.Disabled);
347+
Assert.False(userRecord.EmailVerified);
348+
Assert.Equal(UserRecord.UnixEpoch, userRecord.TokensValidAfterTimestamp);
349+
Assert.Empty(userRecord.CustomClaims);
350+
Assert.Empty(userRecord.ProviderData);
351+
Assert.Null(userRecord.UserMetaData.CreationTimestamp);
352+
Assert.Null(userRecord.UserMetaData.LastSignInTimestamp);
353+
354+
var request = NewtonsoftJsonSerializer.Instance.Deserialize<Dictionary<string, object>>(handler.LastRequestBody);
355+
Assert.Equal(new JArray("{providerId: google.com, rawId: google_uid}"), request["federatedUserId"]);
356+
this.AssertClientVersion(handler.LastRequestHeaders);
357+
}
358+
359+
[Fact]
360+
public async Task GetUserByProviderUidWithPhoneProvider()
361+
{
362+
var handler = new MockMessageHandler()
363+
{
364+
Response = GetUserResponse,
365+
};
366+
var auth = this.CreateFirebaseAuth(handler);
367+
368+
var userRecord = await auth.GetUserByProviderUidAsync("phone", "+1234567890");
369+
370+
Assert.Equal("user1", userRecord.Uid);
371+
372+
var request = NewtonsoftJsonSerializer.Instance.Deserialize<Dictionary<string, object>>(handler.LastRequestBody);
373+
Assert.Equal(new JArray("+1234567890"), request["phoneNumber"]);
374+
Assert.False(request.ContainsKey("federatedUserId"));
375+
this.AssertClientVersion(handler.LastRequestHeaders);
376+
}
377+
378+
[Fact]
379+
public async Task GetUserByProviderUidWithEmailProvider()
380+
{
381+
var handler = new MockMessageHandler()
382+
{
383+
Response = GetUserResponse,
384+
};
385+
var auth = this.CreateFirebaseAuth(handler);
386+
387+
var userRecord = await auth.GetUserByProviderUidAsync("email", "[email protected]");
388+
389+
Assert.Equal("user1", userRecord.Uid);
390+
391+
var request = NewtonsoftJsonSerializer.Instance.Deserialize<Dictionary<string, object>>(handler.LastRequestBody);
392+
Assert.Equal(new JArray("[email protected]"), request["email"]);
393+
Assert.False(request.ContainsKey("federatedUserId"));
394+
this.AssertClientVersion(handler.LastRequestHeaders);
395+
}
396+
397+
[Fact]
398+
public async Task GetUserByProviderUidUserNotFound()
399+
{
400+
var handler = new MockMessageHandler()
401+
{
402+
Response = @"{""users"": []}",
403+
};
404+
var auth = this.CreateFirebaseAuth(handler);
405+
406+
var exception = await Assert.ThrowsAsync<FirebaseAuthException>(
407+
async () => await auth.GetUserByProviderUidAsync("google.com", "google_uid"));
408+
409+
Assert.Equal(ErrorCode.NotFound, exception.ErrorCode);
410+
Assert.Equal(AuthErrorCode.UserNotFound, exception.AuthErrorCode);
411+
Assert.Equal("Failed to get user with federated user ID: {providerId: google.com, rawId: google_uid}", exception.Message);
412+
Assert.NotNull(exception.HttpResponse);
413+
Assert.Null(exception.InnerException);
414+
}
415+
416+
[Fact]
417+
public async Task GetUserByProviderUidNull()
418+
{
419+
var auth = this.CreateFirebaseAuth(new MockMessageHandler());
420+
await Assert.ThrowsAsync<ArgumentException>(() => auth.GetUserByProviderUidAsync("google.com", null));
421+
await Assert.ThrowsAsync<ArgumentException>(() => auth.GetUserByProviderUidAsync(null, "google_uid"));
422+
}
423+
424+
[Fact]
425+
public async Task GetUserByProviderUidEmpty()
426+
{
427+
var auth = this.CreateFirebaseAuth(new MockMessageHandler());
428+
await Assert.ThrowsAsync<ArgumentException>(() => auth.GetUserByProviderUidAsync("google.com", string.Empty));
429+
await Assert.ThrowsAsync<ArgumentException>(() => auth.GetUserByProviderUidAsync(string.Empty, "google_uid"));
430+
}
431+
329432
[Fact]
330433
public async Task ListUsers()
331434
{

FirebaseAdmin/FirebaseAdmin/Auth/FirebaseAuth.cs

+43
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,49 @@ public async Task<UserRecord> GetUserByPhoneNumberAsync(
413413
.ConfigureAwait(false);
414414
}
415415

416+
/// <summary>
417+
/// Gets a <see cref="UserRecord"/> object containing information about the user identified by
418+
/// <paramref name="providerId"/> and <paramref name="providerUid"/>.
419+
/// </summary>
420+
/// <param name="providerId">Identifier for the given provider, for example,
421+
/// "google.com" for the Google provider.</param>
422+
/// <param name="providerUid">The user identifier with the given provider.</param>
423+
/// <returns>A task that completes with a <see cref="UserRecord"/> representing
424+
/// a user with the specified provider user identifier.</returns>
425+
/// <exception cref="ArgumentException">If the provider identifier is null or empty,
426+
/// or if the provider user identifier is empty.</exception>
427+
/// <exception cref="FirebaseAuthException">If a user cannot be found with the specified
428+
/// provider user identifier.</exception>
429+
public async Task<UserRecord> GetUserByProviderUidAsync(string providerId, string providerUid)
430+
{
431+
return await this.GetUserByProviderUidAsync(providerId, providerUid, default(CancellationToken))
432+
.ConfigureAwait(false);
433+
}
434+
435+
/// <summary>
436+
/// Gets a <see cref="UserRecord"/> object containing information about the user identified by
437+
/// <paramref name="providerId"/> and <paramref name="providerUid"/>.
438+
/// </summary>
439+
/// <param name="providerId">Identifier for the given provider, for example,
440+
/// "google.com" for the Google provider.</param>
441+
/// <param name="providerUid">The user identifier with the given provider.</param>
442+
/// <param name="cancellationToken">A cancellation token to monitor the asynchronous
443+
/// operation.</param>
444+
/// <returns>A task that completes with a <see cref="UserRecord"/> representing
445+
/// a user with the specified provider user identifier.</returns>
446+
/// <exception cref="ArgumentException">If the provider identifier is null or empty,
447+
/// or if the provider user identifier is empty.</exception>
448+
/// <exception cref="FirebaseAuthException">If a user cannot be found with the specified
449+
/// provider user identifier.</exception>
450+
public async Task<UserRecord> GetUserByProviderUidAsync(
451+
string providerId, string providerUid, CancellationToken cancellationToken)
452+
{
453+
var userManager = this.IfNotDeleted(() => this.userManager.Value);
454+
455+
return await userManager.GetUserByProviderUidAsync(providerId, providerUid, cancellationToken)
456+
.ConfigureAwait(false);
457+
}
458+
416459
/// <summary>
417460
/// Updates an existing user account with the attributes contained in the specified <see cref="UserRecordArgs"/>.
418461
/// The <see cref="UserRecordArgs.Uid"/> property must be specified.

FirebaseAdmin/FirebaseAdmin/Auth/FirebaseUserManager.cs

+52-4
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ internal async Task<UserRecord> GetUserByIdAsync(
102102
var query = new UserQuery()
103103
{
104104
Field = "localId",
105-
Value = uid,
105+
Value = new string[] { uid },
106106
Label = "uid",
107107
};
108108
return await this.GetUserAsync(query, cancellationToken)
@@ -127,7 +127,55 @@ internal async Task<UserRecord> GetUserByEmailAsync(
127127
var query = new UserQuery()
128128
{
129129
Field = "email",
130-
Value = email,
130+
Value = new string[] { email },
131+
};
132+
return await this.GetUserAsync(query, cancellationToken)
133+
.ConfigureAwait(false);
134+
}
135+
136+
/// <summary>
137+
/// Gets the user data corresponding to the given provider user identifer.
138+
/// </summary>
139+
/// <param name="providerId">Identifier for the given provider, for example,
140+
/// "google.com" for the Google provider.</param>
141+
/// <param name="providerUid">The user identifier with the given provider.</param>
142+
/// <param name="cancellationToken">A cancellation token to monitor the asynchronous
143+
/// operation.</param>
144+
/// <returns>A record of user with the queried provider user identifier if one exists.</returns>
145+
internal async Task<UserRecord> GetUserByProviderUidAsync(
146+
string providerId, string providerUid, CancellationToken cancellationToken = default(CancellationToken))
147+
{
148+
if (string.IsNullOrEmpty(providerId))
149+
{
150+
throw new ArgumentException("providerId cannot be null or empty.");
151+
}
152+
153+
if (string.IsNullOrEmpty(providerUid))
154+
{
155+
throw new ArgumentException("providerUid cannot be null or empty.");
156+
}
157+
158+
if (providerId.Equals("phone"))
159+
{
160+
return await this.GetUserByPhoneNumberAsync(providerUid, cancellationToken);
161+
}
162+
163+
if (providerId.Equals("email"))
164+
{
165+
return await this.GetUserByEmailAsync(providerUid, cancellationToken);
166+
}
167+
168+
var federatedUserId = new Dictionary<string, object>()
169+
{
170+
{ "rawId", providerUid },
171+
{ "providerId", providerId },
172+
};
173+
174+
var query = new UserQuery()
175+
{
176+
Field = "federatedUserId",
177+
Value = new Dictionary<string, object>[] { federatedUserId },
178+
Label = "Provider user ID",
131179
};
132180
return await this.GetUserAsync(query, cancellationToken)
133181
.ConfigureAwait(false);
@@ -309,7 +357,7 @@ private class UserQuery
309357
{
310358
internal string Field { get; set; }
311359

312-
internal string Value { get; set; }
360+
internal object Value { get; set; }
313361

314362
internal string Label { get; set; }
315363

@@ -331,7 +379,7 @@ internal Dictionary<string, object> Build()
331379
{
332380
return new Dictionary<string, object>()
333381
{
334-
{ this.Field, new string[] { this.Value } },
382+
{ this.Field, this.Value },
335383
};
336384
}
337385
}

0 commit comments

Comments
 (0)