Подтвердить что ты не робот

Как использовать аутентификацию Windows Active Directory и заявления на основе идентификации?

Проблема

Мы хотим использовать Windows Active Directory для аутентификации пользователя в приложении. Однако мы не хотим использовать группы Active Directory для управления авторизацией контроллеров/представлений.

Насколько я знаю, нет простого способа выйти замуж за AD и заявления на основе идентичности.

Цели

  • Аутентификация пользователей с локальной Active Directory
  • Использование структуры Identity для управления претензиями

Попытки (сбой)

  • Windows.Owin.Security.ActiveDirectory - Doh. Это для Azure AD. Нет поддержки LDAP. Могут ли они назвать это AzureActiveDirectory?
  • Аутентификация Windows - это нормально с проверкой подлинности NTLM или Keberos. Проблемы начинаются с: i) токенов и претензий управляет AD, и я не могу понять, как использовать с ним требования идентификации.
  • LDAP. Но, похоже, они заставляют меня вручную выполнять проверку подлинности форм, чтобы использовать требования идентификации? Разумеется, должен быть более простой способ?

Любая помощь будет более чем оценена. Я давно застрял в этой проблеме и был бы благодарен за внешний вклад в этом вопросе.

4b9b3361

Ответ 1

Обувь вашего решения выше подтолкнула меня к направлению, которое сработало для меня на 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);
}

Ответ 2

Просто нажмите AD с именем пользователя и паролем вместо проверки подлинности вашей БД

// 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);
    }
}

Ответ 3

В ASPNET5 (бета6) идея состоит в использовании CookieAuthentication и Identity: вам нужно добавить в свой класс Startup:

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

В разделе конфигурации добавьте:

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");
    });
}

Затем вам необходимо реализовать:

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

и продлить/переопределить:

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

На самом деле я установил образец проекта, чтобы показать, как это можно сделать. ссылка GitHub.

Я тестировал на бета-версии 8 и с некоторыми небольшими адаптациями (например, Context = > HttpContext), он тоже работал.

Ответ 4

Вы можете использовать ClaimTransformation, я только что получил работу сегодня днем, используя статью и код ниже. Я обращаюсь к приложению с помощью проверки подлинности Windows, а затем добавляю заявки на основе разрешений, хранящихся в базе данных SQL. Это хорошая статья, которая должна помочь вам.

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

Вкратце...

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);
        }
    }

Ответ 5

Вы знаете, как реализовать пользовательский System.Web.Security.MembershipProvider? Вы должны иметь возможность использовать это (переопределить ValidateUser) в сочетании с System.DirectoryServices.AccountManagement.PrincipalContext.ValidateCredentials() для аутентификации против активного каталога.

попробовать: var pc = new PrincipalContext(ContextType.Domain, "example.com", "DC=example,DC=com"); pc.ValidateCredentials(username, password);