using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Identity; using Raven.Client.Documents; using System.Collections.Generic; using System.Linq; using System.Security.Claims; using System.Threading.Tasks; using zero.Core.Entities; using zero.Core.Identity; namespace zero.Core.Api { public class AuthenticationApi : IAuthenticationApi { protected IDocumentStore Raven { get; private set; } protected IHttpContextAccessor HttpContextAccessor { get; set; } protected SignInManager SignInManager { get; private set; } protected ClaimsPrincipal Principal => HttpContextAccessor.HttpContext?.User; public AuthenticationApi(IDocumentStore raven, IHttpContextAccessor httpContextAccessor, SignInManager signInManager) { Raven = raven; HttpContextAccessor = httpContextAccessor; SignInManager = signInManager; } /// public bool IsLoggedIn() { ClaimsPrincipal principal = HttpContextAccessor.HttpContext.User; bool isAuthenticated = principal.Identity.IsAuthenticated; bool isZeroUser = principal.HasClaim(Constants.Auth.Claims.IsZero, PermissionsValue.True); bool isSignedIn = SignInManager.IsSignedIn(principal); return isAuthenticated && isZeroUser && isSignedIn; } /// public bool IsSuper() { return Principal.HasClaim(Constants.Auth.Claims.IsSuper, PermissionsValue.True); } /// public bool IsAdmin() { return Principal.HasClaim(Constants.Auth.Claims.Role, "administrator"); // TODO use constant (in setup as well) } /// public async Task GetUser() { return await SignInManager.UserManager.GetUserAsync(HttpContextAccessor.HttpContext.User); } /// public IList GetPermissions(string prefix = null) { return Principal.Claims .Where(claim => claim.Type == Constants.Auth.Claims.Permission && (prefix == null || claim.Value.StartsWith(prefix))) .Select(claim => Permission.FromClaim(claim, prefix)) .ToList(); } /// public Permission GetPermission(string key = null) { Claim claim = Principal.Claims.FirstOrDefault(claim => claim.Type == Constants.Auth.Claims.Permission && claim.Value.StartsWith(key + ":")); return Permission.FromClaim(claim); } /// public async Task Login(string email, string password, bool isPersistent) { EntityResult result = new EntityResult(); User user = await SignInManager.UserManager.FindByNameAsync(email); if (user == null) { result.AddError("@login.errors.wrongcredentials"); return result; } // TODO probably move this logic into a custom SignInManager which overrides CanSignInAsync() // see https://stackoverflow.com/a/35484758/670860 else if (!user.IsActive) { result.AddError("@login.errors.disabled"); return result; } SignInResult signInResult = await SignInManager.PasswordSignInAsync(email, password, isPersistent, true); if (!signInResult.Succeeded) { if (signInResult.IsLockedOut) { result.AddError("@login.errors.lockedout"); } else if (signInResult.IsNotAllowed) { result.AddError("@login.errors.notallowed"); } else if (signInResult.RequiresTwoFactor) { result.AddError("@login.errors.requirestwofactor"); } else { result.AddError("@login.errors.wrongcredentials"); } return result; } return EntityResult.Success(); } /// public async Task Logout() { await SignInManager.SignOutAsync(); } /// public string GetUserId() { ClaimsPrincipal principal = HttpContextAccessor.HttpContext.User; return principal.Claims.FirstOrDefault(x => x.Type == Constants.Auth.Claims.UserId)?.Value; } } public interface IAuthenticationApi { /// /// Get currently logged-in user /// Task GetUser(); /// /// Whether a user is currently logged-in /// bool IsLoggedIn(); /// /// Whether the current user is the super user who created the zero instance /// bool IsSuper(); /// /// Whether the current user belongs to the administrator role (will always return false if this role gets deleted) /// bool IsAdmin(); /// /// Logs a zero-user in and sets cookie /// Task Login(string email, string password, bool isPersistent); /// /// Logs out the current user /// Task Logout(); /// /// Get the ID of the currently logged in user /// string GetUserId(); /// /// Get all permissions for the current user with an optional prefix /// IList GetPermissions(string prefix = null); /// /// Get a single permissions by key /// public Permission GetPermission(string key = null); } }