Search code examples
asp.net-coreauthorizationwindows-authenticationiis-express

Authorization with windows authentication in ASP.NET Core 3.1


As I understand there is a way to retrieve group where user belong. For example Admins, Users etc.

After doing that I want to transform this into claims. I cannot find how I can retrieve a user's groups.

Currently I am using my local user and not (Domain Active Directory).

Is there any solutions for that issue?

Is it a good approach or it is better to retrieve permissions for each user from the database and then operate with them?


Solution

  • you need to know is that AD is working on windows host only. read Microsoft docs before you start project

    add startup configuration , create login page

    services
    .AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
                 .AddCookie(options =>
                 {
                    options.LoginPath = "/Login";
                 });
    .....
    
    app.UseAuthentication();
    app.UseAuthorization();
    
    

    third your needs:

    1. your AD domain : yourdomain.com
    2. your ldap url example: LDAP://DC.yourdomain.com
    3. some knowledge about ldap query string

    application.json config:

    "ldap": {
        "path": "LDAP://DC.yourdomain.com",
        "domain": "yourdomain.com",
        "personFilter": "(SAMAccountName={username})",
        "groupFilter": "(&(objectCategory=person)(objectClass=user)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))",
        //"property": "cn,displayName,mail,givenName,sn,o,title,company,department,telephoneNumber,description,userPrincipalName",
        "property": "cn,displayName,mail,givenName,sn,o,title,company,department"
        //"property": "cn,member,memberof,sAMAccountName,primaryGroupToken"
    }
    

    and you can use this method to check username and password

    public Dictionary<string, string> UserInfo { get; private set; }
    public bool IsAuthenticated(string username, string password)
            {
                bool result = false;
    
    
                string domainAndUsername = Configuration["ldap:domain"] + @"\" + username;
                DirectoryEntry entry = new DirectoryEntry(Configuration["ldap:path"], domainAndUsername, password);
                try
                {
                    Object obj = entry.NativeObject;
                    DirectorySearcher search = new DirectorySearcher(entry);
                    search.Filter = Configuration["ldap:personFilter"].Replace("{username}", username);
    
                    var propList = Configuration["ldap:property"].Split(',');
                    search.PropertiesToLoad.AddRange(propList);
    
                    SearchResult searchResult = search.FindOne();
                    if (null == searchResult)
                    {
                        return false;
                    }
    
                    foreach (var propName in propList)
                    {
                        UserInfo.Add(propName, GetProperty(searchResult.Properties, propName));
                    }
    
                    DirectoryEntry obUser = new DirectoryEntry(searchResult.Path);
                    object obGroups = obUser.Invoke("Groups");
                    var groupList = new List<string>();
                    foreach (object ob in (IEnumerable)obGroups)
                    {
                        DirectoryEntry obGpEntry = new DirectoryEntry(ob);
                        groupList.Add(obGpEntry.Name);
                    }
    
                    UserInfo.Add("group", string.Join(",", groupList));
                    result = true;
                }
                catch (Exception ex)
                {
                    throw new SysAuthException("Invalid Authentication", ex);
                }
    
                return result;
            }
    

    when login success you can check all user info from userInfo property

    sample code for login page (add claim and login state to net core pipeline):

        try
                {
                    if (Authentication.IsAuthenticated(UserData.Username, UserData.Password))
                    {
                        var claims = new List<Claim>() {
                            new Claim(ClaimTypes.Name, UserData.Username)
                        };
    
                        foreach (var item in Authentication.UserInfo)
                        {
                            claims.Add(new Claim(item.Key, item.Value));
                        }
    
                        var identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
                        var principal = new ClaimsPrincipal(identity);
    
                        await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal, new AuthenticationProperties()
                        {
                            IsPersistent = UserData.RememberLogin
                        });
    
                        if (!string.IsNullOrEmpty(UserData.ReturnUrl))
                            return LocalRedirect(UserData.ReturnUrl);
                        return Redirect("/");
                    }
                }
                catch (SysAuthException ex)
                {
                    Error = ex.InnerException.Message;
                }
    

    if you need to protect your page add @attribute [Authorize] in top of your page also you can check other claim for example roles or group with this attribute

    sample code show current user info

        <div>
        <table class="table table-bordered table-striped">
            <caption>Current User Info</caption>
            @foreach (var claim in User.Claims)
            {
                <tr><td>@claim.Type</td><td>@claim.Value</td></tr>
            }
        </table>
    </div>