0

I'm using a custom binding in my service and client which basically looks like this:

public class UserNameWsTrustBinding : Binding
{
    public override BindingElementCollection CreateBindingElements()
    {
        var coll = new BindingElementCollection();
        coll.Add(CreateSecurityBindingElement());
        coll.Add(new TextMessageEncodingBindingElement());
        coll.Add(new HttpsTransportBindingElement());
        return coll;
    }

    private SecurityBindingElement CreateSecurityBindingElement()
    {
        var elem = SecurityBindingElement.CreateUserNameOverTransportBindingElement();
        elem.MessageSecurityVersion = MessageSecurityVersion.WSSecurity11WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10;
        return elem;
    }
}

This binding works prety well. Except for FaultExceptions which I throw e.g. when validating the user's credentials. I throw non-generic FaultExceptions like this; nothing special I think:

throw new FaultException(new FaultReason("Blah blah"), new FaultCode("Code42"));

WCF then takes care of putting these faults into a SOAP envelope. The problem is, that there don't get security headers (namely a WS-Security timestamp) baked in:

<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"
    xmlns:a="http://www.w3.org/2005/08/addressing">
    <s:Header>
        <a:Action s:mustUnderstand="1">http://www.w3.org/2005/08/addressing/soap/fault</a:Action>
        <a:RelatesTo>urn:uuid:ff1f54d7-53a0-4650-b967-03a75def5fa4</a:RelatesTo>
    </s:Header>
    <s:Body>
        <s:Fault>
            <s:Code>
                <s:Value>s:Sender</s:Value>
                <s:Subcode><s:Value>Code42</s:Value></s:Subcode>
            </s:Code>
            <s:Reason><s:Text>Blah blah</s:Text></s:Reason>
        </s:Fault>
    </s:Body>
</s:Envelope>

When the client application receives this response it complains about it with the following error message:

System.ServiceModel.Security.MessageSecurityException: An unsecured or incorrectly secured fault was received from the other party. See the inner FaultException for the fault code and detail.

This is not surprising, since there is no security header included. I can then get the FaultException from the MessageSecurity's InnerException. It works, but it doesn't feel good.

What is really surprising, however, is that unhandled exceptions that are not caught in my server code get wrapped in a FaultException automatically. And these FaultExceptions have a security header!

<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
    <s:Header>
        <a:Action s:mustUnderstand="1">http://schemas.microsoft.com/net/2005/12/windowscommunicationfoundation/dispatcher/fault</a:Action>
        <a:RelatesTo>urn:uuid:0baffa8b-07ee-4feb-bc44-7e2c7ae85c22</a:RelatesTo>
        <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>2022-07-11T13:41:22.007Z</u:Created>
                <u:Expires>2022-07-11T13:46:22.007Z</u:Expires>
            </u:Timestamp>
        </o:Security>
    </s:Header>
    <s:Body>
        <s:Fault>
            <s:Code>
                <s:Value>s:Receiver</s:Value>
                <s:Subcode><s:Value xmlns:a="http://schemas.microsoft.com/net/2005/12/windowscommunicationfoundation/dispatcher">a:InternalServiceFault</s:Value></s:Subcode>
            </s:Code>
            <s:Reason><s:Text>The server was unable to process the request due to an internal error.  For more information about the error, either turn on IncludeExceptionDetailInFaults (either from ServiceBehaviorAttribute or from the %lt;serviceDebug&gt; configuration behavior) on the server in order to send the exception information back to the client, or turn on tracing as per the Microsoft .NET Framework SDK documentation and inspect the server trace logs.</s:Text></s:Reason>
        </s:Fault>
    </s:Body>
</s:Envelope>

So, long story short: What am I doing wrong? Or in other words: What do I have to do to make my self-thrown FaultExceptions include a timestamp as well?

Jan Köhler
  • 5,817
  • 5
  • 26
  • 35
  • You can see an error message in the second response: (The server was unable to process the request due to an internal error. For more information about the error, either turn on IncludeExceptionDetailInFaults (either from ServiceBehaviorAttribute or from the %lt;serviceDebug> configuration behavior) on the server in order to send the exception information back to the client, or turn on tracing as per the Microsoft .NET Framework SDK documentation and inspect the server trace logs. – Lan Huang Jul 13 '22 at 03:06
  • You can turn on `IncludeExceptionDetailInFaults` on the server as explained in the error message。`` https://learn.microsoft.com/en-us/dotnet/api/system.servicemodel.servicebehaviorattribute.includeexceptiondetailinfaults?view=netframework-4.8 – Lan Huang Jul 13 '22 at 03:07
  • Hello Lan! Thank you for that idea. Setting `includeExceptionDetailInFaults="true"` would be fine for development purposes, sure. But I'm looking for something that I can use in production, where this setting obiously doesn't fit very well, unfortunately. – Jan Köhler Jul 13 '22 at 05:15
  • The timestamp is contained in the SecurityBindingElement. If you want to implement timestamp you need to set security.[IncludeTimestamp](https://learn.microsoft.com/en-us/dotnet/api/system.servicemodel.channels.securitybindingelement.includetimestamp?view=dotnet-plat-ext-6.0) to true.https://stackoverflow.com/a/56287964/17218587 – Lan Huang Jul 13 '22 at 09:01
  • Unfortunately, that does not seem to be the problem. `IncludeTimestamp` ist already set to true. I create the binding via [SecurityBindingElement.CreateUserNameOverTransportBindingElement()](https://referencesource.microsoft.com/#System.ServiceModel/System/ServiceModel/Channels/SecurityBindingElement.cs,1472) which sets that property to true... :-/ – Jan Köhler Jul 13 '22 at 11:11

0 Answers0