@@ -18,7 +18,7 @@ public class AuthenticationManager : IAuthenticationManager
18
18
private readonly IClock clock ;
19
19
private readonly IMySqlConnectionSource mySqlConnectionSource ;
20
20
private readonly ILogger < AuthenticationManager > logger ;
21
- private readonly IPasswordHasher < User ? > passwordHasher ;
21
+ private readonly IPasswordHasher < User > passwordHasher ;
22
22
private readonly IPasswordResetTokenDataProvider passwordResetTokenDataProvider ;
23
23
private readonly IRandomTokenGenerator randomTokenGenerator ;
24
24
private readonly IUrlHelperFactory urlHelperFactory ;
@@ -32,7 +32,7 @@ public AuthenticationManager(
32
32
IClock clock ,
33
33
IMySqlConnectionSource mySqlConnectionSource ,
34
34
ILogger < AuthenticationManager > logger ,
35
- IPasswordHasher < User ? > passwordHasher ,
35
+ IPasswordHasher < User > passwordHasher ,
36
36
IPasswordResetTokenDataProvider passwordResetTokenDataProvider ,
37
37
IRandomTokenGenerator randomTokenGenerator ,
38
38
IUrlHelperFactory urlHelperFactory ,
@@ -79,7 +79,7 @@ await this.authenticationEventDataProvider.LogEvent(
79
79
return null ;
80
80
}
81
81
82
- if ( ! this . VerifyPassword ( user , password ) )
82
+ if ( ! this . VerifyPassword ( user , user . HashedPassword , password ) )
83
83
{
84
84
AuthenticateLogMessages . IncorrectPassword ( this . logger , user . Id , user . Email , null ) ;
85
85
@@ -113,7 +113,7 @@ await this.authenticationEventDataProvider.LogEvent(
113
113
$ "User { user . Id } ({ user . Email } ) does not have a password.") ;
114
114
}
115
115
116
- if ( ! this . VerifyPassword ( user , currentPassword ) )
116
+ if ( ! this . VerifyPassword ( user , user . HashedPassword , currentPassword ) )
117
117
{
118
118
ChangePasswordLogMessages . IncorrectPassword (
119
119
this . logger , user . Id , user . Email , null ) ;
@@ -124,7 +124,7 @@ await this.authenticationEventDataProvider.LogEvent(
124
124
return false ;
125
125
}
126
126
127
- var newSecurityStamp = await this . SetPassword ( connection , user . Id , newPassword ) ;
127
+ var newSecurityStamp = await this . SetPassword ( connection , user , newPassword ) ;
128
128
129
129
ChangePasswordLogMessages . Success ( this . logger , user . Id , user . Email , null ) ;
130
130
@@ -176,18 +176,18 @@ await this.authenticationEventDataProvider.LogEvent(
176
176
throw new InvalidTokenException ( "Password reset token is invalid" ) ;
177
177
}
178
178
179
- await this . SetPassword ( connection , userId . Value , newPassword ) ;
179
+ var user = await this . userDataProvider . GetUser ( connection , userId . Value ) ;
180
+
181
+ var newSecurityStamp = await this . SetPassword ( connection , user , newPassword ) ;
180
182
181
183
ResetPasswordLogMessages . Success ( this . logger , userId . Value , RedactToken ( token ) , null ) ;
182
184
183
185
await this . authenticationEventDataProvider . LogEvent (
184
186
connection , "password_reset_success" , userId . Value ) ;
185
187
186
- var user = await this . userDataProvider . GetUser ( connection , userId . Value ) ;
187
-
188
188
await this . authenticationMailer . SendPasswordChangeNotification ( user . Email ) ;
189
189
190
- return user ;
190
+ return user with { SecurityStamp = newSecurityStamp } ;
191
191
}
192
192
193
193
public async Task SendPasswordResetLink ( ActionContext actionContext , string email )
@@ -258,50 +258,57 @@ public async Task ValidatePrincipal(CookieValidatePrincipalContext context)
258
258
{
259
259
var principal = context . Principal ;
260
260
261
- var userId = principal ? . GetUserId ( ) ;
261
+ if ( principal == null )
262
+ {
263
+ return ;
264
+ }
262
265
263
- if ( userId . HasValue )
266
+ var userId = principal . GetUserId ( ) ;
267
+
268
+ if ( ! userId . HasValue )
264
269
{
265
- User user ;
270
+ return ;
271
+ }
266
272
267
- using ( var connection = await this . mySqlConnectionSource . OpenConnection ( ) )
268
- {
269
- user = await this . userDataProvider . GetUser ( connection , userId . Value ) ;
270
- }
273
+ User user ;
271
274
272
- var securityStamp = principal . FindFirstValue ( CustomClaimTypes . SecurityStamp ) ;
275
+ using ( var connection = await this . mySqlConnectionSource . OpenConnection ( ) )
276
+ {
277
+ user = await this . userDataProvider . GetUser ( connection , userId . Value ) ;
278
+ }
273
279
274
- if ( string . Equals ( securityStamp , user . SecurityStamp , StringComparison . Ordinal ) )
275
- {
276
- context . HttpContext . SetCurrentUser ( user ) ;
280
+ var securityStamp = principal . FindFirstValue ( CustomClaimTypes . SecurityStamp ) ;
277
281
278
- ValidatePrincipalLogMessages . Success ( this . logger , user . Id , user . Email , null ) ;
279
- }
280
- else
281
- {
282
- ValidatePrincipalLogMessages . IncorrectSecurityStamp (
283
- this . logger , user . Id , user . Email , null ) ;
282
+ if ( string . Equals ( securityStamp , user . SecurityStamp , StringComparison . Ordinal ) )
283
+ {
284
+ context . HttpContext . SetCurrentUser ( user ) ;
284
285
285
- context . RejectPrincipal ( ) ;
286
+ ValidatePrincipalLogMessages . Success ( this . logger , user . Id , user . Email , null ) ;
287
+ }
288
+ else
289
+ {
290
+ ValidatePrincipalLogMessages . IncorrectSecurityStamp (
291
+ this . logger , user . Id , user . Email , null ) ;
286
292
287
- await this . SignOutCurrentUser ( context . HttpContext ) ;
288
- }
293
+ context . RejectPrincipal ( ) ;
294
+
295
+ await this . SignOutCurrentUser ( context . HttpContext ) ;
289
296
}
290
297
}
291
298
292
299
private static string RedactToken ( string token ) => $ "{ token [ ..6 ] } …";
293
300
294
301
private async Task < string > SetPassword (
295
- MySqlConnection connection , long userId , string newPassword )
302
+ MySqlConnection connection , User user , string newPassword )
296
303
{
297
- var hashedPassword = this . passwordHasher . HashPassword ( null , newPassword ) ;
304
+ var hashedPassword = this . passwordHasher . HashPassword ( user , newPassword ) ;
298
305
299
306
var securityStamp = this . randomTokenGenerator . Generate ( 2 ) ;
300
307
301
308
await this . userDataProvider . UpdatePassword (
302
- connection , userId , hashedPassword , securityStamp ) ;
309
+ connection , user . Id , hashedPassword , securityStamp ) ;
303
310
304
- await this . passwordResetTokenDataProvider . DeleteTokensForUser ( connection , userId ) ;
311
+ await this . passwordResetTokenDataProvider . DeleteTokensForUser ( connection , user . Id ) ;
305
312
306
313
return securityStamp ;
307
314
}
@@ -328,8 +335,8 @@ await this.passwordResetTokenDataProvider.DeleteExpiredTokens(
328
335
return await this . passwordResetTokenDataProvider . GetUserIdForToken ( connection , token ) ;
329
336
}
330
337
331
- private bool VerifyPassword ( User user , string password ) =>
332
- this . passwordHasher . VerifyHashedPassword ( user , user . HashedPassword , password ) ==
338
+ private bool VerifyPassword ( User user , string hashedPassword , string password ) =>
339
+ this . passwordHasher . VerifyHashedPassword ( user , hashedPassword , password ) ==
333
340
PasswordVerificationResult . Success ;
334
341
335
342
private static class AuthenticateLogMessages
@@ -418,8 +425,8 @@ private static class SignInLogMessages
418
425
419
426
private static class SignOutLogMessages
420
427
{
421
- public static readonly Action < ILogger , long , string , Exception ? > SignedOut =
422
- LoggerMessage . Define < long , string > (
428
+ public static readonly Action < ILogger , long , string ? , Exception ? > SignedOut =
429
+ LoggerMessage . Define < long , string ? > (
423
430
LogLevel . Information , 213 , "User {UserId} ({Email}) signed out" ) ;
424
431
}
425
432
0 commit comments