I can't use protocol integration to get information

How to Authenticate using SOAP? followed the documentation but without success

We have installed Milestone XProtect VMS Products 2019 R2 System Installer.exe and I followed the instruction in to login using SOAP Requests. https://doc.developer.milestonesys.com/html/index.html?base=reference/architecture/product_support.html&tree=tree_3.html without sucess.

I used the same username/password we used to login into XProtect Management Client 1019 R2 with basic authentication.

Below you can see the HTTP messages during our test captured from Wireshark.

We found in the developer forms question regarding this and they pointed to run your samples and capture the network to see what it was sent. We can’t see the content of the message because your samples are sending the data in https and the data is encrypted.

POST /ServerAPI/ServerCommandService.asmx HTTP/1.1

Content-Length: 399

Content-Type: text/xml; charset=UTF-8

Host: 192.168.1.121

Connection: Keep-Alive

User-Agent: Apache-HttpClient/4.2.1 (java 1.5)

<?xml version="1.0" encoding="utf-8"?>

<soap:Envelope xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance xmlns:xsd=“http://www.w3.org/2001/XMLSchema” xmlns:soap=“http://schemas.xmlsoap.org/soap/envelope/”>

soap:Body

fc0352e7-6a7a-418b-ad1d-2f16c09adddf

</soap:Body>

</soap:Envelope>

HTTP/1.1 401 Unauthorized

Content-Type: text/html

Server: Microsoft-IIS/10.0

WWW-Authenticate: Negotiate

WWW-Authenticate: NTLM

X-Powered-By: ASP.NET

X-Frame-Options: SAMEORIGIN

Date: Wed, 30 Jan 2019 14:41:20 GMT

Content-Length: 1293

401 - Unauthorized: Access is denied due to invalid credentials.

Server Error

401 - Unauthorized: Access is denied due to invalid credentials.

You do not have permission to view this directory or page using the credentials that you supplied.

There is a newer page on protocol integration that might be helpful.

https://doc.developer.milestonesys.com/html/index.html?base=gettingstarted/intro_soap_protocols.html&tree=tree_4.html

Sometimes seeing the code implemented in the TCP Video Viewer sample is very helpful.

https://doc.developer.milestonesys.com/html/index.html?base=samples/tcpviewer_sample.html&tree=tree_3.html

This issue can sometimes be caused if you are not sending an InstanceGuid when you obtain the token. To fix it, generate a random GUID (Free Online GUID Generator) for your application, and store it. Then include it always when obtaining the token.

A sample body would be the following one:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xpr="http://videoos.net/2/XProtectCSServerCommand">
   <soapenv:Header/>
   <soapenv:Body>
      <xpr:Login>
      <xpr:instanceId>DDF4BA55-808E-479F-BE8B-72F69913442F</xpr:instanceId>
      </xpr:Login>
   </soapenv:Body>
</soapenv:Envelope>

Here is a sample of how to obtain a token using Node.js.

const xml2js = require("xml2js");
 
const INTEGRATION_INSTANCE_ID = 'd3cd8c36-bbc9-4528-8509-e7dd8898d24a';
const TOKEN_REQUEST_BODY =  `<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xpr="http://videoos.net/2/XProtectCSServerCommand">
   <soapenv:Header/>
   <soapenv:Body>
      <xpr:Login>
        <xpr:instanceId>${INTEGRATION_INSTANCE_ID}</xpr:instanceId>
      </xpr:Login>
   </soapenv:Body>
</soapenv:Envelope>`;
const SOAP_ACTION = 'http://videoos.net/2/XProtectCSServerCommand/IServerCommandService/Login';
const MANAGEMENT_SERVER_HOST = '127.0.0.1';  // IP of the Management server
 
 
/**
 * encodes a string to base64
 *
 * @param data, a string
 * @returns data but base64 encoded
 */
const toBase64 = (data) => new Buffer.from(data).toString('base64');
 
/**
 * returns the basic HTTP authentication header
 * @param username
 * @param password
 * @returns the HTTP basic auth header
 */
const basicAuth = (username, password) => `Basic ${toBase64(`${username}:${password}`)}`;
 
/**
 * parses the token from the xml response body
 * @returns the token
 */
async function getToken(xml){
    const parser = new xml2js.Parser();
 
    return new Promise((resolve, reject) =>
        parser.parseStringPromise(xml).then(function (result) {
        resolve(result['s:Envelope']['s:Body'][0]['LoginResponse'][0]['LoginResult'][0]['Token'][0]);
    }).catch(function (err) {
      reject(err);
    }));
}
 
/**
 * @param username, a Basic user username
 * @param password, a Basic user password
 * @returns the management server token
 */
const getSessionKey = async (username, password) => {
    if (!username) throw new Error("empty username");
    if (!password) throw new Error("empty password");
 
    // exchange username+password for a token through the Management Server
    const response = await request({
        url: `https://${MANAGEMENT_SERVER_HOST}/ManagementServer/ServerCommandService.svc`,
        method: 'POST',
        headers: {
            'content-type': 'text/xml;charset=UTF-8',
            'accept': '*/*',
            'SOAPAction': SOAP_ACTION,
            'Authorization': basicAuth(`[BASIC]\\\\${username}`, password)
        },
        body: TOKEN_REQUEST_BODY
    });
 
    // parse token from response
    const token = await getToken(response.content)
 
    return token;
};