Watch, Follow, &
Connect with Us

For forums, blogs and more please visit our
Developer Tools Community.


Welcome, Guest
Guest Settings
Help

Thread: XML well-formed violation occurred.



Permlink Replies: 1 - Last Post: Mar 8, 2017 9:40 AM Last Post By: ioan ghip
ioan ghip

Posts: 40
Registered: 3/16/00
XML well-formed violation occurred.
Click to report abuse...   Click to reply to this thread Reply
  Posted: Mar 7, 2017 10:20 AM
I'm trying to figure out how ONVIF (Open Network Video Interface Forum) works and I'm getting the error: XML well-formed violation occurred.

ONVIF is an open standard for the interface of physical IP-based security products. The interface is SOAP based. I can't use the WSDL importer because the code in Delphi is just for testing, when everything works I want to convert it to Bright Script (Roku's programming language) which has just basic tcp/ip communication.

Here is the important bit from ONVIF documentation:

6.1.1.3 ONVIF::AuthenticatingByWS-UsernameToken
When a device requires authentication through WS-UsernameToken, the client must set user
information with the appropriate privileges in WS-UsernameToken. This use case contains an
example of setting that user information using SetHostname.
 
WS-UsernameToken requires the following parameters:
 
* Username – The user name for a certified user.
* Nonce – A random, unique number generated by a client.
* Created – The UtcTime when the request is made.
* Password – The password for a certified user. According to the ONVIF specification, 
Password should not be set in plain text. Setting a password generates
PasswordDigest, a digest that is calculated according to an algorithm defined in the specification for WS-UsernameToken:
 
Digest = B64ENCODE( SHA1( B64DECODE( Nonce ) + Date + Password ) )
 
For example:
* Nonce – LKqI6G/AikKCQrN0zqZFlg==
* Date – 2010-09-16T07:50:45Z
* Password – userpassword
* Resulting Digest – tuOSpGlFlIXsozq4HFNeeGeFLEI=


... and their example code:

// The user name of a certified user is set
wsUsernameToken.Username = "username";
 
// A random number value generated with a client uniquely is set
nonceBinaryData = getNonce();
nonceBase64 = base64(nonceBinaryData);
wsUsernameToken.Nonce = nonceBase64;
 
// The time at the time of the request making is set
utctimeData = getUTCTime();
utctimeStringData = uTCTime2DatetimeString(utctimeData);
utctimeBinaryData = string2Binary(utctimeStringData);
wsUsernameToken.Created = utctimeStringData;
 
// The password digest of a certified user is set
password = "userpassword";
passwordBinaryData = string2Binary(password);
passwordDigest = SHA1(nonceBinaryData + utctimeBinaryData + passwordBinaryData);
passwordDigestBase64 = base64(passwordDigest);
wsUsernameToken.Password = passwordDigestBase64;
wsUsernameToken.PasswordType = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest";


... and here is how my test code looks like:


  function HashSHA1(const astr: String): String;
  var
    SHA1: TIdHashSHA1;
  begin
    SHA1 := TIdHashSHA1.Create;
    try
      Result := LowerCase(SHA1.HashStringAsHex(astr));
    finally
      SHA1.Free;
    end;
  end;
 
const
  AuthHeader =
      '<s:Header>'+
          '<Security>'+
            '<UsernameToken>'+
                '<Username>{%username%}</Username>'+
                '<Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">{%password%}</Password>'+
                '<Nonce>{%nonce%}</Nonce>'+
                '<Created>{%date%}</Created>'+
            '</UsernameToken>'+
          '</Security>'+
      '</s:Header>';
 
  
  GetProfiles = '<?xml version="1.0" encoding="UTF-8"?>' +
                  '<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:trt="http://www.onvif.org/ver10/media/wsdl">' +
                 '{%header%}'+
                  '<soap:Body>' +
                    '<trt:GetProfiles/>' +
                  '</soap:Body>' +
                  '</soap:Envelope>';
 
 
 
  // A random number value generated with a client uniquely is set
  nonce := IntToStr(Random(99999999));
 
  nonceBase64 := TNetEncoding.Base64.EncodeBytesToString(ToBytes(nonce));
 
  // The time at the time of the request making is set
  utctimeStringData := DateToISO8601(now - OffsetFromUTC);
 
  // The password digest of a certified user is set
  passwordDigestBase64 := TNetEncoding.Base64.EncodeBytesToString(ToBytes(HashSHA1(nonce + utctimeStringData + 'my_password')));
 
  header := StringsReplace(AuthHeader, ['{%username%}', '{%password%}', '{%nonce%}', '{%date%}'], ['my_username', passwordDigestBase64, nonceBase64, utctimeStringData]);
 
  lParamList := TStringList.Create;
  fsParams:= TMemoryStream.Create;
  lParamList.Text := StringReplace(GetProfiles, '{%header%}', header, [rfReplaceAll]);
 
  lParamList.SaveToStream(fsParams);
  lHTTP := TIdHTTP.Create(nil);
  try
    lHTTP.Request.ContentType := 'application/soap+xml; charset=utf-8; action="http://www.onvif.org/ver10/media/wsdl/GetProfiles"';
    Result := lHTTP.Post('http://' + IP + ':' + IntToStr(PORT) +'/onvif/services', fsParams);
  finally
    lHTTP.Free;
    lParamList.Free;
    fsParams.Free;
  end;


Here is the ONVIF wsdl:
https://www.onvif.org/onvif/ver10/media/wsdl/media.wsdl

... and here is the Wireshark capture of my request:
https://sites.google.com/site/ioanghip/capture.txt?attredirects=0&d=1

Edited by: ioan ghip on Mar 7, 2017 10:24 AM
ioan ghip

Posts: 40
Registered: 3/16/00
Re: XML well-formed violation occurred.
Click to report abuse...   Click to reply to this thread Reply
  Posted: Mar 8, 2017 9:40 AM   in response to: ioan ghip in response to: ioan ghip
I'm answering my own question. The soap message had to be changed to this, to not get the error:


  AuthHeader =
      '<s:Header>' +
          '<Security s:mustUnderstand="1" xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">' +
              '<UsernameToken>' +
                  '<Username>{%username%}</Username>' +
                  '<Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">{%password%}</Password>' +
                  '<Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">{%nonce%}</Nonce>' +
                  '<Created xmlns="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">{%date%}</Created>' +
              '</UsernameToken>' +
          '</Security>' +
      '</s:Header>';
 
  GetProfiles = '<?xml version="1.0" encoding="UTF-8"?>' +
                '<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope">' +
                '{%header%}' +
                '<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">' +
                '<GetProfiles xmlns="http://www.onvif.org/ver10/media/wsdl"/>' +
                '</s:Body>' +
                '</s:Envelope>';
 
 
Legend
Helpful Answer (5 pts)
Correct Answer (10 pts)

Server Response from: ETNAJIVE02