1

下面的代碼假設運行自定義身份驗證的需要向Silverlight 4客戶端提供其服務的WCF服務(請參閱下面的代碼)。自行託管的WCF +自定義UserNamePasswordValidator + Silverlight 4

結果是,即使clientaccesspolicy.xml在瀏覽器中可見並且不顯示SSL錯誤,也會拋出臭名昭着的clientaccesspolicy安全錯誤通信異常未命中clientaccesspolicy.xml斷點。

我知道我只需要指定條目,但我試過 各種遊戲與clientaccesspolicy.xml沒有工作。

您的幫助表示讚賞

1)這是服務的app.config和代碼:

<?xml version="1.0"?> 
<configuration> 
    <startup> 
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/> 
    </startup> 
    <system.serviceModel> 
    <client /> 
    <bindings> 
     <basicHttpBinding> 
     <binding name="slBindingWithUserNamePassValidator"> 
      <security mode="TransportWithMessageCredential"> 
      <message clientCredentialType="UserName" /> 
      </security> 
     </binding> 
     </basicHttpBinding> 
     <webHttpBinding> 
     <binding name="capService" crossDomainScriptAccessEnabled="true"> 
      <security mode="Transport" /> 
     </binding> 
     <binding name="capServiceNoSSL" crossDomainScriptAccessEnabled="true"> 
      <security mode="None" /> 
     </binding> 
     </webHttpBinding> 
    </bindings> 
    <services> 
     <service behaviorConfiguration="svcBehavior" name="WCF_Self_Hosted_UserName_Validator.Service1"> 
     <endpoint address="" binding="webHttpBinding" bindingConfiguration="capService" behaviorConfiguration="capServiceBehavior" 
      contract="WCF_Self_Hosted_UserName_Validator.ICAPService" /> 
     <endpoint address="" binding="webHttpBinding" bindingConfiguration="capServiceNoSSL" behaviorConfiguration="capServiceBehavior" 
      contract="WCF_Self_Hosted_UserName_Validator.ICAPService" /> 
     <endpoint address="MyCustomValidationService" binding="basicHttpBinding" bindingConfiguration="slBindingWithUserNamePassValidator" 
      contract="WCF_Self_Hosted_UserName_Validator.IService1"> 
     </endpoint> 
     <host> 
      <baseAddresses> 
      <add baseAddress="https://(somesite):9999/" /> 
      <add baseAddress="http://(somesite):9998/" /> 
      </baseAddresses> 
     </host> 
     </service> 
    </services> 
    <behaviors> 
     <serviceBehaviors> 
     <behavior name="svcBehavior"> 
      <serviceMetadata httpsGetEnabled="true" httpGetEnabled="true" /> 
      <serviceDebug includeExceptionDetailInFaults="true" /> 
     </behavior> 
     </serviceBehaviors> 
     <endpointBehaviors> 
     <behavior name="capServiceBehavior"> 
      <webHttp/> 
     </behavior> 
     </endpointBehaviors> 
    </behaviors> 
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" /> 
    </system.serviceModel> 
</configuration> 

該服務的代碼:

Using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Security.Cryptography.X509Certificates; 
using System.ServiceModel; 
using System.IdentityModel.Selectors; 
using System.IO; 
using System.ServiceModel.Web; 

namespace WCF_Self_Hosted_UserName_Validator 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      MyServiceHost host = new MyServiceHost(new Service1()); 
      host.Open(); 
      Console.WriteLine("Host open..."); 
      Console.ReadLine(); 
     } 

    } 
    public class MyServiceHost : ServiceHost 
    { 
     SecurityValidator _securityValidator = null; 
     public MyServiceHost(IService1 svc) : base(svc) 
     { 
      Credentials.UserNameAuthentication.UserNamePasswordValidationMode = System.ServiceModel.Security.UserNamePasswordValidationMode.Custom; 
      _securityValidator = new SecurityValidator(); 
      Credentials.UserNameAuthentication.CustomUserNamePasswordValidator = _securityValidator; 
      Credentials.ServiceCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindBySubjectName, "my-fqdn-valid-cert.dot.something"); 
     } 
    } 
    public class SecurityValidator : UserNamePasswordValidator 
    { 
     public SecurityValidator() 
     { 
     } 
     public override void Validate(string userName, string password) 
     { 
      try 
      { 
       if (userName != "1" && password != "1") 
        throw new FaultException("auth error"); 
      } 
      catch (Exception ex) 
      { 
       throw ex; 
      } 
     } 
    } 
    [ServiceContract] 
    public interface IService1 
    { 
     [OperationContract] 
     string GetPrivateInfo(); 
    } 
    [ServiceContract] 
    public interface ICAPService 
    { 
     [OperationContract, WebGet(UriTemplate = "/clientaccesspolicy.xml")] 
     Stream GetClientAccessPolicy(); 
    } 
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)] 
    public class Service1 : IService1, ICAPService 
    { 
     public string GetPrivateInfo() 
     { 
      return "Some info " + DateTime.Now.ToShortTimeString(); 
     } 
     public System.IO.Stream GetClientAccessPolicy() 
     { 
      WebOperationContext ctx = new WebOperationContext(OperationContext.Current); 
      string txtCap = @"<?xml version=""1.0"" encoding=""utf-8"" ?> 
<access-policy> 
    <cross-domain-access> 
     <policy> 
      <allow-from http-request-headers=""*""> 
       <domain uri=""*""/> 
       <domain uri=""http://*""/> 
       <domain uri=""https://*""/> 
      </allow-from> 
      <grant-to> 
       <resource include-subpaths=""true"" path=""/""/> 
      </grant-to> 
     </policy> 
    </cross-domain-access> 
</access-policy>"; 
      WebOperationContext.Current.OutgoingResponse.ContentType = "text/xml"; 
      MemoryStream response = new MemoryStream(Encoding.UTF8.GetBytes(txtCap)); 
      return response; 
     } 
    } 
} 

2)我們有CA在LOCAL MACHINE的MY容器中籤署了SSL證書並使用了網絡

netsh http add sslcert ipport=0.0.0.0:9999 certhash=aabbcc_thumbprint 
appid={my_app_id_guid} clientcertnegotiation=enable 

以上執行成功,主機正確加載並允許創建一個新的silverlight項目。

3)Silverlight項目是與附加服務引用一個只是一個新項目silveright和以下代碼:

namespace SilverlightApplication1 
{ 
    public partial class MainPage : UserControl 
    { 
     public MainPage() 
     { 
      InitializeComponent(); 
     } 

     private void button1_Click(object sender, RoutedEventArgs e) 
     { 
      ServiceReference1.Service1Client c = new ServiceReference1.Service1Client(); 
      c.ClientCredentials.UserName.UserName = "1"; 
      c.ClientCredentials.UserName.Password = "1"; 
      c.GetPrivateInfoCompleted += new EventHandler<ServiceReference1.GetPrivateInfoCompletedEventArgs>(c_GetPrivateInfoCompleted); 
      c.GetPrivateInfoAsync(); 
     } 

     void c_GetPrivateInfoCompleted(object sender, ServiceReference1.GetPrivateInfoCompletedEventArgs e) 
     { 
      if (e.Error == null) 
      { 
       this.Content = new TextBlock() { Text = e.Result }; 
      } 
      else 
      { 
       this.Content = new TextBlock() { Text = e.Error.GetBaseException().Message }; 
      } 
     } 
    } 
} 

4)這是ServiceReferences.ClientConfig產生

<configuration> 
    <system.serviceModel> 
     <bindings> 
      <basicHttpBinding> 
       <binding name="BasicHttpBinding_IService1" maxBufferSize="2147483647" 
        maxReceivedMessageSize="2147483647"> 
        <security mode="TransportWithMessageCredential" /> 
       </binding> 
      </basicHttpBinding> 
     </bindings> 
     <client> 
      <endpoint address="https://(TheAddress)/MyCustomValidationService" 
       binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IService1" 
       contract="ServiceReference1.IService1" name="BasicHttpBinding_IService1" /> 
     </client> 
    </system.serviceModel> 
</configuration> 

回答

0

Blockquote netsh http add sslcert ipport = 0.0.0.0:9999 certhash = aabbcc_thumbprint appid = {my_app_id_guid} clientcertnegotiation = enable

您已將netsh與clientcertnegotiation標誌一起使用,這意味着服務器需要客戶端證書。當Silverlight調用clientaccesspolicy時,它不會發送客戶端證書,這就是您獲取該例外的原因。

如果您不需要客戶端證書,請刪除此標誌。

我不確定SL是否能夠在獲取clientaccesspolicy時發送客戶端證書,但是如果您的網頁也訪問該網站,瀏覽器應該使用您提供的證書。所以你可以嘗試添加一個鏈接到你的託管html/aspx中的安全站點,這將要求你選擇一個證書,然後SL將使用該證書