我有一个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
}
}
答案 0 :(得分:1)
我还使用UserNamePasswordValidator和使用makecert生成的证书。
使用WcfSvcHost代替使用IIS,以确保它成功启动。我建议这样做的原因是证书的链式构建可能失败了。您可以使用一个设置来禁用链构建。 (更新:我认为您已经使用CertificateValidationMode =“none”进行了此操作)
我注意到的另一件事是,并非所有服务定义都指定了behaviourConfiguration。这是一个很容易找到的山毛榉,因为当您更新服务引用时,它有时会被VS删除。
你提到的例外是来自内部最常见的消息吗?