2009-02-18 3 views
23

Мне пришлось отказаться от базовой безопасности WCF UserName/Pwd и реализовать свои собственные пользовательские учетные данные для хранения дополнительной информации, кроме того, что предоставляется по умолчанию.Аутентификация WCF с помощью пользовательских ClientCredentials: какой тип clientCredentialType использовать?

Я работал через this MSDN article, но мне что-то не хватает, потому что он не работает.

Во-первых, у меня есть некоторые пользовательские ClientCredentials, которые обеспечивают пользовательский ClientCredentialsSecurityTokenManager:

public class CentralAuthCredentials : ClientCredentials 
{ 
    public override System.IdentityModel.Selectors.SecurityTokenManager CreateSecurityTokenManager() 
    { 
     return new CentralAuthTokenManager(this); 
    } 
} 

public class CentralAuthTokenManager : ClientCredentialsSecurityTokenManager 
{ 
    private CentralAuthCredentials credentials; 

    public CentralAuthTokenManager(CentralAuthCredentials creds) : base(creds) 
    { 
     this.credentials = creds; 
    } 

    public override SecurityTokenProvider CreateSecurityTokenProvider(SecurityTokenRequirement tokenRequirement) 
    { 
     if (this.IsIssuedSecurityTokenRequirement(tokenRequirement) || tokenRequirement.TokenType == CentralAuthToken.TOKEN_TYPE) 
      return new CentralAuthTokenProvider(credentials.UserId, credentials.UserPassword, credentials.ImpersonateId, credentials.LoginType); 
     else 
      return base.CreateSecurityTokenProvider(tokenRequirement); 
    } 

    public override SecurityTokenAuthenticator CreateSecurityTokenAuthenticator(SecurityTokenRequirement tokenRequirement, out SecurityTokenResolver outOfBandTokenResolver) 
    { 
     outOfBandTokenResolver = null; 
     if (this.IsIssuedSecurityTokenRequirement(tokenRequirement) || tokenRequirement.TokenType == CentralAuthToken.TOKEN_TYPE) 
      return new CentralAuthTokenAuthenticator(); 
     else 
      return base.CreateSecurityTokenAuthenticator(tokenRequirement, out outOfBandTokenResolver); 
    } 

    public override SecurityTokenSerializer CreateSecurityTokenSerializer(SecurityTokenVersion version) 
    { 
     return new CentralAuthTokenSerializer(); 
    } 
} 

Теперь, когда я запустить приложение, мои пользовательские учетные данные и маркер менеджер действительно получить создан. Однако в методе:

CreateSecurityTokenProvider(SecurityTokenRequirement tokenRequirement) 
{ 
    ... 
} 

tokenRequirement.TokenType попадается как нечто иное, чем мой пользовательский маркер. Что вызывает мой 1-й вопрос: Как, черт возьми, WCF знает, что означают требования к токену?

Кроме того, метод:

public override SecurityTokenSerializer CreateSecurityTokenSerializer(SecurityTokenVersion version) 
{ 
    return new CentralAuthTokenSerializer(); 
} 

ли дозвонились один раз клиентом, но ни один из методов на возвращаемой лексемы сериализатором не всегда называется. Это указывает на то, что пользовательский токен никогда не отправляется через провод. Я предполагаю, что это вызвано тем, что вызов CreateSecurityTokenProvider() никогда не возвращал мой пользовательский поставщик токенов, так как SecurityTokenRequirement никогда не передается с указанием моего пользовательского токена.

На стороне клиента, у меня есть:

public class CentralAuthorizationManagerClient : ClientBase<ICentralAuthorizationManager>, ICentralAuthorizationManager, IDisposable 
{ 
    public PFPrincipal GenerateToken() 
    { 
     if (!this.ChannelFactory.Endpoint.Behaviors.Contains(typeof(CentralAuthCredentials))) 
      throw new ArgumentException("Must set CentralAuthCredentials before calling this method."); 
     return base.Channel.GenerateToken(); 
    } 

    public PFPrincipal GenerateToken(CentralAuthToken token) 
    { 
     this.ChannelFactory.Endpoint.Behaviors.Remove<ClientCredentials>(); 
     this.ChannelFactory.Endpoint.Behaviors.Add(new CentralAuthCredentials(token)); 
     return this.GenerateToken(); 
    } 

Эти методы в основном должны удалить учетные данные по умолчанию из конечной точки и прикрепить новый экземпляр моих пользовательских CentralAuthCredentials. (Я схватил это Удалить/Добавить комбо из статьи MSDN где-нибудь).

В конфигурации:

<behaviors> 
     <endpointBehaviors> 
      <behavior name="Server2ServerEndpointBehavior"> 
       <clientCredentials type="MyApp.Security.CentralAuthCredentials, MyApp"> 
        <clientCertificate findValue="localhost" x509FindType="FindBySubjectName" storeLocation="CurrentUser" storeName="My" /> 
        <serviceCertificate> 
         <authentication certificateValidationMode="None" revocationMode="NoCheck" /> 
        </serviceCertificate> 
       </clientCredentials> 
      </behavior> 
     </endpointBehaviors> 
    </behaviors> 

    <bindings> 
     <wsHttpBinding> 
      <binding name="wsHttpServer2Server"> 
       <security mode="Message"> 
        <message clientCredentialType="UserName" /> 
       </security> 
      </binding> 
     </wsHttpBinding> 
    </bindings> 

Обратите внимание, что тип ClientCredentials поведения установлен в моем пользовательском учетные данные клиента. Тем не менее, на данный момент у меня все еще есть clientCredentialType привязки, установленного в «UserName». Это вызывает мой Второй вопрос: Какая черта должна clientCredentialType = "?" быть установленным, если я использую пользовательские учетные данные? Согласно MSDN, доступные значения для Сообщение безопасности не являются: Ни, Окна, UserName, Сертификат и IssuedToken.

Любые идеи? Надеюсь, я просто пропустил что-то простое? Для всей реализации существует как еще 6 классов, но я попытался включить только биты, необходимые для понимания ситуации ...


UPDATE # 1:

Я работал над этим весь день, и благодаря нескольким источникам, я понял, что часть того, что я пропускал был самый последний шаг на this page , который добавляет TokenParameters к привязке, так что привязка знает, как выглядит токен. Это ответ на мой первоначальный 1-й вопрос; «Какая черта устанавливает требования к токену?» Ответ: TokenParameters, назначенные привязке.

Так что теперь я добавил следующее расширение задающий TokenParameters на переплете:

public sealed class CentralAuthTokenBindingExtension : BindingElementExtensionElement 
{ 
    public CentralAuthTokenBindingExtension() 
     : base() 
    { 
    } 

    public override Type BindingElementType 
    { 
     get { return typeof(SymmetricSecurityBindingElement); } 
    } 

    protected override System.ServiceModel.Channels.BindingElement CreateBindingElement() 
    { 
     X509SecurityTokenParameters protectionParams = new X509SecurityTokenParameters(); 
     protectionParams.InclusionMode = SecurityTokenInclusionMode.Never; 

     SymmetricSecurityBindingElement innerBindingElement = new SymmetricSecurityBindingElement(); 
     innerBindingElement.EndpointSupportingTokenParameters.SignedEncrypted.Add(new CentralAuthTokenParameters()); 
     //innerBindingElement.MessageProtectionOrder = MessageProtectionOrder.SignBeforeEncrypt; 
     innerBindingElement.ProtectionTokenParameters = protectionParams; 

     return innerBindingElement; 
    } 
} 

    <extensions> 
     <bindingElementExtensions> 
      <add name="CentralAuthCreds" type="MyApp.Security.Configuration.CentralAuthTokenBindingExtension, MyApp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> 
     </bindingElementExtensions> 
    </extensions> 

    <bindings> 
     <customBinding> 
      <binding name="wsHttpServer2Server"> 
       <CentralAuthCreds /> 
       <binaryMessageEncoding /> 
       <httpTransport /> 
      </binding> 
     </customBinding> 
    </bindings> 

Ну что получает меня шаг вперед. Теперь я получаю новое исключение на сервере:

"The security token manager cannot create a token authenticator for requirement ..." 

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

<endpointBehaviors> 
    <behavior name="Server2ServerEndpointBehavior"> 
     <clientCredentials type="MyApp.Security.CentralAuthCredentials, MyApp"> 

Но на сервере у меня нет никакого эквивалента, чтобы позволить ему знать о пользовательских учетных данных клиента. Итак, новый вопрос: Где в конфигурации для сервера я рассказываю, что такое пользовательские ClientCredentials?


Update # 2:

Ну, я, наконец, понял, немного больше головоломки. Я только реализовал реализацию ClientCredentials, считая, что клиент отправляет кредиты, и это все. Клиент не выполняет аутентификацию службы, поэтому мне не нужны специальные ServiceCredentials. Ну, я был неправ. Указанные ServiceCredentials аутентифицируют токен из ClientCredentials и наоборот. Поэтому мне просто пришлось добавить пользовательскую реализацию ServiceCredentials, которая передала те же классы TokenSerializer и TokenAuthenticator.

К следующему вопросу: WCF теперь игнорирует мои сертификаты x509, указанные в конфигурации, которые отлично работают с UserName auth. Я собираюсь открыть для него совершенно новый вопрос!

+0

Итак, этот вопрос читается почти так же, как мой последний два дня! – basscinner

ответ

1

Я столкнулся с подобными проблемами с приложением, над которым я работаю, к сожалению, я сдался, так как не смог получить пользовательские учетные данные. Теперь я использую имя пользователя/пароль (учетные данные клиента) и сертификат (учетные данные службы) с пользовательскими зашифрованными заголовками мыла, добавленными к вызовам службы, чтобы передать дополнительную информацию, например, UserID и т. Д.

Смежные вопросы