14

I created an asp.net core project in visual studio 2015 with windows authentication. I can't figure out how to add roles to the Identity.

I have a table with usernames for the windows account. And when the user opens the website the user is added to the Identity (I assume that's what happens, because I can display the username by User.Identity.Name) and I want to pull out Roles from another table and assign them to the user, is this possible? Or perhaps is there a better way to do it? (Why?, How?)

I couldn't find any examples specific examples related to windows authentication, but I have read the documentation and went through this guide. And I'm still stuck.

Anton Toshik
  • 1,881
  • 2
  • 14
  • 33
  • can you show your code including your using statements. Im guessing at this stage youve not references `System.DirectoryServices` at the moment. When you do this you can get the AD information with relative ease – Simon Price Oct 23 '16 at 20:16
  • @SimonPrice I have no code to show sorry, I scrapped my every attempt because it didn't work. But to give you an idea it's just a new project with windows authentication enabled, and from there it's just me suffering and failing miserably. I will definitely look up 'System.DirectoryServices', also what is AD? – Anton Toshik Oct 23 '16 at 20:28
  • AD is Active Directory. What is the idea of the project that youre trying to achieve? – Simon Price Oct 23 '16 at 20:30
  • @SimonPrice If a company employs like 100 people, and they look after their windows accounts (status/information/etc..). Having a separate account for internally used website/application would be a bad solution for them. So I am looking if it's viable to just use the windows accounts, and apply roles to them. And what actual information I can grab form the account they connect with. I am new to web dev, so everything is very confusing still. – Anton Toshik Oct 23 '16 at 20:41
  • come and chat to me here http://chat.stackoverflow.com/rooms/126473/windows-auth – Simon Price Oct 23 '16 at 20:43
  • @SimonPrice sorry to drop a comment but I can't write messages in the chat room :D you need to grant me permission – Anton Toshik Oct 24 '16 at 19:23
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/126551/discussion-between-anton-toshik-and-simon-price). – Anton Toshik Oct 24 '16 at 19:29

3 Answers3

11

With Windows Authentication the roles come from Active Directory, not a database.

You could use Claims Transformation to change the inbound identity on every request to pull extra roles from your database.

public class ClaimsTransformer : IClaimsTransformer
{
    public Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
    {
        ((ClaimsIdentity)principal.Identity).AddClaim(
            new Claim("ExampleClaim", "true"));
        return Task.FromResult(principal);
    }
}

And then wire it up with

app.UseClaimsTransformation(new ClaimsTransformationOptions
{
    Transformer = new ClaimsTransformer()
});

Note that in the current incarnation there's no DI support, so you'll have to manually pull out your database information from DI if that's where it is.

blowdart
  • 52,422
  • 11
  • 102
  • 145
7

this is working code that I use to check is a user is in a role \ group, please use it at your leisure

using System.Collections.Generic;
using System.DirectoryServices.AccountManagement;
using System.Linq;
using System.Security.Principal;

namespace Santander.IsUserInGroupOrRole_cs
{

public class IsUserInRole
{
    public static bool IsInGroup(string groupName)
    {
        var myIdentity = GetUserIdWithDomain();
        var myPrincipal = new WindowsPrincipal(myIdentity);
        return myPrincipal.IsInRole(groupName);
    }

    public bool IsInGroup(List<string> groupNames)
    {
        var myIdentity = GetUserIdWithDomain();
        var myPrincipal = new WindowsPrincipal(myIdentity);

        return groupNames.Any(group => myPrincipal.IsInRole(group));
    }

    public static WindowsIdentity GetUserIdWithDomain()
    {
        var myIdentity = WindowsIdentity.GetCurrent();
        return myIdentity;
    }

    public static string GetUserId()
    {
        var id = GetUserIdWithDomain().Name.Split('\\');
        return id[1];
    }

    public static string GetUserDisplayName()
    {
        var id = GetUserIdWithDomain().Name.Split('\\');

        var dc = new PrincipalContext(ContextType.Domain, id[0]);
        var adUser = UserPrincipal.FindByIdentity(dc, id[1]);
        return adUser.DisplayName;

    }
}
}
spottedmahn
  • 11,379
  • 7
  • 75
  • 144
Simon Price
  • 2,489
  • 1
  • 24
  • 66
4

For anyone interested, here is a simple example of how you can inject an EF DBContext into a custom ClaimsTransformer and add some custom role claims.

Startup.cs

public void ConfigureServices(IServiceCollection services)
{
  services.AddScoped<IClaimsTransformer, MyClaimsTransformer>();

  services.AddMvc();

  services.AddDbContext<MyDbContext>(options => options.UseSqlServer(
      Configuration.GetConnectionString("MyConnStringSetting")
    ));

  (...)
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
  app.UseClaimsTransformation(context =>
  {
    var transformer = context.Context.RequestServices.GetRequiredService<IClaimsTransformer>();
    return transformer.TransformAsync(context);
  });

  (...)
}

MyClaimsTransformer.cs

public class MyClaimsTransformer : IClaimsTransformer
{
  private readonly MyDbContext _context;

  public MyClaimsTransformer(MyDbContext context)
  {
    _context = context;
  }

  public Task<ClaimsPrincipal> TransformAsync(ClaimsTransformationContext context)
  {
    var identity = (ClaimsIdentity)context.Principal.Identity;
    var userName = identity.Name;
    var roles = _context.Role.Where(r => r.UserRole.Any(u => u.User.Username == userName)).Select(r => r.Name);
    foreach (var role in roles)
    {
      var claim = new Claim(ClaimTypes.Role, role);
      identity.AddClaim(claim);
    }
    return Task.FromResult(context.Principal);
  }
}
DanO
  • 832
  • 1
  • 7
  • 15