Аутентификация Windows - требуется дополнительный пароль для специальных пользователей - PullRequest
12 голосов
/ 06 мая 2019

Я занимаюсь разработкой основного веб-API-приложения asp.net для внутренней сети.Требования к аутентификации:

  • REQ1 - когда пользователь, пытающийся получить доступ к сайту, не входит в специальную группу Active Directory (назовем его «commonUsers»), он просто не авторизован
  • REQ2 - когда пользователь, пытающийся получить доступ к веб-сайту, находится в группе Active Directory, «commonUsers» авторизован, и веб-ресурс возвращается
  • REQ3 - когда пользователь, пытающийся получить доступ к веб-сайту, находится в ActiveГруппа каталогов "superUser", необходимо еще раз запросить пароль своего домена (потому что он пытается получить доступ к некоторым очень ограниченным ресурсам)

Теперь, что у меня есть:

  • Моя служба размещена на сервере http.sys для поддержки проверки подлинности Windows.
  • Я использую промежуточный преобразователь утверждений для проверки группы Active Directory пользователя, скажем, что-то вроде этого:

    public class ClaimsTransformer : IClaimsTransformation {
    private readonly IAuthorizationService _authorizationService;
    public ClaimsTransformer(IAuthorizationService authorizationService)
    {
        _authorizationService = authorizationService;
    }
    
    public Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
    {
        _authorizationService.Authorize(principal as  IHmiClaimsPrincipal);
        return Task.FromResult(principal);
    }}
    
  • Я указалспециальные политики также в моей конфигурации службы, например что-то вроде этого:

    services.AddAuthorization(options =>
        {
            options.AddPolicy("TestPolicy", policy => 
                                       policy.RequireClaim(ClaimTypes.Role, "TestUser"));
            options.AddPolicy("TestPolicy2", policy => 
                                       policy.RequireClaim(ClaimTypes.Role, "SuperUser"));
        });
  • Я использую атрибут [Authorize] с определенной политикой, чтобы ограничить доступ к определенным ресурсам на основе политик

Теперь вопрос, как мне удовлетворить REQ3?

Ответы [ 3 ]

2 голосов
/ 20 мая 2019

Думаю, я бы попытался использовать фильтры MVC: https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/filters?view=aspnetcore-2.2#authorization-filters

Фильтры запускаются после всех промежуточных программ, но перед действием.Это позволит вам контролировать перенаправление на страницу учетных данных только для определенных действий или контроллеров.Хотя обычно это не рекомендуемый метод авторизации, я думаю, что он соответствует вашим требованиям для гибридной вторичной аутентификации.

public class SuperUserFilter : Attribute, IAuthorizationFilter
{
    public void OnAuthorization(AuthorizationFilterContext context)
    {
        if (context.HttpContext.Request.Cookies.TryGetValue("SuperUserCookie", out string cookieVal))
        {
            if (!IsValidCookie(cookieVal))
                context.Result = LoginPage(context);

        }
        else
        {
            context.Result = LoginPage(context);
        }
    }

    private bool IsValidCookie(string cookieVal)
    {
        //validate cookie value somehow
        // crytpographic hash, store value in session, whatever
        return true;
    }

    private ActionResult LoginPage(AuthorizationFilterContext context)
    {
        return new RedirectToActionResult("SuperUser", "Login",
            new {redirectUrl = context.HttpContext.Request.GetEncodedUrl()});
    }
}

Затем вы создаете контроллер входа

public class LoginController : Controller
{    
    [HttpGet]    
    public IActionResult SuperUser(string redirectUrl)
    {
        // return a page to enter credentials
        // Include redirectUrl as field
    }

    [HttpPost]
    public IActionResult SuperUser(LoginData loginData)
    {
        // Validate User & Password
        Response.Cookies.Append("SuperUserCookie", "SomeValue");
        return Redirect(loginData.RedirectUrl);
    }
}

Затем вы можетеоформить конкретные действия (или контроллеры), как требуется:

public class MyController : Controller
{
    [HttpGet]
    [SuperUserFilter]
    public IActionResult MySensitiveAction()
    {
        // Do something sensitive
    }
}
0 голосов
/ 17 мая 2019

Я думаю, что, по моему мнению, вам следует рассмотреть возможность использования: авторизации на основе политик с требованиями, в основном у вас есть разные требования авторизации, к которым вы хотите их применять, и на основе AND

REQ1 и REQ2 и REQ3

Здесь у вас есть ссылка на документацию: Требования

Но вам нужно понять эту идентичность! = Разрешения, ребята, которые представляют эту концепцию политик Microsoft, создали проект под названием: PolicyServer и это с открытым исходным кодом: PolicyServer Git , и они создали там образец того, как вы должны использовать свои политики.По сути, у вас есть внешние и внутренние пользователи, прошедшие проверку подлинности в вашей AD, все внутренние пользователи должны иметь разрешения, назначенные роли.И вы только украшаете свое действие контроллера тем правилом разрешений, которое вы создали для этой политики

[Authorize("PerformSurgery")]
public async Task<IActionResult> PerformSurgery()
{
    // omitted
}

Чтобы понять код и то, как они оценивают политику, я думаю, вы должны увидеть видео, которое они имеют онлайн на веб-сайте: Сервер политики

Надеюсь, это поможет

0 голосов
/ 16 мая 2019

Я предполагаю, что вы пытаетесь реализовать двухэтапную аутентификацию для some of your resource.
. Для этого вам нужно использовать несколько authentication scheme и Authorize policies, но это сложно, потому что аутентификация Windows не контролируется.нам нужно использовать некоторую хитрость, чтобы узнать, что это ваш второй логин.

аутентификация

  1. Схема аутентификации по умолчанию: Windows, это базовая схема для аутентификации пользователя Windows.
  2. Вторая Cookies базовая схема аутентификации: SuperUserTwoStep.нам нужно это, чтобы перейти к нашей пользовательской логике входа в систему.

Авторизовать

  1. Authorize policies для указанной схемы.
  2. страницу входа для входа в систему *Схема 1024 *.
//startup
            services.AddAuthentication(HttpSysDefaults.AuthenticationScheme)
                .AddCookie("SuperUserTwoStep",op=>op.LoginPath = "/account/superuser2steplogin");

            services.AddAuthorization(op =>
            {
                op.AddPolicy("SuperUser", b => b.AddAuthenticationSchemes("SuperUserTwoStep")
                    .RequireAuthenticatedUser()
                    .RequireClaim(ClaimTypes.Role, "SuperUser"));
            });

// login 
        public static IDictionary<string, string> States { get; set; } = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

        [Route("/account/superuser2steplogin")]
        public async Task<IActionResult> LoginTwoStepConfirm(string returnUrl, [FromServices]IAuthorizationService authorizationService,
            [FromServices]IAuthorizationPolicyProvider policyProvider)
        {

            var winresult = await HttpContext.AuthenticateAsync(IISDefaults.AuthenticationScheme);
            if (winresult.Succeeded)
            {
                if (States.TryGetValue(winresult.Principal.Identity.Name, out _))
                {
                    States.Remove(winresult.Principal.Identity.Name);
                    var principal = new System.Security.Claims.ClaimsPrincipal(new System.Security.Claims.ClaimsIdentity(winresult.Principal.Claims,"twostepcookie"));
                    await HttpContext.SignInAsync("SuperUserTwoStep", principal);
                    return Redirect(returnUrl);
                }
                else
                {
                    States[winresult.Principal.Identity.Name] = "1";
                    return Challenge(IISDefaults.AuthenticationScheme);
                }
            }

            else
            {
                return Challenge(IISDefaults.AuthenticationScheme);
            }
        }

        [Authorize("SuperUser")]
        public IActionResult YourSecurePage()
        {
            return Content("hello world");
        }

Самое сложное - отследить, что это второй раз для входа в систему, я пытаюсь использовать cookie, но он не работаетпоэтому я пишу static IDitionary<string,string> для отслеживания 10 возможно, лучше использовать распределенный кеш

...