Authentication and authorization
To use any of the SOAP services or the ImageServer protocol, you must first authenticate and login to the XProtect VMS, using the ServerCommandService
to obtain authentication tokens for the session.
ServerCommandService
endpoints
There are currently three ServerCommandService
endpoints available:
ManagementServer/ServerCommandServiceOAuth.svc
XProtect 2021R1 or later. Provides better security for Basic users if accessed over HTTPS.ManagementServer/ServerCommandService.svc
ServerAPI/ServerCommandService.asmx
Use ManagementServer/ServerCommandServiceOAuth.svc
or ManagementServer/ServerCommandService.svc
for new development. Most of the protocol samples relies on a convenience wrapper, ServerCommandWrapper
, that uses ServerCommandServiceOAuth.svc
if available and falls back on ServerCommandService.svc
.
The ServerAPI/ServerCommandService.asmx
endpoint is deprecated, but useful for illustrating the initial login process.
Authentication method
Three authentication methods are available:
- OpenID Connect and OAuth2, authenticating towards an identity provider service (IDP), either internal or external (external IDP supported in 2022 R1 and later). Authenticates users created as Basic or Windows users. Supported in XProtect 2021R1 or later.
- XProtect Basic user credentials, using HTTP Basic Authentication over HTTPS..
- Windows user credentials, using Kerberos or NTLM to authenticate towards a Windows AD domain or workgroup.
The convenience wrapper, ServerCommandWrapper
used by most of the protocol samples will use ServerCommandServiceOAuth.svc
if available and falls back on ServerCommandService.svc
.
Register your protocol integration application
You are encouraged to register your application after each initial login. This will provide data for reporting applications used at this XProtect VMS site. The feature is available in XProtect 2020 R3 and later releases.
The ServerCommandWrapper
for ServerCommandServiceOAuth.svc
and ServerCommandServiceOAuth.svc
includes an overloaded Login()
method that takes care of the registration.
When registering your application, you provide the following information:
Parameter | Type | Description |
---|---|---|
instanceId | string | Identifier uniquely identifying the calling instance. Typically, each ID should refer to a specific machine running an integration. |
integrationId | guid | Unique identifier representing the integration. Should be hardcoded in the integrating application. |
integrationVersion | string | Version of the calling application. |
integrationName | string | Name of the calling application. |
manufacturerName | string | Name of the manufacturer of the calling application |
All strings are max 256 characters.
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> <Login xmlns="http://videoos.net/2/XProtectCSServerCommand"> <instanceId>{guid}</instanceId> <currentToken>{token}</currentToken> </Login> </soap:Body> </soap:Envelope>
- To initiate a new session, create a new GUID value for the initial login request.
- Omit the
<currentToken>
element in the initial login request in a session.
If the login is successful, you will receive a response which looks like this:
HTTP/1.1 200 OK Content-Type: text/xml; charset=utf-8 Content-Length: {length} <?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> <LoginResponse xmlns="http://videoos.net/2/XProtectCSServerCommand"> <LoginResult> <Token>{token}</Token> <RegistrationTime>{DateTime}</RegistrationTime> <TimeToLive> <MicroSeconds>{valid period}</MicroSeconds> </TimeToLive> </LoginResult> </LoginResponse> </soap:Body> </soap:Envelope>
- During the "valid period", you can use the token you received for any number of ImageServer connect requests and SOAP requests.
- Just before the current token expires, submit a login request again to renew the session and receive a new token, using the
instanceId
and currenttoken
. - Pass the new token to all open ImageServer session, using the
connectupdate
request, and use the new token in subsequent SOAP requests.
Right after authenticating and obtaining a token, submit a RegisterIntegration
request:
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/RegisterIntegration" <?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> <RegisterIntegration xmlns="http://videoos.net/2/XProtectCSServerCommand"> <token>{token}</currentToken> <instanceId>{instanceId}</instanceId> <integrationId>{integrationId}<integrationId> <integrationVersion>{integrationVersion}<integrationVersion> <integrationName>{integrationName}<integrationName> <manufacturerName>{manufacturerName}<manufacturerName> </RegisterIntegration> </soap:Body> </soap:Envelope>
Login and register using ServerCommandServiceOAuth.svc
or ServerCommandService.svc
The TcpVideoViewer
sample illustrates how a convenience wrapper, ServerCommandWrapper
, can simplify authentication and login, and also how to maintain token-authenticated sessions, in this case ImageServer connections. This section highlights the initial login and subsequent re-logins; it is not a complete walk-through of the TcpVideoViewer
sample.
In the TcpVideoViewer
sample, the proxy class SystemAccess
takes care of the connection:
- The
NtlmConnection
andBasicConnection
classes from theServerCommandService
wrapper manages authentication and login forSystemAccess
. TheNtlmConnection()
andBasicConnection
methods in theServerCommandService
wrapper usesManagementServer/ServerCommandServiceOAuth.svc
if available and falls back onManagementServer/ServerCommandService.svc
. - The
NtlmConnection.Login
andBasicConnection.Login
methods are overloaded so that you can do just theLogin
request, or both theLogin
and theRegisterIntegration
requests in oneLogin
call. - The
NtlmConnection.Login
andBasicConnection.Login
methods also set up a timer with a callback that refreshes the token and invokes anOnTokenRefreshed
event. - An event handler in
SystemAccess
subscribes toOnTokenRefreshed
events in order to refresh tokens in current sessions.
public class SystemAccess { private static readonly Guid IntegrationId = new Guid("BE07504F-B330-4475-9AE4-1A7FF10BD486"); private const string IntegrationName = "TCP Video Viewer"; private const string Version = "1.0"; public AuthenticationType AuthenticationType = AuthenticationType.WindowsDefault; public String Server = "localhost"; public String User = ""; public String Password = ""; public String Domain = ""; public LoginInfo LoginInfo; private NtlmConnection _ntlmConnection; private BasicConnection _basicConnection; public event EventHandler<string> OnTokenRefreshed = delegate { }; /// <summary> /// Connect to the specified server /// </summary> /// <param name="server">URL of the server</param> public void Connect(String server) { if (_basicConnection != null) { _basicConnection.OnTokenRefreshed -= _connection_OnTokenRefreshed; _basicConnection.Logout(); _basicConnection = null; } if (_ntlmConnection != null) { _ntlmConnection.OnTokenRefreshed -= _connection_OnTokenRefreshed; _ntlmConnection.Logout(); _ntlmConnection = null; } Server = server; switch (AuthenticationType) { case AuthenticationType.Basic: { int port = 443; _basicConnection = new BasicConnection(User, Password, Server, port); LoginInfo = _basicConnection.Login(IntegrationId, Version, IntegrationName); _basicConnection.OnTokenRefreshed += _connection_OnTokenRefreshed; break; } case AuthenticationType.Windows: case AuthenticationType.WindowsDefault: { _ntlmConnection = new NtlmConnection(Domain, AuthenticationType, User, Password, Server); LoginInfo = _ntlmConnection.Login(IntegrationId, Version, IntegrationName); _ntlmConnection.OnTokenRefreshed += _connection_OnTokenRefreshed; break; } default: //empty break; } } private void _connection_OnTokenRefreshed(object sender, string e) { OnTokenRefreshed.Invoke(this, e); } ...
When the OnTokenRefreshed
event is raised, the new token is passed on to all connections in the session.
/// <summary> /// Interaction logic for WindowMain.xaml /// </summary> public partial class WindowMain : Window , INotifyPropertyChanged { private SystemAccess _sysInfo = new SystemAccess(); ... private ImageServerConnection _isc = null; ... public WindowMain() { ... _sysInfo.OnTokenRefreshed += Token_Refreshed; } private void Token_Refreshed(object sender, string e) { TokenString = e; ... if (_isc != null) { _isc.SetToken(TokenString); // We need to update the Token on the recording server: // This will pass the token back on the live imageserver TCP session using the CONNECTUPDATE command // DoLiveCmd() will do nothing if there is no live sesssion _isc.DoLiveCmd(_isc.FormatConnectUpdate()); // This will cause an active playback to pass the token back on the imageserver TCP session using the CONNECTUPDATE command // If no playback session is active, this will cause no change. _isc.PlaybackSendConnectUpdateFlag = true; } }
ImageServer requests like the connectupdate
request can be wrapped in a simple string formatting function like this:
class ImageServerConnection { ... public string FormatConnectUpdate() { string sendBuffer = string.Format( "<?xml version=\"1.0\" encoding=\"utf-8\"?><methodcall><requestid>{0}</requestid>" + "<methodname>connectupdate</methodname>" + "<connectparam>id={1}&connectiontoken={2}</connectparam>" + "</methodcall>\r\n\r\n", ++_reqCounter, _cameraGuid, _token); return sendBuffer; } ....