Skip to content
Merged
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Unreleased

- [added] Implemented the `GetUserById()` API in the `FirebaseUserManager` class.

-

# v1.4.0
Expand Down
22 changes: 19 additions & 3 deletions FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseUserManagerTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ public class FirebaseUserManagerTest
[Fact]
public void InvalidUidForUserRecord()
{
Assert.Throws<ArgumentException>(() => new UserRecord(null));
Assert.Throws<ArgumentException>(() => new UserRecord((string)null));
Assert.Throws<ArgumentException>(() => new UserRecord((GetAccountInfoResponse.User)null));
Assert.Throws<ArgumentException>(() => new UserRecord(string.Empty));
Assert.Throws<ArgumentException>(() => new UserRecord(new string('a', 129)));
}
Expand Down Expand Up @@ -76,8 +77,16 @@ public async Task GetUserById()
{
var handler = new MockMessageHandler()
{
Response = new UserRecord("user1"),
Response = new GetAccountInfoResponse()
{
Kind = "identitytoolkit#GetAccountInfoResponse",
Users = new List<GetAccountInfoResponse.User>()
{
new GetAccountInfoResponse.User() { UserId = "user1" },
},
},
};

var factory = new MockHttpClientFactory(handler);
var userManager = new FirebaseUserManager(
new FirebaseUserManagerArgs
Expand Down Expand Up @@ -114,7 +123,14 @@ public async Task UpdateUser()
{
var handler = new MockMessageHandler()
{
Response = new UserRecord("user1"),
Response = new GetAccountInfoResponse()
{
Kind = "identitytoolkit#GetAccountInfoResponse",
Users = new List<GetAccountInfoResponse.User>()
{
new GetAccountInfoResponse.User() { UserId = "user1" },
},
},
};
var factory = new MockHttpClientFactory(handler);
var userManager = new FirebaseUserManager(
Expand Down
33 changes: 33 additions & 0 deletions FirebaseAdmin/FirebaseAdmin/Auth/FirebaseAuth.cs
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,39 @@ public async Task<FirebaseToken> VerifyIdTokenAsync(
.ConfigureAwait(false);
}

/// <summary>
/// Gets a <see cref="UserRecord"/> object containig information about the user who's
/// user ID was specified in <paramref name="uid"/>.
/// </summary>
/// <param name="uid">The user ID for the user who's data is to be retrieved.</param>
/// <returns>A task that completes with a <see cref="UserRecord"/> representing
/// a user with the specified user ID.</returns>
/// <exception cref="ArgumentException">If user ID argument is null or empty.</exception>
/// <exception cref="FirebaseException">If a user cannot be found with the specified user ID.</exception>
public async Task<UserRecord> GetUserAsync(string uid)
{
return await this.GetUserAsync(uid, default(CancellationToken));
}

/// <summary>
/// Gets a <see cref="UserRecord"/> object containig information about the user who's
/// user ID was specified in <paramref name="uid"/>.
/// </summary>
/// <param name="uid">The user ID for the user who's data is to be retrieved.</param>
/// <param name="cancellationToken">A cancellation token to monitor the asynchronous
/// operation.</param>
/// <returns>A task that completes with a <see cref="UserRecord"/> representing
/// a user with the specified user ID.</returns>
/// <exception cref="ArgumentException">If user ID argument is null or empty.</exception>
/// <exception cref="FirebaseException">If a user cannot be found with the specified user ID.</exception>
public async Task<UserRecord> GetUserAsync(
string uid, CancellationToken cancellationToken)
{
var userManager = this.IfNotDeleted(() => this.userManager.Value);

return await userManager.GetUserById(uid, cancellationToken);
}

/// <summary>
/// Sets the specified custom claims on an existing user account. A null claims value
/// removes any claims currently set on the user account. The claims must serialize into
Expand Down
23 changes: 18 additions & 5 deletions FirebaseAdmin/FirebaseAdmin/Auth/FirebaseUserManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,14 +81,21 @@ public async Task<UserRecord> GetUserById(
{
{ "localId", uid },
};
var response = await this.PostAndDeserializeAsync<JObject>(

var response = await this.PostAndDeserializeAsync<GetAccountInfoResponse>(
getUserPath, payload, cancellationToken).ConfigureAwait(false);
if (response == null || uid != (string)response["localId"])
if (response == null || response.Users == null || response.Users.Count == 0)
{
throw new FirebaseException($"Failed to get user: {uid}");
}

var user = response.Users[0];
if (user == null || user.UserId != uid)
{
throw new FirebaseException($"Failed to get user: {uid}");
}

return new UserRecord((string)response["localId"]);
return new UserRecord(user);
}

/// <summary>
Expand All @@ -102,9 +109,15 @@ public async Task UpdateUserAsync(
UserRecord user, CancellationToken cancellationToken = default(CancellationToken))
{
const string updatePath = "accounts:update";
var response = await this.PostAndDeserializeAsync<JObject>(
var response = await this.PostAndDeserializeAsync<GetAccountInfoResponse>(
updatePath, user, cancellationToken).ConfigureAwait(false);
if (user.Uid != (string)response["localId"])
if (response == null || response.Users == null || response.Users.Count == 0)
{
throw new FirebaseException($"Failed to get user: {user.Uid}");
}

var updatedUser = response.Users[0];
if (updatedUser == null || updatedUser.UserId != user.Uid)
{
throw new FirebaseException($"Failed to update user: {user.Uid}");
}
Expand Down
68 changes: 68 additions & 0 deletions FirebaseAdmin/FirebaseAdmin/Auth/IUserInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace FirebaseAdmin.Auth
{
/// <summary>
/// A collection of standard profile information for a user. Used to expose profile information
/// returned by an identity provider.
/// </summary>
public interface IUserInfo
{
/// <summary>
/// Gets the user's unique ID assigned by the identity provider.
/// </summary>
/// <returns>a user ID string.</returns>
string Uid
{
get;
}

/// <summary>
/// Gets the user's display name, if available.
/// </summary>
/// <returns>a display name string or null.</returns>
string DisplayName
{
get;
}

/// <summary>
/// Gets the user's email address, if available.
/// </summary>
/// <returns>an email address string or null.</returns>
string Email
{
get;
}

/// <summary>
/// Gets the user's phone number, if available.
/// </summary>
/// <returns>a phone number string or null.</returns>
string PhoneNumber
{
get;
}

/// <summary>
/// Gets the user's photo URL, if available.
/// </summary>
/// <returns>a URL string or null.</returns>
string PhotoUrl
{
get;
}

/// <summary>
/// Gets the ID of the identity provider. This can be a short domain name (e.g. google.com) or
/// the identifier of an OpenID identity provider.
/// </summary>
/// <returns>an ID string that uniquely identifies the identity provider.</returns>
string ProviderId
{
get;
}
}
}
145 changes: 145 additions & 0 deletions FirebaseAdmin/FirebaseAdmin/Auth/Internal/GetAccountInfoResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
using System;
using System.Collections.Generic;
using System.Text;
using Newtonsoft.Json;

namespace FirebaseAdmin.Auth
{
/// <summary>
/// JSON data binding for GetAccountInfoResponse messages sent by Google identity toolkit service.
/// </summary>
internal sealed class GetAccountInfoResponse
{
/// <summary>
/// Gets or sets a string representing what kind of account is represented by this object.
/// </summary>
[JsonProperty(PropertyName = "kind")]
public string Kind { get; set; }

/// <summary>
/// Gets or sets a list of provider users linked to this account.
/// </summary>
[JsonProperty(PropertyName = "users")]
public List<User> Users { get; set; }

/// <summary>
/// JSON data binding for user records.
/// </summary>
internal sealed class User
{
/// <summary>
/// Gets or sets the user's ID.
/// </summary>
[JsonProperty(PropertyName = "localId")]
public string UserId { get; set; }

/// <summary>
/// Gets or sets the user's email address.
/// </summary>
[JsonProperty(PropertyName = "email")]
public string Email { get; set; }

/// <summary>
/// Gets or sets the user's phone number.
/// </summary>
[JsonProperty(PropertyName = "phoneNumber")]
public string PhoneNumber { get; set; }

/// <summary>
/// Gets or sets a value indicating whether the user's email address is verified or not.
/// </summary>
[JsonProperty(PropertyName = "emailVerified")]
public bool EmailVerified { get; set; }

/// <summary>
/// Gets or sets the user's display name.
/// </summary>
[JsonProperty(PropertyName = "displayName")]
public string DisplayName { get; set; }

/// <summary>
/// Gets or sets the URL for the user's photo.
/// </summary>
[JsonProperty(PropertyName = "photoUrl")]
public string PhotoUrl { get; set; }

/// <summary>
/// Gets or sets a value indicating whether the user is disabled or not.
/// </summary>
[JsonProperty(PropertyName = "disabled")]
public bool Disabled { get; set; }

/// <summary>
/// Gets or sets a list of provider-specified data for this user.
/// </summary>
[JsonProperty(PropertyName = "providerUserInfo")]
public List<Provider> Providers { get; set; }

/// <summary>
/// Gets or sets the timestamp representing the time that the user account was created.
/// </summary>
[JsonProperty(PropertyName = "createdAt")]
public long CreatedAt { get; set; }

/// <summary>
/// Gets or sets the timestamp representing the last time that the user has logged in.
/// </summary>
[JsonProperty(PropertyName = "lastLoginAt")]
public long LastLoginAt { get; set; }

/// <summary>
/// Gets or sets the timestamp representing the time that the user account was first valid.
/// </summary>
[JsonProperty(PropertyName = "validSince")]
public long ValidSince { get; set; }

/// <summary>
/// Gets or sets the user's custom claims.
/// </summary>
[JsonProperty(PropertyName = "customAttributes")]
public string CustomClaims { get; set; }
}

/// <summary>
/// JSON data binding for provider data.
/// </summary>
internal sealed class Provider
{
/// <summary>
/// Gets or sets the user's ID.
/// </summary>
[JsonProperty(PropertyName = "uid")]
public string UserId { get; set; }

/// <summary>
/// Gets or sets the user's display name.
/// </summary>
[JsonProperty(PropertyName = "displayName")]
public string DisplayName { get; set; }

/// <summary>
/// Gets or sets the user's email address.
/// </summary>
[JsonProperty(PropertyName = "email")]
public string Email { get; set; }

/// <summary>
/// Gets or sets the user's phone number.
/// </summary>
[JsonProperty(PropertyName = "phoneNumber")]
public string PhoneNumber { get; set; }

/// <summary>
/// Gets or sets the URL for the user's photo.
/// </summary>
[JsonProperty(PropertyName = "photoUrl")]
public string PhotoUrl { get; set; }

/// <summary>
/// Gets or sets the provider's ID.
/// </summary>
[JsonProperty(PropertyName = "providerId")]
public string ProviderID { get; set; }
}
}
}
Loading