dotnet / wcf

This repo contains the client-oriented WCF libraries that enable applications built on .NET Core to communicate with WCF services.
MIT License
1.7k stars 559 forks source link

UsernameToken SOAP in .NET Core 5.0 #5240

Open Mbialas1 opened 1 year ago

Mbialas1 commented 1 year ago

Hello,

I have problem with send SOAP xml file to service. I get error like: "wsse:FailedAuthentication

Failed to assert identity with UsernameToken. " I think that I'm send correct imitation of UsernameToken. It look like this: ``` user e4lt9L9z/Zu9a3WlcLEqzIEaz94= 0JGFVXqhNMr6wz0RTToMXw== 2023-08-08T14:12:44Z } ``` Any idea? Maybe I'm generate not correctly wsu:ID? `this.Id = $"SecurityToken-{Guid.NewGuid()}";` Generated password, nonce and time of created is correctly. In project .net framework 4.8 this work fine, but in .net core 5.0 I cant send request to service. Im using this code: https://github.com/dotnet/wcf/issues/3248
ghost commented 1 year ago

Tagging subscribers to this area: @dotnet/area-system-security, @bartonjs, @vcsjones See info in area-owners.md if you want to be subscribed.

Issue Details
Hello, I have problem with send SOAP xml file to service. I get error like: "wsse:FailedAuthentication Failed to assert identity with UsernameToken. " I think that I'm send correct imitation of UsernameToken. It look like this: user e4lt9L9z/Zu9a3WlcLEqzIEaz94= 0JGFVXqhNMr6wz0RTToMXw== 2023-08-08T14:12:44Z } Any idea? Maybe I'm generate not correctly wsu:ID? `this.Id = $"SecurityToken-{Guid.NewGuid()}";` From project .net framework 4.8 this work fine, but in .net core 5.0 I cant send request to service. Im using this code: https://github.com/dotnet/wcf/issues/3248
Author: Mbialas1
Assignees: -
Labels: `area-System.Security`
Milestone: -
mconnew commented 1 year ago

I presume you have written a custom SecurityTokenProvider and SecurityTokenSerializer and are using that to treat your UsernameToken like a custom SecurityToken type? We have special handling for built in UserNameSecurityToken and it doesn't use the same mechanisms as an external token provider like yours would.

The Id should just be retrieved as a property and used as an opaque value in the rest of the security header. Our implementation of SignedXml has changed between .NET Framework (we used our own custom implementation of SignedXml) and .NET [Core} (we use the public Crypto SignedXml api instead) so it's possible there's a difference in behavior there.

Have you looked at the final SecurityHeader XML that includes the SignedInfo block etc? Is the reference Id correct in the SignedInfo block? Can you artificially make the nonce a static value so you can compare what's generated between .NET Framework and .NET Core? It's going to be difficult to validate though because of the timestamp included in the signature.

Are you able to provide a sample client repro app for .NET Framework and .NET that I can use a debugger to see what's going on different between the two platforms?

Adding support for PasswordDigest is something I've wanted to do for some time. We couldn't do it on .NET Framework as WCF on the service side needs the password to authenticate against Windows, and all the extensibility to validate the password using custom mechanisms are all based around the actual password being provided. I think there's a good argument for adding this support natively into the WCF Client packages now.

Mbialas1 commented 1 year ago

I presume you have written a custom SecurityTokenProvider and SecurityTokenSerializer and are using that to treat your UsernameToken like a custom SecurityToken type? We have special handling for built in UserNameSecurityToken and it doesn't use the same mechanisms as an external token provider like yours would.

Yes, exactly like in this issue: https://github.com/dotnet/wcf/issues/3248

Are you able to provide a sample client repro app for .NET Framework and .NET that I can use a debugger to see what's going on different between the two platforms?

Sorry, it's not possible. It's, a large program and private soap from client.

I take this same nonce and createdDate for .net core to check it's a my method for hash password in .net core is correctly. Method return this same hash password like in framework 4.8.

Like I write before I'm using this same code: https://github.com/dotnet/wcf/issues/3248 .In method 'WriteLog' I have string stringMessage without alias xml (<?xml version="1.0" encoding="utf-16"?>) but at end return 'item' have in first line <?xml version="1.0" encoding="utf-16"?> so maybe that's why I get error.

This is xml from UsernameToken .net framework:

`

myuser +eBXBio5ixU/otFmkOq/UPyzJg4= oIfZWzaDwGQ3prXKZDUPmw== 2023-08-09T09:02:57Z }` and from .net core which returns my method: ` myuser e4lt9L9z/Zu9a3WlcLEqzIEaz94= 0JGFVXqhNMr6wz0RTToMXw== 2023-08-08T14:12:44Z }` But I noticed that copy2 variable return too xml txt with . `private void WriteLog(ref Message item) { var maxBufferSize = 1048576; var messageBuffer = item.CreateBufferedCopy(maxBufferSize); // for logging var copy1 = messageBuffer.CreateMessage(); // for output var copy2 = messageBuffer.CreateMessage(); (messageBuffer as IDisposable)?.Dispose(); // string for logging string stringMessage = null; using (var memoryStream = new MemoryStream()) { using (var streamReader = new StreamReader(memoryStream)) { _messageEncoder.WriteMessage(copy1, memoryStream); (copy1 as IDisposable)?.Dispose(); memoryStream.Position = 0; stringMessage = streamReader.ReadToEnd(); } } item = copy2; }`
mconnew commented 1 year ago

I'm not sure where the problem is. The layout of the XML looks consistent within the UsernameToken. I presume the xml header <?xml version="1.0" encoding="utf-16"?> isn't appearing in the real request going to the service and that's just an artifact from some logging code?
For the remote service to reject the token, it's one of 3 things. The credentials are incorrect (unlikely when it works on Framework), the token is malformed (e.g. hash miscalculated but doubtful as I wouldn't expect the execution of that to change between platforms), or the SecurityToken signedInfo signature has been calculated incorrectly. My suspicion is it's this last one. I think I have enough information to investigate, but it will require writing and mocking up an implementation which outputs the same thing as your token does. I will need to schedule this work as it's likely a couple of days to root cause. Having a simple repo would make it faster for me to solve. I would only need a console app with a ChannelFactory which uses your token implementation using a simple Hello World style service contract. No actual service would be needed to send anything to as I can temporarily modify WCF to use fixed values for things like the timestamp.