I'm going to implement basic authentication in WCF. I'm very new in all this stuff and my program is based on this series of articles http://leastprivilege.com/2008/01/11/http-basic-authentication-against-non-windows-accounts-in-iisasp-net-part-0-intro/ I do use webHttpBinding and HTTPS is on.
So the main idea is implementation of IHttpModule in this way:
When user requests some resource a module checks if Authorization header is present.
In case of Authorization is present, the module extracts the header's value, decodes and checks login and pass
In the other case the module sends a response with 401 code and a header "WWW-Authenticate".
Here is my implementation of the module:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Management;
using System.Text;
namespace MyProj_A
{
public class MyHTTPModule : IHttpModule
{
void IHttpModule.Dispose()
{
}
void IHttpModule.Init(HttpApplication context)
{
context.BeginRequest += Context_BeginRequest;
context.AuthenticateRequest += OnEnter;
context.EndRequest += OnLeave;
}
private void Context_BeginRequest(object sender, EventArgs e)
{
HttpContext context = HttpContext.Current;
context.Response.Write("BeginRequest");
}
void OnEnter(object sender, EventArgs e)
{
HttpContext context = HttpContext.Current;
if (IsHeaderPresent())
{
if (!AuthenticateUser())
{
DenyAccess();
}
}
else
{
// if anonymous requests are not allowed - end the request
DenyAccess();
}
}
bool IsHeaderPresent()
{
return HttpContext.Current.Request.Headers["Authorization"] != null;
}
bool AuthenticateUser()
{
string username = "", password = "";
string authHeader = HttpContext.Current.Request.Headers["Authorization"];
if (authHeader != null && authHeader.StartsWith("Basic"))
{
// extract credentials from header
string[] credentials = ExtractCredentials(authHeader);
username = credentials[0];
password = credentials[1];
if (username.CompareTo("tikskit") == 0 && password.CompareTo("") == 0)
{
return true;
} else
{
return false;
}
}
else
{
return false;
}
}
private static void DenyAccess()
{
HttpContext context = HttpContext.Current;
context.Response.StatusCode = 401;
context.Response.End();
}
void OnLeave(object sender, EventArgs e)
{
// check if module is enabled
if (HttpContext.Current.Response.StatusCode == 401)
{
SendAuthenticationHeader();
}
}
private void SendAuthenticationHeader()
{
HttpContext context = HttpContext.Current;
context.Response.StatusCode = 401;
context.Response.AddHeader(
"WWW-Authenticate",
"Basic realm=\"yo-ho-ho\""
);
}
}
}
I publish it under IIS 7.5 on remote computer and connect to it with remote debugger from my Visual Studio. I set breakpoints at Context_BeginRequest, OnEnter and OnLeave.
Then I access to my WCF from a browser using URL and here is what happens:
After I inputted an URL and pressed the Enter Context_BeginRequest is fired
In VS I can see that the Authorization header isn't present
OnEnter is fired and eventually it assigns 401 code to the response
OnLeave is executed as well and it sets WWW-Authenticate to the response header
In the browser the standart login dialog is shown
I input the user name and password and press OK
Now Context_BeginRequest is fired again and I can see that Authorization header is present and consists a value like "Basic ", which is right
OnEnter isn't executed at all this time
OnLeave is fired but a value of HttpContext.Current.Response.StatusCode is 401 by some reason
Here is my Web.config
<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.5.2" />
<httpRuntime targetFramework="4.5.2"/>
<customErrors mode="Off" />
</system.web>
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="webBehavior">
<webHttp automaticFormatSelectionEnabled="false"/>
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="Default" >
<serviceMetadata httpGetEnabled="false" />
<serviceMetadata httpsGetEnabled="false"/>
<serviceAuthenticationManager authenticationSchemes="Basic"/>
<serviceCredentials>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<webHttpBinding>
<binding name="MyBinding">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Basic"/>
</security>
</binding>
</webHttpBinding>
</bindings>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
<services>
<service name="MyProj_A.Service1">
<endpoint address="" binding="webHttpBinding" contract="MyProj_A.IService1"
behaviorConfiguration="webBehavior"/>
<host>
<baseAddresses>
<add baseAddress="http://localhost/" />
</baseAddresses>
</host>
</service>
</services>
<diagnostics>
<endToEndTracing activityTracing="false" messageFlowTracing="true" propagateActivity="true"></endToEndTracing>
</diagnostics>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<add name="MyHTTPModule"
type="MyProj_A.MyHTTPModule,MyProj-A"/>
</modules>
<directoryBrowse enabled="false"/>
</system.webServer>
</configuration>
So my questions are
1. Why OnEnter isn't fired second time, in 8, and how is 401 assigned in an item 9?
2. How to work around this behaviour, I mean do I need to move all the authentication processing from AuthenticateRequest (OnLeave) to BeginRequest (Context_BeginRequest) for example? Or maybe there is a better place for such processing?
Thanks!
Case is closed
I've forgotten to refer to binding configuration in endpoint configuration:
<endpoint address="" binding="webHttpBinding"
contract="MyProj_A.IService1"
behaviorConfiguration="webBehavior"
**bindingConfiguration="MyBinding"**/>
Related
I try to write simple subscription service with soap and rest operations. This is my code:
SubsService.svc:
namespace SubscriptionService
{
public class SubsService : ISubsService
{
public string RegisterEvent(string serviceId, string name, string description)
{
return "ok";
}
public void UnregisterEvent(string serviceId, string name)
{
// TO DO
}
public void RiseEvent(string serviceId, string name)
{
// TO DO
}
public string EventsList(string token)
{
return token;
}
public void Subscribe(string token, string serviceId, string name)
{
// TO DO
}
public void UnSubscribe(string token, string serviceId, string name)
{
// TO DO
}
}
}
ISubsService.cs:
namespace SubscriptionService
{
[ServiceContract]
public interface ISubsService
{
// SOA
[OperationContract]
string RegisterEvent(string serviceId, string name, string description);
[OperationContract]
void UnregisterEvent(string serviceId, string name);
[OperationContract]
void RiseEvent(string serviceId, string name);
// REST
[OperationContract]
[WebGet(UriTemplate = "events?token={token}")]
string EventsList(string token);
[OperationContract]
[WebInvoke(Method = "GET", UriTemplate = "subscribe?token={token}&serviceId={serviceId}&name={name}")]
void Subscribe(string token, string serviceId, string name);
[OperationContract]
[WebInvoke(Method = "GET", UriTemplate = "unsubscribe?token={token}&serviceId={serviceId}&name={name}")]
void UnSubscribe(string token, string serviceId, string name);
}
}
and web.config:
<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5"/>
</system.web>
<system.serviceModel>
<services>
<service name="SubscriptionService.SubsService">
<endpoint address="soap" binding="basicHttpBinding" contract="SubscriptionService.ISubsService"></endpoint>
<endpoint address="rest" binding="webHttpBinding" contract="SubscriptionService.ISubsService" behaviorConfiguration="web"></endpoint>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information, set the values below to false before deployment -->
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="web">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https" />
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<!--
To browse web app root directory during debugging, set the value below to true.
Set to false before deployment to avoid disclosing web app folder information.
-->
<directoryBrowse enabled="true"/>
</system.webServer>
</configuration>
When I try to access http://localhost:2354/SubsService.svc, I get error:
Operation 'RegisterEvent' of contract 'ISubsService' specifies multiple request body parameters to be serialized without any wrapper elements. At most one body parameter can be serialized without wrapper elements. Either remove the extra body parameters or set the BodyStyle property on the WebGetAttribute/WebInvokeAttribute to Wrapped.
But RegisterEvent has to be soap operation. What is wrong with my code? Something in web.config?
I have a problem configuring a ServiceBehavior for my WCF service.
Some background.
Basically I am developing a REST service WCF that is supposed to run on IIS.
I need to be able to log exceptions thrown by the service (I'm using log4net) and return HTTP status codes depending on the type of exception.
I want my service implementation to have a minimum knowledge of WCF related stuff, so I don't want to convert the exceptions to FaultException everywhere in the service.
So I figured out that adding my own IErrorHandler to the service host would be the best way to do it.
My problem is however that no matter what I try I can't seem to get the configuration for my custom ServiceBehavior right in Web.config.
Here is the relevant code.
Web config.
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
</modules>
</system.webServer>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="UsingErrorLogBehavior">
<errorLogBehavior/>
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior>
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
<extensions>
<behaviorExtensions>
<add name="errorLogBehavior"
type="MyNameSpace.Web.ErrorExtensionElement, MyNameSpace.Web"/>
</behaviorExtensions>
</extensions>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
<standardEndpoints>
<webHttpEndpoint>
<standardEndpoint name="" helpEnabled="true"
automaticFormatSelectionEnabled="false"
defaultOutgoingResponseFormat="Json"
maxReceivedMessageSize="4194304" transferMode="Buffered" />
</webHttpEndpoint>
</standardEndpoints>
</system.serviceModel>
ErrorExtensionElement.
namespace MyNameSpace.Web
{
public class ErrorExtensionElement : BehaviorExtensionElement
{
public override Type BehaviorType
{
get { return typeof(ErrorServiceBehavior); }
}
protected override object CreateBehavior()
{
return new ErrorServiceBehavior();
}
}
}
ErrorServiceBehavior.
namespace MyNameSpace.Web
{
public class ErrorServiceBehavior : IServiceBehavior
{
public void AddBindingParameters(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
{
}
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
{
foreach (ChannelDispatcher channelDispatcher in serviceHostBase.ChannelDispatchers)
{
channelDispatcher.ErrorHandlers.Add(new ExceptionModule());
}
}
public void Validate(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
{
}
}
}
Where ExceptionModule implements IErrorHandler.
You have a <serviceBehavior> section named "UsingErrorLogBehavior", but no service configurations are referencing that section. You can either make that section the default service behavior (by not giving it a name, like you have for the endpoint behavior), or add a <service> element for your service which references that behavior:
<services>
<service name="YourNamespace.YourServiceName"
behaviorConfiguration="UsingErrorLogBehavior">
<endpoint address=""
binding="webHttpBinding"
contract="YourNamespace.YourContractName" />
</service>
</services>
Hi a have WCF service libary with this configuration:
<?xml version="1.0"?>
<configuration>
<system.serviceModel>
<services>
<service behaviorConfiguration="Default" name="ComDocs.ControlServerServiceLibary.Concrete.TokenService">
<host>
<baseAddresses>
<add baseAddress="http://localhost:8080/TokenService" />
</baseAddresses>
</host>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<endpoint address="basic" binding="basicHttpBinding" contract="ComDocs.ControlServerServiceLibary.Abstract.ITokenService" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="Default">
<serviceMetadata httpGetEnabled="true" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
If I build it in debug, everything works fine on localhost. But if I make a Windows Service library with the same configuration:
public partial class TokenService : ServiceBase
{
ServiceHost _host = null;
public TokenService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
Trace.WriteLine("Starting Token Service...");
_host = new ServiceHost(typeof(TokenService));
_host.Open();
}
protected override void OnStop()
{
Trace.WriteLine("Shutting down Token Service...");
if (_host != null)
{
_host.Close();
_host = null;
}
}
}
Install it with InstallUtil and start it:
but error:
I suspect this line is the culprit.
_host = new ServiceHost(typeof(TokenService));
TokenService is your Windows service class, not your WCF service class.
I am working on a WCF REST service that will be hosted within Azure and want to check the user id. To this end I have created a custom ServiceAuthorizationManager.
namespace SecureService
{
public class AccessControlServiceAuthorizationManager : ServiceAuthorizationManager
{
String serviceNamespace = String.Empty;
String acsHostname = String.Empty;
String trustedTokenPolicyKey = String.Empty;
String trustedAudience = String.Empty;
public AccessControlServiceAuthorizationManager()
{
try
{
serviceNamespace = RoleEnvironment.GetConfigurationSettingValue("serviceNamespace");
acsHostname = RoleEnvironment.GetConfigurationSettingValue("acsHostname");
trustedTokenPolicyKey = RoleEnvironment.GetConfigurationSettingValue("trustedTokenPolicyKey");
trustedAudience = RoleEnvironment.GetConfigurationSettingValue("trustedAudience");
}
catch
{
GenerateErrorResponse();
}
finally
{
}
} // end AccessControlServiceAuthorizationManager() Constructor
protected override bool CheckAccessCore(OperationContext operationContext)
{
String headerValue = WebOperationContext.Current.IncomingRequest.Headers[HttpRequestHeader.Authorization];
String token = String.Empty;
string[] nameValuePair = null;
TokenValidator validator = null;
if (String.IsNullOrEmpty(headerValue))
{
GenerateErrorResponse();
return false;
}
if (!headerValue.StartsWith("WRAP "))
{
GenerateErrorResponse();
return false;
}
nameValuePair = headerValue.Substring("WRAP ".Length).Split(new char[] { '=' }, 2);
if (nameValuePair.Length != 2 ||
nameValuePair[0] != "access_token" ||
!nameValuePair[1].StartsWith("\"") ||
!nameValuePair[1].EndsWith("\""))
{
GenerateErrorResponse();
return false;
}
token = nameValuePair[1].Substring(1, nameValuePair[1].Length - 2);
validator = new TokenValidator(acsHostname, serviceNamespace, trustedAudience, trustedTokenPolicyKey);
if (!validator.Validate(token))
{
GenerateErrorResponse();
return false;
}
return true;
}
public void GenerateErrorResponse()
{
}
}
}
My Web.config is as follows;
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
<behaviors>
<serviceBehaviors>
<behavior name="Secure">
<serviceAuthorization serviceAuthorizationManagerType="SecureService.AccessControlServiceAuthorizationManager" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="webBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
</behaviors>
<services>
<service name="SecureService.Demo">
<endpoint address="" behaviorConfiguration="webBehavior" binding="webHttpBinding" bindingConfiguration="" contract="SecureService.IDemo" />
<endpoint address="rest" behaviorConfiguration="webBehavior" binding="webHttpBinding" bindingConfiguration="" contract="SecureService.IDemo" />
</service>
</services>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
</modules>
</system.webServer>
However the CheckAccessCore() method does not seem to be called when I call the service via IE. So the question is how can I ensure it is called and therefore ensure that my users are validated.
I have put a break point in the CheckAccessCore and it never seems to get hit.
And just to make things really interesting - I will need to call this webservice from within Silverlight.
Thanks in advance
Ignore your 'services' section in config. Try:
<standardEndpoints>
<webHttpEndpoint>
<standardEndpoint crossDomainScriptAccessEnabled="True" automaticFormatSelectionEnabled="true" helpEnabled="True"/>
</webHttpEndpoint>
</standardEndpoints>
Following the configuration pasted above, I see that service behavior "Secure" is missed to apply on Service. Please check it, if it's not a typo...
The code below suppose to run a self hosted with custom authentication WCF Service which needs to provide its services to a Silverlight 4 client (See code below).
The result is that the infamous clientaccesspolicy Security Error communication exception is thrown even though the clientaccesspolicy.xml is visible in browser and shows no SSL error. The clientaccesspolicy.xml breakpoint is not hit.
I realize I only need to specify the entry but I've tried
various games with the clientaccesspolicy.xml which didnt work.
Your help is appreciated
1) This is the app.config and code for the service:
<?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>
The code for the service:
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) We have a CA signed SSL cert in the MY container of the LOCAL MACHINE and used netsh
netsh http add sslcert ipport=0.0.0.0:9999 certhash=aabbcc_thumbprint
appid={my_app_id_guid} clientcertnegotiation=enable
The above executes succesfully and the host loads properly and allows creating a new silverlight project.
3) The silverlight project is a just an new silveright project with add service reference and the following code:
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) This is the ServiceReferences.ClientConfig generated
<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>
Blockquote
netsh http add sslcert ipport=0.0.0.0:9999 certhash=aabbcc_thumbprint appid={my_app_id_guid} clientcertnegotiation=enable
You've used the netsh with the clientcertnegotiation flag that means the server requires client certificate. When Silverlight calls the clientaccesspolicy, it does not send a client certificate, and that is why you get the exception.
If you don't need the client certificate remove this flag.
I'm not sure if SL is able to send a client certificate when fetching the clientaccesspolicy, but if your web page also access that site the browser should use the certificate you gave it. So yo ucan try adding a link to the secured site in your hosting html/aspx which will require you to select a certificate and then SL will use that certificate