-1

I am trying to call a method on a WebReference (web-service) client that must use WS-Security. When i execute the cargaFicheiro method it returns the following error:

An invalid security token was provided (An error happened processing a Username Token).

The code i'm using is:

// Cuidamos is a WebReference do a WSDL url in https

var token = new UsernameToken("Username", "Password", PasswordOption.SendPlainText);

var serviceProxy = new Cuidamos.CargaFicheiroServiceImplService();

SoapContext requestContext = serviceProxy.RequestSoapContext;
requestContext.Security.Timestamp.TtlInSeconds = 300;
requestContext.Security.Tokens.Add(token);

var result = serviceProxy.cargaFicheiro();

The SOAP header must match this one:

<soap:Header>
    <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" soap:mustUnderstand="1">
        <wsu:Timestamp wsu:Id="TS-2">
            <wsu:Created>2013-10-07T10:13:52Z</wsu:Created>
            <wsu:Expires>2013-10-07T10:20:32Z</wsu:Expires>
        </wsu:Timestamp>
        <wsse:UsernameToken wsu:Id="UsernameToken-1">
            <wsse:Username>USERNAME</wsse:Username>
            <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">PASSWORD</wsse:Password>
        </wsse:UsernameToken>
    </wsse:Security>
</soap:Header>

I have used the following answer to implement my code: https://stackoverflow.com/a/40030906/2449703

Based on Microsoft i am doing all in the right way: https://learn.microsoft.com/en-us/previous-versions/dotnet/netframework-1.1/ms819938(v=msdn.10)

Again other answer that works, but not in my case: https://forums.asp.net/t/2133187.aspx?C+oasis+Username+token

Thanks.

Pl4tinum
  • 123
  • 15

2 Answers2

1

WSSE Nonce is a security attribute with a unique identifier designed to prevent replay attacks. Your server is likely generating this because you have a custom service binding configured in your service config.

It should work exactly once,which is likely why you can't re-use it from SOAPUI

More info here:

https://weblog.west-wind.com/posts/2012/nov/24/wcf-wssecurity-and-wse-nonce-authentication

Matt Evans
  • 7,113
  • 7
  • 32
  • 64
  • But if the soap request is going through https do i need this nonce? I do not have any custom service binding. – Pl4tinum Jun 27 '19 at 14:26
  • The document provided by the team that manages this service doesn't reference the Nonce element in the Soap Header, so i am assuming that is not required. – Pl4tinum Jun 27 '19 at 14:34
  • I also have tried to generate a different Nonce phrase and use it in Soap UI and it returns the same error. I have used GetSHA1String(phrase) method from west-wind blog that you posted. – Pl4tinum Jun 27 '19 at 14:38
  • What does Cuidamos.CargaFicheiroServiceImplService() do? – Matt Evans Jun 27 '19 at 14:55
  • It will generate a proxy from a Service Reference (not Web Reference), legacy btw. Don't know if i answer your question. – Pl4tinum Jun 27 '19 at 15:14
0

My question is almost solved.

I have notice that the SOAP Header generated by this code is the following:

<soapenv:Header>
    <wsa:Action></wsa:Action>
    <wsa:MessageID>uuid:2eead708-03f9-4624-a866-35f3730eac23</wsa:MessageID>
    <wsa:ReplyTo>
        <wsa:Address>http://schemas.xmlsoap.org/ws/2004/03/addressing/role/anonymous</wsa:Address>
    </wsa:ReplyTo>
    <wsa:To>https://cuidamos.com/ws/cuidamos</wsa:To>
    <wsse:Security soapenv:mustUnderstand="1">
        <wsu:Timestamp wsu:Id="Timestamp-64f67137-f82d-4a9c-8b2e-1cc41104683d">
            <wsu:Created>2019-06-27T12:48:00Z</wsu:Created>
            <wsu:Expires>2019-06-27T12:53:00Z</wsu:Expires>
        </wsu:Timestamp>
        <wsse:UsernameToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="SecurityToken-b8467c25-c62c-406a-9831-46e6c676153a">
            <wsse:Username>Username</wsse:Username>
            <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">Password</wsse:Password>
            <wsse:Nonce>JEmovy7RDpapzumPTiUUgQ==</wsse:Nonce>
            <wsu:Created>2019-06-27T12:48:00Z</wsu:Created>
        </wsse:UsernameToken>
    </wsse:Security>
</soapenv:Header>

And i have used this solution to trace my request soap message.

But when i use SoapUI application to make a request with this SOAP Header, i have notice that if i remove <wsse:Nonce> element it will work just fine. So i need to remove this <wsse:Nonce> element that is being dynamically generated and this is where i am working on, but don't know hot do it yet.

EDIT

I'm almost there, i have found that if i create the attribute EncodingType inside Nonce element it works, i don't need to remove Nonce element. This has been tested on SoapUI.

The Nonce element should be created like this, the innerText on Nonce element is a hash string (SHA-1) created on each request:

<wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">6OX8gvIRETEbzaCwZ4byn/NEpzDI=</wsse:Nonce>

To achive this result i have created dynamically UsernameToken with XML:

XmlDocument document = new XmlDocument();
XmlElement usernameTokenElement = document.CreateElement("wsse", "UsernameToken", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");

XmlElement usernameChild;
usernameChild = document.CreateElement("wsse", "Username", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
usernameChild.InnerText = "WSMASSIT";
usernameTokenElement.AppendChild(usernameChild);

XmlElement passwordChild;
passwordChild = document.CreateElement("wsse", "Password", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
passwordChild.SetAttribute("Type", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText");
passwordChild.InnerText = "AstWs218";
usernameTokenElement.AppendChild(passwordChild);

string phrase = Guid.NewGuid().ToString();
var nonce = GetSHA1String(phrase); // User Function to create SHA-1 Hash String

XmlElement nonceChild;
nonceChild = document.CreateElement("wsse", "Nonce", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd");
nonceChild.SetAttribute("EncodingType", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary");
nonceChild.InnerText = nonce;
usernameTokenElement.AppendChild(nonceChild);

var token = new UsernameToken(usernameTokenElement);

Now i have other problem, the Username and Password childs are created with success, but Nonce child is rewritten on runtime, wich means that Username and Password are created exactly as i coded but Nonce continues to be created without EncondingType and the innerText hash string is different from what my code created.

EDIT 2

I have done a simple test, by adding the following code

document.AppendChild(usernameTokenElement);

var xml = token.GetXml(document);

And if i inspect document i can see Nonce element with EncodingType attribute, but if i inspect xml it doesn't have EncodingType attribute on Nonce element.

EDIT 3

Problem solved, but question of EDIT 2 not answered. In a nutshell Nonce is no longer required, the department responsible for managing this endpoint has done that configuration on server. In the specification of UsernameToken WSS document its written that Nonce and Created are not required, so by this assumption the problem was solved that way, remembering that this request is made on a https (SSL Tunneling).

Pl4tinum
  • 123
  • 15