HTTP Stream - Intermittent Auth Prompts From Browser

In Progress

Comments

5 comments

  • Avatar
    David Momberger

    Search results (e.g. this one) tell me one solution would be to set the auth type in the request headers to something other than Basic or Digest. The only 2 requests I'm making to the server are:

    • /api/getNonce
    • the full /media/<cameraID>.mp4?auth=.... URL which I'm setting as the video element's source

    I'm assuming getNonce would never return 401, but I tried the header thing anyway and got an error that the header violates CORS policy.

    For the second, I don't see a way to send or modify headers/metadata like that, and even if I could I'm guessing I'd get the same CORS error...

     
    0
    Comment actions Permalink
  • Avatar
    Andrey Terentyev

    Hello David,

    Please provide the following info: OS version, VMS build number.

    Please share the code example reproducing the issue.

    0
    Comment actions Permalink
  • Avatar
    David Momberger

    Hello Andrey,

    OS: Windows x64

    VMS build #: 5.1.0.37133

    Code example:

    <!DOCTYPE html>
    <html lang="en">

    <video id="video_element" muted autoplay></video>

    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/blueimp-md5/2.10.0/js/md5.js"></script>
    <link href="https://unpkg.com/video.js@7.0.0/dist/video-js.css" rel="stylesheet">
    <script src="https://unpkg.com/video.js@7.0.0/dist/video.min.js"></script>

    <script>

        window.VIDEOJS_NO_DYNAMIC_STYLE = true;

        var updateSrc = () => {
            $.ajax({
                url: serverAddress + "/api/getNonce",
                type: "GET",
                success: function (response) {

                    var realm = response.reply.realm;
                    var nonce = response.reply.nonce;
                    var digest = md5(username + ":" + realm + ":" + password);
                    var partial_ha2 = md5("GET" + ":");
                    var simplified_ha2 = md5(digest + ":" + nonce + ":" + partial_ha2);
                    var authKey = btoa(username + ":" + nonce + ":" + simplified_ha2);

                    var cameraURL = serverAddress + '/media/' + cameraId + '.webm?auth=' + authKey;
                    console.log(cameraURL);

                    player.src(cameraURL);
                    player.load();
                    player.play();
                }
            });
        };

        var username = '';
        var password = '';
        var cameraId = '';
        var serverAddress = "https://" + window.location.hostname + ":7001";

        var player = videojs('video_element', {}, function onPlayerReady() {
            updateSrc();
            videojs.log('Your player is ready!');
            this.on('error', () => {
                videojs.log('an error occured, retrying');
                updateSrc();
            })
            this.on('ended', () => {
                videojs.log('playback ended, reloading');
                updateSrc();
            });
        });

    </script>

    </html>
    0
    Comment actions Permalink
  • Avatar
    Andrey Terentyev

    Hello,

    Most probably, the window appears because the session timeout expires.

    There are two things I'd recommend doing.

    1. Use the token based authorization scheme

    here are examples, in python though

    https://github.com/networkoptix/nx_open_integrations/tree/master/python/examples/authentication.

    2. Use this approach

    you make the player and modify the beforeRequest so that it adds the x-runtime-guid header with the vms token

    this.#videojs.Vhs.xhr.beforeRequest = options => {
                if (!options.headers) {
                    options.headers = {};
                }
                if (this.authorization) {
                    options.headers[this.xRuntimeGuid] = this.authorization;
                }
            };

    And of course, you should check the token expiration period, which can be found in the 'expiresInS' parameter in the API response.

    1
    Comment actions Permalink
  • Avatar
    David Momberger

    Thanks for the reply Andrey!

    I suspect you're right about the session timeout, however I'm having trouble getting the token based auth to work. I can generate the token fine but everything I've tried still gives me a 401 (Unauthorized) when trying to load the src.

    Everything I've tried includes:

    - switching to HLS endpoint, as videojs.Vhs.xhr didn't seem to run when the source was webm or mp4. Guess HLS is required in this case?

    - "setCookie": true when authenticating - am I right in thinking the x-runtime-guid header only works if this is the case?

    - several variations of header syntax for the token:

    options.headers['x-runtime-guid'] = token;
    options.headers[this.xRuntimeGuid] = token; // (this.xRuntimeGuid was undefined)
    options.headers['Authorization'] = 'Bearer ' + token;
    options.headers['Authorization'] = token;
    options.headers['Cookie'] = 'x-runtime-guid=' + token;
    options.headers['Cookie'] = token;

    again, 401 in each case. Below is my current code, any pointers would be greatly appreciated:

    <!DOCTYPE html>
    <html lang="en">

    <div id="player-wrapper" class="wrapper player h-0">
        <video id="my-player" muted autoplay controls></video>
    </div>

    <link href="https://vjs.zencdn.net/8.5.2/video-js.css" rel="stylesheet" />
    <script src="https://vjs.zencdn.net/8.5.2/video.min.js"></script>

    <script>

        window.VIDEOJS_NO_DYNAMIC_STYLE = true;

        var username = '';
        var password = '';
        var cameraId = '';
      var serverAddress = '';

      var cameraURL = serverAddress + '/hls/' + cameraId + '.m3u8';

        var settings = {
            "url": serverAddress + "/rest/v2/login/sessions",
            "method": "POST",
            "timeout": 0,
            "headers": {
                "Content-Type": "application/json"
            },
            "data": JSON.stringify({
                "username": username,
                "password": password,
                "setCookie": true
            }),
        };

        var initPlayer = () => {
            $.ajax(settings).done(
              function (response) {
                    var token = response.token;
                    var expiry = response.expiresInS;

                    var globalXhrRequestHook = (options) => {
                      debugger; // <-- wasn't hitting this breakpoint using /media/ endpoint, only hls
                        options.beforeSend = (xhr) => {
                            debugger;
                            options.headers = options.headers || {};
                            options.headers['x-runtime-guid'] = token;
                        };
                        return options;
                  };
                    videojs.Vhs.xhr.onRequest(globalXhrRequestHook);

                    var player = videojs('my-player', {});

                    player.addClass('d-flex');
                    player.addClass('hw-100');

                    player.src(cameraURL);
                    player.load();
                    player.play();
                }
            );
        };

        initPlayer();

    </script>

    </html>
    0
    Comment actions Permalink

Please sign in to leave a comment.