Преобразование требований с помощью Windows Azure Active Directory (WAAD)

В настоящее время я использую активный каталог Windows Azure в качестве единого входа в мое приложение MVC.NET, и эта часть отлично работает. Я могу пройти аутентификацию в WAAD и без проблем загрузить свой ClaimsPrinicipal.

Следующим шагом было преобразование заявок, полученных из WAAD, путем добавления новых заявок из другого источника данных. Для этого я создал класс, наследующий ClaimsAuthenticationManager (ниже). Утверждения добавляются к субъекту и сохраняются в файле cookie сеанса в методе CreateSession.

Моя проблема сейчас заключается в том, что ClaimsPrincipal.Current не содержит никаких дополнительных утверждений, которые я добавил. Когда я устанавливаю точку останова в событии SessionAuthenticationModule_SessionSecurityTokenReceived, я вижу, что существует несоответствие между ClaimsPrincipal.Current

ClaimsPrincipal.Current.FindAll(ClaimTypes.Email)
Count = 0

и e.SessionToken.ClaimsPrincipal.

e.SessionToken.ClaimsPrincipal.FindAll(ClaimTypes.Email)
Count = 1
[0]: {http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress: [email protected]}

Что мне здесь не хватает? Во всех образцах, связанных с преобразованием утверждений, которые мне удалось найти, нет упоминания о ручной перезагрузке ClaimsPrinicipal из файла cookie. Будет ли событие маркера безопасности сеанса подходящим местом для перезагрузки ClaimsPrincipal, или я нарушаю модель безопасности?

Спасибо.

public class MyAuthenticationManager : ClaimsAuthenticationManager
{
    public override ClaimsPrincipal Authenticate(string resourceName, ClaimsPrincipal incomingPrincipal)
    {
        if (!incomingPrincipal.Identity.IsAuthenticated)
        {
            return base.Authenticate(resourceName, incomingPrincipal);
        }

        var transformedPrincipal = this.CreateUserPrincipal(incomingPrincipal.Identity.Name);
        this.CreateSession(transformedPrincipal);

        return transformedPrincipal;
    }

    private ClaimsPrincipal CreateUserPrincipal(String userName)
    {
        List<Claim> claims = new List<Claim>();
        var user = SecurityController.GetUserIdentity(userName);

        claims.Add(new Claim(ClaimTypes.Name, userName));
        claims.Add(new Claim(ClaimTypes.Email, user.Email));
        claims.Add(new Claim(ClaimTypes.GivenName, user.FirstName));
        claims.Add(new Claim(ClaimTypes.Surname, user.LastName));

        return new ClaimsPrincipal(new ClaimsIdentity(claims, "MyCustom"));
    }

    private void CreateSession(ClaimsPrincipal transformedPrincipal)
    {
        var sessionSecurityToken = new SessionSecurityToken(transformedPrincipal, TimeSpan.FromHours(8));

        if (FederatedAuthentication.SessionAuthenticationModule != null &&
        FederatedAuthentication.SessionAuthenticationModule.ContainsSessionTokenCookie(HttpContext.Current.Request.Cookies))
        {
            return;
        }
        FederatedAuthentication.SessionAuthenticationModule.WriteSessionTokenToCookie(sessionSecurityToken);
        //Added line below as per suggestion in one of the posts
        //Doesn't seem to have any effect
        Thread.CurrentPrincipal = transformedPrincipal;
        FederatedAuthentication.SessionAuthenticationModule.SessionSecurityTokenReceived += SessionAuthenticationModule_SessionSecurityTokenReceived;
    }

    void SessionAuthenticationModule_SessionSecurityTokenReceived(object sender, SessionSecurityTokenReceivedEventArgs e)
    {
        System.Diagnostics.Debug.WriteLine("SessionAuthenticationModule_SessionSecurityTokenReceived");
    }

person Dmitri M    schedule 26.11.2013    source источник
comment
Настроен ли MyAuthenticationManager в файле .config приложения?   -  person mcollier    schedule 27.11.2013
comment
Ваш тест ошибочен, так как вы пытаетесь найти утверждения со строкой Email, это должно быть либо ClaimTypes.Email, либо schemas.xmlsoap.org/ws/2005/05/identity/claims/адрес электронной почты   -  person Rob    schedule 27.11.2013
comment
Да, MyAuthenticationManager настроен в файле .config. Вызывается метод Authenticate, я могу пройти через него.   -  person Dmitri M    schedule 27.11.2013
comment
Да, тест был ошибочным, я обновил его до ClaimTypes.Email, но поведение осталось прежним. Я выбрал электронную почту, но у меня есть другие пользовательские утверждения, которые я тестировал, так что с этой точки зрения ничего не изменилось.   -  person Dmitri M    schedule 27.11.2013


Ответы (2)


Похоже, мне пришлось обращаться к претензиям через ClaimsIdentity вместо ClaimsPrincipal. Теперь я могу успешно получить доступ к утверждениям из любого представления или контроллера в своем приложении.

((ClaimsIdentity)Thread.CurrentPrincipal.Identity).FindAll(ClaimTypes.Email)
Count = 1
    [0]: {http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress: [email protected]}

Окончательная кодовая база в AuthenticationManager выглядит следующим образом (обратите внимание, что в текущем потоке нет явной операции присваивания ClaimsPrincipal).

public class MyAuthenticationManager : ClaimsAuthenticationManager
{
    public override ClaimsPrincipal Authenticate(string resourceName, ClaimsPrincipal incomingPrincipal)
    {
        if (!incomingPrincipal.Identity.IsAuthenticated)
        {
            return base.Authenticate(resourceName, incomingPrincipal);
        }

        var transformedPrincipal = this.CreateUserPrincipal(incomingPrincipal.Identity.Name);
        this.CreateSession(transformedPrincipal);

        return transformedPrincipal;
    }

    private ClaimsPrincipal CreateUserPrincipal(String userName)
    {
        List<Claim> claims = new List<Claim>();
        var user = SecurityController.GetUserIdentity(userName);

        claims.Add(new Claim(ClaimTypes.Name, userName));
        claims.Add(new Claim("UserId", user.Id.ToString()));
        claims.Add(new Claim(ClaimTypes.Email, user.Email));
        claims.Add(new Claim(ClaimTypes.GivenName, user.FirstName));
        claims.Add(new Claim(ClaimTypes.Surname, user.LastName));
        //claims.Add(new Claim(ClaimTypes.NameIdentifier, userName));

        if (user.Account != null)
        {
            claims.Add(new Claim("AccountId", user.Account.Id.ToString()));
            claims.Add(new Claim("AccountName", user.Account.Name.ToString()));
        }
        if (user.Owner != null)
        {
            claims.Add(new Claim("OwnerId", user.Owner.Id.ToString()));
            claims.Add(new Claim("OwnerName", user.Owner.Name.ToString()));
        }

        return new ClaimsPrincipal(new ClaimsIdentity(claims, "MyCustom"));
    }

    private void CreateSession(ClaimsPrincipal transformedPrincipal)
    {
        if (FederatedAuthentication.SessionAuthenticationModule != null &&
        FederatedAuthentication.SessionAuthenticationModule.ContainsSessionTokenCookie(HttpContext.Current.Request.Cookies))
        {
            return;
        }
        var sessionSecurityToken = new SessionSecurityToken(transformedPrincipal, TimeSpan.FromHours(8));
        FederatedAuthentication.SessionAuthenticationModule.WriteSessionTokenToCookie(sessionSecurityToken);
    }
}
person Dmitri M    schedule 30.11.2013

Я не вижу, чтобы вы добавляли свой ClaimsPrincipal (после преобразования) обратно в Thread.CurrentPrincipal. Пожалуйста, попробуй

private void CreateSession(ClaimsPrincipal transformedPrincipal)
    {
        var sessionSecurityToken = new SessionSecurityToken(transformedPrincipal, TimeSpan.FromHours(8));

        if (FederatedAuthentication.SessionAuthenticationModule != null &&
        FederatedAuthentication.SessionAuthenticationModule.ContainsSessionTokenCookie(HttpContext.Current.Request.Cookies))
        {
            return;
        }
        FederatedAuthentication.SessionAuthenticationModule.WriteSessionTokenToCookie(sessionSecurityToken);
        //Following is the missing line of code.
        Thread.CurrentPrincipal = transformedPrincipal;
   }
person Prerak K    schedule 27.11.2013
comment
Я назначил принципала CurrentPrincipal, но это не имело никакого эффекта. Я снова попытаюсь создать отдельное решение POC, следуя статьям. - person Dmitri M; 28.11.2013
comment
вы уверены, что файлы cookie записаны и код не возвращается из следующего кода FederatedAuthentication.SessionAuthenticationModule.ContainsSessionTokenCookie(HttpContext.Current.Request.Cookies)) { return; } - person Prerak K; 29.11.2013
comment
Также вы можете попробовать написать файл cookie со следующим SessionAuthenticationModule sam = FederatedAuthentication.SessionAuthenticationModule; var st = sam.CreateSessionSecurityToken (transformedPrincipal, null, validFrom, validTo, isPersistantCookie); sam.WriteSessionTokenToCookie (st); - person Prerak K; 29.11.2013
comment
Да, куки пишется. Я установил точку останова в части возврата, и она никогда не срабатывает. Также я вижу файл cookie через инструменты разработчика в Chrome. Я попытался изменить код для записи файла cookie в соответствии с вашим предложением, и это ни на что не повлияло. - person Dmitri M; 29.11.2013