WCF has gotchas in a few areas with streaming (I'm looking at you, MTOM1) due to a fundamental issue in how it fails to perform preauthentication the way most people would think that should work (it only affects subsequent requests for that channel, not the first request) Ok, so this is not exactly your issue but please follow along as I will get to yours at the end. Normally the HTTP challenge works like this:
- client hits server anonymously
- server says, sorry, 401, I need authentication
- client hits server with authentication token
- server accepts.
Now, if you ever try to enable MTOM streaming on an WCF endpoint on the server, it will not complain. But, when you configure it on the client proxy (as you should, they must match bindings) it will explode in a fiery death. The reason for this is that the above sequence of events that WCF is trying to prevent is this:
- client streams 100MB file to server anonymously in a single POST
- server says sorry, 401, I need authentication
- client again streams 100MB file to server with an authentication header
- server accepts.
Notice that you just sent 200MB to the server when you only needed to send 100MB. Well, this is the problem. The answer is to send the authentication on the first attempt but this is not possible in WCF without writing a custom behaviour. Anyway, I digress.
Your Problem
First up, let me tell you that what you're trying is impossible2. Now, in order for you to stop spinning your wheels, let me tell you why:
It strikes me that you are now wandering in a similar class of problem. If you enable message level security, the client must load the entire stream of data into memory before it can actually close out the message with the usual hash function and xml signature required by ws-security. If it has to read the entire stream to sign the single message (which is not really a message, but it's a single continuous stream) then you can see the problem here. WCF will have to stream it once "locally" to compute the message security, then stream it again to send it to the server. This is clearly a silly thing, so WCF does not permit message level security for streaming data.
So, the simple answer here is that you should send the token either as a parameter to the initial web service, or as a SOAP header and use a custom behaviour to validate it. You cannot use WS-Security to do this. Frankly, this is not just a WCF issue - I cannot see how it could practically work for any other stacks.
Solving the MTOM Problem
This is just for an example how I solved my MTOM streaming issue for basic authentication, so perhaps you could take the guts of this and implement something similar for your issue. The crux of it is that in order to enable your custom message inspector, you have to disable all notion of security on the client proxy (it remains enabled on the server,) apart from transport level (SSL):
this._contentService.Endpoint.Behaviors.Add(
new BasicAuthenticationBehavior(
username: this.Settings.HttpUser,
password: this.Settings.HttpPass));
var binding = (BasicHttpBinding)this._contentService.Endpoint.Binding;
binding.Security.Mode = BasicHttpSecurityMode.Transport; // SSL only
binding.Security.Transport.ClientCredentialType =
HttpClientCredentialType.None; // Do not provide
Note that I have turned off transport security here because I will be providing that myself using a message inspector and custom behaviour:
internal class BasicAuthenticationBehavior : IEndpointBehavior
{
private readonly string _username;
private readonly string _password;
public BasicAuthenticationBehavior(string username, string password)
{
this._username = username;
this._password = password;
}
public void AddBindingParameters(ServiceEndpoint endpoint,
BindingParameterCollection bindingParameters) { }
public void ApplyClientBehavior(ServiceEndpoint endpoint,
ClientRuntime clientRuntime)
{
var inspector = new BasicAuthenticationInspector(
this._username, this._password);
clientRuntime.MessageInspectors.Add(inspector);
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint,
EndpointDispatcher endpointDispatcher) { }
public void Validate(ServiceEndpoint endpoint) { }
}
internal class BasicAuthenticationInspector : IClientMessageInspector
{
private readonly string _username;
private readonly string _password;
public BasicAuthenticationInspector(string username, string password)
{
this._username = username;
this._password = password;
}
public void AfterReceiveReply(ref Message reply,
object correlationState) { }
public object BeforeSendRequest(ref Message request,
IClientChannel channel)
{
// we add the headers manually rather than using credentials
// due to proxying issues, and with the 101-continue http verb
var authInfo = Convert.ToBase64String(
Encoding.Default.GetBytes(this._username + ":" + this._password));
var messageProperty = new HttpRequestMessageProperty();
messageProperty.Headers.Add("Authorization", "Basic " + authInfo);
request.Properties[HttpRequestMessageProperty.Name] = messageProperty;
return null;
}
}
So, this example is for anyone who is suffering with the MTOM issue, but also as a skeleton for you to implement something similar to authenticate your token generated by the primary WIF-secured token service.
Hope this helps.
(1) Large Data and Streaming
(2) Message Security in WCF (see "disadvantages.")
If we use TransportWithMessageCredentials mode , Is SOAP message(
Header and Body) encrypted?
Yes, since with TransportWithMessageCredential
security mode it is transport security which is providing confidentiality and integrity protection for the messages that are transmitted over the wire. Transport security also provides service authentication in this case. For example, with HTTP, Secure Sockets Layer (SSL) is used for encrypting and signing the contents of the packets sent over Secure HTTP (HTTPS).
With TransportWithMessageCredential
security mode, client authentication is provided by means of SOAP message security where the client credential is put directly in the message.
When the SOAP message leaves the client for the service it is encrypted. However, as with transport security it provides point-to-point (not end-to-end) security between the two endpoints (service and client). So if there are intermediary systems between the client and the service, each intermediate point must forward the message over a new secure connection.
Update Per Comments
you said "When the SOAP message leaves the client for the service it
is encrypted' Then it should be end -end security. why it is only
point -to-point.
Transport security is point-to-point because a message is encrypted when it leaves one endpoint and remains so until it reaches the other endpoint of the secure transport where the message is then decrypted. In deployments where the client and server are talking directly to each other, then this provides encryption the whole way through. However, if your service endpoint is going to forward that message onto the intended recipient, then your message is no longer guaranteed to be encrypted from that point onward.
Message security directly encrypts and signs the message so that only the intended recipient can decrypt and read the actual contents of the message. Therefore security is guaranteed between sender and recipient and not just between endpoints. Therefore, message security provides end-to-end security.
Can i conclude TransportWithMessageCredential provide security point
-to-point and message Level security provide End-to-End Security. then Why WCF security Guide is suggesting to use
TransportWithMessageCredential with UserName When we are using WCF
with Windows form client in internet.
Yes, that is correct. TransportWithMessageCredential
security provides point-to-point and Message
security provides end-to-end security. The WCF Security Guide is suggesting to set the client credential to UserName
because this will be used to authenticate the client. In the UserName
case, we have the username and password pair being put directly in the SOAP message. Unless the client provides some sort of credential such as a UserName
or Certificate
to authenticate themselves to the service you will have an anonymous client. An anonymous client means that anyone can access your service since the client is not being authenticated.
If message body is not encrypted with TransportWithMessageCredential
then why Microsoft says TransportWithMessageCredential is a
combination of both Transport and Message security
As with my original answer: The SOAP messages are encrypted and signed by the transport layer (e.g. HTTPS). TransportWithMessageCredential
is a combination of both transport and message security since transport security encrypts and signs the messages as well as authenticates the service to the client and message security is used to authenticate the client to the service.
Best Answer
Security in WCF actually consists of several features. The difference between those two is how are messages signed and encrypted.
Transport security provides only point-to-point channel security. It means that HTTPS establish secure channel only between client and server exposed to client. But if this server is just a load balancer or reverse proxy server it has direct access to content of the message.
Message security provides end-to-end channel security. It means that security is part of transferred data and only intended destination can decrypt the data (load balancer or proxy sees only encrypted message). Message security in most cases also uses certificates to provide encryption and signing but it is usually slower because transport security can use HW acceleration.
In advanced scenarios these methods can be combined. For example you can have communication to your load balancer secured by HTTPS because you trust your internal network after load balancer but in the same time you can have the message signed (message security) so you can prove that it wasn't changed.
Another difference between those two is that transport security is related to single transport protocol whereas message security is independent on transport protocol.
Message security is based on interoperable protocols (but be aware that not every configuration in WCF is interoperable). WCF supports at least partially these protocols:
WCF also supports WS-I Basic Security Profile 1.0 which is just subset of former protocols with prescribed configuration.
For non interoperable features WCF offers features like Windows security or TLSNego and SPNego (both should be generally interoperable but their are not available in many SOAP stacks) for service credentials exchange.