Permission denied error with video streaming
AnsweredHopefully someone can help. I have a web page that is trying to stream 1 or more camera streams using the API (in this example 3). I'm using chrome as my web browser
I start by requesting the Nonce:
http://<>/api/getNonce?_=1613682154947
{"error":"0","errorString":"","reply":{"nonce":"<>","realm":"VMS"}}
which I used to build the I then check to make sure there is video available (since our cameras are only set to record on motion). All three return that video is available:
http://<>/ec2/recordedTimePeriods?auth=<>&cameraId=306924b1-3628-f4fe-859c-37b760c419e1&startTime=2021-02-18T15:45:57.000Z&endTime=2021-02-18T15:46:57.000Z&groupBy=none&_=1613682154948
{"error":"0","errorString":"","reply":[{"durationMs":"60400","startTimeMs":"1613663127005"}]}
http://<>/ec2/recordedTimePeriods?auth=<>&cameraId=f1e10123-c06f-dba8-7e03-bce8aa1096b5&startTime=2021-02-18T15:45:57.000Z&endTime=2021-02-18T15:46:57.000Z&groupBy=none&_=1613682154949
{"error":"0","errorString":"","reply":[{"durationMs":"150005","startTimeMs":"1613663100560"}]}
http://<>/ec2/recordedTimePeriods?auth=<>&startTime=2021-02-18T15:45:57.000Z&endTime=2021-02-18T15:46:57.000Z&groupBy=none&_=1613682154950
{"error":"0","errorString":"","reply":[{"durationMs":"15730","startTimeMs":"1613663207103"}]}
Then I request the stream. Many of my camera are returning a 403 forbidden, but not all of them:
http://<>/media/306924b1-3628-f4fe-859c-37b760c419e1.webm?auth=<>&pos=2021-02-18T15:45:57.000Z&endPos=2021-02-18T15:46:57.000Z&resolution=702p&sfd
403 forbidden
http://<>/media/f1e10123-c06f-dba8-7e03-bce8aa1096b5.webm?auth=<>&pos=2021-02-18T15:45:57.000Z&endPos=2021-02-18T15:46:57.000Z&resolution=702p&sfd
streaming
http://<>/media/132dc755-7073-aff1-cef2-4b1b2db1ece7.webm?auth=<>&pos=2021-02-18T15:45:57.000Z&endPos=2021-02-18T15:46:57.000Z&resolution=702p&sfd
403 forbidden
I have the same issue trying to request an image :
http://<>/api/getNonce?_=1613683803093
http://<>/ec2/cameraThumbnail?auth=<>&cameraId=306924b1-3628-f4fe-859c-37b760c419e1&time=2021-02-18T15:46:27.000Z&height=240&width=240
403 forbidden
http://<>/ec2/cameraThumbnail?auth=<>&cameraId=f1e10123-c06f-dba8-7e03-bce8aa1096b5&time=2021-02-18T15:46:27.000Z&height=240&width=240
image
http://<>/ec2/cameraThumbnail?auth=<>&cameraId=132dc755-7073-aff1-cef2-4b1b2db1ece7&time=2021-02-18T15:46:27.000Z&height=240&width=240
403 forbidden
I'm guessing is it some sort of permission setting, but I don't have a clue where to start looking.
-
Hello Brian,
could you please show me the code which you use to build auth string? Do you use the same auth string for all requests or do you generate a new one for each request? Do you have a single VMS server or multi-server environment?
Also, please tell me VMS version and build number.0 -
Thanks for the quick response.
Version 4.1.0.32405 Platform windows_x64 My cameras are spread across multiple VMS servers. In my example above, I am using the same VMS server for all the requests (call it #1). Camera 306924b1 and f1e10123 on #1, camera 132dc755 is on #2. I have configured it to make sure the request goes to the server the camera is assigned to with the same results.
I generate 1 auth string per server (in this case one server) per page load. That string is used for all requests.
It seems to always work for (in this example) camera f1e10123, but never for the other two.
Here is my code:
var auths = [];
function nxwEpochSecToTimeSting(time) {
var stimeMS = time * 1000,
stimeStr = new Date(stimeMS).toISOString();
return stimeStr;
}
function nxwVideoServerReq(url) {
var ajaxData;
$.ajax({
type: 'GET',
url: url,
cache: false,
async: false,
success: function(response) {
ajaxData = response;
},
error: function(jqXHR, textStatus, errorThrown) {
ajaxData = errorThrown;
},
});
return ajaxData;
}
function nxwCreateAuth(urlPrefix, username, password) {
var urlPrefix, nonceJSON, auth = '';
nonceJSON = nxwVideoServerReq(urlPrefix + '/api/getNonce');
if (nonceJSON.error == '0')
{
var nonce, realm, digest, partial_ha2, simplified_ha2;
nonce = nonceJSON.reply.nonce;
realm = nonceJSON.reply.realm;
digest = md5(username + ":" + realm + ":" + password);
partial_ha2 = md5("GET:");
simplified_ha2 = md5(digest + ":" + nonce + ":" + partial_ha2);
auth = btoa(username + ":" + nonce + ":" + simplified_ha2);
}
return auth;
}
function videoInit() {
auths = [];
}
function isVideoAvailable(cameraInfo, cameraOffset) {
var ip = cameraInfo.camera[cameraOffset][2],
stime = nxwEpochSecToTimeSting(cameraInfo.videoStartTime)
etime = nxwEpochSecToTimeSting(cameraInfo.videoEndTime),
urlPrefix = 'http://' + ip + ":" + cameraInfo.camera[cameraOffset][3],
availableJSON = '';
if (auths[ip] === undefined)
{
auths[ip] = nxwCreateAuth(urlPrefix, cameraInfo.username, cameraInfo.password);
}
availableJSON = nxwVideoServerReq(urlPrefix +
'/ec2/recordedTimePeriods' +
'?auth=' + auths[ip] +
'&cameraId=' + cameraInfo.camera[cameraOffset][1] +
'&startTime=' + stime +
'&endTime=' + etime +
'&groupBy=none');
if (availableJSON.error === '0' &&
availableJSON.reply.length > 0)
{
return true;
}
return false;
}
function buildVideoURL(cameraInfo, cameraOffset) {
var stime = nxwEpochSecToTimeSting(cameraInfo.videoStartTime)
etime = nxwEpochSecToTimeSting(cameraInfo.videoEndTime),
ip = cameraInfo.camera[cameraOffset][2],
urlPrefix = 'http://' + ip + ":" + cameraInfo.camera[cameraOffset][3],
url = '';
if (auths[ip] === undefined)
{
auths[ip] = nxwCreateAuth(urlPrefix, cameraInfo.username, cameraInfo.password);
}
return urlPrefix +
'/media/' + cameraInfo.camera[cameraOffset][1] + '.webm' +
'?auth=' + auths[ip] +
'&pos=' + stime +
'&endPos=' + etime +
'&resolution=' + cameraInfo.camera[cameraOffset][4] +
'&sfd';
}
function buildImgUrl(cameraInfo, cameraOffset) {
var time = nxwEpochSecToTimeSting(cameraInfo.eventTime),
ip = cameraInfo.camera[cameraOffset][2],
urlPrefix = 'http://' + ip + ":" + cameraInfo.camera[cameraOffset][3]
url = '';
if (auths[ip] === undefined)
{
auths[ip] = nxwCreateAuth(urlPrefix, cameraInfo.username, cameraInfo.password);
}
return urlPrefix +
'/ec2/cameraThumbnail' +
'?auth=' + auths[ip] +
'&cameraId=' + cameraInfo.camera[cameraOffset][1] +
'&time=' + time +
'&height=240' +
'&width=240';
}
function showVideoDialog(webVersion, dialogTitle, dialogBodyLabel, cameraInfo) {
var cameraCount = cameraInfo.camera.length,
tabStr = '',
nav = '',
pane = '',
i;
videoInit();
for (i = 0; i < cameraCount; i++)
{
nav += '<li class="nav-item">' +
'<a class="nav-link' + (i == 0 ? ' active' : '') + '" id="video-nav-tab-' + i + '" data-toggle="tab" href="#video-tab-' + i + '" role="tab" aria-controls="tab-' + i + '" aria-selected="true">' + cameraInfo.camera[i][0] + '</a>' +
'</li>';
pane += '<div class="tab-pane fade show' + (i == 0 ? ' active' : '') + '" id="video-tab-' + i + '" role="tabpanel" aria-labelledby="video-nav-tab-' + i + '">' +
'<pre style="overflow: hidden;">';
if (isVideoAvailable(cameraInfo, i))
{
pane += '<div class="stageVideo">' +
'<video id="video-' + i + '" name="media" style="margin-top: 10px;" controls>' +
'<source src="' + buildVideoURL(cameraInfo, i) + '" type="video/webm">' +
'</video>' +
'</div>';
}
else
{
pane += '<div class="stageNotAvail">' +
'<i class="fa fa-video-slash fa-5x"></i>' +
'</div>';
}
pane += '</pre>' +
'</div>';
}
tabStr = '<ul class="nav nav-tabs" id="videoTab" role="tablist">' +
nav +
'</ul>' +
'<div class="tab-content" id="videoTabContent">' +
pane +
'</div>';
$('#videoTitle').html(dialogTitle);
$('#videoBodyLabel').html(dialogBodyLabel);
$('#videoBody').html(tabStr);
}
$("#videoModal").modal();
}
function showPictureDialog(dialogTitle, bodyLabel, cameraInfo) {
var tabStr = '',
nav = '',
pane = '',
i;
videoInit();
for (i = 0; i < cameraInfo.camera.length; i++)
{
nav += '<li class="nav-item">' +
'<a class="nav-link' + (i == 0 ? ' active' : '') + '" id="pic-nav-tab-' + i + '" data-toggle="tab" href="#pic-tab-' + i + '" role="tab" aria-controls="tab-' + i + '" aria-selected="true">' + cameraInfo.camera[i][0] + '</a>' +
'</li>';
pane += '<div class="tab-pane fade show' + (i == 0 ? ' active' : '') + '" id="pic-tab-' + i + '" role="tabpanel" aria-labelledby="pic-nav-tab-' + i + '">' +
'<img class="img-fluid" src="' + buildImgUrl(cameraInfo, i) + '">' +
'</div>';
}
tabStr = '<ul class="nav nav-tabs" id="pictureTab" role="tablist">' +
nav +
'</ul>' +
'<div class="tab-content" id="pictureTabContent">' +
pane +
'</div>';
$('#pictureTitle').html(dialogTitle);
$('#pictureBodyLabel').html(bodyLabel);
$('#pictureBody').html(tabStr);
$("#pictureModal").modal();
}0 -
Brian, from the first look, I don't see that anything is wrong with your code.
Such behaviour can occur when your user doesn't have permission to access all the cameras. Do you have same issue when using admin's login/password for generating auth string?
VMS server allows building custom access roles without full access to all the cameras.

I was able to reproduce your scenario with permission like on the screenshot above, so this seems like the most logical cause for your issue.
0 -
Anton,
Changing to the admin account seems to have fixed the problem. I will talk to our camera admin to get the permissions changed. Thank you so much for your help.
0
Please sign in to leave a comment.
Comments
4 comments