diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/TokenController.Password.cs b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/TokenController.Password.cs index 07be60da44..b076de7cd8 100644 --- a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/TokenController.Password.cs +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/TokenController.Password.cs @@ -57,24 +57,30 @@ public partial class TokenController if (await externalLoginProvider.TryAuthenticateAsync(request.Username, request.Password)) { - user = await UserManager.FindByNameAsync(request.Username); + user = await UserManager.FindSharedUserByNameAsync(request.Username); if (user == null) { user = await externalLoginProvider.CreateUserAsync(request.Username, externalLoginProviderInfo.Name); } else { - await externalLoginProvider.UpdateUserAsync(user, externalLoginProviderInfo.Name); + using (CurrentTenant.Change(user.TenantId)) + { + await externalLoginProvider.UpdateUserAsync(user, externalLoginProviderInfo.Name); + } } - return await SetSuccessResultAsync(request, user); + using (CurrentTenant.Change(user.TenantId)) + { + return await SetSuccessResultAsync(request, user); + } } } } await IdentityOptions.SetAsync(); - user = await UserManager.FindByNameAsync(request.Username); + user = await UserManager.FindSharedUserByNameAsync(request.Username); if (user == null) { Logger.LogInformation("No user found matching username: {username}", request.Username); @@ -96,77 +102,82 @@ public partial class TokenController return Forbid(properties, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme); } - var result = await SignInManager.CheckPasswordSignInAsync(user, request.Password, true); - if (!result.Succeeded) + using (CurrentTenant.Change(user.TenantId)) { - await IdentitySecurityLogManager.SaveAsync(new IdentitySecurityLogContext + await IdentityOptions.SetAsync(); + + var result = await SignInManager.CheckPasswordSignInAsync(user, request.Password, true); + if (!result.Succeeded) { - Identity = OpenIddictSecurityLogIdentityConsts.OpenIddict, - Action = result.ToIdentitySecurityLogAction(), - UserName = request.Username, - ClientId = request.ClientId - }); + await IdentitySecurityLogManager.SaveAsync(new IdentitySecurityLogContext + { + Identity = OpenIddictSecurityLogIdentityConsts.OpenIddict, + Action = result.ToIdentitySecurityLogAction(), + UserName = request.Username, + ClientId = request.ClientId + }); - var errorCode = OpenIddictConstants.Errors.InvalidGrant; - string errorDescription; + var errorCode = OpenIddictConstants.Errors.InvalidGrant; + string errorDescription; - if (result.IsLockedOut) - { - Logger.LogInformation("Authentication failed for username: {username}, reason: locked out", request.Username); - errorCode = AbpOpenIddictErrors.AccountLocked; - errorDescription = "The user account has been locked out due to invalid login attempts. Please wait a while and try again."; - } - else if (result.IsNotAllowed) - { - if (!await UserManager.CheckPasswordAsync(user, request.Password)) + if (result.IsLockedOut) { - Logger.LogInformation("Authentication failed for username: {username}, reason: invalid credentials", request.Username); - errorDescription = "Invalid username or password!"; + Logger.LogInformation("Authentication failed for username: {username}, reason: locked out", request.Username); + errorCode = AbpOpenIddictErrors.AccountLocked; + errorDescription = "The user account has been locked out due to invalid login attempts. Please wait a while and try again."; } - else + else if (result.IsNotAllowed) { - Logger.LogInformation("Authentication failed for username: {username}, reason: not allowed", request.Username); - - if (user.ShouldChangePasswordOnNextLogin) + if (!await UserManager.CheckPasswordAsync(user, request.Password)) { - return await HandleShouldChangePasswordOnNextLoginAsync(request, user, request.Password); + Logger.LogInformation("Authentication failed for username: {username}, reason: invalid credentials", request.Username); + errorDescription = "Invalid username or password!"; } - - if (await UserManager.ShouldPeriodicallyChangePasswordAsync(user)) + else { - return await HandlePeriodicallyChangePasswordAsync(request, user, request.Password); - } + Logger.LogInformation("Authentication failed for username: {username}, reason: not allowed", request.Username); - if (user.IsActive) - { - return await HandleConfirmUserAsync(request, user); - } + if (user.ShouldChangePasswordOnNextLogin) + { + return await HandleShouldChangePasswordOnNextLoginAsync(request, user, request.Password); + } + + if (await UserManager.ShouldPeriodicallyChangePasswordAsync(user)) + { + return await HandlePeriodicallyChangePasswordAsync(request, user, request.Password); + } - errorCode = AbpOpenIddictErrors.AccountInactive; - errorDescription = "You are not allowed to login! Your account is inactive or needs to confirm your email/phone number."; + if (user.IsActive) + { + return await HandleConfirmUserAsync(request, user); + } + + errorCode = AbpOpenIddictErrors.AccountInactive; + errorDescription = "You are not allowed to login! Your account is inactive or needs to confirm your email/phone number."; + } } - } - else - { - Logger.LogInformation("Authentication failed for username: {username}, reason: invalid credentials", request.Username); - errorDescription = "Invalid username or password!"; + else + { + Logger.LogInformation("Authentication failed for username: {username}, reason: invalid credentials", request.Username); + errorDescription = "Invalid username or password!"; + } + + var properties = new AuthenticationProperties(new Dictionary + { + [OpenIddictServerAspNetCoreConstants.Properties.Error] = errorCode, + [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = errorDescription + }); + + return Forbid(properties, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme); } - var properties = new AuthenticationProperties(new Dictionary + if (await IsTfaEnabledAsync(user)) { - [OpenIddictServerAspNetCoreConstants.Properties.Error] = errorCode, - [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = errorDescription - }); - - return Forbid(properties, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme); - } + return await HandleTwoFactorLoginAsync(request, user); + } - if (await IsTfaEnabledAsync(user)) - { - return await HandleTwoFactorLoginAsync(request, user); + return await SetSuccessResultAsync(request, user); } - - return await SetSuccessResultAsync(request, user); } } } @@ -178,13 +189,13 @@ public partial class TokenController return; } - var userByUsername = await UserManager.FindByNameAsync(request.Username); + var userByUsername = await UserManager.FindSharedUserByNameAsync(request.Username); if (userByUsername != null) { return; } - var userByEmail = await UserManager.FindByEmailAsync(request.Username); + var userByEmail = await UserManager.FindSharedUserByEmailAsync(request.Username); if (userByEmail == null) { return; diff --git a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/TokenController.TokenExchange.cs b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/TokenController.TokenExchange.cs index 8f17a34be0..81e85057ac 100644 --- a/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/TokenController.TokenExchange.cs +++ b/modules/openiddict/src/Volo.Abp.OpenIddict.AspNetCore/Volo/Abp/OpenIddict/Controllers/TokenController.TokenExchange.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Security.Claims; +using System.Security.Principal; using System.Text.Json.Nodes; using System.Threading.Tasks; using Microsoft.AspNetCore.Authentication; @@ -27,66 +28,69 @@ public partial class TokenController // If available, retrieve the claims principal stored in the actor token. var actor = result.Properties?.GetParameter(OpenIddictServerAspNetCoreConstants.Properties.ActorTokenPrincipal); - // Retrieve the user profile corresponding to the subject token. - var user = await UserManager.FindByIdAsync(result.Principal!.GetClaim(OpenIddictConstants.Claims.Subject)!); - if (user is null) + using (CurrentTenant.Change(result.Principal!.FindTenantId())) { - return Forbid( - authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme, - properties: new AuthenticationProperties(new Dictionary - { - [OpenIddictServerAspNetCoreConstants.Properties.Error] = OpenIddictConstants.Errors.InvalidGrant, - [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "The token is no longer valid." - })); - } + // Retrieve the user profile corresponding to the subject token. + var user = await UserManager.FindByIdAsync(result.Principal!.GetClaim(OpenIddictConstants.Claims.Subject)!); + if (user is null) + { + return Forbid( + authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme, + properties: new AuthenticationProperties(new Dictionary + { + [OpenIddictServerAspNetCoreConstants.Properties.Error] = OpenIddictConstants.Errors.InvalidGrant, + [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "The token is no longer valid." + })); + } - // Ensure the user is still allowed to sign in. - if (!await PreSignInCheckAsync(user)) - { - return Forbid( - authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme, - properties: new AuthenticationProperties(new Dictionary - { - [OpenIddictServerAspNetCoreConstants.Properties.Error] = OpenIddictConstants.Errors.InvalidGrant, - [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "The user is no longer allowed to sign in." - })); - } + // Ensure the user is still allowed to sign in. + if (!await PreSignInCheckAsync(user)) + { + return Forbid( + authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme, + properties: new AuthenticationProperties(new Dictionary + { + [OpenIddictServerAspNetCoreConstants.Properties.Error] = OpenIddictConstants.Errors.InvalidGrant, + [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "The user is no longer allowed to sign in." + })); + } - // Note: whether the identity represents a delegated or impersonated access (or any other - // model) is entirely up to the implementer: to support all scenarios, OpenIddict doesn't - // enforce any specific constraint on the identity used for the sign-in operation and only - // requires that the standard "act" and "may_act" claims be valid JSON objects if present. + // Note: whether the identity represents a delegated or impersonated access (or any other + // model) is entirely up to the implementer: to support all scenarios, OpenIddict doesn't + // enforce any specific constraint on the identity used for the sign-in operation and only + // requires that the standard "act" and "may_act" claims be valid JSON objects if present. - // Clear the dynamic claims cache. - await IdentityDynamicClaimsPrincipalContributorCache.ClearAsync(user.Id, user.TenantId); + // Clear the dynamic claims cache. + await IdentityDynamicClaimsPrincipalContributorCache.ClearAsync(user.Id, user.TenantId); - // Create a new ClaimsPrincipal containing the claims that - // will be used to create an id_token, a token or a code. - var principal = await SignInManager.CreateUserPrincipalAsync(user); + // Create a new ClaimsPrincipal containing the claims that + // will be used to create an id_token, a token or a code. + var principal = await SignInManager.CreateUserPrincipalAsync(user); - // Note: IdentityModel doesn't support serializing ClaimsIdentity.Actor to the - // standard "act" claim yet, which requires adding the "act" claim manually. - // - // For more information, see - // https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/pull/3219. - if (!string.IsNullOrEmpty(actor?.GetClaim(OpenIddictConstants.Claims.Subject)) && - !string.Equals(principal.GetClaim(OpenIddictConstants.Claims.Subject), actor.GetClaim(OpenIddictConstants.Claims.Subject), StringComparison.Ordinal)) - { - principal.SetClaim(OpenIddictConstants.Claims.Actor, new JsonObject + // Note: IdentityModel doesn't support serializing ClaimsIdentity.Actor to the + // standard "act" claim yet, which requires adding the "act" claim manually. + // + // For more information, see + // https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/pull/3219. + if (!string.IsNullOrEmpty(actor?.GetClaim(OpenIddictConstants.Claims.Subject)) && + !string.Equals(principal.GetClaim(OpenIddictConstants.Claims.Subject), actor.GetClaim(OpenIddictConstants.Claims.Subject), StringComparison.Ordinal)) { - [OpenIddictConstants.Claims.Subject] = actor.GetClaim(OpenIddictConstants.Claims.Subject) - }); - } + principal.SetClaim(OpenIddictConstants.Claims.Actor, new JsonObject + { + [OpenIddictConstants.Claims.Subject] = actor.GetClaim(OpenIddictConstants.Claims.Subject) + }); + } - // Note: in this sample, the granted scopes match the requested scope - // but you may want to allow the user to uncheck specific scopes. - // For that, simply restrict the list of scopes before calling SetScopes. - principal.SetScopes(request.GetScopes()); - principal.SetResources(await GetResourcesAsync(request.GetScopes())); + // Note: in this sample, the granted scopes match the requested scope + // but you may want to allow the user to uncheck specific scopes. + // For that, simply restrict the list of scopes before calling SetScopes. + principal.SetScopes(request.GetScopes()); + principal.SetResources(await GetResourcesAsync(request.GetScopes())); - await OpenIddictClaimsPrincipalManager.HandleAsync(request, principal); + await OpenIddictClaimsPrincipalManager.HandleAsync(request, principal); - // Returning a SignInResult will ask OpenIddict to issue the appropriate access/identity tokens. - return SignIn(principal, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme); + // Returning a SignInResult will ask OpenIddict to issue the appropriate access/identity tokens. + return SignIn(principal, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme); + } } }