Аутентификация WCF - Имя пользователя-Пароль с использованием пользовательского валидатора - Работает на моей машине - PullRequest
1 голос
/ 17 мая 2011

У меня есть служба WCF и клиент, который использует для аутентификации пользовательский UserNamePasswordValidator.

Я использую самоподписанный сертификат, созданный следующей командной строкой:

makecert -sr LocalMachine -ss My -a sha1 -n CN=SelfSignedCertificate -sky exchange -pe

Вызов методов в службе из нижеуказанного клиента работает нормально на моей машине :) Но как только я разверну его на своем сервере, я получаю это сообщение об ошибке: The request for security token could not be satisfied because authentication failed.

Я могу просмотреть URL-адрес конечной точкии посмотрите WSDL для службы.Я не уверен, но я вспоминаю, что я настроил некоторую анонимную аутентификацию в IIS на моем локальном компьютере, но на сервере она выглядит аналогично.

Моя служба WCF размещается в IIS 7.0 с использованием этой конфигурации:

<system.serviceModel>
    <bindings>
        <wsHttpBinding>
            <binding name="secured">
                <security mode="Message">
                    <message clientCredentialType="UserName" />
                </security>
            </binding>
            <binding name="unsecured">
                <security mode="None" />
            </binding>
        </wsHttpBinding>
        <basicHttpBinding>
            <binding name="secured">
                <security mode="TransportWithMessageCredential">
                    <message clientCredentialType="UserName" />
                </security>
            </binding>
            <binding name="unsecured">
                <security mode="None" />
            </binding>
        </basicHttpBinding>
        <webHttpBinding>
            <binding name="unsecured">
                <security mode="None" />
            </binding>
        </webHttpBinding>
    </bindings>
    <services>
        <service name="Milkshake.Admin.Services.AdminService" behaviorConfiguration="CustomValidator">
            <endpoint address="" binding="wsHttpBinding" contract="Milkshake.Admin.Model.ServiceContracts.IAdminService" bindingConfiguration="secured" />
        </service>
        <service name="Milkshake.Admin.Services.DeploymentService">
            <endpoint address="" binding="wsHttpBinding" contract="Milkshake.Admin.Model.ServiceContracts.IDeploymentService"/>
        </service>
        <service name="Milkshake.Admin.Services.LogService" behaviorConfiguration="CustomValidator">
            <endpoint address="" binding="wsHttpBinding" contract="Milkshake.Core.Logging.ILogService" bindingConfiguration="secured" />
        </service>
        <service name="Milkshake.Admin.Services.MailService">
            <endpoint address="" binding="wsHttpBinding" contract="Milkshake.Admin.Model.ServiceContracts.IMailService"/>
        </service>
    </services>
    <behaviors>
        <serviceBehaviors>
            <behavior name="CustomValidator">
                <serviceMetadata httpGetEnabled="true" />
                <serviceCredentials>
                    <serviceCertificate findValue="SelfSignedCertificate" x509FindType="FindBySubjectName" />
                    <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="Milkshake.Admin.Services.MilkshakeCredentialValidator, Milkshake.Admin.Services" />
                    <clientCertificate>
                        <authentication certificateValidationMode="None" />
                    </clientCertificate>
                </serviceCredentials>
                <serviceDebug httpHelpPageEnabled="true" includeExceptionDetailInFaults="true" />
            </behavior>
        </serviceBehaviors>

        <endpointBehaviors>
            <behavior name="json">
                <enableWebScript />
            </behavior>

            <behavior name="xml">
                <webHttp defaultOutgoingResponseFormat="Xml" defaultBodyStyle="Wrapped" />
            </behavior>
        </endpointBehaviors>
    </behaviors>
</system.serviceModel>

Конфигурация клиента выглядит следующим образом:

<system.serviceModel>
    <client>
        <endpoint address="http://server-url/LogService.svc" binding="wsHttpBinding" contract="Milkshake.Core.Logging.ILogService">
            <identity>
                <dns value="SelfSignedCertificate" />
            </identity>
        </endpoint>
    </client>
</system.serviceModel>

Мой пользовательский валидатор выглядит так:

using System;
using System.IdentityModel.Selectors;
using System.ServiceModel;

namespace Milkshake.Admin.Services
{
    /// <summary>
    /// WCF Service validator for Milkshake.
    /// </summary>
    public class MilkshakeCredentialValidator : UserNamePasswordValidator
    {
        /// <summary>
        /// When overridden in a derived class, validates the specified username and password.
        /// </summary>
        /// <param name="userName">The username to validate.</param>
        /// <param name="password">The password to validate.</param>
        public override void Validate(string userName, string password)
        {
            if (String.IsNullOrWhiteSpace(userName) || String.IsNullOrWhiteSpace(password))
            {
                throw new ArgumentNullException();
            }

            if (userName.Equals("martin") && password.Equals("normark"))
            {
                return;
            }

            FaultCode fc = new FaultCode("ValidationFailed");
            FaultReason fr = new FaultReason("Good reason");

            throw new FaultException(fr, fc);
        }
    }
}

Мой клиент службы выглядит следующим образом:

using System;
using System.ServiceModel;
using System.ServiceModel.Security;
using Milkshake.Core.Logging;

namespace Milkshake.Admin.ServiceClients.Logging
{
    /// <summary>
    /// WCF Service Client implementation of the <see cref="ILogService"/> contract.
    /// </summary>
    public class LogServiceClient : ILogService
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="LogServiceClient"/> class.
        /// </summary>
        public LogServiceClient()
        {
            var factory = new ChannelFactory<ILogService>(String.Empty);
            factory.Credentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.None;
            factory.Credentials.UserName.UserName = "martin";
            factory.Credentials.UserName.Password = "normark";

            var binding = factory.Endpoint.Binding as WSHttpBinding;

            if (binding != null)
            {
                binding.Security.Mode = SecurityMode.Message;
                binding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
            }

            this.AdminLogService = factory.CreateChannel();
        }

        /// <summary>
        /// Gets or sets the admin log service.
        /// </summary>
        /// <value>The admin log service.</value>
        private ILogService AdminLogService { get; set; }

        #region ILogService Members

        /// <summary>
        /// Logs the error simple.
        /// </summary>
        /// <param name="applicationInstanceId">The application instance id.</param>
        /// <param name="logDate">The log date.</param>
        /// <param name="exceptionMessage">The exception message.</param>
        /// <param name="description">The description.</param>
        /// <param name="severity">The severity.</param>
        /// <param name="userAgent">The user agent.</param>
        /// <param name="source">The source.</param>
        public void LogErrorSimple(int applicationInstanceId, DateTime logDate, string exceptionMessage, string description, Severity severity, string userAgent, string source)
        {
            this.AdminLogService.LogErrorSimple(applicationInstanceId, logDate, exceptionMessage, description, severity, userAgent, source);
        }

        /// <summary>
        /// Logs the error advanced.
        /// </summary>
        /// <param name="applicationInstanceId">The application instance id.</param>
        /// <param name="logDate">The log date.</param>
        /// <param name="exceptionType">Type of the exception.</param>
        /// <param name="exceptionCode">The exception code.</param>
        /// <param name="exceptionMessage">The exception message.</param>
        /// <param name="stackTrace">The stack trace.</param>
        /// <param name="caller">The caller.</param>
        /// <param name="location">The location.</param>
        /// <param name="source">The source (A service, app etc).</param>
        /// <param name="description">The description.</param>
        /// <param name="severity">The severity.</param>
        /// <param name="username">The username.</param>
        /// <param name="userAgent">The user agent.</param>
        public void LogErrorAdvanced(int applicationInstanceId, DateTime logDate, string exceptionType, string exceptionCode, string exceptionMessage, string stackTrace, string caller, string location, string source, string description, Severity severity, string username, string userAgent)
        {
            this.AdminLogService.LogErrorAdvanced(applicationInstanceId, logDate, exceptionType, exceptionCode, exceptionMessage, stackTrace, caller, location, source, description, severity, userAgent, userAgent);
        }

        /// <summary>
        /// Logs the behavior with data.
        /// </summary>
        /// <param name="applicationInstanceId">The application instance id.</param>
        /// <param name="action">The action.</param>
        /// <param name="logDate">The log date.</param>
        /// <param name="userAgent">The user agent.</param>
        /// <param name="behaviorData">The behavior data.</param>
        /// <param name="source">The source.</param>
        public void LogBehaviorWithData(int applicationInstanceId, string action, DateTime logDate, string userAgent, string behaviorData, string source)
        {
            this.AdminLogService.LogBehaviorWithData(applicationInstanceId, action, logDate, userAgent, behaviorData, source);
        }

        /// <summary>
        /// Logs the behavior.
        /// </summary>
        /// <param name="applicationInstanceId">The application instance id.</param>
        /// <param name="action">The action.</param>
        /// <param name="logDate">The log date.</param>
        /// <param name="userAgent">The user agent.</param>
        /// <param name="source">The source.</param>
        public void LogBehavior(int applicationInstanceId, string action, DateTime logDate, string userAgent, string source)
        {
            this.AdminLogService.LogBehavior(applicationInstanceId, action, logDate, userAgent, source);
        }

        #endregion
    }
}

1 Ответ

1 голос
/ 17 мая 2011

Я также использую UserNamePasswordValidator с сертификатами, сгенерированными с помощью makecert.

Вместо IIS используйте WcfSvcHost, чтобы вы могли быть уверены, что он запускается успешно.Причина, по которой я предлагаю это, заключается в том, что возможно создание цепочки для сертификата не удается.Есть настройка, которую вы можете использовать, чтобы отключить построение цепочки.( Обновление: Я думаю, что вы делаете это уже с CertificateValidationMode = "none")

Еще одна вещь, которую я замечаю, состоит в том, что не все ваши определения сервисов определяют поведение_конфигурации.Это небольшая буква, которую можно найти, потому что она иногда удаляется VS при обновлении ссылок на ваши сервисы.

Исключение, которое вы упоминаете, это сообщение из самого внутреннего исключения?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...