Click here to Skip to main content
15,896,063 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hi,
I am trying to bind soap sercurity header tag with usernametoken. I am using SHA1 algorithm to hashing the password with using datetime and 16 byte nonce; instead I have tried with Microsoft.Web.Services3.Security.Tokens - UsernameToken class also to generate nonce.

I am binding the SOAP message in stringbuilder and using MSXML2 component's ServerXMLHTTPClass to send request and response from the server.

this is my soap message building method.

XML
sb.Append("<soap:Envelope xmlns:soap=\"http://www.w3.org/2003/05/soap-envelope\" xmlns:wsdl=\"http://www.onvif.org/ver10/device/wsdl\">");
credential = AuthenticationCore("service", "service");

sb.Append("<soap:Header>");
sb.Append("<wsse:Security soap:mustUnderstand = \"true\" xmlns:wsse=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\">");
sb.Append("<wsse:UsernameToken wsu:Id=\"UsernameToken-" + System.Guid.NewGuid() + "\" xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\">");
sb.Append("<wsse:Username>" + credential.UserName + "</wsse:Username>");
sb.Append("<wsse:Password Type=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest\">" + credential.Password + "</wsse:Password>");
sb.Append("<wsse:Nonce EncodingType=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary\">" + credential.Nonce + "</wsse:Nonce>");
sb.Append("<wsu:Created>" + credential.Created + "</wsu:Created>");
sb.Append("</wsse:UsernameToken>");
sb.Append("</wsse:Security>");
sb.Append("</soap:Header>");

//sb.Append(GetHeadder());
sb.Append("<soap:Body>");

if (BodyContent != null)
    sb.Append(BodyContent.ToString());
sb.Append("</soap:Body>");
sb.Append("</soap:Envelope>");


and this is my method which i am using to encrypt the password and generate nonce.

internal const int NonceLength = 0x10;
        private RNGCryptoServiceProvider Rand;
               
        private byte[] CreateNonce()
        {
            byte[] buf = new byte[NonceLength];
            Rand.GetBytes(buf);
            return buf;
        }
        private UserCredential AuthenticationCore(string username, string password)
        {
            UserCredential Return = new UserCredential();
            UsernameToken usernameToken = new UsernameToken(username, password, PasswordOption.SendHashed);
            try
            {
                //Rand = new RNGCryptoServiceProvider();
                //byte[] nonce = CreateNonce(); 
                byte[] nonce = usernameToken.Nonce;
                string createtime; // = DateTime.Now.ToUniversalTime().ToString(DateTimeFormatInfo.InvariantInfo.SortableDateTimePattern) + "Z";
                //createtime = DateTime.Now.ToUniversalTime().ToString(DateTimeFormatInfo.InvariantInfo.SortableDateTimePattern) + "Z";

                createtime = DateTime.UtcNow.ToUniversalTime().ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'FFF") + "Z";
                string expiretime = DateTime.UtcNow.AddMinutes(5).ToUniversalTime().ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'FFF") + "Z";
                
                byte[] digestbuf = new byte[nonce.Length + Encoding.Unicode.GetByteCount(createtime + password)];
                nonce.CopyTo(digestbuf, 0);
                Encoding.Unicode.GetBytes(createtime + password).CopyTo(digestbuf, nonce.Length);
                SHA1 sha1 = SHA1.Create();
                string digest = Convert.ToBase64String(sha1.ComputeHash(digestbuf));
                //SHA256 sha256 = SHA256.Create();
                //string digest = Convert.ToBase64String(sha256.ComputeHash(digestbuf));
                                
                Return.UserName = username;
                Return.Password = digest;
                Return.Nonce = Convert.ToBase64String(nonce);
                Return.Created = createtime;
                Return.Expaire = expiretime;
            }
            catch
            {
            }
            return Return;
        }


C#
public struct UserCredential
{
    public string UserName;
    public string Password;
    public string Nonce;
    public string Created;
    public string Expaire;
}


but while send the Soap message request, it alway response as Authentication failed.
Request:
XML
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:wsdl="http://www.onvif.org/ver10/device/wsdl">
  <soap:Header>
    <wsse:Security soap:mustUnderstand = "true" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
      <wsse:UsernameToken wsu:Id="UsernameToken-3ae8d972-d014-47b0-858b-2364f6119763" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
        <wsse:Username>service</wsse:Username>
        <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">jJdUs+AXDHZou8EmltlzwwNbe/M=</wsse:Password>
        <wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">V0db+It+XZpH5s2mrh1ylA==</wsse:Nonce>
        <wsu:Created>2010-11-22T06:43:47.61Z</wsu:Created>
      </wsse:UsernameToken>
    </wsse:Security>
  </soap:Header>
  <soap:Body>
    <tds:GetDeviceInformation xmlns:tet="http://www.onvif.org/ver10/events/wsdl" xmlns:tt="http://www.onvif.org/ver10/schema" xmlns:trt="http://www.onvif.org/ver10/media/wsdl" xmlns:timg="http://www.onvif.org/ver10/imaging/wsdl" xmlns:tds="http://www.onvif.org/ver10/device/wsdl" />
  </soap:Body>
</soap:Envelope>

Response:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope" xmlns:SOAP-ENC="http://www.w3.org/2003/05/soap-encoding" xmlns:ter="http://www.onvif.org/ver10/error">
  <SOAP-ENV:Body>
    <SOAP-ENV:Fault>
      <SOAP-ENV:Code>
        <SOAP-ENV:Value>SOAP-ENV:Sender</SOAP-ENV:Value>
        <SOAP-ENV:Subcode>
          <SOAP-ENV:Value>ter:NotAuthorized</SOAP-ENV:Value>
          <SOAP-ENV:Subcode>
            <SOAP-ENV:Value>ter:SenderNotAuthorized</SOAP-ENV:Value>
          </SOAP-ENV:Subcode>
        </SOAP-ENV:Subcode>
      </SOAP-ENV:Code>
      <SOAP-ENV:Reason>
        <SOAP-ENV:Text>The requested action requires authorization</SOAP-ENV:Text>
      </SOAP-ENV:Reason>
      <SOAP-ENV:Node>http://www.w3.org/2003/05/soap-envelope/node/ultimateReceiver</SOAP-ENV:Node>
      <SOAP-ENV:Role>http://www.w3.org/2003/05/soap-envelope/node/ultimateReceiver</SOAP-ENV:Role>
    </SOAP-ENV:Fault>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>



I don't know where I am doing the mistake :(

Can anyone help me to solve this problem?
Posted
Updated 8-Mar-17 17:06pm
v2

case sensitive?

Check the bytes you send and the bytes received from the 'encrypted' password - they differ probably.

Check username as well.
 
Share this answer
 
This problem is solved, please use Utf-8 encoding instead of unicode

MIDL
byte[] digestbuf = new byte[nonce.Length + Encoding.UTF8.GetByteCount(createtime + password)];
nonce.CopyTo(digestbuf, 0);
Encoding.UTF8.GetBytes(createtime + password).CopyTo(digestbuf, nonce.Length);


:thumbsup: Cheers up,
Vasanth
 
Share this answer
 
Comments
Dalek Dave 2-Dec-10 3:34am    
Good Call.
Member 13042474 10-Mar-17 0:29am    
Hello.
I don't know if I can hear the response because it is a very old post.
I don't know because I am the first programmer.
In your post, " credential = AuthenticationCore (" service "," service ");"

I do not understand this part.
so, I added this to the sentence.
"UserCredential credential = new UserCredential();"

Then, the error is gone, but the authentication is denied.


Accound: admin / admin
Debug.WriteLine(credential.UserName + " " + credential.Password + " " + credential.Nonce + " " + credential.Created + " " + credential.Created);

Result: admin aXeERaYZqMkXsIIsnsiVh0NQdUM = 5eWn2SRx67nMS / 3C5ha6AQ == 2017-03-10T05: 20: 32.129Z 2017-03-10T05: 20: 32.129Z


Can I hear the explanation?

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900