Reduce repeated nested identity in WCF config - wcf

My web.config for my WCF app has a series of endpoints defined like so:
<system.serviceModel>
<services>
<service behaviorConfiguration="whatever" name="MyService">
<endpoint name="Endpoint1" address="" binding="customBinding" bindingConfiguration="HttpIssuedTokenBinding" contract="My.App.Contract1">
<identity>
<certificateReference findValue="cert name storeName="TrustedPeople" storeLocation="LocalMachine" x509FindType="FindBySubjectName" />
</identity>
</endpoint>
<endpoint name="Endpoint2" address="" binding="customBinding" bindingConfiguration="HttpIssuedTokenBinding" contract="My.App.Contract2">
<identity>
<certificateReference findValue="cert name storeName="TrustedPeople" storeLocation="LocalMachine" x509FindType="FindBySubjectName" />
</identity>
</endpoint>
<endpoint name="Endpoint3" address="" binding="customBinding" bindingConfiguration="HttpIssuedTokenBinding" contract="My.App.Contract3">
<identity>
<certificateReference findValue="cert name storeName="TrustedPeople" storeLocation="LocalMachine" x509FindType="FindBySubjectName" />
</identity>
</endpoint>
<endpoint name="Endpoint4" address="" binding="customBinding" bindingConfiguration="HttpIssuedTokenBinding" contract="My.App.Contract4">
<identity>
<certificateReference findValue="cert name storeName="TrustedPeople" storeLocation="LocalMachine" x509FindType="FindBySubjectName" />
</identity>
</endpoint>
What I would like to do is
<system.serviceModel>
<services>
<service behaviorConfiguration="whatever" name="MyService">
<endpoint name="Endpoint1" address="" binding="customBinding" bindingConfiguration="HttpIssuedTokenBinding" contract="My.App.Contract1" />
<endpoint name="Endpoint2" address="" binding="customBinding" bindingConfiguration="HttpIssuedTokenBinding" contract="My.App.Contract2" />
<endpoint name="Endpoint3" address="" binding="customBinding" bindingConfiguration="HttpIssuedTokenBinding" contract="My.App.Contract3" />
<endpoint name="Endpoint4" address="" binding="customBinding" bindingConfiguration="HttpIssuedTokenBinding" contract="My.App.Contract4" />
with a default identity definition specified once in another place (even just a top level in the system.serviceModel element).
Basically I want to DRY, because the config is consistent all the way throughout. What I need help from SO is where does one find the "default identity for all endpoints" configuration element. MSDN isn't giving a lot of help, and I'm not sure where to reflect the .NET libs to see how this is interpreted when web.configs are read in at app startup.

Summary
Use Standard Endpoints to create a custom endpoint with the appropriate identity information, which can be configured from the configuration file.
Detail
Thank you for the question!. The uniform configuration of WCF services to reduce the configuration overhead is something I've been meaning to look into, and your question gave me just the excuse to do it.
I tackled this using Standard Endpoints, which have been around since .NET 4. The bulk of the work is done by inheriting from StandardEndpointElement:
namespace WcfEx
{
public class X509EndpointElement : StandardEndpointElement
{
private static string _findValueKey = "findValue";
private static string _storeNameKey = "storeName";
private static string _storeLocationKey = "storeLocation";
private static string _x509FindTypeKey = "x509SearchType";
public virtual string FindValue
{
get { return base[_findValueKey] as string; }
set { base[_findValueKey] = value; }
}
public virtual StoreName StoreName
{
get { return this[_storeNameKey] is StoreName ? (StoreName) this[_storeNameKey] : (StoreName) 0; }
set { this[_storeNameKey] = value; }
}
public virtual StoreLocation StoreLocation
{
get
{
return this[_storeLocationKey] is StoreLocation
? (StoreLocation) this[_storeLocationKey]
: (StoreLocation) 0;
}
set { this[_storeLocationKey] = value; }
}
public virtual X509FindType X509FindType
{
get { return this[_x509FindTypeKey] is X509FindType ? (X509FindType) this[_x509FindTypeKey] : (X509FindType) 0; }
set { this[_x509FindTypeKey] = value; }
}
protected override ConfigurationPropertyCollection Properties
{
get
{
ConfigurationPropertyCollection properties = base.Properties;
properties.Add(new ConfigurationProperty(_findValueKey, typeof (string), null,
ConfigurationPropertyOptions.None));
properties.Add(new ConfigurationProperty(_storeNameKey, typeof (StoreName), null,
ConfigurationPropertyOptions.None));
properties.Add(new ConfigurationProperty(_storeLocationKey, typeof (StoreLocation), null,
ConfigurationPropertyOptions.None));
properties.Add(new ConfigurationProperty(_x509FindTypeKey, typeof (X509FindType), null,
ConfigurationPropertyOptions.None));
return properties;
}
}
protected override Type EndpointType
{
get { return typeof (ServiceEndpoint); }
}
protected override ServiceEndpoint CreateServiceEndpoint(ContractDescription contract)
{
return new ServiceEndpoint(contract);
}
protected override void OnApplyConfiguration(ServiceEndpoint endpoint,
ServiceEndpointElement serviceEndpointElement)
{
endpoint.Address = new EndpointAddress(endpoint.Address.Uri,
EndpointIdentity.CreateX509CertificateIdentity(
GetCertificateFromStore()));
}
protected override void OnApplyConfiguration(ServiceEndpoint endpoint,
ChannelEndpointElement channelEndpointElement)
{
endpoint.Address = new EndpointAddress(endpoint.Address.Uri,
EndpointIdentity.CreateX509CertificateIdentity(
GetCertificateFromStore()));
}
private X509Certificate2 GetCertificateFromStore()
{
var certificateStore = new X509Store(StoreName, StoreLocation);
certificateStore.Open(OpenFlags.ReadOnly);
var matchingCertificates = certificateStore.Certificates.Find(X509FindType, FindValue, false);
X509Certificate2 matchingCertificate = null;
if (matchingCertificates.Count > 0)
matchingCertificate = matchingCertificates[0];
else throw new InvalidOperationException("Could not find specified certificate");
certificateStore.Close();
return matchingCertificate;
}
protected override void OnInitializeAndValidate(ChannelEndpointElement channelEndpointElement)
{
}
protected override void OnInitializeAndValidate(ServiceEndpointElement serviceEndpointElement)
{
}
}
}
A quick summary of the above code:
This class can be made visible in the .config file - so it's properties can be set through configuration;
There are four properties that specify the parameters for selecting the X509 certificate;
At some point in the lifetime of this class, the endpoint address is set with the identity specified by a certificate satisfying the search criteria.
You need a collection class in which to hold elements of the above class:
namespace WcfEx
{
public class X509EndpointCollectionElement : StandardEndpointCollectionElement<ServiceEndpoint, X509EndpointElement>
{
}
}
The system.serviceModel section of the .config file looks like this:
<system.serviceModel>
<extensions>
<endpointExtensions>
<add name="x509Endpoint" type="WcfEx.X509EndpointCollectionElement, WcfEx, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
</endpointExtensions>
</extensions>
<standardEndpoints>
<x509Endpoint>
<standardEndpoint storeLocation="LocalMachine" storeName="TrustedPeople" findValue="cert name" x509SearchType="FindBySubjectName"/>
</x509Endpoint>
</standardEndpoints>
<services>
<service name="WcfHost.Service1">
<endpoint address="" binding="wsHttpBinding" contract="WcfHost.IService1" kind="x509Endpoint" >
</endpoint>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
Things to note:
Be very careful about the value of the type attribute here - it needs to be exactly the same as typeof (X509EndpointElement).AssemblyQualifiedName.
Once registered, we can add the relevant configuration to the standardEndpoints element.
We "tag" an endpoint as having the customisation by using the kind attribute.

Related

The value could not be added to the collection, as the collection already contains an item of the same type ...

I need to customise each method in a WCF service - add logging.
So, I install a dedicated operation behavior for each operation when the service host is created:
public class CoreServiceHostFactory : ServiceHostFactory
{
#region Overrides of ServiceHostFactory
protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
var host = base.CreateServiceHost(serviceType, baseAddresses);
var operationBehavior = new WcfOperationBehavior();
host.Description.Endpoints
.SelectMany(e => e.Contract.Operations)
.ForEach(o => o.Behaviors.Add(operationBehavior));
return host;
}
#endregion
}
It works locally, but when deployed in QA fails with
The value could not be added to the collection, as the collection
already contains an item of the same type:
... This collection only
supports one instance of each type. Parameter name: item
The relevant section of the web.config is:
<services>
<service name="DeviceServices.DeviceService" behaviorConfiguration="SLDeviceServices.ServiceBehavior">
<endpoint address="" binding="basicHttpBinding" bindingConfiguration="StandardBindingSSL" contract="DeviceServices.IDeviceService">
</endpoint>
<endpoint address="" binding="basicHttpBinding" bindingConfiguration="StandardBinding" contract="DeviceServices.IDeviceService">
</endpoint>
</service>
<service name="DeviceServices.DeviceServiceJSON" behaviorConfiguration="SLDeviceServices.ServiceBehavior">
<endpoint address="" binding="webHttpBinding" bindingConfiguration="StandardBindingSSL" contract="DeviceServices.DeviceServiceJSON" behaviorConfiguration="DeviceServices.JSONDeviceServiceBehavior">
</endpoint>
<endpoint address="" binding="webHttpBinding" bindingConfiguration="StandardBinding" contract="DeviceServices.DeviceServiceJSON" behaviorConfiguration="DeviceServices.JSONDeviceServiceBehavior">
</endpoint>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="SLDeviceServices.ServiceBehavior">
<serviceMetadata httpsGetEnabled="false" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="DeviceServices.JSONDeviceServiceBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
</behaviors>
I fail to understand what is the problem. Anyone?
I found the root cause. In QA the service has two endpoints - http and https, but both are bound to the same Contract.
Hence the code
host.Description.Endpoints
.SelectMany(e => e.Contract.Operations)
.ForEach(o => o.Behaviors.Add(operationBehavior));
traverses the same Contract twice. The fix is:
host.Description.Endpoints
.Select(e => e.Contract)
.Distinct()
.SelectMany(c => c.Operations)
.ForEach(o => o.Behaviors.Add(operationBehavior));
The problem when you access multiple services.
Need to check for duplicates when adding operation behavior
host.Description.Endpoints
.Select(e => e.Contract)
.Distinct()
.SelectMany(c => c.Operations)
.ForEach(o =>
{
if(o.Behaviors.Any(x=> x.GetType().Equals(typeof(WcfOperationBehavior))))
{
o.Behaviors.Add(operationBehavior));
}
});

Error In consuming WCF services at client side end-point not found

I am working on ASP.NET WCF simple HelloWorld Example. I have successfully completed server side but I am getting issue while working on client side. I have used SVCUTIL.exe to generate proxy classes for me.
On debug I am getting following error;
An exception of type 'System.InvalidOperationException' occurred in System.ServiceModel.dll but was not handled in user code
Additional information: Could not find endpoint element with name 'WSHttpBinding_IHelloWorldService' and contract 'IHelloWorldService' in the ServiceModel client configuration section. This might be because no configuration file was found for your application, or because no endpoint element matching this name could be found in the client element.
another thing, can I use Channel Factory if I don't access to dll file from server, say If I got access to WSDL url link
On Client Side app.config
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IHelloWorldService" />
<binding name="WSHttpBinding_IHelloWorldServiceAsyn" />
</wsHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:8087/CreditUnionServices/HelloWorldServices/HelloWorldService"
binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IHelloWorldService"
contract="IHelloWorldService" name="WSHttpBinding_IHelloWorldService">
<identity>
<userPrincipalName value="DESKTOP-G6LE8I4\Khurram Zahid" />
</identity>
</endpoint>
<endpoint address="http://localhost:8087/CreditUnionServices/HelloWorldServices/HelloWorldServiceAsyn"
binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IHelloWorldServiceAsyn"
contract="IHelloWorldServiceAsyn" name="WSHttpBinding_IHelloWorldServiceAsyn">
<identity>
<userPrincipalName value="xyz\abc" />
</identity>
</endpoint>
</client>
</system.serviceModel>
Client Proxy Channel Factory
public class HelloWorldClient
{
public string SendTestMessage(string name)
{
ChannelFactory<IHelloWorldService> _HelloWorldClientService = new ChannelFactory<IHelloWorldService>("WSHttpBinding_IHelloWorldService");
IHelloWorldService _HelloWorldChannelService = _HelloWorldClientService.CreateChannel();
var _returnMessage = _HelloWorldChannelService.GetMessage(name);
((IClientChannel)_HelloWorldChannelService).Close();
return _returnMessage;
}
}
Server side config file
<system.serviceModel>
<services>
<service name="App.Services.Managers.HelloWorldManager" behaviorConfiguration="DefaultServiceBehavior">
<host>
<baseAddresses>
<add baseAddress="http://localhost:8087/CreditUnionServices/HelloWorldServices"/>
</baseAddresses>
</host>
<endpoint address="HelloWorldService" binding="wsHttpBinding" contract="App.Services.Contracts.IHelloWorldService"></endpoint>
<endpoint address="HelloWorldServiceAsyn" binding="wsHttpBinding" contract="App.Services.Contracts.IHelloWorldServiceAsyn"></endpoint>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="DefaultServiceBehavior">
<serviceMetadata httpGetEnabled="True" httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="False" />
</behavior>
</serviceBehaviors>
</behaviors>
Update Code
public static class HelloWorldClient
{
public static string SendTestMessage(string name)
{
HelloWorldServiceClient _helloWorldService = new HelloWorldServiceClient("WSHttpBinding_IHelloWorldService");
var _returnMessage = _helloWorldService.GetMessage("mr kz ....");
return _returnMessage;
}
}

WCF Web Service Hosted in SharePoint 2010 browser blank page response

I'm facing a problem with SharePoint 2010 custom web service.
The service is an SVC installed and deployed on the system: without particular configuration it works but I need to customize the web.config to achieve some security roles.
The problems is that when I try to invoke methods from browser the response is empty.
This is my web.config
<?xml version="1.0"?>
<configuration>
<system.serviceModel>
<services>
<service name="SharePointWCFService.GetListData"
behaviorConfiguration="WCFBasicHttpBinding.Service1Behavior">
<endpoint address="http://address" binding="basicHttpBinding" contract="SharePointWCFService.IGetListData">
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
<endpoint address="http://address" binding="WebHttpBinding" contract="SharePointWCFService.IGetListData" >
<identity>
<dns value="localhost" />
</identity>
</endpoint>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="WCFBasicHttpBinding.Service1Behavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
This is the interface I'm implementing:
[ServiceContract]
public interface IGetListData
{
[OperationContract]
[WebInvoke(Method = "GET", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)]
JSonResult GetJsonResponse(string data);
}
And this the class
[BasicHttpBindingServiceMetadataExchangeEndpointAttribute]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
class GetListData : IGetListData
{
private const string Admin_Svc_GetListData = "Admin_Svc_GetListData";
public JSonResult GetJsonResponse(string data)
{
return new JSonResult()
{
Firstname = "MyFirstname",
Lastname = "MyLastname"
};
} // public JSonResult GetJsonResponse(string data)
Do I must declare something different at web.config side?

Trying to get basic Http URL with querystring parameters processed in WCF service

I'm trying to process a post by a third party server (Paypal) processed by my server through a WCF (.Net 3.5 SP1) service. All I need is to get and process the values with the query string. This sounds incredibly easy, but after a weekend, I'm still stumped. Any help would be greatly appreciated.
Passing the following URL from my browser to the service causes a AddressFilter mismatch fault (below).
http://localhost:9409/PPInfo.svc/ReadResponse?RESULT=0&AUTHCODE=10001&RESPMSG=APROVED&PNREF=12345
produces
<Fault xmlns="http://schemas.microsoft.com/ws/2005/05/envelope/none">
- <Code>
<Value>Sender</Value>
- <Subcode>
<Value xmlns:a="http://schemas.microsoft.com/ws/2005/05/addressing/none">a:DestinationUnreachable</Value>
</Subcode>
</Code>
- <Reason>
<Text xml:lang="en-US">The message with To 'http://localhost:9409/PPInfo.svc/ReadResponse?RESULT=0&AUTHCODE=10001&RESPMSG=APROVED&PNREF=12345' cannot be processed at the receiver, due to an AddressFilter mismatch at the EndpointDispatcher. Check that the sender and receiver's EndpointAddresses agree.</Text>
</Reason>
</Fault>
// web.config
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="ASEEESPrivate.PPInfoBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="ASEEESPrivate.PPInfoBehavior" name="ASEEESPrivate.PPInfo">
<endpoint address="" binding="webHttpBinding" contract="ASEEESPrivate.IPPInfo">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
</system.serviceModel>
</configuration>
================================
[ServiceContract]
public interface IPPInfo
{
// expecting RESULT = 0 and RESPMSG = APPROVED
[OperationContract]
[WebGet(UriTemplate = "Presponse?RESULT={result}&AUTHCODE={authcode}&RESPMSG={respmsg}&AVSDATA={avsdata}&PNREF={pnref}",
BodyStyle = WebMessageBodyStyle.Bare, RequestFormat = WebMessageFormat.Xml)]
void ReadResponse();
}
=========================================
// write parameters of query string to tlkpOnlineMessage table
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, AddressFilterMode=AddressFilterMode.Any)]
public class PPInfo : IPPInfo
{
public void ReadResponse()
{
var qString = HttpContext.Current.Request.QueryString;
var ctx =
new MembershipEntities();
var log = new tlkpOnlineMessage();
foreach (string s in qString)
{
log.LoginPageMsg = s;
ctx.AddTotlkpOnlineMessages(log);
}
ctx.SaveChanges();
}
}
Besides the typo in your code, I believe you have two problems that are easily correctable:
1) For a RESTful service, you should define an endpoint behavior and enable the webHttp behavior. You can do this by adding an <endpointBehavior> to your web.config as such:
<behaviors>
<serviceBehaviors>
<behavior name="ASEEESPrivate.PPInfoBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="ASEEESPrivate.PPInfoEndpointBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
</behaviors>
And then add this endpoint behavior to your service definition:
<service behaviorConfiguration="ASEEESPrivate.PPInfoBehavior" name="WcfRestService1.PPInfo">
<endpoint address="" binding="webHttpBinding" contract="WcfRestService1.IPPInfo"
behaviorConfiguration="ASEEESPrivate.PPInfoEndpointBehavior">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
2) Secondly, you define a UriTemplate for your service with placeholders (result, authcode, etc.) but you don't define parameters for them in your interface. If you're going to define a UriTemplate for your service definition with placeholders, then you need to have your service define those parameters accordingly. You can do that as such:
[ServiceContract]
public interface IPPInfo
{
// expecting RESULT = 0 and RESPMSG = APPROVED
[OperationContract]
[WebGet(UriTemplate = "ReadResponse?RESULT={result}&AUTHCODE={authcode}&RESPMSG={respmsg}&AVSDATA={avsdata}&PNREF={pnref}",
BodyStyle = WebMessageBodyStyle.Bare, RequestFormat = WebMessageFormat.Xml)]
void ReadResponse(string result, string authcode, string respmsg, string avsdata, string pnref);
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, AddressFilterMode = AddressFilterMode.Any)]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class PPInfo : IPPInfo
{
public void ReadResponse(string result, string authcode, string respmsg, string avsdata, string pnref)
{
...
}
}
By using a UriTemplate, you don't need to extract your querystring parameters out; or, if you want to extract parameters from your querystring, don't define a UriTemplate.
Once I made these two changes, I was able to get the service to run locally on my machine.
I hope this helps!

Securing WCF service endpoint with custom authentication

I want to secure some endpoint of a WCF service, i dont know if you can secure some endpoint and some not. Below I have the stripped WCF service (self hosted). The same WCF serves also the CA Policy file. If I secure this WCF service or some endpoints of ut the CA Policy part must not ask me a username password. The policy file must be accessible all the time. Is that also possible?
I found alot WCF custom blogs/postings. There are alot of ways to do security. All I want is that I can secure some endpoints with username/password but the credentials must not be visible with tools like Fiddler. The data however it can be visible in this case.
I implemented already a Customvalidator but the app.config file is also importent to define things. And I am not very good at that.
namespace WindowsFormsApplication11
{
public partial class Form1 : Form
{
public ServiceHost _host = null;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
// Create a ServiceHost for the CalculatorService type and
// provide the base address.
_host = new ServiceHost(typeof(WmsStatService));
_host.AddServiceEndpoint(typeof(IPolicyProvider), new WebHttpBinding(), "").Behaviors.Add(new WebHttpBehavior());
_host.Open();
}
}
// Define a service contract.
[ServiceContract(Namespace = "http://WindowsFormsApplication11")]
public interface IWmsStat
{
[OperationContract]
string getConnectedViewers(string channelName);
[OperationContract]
string sayHello(string name);
}
[ServiceContract]
public interface IPolicyProvider
{
[OperationContract, WebGet(UriTemplate = "/ClientAccessPolicy.xml")]
Stream ProvidePolicy();
}
//[DataContract]
public class Ads
{
// [DataMember]
public string AdFileName { get; set; }
//[DataMember]
public string AdDestenationUrl { get; set; }
public string ConnectedUserIP { get; set; }
}
//
public class CustomValidator : UserNamePasswordValidator
{
public override void Validate(string userName, string password)
{
if(null == userName || null == password)
{
throw new ArgumentNullException();
}
if(userName == "Oguz" && password == "2009")
{
return;
}
FaultCode fc = new FaultCode("ValidationFailed");
FaultReason fr = new FaultReason("Good reason");
throw new FaultException(fr,fc);
}
}
//
public class WmsStatService : IWmsStat, IPolicyProvider
{
public string sayHello(string name)
{
return "hello there " + name + " nice to meet you!";
}
public Stream ProvidePolicy()
{
WebOperationContext.Current.OutgoingResponse.ContentType = "application/xml";
return new MemoryStream(File.ReadAllBytes("ClientAccessPolicy.xml"), false);
}
public string getConnectedViewers(string channelname)
{
// do stuff
return null;
}
}
}
The app.config. This config file does not work. I wanted to put the custom authentication for a endpoint. I have no clue.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<services>
<service name="WindowsFormsApplication11.WmsStatService" behaviorConfiguration="mex">
<host>
<baseAddresses>
<add baseAddress="http://192.168.0.199:87" />
</baseAddresses>
</host>
<endpoint address="http://192.168.0.199:87/Test" binding="basicHttpBinding" bindingConfiguration="" contract="WindowsFormsApplication11.IWmsStat" behaviorConfiguration="MyServiceBehavior" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
<!--<bindings>
<wsHttpBinding>
<binding name="wshttp">
<security mode="Message">
<message clientCredentialType="UserName" />
</security>
</binding>
</wsHttpBinding>
</bindings>-->
<behaviors>
<serviceBehaviors>
<behavior name="mex">
<serviceMetadata httpGetEnabled="true" httpGetUrl=""/>
</behavior>
<behavior name="MyServiceBehavior">
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="WindowsFormsApplication11.CustomValidator, CustomValidator" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
I want to secure some endpoint of a
WCF service, i dont know if you can
secure some endpoint and some not.
Sure - you just need to create two separate binding configurations, and use one on those endpoints that are secured, the other on the others:
<bindings>
<basicHttpBinding>
<binding name="secured">
<security mode="Message">
<message ...... />
</security>
</binding>
<binding name="unsecured">
<security mode="None" />
</binding>
</basicHttpBinding>
</bindings>
<services>
<service name="WindowsFormsApplication11.WmsStatService" behaviorConfiguration="mex">
<host>
<baseAddresses>
<add baseAddress="http://192.168.0.199:87" />
</baseAddresses>
</host>
<endpoint address="/Secured/Test"
binding="basicHttpBinding" bindingConfiguration="secured"
contract="WindowsFormsApplication11.IWmsStat"
behaviorConfiguration="MyServiceBehavior" />
<endpoint address="/Unsecured/Test"
binding="basicHttpBinding" bindingConfiguration="unsecured"
contract="WindowsFormsApplication11.IWmsStat"
behaviorConfiguration="MyServiceBehavior" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
Marc
PS: not sure if that's just a problem with your postings not being up to date anymore - have you noticed, that you have two separate behavior configurations:
<behaviors>
<serviceBehaviors>
<behavior name="mex">
<serviceMetadata httpGetEnabled="true" httpGetUrl=""/>
</behavior>
<behavior name="MyServiceBehavior">
<serviceCredentials>
<userNameAuthentication
userNamePasswordValidationMode="Custom"
customUserNamePasswordValidatorType="WindowsFormsApplication11.CustomValidator, CustomValidator" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
and your service is only referencing the "mex" behavior? That means, your service is indeed using the <serviceMetadata> behavior - but NOT the <serviceCredentials> one!
You need to merge these into one and then reference just that:
<behaviors>
<serviceBehaviors>
<behavior name="Default">
<serviceMetadata httpGetEnabled="true" httpGetUrl=""/>
<serviceCredentials>
<userNameAuthentication
userNamePasswordValidationMode="Custom"
customUserNamePasswordValidatorType="WindowsFormsApplication11.CustomValidator, CustomValidator" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="...." behaviorConfiguration="Default"
Marc
If you want to protect entire message, Transport security mode is a way to go. If you want to only your headers to be encrypted/signed, Message security mode allows this, but you'll have to use wsHttpBinding. You may also consider using Digest to protect credentials.
As for your example, I think your commented part should look like this:
<bindings>
<basicHttpBinding>
<binding name="secure">
<security mode="Transport">
<transport clientCredentialType="Basic" />
</security>
</binding>
</basicHttpBinding>
</bindings>
You'll also have to update your endpoint declaration:
<endpoint
address="https://192.168.0.199:87/Test"
binding="basicHttpBinding" bindingConfiguration="secure"
contract="WindowsFormsApplication11.IWmsStat" />
You won't be allowed to use plain HTTP with transport security mode.