From 6579e7e3aa1ad5a321f8a7aa52798f555c85068c Mon Sep 17 00:00:00 2001 From: Renato Ciuffo Date: Wed, 1 May 2019 12:57:05 -0700 Subject: [PATCH 1/9] Added GetUser method to FirebaseAuth that can be used to retrieve a UserRecord object for the specified user ID. --- .../Auth/FirebaseUserManagerTest.cs | 13 +- .../FirebaseAdmin/Auth/FirebaseAuth.cs | 14 ++ .../FirebaseAdmin/Auth/FirebaseUserManager.cs | 7 +- .../Auth/Internal/GetAccountInfoResponse.cs | 145 ++++++++++++++++++ .../FirebaseAdmin/Auth/ProviderUserInfo.cs | 64 ++++++++ .../FirebaseAdmin/Auth/UserMetadata.cs | 36 +++++ .../FirebaseAdmin/Auth/UserRecord.cs | 126 ++++++++++++++- 7 files changed, 397 insertions(+), 8 deletions(-) create mode 100644 FirebaseAdmin/FirebaseAdmin/Auth/Internal/GetAccountInfoResponse.cs create mode 100644 FirebaseAdmin/FirebaseAdmin/Auth/ProviderUserInfo.cs create mode 100644 FirebaseAdmin/FirebaseAdmin/Auth/UserMetadata.cs diff --git a/FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseUserManagerTest.cs b/FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseUserManagerTest.cs index f8ba735a..14b9bfbf 100644 --- a/FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseUserManagerTest.cs +++ b/FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseUserManagerTest.cs @@ -32,7 +32,8 @@ public class FirebaseUserManagerTest [Fact] public void InvalidUidForUserRecord() { - Assert.Throws(() => new UserRecord(null)); + Assert.Throws(() => new UserRecord((string)null)); + Assert.Throws(() => new UserRecord((Internal.GetAccountInfoResponse.User)null)); Assert.Throws(() => new UserRecord(string.Empty)); Assert.Throws(() => new UserRecord(new string('a', 129))); } @@ -76,8 +77,16 @@ public async Task GetUserById() { var handler = new MockMessageHandler() { - Response = new UserRecord("user1"), + Response = new Internal.GetAccountInfoResponse() + { + Kind = "identitytoolkit#GetAccountInfoResponse", + Users = new List() + { + new Internal.GetAccountInfoResponse.User() { UserID = "user1" }, + }, + }, }; + var factory = new MockHttpClientFactory(handler); var userManager = new FirebaseUserManager( new FirebaseUserManagerArgs diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseAuth.cs b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseAuth.cs index cd3827ef..54528528 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseAuth.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseAuth.cs @@ -263,6 +263,20 @@ public async Task VerifyIdTokenAsync( .ConfigureAwait(false); } + /// + /// Gets a object containig information about the user who's + /// user ID was specified in . + /// + /// The user ID for the user who's data is to be retrieved.. + /// A task that completes with a representing + /// a user with the specified user ID. + /// If user ID argument is null or empty. + /// If a user cannot be found with the specified user ID. + public async Task GetUser(string uid) + { + return await this.userManager.Value.GetUserById(uid); + } + /// /// 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 diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseUserManager.cs b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseUserManager.cs index 4da678cd..f87bf705 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseUserManager.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseUserManager.cs @@ -81,14 +81,15 @@ public async Task GetUserById( { { "localId", uid }, }; - var response = await this.PostAndDeserializeAsync( + + var response = await this.PostAndDeserializeAsync( 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}"); } - return new UserRecord((string)response["localId"]); + return new UserRecord(response.Users[0]); } /// diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/Internal/GetAccountInfoResponse.cs b/FirebaseAdmin/FirebaseAdmin/Auth/Internal/GetAccountInfoResponse.cs new file mode 100644 index 00000000..d7361d2f --- /dev/null +++ b/FirebaseAdmin/FirebaseAdmin/Auth/Internal/GetAccountInfoResponse.cs @@ -0,0 +1,145 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Newtonsoft.Json; + +namespace FirebaseAdmin.Auth.Internal +{ + /// + /// JSON data binding for GetAccountInfoResponse messages sent by Google identity toolkit service. + /// + public sealed class GetAccountInfoResponse + { + /// + /// Gets or sets a string representing what kind of account is represented by this object. + /// + [JsonProperty(PropertyName = "kind")] + public string Kind { get; set; } + + /// + /// Gets or sets a list of provider users linked to this account. + /// + [JsonProperty(PropertyName = "users")] + public List Users { get; set; } + + /// + /// JSON data binding for user records. + /// + public sealed class User + { + /// + /// Gets or sets the user's ID. + /// + [JsonProperty(PropertyName = "localId")] + public string UserID { get; set; } + + /// + /// Gets or sets the user's email address. + /// + [JsonProperty(PropertyName = "email")] + public string Email { get; set; } + + /// + /// Gets or sets the user's phone number. + /// + [JsonProperty(PropertyName = "phoneNumber")] + public string PhoneNumber { get; set; } + + /// + /// Gets or sets a value indicating whether the user's email address is verified or not. + /// + [JsonProperty(PropertyName = "emailVerified")] + public bool EmailVerified { get; set; } + + /// + /// Gets or sets the user's display name. + /// + [JsonProperty(PropertyName = "displayName")] + public string DisplayName { get; set; } + + /// + /// Gets or sets the URL for the user's photo. + /// + [JsonProperty(PropertyName = "photoUrl")] + public string PhotoUrl { get; set; } + + /// + /// Gets or sets a value indicating whether the user is disabled or not. + /// + [JsonProperty(PropertyName = "disabled")] + public bool Disabled { get; set; } + + /// + /// Gets or sets a list of provider-specified data for this user. + /// + [JsonProperty(PropertyName = "providerUserInfo")] + public List Providers { get; set; } + + /// + /// Gets or sets the timestamp representing the time that the user account was created. + /// + [JsonProperty(PropertyName = "createdAt")] + public long CreatedAt { get; set; } + + /// + /// Gets or sets the timestamp representing the last time that the user has logged in. + /// + [JsonProperty(PropertyName = "lastLoginAt")] + public long LastLoginAt { get; set; } + + /// + /// Gets or sets the timestamp representing the time that the user account was first valid. + /// + [JsonProperty(PropertyName = "validSince")] + public long ValidSince { get; set; } + + /// + /// Gets or sets the user's custom claims. + /// + [JsonProperty(PropertyName = "customAttributes")] + public string CustomClaims { get; set; } + } + + /// + /// JSON data binding for provider data. + /// + public sealed class Provider + { + /// + /// Gets or sets the user's ID. + /// + [JsonProperty(PropertyName = "uid")] + public string UserID { get; set; } + + /// + /// Gets or sets the user's display name. + /// + [JsonProperty(PropertyName = "displayName")] + public string DisplayName { get; set; } + + /// + /// Gets or sets the user's email address. + /// + [JsonProperty(PropertyName = "email")] + public string Email { get; set; } + + /// + /// Gets or sets the user's phone number. + /// + [JsonProperty(PropertyName = "phoneNumber")] + public string PhoneNumber { get; set; } + + /// + /// Gets or sets the URL for the user's photo. + /// + [JsonProperty(PropertyName = "photoUrl")] + public string PhotoUrl { get; set; } + + /// + /// Gets or sets the provider's ID. + /// + [JsonProperty(PropertyName = "providerId")] + public string ProviderID { get; set; } + } + } +} diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/ProviderUserInfo.cs b/FirebaseAdmin/FirebaseAdmin/Auth/ProviderUserInfo.cs new file mode 100644 index 00000000..f6444d4a --- /dev/null +++ b/FirebaseAdmin/FirebaseAdmin/Auth/ProviderUserInfo.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace FirebaseAdmin.Auth +{ + /// + /// Contains metadata regarding how a user is known by a particular identity provider (IdP). + /// Instances of this class are immutable and thread safe. + /// + public sealed class ProviderUserInfo + { + private string uid; + private string displayName; + private string email; + private string phoneNumber; + private string photoUrl; + private string providerId; + + /// + /// Initializes a new instance of the class with data provided by an authentication provider. + /// + /// The deserialized JSON user data from the provider. + public ProviderUserInfo(Internal.GetAccountInfoResponse.Provider provider) + { + this.uid = provider.UserID; + this.displayName = provider.DisplayName; + this.email = provider.Email; + this.phoneNumber = provider.PhoneNumber; + this.photoUrl = provider.PhotoUrl; + this.providerId = provider.ProviderID; + } + + /// + /// Gets the user's ID. + /// + public string UserID { get => this.uid; } + + /// + /// Gets the user's display name. + /// + public string DisplayName { get => this.displayName; } + + /// + /// Gets the user's email address. + /// + public string Email { get => this.email; } + + /// + /// Gets the user's phone number. + /// + public string PhoneNumber { get => this.phoneNumber; } + + /// + /// Gets the URL for the user's photo/avatar. + /// + public string PhotoUrl { get => this.photoUrl; } + + /// + /// Gets the user's ID specified by the provider. + /// + public string ProviderId { get => this.providerId; } + } +} diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/UserMetadata.cs b/FirebaseAdmin/FirebaseAdmin/Auth/UserMetadata.cs new file mode 100644 index 00000000..546c13f7 --- /dev/null +++ b/FirebaseAdmin/FirebaseAdmin/Auth/UserMetadata.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Newtonsoft.Json; + +namespace FirebaseAdmin.Auth +{ + /// + /// Contains additional metadata associated with a user account. + /// + public sealed class UserMetadata + { + /// + /// Initializes a new instance of the class with the specified creation and last sign-in timestamps. + /// + /// A timestamp representing the date and time that the user account was created. + /// A timestamp representing the date and time that the user account was last signed-on to. + public UserMetadata(long creationTimestamp, long lastSignInTimestamp) + { + this.CreationTimestamp = creationTimestamp; + this.LastSignInTimestamp = lastSignInTimestamp; + } + + /// + /// Gets or sets a timestamp representing the date and time that the account was created. + /// + [JsonProperty("creationTimestamp")] + public long CreationTimestamp { get; set; } + + /// + /// Gets or sets a timestamp representing the last time that the user has logged in. + /// + [JsonProperty("lastSignInTimestamp")] + public long LastSignInTimestamp { get; set; } + } +} diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/UserRecord.cs b/FirebaseAdmin/FirebaseAdmin/Auth/UserRecord.cs index ec584e87..4a694179 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/UserRecord.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/UserRecord.cs @@ -14,6 +14,7 @@ using System; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Text; using Google.Apis.Json; using Newtonsoft.Json; @@ -24,20 +25,80 @@ namespace FirebaseAdmin.Auth /// Contains metadata associated with a Firebase user account. Instances /// of this class are immutable and thread safe. /// - internal class UserRecord + public sealed class UserRecord { private string uid; + private string email; + private string phoneNumber; + private bool emailVerified; + private string displayName; + private string photoUrl; + private bool disabled; + private List providers; + private long tokensValidAfterTimestamp; + private UserMetadata userMetaData; private IReadOnlyDictionary customClaims; + /// + /// Initializes a new instance of the class with the specified user ID. + /// + /// The user's ID. public UserRecord(string uid) { - this.Uid = uid; + if (string.IsNullOrEmpty(uid)) + { + throw new ArgumentNullException(nameof(uid)); + } + + this.uid = uid; + } + + /// + /// Initializes a new instance of the class from an existing instance of the class. + /// + /// The instance to copy the user's data from. + public UserRecord(Internal.GetAccountInfoResponse.User user) + { + if (user == null) + { + throw new ArgumentNullException(nameof(user)); + } + else if (string.IsNullOrEmpty(user.UserID)) + { + throw new ArgumentException("UserID must not be null or empty."); + } + + this.uid = user.UserID; + this.email = user.Email; + this.phoneNumber = user.PhoneNumber; + this.emailVerified = user.EmailVerified; + this.displayName = user.DisplayName; + this.photoUrl = user.PhotoUrl; + this.disabled = user.Disabled; + + if (user.Providers == null || user.Providers.Count == 0) + { + this.providers = new List(); + } + else + { + var count = user.Providers.Count; + this.providers = new List(count); + + for (int i = 0; i < count; i++) + { + this.providers.Add(new ProviderUserInfo(user.Providers[i])); + } + } + + this.tokensValidAfterTimestamp = user.ValidSince * 1000; + this.userMetaData = new UserMetadata(user.CreatedAt, user.LastLoginAt); + this.customClaims = this.ParseCustomClaims(user.CustomClaims); } /// /// Gets the user ID of this user. /// - [JsonProperty("localId")] public string Uid { get => this.uid; @@ -48,6 +109,51 @@ private set } } + /// + /// Gets the user's email address. + /// + public string Email => this.email; + + /// + /// Gets the user's phone number. + /// + public string PhoneNumber => this.phoneNumber; + + /// + /// Gets a value indicating whether the user's email address is verified or not. + /// + public bool EmailVerified => this.emailVerified; + + /// + /// Gets the user's display name. + /// + public string DisplayName => this.displayName; + + /// + /// Gets the user's photo URL. + /// + public string PhotoUrl => this.photoUrl; + + /// + /// Gets a value indicating whether the user account is disabled or not. + /// + public bool Disabled => this.disabled; + + /// + /// Gets a list of provider data for this user. + /// + public List Providers => this.providers; + + /// + /// Gets a timestamp representing the date and time that this token will become active. + /// + public long TokensValidAfterTimestamp => this.tokensValidAfterTimestamp; + + /// + /// Gets additional user metadata. + /// + public UserMetadata UserMetaData => this.userMetaData; + /// /// Gets or sets the custom claims set on this user. /// @@ -120,5 +226,19 @@ private static string SerializeClaims(IReadOnlyDictionary claims { return NewtonsoftJsonSerializer.Instance.Serialize(claims); } + + private ReadOnlyDictionary ParseCustomClaims(string customClaims) + { + if (string.IsNullOrEmpty(customClaims)) + { + return new ReadOnlyDictionary(new Dictionary()); + } + else + { + var parsed = NewtonsoftJsonSerializer.Instance.Deserialize>(customClaims); + + return new ReadOnlyDictionary(parsed); + } + } } } From 9f1e69c1ca0dd36fc3f5cbdef4a832677d8481fe Mon Sep 17 00:00:00 2001 From: Renato Ciuffo Date: Wed, 1 May 2019 15:14:55 -0700 Subject: [PATCH 2/9] -Moved classes in the FirebaseAdmin.Auth.Internal namespace to FirebaseAdmin.Auth. -Renamed GetUser() to GetUserAsync(), and added an overload that accepts a cancellationToken. -Added IUserInfo and implemented it in UserRecord and ProviderUserInfo. --- .../Auth/FirebaseUserManagerTest.cs | 8 +- .../FirebaseAdmin/Auth/FirebaseAuth.cs | 19 ++++- .../FirebaseAdmin/Auth/FirebaseUserManager.cs | 2 +- FirebaseAdmin/FirebaseAdmin/Auth/IUserInfo.cs | 50 +++++++++++++ .../Auth/Internal/GetAccountInfoResponse.cs | 8 +- .../FirebaseAdmin/Auth/ProviderUserInfo.cs | 33 +++++---- .../FirebaseAdmin/Auth/UserRecord.cs | 73 ++++++++++++------- 7 files changed, 143 insertions(+), 50 deletions(-) create mode 100644 FirebaseAdmin/FirebaseAdmin/Auth/IUserInfo.cs diff --git a/FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseUserManagerTest.cs b/FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseUserManagerTest.cs index 14b9bfbf..fdcf4ce0 100644 --- a/FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseUserManagerTest.cs +++ b/FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseUserManagerTest.cs @@ -33,7 +33,7 @@ public class FirebaseUserManagerTest public void InvalidUidForUserRecord() { Assert.Throws(() => new UserRecord((string)null)); - Assert.Throws(() => new UserRecord((Internal.GetAccountInfoResponse.User)null)); + Assert.Throws(() => new UserRecord((GetAccountInfoResponse.User)null)); Assert.Throws(() => new UserRecord(string.Empty)); Assert.Throws(() => new UserRecord(new string('a', 129))); } @@ -77,12 +77,12 @@ public async Task GetUserById() { var handler = new MockMessageHandler() { - Response = new Internal.GetAccountInfoResponse() + Response = new GetAccountInfoResponse() { Kind = "identitytoolkit#GetAccountInfoResponse", - Users = new List() + Users = new List() { - new Internal.GetAccountInfoResponse.User() { UserID = "user1" }, + new GetAccountInfoResponse.User() { UserID = "user1" }, }, }, }; diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseAuth.cs b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseAuth.cs index 54528528..7420d26c 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseAuth.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseAuth.cs @@ -272,11 +272,28 @@ public async Task VerifyIdTokenAsync( /// a user with the specified user ID. /// If user ID argument is null or empty. /// If a user cannot be found with the specified user ID. - public async Task GetUser(string uid) + public async Task GetUserAsync(string uid) { return await this.userManager.Value.GetUserById(uid); } + /// + /// Gets a object containig information about the user who's + /// user ID was specified in . + /// + /// The user ID for the user who's data is to be retrieved. + /// A cancellation token to monitor the asynchronous + /// operation. + /// A task that completes with a representing + /// a user with the specified user ID. + /// If user ID argument is null or empty. + /// If a user cannot be found with the specified user ID. + public async Task GetUserAsync( + string uid, CancellationToken cancellationToken) + { + return await this.userManager.Value.GetUserById(uid, cancellationToken); + } + /// /// 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 diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseUserManager.cs b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseUserManager.cs index f87bf705..e6fba80b 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseUserManager.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseUserManager.cs @@ -82,7 +82,7 @@ public async Task GetUserById( { "localId", uid }, }; - var response = await this.PostAndDeserializeAsync( + var response = await this.PostAndDeserializeAsync( getUserPath, payload, cancellationToken).ConfigureAwait(false); if (response == null || response.Users == null || response.Users.Count == 0) { diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/IUserInfo.cs b/FirebaseAdmin/FirebaseAdmin/Auth/IUserInfo.cs new file mode 100644 index 00000000..035cfa72 --- /dev/null +++ b/FirebaseAdmin/FirebaseAdmin/Auth/IUserInfo.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace FirebaseAdmin.Auth +{ + /// + /// A collection of standard profile information for a user. Used to expose profile information + /// returned by an identity provider. + /// + public interface IUserInfo + { + /// + /// Returns the user's unique ID assigned by the identity provider. + /// + /// a user ID string. + string GetUid(); + + /// + /// Returns the user's display name, if available. + /// + /// a display name string or null. + string GetDisplayName(); + + /// + /// Returns the user's email address, if available. + /// + /// an email address string or null. + string GetEmail(); + + /// + /// Returns the user's phone number, if available. + /// + /// a phone number string or null. + string GetPhoneNumber(); + + /// + /// Returns the user's photo URL, if available. + /// + /// a URL string or null. + string GetPhotoUrl(); + + /// + /// Returns 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. + /// + /// an ID string that uniquely identifies the identity provider. + string GetProviderId(); + } +} diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/Internal/GetAccountInfoResponse.cs b/FirebaseAdmin/FirebaseAdmin/Auth/Internal/GetAccountInfoResponse.cs index d7361d2f..6d9fd051 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/Internal/GetAccountInfoResponse.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/Internal/GetAccountInfoResponse.cs @@ -3,12 +3,12 @@ using System.Text; using Newtonsoft.Json; -namespace FirebaseAdmin.Auth.Internal +namespace FirebaseAdmin.Auth { /// /// JSON data binding for GetAccountInfoResponse messages sent by Google identity toolkit service. /// - public sealed class GetAccountInfoResponse + internal sealed class GetAccountInfoResponse { /// /// Gets or sets a string representing what kind of account is represented by this object. @@ -25,7 +25,7 @@ public sealed class GetAccountInfoResponse /// /// JSON data binding for user records. /// - public sealed class User + internal sealed class User { /// /// Gets or sets the user's ID. @@ -103,7 +103,7 @@ public sealed class User /// /// JSON data binding for provider data. /// - public sealed class Provider + internal sealed class Provider { /// /// Gets or sets the user's ID. diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/ProviderUserInfo.cs b/FirebaseAdmin/FirebaseAdmin/Auth/ProviderUserInfo.cs index f6444d4a..2807d212 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/ProviderUserInfo.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/ProviderUserInfo.cs @@ -8,7 +8,7 @@ namespace FirebaseAdmin.Auth /// Contains metadata regarding how a user is known by a particular identity provider (IdP). /// Instances of this class are immutable and thread safe. /// - public sealed class ProviderUserInfo + public sealed class ProviderUserInfo : IUserInfo { private string uid; private string displayName; @@ -21,7 +21,7 @@ public sealed class ProviderUserInfo /// Initializes a new instance of the class with data provided by an authentication provider. /// /// The deserialized JSON user data from the provider. - public ProviderUserInfo(Internal.GetAccountInfoResponse.Provider provider) + internal ProviderUserInfo(GetAccountInfoResponse.Provider provider) { this.uid = provider.UserID; this.displayName = provider.DisplayName; @@ -32,33 +32,40 @@ public ProviderUserInfo(Internal.GetAccountInfoResponse.Provider provider) } /// - /// Gets the user's ID. + /// Returns the user's unique ID assigned by the identity provider. /// - public string UserID { get => this.uid; } + /// a user ID string. + string IUserInfo.GetUid() => this.uid; /// - /// Gets the user's display name. + /// Returns the user's display name, if available. /// - public string DisplayName { get => this.displayName; } + /// a display name string or null. + string IUserInfo.GetDisplayName() => this.displayName; /// - /// Gets the user's email address. + /// Returns the user's email address, if available. /// - public string Email { get => this.email; } + /// an email address string or null. + string IUserInfo.GetEmail() => this.email; /// /// Gets the user's phone number. /// - public string PhoneNumber { get => this.phoneNumber; } + /// a phone number string or null. + string IUserInfo.GetPhoneNumber() => this.phoneNumber; /// - /// Gets the URL for the user's photo/avatar. + /// Returns the user's photo URL, if available. /// - public string PhotoUrl { get => this.photoUrl; } + /// a URL string or null. + string IUserInfo.GetPhotoUrl() => this.photoUrl; /// - /// Gets the user's ID specified by the provider. + /// Returns 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. /// - public string ProviderId { get => this.providerId; } + /// an ID string that uniquely identifies the identity provider. + string IUserInfo.GetProviderId() => this.providerId; } } diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/UserRecord.cs b/FirebaseAdmin/FirebaseAdmin/Auth/UserRecord.cs index 4a694179..816e7ff7 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/UserRecord.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/UserRecord.cs @@ -25,8 +25,10 @@ namespace FirebaseAdmin.Auth /// Contains metadata associated with a Firebase user account. Instances /// of this class are immutable and thread safe. /// - public sealed class UserRecord + public sealed class UserRecord : IUserInfo { + private const string PROVIDERID = "firebase"; + private string uid; private string email; private string phoneNumber; @@ -43,7 +45,7 @@ public sealed class UserRecord /// Initializes a new instance of the class with the specified user ID. /// /// The user's ID. - public UserRecord(string uid) + internal UserRecord(string uid) { if (string.IsNullOrEmpty(uid)) { @@ -54,10 +56,10 @@ public UserRecord(string uid) } /// - /// Initializes a new instance of the class from an existing instance of the class. + /// Initializes a new instance of the class from an existing instance of the class. /// - /// The instance to copy the user's data from. - public UserRecord(Internal.GetAccountInfoResponse.User user) + /// The instance to copy the user's data from. + internal UserRecord(GetAccountInfoResponse.User user) { if (user == null) { @@ -93,7 +95,7 @@ public UserRecord(Internal.GetAccountInfoResponse.User user) this.tokensValidAfterTimestamp = user.ValidSince * 1000; this.userMetaData = new UserMetadata(user.CreatedAt, user.LastLoginAt); - this.customClaims = this.ParseCustomClaims(user.CustomClaims); + this.customClaims = UserRecord.ParseCustomClaims(user.CustomClaims); } /// @@ -109,31 +111,11 @@ private set } } - /// - /// Gets the user's email address. - /// - public string Email => this.email; - - /// - /// Gets the user's phone number. - /// - public string PhoneNumber => this.phoneNumber; - /// /// Gets a value indicating whether the user's email address is verified or not. /// public bool EmailVerified => this.emailVerified; - /// - /// Gets the user's display name. - /// - public string DisplayName => this.displayName; - - /// - /// Gets the user's photo URL. - /// - public string PhotoUrl => this.photoUrl; - /// /// Gets a value indicating whether the user account is disabled or not. /// @@ -188,6 +170,43 @@ public static void CheckUid(string uid) } } + /// + /// Returns the user's unique ID assigned by the identity provider. + /// + /// a user ID string. + string IUserInfo.GetUid() => this.uid; + + /// + /// Returns the user's display name, if available. + /// + /// a display name string or null. + string IUserInfo.GetDisplayName() => this.displayName; + + /// + /// Returns the user's email address, if available. + /// + /// an email address string or null. + string IUserInfo.GetEmail() => this.email; + + /// + /// Gets the user's phone number. + /// + /// a phone number string or null. + string IUserInfo.GetPhoneNumber() => this.phoneNumber; + + /// + /// Returns the user's photo URL, if available. + /// + /// a URL string or null. + string IUserInfo.GetPhotoUrl() => this.photoUrl; + + /// + /// Returns 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. + /// + /// an ID string that uniquely identifies the identity provider. + string IUserInfo.GetProviderId() => UserRecord.PROVIDERID; + /// /// Checks if the given set of custom claims are valid. /// @@ -227,7 +246,7 @@ private static string SerializeClaims(IReadOnlyDictionary claims return NewtonsoftJsonSerializer.Instance.Serialize(claims); } - private ReadOnlyDictionary ParseCustomClaims(string customClaims) + private static ReadOnlyDictionary ParseCustomClaims(string customClaims) { if (string.IsNullOrEmpty(customClaims)) { From 5e5e0ed456dc240cf5d18ed6f5b5a3227990abcb Mon Sep 17 00:00:00 2001 From: Renato Ciuffo Date: Wed, 1 May 2019 15:20:26 -0700 Subject: [PATCH 3/9] Changed access level of IUserInfo function implementations for UserRecord and ProviderUserInfo to public. --- FirebaseAdmin/FirebaseAdmin/Auth/ProviderUserInfo.cs | 12 ++++++------ FirebaseAdmin/FirebaseAdmin/Auth/UserRecord.cs | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/ProviderUserInfo.cs b/FirebaseAdmin/FirebaseAdmin/Auth/ProviderUserInfo.cs index 2807d212..beaf0255 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/ProviderUserInfo.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/ProviderUserInfo.cs @@ -35,37 +35,37 @@ internal ProviderUserInfo(GetAccountInfoResponse.Provider provider) /// Returns the user's unique ID assigned by the identity provider. /// /// a user ID string. - string IUserInfo.GetUid() => this.uid; + public string GetUid() => this.uid; /// /// Returns the user's display name, if available. /// /// a display name string or null. - string IUserInfo.GetDisplayName() => this.displayName; + public string GetDisplayName() => this.displayName; /// /// Returns the user's email address, if available. /// /// an email address string or null. - string IUserInfo.GetEmail() => this.email; + public string GetEmail() => this.email; /// /// Gets the user's phone number. /// /// a phone number string or null. - string IUserInfo.GetPhoneNumber() => this.phoneNumber; + public string GetPhoneNumber() => this.phoneNumber; /// /// Returns the user's photo URL, if available. /// /// a URL string or null. - string IUserInfo.GetPhotoUrl() => this.photoUrl; + public string GetPhotoUrl() => this.photoUrl; /// /// Returns 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. /// /// an ID string that uniquely identifies the identity provider. - string IUserInfo.GetProviderId() => this.providerId; + public string GetProviderId() => this.providerId; } } diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/UserRecord.cs b/FirebaseAdmin/FirebaseAdmin/Auth/UserRecord.cs index 816e7ff7..e41c49c3 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/UserRecord.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/UserRecord.cs @@ -174,38 +174,38 @@ public static void CheckUid(string uid) /// Returns the user's unique ID assigned by the identity provider. /// /// a user ID string. - string IUserInfo.GetUid() => this.uid; + public string GetUid() => this.uid; /// /// Returns the user's display name, if available. /// /// a display name string or null. - string IUserInfo.GetDisplayName() => this.displayName; + public string GetDisplayName() => this.displayName; /// /// Returns the user's email address, if available. /// /// an email address string or null. - string IUserInfo.GetEmail() => this.email; + public string GetEmail() => this.email; /// /// Gets the user's phone number. /// /// a phone number string or null. - string IUserInfo.GetPhoneNumber() => this.phoneNumber; + public string GetPhoneNumber() => this.phoneNumber; /// /// Returns the user's photo URL, if available. /// /// a URL string or null. - string IUserInfo.GetPhotoUrl() => this.photoUrl; + public string GetPhotoUrl() => this.photoUrl; /// /// Returns 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. /// /// an ID string that uniquely identifies the identity provider. - string IUserInfo.GetProviderId() => UserRecord.PROVIDERID; + public string GetProviderId() => UserRecord.PROVIDERID; /// /// Checks if the given set of custom claims are valid. From 702572afcfbca83e51aa48d20d456ac96146587c Mon Sep 17 00:00:00 2001 From: Renato Ciuffo Date: Wed, 1 May 2019 15:32:52 -0700 Subject: [PATCH 4/9] Fixed a failing CI test. --- .../Auth/FirebaseUserManagerTest.cs | 9 ++++++++- .../FirebaseAdmin/Auth/FirebaseUserManager.cs | 18 +++++++++++++++--- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseUserManagerTest.cs b/FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseUserManagerTest.cs index fdcf4ce0..6f5503c3 100644 --- a/FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseUserManagerTest.cs +++ b/FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseUserManagerTest.cs @@ -123,7 +123,14 @@ public async Task UpdateUser() { var handler = new MockMessageHandler() { - Response = new UserRecord("user1"), + Response = new GetAccountInfoResponse() + { + Kind = "identitytoolkit#GetAccountInfoResponse", + Users = new List() + { + new GetAccountInfoResponse.User() { UserID = "user1" }, + }, + }, }; var factory = new MockHttpClientFactory(handler); var userManager = new FirebaseUserManager( diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseUserManager.cs b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseUserManager.cs index e6fba80b..b9518869 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseUserManager.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseUserManager.cs @@ -89,7 +89,13 @@ public async Task GetUserById( throw new FirebaseException($"Failed to get user: {uid}"); } - return new UserRecord(response.Users[0]); + var user = response.Users[0]; + if (user == null || user.UserID != uid) + { + throw new FirebaseException($"Failed to get user: {uid}"); + } + + return new UserRecord(user); } /// @@ -103,9 +109,15 @@ public async Task UpdateUserAsync( UserRecord user, CancellationToken cancellationToken = default(CancellationToken)) { const string updatePath = "accounts:update"; - var response = await this.PostAndDeserializeAsync( + var response = await this.PostAndDeserializeAsync( 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}"); } From fcad198f939a25d3eeb4872cbe5b7973d326daf4 Mon Sep 17 00:00:00 2001 From: Renato Ciuffo Date: Wed, 1 May 2019 15:45:16 -0700 Subject: [PATCH 5/9] Fixed the InvalidUidForUserRecord test. --- .../FirebaseAdmin.Tests/Auth/FirebaseUserManagerTest.cs | 4 +++- FirebaseAdmin/FirebaseAdmin/Auth/UserRecord.cs | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseUserManagerTest.cs b/FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseUserManagerTest.cs index 6f5503c3..7ba45847 100644 --- a/FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseUserManagerTest.cs +++ b/FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseUserManagerTest.cs @@ -35,7 +35,9 @@ public void InvalidUidForUserRecord() Assert.Throws(() => new UserRecord((string)null)); Assert.Throws(() => new UserRecord((GetAccountInfoResponse.User)null)); Assert.Throws(() => new UserRecord(string.Empty)); - Assert.Throws(() => new UserRecord(new string('a', 129))); + + // The constructor for UserRecord should not throw an exception when initialized with a valid string. + var userRecord = new UserRecord(new string('a', 129)); } [Fact] diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/UserRecord.cs b/FirebaseAdmin/FirebaseAdmin/Auth/UserRecord.cs index e41c49c3..fe2350b3 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/UserRecord.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/UserRecord.cs @@ -49,7 +49,7 @@ internal UserRecord(string uid) { if (string.IsNullOrEmpty(uid)) { - throw new ArgumentNullException(nameof(uid)); + throw new ArgumentException("UserID must not be null or empty."); } this.uid = uid; @@ -63,7 +63,7 @@ internal UserRecord(GetAccountInfoResponse.User user) { if (user == null) { - throw new ArgumentNullException(nameof(user)); + throw new ArgumentException("User object must not be null or empty."); } else if (string.IsNullOrEmpty(user.UserID)) { From 27688ade701e2a4e71e3793f842ddbdae1d5d8fd Mon Sep 17 00:00:00 2001 From: Renato Ciuffo Date: Wed, 1 May 2019 16:49:49 -0700 Subject: [PATCH 6/9] Converted IUserInfo to use properties instead of functions. --- .../FirebaseAdmin/Auth/FirebaseAuth.cs | 8 +- FirebaseAdmin/FirebaseAdmin/Auth/IUserInfo.cs | 42 ++++++--- .../FirebaseAdmin/Auth/ProviderUserInfo.cs | 40 +++++--- .../FirebaseAdmin/Auth/UserMetadata.cs | 2 +- .../FirebaseAdmin/Auth/UserRecord.cs | 93 ++++++++++--------- 5 files changed, 115 insertions(+), 70 deletions(-) diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseAuth.cs b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseAuth.cs index 7420d26c..a8c436c4 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseAuth.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseAuth.cs @@ -267,14 +267,14 @@ public async Task VerifyIdTokenAsync( /// Gets a object containig information about the user who's /// user ID was specified in . /// - /// The user ID for the user who's data is to be retrieved.. + /// The user ID for the user who's data is to be retrieved. /// A task that completes with a representing /// a user with the specified user ID. /// If user ID argument is null or empty. /// If a user cannot be found with the specified user ID. public async Task GetUserAsync(string uid) { - return await this.userManager.Value.GetUserById(uid); + return await this.GetUserAsync(uid, default(CancellationToken)); } /// @@ -291,7 +291,9 @@ public async Task GetUserAsync(string uid) public async Task GetUserAsync( string uid, CancellationToken cancellationToken) { - return await this.userManager.Value.GetUserById(uid, cancellationToken); + var userManager = this.IfNotDeleted(() => this.userManager.Value); + + return await userManager.GetUserById(uid, cancellationToken); } /// diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/IUserInfo.cs b/FirebaseAdmin/FirebaseAdmin/Auth/IUserInfo.cs index 035cfa72..1f6945fa 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/IUserInfo.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/IUserInfo.cs @@ -11,40 +11,58 @@ namespace FirebaseAdmin.Auth public interface IUserInfo { /// - /// Returns the user's unique ID assigned by the identity provider. + /// Gets the user's unique ID assigned by the identity provider. /// /// a user ID string. - string GetUid(); + string Uid + { + get; + } /// - /// Returns the user's display name, if available. + /// Gets the user's display name, if available. /// /// a display name string or null. - string GetDisplayName(); + string DisplayName + { + get; + } /// - /// Returns the user's email address, if available. + /// Gets the user's email address, if available. /// /// an email address string or null. - string GetEmail(); + string Email + { + get; + } /// - /// Returns the user's phone number, if available. + /// Gets the user's phone number, if available. /// /// a phone number string or null. - string GetPhoneNumber(); + string PhoneNumber + { + get; + } /// - /// Returns the user's photo URL, if available. + /// Gets the user's photo URL, if available. /// /// a URL string or null. - string GetPhotoUrl(); + string PhotoUrl + { + get; + } /// - /// Returns the ID of the identity provider. This can be a short domain name (e.g. google.com) or + /// 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. /// /// an ID string that uniquely identifies the identity provider. - string GetProviderId(); + string ProviderId + { + get; + } } } diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/ProviderUserInfo.cs b/FirebaseAdmin/FirebaseAdmin/Auth/ProviderUserInfo.cs index beaf0255..31401133 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/ProviderUserInfo.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/ProviderUserInfo.cs @@ -32,40 +32,58 @@ internal ProviderUserInfo(GetAccountInfoResponse.Provider provider) } /// - /// Returns the user's unique ID assigned by the identity provider. + /// Gets the user's unique ID assigned by the identity provider. /// /// a user ID string. - public string GetUid() => this.uid; + public string Uid + { + get => this.uid; + } /// - /// Returns the user's display name, if available. + /// Gets the user's display name, if available. /// /// a display name string or null. - public string GetDisplayName() => this.displayName; + public string DisplayName + { + get => this.displayName; + } /// - /// Returns the user's email address, if available. + /// Gets the user's email address, if available. /// /// an email address string or null. - public string GetEmail() => this.email; + public string Email + { + get => this.email; + } /// /// Gets the user's phone number. /// /// a phone number string or null. - public string GetPhoneNumber() => this.phoneNumber; + public string PhoneNumber + { + get => this.phoneNumber; + } /// - /// Returns the user's photo URL, if available. + /// Gets the user's photo URL, if available. /// /// a URL string or null. - public string GetPhotoUrl() => this.photoUrl; + public string PhotoUrl + { + get => this.photoUrl; + } /// - /// Returns the ID of the identity provider. This can be a short domain name (e.g. google.com) or + /// 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. /// /// an ID string that uniquely identifies the identity provider. - public string GetProviderId() => this.providerId; + public string ProviderId + { + get => this.providerId; + } } } diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/UserMetadata.cs b/FirebaseAdmin/FirebaseAdmin/Auth/UserMetadata.cs index 546c13f7..895ff66c 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/UserMetadata.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/UserMetadata.cs @@ -15,7 +15,7 @@ public sealed class UserMetadata /// /// A timestamp representing the date and time that the user account was created. /// A timestamp representing the date and time that the user account was last signed-on to. - public UserMetadata(long creationTimestamp, long lastSignInTimestamp) + internal UserMetadata(long creationTimestamp, long lastSignInTimestamp) { this.CreationTimestamp = creationTimestamp; this.LastSignInTimestamp = lastSignInTimestamp; diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/UserRecord.cs b/FirebaseAdmin/FirebaseAdmin/Auth/UserRecord.cs index fe2350b3..b1bc4e1d 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/UserRecord.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/UserRecord.cs @@ -111,6 +111,52 @@ private set } } + /// + /// Gets the user's display name, if available. + /// + /// a display name string or null. + public string DisplayName + { + get => this.displayName; + } + + /// + /// Gets the user's email address, if available. + /// + /// an email address string or null. + public string Email + { + get => this.email; + } + + /// + /// Gets the user's phone number. + /// + /// a phone number string or null. + public string PhoneNumber + { + get => this.phoneNumber; + } + + /// + /// Gets the user's photo URL, if available. + /// + /// a URL string or null. + public string PhotoUrl + { + get => this.photoUrl; + } + + /// + /// 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. + /// + /// an ID string that uniquely identifies the identity provider. + public string ProviderId + { + get => UserRecord.PROVIDERID; + } + /// /// Gets a value indicating whether the user's email address is verified or not. /// @@ -124,7 +170,7 @@ private set /// /// Gets a list of provider data for this user. /// - public List Providers => this.providers; + public IEnumerable Providers => this.providers; /// /// Gets a timestamp representing the date and time that this token will become active. @@ -170,43 +216,6 @@ public static void CheckUid(string uid) } } - /// - /// Returns the user's unique ID assigned by the identity provider. - /// - /// a user ID string. - public string GetUid() => this.uid; - - /// - /// Returns the user's display name, if available. - /// - /// a display name string or null. - public string GetDisplayName() => this.displayName; - - /// - /// Returns the user's email address, if available. - /// - /// an email address string or null. - public string GetEmail() => this.email; - - /// - /// Gets the user's phone number. - /// - /// a phone number string or null. - public string GetPhoneNumber() => this.phoneNumber; - - /// - /// Returns the user's photo URL, if available. - /// - /// a URL string or null. - public string GetPhotoUrl() => this.photoUrl; - - /// - /// Returns 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. - /// - /// an ID string that uniquely identifies the identity provider. - public string GetProviderId() => UserRecord.PROVIDERID; - /// /// Checks if the given set of custom claims are valid. /// @@ -246,17 +255,15 @@ private static string SerializeClaims(IReadOnlyDictionary claims return NewtonsoftJsonSerializer.Instance.Serialize(claims); } - private static ReadOnlyDictionary ParseCustomClaims(string customClaims) + private static IReadOnlyDictionary ParseCustomClaims(string customClaims) { if (string.IsNullOrEmpty(customClaims)) { - return new ReadOnlyDictionary(new Dictionary()); + return new Dictionary(); } else { - var parsed = NewtonsoftJsonSerializer.Instance.Deserialize>(customClaims); - - return new ReadOnlyDictionary(parsed); + return NewtonsoftJsonSerializer.Instance.Deserialize>(customClaims); } } } From cef53826227ad974982147e9aeea1fbd462c3ec3 Mon Sep 17 00:00:00 2001 From: Renato Ciuffo Date: Thu, 2 May 2019 08:29:27 -0700 Subject: [PATCH 7/9] Removed setters from the properties of UserMetadata. --- FirebaseAdmin/FirebaseAdmin/Auth/UserMetadata.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/UserMetadata.cs b/FirebaseAdmin/FirebaseAdmin/Auth/UserMetadata.cs index 895ff66c..1555c13e 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/UserMetadata.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/UserMetadata.cs @@ -22,15 +22,15 @@ internal UserMetadata(long creationTimestamp, long lastSignInTimestamp) } /// - /// Gets or sets a timestamp representing the date and time that the account was created. + /// Gets a timestamp representing the date and time that the account was created. /// [JsonProperty("creationTimestamp")] - public long CreationTimestamp { get; set; } + public long CreationTimestamp { get; } /// - /// Gets or sets a timestamp representing the last time that the user has logged in. + /// Gets a timestamp representing the last time that the user has logged in. /// [JsonProperty("lastSignInTimestamp")] - public long LastSignInTimestamp { get; set; } + public long LastSignInTimestamp { get; } } } From 0e215983826455b34f96fc11b4d8ff9ac5347aed Mon Sep 17 00:00:00 2001 From: Renato Ciuffo Date: Thu, 2 May 2019 16:48:50 -0700 Subject: [PATCH 8/9] Renamed UserID to UserId in the classes inside of GetAccountInfoResponse. Converted ProviderUserInfo to be an internal class, with auto properties. Fixed the FirebaseUserManagerTest test so that it would fail when instantiating a UserRecord class with a uid that's longer than 128 characters. --- .../Auth/FirebaseUserManagerTest.cs | 8 ++- .../FirebaseAdmin/Auth/FirebaseUserManager.cs | 4 +- .../Auth/Internal/GetAccountInfoResponse.cs | 4 +- .../FirebaseAdmin/Auth/ProviderUserInfo.cs | 51 +++++-------------- .../FirebaseAdmin/Auth/UserRecord.cs | 10 ++-- 5 files changed, 25 insertions(+), 52 deletions(-) diff --git a/FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseUserManagerTest.cs b/FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseUserManagerTest.cs index 7ba45847..837ca314 100644 --- a/FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseUserManagerTest.cs +++ b/FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseUserManagerTest.cs @@ -35,9 +35,7 @@ public void InvalidUidForUserRecord() Assert.Throws(() => new UserRecord((string)null)); Assert.Throws(() => new UserRecord((GetAccountInfoResponse.User)null)); Assert.Throws(() => new UserRecord(string.Empty)); - - // The constructor for UserRecord should not throw an exception when initialized with a valid string. - var userRecord = new UserRecord(new string('a', 129)); + Assert.Throws(() => new UserRecord(new string('a', 129))); } [Fact] @@ -84,7 +82,7 @@ public async Task GetUserById() Kind = "identitytoolkit#GetAccountInfoResponse", Users = new List() { - new GetAccountInfoResponse.User() { UserID = "user1" }, + new GetAccountInfoResponse.User() { UserId = "user1" }, }, }, }; @@ -130,7 +128,7 @@ public async Task UpdateUser() Kind = "identitytoolkit#GetAccountInfoResponse", Users = new List() { - new GetAccountInfoResponse.User() { UserID = "user1" }, + new GetAccountInfoResponse.User() { UserId = "user1" }, }, }, }; diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseUserManager.cs b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseUserManager.cs index b9518869..c2b5d78a 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseUserManager.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/FirebaseUserManager.cs @@ -90,7 +90,7 @@ public async Task GetUserById( } var user = response.Users[0]; - if (user == null || user.UserID != uid) + if (user == null || user.UserId != uid) { throw new FirebaseException($"Failed to get user: {uid}"); } @@ -117,7 +117,7 @@ public async Task UpdateUserAsync( } var updatedUser = response.Users[0]; - if (updatedUser == null || updatedUser.UserID != user.Uid) + if (updatedUser == null || updatedUser.UserId != user.Uid) { throw new FirebaseException($"Failed to update user: {user.Uid}"); } diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/Internal/GetAccountInfoResponse.cs b/FirebaseAdmin/FirebaseAdmin/Auth/Internal/GetAccountInfoResponse.cs index 6d9fd051..50daf996 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/Internal/GetAccountInfoResponse.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/Internal/GetAccountInfoResponse.cs @@ -31,7 +31,7 @@ internal sealed class User /// Gets or sets the user's ID. /// [JsonProperty(PropertyName = "localId")] - public string UserID { get; set; } + public string UserId { get; set; } /// /// Gets or sets the user's email address. @@ -109,7 +109,7 @@ internal sealed class Provider /// Gets or sets the user's ID. /// [JsonProperty(PropertyName = "uid")] - public string UserID { get; set; } + public string UserId { get; set; } /// /// Gets or sets the user's display name. diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/ProviderUserInfo.cs b/FirebaseAdmin/FirebaseAdmin/Auth/ProviderUserInfo.cs index 31401133..1fef1f1d 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/ProviderUserInfo.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/ProviderUserInfo.cs @@ -8,82 +8,57 @@ namespace FirebaseAdmin.Auth /// Contains metadata regarding how a user is known by a particular identity provider (IdP). /// Instances of this class are immutable and thread safe. /// - public sealed class ProviderUserInfo : IUserInfo + internal sealed class ProviderUserInfo : IUserInfo { - private string uid; - private string displayName; - private string email; - private string phoneNumber; - private string photoUrl; - private string providerId; - /// /// Initializes a new instance of the class with data provided by an authentication provider. /// /// The deserialized JSON user data from the provider. internal ProviderUserInfo(GetAccountInfoResponse.Provider provider) { - this.uid = provider.UserID; - this.displayName = provider.DisplayName; - this.email = provider.Email; - this.phoneNumber = provider.PhoneNumber; - this.photoUrl = provider.PhotoUrl; - this.providerId = provider.ProviderID; + this.Uid = provider.UserId; + this.DisplayName = provider.DisplayName; + this.Email = provider.Email; + this.PhoneNumber = provider.PhoneNumber; + this.PhotoUrl = provider.PhotoUrl; + this.ProviderId = provider.ProviderID; } /// /// Gets the user's unique ID assigned by the identity provider. /// /// a user ID string. - public string Uid - { - get => this.uid; - } + public string Uid { get; private set; } /// /// Gets the user's display name, if available. /// /// a display name string or null. - public string DisplayName - { - get => this.displayName; - } + public string DisplayName { get; private set; } /// /// Gets the user's email address, if available. /// /// an email address string or null. - public string Email - { - get => this.email; - } + public string Email { get; private set; } /// /// Gets the user's phone number. /// /// a phone number string or null. - public string PhoneNumber - { - get => this.phoneNumber; - } + public string PhoneNumber { get; private set; } /// /// Gets the user's photo URL, if available. /// /// a URL string or null. - public string PhotoUrl - { - get => this.photoUrl; - } + public string PhotoUrl { get; private set; } /// /// 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. /// /// an ID string that uniquely identifies the identity provider. - public string ProviderId - { - get => this.providerId; - } + public string ProviderId { get; private set; } } } diff --git a/FirebaseAdmin/FirebaseAdmin/Auth/UserRecord.cs b/FirebaseAdmin/FirebaseAdmin/Auth/UserRecord.cs index b1bc4e1d..9633ae04 100644 --- a/FirebaseAdmin/FirebaseAdmin/Auth/UserRecord.cs +++ b/FirebaseAdmin/FirebaseAdmin/Auth/UserRecord.cs @@ -47,9 +47,9 @@ public sealed class UserRecord : IUserInfo /// The user's ID. internal UserRecord(string uid) { - if (string.IsNullOrEmpty(uid)) + if (string.IsNullOrEmpty(uid) || uid.Length > 128) { - throw new ArgumentException("UserID must not be null or empty."); + throw new ArgumentException("User ID must not be null or empty, and be 128 characters or shorter."); } this.uid = uid; @@ -65,12 +65,12 @@ internal UserRecord(GetAccountInfoResponse.User user) { throw new ArgumentException("User object must not be null or empty."); } - else if (string.IsNullOrEmpty(user.UserID)) + else if (string.IsNullOrEmpty(user.UserId)) { - throw new ArgumentException("UserID must not be null or empty."); + throw new ArgumentException("User ID must not be null or empty."); } - this.uid = user.UserID; + this.uid = user.UserId; this.email = user.Email; this.phoneNumber = user.PhoneNumber; this.emailVerified = user.EmailVerified; From cced76223777066d9693927165832f5088568ffb Mon Sep 17 00:00:00 2001 From: Renato Ciuffo Date: Fri, 3 May 2019 11:19:05 -0700 Subject: [PATCH 9/9] Added entry to CHANGELOG about implementing the `GetUserById()` API in the FirebaseUserManager class. --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 11e68843..be98e016 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ # Unreleased +- [added] Implemented the `GetUserById()` API in the `FirebaseUserManager` class. + - # v1.4.0