How to use endpoint ServerCommandService.svc?

I am trying to figure out how to use Protocol integration and am hoping someone can point me in the right direction.

From the documentation:

---------------------------------------------------

Login and register using ServerCommandService.asmx

The following example assumes that you are using a HTTP library or class that supports Windows authentication.

POST /ServerAPI/ServerCommandService.asmx HTTP/1.1

Host: {xprotectserver.company.com}

Authorization: {generated by HTTP library or class applied}

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

Content-Length: {number of bytes}

SOAPAction: http://videoos.net/2/XProtectCSServerCommand/Login"

<?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

 <instanceId>{guid}</instanceId>

 <currentToken>{token}</currentToken>

</soap:Body>

</soap:Envelope>

To initiate a new session, create a new GUID value for the initial login request.

Omit the element in the initial login request in a session.

-------------------------------------------

I have gleaned enough information to create this code that returns a Token:

AuthRequest.py:

import requests
 
from requests_ntlm import HttpNtlmAuth
 
import uuid
 
from xml.etree import ElementTree as ET
 
from collections import namedtuple
 
 
class AuthRequest:
 
   def __init__(self, url, username, password):
 
       self.url = url
 
       self.username = username
 
       self.password = password
 
 
   def send_request(self):
 
       # Generate a GUID
 
       guid = str(uuid.uuid4())
 
 
       # Define the request headers
 
       headers = {
 
           'Content-Type': 'text/xml; charset=utf-8',
 
           'SOAPAction': 'http://videoos.net/2/XProtectCSServerCommand/Login',
 
       }
 
 
       # Construct the SOAP request payload
 
       soap_request = '''<?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>
 
           <Login xmlns="http://videoos.net/2/XProtectCSServerCommand">
 
             <instanceId>{guid}</instanceId>
 
           </Login>
 
         </soap:Body>
 
       </soap:Envelope>'''.format(guid=guid)
 
 
       # Send the HTTP POST request with Windows authentication
 
       response = requests.post(self.url, headers=headers, auth=HttpNtlmAuth(self.username, self.password), data=soap_request)
 
       print(response)
 
       # Create the Response object
 
       Response = namedtuple('Response', ['output', 'code', 'fulltoken', 'token'])
 
 
       # Parse the XML response content to get the Token
 
       root = ET.fromstring(response.text)
 
       token_element = root.find(".//{http://videoos.net/2/XProtectCSServerCommand}Token")
 
       if token_element is not None:
 
           fulltoken = token_element.text
 
           token = fulltoken.split('#')[1]
 
       else:
 
           fulltoken = "No Token Found in Response"
 
           token = ''
 
 
       response_object = Response(
 
           output = response.text,
 
           code = str(response.status_code),
 
           fulltoken = fulltoken,
 
           token = token
 
       )
 
 
       # Create the Result object
 
       Result = namedtuple('Result', ['headers', 'response'])
 
       headers = {header: value for header, value in response.request.headers.items()}
 
       result = Result(headers = headers, response = response_object)
 
 
       return result

Which is called by:

test:

from AuthRequest import AuthRequest
 
auth = AuthRequest('http://SERVERNAME/ServerCommandService.asmx', 'USERNAME', 'PASSWORD')
 
result = auth.send_request()
 
 
print("Headers:", result.headers)
 
print("Response Output:", result.response.output)
 
print("Response Code:", result.response.code)
 
print("Response Token:", result.response.token)

and returns the following:

---------------------------------------

<Response [200]>

Headers: {‘User-Agent’: ‘python-requests/2.28.1’, ‘Accept-Encoding’: ‘gzip, deflate’, ‘Accept’: ‘*/*’, ‘Connection’: ‘Keep-Alive’, ‘Content-Type’: ‘text/xml; charset=utf-8’, ‘SOAPAction’: ‘http://videoos.net/2/XProtectCSServerCommand/Login’, ‘Content-Length’: ‘456’, ‘Authorization’: ‘NTLM TlRMTVNTUAADAAAAGAAYAIIAAAA+AT4BmgAAAAoACgBYAAAADgAOAGIAAAASABIAcAAAABAAEADYAQAANYKI4goAYUoAAAAPvWbfrSlFv1ACTRh5eX0td1MARgBBAFMAVQBlAGQAZQBuAHMAagBjAFUAUABEADEANAAwADYANQA2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH5sKAv+h/ZYrYwqdaEBoxoBAQAAAAAAAH+tOrODg9kB4d4zHRpUu7kAAAAAAgAKAFMARgBBAFMAVQABABoATQBJAEwARQBTAFQATwBOAEUALQBTAFYAUgAEABIAcwBmAGEAcwB1AC4AbgBhAGMAAwAuAE0AaQBsAGUAUwB0AG8AbgBlAC0AUwBWAFIALgBzAGYAYQBzAHUALgBuAGEAYwAFABIAcwBmAGEAcwB1AC4AbgBhAGMABwAIAH+tOrODg9kBBgAEAAIAAAAIADAAMAAAAAAAAAABAAAAACAAALpBDZtlW/WHp6uYZhJT7SyudfhICM6+nb5e+5XLa3V6CgAQAAAAAAAAAAAAAAAAAAAAAAAJACAAaABvAHMAdAAvAHUAbgBzAHAAZQBjAGkAZgBpAGUAZAAAAAAAAAAAAL09AL21kQQXiEUBz2WPpRo=’}

Response Output: <?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap=“http://schemas.xmlsoap.org/soap/envelope/” xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance” xmlns:xsd=“http://www.w3.org/2001/XMLSchema”>soap:BodyTOKEN#1c03932a-eccb-47f5-aaef-78d272af4b0f#SERVERNAME//ServerConnector#2023-05-10T21:09:26.387Z14400000000false</soap:Body></soap:Envelope>

Response Code: 200

Response Token: 1c03932a-eccb-47f5-aaef-78d272af4b0f

--------------------------------------------------------------------

Okay, step one done - but “The ServerAPI/ServerCommandService.asmx endpoint is deprecated, but useful for illustrating the initial login process.

So how do I go about doing this using the endpoint ManagementServer/ServerCommandService.svc ?

Maybe it is just a matter of using that endpoint in the URL, so I modify the first test program:

test2:

from AuthRequest import AuthRequest
 
auth = AuthRequest('http://SERVERNAME/ManagementServer/ServerCommandService.svc', 'USERNAME', 'PASSWORD')
 
result = auth.send_request()
 
 
print("Headers:", result.headers)
 
print("Response Output:", result.response.output)
 
print("Response Code:", result.response.code)
 
print("Response Token:", result.response.token)

and that returns a 415 error code which suggests that the server refused to accept the request because the media type or representation of the request is not supported by the server.

So I’m wondering if this reference is wrong:

http://videoos.net/2/XProtectCSServerCommand/Login

Should it reference another document?

Or is something else going on?

I suspect you find the answers if you look at the protocol samples, primary sample on how to login is the Login .NET Soap sample.

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

https://github.com/milestonesys/mipsdk-samples-protocol

I’ve hardly touched Python in the last decade and this code was only written for testing purposes while trying to figure out an easy way to use the WCF endpoints from Python, but hopefully it helps.

https://github.com/joshooaj/PythonLib/blob/main/test.py

What I wanted to do was pretend that those nasty soap xml blobs don’t exist because there are about a thousand better things we should be doing with our time than constructing soap messages and interpreting responses. So I needed a Python library for generating WCF proxy clients from the WSDL provided by the endpoints.

As far as I can tell, zeep is it. If you happen to come across a better option let me know :slight_smile:

So using zeep we can create a client and pass it the URL for the WSDL file of the service we want to use. The WSDL describes the endpoint and the methods/types/parameters associated with it, kind of like a swagger/openapi spec for a REST api.

The test code I wrote should hopefully get you logged in using a basic user - I haven’t tried supporting windows authentication as I’m pretty sure the WSHttp bindings are about as cross-platform un-friendly as it gets.

Note that once you’re logged in, you’ll want to have a timer kicking off a token renewal/login task before your token expires. Also this example only uses ServerCommandService, and a more well-rounded implementation should probably also support ServerCommandServiceOauth and intelligently choose the best available interface similar to the C# protocol examples.

HI Josh, thanks very much for this! While I am flattered by Bo’s suggestion that my skills are strong enough to figure out how to make these calls by studying the C# example, I fear his confidence is misplaced…

I understand what you mean about the benefits of abstracting away the complexities of the soap messages. That certainly makes sense for folks who have a good grasp of how those work, but I found a lot of value in working through the .asmx example in terms of figuring out what was going on ‘under the hood’.

I’m looking forward to working with your sample code. I suspect that zeep has functionality that will expose the underlying soap it generates.