Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Another question about WCF Core and MutualCertificateBinding #4854

Closed
thuannguy opened this issue Jun 29, 2022 · 5 comments
Closed

Another question about WCF Core and MutualCertificateBinding #4854

thuannguy opened this issue Jun 29, 2022 · 5 comments
Assignees
Labels
customer assistance Help customers with questions regarding usage of WCF features. WSFederation Issues related to adding support for WSFederation.

Comments

@thuannguy
Copy link

Per #4659, the MutualCertificate binding is not supported yet.

This is how source code looks like today:

image

@mconnew replied that " unfortunately due to missing dependencies we can't yet support full Message security which is needed for your configuration".

I open this issue as an attempt to learn more about that "missing dependencies". Could you please clarify what the missing dependencies are? What if I need to port or implement the MutualCertificateBinding (as a custom binding) myself (perhaps just enough for my use cases?). Is that doable or do I really need to wait for those "missing dependencies"? Could you please point me to the right directly?

@thuannguy thuannguy added the WSFederation Issues related to adding support for WSFederation. label Jun 29, 2022
@mconnew
Copy link
Member

mconnew commented Jun 29, 2022

Here's a comment I wrote answering a similar question. Let me know if you have more questions beyond that.

@thuannguy
Copy link
Author

thuannguy commented Jun 30, 2022

Thank you for the swift reply. That StrTransform is definitely a troublesome one.

The implementation in .NET Framework that WCF uses is a cheater implementation taking some shortcuts and isn't a full implementation

When studying how the StrTransform was done in .NET Framework, I thought the StrTransform class was where I needed to look at. It was not until I could debug into .NET Framework code that I figured out where the cheat was. 😢
It doesn't seem to me that Microsoft.IdentityModel.* has support for StrTransform. Btw, it is strange that there have been too many SignedXml implementations in .NET Framework: one in System.Security.Cryptography.Xml, one in System.IdentityModel (internal class), then Microsoft.IdentityModel.* took another approach.

That said, I actually managed to make a StrTransform (cheat) implementation that works for me 😁. My use cases only need to use a SecurityTokenReference that always points to an SAML assertion, so it was easier (and has smaller attack surface) than a full support for sure.

I have two problems left (at least for now): The first one is that when my client code handles a response, it throws:

Cannot find a token authenticator for the 'System.IdentityModel.Tokens.X509SecurityToken' token type. Tokens of that type cannot be accepted according to current security settings.

image

The reason is obvious: because the Mutual binding is not supported, allowedTokenAuthenticators is never initialized. How to initialize it is not obvious though: all related classes are internal which leave me virtual no chance to touch them. I understand why some classes have to be internal, but given the fact that WCF support in Core is limited, sometimes I wish it made more classes public and extensible. Anyway, I don't mind writing some ugly code to achieve my goal. If you happen to have an idea about how I can "hack" around this issue, please let me know 😁
Update: I found no extensible points that can help. The only way is to skip default validation and does all validations manually.

The second issue is that if my client code gets the error below, but if I open Fiddler and configure a client certificate for it, the error disappears. This is probably me configuring my custom binding wrong so I will do my own research for this one :)
Update: it was because transport.RequireClientCertificate = true was missing

Unhandled exception. System.AggregateException: One or more errors occurred. (An error occurred while sending the request.)
 ---> System.ServiceModel.CommunicationException: An error occurred while sending the request.
 ---> System.Net.Http.HttpRequestException: An error occurred while sending the request.
 ---> System.IO.IOException: The decryption operation failed, see inner exception.
 ---> System.ComponentModel.Win32Exception (0x80090330): The specified data could not be decrypted.
   --- End of inner exception stack trace ---

@HongGit HongGit added the customer assistance Help customers with questions regarding usage of WCF features. label Jul 7, 2022
@OleksandrBorovenskyi
Copy link

Hi @thuannguy ,

Could you please explain how to overcome the exception:
Cannot find a token authenticator for the 'System.IdentityModel.Tokens.X509SecurityToken' token type. Tokens of that type cannot be accepted according to current security settings.

You mentioned manual validation.
Could you point me to the solution, please?

@thuannguy
Copy link
Author

My workaround is to implement a custom IRequestChannel that wraps around the original channel. In WCF, the response's signature is validated after the EndRequest method exits. Therefore, I add my own signature validation to the EndRequest method. This involves converting the Message object to an XmlDocument and validating its signature. After validation, I remove the signature and convert the no-signature message back to a new Message object. Finally, I store the original message in the Properties list so that other code can use it when needed.

Security-wise, this solution works for me because my use cases are well-controlled. I know exactly the message format, what certificate that I need to use for signature validation, and what algorithms to use.

    public class MyCustomSoapChannel : ChannelBase, IRequestChannel
    {
        public Message EndRequest(IAsyncResult result)
        {
            Message originalResponse = _innerChannel.EndRequest(result);

            originalResponse = ValidateSignature(originalResponse);

            var manipulatedResponse = ModifyMessageToSkipDefautValidation(originalResponse);

            manipulatedResponse.Properties.Add("originalMessage", originalResponse);
            return manipulatedResponse;
        }
    }

@OleksandrBorovenskyi
Copy link

@thuannguy, thank you very much.
I will try to implement this way.
Really appreciate your quick response

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
customer assistance Help customers with questions regarding usage of WCF features. WSFederation Issues related to adding support for WSFederation.
Projects
None yet
Development

No branches or pull requests

4 participants