Comment utiliser Windows Active Directory Authentication and Identity Based Claims?

Problème

Nous voulons utiliser Windows Active Directory pour authentifier un utilisateur dans l'application. Cependant, nous ne voulons pas utiliser les groupes Active Directory pour gérer l'autorisation des controllers/views.

<!-Pour autant que je sache, il n'y a pas de moyen facile de marier la publicité et les allégations fondées sur l'identité.

buts

  • authentifier les utilisateurs avec le répertoire actif local
  • utiliser le cadre D'identité pour gérer les réclamations

Tentatives (Échoue)

  • Windows.Owin.Sécurité.ActiveDirectory-Doh. C'est pour Azure AD. Pas de support de LDAP. Ils auraient pu l'appeler AzureActiveDirectory à la place?
  • authentification Windows - C'est d'accord avec L'authentification NTLM ou Keberos. Les problèmes commencent avec: i) les jetons et les revendications sont tous gérés par AD et je ne peux pas comprendre comment utiliser les revendications d'identité avec elle.
  • LDAP-mais ceux-ci semblent me forcer à faire manuellement les formulaires d'authentification pour utiliser des revendications d'identité? Il doit sûrement y avoir un moyen plus facile?

Toute aide serait plus apprécié. Cela fait longtemps que je m'occupe de ce problème et j'apprécierais une contribution extérieure à ce sujet.

26
demandé sur hlyates 2015-03-06 00:24:08

5 réponses

Chaussure de votre solution ci-dessus m'a poussé vers une direction qui a fonctionné pour moi sur MVC6-Beta3 Identityframework7-Beta3 EntityFramework7-Beta3:

// POST: /Account/Login
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null)
{
    if (!ModelState.IsValid)
    {
        return View(model);
    }

    //
    // Check for user existance in Identity Framework
    //
    ApplicationUser applicationUser = await _userManager.FindByNameAsync(model.eID);
    if (applicationUser == null)
    {
        ModelState.AddModelError("", "Invalid username");
        return View(model);
    }

    //
    // Authenticate user credentials against Active Directory
    //
    bool isAuthenticated = await Authentication.ValidateCredentialsAsync(
        _applicationSettings.Options.DomainController, 
        _applicationSettings.Options.DomainControllerSslPort, 
        model.eID, model.Password);
    if (isAuthenticated == false)
    {
        ModelState.AddModelError("", "Invalid username or password.");
        return View(model);
    }

    //
    // Signing the user step 1.
    //
    IdentityResult identityResult 
        = await _userManager.CreateAsync(
            applicationUser, 
            cancellationToken: Context.RequestAborted);

    if(identityResult != IdentityResult.Success)
    {
        foreach (IdentityError error in identityResult.Errors)
        {
            ModelState.AddModelError("", error.Description);
        }
        return View(model);
    }

    //
    // Signing the user step 2.
    //
    await _signInManager.SignInAsync(applicationUser,
        isPersistent: false,
        authenticationMethod:null,
        cancellationToken: Context.RequestAborted);

    return RedirectToLocal(returnUrl);
}
1
répondu Will 2018-01-02 20:18:00

il suffit de cliquer sur AD avec le nom d'utilisateur et le mot de passe au lieu de s'authentifier contre votre DB

// POST: /Account/Login
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
    if (ModelState.IsValid)
    {
        var user = await UserManager.FindByNameAsync(model.UserName);
        if (user != null && AuthenticateAD(model.UserName, model.Password))
        {
            await SignInAsync(user, model.RememberMe);
            return RedirectToLocal(returnUrl);
        }
        else
        {
            ModelState.AddModelError("", "Invalid username or password.");
        }
    }
    return View(model);
}

public bool AuthenticateAD(string username, string password)
{
    using(var context = new PrincipalContext(ContextType.Domain, "MYDOMAIN"))
    {
        return context.ValidateCredentials(username, password);
    }
}
17
répondu Shoe 2018-01-02 20:21:55

sur ASPNET5 (beta6), l'idée est d'utiliser CookieAuthentication et Identity : vous aurez besoin d'ajouter dans votre classe de démarrage:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();
    services.AddAuthorization();
    services.AddIdentity<MyUser, MyRole>()
        .AddUserStore<MyUserStore<MyUser>>()
        .AddRoleStore<MyRoleStore<MyRole>>()
        .AddUserManager<MyUserManager>()
        .AddDefaultTokenProviders();
}

Dans la section configurer, ajouter:

private void ConfigureAuth(IApplicationBuilder app)
{
    // Use Microsoft.AspNet.Identity & Cookie authentication
    app.UseIdentity();
    app.UseCookieAuthentication(options =>
    {
        options.AutomaticAuthentication = true;
        options.LoginPath = new PathString("/App/Login");
    });
}

Ensuite, vous aurez besoin de mettre en place:

Microsoft.AspNet.Identity.IUserStore
Microsoft.AspNet.Identity.IRoleStore
Microsoft.AspNet.Identity.IUserClaimsPrincipalFactory

et étendre/remplacer:

Microsoft.AspNet.Identity.UserManager
Microsoft.AspNet.Identity.SignInManager

j'ai en fait mis en place un exemple de projet pour montrer comment cela peut être fait. Github Link.

j'ai testé sur le beta8 et et avec quelques petites adaptatons (comme Context = > HttpContext) cela a fonctionné aussi.

4
répondu jesblit 2018-01-02 20:30:57

vous pourriez utiliser ClaimTransformation, je viens de le faire travailler cet après-midi en utilisant l'article et le code ci-dessous. Je suis en train d'accéder à une application avec une authentification de fenêtre et puis d'ajouter des revendications basées sur les permissions stockées dans une base de données SQL. C'est un bon article qui devrait vous aider.

https://github.com/aspnet/Security/issues/863

En résumé ...

services.AddScoped<IClaimsTransformer, ClaimsTransformer>();

app.UseClaimsTransformation(async (context) =>
{
IClaimsTransformer transformer = context.Context.RequestServices.GetRequiredService<IClaimsTransformer>();
return await transformer.TransformAsync(context);
});

public class ClaimsTransformer : IClaimsTransformer
    {
        private readonly DbContext _context;

        public ClaimsTransformer(DbContext dbContext)
        {
            _context = dbContext;
        }
        public async Task<ClaimsPrincipal> TransformAsync(ClaimsTransformationContext context)
        {

            System.Security.Principal.WindowsIdentity windowsIdentity = null;

            foreach (var i in context.Principal.Identities)
            {
                //windows token
                if (i.GetType() == typeof(System.Security.Principal.WindowsIdentity))
                {
                    windowsIdentity = (System.Security.Principal.WindowsIdentity)i;
                }
            }

            if (windowsIdentity != null)
            {
                //find user in database by username
                var username = windowsIdentity.Name.Remove(0, 6);
                var appUser = _context.User.FirstOrDefault(m => m.Username == username);

                if (appUser != null)
                {

                    ((ClaimsIdentity)context.Principal.Identity).AddClaim(new Claim("Id", Convert.ToString(appUser.Id)));

                    /*//add all claims from security profile
                    foreach (var p in appUser.Id)
                    {
                        ((ClaimsIdentity)context.Principal.Identity).AddClaim(new Claim(p.Permission, "true"));
                    }*/

                }

            }
            return await System.Threading.Tasks.Task.FromResult(context.Principal);
        }
    }
3
répondu K7Buoy 2016-10-28 14:39:47

savez-vous comment mettre en œuvre un custom System.Web.Security.MembershipProvider? Vous devriez pouvoir utiliser ceci (override ValidateUser) en conjonction avec System.DirectoryServices.AccountManagement.PrincipalContext.ValidateCredentials() pour s'authentifier contre active directory.

essayer: var pc = new PrincipalContext(ContextType.Domain, "example.com", "DC=example,DC=com"); pc.ValidateCredentials(username, password);

1
répondu rybl 2015-03-05 21:52:56