Web Service user authentication - c#

I'm trying to develop web service client with user authorization.
I've added service references to my project but now i've stuck on user authentication,
all i get is:
The HTTP request is unauthorized with client authentication scheme 'Anonymous'.
This is how i call my webservice:
BasicHttpBinding a = new BasicHttpBinding("MyWebService1");
a.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;
a.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName;
MyWebService1Client mySeviceClient= new MyWebService1Client();
mySeviceClient= new MyWebService1Client(a, mySeviceClient.Endpoint.Address);
mySeviceClient.ClientCredentials.UserName.UserName = "test2";
mySeviceClient.ClientCredentials.UserName.Password = "password";
try
{
mySeviceClient.Open();
MyWebService1 myWebService= mySeviceClient;
myRequest req = new myRequest(1234, "Test");
myResponse res = myWebService.getMyData(req);
mySeviceClient.Close();
}
catch (AddressAccessDeniedException adExc)
{
Console.WriteLine(adExc.Message);
Console.ReadLine();
}
catch (System.Exception exc)
{
Console.WriteLine(exc.Message);
Console.ReadLine();
}
And here is my app.config file
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="MyWebService1"/>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:7002/WSauth-WS_auth-context-root/MyWebService1Port"
binding="basicHttpBinding" bindingConfiguration="MyWebService1"
contract="TestWs.MyWebService1" name="MyWebService1Port" />
</client>
</system.serviceModel>
</configuration>

Related

Connect to SSL SOAP Host via "Service Reference" and pass Security Header

I am trying to connect to a SSL SOAP service host by C# using Service Reference.
This is my request message:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<s:Header>
<VsDebuggerCausalityData xmlns="http://schemas.microsoft.com/vstudio/diagnostics/servicemodelsink">uIDPo/zwMmtdsVhFsAVDkQbiV/4AAAAA1zXtnc72UEm+4tlKzvCxsvN6OC2prvRIljIX4XzHKEYACQAA</VsDebuggerCausalityData>
<o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<u:Timestamp u:Id="_0">
<u:Created>2016-03-18T12:45:27.558Z</u:Created>
<u:Expires>2016-03-18T12:50:27.558Z</u:Expires>
</u:Timestamp>
<o:UsernameToken u:Id="uuid-2c7986ba-eee5-4411-90a9-a02b625c55ff-1">
<o:Username>MyUserName</o:Username>
<o:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">MyPlainPassword</o:Password>
</o:UsernameToken>
</o:Security>
</s:Header>
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<generateId xmlns="http://com.vedaadvantage/dp3/Enterprise/StandardTradeCreditCommercial/IndividualCommercialService"/>
</s:Body>
</s:Envelope>
This is the message that my service sends to the host. But the host returns as below:
Security processor was unable to find a security header in the message. This might be because the message is an unsecured fault or because there is a binding mismatch between the communicating parties. This can occur if the service is configured for security and the client is not using security.
This is my config file:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<bindings>
<customBinding>
<binding name="myBinding">
<textMessageEncoding messageVersion="Soap11" />
<security authenticationMode="UserNameOverTransport"
messageSecurityVersion="WSSecurity10WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10" >
</security>
<httpsTransport />
</binding>
</customBinding>
</bindings>
<client>
<endpoint address="https://{URL}"
binding="customBinding"
bindingConfiguration="myBinding"
contract="ServiceReference2.MyService"
name="IndividualCommercialService" />
</client>
</system.serviceModel>
</configuration>
Although when I send the same XML via SOAPUI or other HTTP Post methods it works fine.
I also extract and attached the certificate and user/pass as below:
private static X509Certificate2 DownloadSslCertificate(string strDNSEntry)
{
X509Certificate2 cert = null;
using (TcpClient client = new TcpClient())
{
//ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;
client.Connect(strDNSEntry, 443);
SslStream ssl = new SslStream(client.GetStream(), false, new RemoteCertificateValidationCallback(ValidateServerCertificate), null);
try
{
ssl.AuthenticateAsClient(strDNSEntry);
}
catch (AuthenticationException e)
{
//log.Debug(e.Message);
ssl.Close();
client.Close();
return cert;
}
catch (Exception e)
{
//log.Debug(e.Message);
ssl.Close();
client.Close();
return cert;
}
cert = new X509Certificate2(ssl.RemoteCertificate);
ssl.Close();
client.Close();
return cert;
}
}
private static void Main(string[] args){
var proxy = new MyService();
var uri = proxy.Endpoint.Address.Uri;
var cer = DownloadSslCertificate(uri.DnsSafeHost);
EndpointIdentity identity = EndpointIdentity.CreateDnsIdentity(cer.Subject.Replace("CN=", ""));
EndpointAddress address = new EndpointAddress(proxy.Endpoint.Address.Uri, identity);
proxy.Endpoint.Address = address;
proxy.ClientCredentials.UserName.UserName = "MyUserName";
proxy.ClientCredentials.UserName.Password = "MyPlainPassword";
proxy.ClientCredentials.ServiceCertificate.DefaultCertificate = cer;
proxy.HellowWorld();
}
I am not sure whether the method that I am getting the certificate is correct or not and also why HTTP Post works but my Service Reference Call does not.
Thanks in advance for your help.
Cheers
Try to look inside WSDL (Service References) in order to see hidden files first select Show All Files in Solution explorer.
You`ll se inside service reference Reference.svcmap -> Reference.cs, and inside of this file add ProtectionLevel = System.Net.Security.ProtectionLevel.Sign
as shown below
[System.ServiceModel.ServiceContractAttribute(Namespace = "http://www.your.url/Service/", ConfigurationName = "Service.Service", ProtectionLevel = System.Net.Security.ProtectionLevel.Sign)]
that should help you. Usually it`s really bad idea to modify autogenerated proxy, but seems like that is the only option.

Running wcf service without App.config doesn't work

I create simple wcf host in console application. It doesn't work and the exception make NO SENSE:/
The exception looks really wierd:
"ContractDescription 'IFooService' has zero operations; a contract
must have at least one operation."
because, here is the code and i I have an operation:
[ServiceContract]
public interface IFooService
{
[OperationContract]
void DoNothing();
[OperationContract]
int GetFoo(int i);
}
public class FooService : IFooService
{
public void DoNothing()
{
}
public int GetFoo(int i)
{
return i + 1;
}
}
class Program
{
static void Main(string[] args)
{
try
{
string address = "http://localhost:9003/FooService";
Uri addressBase = new Uri(address);
var svcHost = new ServiceHost(typeof(FooService), addressBase);
BasicHttpBinding bHttp = new BasicHttpBinding();
Type contractType = typeof(IFooService);
ContractDescription contractDescription = new ContractDescription(contractType.Name);
contractDescription.ProtectionLevel = ProtectionLevel.None;
contractDescription.ContractType = contractType;
contractDescription.ConfigurationName = contractType.FullName;
contractDescription.SessionMode = SessionMode.NotAllowed;
svcHost.AddServiceEndpoint(new ServiceEndpoint(contractDescription, bHttp, new EndpointAddress(address)));
svcHost.Open();
Console.WriteLine("\n\nService is Running as >> " + address);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
Console.ReadKey();
}
}
This is basically entire code. App.config is left untouched:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup>
</configuration>
EDIT: A little clue, this way it works: I didn't change service or contract, but moved configuration to App.config, so changed only Main method:
App.config:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup>
<system.serviceModel>
<services>
<service name="WcfDemos.ConsoleHost.FooService">
<endpoint address="http://localhost:9003/FooService" binding="basicHttpBinding"
contract="WcfDemos.ConsoleHost.IFooService" />
</service>
</services>
</system.serviceModel>
</configuration>
Main:
static void Main(string[] args)
{
try
{
string address = "http://localhost:9003/FooService";
Uri addressBase = new Uri(address);
var svcHost = new ServiceHost(typeof(FooService), addressBase);
svcHost.Open();
Console.WriteLine("\n\nService is Running as >> " + address);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
Console.ReadKey();
}
Why do you need to use the ContractDescription? I suppose it looks for the settings in the configuration file.
You may do the following (use the AddServiceEndpoint method without ContractDescription):
static void Main(string[] args)
{
try
{
string address = "http://localhost:9003/FooService";
Uri addressBase = new Uri(address);
var svcHost = new ServiceHost(typeof(FooService), addressBase);
BasicHttpBinding bHttp = new BasicHttpBinding();
//Type contractType = typeof(IFooService);
//ContractDescription contractDescription = new ContractDescription(contractType.Name);
//contractDescription.ProtectionLevel = ProtectionLevel.None;
//contractDescription.ContractType = contractType;
//contractDescription.ConfigurationName = contractType.FullName;
//contractDescription.SessionMode = SessionMode.NotAllowed;
//svcHost.AddServiceEndpoint(new ServiceEndpoint(contractDescription, bHttp, new EndpointAddress(address)));
svcHost.AddServiceEndpoint(typeof(IFooService).ToString(), bHttp, address);
svcHost.Open();
Console.WriteLine("\n\nService is Running as >> " + address);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
Console.ReadKey();
}
BTW here you may find some library for configuring your WCF services without app.config files: WCF NetTcpBinding Bootcamp
I believe you have to add an endpoint to the ServiceHost if you don't provide the endpoints in the config file. See the AddServiceEndpoint call:
Uri baseAddr = new Uri("http://localhost:8000/WCFService1");
ServiceHost localHost = new ServiceHost(typeof(CalculatorService), baseAddr);
try
{
localHost.AddServiceEndpoint(typeof(ICalculator), new WSHttpBinding(), "CalculatorService");
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
localHost.Description.Behaviors.Add(smb);
localHost.Open();
Console.WriteLine("Service initialized.");
Console.WriteLine("Press the ENTER key to terminate service.");
Console.WriteLine();
Console.ReadLine();
localHost.Close();
}
catch (CommunicationException ex)
{
Console.WriteLine("Oops! Exception: {0}", ex.Message);
localHost.Abort();
}
http://www.programminghelp.com/dotnet/wcf-creating-and-implementing-a-service-in-c/
The above comes from Microsoft example:
https://learn.microsoft.com/en-us/dotnet/framework/wcf/how-to-host-and-run-a-basic-wcf-service
which is a great place to start. Nonetheless ... it is still unclear what needs to be added in code to make the app.config content below redundant:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
</appSettings>
<system.web>
<compilation debug="true" />
</system.web>
<!-- When deploying the service library project, the content of the config file must be added to the host's
app.config file. System.Configuration does not support config files for libraries. -->
<system.serviceModel>
<services>
<service name="GettingStartedLib.CalculatorService">
<host>
<baseAddresses>
<add baseAddress = "http://localhost:8000/GettingStarted/CalculatorService" />
</baseAddresses>
</host>
<!-- Service Endpoints -->
<!-- Unless fully qualified, address is relative to base address supplied above -->
<endpoint address="" binding="wsHttpBinding" contract="GettingStartedLib.ICalculator">
<!--
Upon deployment, the following identity element should be removed or replaced to reflect the
identity under which the deployed service runs. If removed, WCF will infer an appropriate identity
automatically.
-->
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<!-- Metadata Endpoints -->
<!-- The Metadata Exchange endpoint is used by the service to describe itself to clients. -->
<!-- This endpoint does not use a secure binding and should be secured or removed before deployment -->
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</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>
</behaviors>
</system.serviceModel>
</configuration>

WCF REST service url routing based on query parameters

Since WCF routing doesn't support routing for REST services, I created a REST service that has one enpoint which accepts all incoming requests and than redirects those requests based on the query parameters.
I did this by following this article http://blog.tonysneed.com/2012/04/24/roll-your-own-rest-ful-wcf-router/.
This approach works for passing through requests and returning the results. The problem is whenever I get an error, like a 404, from the actual service the message that is returned to the client is a 400 (Bad Request).
What I would like to have is a routing proxy that actually just redirects the calls to the real service based on the query and returns all the errors to the client as they come from the real service.
Is this even the right approach to what I'm trying to accomplish, or are there easier or better solutions?
Any help is appreciated!
In the following I added what my code looks like.
app.config:
<!--
System.net
-->
<system.net>
<settings>
<servicePointManager expect100Continue="false" useNagleAlgorithm="false" />
</settings>
<connectionManagement>
<add address="*" maxconnection="24" />
</connectionManagement>
</system.net>
<!--
System.ServiceModel
-->
<system.serviceModel>
<!--
Services
-->
<services>
<service name="RoutingGateway.RoutingService">
<endpoint address="/api/routing" binding="webHttpBinding" bindingConfiguration="secureWebHttpBinding" contract="RoutingGateway.IRoutingService" behaviorConfiguration="RESTBehaviour" />
</service>
</services>
<client>
<endpoint binding="webHttpBinding" bindingConfiguration="secureWebHttpBinding" contract="RoutingGateway.IRoutingService" name="routingService" behaviorConfiguration="RESTBehaviour" />
</client>
<!--
Bindings
-->
<bindings>
<webHttpBinding>
<binding name="secureWebHttpBinding" hostNameComparisonMode="StrongWildcard" maxReceivedMessageSize="2147483647" transferMode="Streamed">
<security mode="Transport">
<transport clientCredentialType="None" />
</security>
</binding>
</webHttpBinding>
</bindings>
<!--
Behaviors
-->
<behaviors>
<endpointBehaviors>
<behavior name="RESTBehaviour">
<dispatcherSynchronization asynchronousSendEnabled="true" />
<webHttp helpEnabled="true" />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information, set the value below to false before deployment -->
<serviceMetadata httpsGetEnabled="false" />
<!-- 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" />
<!-- Enable Throttling -->
<serviceThrottling maxConcurrentCalls="100" maxConcurrentInstances="100" maxConcurrentSessions="100" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
IRoutingService.cs:
[ServiceContract(Namespace = "https://test/api/routing")]
public interface IRoutingService
{
[OperationContract(Action = "*", ReplyAction = "*")]
[WebInvoke(UriTemplate = "*", Method = "*")]
Message ProcessRequest(Message requestMessage);
}
RoutingService.cs:
public Message ProcessRequest(Message requestMessage)
{
ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, errors) => true;
Uri originalRequestUri = WebOperationContext.Current.IncomingRequest.UriTemplateMatch.RequestUri;
// Gets the URI depending on the query parameters
Uri uri = GetUriForRequest(requestMessage);
// Select rest client endpoint
string endpoint = "routingService";
// Create channel factory
var factory = new ChannelFactory<IRoutingService>(endpoint);
Uri requestUri = new Uri(uri, originalRequestUri.PathAndQuery);
factory.Endpoint.Address = new EndpointAddress(requestUri);
requestMessage.Headers.To = requestUri;
// Create client channel
_client = factory.CreateChannel();
// Begin request
Message result = _client.ProcessRequest(requestMessage);
return result;
}
I ended up catching all CommunicationExceptions and then rethrowing WebFaultExceptions with the appropriate messages and status codes.
Here is the code:
Message result = null;
try
{
result = _client.ProcessRequest(requestMessage);
}
catch (CommunicationException ex)
{
if (ex.InnerException == null ||
!(ex.InnerException is WebException))
{
throw new WebFaultException<string>("An unknown internal Server Error occurred.",
HttpStatusCode.InternalServerError);
}
else
{
var webException = ex.InnerException as WebException;
var webResponse = webException.Response as HttpWebResponse;
if (webResponse == null)
{
throw new WebFaultException<string>(webException.Message, HttpStatusCode.InternalServerError);
}
else
{
var responseStream = webResponse.GetResponseStream();
string message = string.Empty;
if (responseStream != null)
{
using (StreamReader sr = new StreamReader(responseStream))
{
message = sr.ReadToEnd();
}
throw new WebFaultException<string>(message, webResponse.StatusCode);
}
else
{
throw new WebFaultException<string>(webException.Message, webResponse.StatusCode);
}
}
}
}

'https' is invalid; expected 'http'

I have been trying to send ping request to https://americas-uapi.copy-webservices.travelport.com/B2BGateway/connect/uAPI/SystemService but i am receiving following error:
Error making ping request: The provided URI scheme 'https' is invalid; expected 'http'.
The end point provided to me uses https. How can I correct this error?
Here is my web.config
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" />
</system.web>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="ExternalCacheAccessBinding" />
<binding name="SystemPingBinding" />
<binding name="SystemInfoBinding" />
<binding name="SystemTimeBinding" />
</basicHttpBinding>
</bindings>
<client>
<endpoint address="https://americas-uapi.copy-webservices.travelport.com/B2BGateway/connect/uAPI/SystemService"
binding="basicHttpBinding" bindingConfiguration="ExternalCacheAccessBinding"
contract="WSDLService.ExternalCacheAccessPortType" name="ExternalCacheAccessPort" />
<endpoint address="https://americas-uapi.copy-webservices.travelport.com/B2BGateway/connect/uAPI/SystemService"
binding="basicHttpBinding" bindingConfiguration="SystemPingBinding"
contract="WSDLService.SystemPingPortType" name="SystemPingPort" />
<endpoint address="https://americas-uapi.copy-webservices.travelport.com/B2BGateway/connect/uAPI/SystemService"
binding="basicHttpBinding" bindingConfiguration="SystemInfoBinding"
contract="WSDLService.SystemInfoPortType" name="SystemInfoPort" />
<endpoint address="https://americas-uapi.copy-webservices.travelport.com/B2BGateway/connect/uAPI/SystemService"
binding="basicHttpBinding" bindingConfiguration="SystemTimeBinding"
contract="WSDLService.SystemTimePortType" name="SystemtimePort" />
</client>
</system.serviceModel>
This is the request I am sending following a tutorial:
// PING REQUEST
//
String payload= "this my payload; there are many like it but this one is mine";
String someTraceId = "doesntmatter-8176";
//set up the request parameters into a PingReq object
PingReq req = new PingReq();
PingRsp rsp = new PingRsp();
req.Payload=payload;
req.TraceId=someTraceId;
SystemPingPortTypeClient port = new SystemPingPortTypeClient();
try {
//run the ping request
UserNamePasswordClientCredential creds = port.ClientCredentials.UserName;
creds.UserName = "MyUserName";
creds.Password = "MyPassword";
rsp = port.service(req);
//print results.. payload and trace ID are echoed back in response
Label1.Text = rsp.Payload;
Label2.Text = rsp.TraceId;
Label3.Text = rsp.TransactionId;
}
catch (Exception ex) {
//usually only the error message is useful, not the full stack
//trace, since the stack trace in is your address space...
Label1.Text = "Error making ping request: " + ex.Message;
<security mode="Transport"> in Servicereference.ClientConfig file
Here
Check here too
UPDATE : As per your comments :
<bindings>
<basicHttpBinding>
<security mode="Transport">

SSL client/server mutual authentication

Hello I am trying to do in C# an ssl client/server communication with mutual authentication using server and client certificate. A managed to do the ssl communication only using server certificate, where on the client side I use sth like that:
TcpClient client = new TcpClient(machineName, port);
//Create an SSL stream that will close the client's stream.
SslStream sslStream = new SslStream(
client.GetStream(),
false,
new RemoteCertificateValidationCallback(ValidateServerCertificate),
null
);
try
{
// The server name must match the name on the server certificate.
sslStream.AuthenticateAsClient(serverName);
}
catch (AuthenticationException e)
{
Console.WriteLine("Exception: {0}", e.Message);
if (e.InnerException != null)
{
Console.WriteLine("Inner exception: {0}", e.InnerException.Message);
}
Console.WriteLine("Authentication failed - closing the connection.");
client.Close();
return;
}
I assume I would need to use
AuthenticateAsClient(string targetHost, X509CertificateCollection clientCertificates, SslProtocols enabledSslProtocols, bool checkCertificateRevocation)
method, am I corrent? Could anyone please show me how to use it with all things around?Even on the server side, or point me to a basic example?
Thank you a lot.
static void HTTPSClient()
{
try
{
string message = "GET / HTTP/1.0\r\nHost: host.com\r\n\r\n";
byte[] data = System.Text.Encoding.ASCII.GetBytes(message);
string server = "host.com";
int nPort = 443;
TcpClient client = new TcpClient(server, nPort);
X509Certificate2Collection cCollection = new X509Certificate2Collection();
cCollection.Add(new X509Certificate2("cert.pfx", "password"));
using (SslStream sslStream = new SslStream(client.GetStream(), false, new RemoteCertificateValidationCallback(ValidateServerCertificate), null))
{
// Add a client certificate to the ssl connection
sslStream.AuthenticateAsClient(server, cCollection, System.Security.Authentication.SslProtocols.Default, true);
sslStream.Write(data, 0, data.Length);
data = new Byte[8192];
int bytes = 0;
string responseData = "";
do
{
bytes = sslStream.Read(data, 0, data.Length);
if (bytes > 0)
{
responseData += System.Text.Encoding.ASCII.GetString(data, 0, bytes);
}
}
while (bytes > 0);
Console.WriteLine("Response: " + responseData);
}
// Disconnect and close the client
client.Close();
}
catch (Exception ex)
{
Console.WriteLine("Error: " + ex.ToString());
}
}
public static bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
if (sslPolicyErrors == SslPolicyErrors.None)
return true;
Console.WriteLine("Certificate error: {0}", sslPolicyErrors);
// Do not allow this client to communicate with unauthenticated servers.
return false;
}
You need a x509 self certificate, to create it simple, download pluralsight self cert
Generate certificate as in image
Create new web site, there choose wcf service.
Add in solution new console application, to test our service.
In web.config of service put configuration:
<?xml version="1.0"?>
<configuration>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceCredentialsBehavior">
<serviceCredentials>
<serviceCertificate findValue="cn=cool" storeName="TrustedPeople" storeLocation="CurrentUser" />
</serviceCredentials>
<serviceMetadata httpGetEnabled="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="ServiceCredentialsBehavior" name="Service">
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="MessageAndUserName" name="SecuredByTransportEndpoint" contract="IService"/>
</service>
</services>
<bindings>
<wsHttpBinding>
<binding name="MessageAndUserName">
<security mode="Message">
<message clientCredentialType="UserName"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<client/>
In Service class, delete existing methods and add:
public string TestAccess()
{
return OperationContext.Current.ServiceSecurityContext.PrimaryIdentity.Name;
}
in IService delete Data Contract, delete operation contracts and add new operation contract:
[OperationContract]
public string TestAccess();
Run service and add service reference in client application to our service
Client config:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="LocalCertValidation">
<clientCredentials>
<serviceCertificate>
<authentication certificateValidationMode="PeerTrust" trustedStoreLocation="CurrentUser" />
</serviceCertificate>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IService" >
<security mode="Message">
<message clientCredentialType="UserName" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="your service addresss"
binding="wsHttpBinding"
bindingConfiguration="WSHttpBinding_IService"
contract="ServiceReference1.IService"
name="WSHttpBinding_IService" behaviorConfiguration="LocalCertValidation">
<identity>
<dns value ="cool" />
</identity>
</endpoint>
</client>
Client code:
ServiceClient client = new ServiceClient();
client.ClientCredentials.UserName.UserName = "Your windows user";
client.ClientCredentials.UserName.Password = "Your windows user password";
Console.WriteLine(client.TestAccess());
Console.ReadLine();
if you dont want to use windows login/password you have to create a custom user/passwd validator ->msdn:
Regards,
Sergiu.

Categories

Resources