Skip to content

Commit bc35156

Browse files
committed
RE1-T117 PR#403 fixes
1 parent a52f9f2 commit bc35156

1 file changed

Lines changed: 35 additions & 16 deletions

File tree

Repositories/Resgrid.Repositories.DataRepository/IdentityRepository.cs

Lines changed: 35 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,9 @@ public async Task<IdentityUser> GetUserByUserNameAsync(string userName)
6363
{
6464
using (IDbConnection db = new NpgsqlConnection(DataConfig.CoreConnectionString))
6565
{
66-
// PostgreSQL text comparison is case-sensitive (unlike SQL Server's default collation),
67-
// so match on normalizedusername the same way ASP.NET Identity sign-in does. Otherwise a
68-
// user who authenticated with different casing than the stored username is not found here.
66+
// aspnetusers columns are citext (case-insensitive), so match on the same key ASP.NET
67+
// Identity authenticated against -- normalizedusername -- so a row whose username and
68+
// normalizedusername have drifted apart is still found here.
6969
var result = await db.QueryAsync<IdentityUser>($"SELECT * FROM aspnetusers WHERE normalizedusername = @normalizedUserName", new { normalizedUserName = userName?.ToUpperInvariant() });
7070

7171
return result.FirstOrDefault();
@@ -90,9 +90,9 @@ public IdentityUser GetUserByEmail(string email)
9090
{
9191
using (IDbConnection db = new NpgsqlConnection(DataConfig.CoreConnectionString))
9292
{
93-
// PostgreSQL text comparison is case-sensitive; LOWER() both sides so a different-cased email
94-
// still matches (normalizedemail is not maintained on the PG update path, so it can't be relied on).
95-
return db.Query<IdentityUser>($"SELECT * FROM aspnetusers WHERE LOWER(email) = LOWER(@email)", new { email = email }).FirstOrDefault();
93+
// email is citext (case-insensitive), so plain equality is already case-insensitive and can
94+
// use the index -- no LOWER() needed.
95+
return db.Query<IdentityUser>($"SELECT * FROM aspnetusers WHERE email = @email", new { email = email }).FirstOrDefault();
9696
}
9797
}
9898
else
@@ -112,15 +112,15 @@ public void UpdateUsername(string oldUsername, string newUsername)
112112
{
113113
using (IDbConnection db = new NpgsqlConnection(DataConfig.CoreConnectionString))
114114
{
115-
// Case-insensitive match on the old username (PostgreSQL text comparison is case-sensitive).
116-
db.Execute($"UPDATE public.aspnetusers SET username = @newUsername, normalizedusername = @newUsernameUpper WHERE LOWER(username) = LOWER(@oldUsername)", new { newUsername = newUsername, newUsernameUpper = newUsername.ToUpper(), oldUsername = oldUsername });
115+
// username is citext, so equality is already case-insensitive and index-friendly.
116+
db.Execute($"UPDATE public.aspnetusers SET username = @newUsername, normalizedusername = @newUsernameUpper WHERE username = @oldUsername", new { newUsername = newUsername, newUsernameUpper = newUsername.ToUpperInvariant(), oldUsername = oldUsername });
117117
}
118118
}
119119
else
120120
{
121121
using (IDbConnection db = new SqlConnection(DataConfig.CoreConnectionString))
122122
{
123-
db.Execute($"UPDATE [AspNetUsers] SET [UserName] = @newUsername, [NormalizedUserName] = @newUsernameUpper WHERE UserName = @oldUsername", new { newUsername = newUsername, newUsernameUpper = newUsername.ToUpper(), oldUsername = oldUsername });
123+
db.Execute($"UPDATE [AspNetUsers] SET [UserName] = @newUsername, [NormalizedUserName] = @newUsernameUpper WHERE UserName = @oldUsername", new { newUsername = newUsername, newUsernameUpper = newUsername.ToUpperInvariant(), oldUsername = oldUsername });
124124
}
125125
}
126126
}
@@ -133,14 +133,14 @@ public void UpdateEmail(string userId, string newEmail)
133133
{
134134
// Keep normalizedemail in sync (ASP.NET Identity's FindByEmailAsync looks up by it); the
135135
// SQL Server branch already does this. Without it, email lookups go stale after a change.
136-
db.Execute($"UPDATE public.aspnetusers SET email = @newEmail, normalizedemail = @newEmailUpper WHERE id = @userId", new { userId = userId, newEmail = newEmail, newEmailUpper = newEmail?.ToUpper() });
136+
db.Execute($"UPDATE public.aspnetusers SET email = @newEmail, normalizedemail = @newEmailUpper WHERE id = @userId", new { userId = userId, newEmail = newEmail, newEmailUpper = newEmail?.ToUpperInvariant() });
137137
}
138138
}
139139
else
140140
{
141141
using (IDbConnection db = new SqlConnection(DataConfig.CoreConnectionString))
142142
{
143-
db.Execute($"UPDATE [AspNetUsers] SET [Email] = @newEmail, [NormalizedEmail] = @newEmailUpper WHERE Id = @userId", new { userId = userId, newEmail = newEmail, newEmailUpper = newEmail.ToUpper() });
143+
db.Execute($"UPDATE [AspNetUsers] SET [Email] = @newEmail, [NormalizedEmail] = @newEmailUpper WHERE Id = @userId", new { userId = userId, newEmail = newEmail, newEmailUpper = newEmail.ToUpperInvariant() });
144144
}
145145
}
146146
}
@@ -469,22 +469,41 @@ public async Task<bool> ClearOutUserLoginAsync(string userId)
469469
{
470470
var deleteId = Guid.NewGuid().ToString();
471471
var maskedEmail = deleteId + "@resgrid.del";
472+
// Full de-provisioning: mask the normalized columns too (so ASP.NET Identity's normalized
473+
// lookups can't find the row), null the password hash, rotate the security stamp, and lock
474+
// the account so a deleted user can no longer authenticate.
472475
var result = await db.ExecuteAsync(@"UPDATE public.aspnetusers
473476
SET username = @deleteId,
474-
email = @maskedEmail
477+
normalizedusername = @normalizedDeleteId,
478+
email = @maskedEmail,
479+
normalizedemail = @normalizedMaskedEmail,
480+
passwordhash = NULL,
481+
securitystamp = @securityStamp,
482+
emailconfirmed = false,
483+
lockoutenabled = true,
484+
lockoutend = @lockoutEnd
475485
WHERE id = @userId",
476-
new { userId = userId, deleteId = deleteId, maskedEmail = maskedEmail });
486+
new { userId = userId, deleteId = deleteId, normalizedDeleteId = deleteId.ToUpperInvariant(), maskedEmail = maskedEmail, normalizedMaskedEmail = maskedEmail.ToUpperInvariant(), securityStamp = Guid.NewGuid().ToString(), lockoutEnd = new DateTimeOffset(9999, 12, 31, 23, 59, 59, TimeSpan.Zero) });
477487
}
478488
}
479489
else
480490
{
481491
using (IDbConnection db = new SqlConnection(DataConfig.CoreConnectionString))
482492
{
493+
var deleteId = Guid.NewGuid().ToString();
494+
var maskedEmail = deleteId + "@resgrid.del";
483495
var result = await db.ExecuteAsync(@"UPDATE AspNetUsers
484-
SET UserName = @deleteid,
485-
Email = @deleteid + '@resgrid.del'
496+
SET UserName = @deleteId,
497+
NormalizedUserName = @normalizedDeleteId,
498+
Email = @maskedEmail,
499+
NormalizedEmail = @normalizedMaskedEmail,
500+
PasswordHash = NULL,
501+
SecurityStamp = @securityStamp,
502+
EmailConfirmed = 0,
503+
LockoutEnabled = 1,
504+
LockoutEnd = @lockoutEnd
486505
WHERE Id = @userId",
487-
new { userId = userId, deleteid = Guid.NewGuid().ToString() });
506+
new { userId = userId, deleteId = deleteId, normalizedDeleteId = deleteId.ToUpperInvariant(), maskedEmail = maskedEmail, normalizedMaskedEmail = maskedEmail.ToUpperInvariant(), securityStamp = Guid.NewGuid().ToString(), lockoutEnd = new DateTimeOffset(9999, 12, 31, 23, 59, 59, TimeSpan.Zero) });
488507
}
489508
}
490509

0 commit comments

Comments
 (0)