I have setup my application which uses Identity for role access on the site.

I am switching over from Windows Authentication with custom claims transformer to using LDAP so that the users will have a login page unlike with the "javascript alert like" windows authentication pop up in chrome.

The issue is that even though I find the user within LDAP to login in as well as finding users with roles in the application it still does not log them in. The SignInAsync function executes without any issues but on redirect still shows not signed in. Is there something wrong with my CookieAuthentication Setup or am I wrong. The _LoginPartial still shows Login as well.

My current setup is :

ConfigureServices

        services.AddIdentity<User, Role>(options =>
        {
            options.User.AllowedUserNameCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_\\";
        }).AddEntityFrameworkStores<VIPADBContext>();

        services.ConfigureApplicationCookie(options =>
        {
            options.AccessDeniedPath = "/UserAccounts/AccessDenied";
            options.Cookie.Name = CookieAuthenticationDefaults.AuthenticationScheme;
            options.ExpireTimeSpan = TimeSpan.FromMinutes(60);
            options.LoginPath = "/UserAccounts/Login";
            options.SlidingExpiration = true;
        });

        services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
            .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
            {
                options.LoginPath = "UserAccounts/Login";
            });

Configure

        app.UseStaticFiles();

        app.UseAuthentication();

        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: "{controller=Home}/{action=Index}/{id?}");

        });

        app.UseCookiePolicy();

Custom SignInManager

    public class SignInManager : ISignInManager
{
    private readonly IHttpContextAccessor _httpContextAccessor;

    public SignInManager(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }

    public async Task SignInAsync(User user, IList<string> roleNames)
    {
        var claims = new List<Claim>
        {
            new Claim(ClaimTypes.Sid, user.Id.ToString()),
            new Claim(ClaimTypes.Name, user.UserName),
        };

        foreach (string roleName in roleNames)
        {
            claims.Add(new Claim(ClaimTypes.Role, roleName));
        }

        var identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
        var principal = new ClaimsPrincipal(identity);

        await _httpContextAccessor.HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal);
    }

    public async Task SignOutAsync()
    {
        await _httpContextAccessor.HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
    }
}

UserAccountsController with Login and Logout

    [HttpPost]
    [AllowAnonymous]
    public async Task<IActionResult> Login(LoginViewModel model)
    {
        if (ModelState.IsValid)
        {
            try
            {
                var user = _authService.Login(model.Username, model.Password);
                if (user != null)
                {
                    //var userClaims = new List<Claim>
                    //{
                    //   new Claim(ClaimTypes.Name, user.UserName)
                    //};
                    User currentUser = _context.Users.FirstOrDefault(u => u.Logon.Equals(model.Username, StringComparison.CurrentCultureIgnoreCase));
                    if (currentUser != null)
                    {
                        var userRolesNames = _context.Roles.Join(_context.UserRoles.Where(p => p.UserId == currentUser.Id), roles => roles.Id, userRoles => userRoles.RoleId, (roles, userRoles) => roles).Select(roles => roles.Name).ToList();

                        await _signInManager.SignInAsync(currentUser, userRolesNames);
                        return Redirect("/Home/Index");
                    }

                    List<string> rolesList = null;
                    //var principal = new ClaimsPrincipal(new ClaimsIdentity(userClaims, "Identity.Application"));
                    await _signInManager.SignInAsync(currentUser, rolesList);

                    return Redirect("/Home/Index");
                }
            }
            catch (Exception ex)
            {
                ModelState.AddModelError(string.Empty, ex.Message);
            }
        }
        return View(model);
    }

    [Authorize(Roles = "Admin")]
    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task SignOut()
    {
        await MyCustomSignOut("/Home/Index");
    }


    public async Task MyCustomSignOut(string redirectUri)
    {
        // inject the HttpContextAccessor to get "context"
        await _signInManager.SignOutAsync();
        var prop = new AuthenticationProperties()
        {
            RedirectUri = redirectUri
        };
        // after signout this will redirect to your provided target
        await _httpContextAccessor.HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme, prop);
    }
}

_LoginPartial

<ul class="navbar-nav">
@if (User.Identity.IsAuthenticated)
{
    <li class="nav-item">
        <a>@User.Identity.Name</a>
    </li>
    <li class="nav-item">
        <form method="post" asp-controller="UserAccounts" asp-action="SignOut">
            <input type="submit" class="btn btn-primary" value="Logout" />
        </form>
    </li>
}
else
{
    <li class="dropdown nav-item">
        <a asp-controller="UserAccounts" asp-action="Login">Login</a>
    </li>

}

1 Answers

0
user2806570 On

Turns out most of the code is correct. The only amendment I needed to make was the below.

services.AddAuthentication(options =>
        {
            options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        })
        .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
        {
            options.LoginPath = new PathString("/UserAccounts/Login");
            options.AccessDeniedPath = new PathString("/UserAccounts/AccessDenied");
        });

For some reason I had to declare all the various authentication scheme options even though they are all the same in my application.