mirror of https://github.com/abpframework/abp
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
228 lines
8.3 KiB
228 lines
8.3 KiB
using IdentityModel;
|
|
using IdentityServer4.Events;
|
|
using IdentityServer4.Models;
|
|
using IdentityServer4.Services;
|
|
using IdentityServer4.Stores;
|
|
using Microsoft.AspNetCore.Authentication;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.Extensions.Options;
|
|
using System;
|
|
using System.Diagnostics;
|
|
using System.Linq;
|
|
using System.Security.Claims;
|
|
using System.Security.Principal;
|
|
using System.Threading.Tasks;
|
|
using Volo.Abp.Account.Settings;
|
|
using Volo.Abp.DependencyInjection;
|
|
using Volo.Abp.MultiTenancy;
|
|
using Volo.Abp.Settings;
|
|
using Volo.Abp.Uow;
|
|
|
|
namespace Volo.Abp.Account.Web.Pages.Account
|
|
{
|
|
[ExposeServices(typeof(LoginModel))]
|
|
public class IdentityServerSupportedLoginModel : LoginModel
|
|
{
|
|
protected IIdentityServerInteractionService Interaction { get; }
|
|
protected IClientStore ClientStore { get; }
|
|
protected IEventService IdentityServerEvents { get; }
|
|
|
|
public IdentityServerSupportedLoginModel(
|
|
IAuthenticationSchemeProvider schemeProvider,
|
|
IOptions<AbpAccountOptions> accountOptions,
|
|
IIdentityServerInteractionService interaction,
|
|
IClientStore clientStore,
|
|
IEventService identityServerEvents)
|
|
:base(
|
|
schemeProvider,
|
|
accountOptions)
|
|
{
|
|
Interaction = interaction;
|
|
ClientStore = clientStore;
|
|
IdentityServerEvents = identityServerEvents;
|
|
}
|
|
|
|
public override async Task<IActionResult> OnGetAsync()
|
|
{
|
|
LoginInput = new LoginInputModel();
|
|
|
|
var context = await Interaction.GetAuthorizationContextAsync(ReturnUrl);
|
|
|
|
if (context != null)
|
|
{
|
|
LoginInput.UserNameOrEmailAddress = context.LoginHint;
|
|
|
|
//TODO: Reference AspNetCore MultiTenancy module and use options to get the tenant key!
|
|
var tenant = context.Parameters[TenantResolverConsts.DefaultTenantKey];
|
|
if (!string.IsNullOrEmpty(tenant))
|
|
{
|
|
CurrentTenant.Change(Guid.Parse(tenant));
|
|
Response.Cookies.Append(TenantResolverConsts.DefaultTenantKey, tenant);
|
|
}
|
|
}
|
|
|
|
if (context?.IdP != null)
|
|
{
|
|
LoginInput.UserNameOrEmailAddress = context.LoginHint;
|
|
ExternalProviders = new[] { new ExternalProviderModel { AuthenticationScheme = context.IdP } };
|
|
return Page();
|
|
}
|
|
|
|
var schemes = await SchemeProvider.GetAllSchemesAsync();
|
|
|
|
var providers = schemes
|
|
.Where(x => x.DisplayName != null || x.Name.Equals(AccountOptions.WindowsAuthenticationSchemeName, StringComparison.OrdinalIgnoreCase))
|
|
.Select(x => new ExternalProviderModel
|
|
{
|
|
DisplayName = x.DisplayName,
|
|
AuthenticationScheme = x.Name
|
|
})
|
|
.ToList();
|
|
|
|
EnableLocalLogin = await SettingProvider.IsTrueAsync(AccountSettingNames.EnableLocalLogin);
|
|
if (context?.ClientId != null)
|
|
{
|
|
var client = await ClientStore.FindEnabledClientByIdAsync(context.ClientId);
|
|
if (client != null)
|
|
{
|
|
EnableLocalLogin = client.EnableLocalLogin;
|
|
|
|
if (client.IdentityProviderRestrictions != null && client.IdentityProviderRestrictions.Any())
|
|
{
|
|
providers = providers.Where(provider => client.IdentityProviderRestrictions.Contains(provider.AuthenticationScheme)).ToList();
|
|
}
|
|
}
|
|
}
|
|
|
|
ExternalProviders = providers.ToArray();
|
|
|
|
if (IsExternalLoginOnly)
|
|
{
|
|
return await base.OnPostExternalLogin(providers.First().AuthenticationScheme);
|
|
}
|
|
|
|
return Page();
|
|
}
|
|
|
|
[UnitOfWork] //TODO: Will be removed when we implement action filter
|
|
public override async Task<IActionResult> OnPostAsync(string action)
|
|
{
|
|
if (action == "Cancel")
|
|
{
|
|
var context = await Interaction.GetAuthorizationContextAsync(ReturnUrl);
|
|
if (context == null)
|
|
{
|
|
return Redirect("~/");
|
|
}
|
|
|
|
await Interaction.GrantConsentAsync(context, ConsentResponse.Denied);
|
|
|
|
return Redirect(ReturnUrl);
|
|
}
|
|
|
|
await CheckLocalLoginAsync();
|
|
|
|
ValidateModel();
|
|
|
|
await ReplaceEmailToUsernameOfInputIfNeeds();
|
|
|
|
var result = await SignInManager.PasswordSignInAsync(
|
|
LoginInput.UserNameOrEmailAddress,
|
|
LoginInput.Password,
|
|
LoginInput.RememberMe,
|
|
true
|
|
);
|
|
|
|
if (result.RequiresTwoFactor)
|
|
{
|
|
return RedirectToPage("./SendSecurityCode", new
|
|
{
|
|
returnUrl = ReturnUrl,
|
|
returnUrlHash = ReturnUrlHash,
|
|
rememberMe = LoginInput.RememberMe
|
|
});
|
|
}
|
|
|
|
if (result.IsLockedOut)
|
|
{
|
|
Alerts.Warning(L["UserLockedOutMessage"]);
|
|
return Page();
|
|
}
|
|
|
|
if (result.IsNotAllowed)
|
|
{
|
|
Alerts.Warning(L["LoginIsNotAllowed"]);
|
|
return Page();
|
|
}
|
|
|
|
if (!result.Succeeded)
|
|
{
|
|
Alerts.Danger(L["InvalidUserNameOrPassword"]);
|
|
return Page();
|
|
}
|
|
|
|
//TODO: Find a way of getting user's id from the logged in user and do not query it again like that!
|
|
var user = await UserManager.FindByNameAsync(LoginInput.UserNameOrEmailAddress) ??
|
|
await UserManager.FindByEmailAsync(LoginInput.UserNameOrEmailAddress);
|
|
|
|
Debug.Assert(user != null, nameof(user) + " != null");
|
|
await IdentityServerEvents.RaiseAsync(new UserLoginSuccessEvent(user.UserName, user.Id.ToString(), user.UserName)); //TODO: Use user's name once implemented
|
|
|
|
return RedirectSafely(ReturnUrl, ReturnUrlHash);
|
|
}
|
|
|
|
[UnitOfWork]
|
|
public override async Task<IActionResult> OnPostExternalLogin(string provider)
|
|
{
|
|
if (AccountOptions.WindowsAuthenticationSchemeName == provider)
|
|
{
|
|
return await ProcessWindowsLoginAsync();
|
|
}
|
|
|
|
return await base.OnPostExternalLogin(provider);
|
|
}
|
|
|
|
private async Task<IActionResult> ProcessWindowsLoginAsync()
|
|
{
|
|
var result = await HttpContext.AuthenticateAsync(AccountOptions.WindowsAuthenticationSchemeName);
|
|
if (!(result?.Principal is WindowsPrincipal windowsPrincipal))
|
|
{
|
|
return Challenge(AccountOptions.WindowsAuthenticationSchemeName);
|
|
}
|
|
|
|
var props = new AuthenticationProperties
|
|
{
|
|
RedirectUri = Url.Page("./Login", pageHandler: "ExternalLoginCallback", values: new { ReturnUrl, ReturnUrlHash }),
|
|
Items =
|
|
{
|
|
{"scheme", AccountOptions.WindowsAuthenticationSchemeName},
|
|
}
|
|
};
|
|
|
|
var identity = new ClaimsIdentity(AccountOptions.WindowsAuthenticationSchemeName);
|
|
identity.AddClaim(new Claim(JwtClaimTypes.Subject, windowsPrincipal.Identity.Name));
|
|
identity.AddClaim(new Claim(JwtClaimTypes.Name, windowsPrincipal.Identity.Name));
|
|
|
|
//TODO: Consider to add Windows groups the the identity
|
|
//if (_accountOptions.IncludeWindowsGroups)
|
|
//{
|
|
// var windowsIdentity = windowsPrincipal.Identity as WindowsIdentity;
|
|
// if (windowsIdentity != null)
|
|
// {
|
|
// var groups = windowsIdentity.Groups?.Translate(typeof(NTAccount));
|
|
// var roles = groups.Select(x => new Claim(JwtClaimTypes.Role, x.Value));
|
|
// identity.AddClaims(roles);
|
|
// }
|
|
//}
|
|
|
|
await HttpContext.SignInAsync(
|
|
IdentityServer4.IdentityServerConstants.ExternalCookieAuthenticationScheme,
|
|
new ClaimsPrincipal(identity),
|
|
props
|
|
);
|
|
|
|
return RedirectSafely(props.RedirectUri);
|
|
}
|
|
}
|
|
}
|