Заполнение первичного идентификатора в WCF - PullRequest
4 голосов
/ 14 мая 2010

Я использую простые HTTP-заголовки для передачи токена службе WCF для аутентификации (службе WCF требуется использовать базовую привязку HTTB, поэтому я, к сожалению, не могу использовать стандартную реализацию ws-security). Я хотел бы заполнить объект PrimaryIdentity, чтобы службы WCF могли проверить его, чтобы определить прошедшего проверку пользователя.

Проблема в том, что свойство OperationContext.Current.ServiceSecurityContext.PrimaryIdentity доступно только для чтения, когда я пытаюсь его заполнить. Я пытался использовать объекты SecurityTokenAuthenticators и IAuthorizationPolicy для установки идентификационной информации, но этот маршрут требует использования защиты на уровне сообщений (такой как всегда отправка имени пользователя и пароля), а это не то, что мне нужно.

Может кто-нибудь пролить свет на то, как я могу установить поле PrimaryIdentity?

Ответы [ 3 ]

12 голосов
/ 12 августа 2011

Вы можете создать класс, который реализует IAuthorizationPolicy . WCF анализирует все токены идентификации (X509, имя пользователя / пароль WS-Security и т. Д.) И помещает их вvaluationContext.Properties ["Identities"], который вы получаете в функции Evaluate. Это вернет вам список. Если вы замените этот список списком, содержащим ваш собственный класс, который реализует IIdentity , то WCF прочитает его в ServiceSecurityContext.Current.PrimaryIdentity. пожалуйста, убедитесь, что список содержит только один элемент, иначе вы перепутаете WCF и PrimaryIdentity.Name будет пустой строкой.

var myIdentity = new MyIdentity("MyId", otherstuff);
evaluationContext.Properties["Identities"] = new List<IIdentity> {myIdentity};

Кроме того, вы можете захотеть обработать / прочитать любые токены перед их заменой.

var identities = evaluationContext.Properties.ContainsKey("Identities")
                                 ? (List<IIdentity>) evaluationContext.Properties["Identities"]
                                 : new List<IIdentity>();

var genericIdentity = identities.Find(x => x.AuthenticationType == "MyUserNamePasswordValidator");

genericIdentity.Name -> содержит имя пользователя из токена имени пользователя WSS.

Вам понадобится UsernamePasswordValidator (http://msdn.microsoft.com/en-us/library/system.identitymodel.selectors.usernamepasswordvalidator.aspx), если вы используете токен имени пользователя WS-Security и не хотите никакой проверки WCF по умолчанию. Так как у нас есть устройство DataPower, которое проверяет токен до того, как сообщение попадет в наш сервис, нам не нужно проверять имя пользователя и пароль. В нашем случае он просто возвращает true.

5 голосов
/ 14 мая 2010

PrimaryIdentity не предназначен для заполнения вами - это задача среды выполнения WCF, чтобы определить, кто звонит, и соответственно установить PrimaryIdentity.

Так что, если вы звоните с учетными данными Windows, тогда вы получите WindowsIdentity, хранящийся там; если вы используете провайдеров членства ASP.NET, этот вызывающий абонент будет храниться в PrimaryIdentity.

Единственный способ установить это - создать свой собственный механизм аутентификации на стороне сервера и подключить его к WCF.

См:

4 голосов
/ 09 мая 2012

Это работает для меня ... Сначала настройте поведение аутентификации хоста (здесь показано через код, но также может быть сделано в конфигурации):

ServiceAuthorizationBehavior author = Description.Behaviors.Find<ServiceAuthorizationBehavior>();
author.ServiceAuthorizationManager = new FormCookieServiceAuthorizationManager();
author.PrincipalPermissionMode = PrincipalPermissionMode.Custom;
author.ExternalAuthorizationPolicies = new List<IAuthorizationPolicy> { new CustomAuthorizationPolicy() }.AsReadOnly();

А потом вспомогательные классы

  internal class FormCookieServiceAuthorizationManager : ServiceAuthorizationManager
  {
     public override bool CheckAccess(OperationContext operationContext)
     {
        ParseFormsCookie(operationContext.RequestContext.RequestMessage);
        return base.CheckAccess(operationContext);
     }
     private static void ParseFormsCookie(Message message)
     {
        HttpRequestMessageProperty httpRequest = message.Properties[HttpRequestMessageProperty.Name] as HttpRequestMessageProperty;
        if (httpRequest == null) return;

        string cookie = httpRequest.Headers[HttpRequestHeader.Cookie];
        if (string.IsNullOrEmpty(cookie)) return;

        string regexp = Regex.Escape(FormsAuthentication.FormsCookieName) + "=(?<val>[^;]+)";
        var myMatch = Regex.Match(cookie, regexp);
        if (!myMatch.Success) return;

        string cookieVal = myMatch.Groups["val"].ToString();
        FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(cookieVal);
        Thread.CurrentPrincipal = new GenericPrincipal(new GenericIdentity(authTicket.Name), new string[0]);
     }
  }
  internal class CustomAuthorizationPolicy : IAuthorizationPolicy
  {
     static readonly string _id = Guid.NewGuid().ToString();
     public string Id
     {
        get { return _id; }
     }

     public bool Evaluate(EvaluationContext evaluationContext, ref object state)
     {
        evaluationContext.Properties["Principal"] = Thread.CurrentPrincipal;
        evaluationContext.Properties["Identities"] = new List<IIdentity> { Thread.CurrentPrincipal.Identity };
        return true;
     }

     public ClaimSet Issuer
     {
        get { return ClaimSet.System; }
     }
  }

А если установлена ​​AspNetCompatibility, то FormCookieServiceAuthorizationManager немного проще:

 internal class FormCookieServiceAuthorizationManager : ServiceAuthorizationManager
 {
    public override bool CheckAccess(OperationContext operationContext)
    {
       Thread.CurrentPrincipal = HttpContext.Current.User;
       return base.CheckAccess(operationContext);
    }
 }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...