[英]WCF Authentication - Username-Password using custom validator - Works on My Machine
I have a WCF service and a client, that uses a custom UserNamePasswordValidator
for authentication. 我有一个WCF服务和一个客户端,该客户端使用自定义
UserNamePasswordValidator
进行身份验证。
I use a self-signed certificate, created by the following command line: 我使用由以下命令行创建的自签名证书:
makecert -sr LocalMachine -ss My -a sha1 -n CN=SelfSignedCertificate -sky exchange -pe
Calling methods in the service from the below client works fine on my machine :) But as soon as I deploy it to my server, I get this error message: The request for security token could not be satisfied because authentication failed.
从下面的客户端在服务中调用方法在我的机器上可以正常工作:)但是,一旦将其部署到服务器上,我就会收到此错误消息:
The request for security token could not be satisfied because authentication failed.
I can browse the endpoint URL and see the WSDL for the service. 我可以浏览端点URL并查看该服务的WSDL。 I'm not sure, but I recall that I configured some Anonymous Authentication in IIS on my local machine, but it looks similar on the server as well.
我不确定,但是我记得我在本地计算机上的IIS中配置了一些匿名身份验证,但是在服务器上看起来也是如此。
My WCF service is hosted in IIS 7.0, using this configuration: 我的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>
The client configuration looks like this: 客户端配置如下所示:
<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>
My custom validator is this: 我的自定义验证器是这样的:
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);
}
}
}
My service client, looks like this: 我的服务客户端如下所示:
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
}
}
I also use the UserNamePasswordValidator with certificates generated using makecert. 我还将UserNamePasswordValidator与使用makecert生成的证书一起使用。
Instead of using IIS, use WcfSvcHost so you can be sure it starts successfully. 可以使用WcfSvcHost而不是IIS,以确保它可以成功启动。 The reason I'm suggesting this is that possibly Chain building for the certificate is failing.
我建议这样做的原因是证书的链构建可能失败。 There is a setting you can use to disable chain building.
您可以使用一个设置来禁用链构建。 ( Update: I think you're doing that already with CertificateValidationMode="none")
( 更新:我认为您已经使用CertificateValidationMode =“ none”进行了此操作)
Another thing I'm noticing is that not all your service definitions specify behaviourConfiguration. 我要注意的另一件事是,并非您的所有服务定义都指定了behaviourConfiguration。 This is a little beech to find because it gets removed sometimes by VS when you update your service references.
这有点像山毛榉,因为在更新服务引用时,有时VS会将其删除。
The exception you mention, is that the message from the inner most exception? 您提到的异常是最内部异常的消息吗?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.