WCF message encryption - key - wcf

I'm quite new in WCF.
I created a WCF application with message encryption and username/password authentication. I have multiple clients connecting with my server and I want to encrypt messages with unique key for every connection.
Here is my binding:
<wsHttpBinding>
<binding name="NewBinding0">
<security mode="Message">
<transport clientCredentialType="None" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
</wsHttpBinding>
And here is service credentials section in seviceBehaviour
<serviceCredentials>
<serviceCertificate findValue="ls Server" storeLocation="CurrentUser" x509FindType="FindBySubjectName" />
<userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="Server.CustomUserValidation, Server" />
</serviceCredentials>
And here is my question, how the key for encryption algorithm is generated? It will be unique for every client? If not, what I have to do to accomplish my task?
Thanks in advance.
Edit1:
Maybe can I set the user password to be the encryption key? It would be the best solution for me.

Related

Mutual SSL security mode binding configurations

I have two questions regarding the security mode regarding mutual ssl.
I have look through a few sites such as:
1.https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/transport-security-with-certificate-authentication%20
2.https://www.codeproject.com/Articles/348595/Use-Mutual-SSL-Authentication-in-WCF
In all the binding configurations. I realized that all security mode is set as 'Transport'.
<bindings>
<wsHttpBinding>
<!-- configure wsHttp binding with Transport security mode and clientCredentialType as Certificate -->
<binding>
<security mode="Transport">
<transport clientCredentialType="Certificate"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
In regards to this, what I want to know is if its possible to use other kind of security mode such as
'Message' or 'TransportWithMessageCredential'. If so why?
Furthermore if its possible, does the client side have to change their security mode to the same as the server side?
The Microsoft official document also offers an example of authenticating the client with message security mode with mutual certificates.
https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/message-security-with-mutual-certificates
What we need to do is configuring a service certificate on the server-side, a certificate on the client-side, also establishing the certificate trust relationship between the client-side and server-side.
Here is a standard configuration.
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="serviceCredentialBehavior">
<serviceCredentials>
<serviceCertificate findValue="Contoso.com"
storeLocation="LocalMachine"
storeName="My"
x509FindType="FindBySubjectName" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="serviceCredentialBehavior"
name="ServiceModel.Calculator">
<endpoint address="http://localhost/Calculator"
binding="wsHttpBinding"
bindingConfiguration="InteropCertificateBinding"
name="WSHttpBinding_ICalculator"
contract="ServiceModel.ICalculator" />
</service>
</services>
<bindings>
<wsHttpBinding>
<binding name="InteropCertificateBinding">
<security mode="Message">
<message clientCredentialType="Certificate"
negotiateServiceCredential="false"
establishSecurityContext="false" />
</security>
</binding>
</wsHttpBinding>
</bindings>
</system.serviceModel>
This is also applicable to the TransportWithMessageCredential security mode. As long as the security mode is Transport security mode, we need to bind a certificate to the particular port.
Besides, the binding configuration should be coherent between the client-side and the server-side. Just like the service contract is shared between the client-side and the server-side.
Feel free to let me know if there is anything I can help with.

Can't authenticate using wsHttpBinding with ClientCredentialsType=Username

I am new to WCF and now really lost with this problem...
I want my WCF Service to authenticate incoming request using the username and password provided by client.
Relevant parts of Web.Config looks like this:
<endpoint name="wsBinding"
address=""
binding="wsHttpBinding"
contract="ServiceLib.IBooking"
bindingConfiguration="myWSSettings"
/>
And...
<bindings>
<wsHttpBinding>
<binding name="myWSSettings">
<security mode="Transport">
<message clientCredentialType="UserName" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
<serviceCredentials>
<userNameAuthentication
userNamePasswordValidationMode="Custom"
customUserNamePasswordValidatorType= "ServiceLib.MyCustomUserNameValidator, ServiceLib" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
MyCustomUserNameValidator is just a temporary validator which simply throws Exception if username is not equal to password.
Client program (a console app) is doing this:
BookingClient client = new BookingClient("wsBinding");
Passenger passenger = new Passenger();
// ../
client.ClientCredentials.UserName.UserName = "SomeUserName";
client.ClientCredentials.UserName.Password = "WrongPassword";
// ...
// ...
// NOTE: Following should throw My SecurityException Since username and
// Password are not equal
bool confirmed = client.IsTicketConfirmed(passenger);
This is the error I get:
The HTTP request is unauthorized with client authentication scheme 'Negotiate'. The authentication header received from the server was 'Negotiate,NTLM,Basic
Would really appreciate any help! I have spent tons of time trying to figure this out but in vain.
Thanks
Sandeep
Note:--------
I am using GoDaddy to host my WCF Service. Security mode = "Message" cannot be used there due to partial trust.
SSL certificate is correctly installed.
You must change security mode to TransportWithMessageCredential :
<wsHttpBinding>
<binding name="SafeServiceConf">
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName"/>
</security>
</binding>
</wsHttpBinding>
You will found a good sample here.

WCF Message body encryption with SSL

I am new to WCF. I am investigating the right way to have message body encryption over HTTPS (mixing both transport and message level security at the moment)
I have HttpsGetEnabled.
Using WsHttpBinding, I still see the message body unencrypted
<wsHttpBinding>
<binding name="myCustomWsHttpBinding">
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None"/>
<message clientCredentialType="Certificate" />
</security>
</binding>
</wsHttpBinding>
I have also tried using custom binding but same result
<binding name="myCustomBinding">
<security authenticationMode="CertificateOverTransport"
messageProtectionOrder="EncryptBeforeSign"
includeTimestamp="true"
protectTokens="true"
>
</security>
<textMessageEncoding messageVersion="Soap11WSAddressing10" />
<httpsTransport/>
</binding>
How can we have message body encrypted when using Https? If I understand correctly message level security is independent of transport so using https is possible in this case?
In the custom binding, set authenticationMode to "mutualCertificate"

WCF and Kerberos Authentication

I have followed numerous msdn articles and the codeplex guidance but cannot get WCF to work with Kerberos authentication and delegation and would appreciate a little help.
Setup
I have the WCF service in an IIS website on a remote machine
IIS 6.0 on Windows 2003 R2 - SP 2
The SPN for the machine has been added (http/myserver && http/myserver:8080)
An AD account has been created for the IIS app pool
The AD account has the setting, allow delegation (for Kerberos), set to true
I am using Brian Booth's debug site on 8080 and the site passes all requirements for Kerberos delegation. The debug IIS site has anonymous authentication off, and Integrated Windows authentication on.
I have mirrored these settings to the site hosting the WCF service.
Web Service - Web Config (Original)
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WsHttpBindingConfig">
<security>
<message negotiateServiceCredential="true" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<services>
<service behaviorConfiguration="ServiceBehavior" name="Service">
<endpoint address=""
binding="wsHttpBinding"
bindingConfiguration="WsHttpBindingConfig"
contract="IService">
<identity>
<servicePrincipalName value="http/myserver" />
<dns value="" />
</identity>
</endpoint>
<endpoint address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceBehavior">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceAuthorization
impersonateCallerForAllOperations="true" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
Web Service - Web Method
[OperationBehavior(Impersonation = ImpersonationOption.Required)]
public string GetCurrentUserName()
{
string name = WindowsIdentity.GetCurrent().Name;
return name;
}
Client App - App Config
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IService"
... />
...
<security mode="Message">
<transport clientCredentialType="Windows"
proxyCredentialType="None"
realm="" />
<message clientCredentialType="Windows"
negotiateServiceCredential="true"
algorithmSuite="Default"
establishSecurityContext="true" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="http://myserver/Service.svc"
binding="wsHttpBinding"
bindingConfiguration="WSHttpBinding_IService"
contract="KerberosService.IService"
name="WSHttpBinding_IService">
<identity>
<servicePrincipalName value="http/myserver" />
</identity>
</endpoint>
</client>
</system.serviceModel>
Application Error
The following error occurs when my test application, a WinForms app, tries to call the web method:
"The HTTP request is unauthorized with
client authentication scheme
'Anonymous'. The authentication header
received from the server was
'Negotiate,NTLM'."
Event Log
The following error is in the event log:
Exception:
System.ServiceModel.ServiceActivationException:
The service '/Service.svc' cannot be
activated due to an exception during
compilation. The exception message
is: Security settings for this service
require 'Anonymous' Authentication but
it is not enabled for the IIS
application that hosts this service.
Which I don't understand. The whole point of this service is to not allow anonymous authentication, every user/request must be authenticated using Kerberos tickets, then passing them through to other machines.
How should I configure this WCF service for Kerberos authentication and delegation?
Revision 1
After reading this SO question I removed the metadata endpoint. This has not resolved the issue.
Revision 2
After more researching I found a few posts suggesting to change wsHttpBinding to basicHttpBinding. The modification to that portion of the web.config has been included below, and the service endpoint has been updated to refer to that binding.
Web Service - Web Config (Revised)
<basicHttpBinding>
<binding name="basicBindingConfig">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows"
proxyCredentialType="Windows"
realm="" />
</security>
</binding>
</basicHttpBinding>
Client App - App Config (Revised)
<!-- ... -->
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows"
proxyCredentialType="Windows"
realm="" />
<message clientCredentialType="UserName"
algorithmSuite="Default" />
</security>
<!-- ... -->
Error (Revised)
The current error looks like it contains a Kerberos authentication header.
The HTTP request is unauthorized with
client authentication scheme
'Negotiate'. The authentication header
received from the server was
'Negotiate SOMEHUGESCARYKEYHERE
For me the current setup does work:
On the Server:
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="wsHttpBindingConf" useDefaultWebProxy="true"/>
</wsHttpBinding>
</bindings>
<services>
<service behaviorConfiguration="returnFaults" name="Epze.BusinessLayer.ZeitManager">
<endpoint binding="wsHttpBinding" bindingConfiguration="wsHttpBindingConf" contract="Epze.Contract.IZeitManager"/>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="returnFaults">
<serviceMetadata httpGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>
<serviceAuthorization impersonateCallerForAllOperations="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
Set the following attribute on all methods for the WCF:
[OperationBehavior(Impersonation = ImpersonationOption.Required)]
On the Client:
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IZeitManager" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="524288" maxReceivedMessageSize="65536" messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true" allowCookies="false">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384"/>
<reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="false"/>
<security mode="Message">
<transport clientCredentialType="Windows" proxyCredentialType="None" realm=""/>
<message clientCredentialType="Windows" negotiateServiceCredential="true" algorithmSuite="Default" establishSecurityContext="true"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<endpointBehaviors>
<behavior name="Delegation">
<clientCredentials>
<windows allowedImpersonationLevel="Delegation" />
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
<client>
<endpoint address="http://server.mydomain.net/ePZEsvc/ZeitManager.svc" binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IZeitManager"
contract="External.Epze.IZeitManager" name="WSHttpBinding_IZeitManager" behaviorConfiguration="Delegation">
<identity>
<servicePrincipalName value="HOST/localhost"/>
</identity>
</endpoint>
</client>
</system.serviceModel>
HTH, Sven
Something that I notice: the client and server config don't seem to agree on security mode.
In the original section, you have <security>..... in the web.config (omitted the mode="message"), and <security mode="Message"> on the client side.
After your edit, it seems that the client side is unchanged, but the server (web.config) now contains <security mode="TransportCredentialOnly">.
The question really is: can you guarantee that there's only ever going to be one network leg between the client and the server being called? I.e. is this behind a corporate firewall? In that case, I would recommend netTcp binding with <security mode="Transport"> on both ends.
If that's not the case, then you're ok with either wsHttpBinding (which supports more security and reliability features, but is slower and "heavier") or basicHttpBinding. In that case, you would have to use <security mode="Message"> on both ends, and authenticate the service with a certificate (so that the service and client have a common "secret" which to use for encryption).
I would try to leave out the impersonation parts out for the beginning and just get the basic communication and mutual authentication between service and client up and running first - once that's in place, you can start adding the impersonation bits to it, and you can always fall back on a known configuration which works.
David Sackstein has a great series of blog posts explaining the five security scenarios that industry guru Juval Lowy has identified (in his Programming WCF book - the WCF Bible) as the most common and most useful - in order to limit the number of possible combinations of parameters you might want to tweak. One of them is a "Internet" scenario which would probably apply here, if your service is outward facing.
Marc
You need to specify a behaviorConfiguration in your client config. SVCUtil does not auto generate. This resolved my issue and I am now successfully using Kerberos. It was a mission though!
<client>
<endpoint address="..."
binding="customBinding" bindingConfiguration="..."
contract="..." name="..." behaviorConfiguration="ImpersonationBehavior" />
</client>
<behaviors>
<endpointBehaviors>
<behavior name="ImpersonationBehavior">
<clientCredentials>
<windows allowedImpersonationLevel="Impersonation"/> </clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
You should try your initial configuration and make sure to set the IIS to be anonymous and windows authentication at the same time.The reason is when you are using wsHttpBinding default security is message security and there is no transport security defined unless you want to do https. SO Clr states that it needs anonymous authentication turned-on on the IIS.

How do I convert a basicHttpBinding to a customBinding

I've been working on converting a basicHttpBinding to a customBinding to get my client working on a web farm. I've been fumbling translating the following security section.
<basicHttpBinding ...>
<security mode="Transport">
<transport clientCredentialType="Certificate">
</security>
</basicHttpBinding>
<behaviors>
<behavior>
<clientCredentials>
<clientCertificate
x509FindType="FindBySerialNumber"
findValue="..."
/>
</clientCredentials>
<behavior>
</behaviors>
I'd show you my translation, but what I've been able to fathom is really undereducated guessing. I will also continue doing some more independent research via the web.
This tool converts automatically your binding into a customBinding.
http://webservices20.cloudapp.net/default.aspx
Ok, I figured this out, didn't need to even use the security section in the custombinding, everything I need to set was on the <httpsTransport/> element itself. I've cut out all the non important bits.
<customBinding>
<binding name="viaLoadBalancers">
<textMessageEncoding
messageVersion="Soap11"
writeEncoding="utf-8"
/>
<httpsTransport
authenticationScheme="Anonymous"
requireClientCertificate="true"
/>
</binding>
</customBinding>