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

Аутентификация WCF с пользовательскими ClientCredentials: каков тип clientCredentialType?

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

Я работал над этой статьей MSDN, но я что-то упустил, потому что он не работает.

Во-первых, у меня есть некоторые пользовательские 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". Это вызывает мой 2-й вопрос. Какая черта должна быть clientCredentialType = "?" быть установленным, если я использую пользовательские учетные данные? Согласно MSDN, доступными значениями для безопасности сообщений являются: None, Windows, UserName, Certificate и IssuedToken.

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


ОБНОВЛЕНИЕ # 1:

Я работаю над этим весь день, и благодаря нескольким источникам я понял, что часть того, что мне не хватало, это последний шаг на эта страница, которая добавляет 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 ..."

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

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

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


Обновление # 2:

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

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

4b9b3361

Ответ 1

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