下面的代码假设使用自定义身份验证 WCF服务运行自托管,该服务需要向Silverlight 4客户端提供服务(请参阅下面的代码)。
结果是臭名昭着的clientaccesspolicy安全错误通信异常被抛出,即使clientaccesspolicy.xml在浏览器中可见并且没有显示SSL错误。没有命中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)我们在LOCAL MACHINE的MY容器中有一个CA签名的SSL证书并使用了netsh
netsh http add sslcert ipport=0.0.0.0:9999 certhash=aabbcc_thumbprint
appid={my_app_id_guid} clientcertnegotiation=enable
以上执行成功并且主机正确加载并允许创建新的silverlight项目。
3)silverlight项目只是一个新的银色项目,添加了服务参考和以下代码:
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 :(得分:0)
块引用 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将使用该证书