Secure my streams from unauthorized watching

Discussion in 'Web Call Server 5' started by tbr666, May 5, 2017.

  1. tbr666

    tbr666 New Member

    I have a problem regarding my playback security. Just by knowing the rtsp url of a stream, the stream can be played from any Flashphoner sample player. I would like to add access control which checks if stream is actually watched by a user currently logged in on my website. I need to add a module which catches a token with GET method, connects to my database with remote MySQL and checks if the token is valid. Is it possible to add a security .jar module to my server which can override connection event and reject the playback if it's not authorized? Then the playback url would be for example rtsp://[host]:1935/[app-name]/[stream-name]?token=xyz
  2. Max

    Max Administrator Staff Member

    WCS server delegates authentication to your server-side web application.
    For example,
    Code:
    session.createStream({name: 'rtsp://host:554/live.sdp', custom: {token: 'xyz'}}).play();
    Here you pass custom object and token 'xyz'.
    WCS server will send REST/HTTP request to your web application.
    You can reply with 403 Forbidden to reject the playback attempt.
    Example:
    Code:
    HTTP/1.1 403 Forbidden
    Date: Tue, 28 Feb 2017 09:05:56 GMT
    Server: Apache/2.2.15 (CentOS)
    X-Powered-By: PHP/5.3.3
    Content-Length: 0
    Connection: close
    Content-Type: text/html; charset=UTF-8
    You can get more information in the REST Methods documentation:
    https://flashphoner.com/docs/wcs5/wcs_docs/html/en/wcs-rest-methods/
  3. Max

    Max Administrator Staff Member

    Using REST Methods you can even hide RTSP URL.
    Example:
    Code:
    session.createStream({name: 'rtsp-stream-xyz', custom: {token: 'xyz'}}).play();
    And then replace on server-side
    Code:
    rtsp-stream-xyz
    with
    Code:
    rtsp://host:554/live.sdp
    Therefore user will not know RTSP URL.
  4. tbr666

    tbr666 New Member

    session.createStream({name: 'rtsp://host:554/live.sdp', custom: {token: 'xyz'}}).play();
    I am using the sample Flashphoner client provided with the server. For playback I use vow-player-min.js javascript and Flashphoner.js provided with the server client. Where in the code of the sample javascript should I add the custom field? I tried to add it in this part of the code, but the connection failed:
    function connect(url) {
    var urlServer = $("#urlServer").val();
    //connect to server
    f.connect({
    urlServer: urlServer,
    appKey: "defaultApp",
    useWsTunnel: true,
    useBase64BinaryEncoding: false,
    width: config.videoWidth,
    height: config.videoHeight,
    custom: {
    "token":"xyz"
    }

    });
    }
  5. Max

    Max Administrator Staff Member

    This script is out of date.
    You have to use latest Player and latest server to get this working:
    Demo
    https://wcs5-eu.flashphoner.com/demo2/player
    https://wcs5-eu.flashphoner.com/client2/examples/demo/streaming/player/player.html
    Scripts
    https://github.com/flashphoner/flashphoner_client/tree/wcs_api-2.0/examples/demo/streaming/player
    As you can see in js file:
    https://github.com/flashphoner/flas...-2.0/examples/demo/streaming/player/player.js
    We init api with WSReceiver2.js and video-worker2.js to get this working in iOS Safari.
    Code:
     Flashphoner.init({
                flashMediaProviderSwfLocation: '../../../../media-provider.swf',
                receiverLocation: '../../dependencies/websocket-player/WSReceiver2.js',
                decoderLocation: '../../dependencies/websocket-player/video-worker2.js',
                preferredMediaProvider: mediaProvider
            });
    This player is based on Flashphoner Web SDK. So using this script you can pass parameter custom.
  6. tbr666

    tbr666 New Member

    I am currently using this version of server: v. 0.5.18.1977 - 5.0.2200
    Do I need to update the server or only the client? How do I update the server without reinstalling it?
  7. Max

    Max Administrator Staff Member

    To update you can do
    Code:
    service webcallserver update
    Or manually:
    1. Download latest tar.gz
    2. Unzip an run ./install.sh
    Note. Do not download to /usr/local/FlashphonerWebCallServer or /usr/local, it may cause a conflict.
  8. tbr666

    tbr666 New Member

    I have updated my server to the latest version FlashphonerWebCallServer-5.0.2211. I need the Flashphoner player to work both on Edge in Windows 10 and Safari in iOS.
    I have downloaded a sample client from address http://flashphoner.com/download-wcs5-client.tar.gz. It also contains the script vow-player-min.js but it appears to be later client version. In the function initOnLoad init function is also executed on Flashphoner instance like in the example you stated.
    var f = Flashphoner.getInstance();

    // Init player
    function initOnLoad() {
    //add listeners
    f.addListener(WCSEvent.ErrorStatusEvent, errorEvent);
    f.addListener(WCSEvent.ConnectionStatusEvent, connectionStatusListener);
    f.addListener(WCSEvent.StreamStatusEvent, streamStatusListener);
    var configuration = new Configuration();
    configuration.wsPlayerCanvas = document.getElementById('videoCanvas');
    configuration.wsPlayerReceiverPath = "../../../dependencies/websocket-player/WSReceiver.js";
    configuration.custom={"token":"xyz"};
    f.init(configuration);
    initVisibility();
    }

    I have added custom parameter to configuration variable and the playback works without error. Is this the good way to pass it to the server or I should download the client from another location?
  9. Max

    Max Administrator Staff Member

  10. tbr666

    tbr666 New Member

    I have updated the client to the latest version and added the token param to stream options in playStream function inside examples/demo/streaming/player/player.js script.

    function playStream(session) {
    var streamName = $('#streamName').val();
    var options = {
    name: streamName,
    display: remoteVideo,
    custom: {token: 'xyz'}
    };
    ...
    stream = session.createStream(options).on(STREAM_STATUS.PLAYING, function(stream) {
    ...
    stream.play();
    }
    Is this the correct way to init the stream play with token? Should I put token in quotes (custom: {'token':'xyz'} ) or set it without quotes (custom: {token: 'xyz'}) to pass in correctly?
  11. Max

    Max Administrator Staff Member

    Yes, this is correct.
    As an example you can see implementation of room module:
    https://github.com/flashphoner/flashphoner_client/blob/wcs_api-2.0/src/room-module.js#L38
    Code:
     var session = Flashphoner.createSession({
            urlServer: options.urlServer,
            appKey: ROOM_REST_APP,
            custom: {
                login: options.username
            }
        });
    It should be correct JavaScript object.
    Example:
    Code:
    var myToken = 'xyz';
    custom : {token: myToken}
    or
    Code:
    custom : {token: 'xyz'}
  12. tbr666

    tbr666 New Member

    It seems that everything is ok now, but after reading the REST documentation you sent me, I can't seem to find out how exactly should I override my web server response to remote connect to my database, check token validity and refuse the connection if it's not valid. I have my Flashphoner server running on Centos 7 server which is different from my website server and I have Apache installed with command.
    yum install httpd
    I have a root access to that server.
    Which files should I modify to change the behaviour to suit my logic?
  13. Max

    Max Administrator Staff Member

    By default WCS sends REST request to http://localhost:9091/EchoApp
    You have to replace this URL to your own URL, i.e. http://mywebsite/EchoApp
    You can read this from here
    https://flashphoner.com/docs/wcs5/w...thods/index.html?controlling_rest_methods.htm
    Please also check how authentication works:
    https://flashphoner.com/docs/wcs5/w.../index.html?method_connect_authentication.htm

    Step by step:
    1. Create a new REST app.
    add app newApp newApp http://mywebsite/NewApp
    2. Add all REST methods for your app.
    add app-rest-method -a newApp
    3. Implement all scripts on your web server:
    Code:
    http://mywebsite/NewApp/connect
    http://mywebsite/NewApp/play
    http://mywebsite/NewApp/publish
    etc
    http://mywebsite/NewApp/*
    4. Configure playStream method with restOnError=true as described below.
    https://flashphoner.com/docs/wcs5/w...od_connect_nonfiguring_other_rest_methods.htm
    5. Implement your http://mywebsite/NewApp/play logic.
    6. Pass key newApp during session creation
    Code:
    Flashphoner.createSession({appKey:'newApp'});
    If you pass this key, WCS will send REST requests to associated URLs http://mywebsite/NewApp/*

    Please let me know if you have any troubles on any of listed steps.
  14. tbr666

    tbr666 New Member

    Hello. I have added a new app to named "standard" and assigned url www.[mydomainname].com/standard to it. I also added all rest method through the command line. As I assume, at this point I need to add all scripts I need to the directory var/www/html/standard inside my Apache root folder. I would like the scripts to be completely the same as for default app, the only difference is the play method which I will need to alter. Where do I find the source code of the default scripts to copy it in the directory of standard app and to apply my play logic in it? I can't seem to find EchoApp directory anywhere on my Centos server where I installed Flashphoner.
  15. Max

    Max Administrator Staff Member

    All your REST methods should work in Echo mode (This is how EchoApp works). This means each method should return exactly the same data as received.
    You can download PHP samples from here.
    www.[mydomainname].com/standard/connect
    www.[mydomainname].com/standard/playStream
    etc
    So your scripts should return HTTP 200 OK and application/json content with the same body as received.
    Request
    Code:
    POST /EchoApp/publishStream HTTP/1.1
    Accept: application/json, application/*+json
    Content-Type: application/json;charset=UTF-8
    User-Agent: Java/1.8.0_45
    Host: localhost:9091
    Connection: keep-alive
    Content-Length: 3622
    { 
       "nodeId":"H4gfHeULtX6ddGGUWwZxhUNyqZHUFH8j@192.168.1.59",
       "appKey":"defaultApp",
       "sessionId":"/192.168.1.38:52791/192.168.1.59:8443",
       "mediaSessionId":"87c5ff20-fb59-11e6-812c-1b28ccb49323",
       "name":"84cac22c",
       "published":true,
       "hasVideo":true,
       "hasAudio":true,
       "status":"PENDING",
       "record":false,
       "width":0,
       "height":0,
       "bitrate":0,
       "quality":0,
       "mediaProvider":"WebRTC"
    }
    Response
    Code:
    HTTP/1.1 200 OK
    Server: Apache-Coyote/1.1
    Content-Type: application/json;charset=UTF-8
    Transfer-Encoding: chunked
    Date: Sat, 25 Feb 2017 05:51:11 GMT
    { 
       "nodeId":"H4gfHeULtX6ddGGUWwZxhUNyqZHUFH8j@192.168.1.59",
       "appKey":"defaultApp",
       "sessionId":"/192.168.1.38:52791/192.168.1.59:8443",
       "mediaSessionId":"87c5ff20-fb59-11e6-812c-1b28ccb49323",
       "name":"84cac22c",
       "published":true,
       "hasVideo":true,
       "hasAudio":true,
       "status":"PENDING",
       "record":false,
       "width":0,
       "height":0,
       "bitrate":0,
       "quality":0,
       "mediaProvider":"WebRTC"
    }
    You can test your REST Methods using REST Console in Google Chrome.
    Make sure your methods /connect, /playStream works properly and return Echo JSON data.
  16. tbr666

    tbr666 New Member

    I have successfully created my application, added the rest methods to it and altered the example php file. I also tested it with Advanced rest client and it works well both with connect and playStream method. The connection is refused when there is no token or the token is invalid and the echo occurs when the token is valid. Additionally, when I test with connect method it adds restClientConfig.json the echoed data. When I test the same application with the player it displays the status DISCONNECTED even with valid token. This is the part of my altered php script:

    PHP:
    $api_method array_pop(explode("/"$_SERVER['REQUEST_URI']));
    $incoming_data json_decode(file_get_contents('php://input'),en I  true);

    //process method
    switch($api_method) {
        case
    "connect":   
           
        
    $rest_client_config json_decode(file_get_contents('rest_client_config.json'), true);   
        
    $incoming_data['restClientConfig'] = $rest_client_config;
       
            if(isset(
    $incoming_data['custom']) && isset($incoming_data['custom']['token'])) {
            
    $token $incoming_data['custom']['token'];   
            }
            else {
                
    ubnormalResponse(403);
        }
            
    $found checkTokenValidity($token);
        if (
    $found){
            
    error_log("Record found by " $token);
        }else{
            
    error_log("Record not found by token: " $token " Connection failed with 403 status.");
            
    ubnormalResponse(403);
        }
        break;
        case
    "ConnectionStatusEvent":
        break;
        case
    "RegistrationStatusEvent":
        break;
        case
    "sendXcapRequest":
        break;
        case
    "XcapStatusEvent":
        break;
        case
    "sendDtmf":
        break;
        case
    "call":
        break;
        case
    "OnCallEvent":
        break;
        case
    "answer":
        break;
        case
    "hangup":
        
    //ubnormalResponse(403);
        
    break;
        case
    "hold":
        break;
        case
    "unhold":
        break;
        case
    "transfer":
        break;
        case
    "OnTransferEvent":
        
    //ubnormalResponse(403);
        
    break;
        case
    "TransferStatusEvent":
        if (
    $incoming_data['status'] == "PENDING") {
            
    //ubnormalResponse(403);
        
    }
        break;
        case
    "CallStatusEvent":
        break;
        case
    "sendMessage":
        
    //ubnormalResponse(403);
        
    break;
        case
    "OnMessageEvent":
        break;
        case
    "MessageStatusEvent":
        break;
        case
    "publishStream":
        break;
        case
    "unPublishStream":
        break;
        case
    "playStream":
        break;
        case
    "stopStream":
        break;
        case
    "StreamStatusEvent":
        break;
        case
    "subscribe":
        break;
        case
    "SubscriptionStatusEvent":
        break;
        case
    "OnDataEvent":
        break;
        case
    "DataStatusEvent":
        break;
        case
    "submitBugReport":
        break;
        case
    "BugReportStatusEvent":
        break;
        case
    "pushLogs":
        break;
        case
    "RecordingStatusEvent":
        break;
        case
    "ErrorStatusEvent":
        break;
        case
    "disconnect":
        break;
    }
    header('Content-Type: application/json');
    echo 
    json_encode($incoming_data);
    Those are the only changes I made to the client side code:

    Code:
     Flashphoner.createSession({appKey:"standardKey", urlServer: url}).on(SESSION_STATUS.ESTABLISHED, function(session){
            setStatus(session.status());
            //session connected, start playback
            playStream(session);
         ...
    function playStream(session) {
        var streamName = $('#streamName').val();
        var options = {
            name: streamName,
            display: remoteVideo,
            custom: {token: '1b0c2d82ac48c2d3350e19cc7c670633eae7fe66d1abf4e36c01837ad1b26def5e8ebe5511e43d50b8cf078903dc406c96d7d38bccca57786dcd889b15a49be0'}
        };
    Also, when I try to access my domain with browser the connection to the server works properly. Do I need to add some code to the playStream method in the php script to make it work? As I see, the sample echo app doesn't have it. Maybe I have specified something wrong on the client side?
    It actually would help me a lot if I could see which POST data is being sent to the server or received by the server when I start the player. Then I would be able to compare the data I'm sending with advanced rest client with the data which is being sent by my Google chrome browser for playback.
  17. Max

    Max Administrator Staff Member

    Hello
    You can see all REST messages in the log
    Code:
    /usr/local/FlashphonerWebCallServer/logs/flashphoner_manager.log
    You can also make a dump and see HTTP packets in Wireshark
    Code:
    tcpdump -i any -w log.pcap
    wireshark.jpg
    You can see Websocket frames in Chrome browser.
    Example:
    websocket-frames.jpg
  18. Max

    Max Administrator Staff Member

    First of you have to check log /usr/local/FlashphonerWebCallServer/logs/flashphoner_manager.log
    If your php script returns 403 Forbidden, it will be printed to this log.
  19. tbr666

    tbr666 New Member

    Rest client config json is added to the echoed data when connect method is executed (I configured the playStream method inside client config json with restOnError=true as you instructed me). Maybe it bothers the player somehow?
    When the playStream method is executed this switch branch is empty and the application only echoes incoming data. Is it ok that playStream method inside api.php only echoes the data sent to the php to enable playback?
    case"connect":
    ...
    $rest_client_config = json_decode(file_get_contents('rest_client_config.json'), true);
    $incoming_data['restClientConfig'] = $rest_client_config;
    ...
    break;
    case "playStream":
    break;
    ...
    header('Content-Type: application/json');
    echo json_encode($incoming_data);
  20. Max

    Max Administrator Staff Member

    Please share your
    /usr/local/FlashphonerWebCallServer/logs/flashphoner_manager.log
    or send to logs@flashphoner.com

Share This Page