65.9K
CodeProject 正在变化。 阅读更多。
Home

MCF 服务(带成员资格提供程序) 通过 SSL

emptyStarIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

0/5 (0投票)

2008年1月22日

CPOL

4分钟阅读

viewsIcon

18620

如何设置 MCF 服务以使用 ASP 会员提供者。

引言

我为我正在处理的一个客户端应用程序创建了一个简单的 MCF 服务。我想让通信使用 SSL,并使用 ASP 会员提供者作为身份验证源。这一切似乎都很简单,当我将 wsHttpBinding 安全消息的 clientCredentialType 更改为 Username 时,一切都很顺利。然后,开始了七个小时的相同非常无用的错误:“请求安全令牌的元素无效或格式错误。”

背景

在花费了七个小时搜索“请求安全令牌的元素无效或格式错误”之后,我偶然发现了一篇关于 svcTraceviewer.exe 的文章。无论如何,我找不到这个神奇的应用程序。最后,我找到并下载了 Windows Vista SDK,其中包含 .NET 3.0 SDK。我不知道为什么不只是一个 .NET 3.0 SDK,但我肯定没有打算在我的 XP 开发机器上安装 Vista SDK。无论如何,我添加了一些行来启用客户端和 MCF 服务上的日志记录。然后,我觉得我取得了一些进展。此时的错误与之前相同:“请求安全令牌的元素无效或格式错误。” 好的,那么现在怎么办?我现在知道当 clientCredentialType="windows" 时,一切都正常工作,但当我将其更改为 clientCredentialType="UserName" 时,错误就会再次出现。我知道 Microsoft 不会在 MSDN 帖子中以明文形式发送用户名和密码,这与客户端验证 SSL 证书有关,但即使我尝试在客户端使用我自己的 customCertificateValidator,代码也从未被调用。我的问题是,在我阅读的所有文章中,我从未见过客户端 enpointBehaviors serverCertificate 身份验证 certificateValidationMode 属性被设置。一旦我将其设置为 PeerOrChainTrust,我就开始收到有意义的错误。例如:x509 证书不受信任身份不匹配,请尝试将“www.domain.com”更改为“domain.com”。现在有了有意义的错误,我就可以找出需要修复的地方了。

使用代码

您需要做的第一件事是使用 makecert 可执行文件创建一个测试证书。我使用了

C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0>makecert.exe 
   -sr LocalMachine -ss My -a sha1 -n CN=localhost -sky exchange -pe

我在 http://www.eggheadcafe.com/articles/20021231.asp 上找到了“如何授予 ASPNET 帐户访问证书的权限”。

为了让 WSE 从本地计算机证书存储中获取 X.509 私钥,它必须拥有访问权限。默认情况下,只有所有者和系统帐户可以访问证书的私钥。此外,默认情况下,ASP.NET 服务在 ASPNET 帐户下运行,并且该帐户无权访问私钥。

要授予 ASPNET 帐户访问私钥的权限,请授予 ASP.NET 运行所在的帐户对包含 WSE 需要在以下文件夹中检索的密钥的文件拥有完全控制权限。

C:\Documents and Settings\All Users\Application Data\
           Microsoft\Crypto\RSA\MachineKeys

ASP.NET 工作进程运行所在的帐户由 Machine.config 文件中的 <processModel> 元素控制。设置 <processModel> 元素的 userName 属性来指定 ASP.NET 运行所在的帐户。默认情况下,userName 属性设置为特殊的计算机帐户,该帐户映射到安装 .NET Framework SDK 时创建的低权限 ASPNET 用户帐户。

  • 打开 Windows 资源管理器。
  • 导航到 C:\Documents and Settings\All Users\Application Data\Microsoft\Crypto\RSA\MachineKeys 文件夹。
  • 选择包含 WSE 需要检索的密钥的文件。
  • 在“文件”菜单中,选择“属性”。
  • 在“安全”选项卡上,添加 ASPNET 帐户并选择“完全控制”选项。
  • 注意:确定 MachineKeys 文件夹中的哪个密钥文件与证书相关联可能很困难。一个简单的解决方法是注意创建新证书时的时间和日期。在查看 MachineKeys 目录中的文件时,检查相应日期和时间的“修改日期”字段。

现在,运行 MMC 并添加两次证书插件。我将第一个添加为我的用户帐户,并将第二个添加为计算机。使用此 MMC 插件,您可以查看已作为个人证书安装在本地计算机上的证书,以及在文件夹之间进行复制和粘贴。您要查找的是本地计算机个人证书,如果存在一个友好名称与 serviceBehaviors serviceCredentials serviceCertificate 中的 findvalue 属性匹配的证书。应该注意的是,我还可以使用我之前在 IIS 中用于真实域的 godaddy 签名证书,即使 DNS 名称与 certname 不匹配,方法是编辑客户端身份。

这是我的 web.config

<system.serviceModel>
<diagnostics>
 <messageLogging
   logEntireMessage="true"
   logMalformedMessages="true"
   logMessagesAtServiceLevel="true"
   logMessagesAtTransportLevel="false"
   maxMessagesToLog="30000"
   maxSizeOfMessageToLog="200000"/>
</diagnostics> 

<bindings>
<wsHttpBinding>
<binding name="AuroraSyncService">
<security mode="Message">
<transport clientCredentialType="None" />
<message clientCredentialType="UserName" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<services>
<service behaviorConfiguration="AuroraSyncServiceBehavior" 
  name="AuroraSyncService">
<endpoint address="" binding="wsHttpBinding" 
  bindingConfiguration="AuroraSyncService"
  contract="IAuroraSyncService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" 
  contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="AuroraSyncServiceBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceAuthorization principalPermissionMode="UseAspNetRoles" />
<serviceCredentials>
<serviceCertificate findValue="localhost" 
  x509FindType="FindBySubjectName" 
  storeLocation="LocalMachine" 
  storeName="My" />

<userNameAuthentication 
  userNamePasswordValidationMode="MembershipProvider" 
  membershipProviderName="MembershipSqlProvider" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
<system.diagnostics>
<sources>
<source name="System.ServiceModel.MessageLogging">
<listeners>
<add name="messages"
  type="System.Diagnostics.XmlWriterTraceListener"
  initializeData="c:\logs\servermessages.svclog" />
</listeners>
</source>
</sources>
</system.diagnostics>

这是我的 app.config

<system.diagnostics>
<sources>
<source name="System.ServiceModel.MessageLogging">
<listeners>
<add name="messages"
  type="System.Diagnostics.XmlWriterTraceListener"
  initializeData="c:\logs\clientmessages.svclog" />
</listeners>
</source>
</sources>
</system.diagnostics>
<system.serviceModel>
<diagnostics>
<messageLogging
  logEntireMessage="true"
  logMalformedMessages="true"
  logMessagesAtServiceLevel="true"
  logMessagesAtTransportLevel="false"
  maxMessagesToLog="30000"
  maxSizeOfMessageToLog="200000"/>
</diagnostics>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IAuroraSyncService" 
  closeTimeout="00:01:00"
  openTimeout="00:01:00" 
  receiveTimeout="00:10:00" 
  sendTimeout="00:01:00"
  bypassProxyOnLocal="false" 
  transactionFlow="false" 
  hostNameComparisonMode="StrongWildcard"
  maxBufferPoolSize="524288" 
  maxReceivedMessageSize="1000000000"
  messageEncoding="Text" 
  textEncoding="utf-8" 
  useDefaultWebProxy="true"
  allowCookies="True">

<readerQuotas maxDepth="32" 
  maxStringContentLength="8192" 
  maxArrayLength="16384"
  maxBytesPerRead="4096" 
  maxNameTableCharCount="16384" />

<reliableSession ordered="true" 
  inactivityTimeout="00:10:00"
  enabled="false" />

<security mode="Message">

<transport clientCredentialType="None" 
  proxyCredentialType="None"/>

<message clientCredentialType="UserName" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>

<endpoint 
  address="https://:4358/FamilyOrganizer.Aurora.
           Sync.WCFService/AuroraSyncService.svc"
  binding="wsHttpBinding" 
  bindingConfiguration="WSHttpBinding_IAuroraSyncService"
  contract="FamilyOrganizer.Aurora.Sync.WCFService.IAuroraSyncService"
  name="WSHttpBinding_IAuroraSyncService" 
  behaviorConfiguration="myClientBehavior">

<identity>
<dns value="localhost" />
</identity>
</endpoint>
</client>
<behaviors>
<endpointBehaviors>
<behavior name="myClientBehavior">
<clientCredentials>
<serviceCertificate>
<authentication certificateValidationMode="PeerOrChainTrust" />
</serviceCertificate>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>

您的应用程序将需要创建 MCFclient 的实例并像这样设置用户名和密码

_WebServerSyncService = New WCFService.SyncServiceClient
_WebServerSyncService.ClientCredentials.UserName.UserName = myUserName
_WebServerSyncService.ClientCredentials.UserName.Password = myPassword

关注点

关于安全通道的那些含糊不清的错误惹恼了我。为什么不给出类似这样的错误:抱歉,客户端未设置为信任此证书,请尝试更改此属性,就像 MCF 抛出的所有其他错误一样。

历史

  • 添加了 ASPNET 权限部分
  • 修复了一些拼写错误
  • 格式化 XML 以防止滚动
© . All rights reserved.