Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Windows Authentication Asp.net core 2 database role authorization

I am working on an intranet application that will use Asp.Net Core 2.1 and Windows authentication. I am getting the pass through from IIS just fine, but I want to use roles stored in a database for the authorization.

I have an IClaimsTransformeration class that gets the roles from a database based on the LAN Id and adds them to the claims list with the role key.

public class MyClaimsTransformer : IClaimsTransformation
{
    private readonly IUnitOfWorkMtuSecurity _unitOfWork;

    public MyClaimsTransformer(IUnitOfWorkMtuSecurity unitOfWork)
    {
        _unitOfWork = unitOfWork;
    }

    // Each time HttpContext.AuthenticateAsync() or HttpContext.SignInAsync(...) is called the claims transformer is invoked. So this might be invoked multiple times. 
    public async Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
    {
        var identity = principal.Identities.FirstOrDefault(x => x.IsAuthenticated);
        if (identity == null) return principal;

        //var user = await _userManager.GetUserAsync(principal);
        var user = identity.Name;
        if (user == null) return principal;

        //Get user with roles from repository.
        var dbUser = _unitOfWork.UserInformations.GetUserWithRoles(user);

        // Inject DbRoles into Claims list
        foreach (var role in dbUser.UserInformationUserRoles.Select((r=>r.UserRole)))
        {
            var claim = new Claim(ClaimTypes.Role, role.Name);
            identity.AddClaim(claim);
        }

        return new ClaimsPrincipal(identity);
    }  
}

I added the IClaimsTransformation to my services in the startup.cs

services.AddScoped<IClaimsTransformation, MyClaimsTransformer>();

Then I added the attribute to my controller

[Authorize(Roles = "Administrator")]

When I run my application I get the following error:

An unhandled exception occurred while processing the request. InvalidOperationException: No authenticationScheme was specified, and there was no DefaultForbidScheme found. Microsoft.AspNetCore.Authentication.AuthenticationService.ForbidAsync(HttpContext context, string scheme, AuthenticationProperties properties)

In the startup.cs I added the following to the services

services.AddAuthentication(IISDefaults.AuthenticationScheme);

This got rid of the error, but no matter what I get a 403 error.

You don't have authorization to view this page. HTTP ERROR 403

When I watch the return value from MyClaimsTransformer, I can see the role of administrator has been added to the list of claims, but no matter what I get a 403 error.

Does anyone have a suggestion for what I am missing?

If I use the following syntax in my view it works at the view level:

 @if (User.HasClaim("http://schemas.microsoft.com/ws/2008/06/identity/claims/role", "Administrator"))
                    {
                <li><a asp-area="" asp-controller="UserInformationAdmin" asp-action="Index">Admin</a></li>
                     } 

I have to specify the entire schema url though.

like image 850
Jim Karnopp Avatar asked Jun 07 '18 20:06

Jim Karnopp


People also ask

How do you implement Windows Authentication How do you specify roles and permissions to the users?

To set up your ASP.NET application to work with Windows-based authentication, begin by creating some users and groups. Within your Windows operating system, go to "Control Panel" -> "User Accounts" -> "Manage another account" -> "Create a new account" then choose "Add or Remove User".

How can I get a users role from DB to populate the Authorizeattribute?

You need to specify which role for this method. Get all roles from db, Check if list of Roles on Authorize attribute exists on the list from db, if they exist populate them to the authorize attribute . confused. what do you mean by Check if list of Roles on Authorize attribute exists on the list from db .


1 Answers

The ClaimIdentity had a RoleClaimType of "http://schemas.microsoft.com/ws/2008/06/identity/claims/groupsid"

and it needed to be a RoleClaimType of "http://schemas.microsoft.com/ws/2008/06/identity/claims/role"

Since this is a readonly property, I changed the TransformAsync method to create a new ClaimsPrincipal instead of trying to add database roles to the existing claims. My application doesn't require any of the AD groups, so it only uses windows for Authentication. The code below seems to work.

public class MyClaimsTransformer : IClaimsTransformation
{
    private readonly IUnitOfWorkSecurity _unitOfWork;

    public MyClaimsTransformer(IUnitOfWorkSecurity unitOfWork)
    {
        _unitOfWork = unitOfWork;
    }

    // Each time HttpContext.AuthenticateAsync() or HttpContext.SignInAsync(...) is called the claims transformer is invoked. So this might be invoked multiple times. 
    public async Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
    {
        var identity = principal.Identities.FirstOrDefault(x => x.IsAuthenticated);
        if (identity == null) return principal;

        var user = identity.Name;
        if (user == null) return principal;

        //Get user with roles from repository.
        var dbUser = _unitOfWork.UserInformations.GetUserWithRoles(user);

        var claims = new List<Claim>();

        //The claim identity uses a claim with the claim type below to determine the name property.
        claims.Add(new Claim(@"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name", user, "Name"));

        //todo: We should probably create a cache for this
        // Get User Roles from database and add to list of claims.
        foreach (var role in dbUser.UserInformationUserRoles.Select((r=>r.UserRole)))
        {
            claims.Add(new Claim(ClaimTypes.Role, role.Name));
        }

        var newClaimsIdentity = new ClaimsIdentity(claims,"Kerberos","", "http://schemas.microsoft.com/ws/2008/06/identity/claims/role");

        var newClaimsPrincipal = new ClaimsPrincipal(newClaimsIdentity);

        return new ClaimsPrincipal(newClaimsPrincipal);
    }  
}
like image 191
Jim Karnopp Avatar answered Sep 27 '22 17:09

Jim Karnopp