Skip to content

Commit d5a7a3f

Browse files
authored
feat(auth): Add bulk user import functionality and hashing algorithms namespace (#191)
* Add progress for bulk importing users * Add more unit tests * Fix bug for custom claims, add test for custom claims and user provider * Add ImportUserRecordArgs tests * Add newlines at the end of files * Leverage pre-existing UserRecordArgs validators, general code refactoring * Cleanup indentation * Minor refactoring * Fix indentation * Add missing newline in Sha512 * Fix Scrypt lowerbound to be 0, nested conditionals * Update Scrypt lowerbound test to match fixed lowerbound * Address feedback for user imports * Address review feedback for user import implementation * Refactor to use var in for loops within UserImportHashTest * Address feedback for user import implementation * Address feedback for user import unit tests (#193) * Address integration test feedback * Add user email verification to test * Invoke ImportUserAsync using overloaded method without options * Enhance user import integration test by verifying user can login (#194) * Add signing in as part of import users integration tests * Address doc review comments * Change uid to user ID in API docs * Add sample snippets for user imports (#195) * Add sample snippets for user imports * Make Pbkdf2Sha256 hash use 100000 rounds * Address some failing linting results * Remove trailing whitespace * Resolve Auth snippet salt and hash flip * Add comments and use string interpolation whenever possible
1 parent 21d535f commit d5a7a3f

34 files changed

+2502
-39
lines changed

FirebaseAdmin/FirebaseAdmin.IntegrationTests/FirebaseAuthTest.cs

Lines changed: 103 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@
1717
using System.Linq;
1818
using System.Net.Http;
1919
using System.Text;
20-
using System.Threading;
2120
using System.Threading.Tasks;
2221
using System.Web;
2322
using FirebaseAdmin.Auth;
23+
using FirebaseAdmin.Auth.Hash;
2424
using Google.Apis.Auth.OAuth2;
2525
using Google.Apis.Util;
2626
using Xunit;
@@ -510,6 +510,108 @@ public async Task ListUsers()
510510
}
511511
}
512512

513+
[Fact]
514+
public async Task ImportUsers()
515+
{
516+
var randomUser = RandomUser.Create();
517+
var args = new ImportUserRecordArgs()
518+
{
519+
Uid = randomUser.Uid,
520+
Email = randomUser.Email,
521+
DisplayName = "Random User",
522+
PhotoUrl = "https://example.com/photo.png",
523+
EmailVerified = true,
524+
};
525+
526+
IEnumerable<ImportUserRecordArgs> usersLst = new List<ImportUserRecordArgs>();
527+
usersLst = usersLst.Append(args);
528+
529+
var resp = await FirebaseAuth.DefaultInstance.ImportUsersAsync(usersLst);
530+
531+
try
532+
{
533+
Assert.Equal(1, resp.SuccessCount);
534+
Assert.Equal(0, resp.FailureCount);
535+
536+
var user = await FirebaseAuth.DefaultInstance.GetUserAsync(randomUser.Uid);
537+
Assert.Equal(randomUser.Email, user.Email);
538+
}
539+
finally
540+
{
541+
await FirebaseAuth.DefaultInstance.DeleteUserAsync(randomUser.Uid);
542+
}
543+
}
544+
545+
[Fact]
546+
public async Task ImportUsersWithPassword()
547+
{
548+
var randomUser = RandomUser.Create();
549+
var args = new ImportUserRecordArgs()
550+
{
551+
Uid = randomUser.Uid,
552+
Email = randomUser.Email,
553+
DisplayName = "Random User",
554+
PhotoUrl = "https://example.com/photo.png",
555+
EmailVerified = true,
556+
PasswordSalt = Encoding.ASCII.GetBytes("NaCl"),
557+
PasswordHash = Convert.FromBase64String("V358E8LdWJXAO7muq0CufVpEOXaj8aFiC7"
558+
+ "T/rcaGieN04q/ZPJ08WhJEHGjj9lz/2TT+/86N5VjVoc5DdBhBiw=="),
559+
CustomClaims = new Dictionary<string, object>()
560+
{
561+
{ "admin", true },
562+
},
563+
UserProviders = new List<UserProvider>
564+
{
565+
new UserProvider()
566+
{
567+
Uid = randomUser.Uid,
568+
Email = randomUser.Email,
569+
DisplayName = "John Doe",
570+
PhotoUrl = "http://example.com/123/photo.png",
571+
ProviderId = "google.com",
572+
},
573+
new UserProvider()
574+
{
575+
Uid = "fb.uid",
576+
Email = "[email protected]",
577+
DisplayName = "John Doe",
578+
PhotoUrl = "http://example.com/123/photo.png",
579+
ProviderId = "facebook.com",
580+
},
581+
},
582+
};
583+
584+
var options = new UserImportOptions()
585+
{
586+
Hash = new Scrypt()
587+
{
588+
Key = Convert.FromBase64String("jxspr8Ki0RYycVU8zykbdLGjFQ3McFUH0uiiTvC"
589+
+ "8pVMXAn210wjLNmdZJzxUECKbm0QsEmYUSDzZvpjeJ9WmXA=="),
590+
SaltSeparator = Convert.FromBase64String("Bw=="),
591+
Rounds = 8,
592+
MemoryCost = 14,
593+
},
594+
};
595+
IEnumerable<ImportUserRecordArgs> usersLst = new List<ImportUserRecordArgs>();
596+
usersLst = usersLst.Append(args);
597+
var resp = await FirebaseAuth.DefaultInstance.ImportUsersAsync(usersLst, options);
598+
599+
try
600+
{
601+
Assert.Equal(1, resp.SuccessCount);
602+
Assert.Equal(0, resp.FailureCount);
603+
604+
var user = await FirebaseAuth.DefaultInstance.GetUserAsync(randomUser.Uid);
605+
Assert.Equal(randomUser.Email, user.Email);
606+
var idToken = await SignInWithPasswordAsync(randomUser.Email, "password");
607+
Assert.False(string.IsNullOrEmpty(idToken));
608+
}
609+
finally
610+
{
611+
await FirebaseAuth.DefaultInstance.DeleteUserAsync(randomUser.Uid);
612+
}
613+
}
614+
513615
[Fact]
514616
public async Task EmailVerificationLink()
515617
{

0 commit comments

Comments
 (0)