wms-plugin-auth-mysql

A simple Wowza Media Server 2-3 module for authenticating clients using MySQL.

This module allows you to hook into your existing MySQL database to provide an additional layer of security when playing and publishing streams. Simply drop in the JAR, modify your Wowza configuration files, and up the security of your media server!

The way Wowza Media Server ships by default allows any user on the internet to connect to your server and publish and play streams at will. As you're reading this, your server could be being used by tens, hundreds, or thousands of users to publish their own streams or watch existing streams without your knowledge. A smart developer could build a site for one on one video chats simply using your server and bandwidth, paying nothing for the gigabytes and terabytes of transfer while you foot the bill.

This module allows you to change that. By restricting either all access, publishing access, or playback access, you can prevent your media server and bandwidth from being hijacked.

NEW!New in version 1.2.1: HTTP streaming is now supported for authentication. All streams can now be required to pass a username and password as query parameters in the URL.

NEW!New in version 1.1.0: you can now use RTMP query string variables to provide the username and password, so you don't have to write any custom player code to get up to speed. See the client section for more details.

So what exactly does wms-plugin-auth-mysql provide?

  1. A Drop-In Solution.

    wms-plugin-auth-mysql is designed off the bat to work with the database you have. Whether you're using email addresses as user logins or usernames, whether you're hashing all your passwords (as you should be), whether your table is simple or complex, you can use this module.

    At the very simplest, wms-plugin-auth-mysql needs a database table with two fields, one indicating a username and one indicating a password. All of the following MySQL table definitions will work with this module:

    create table auth(id int primary key auto_increment,
        username varchar, password varchar);
    create table logins(username varchar, password varchar);
    create table users(id int primary key auto_increment,
        email_address varchar, password varchar, is_happy boolean,
        is_a_badger boolean, profile_image text);

    Since the module is easily and readibly configurable, you can tweak it to work with just about any table definition you can think of. The only requirements are that you have one field that designates a user's login/username/email and one field that defines their password.

    The configurable design of the module allows you to use it with just about any table configuration you can think of. You don't need a special table, though you can use one if you want to. Simply drop in the module, point it to your database, table, and fields, and get going immediately.

  2. Cross-Platform Support.

    Whether you're running Linux, Mac OSX, or Windows, wms-plugin-auth-mysql will work with your setup. All you need is Wowza Media Server (which is cross-platform) and MySQL 5 or later (which is also cross-platform), and things will "just work.™" Setting up the module is basically the same on all three platforms.

  3. A Compiled, Tested, Customizable Library.

    Sure, there may be scripts floating around the intertubes which might get you what you're looking for, but we've all used solutions that "should work" in the past. For something like media server security, you need something that not only is ready to go, but something that has been tested. Don't mess around with finding libraries to compile and hoping things work, use something that's experience hardened and is configurable. Installation is a snap, and it really couldn't be easier to configure.

Installation really couldn't be easier. There's only one JAR to install, and a bit of configuration to add.

Copy the JAR to Wowza's Library Folder

Simply move the wms-plugin-auth-mysql module to Wowza's library directory. This varies, depending on your operating system, see the tab with the name of your operating system to see the directory:

Wowza Library Location:

/usr/local/WowzaMediaServer/lib

Copy Command:

cp path/to/wms-plugin-auth-mysql.jar /usr/local/WowzaMediaServer/lib

Wowza Library Location:

/Library/WowzaMediaServer/lib

Copy Command

cp path/to/wms-plugin-auth-mysql.jar /Library/WowzaMediaServer/lib

Wowza Library Location:

C:\Program Files\Wowza Media Systems\Wowza Media Server {VERSION}\lib

Copy Command:

cp path\to\wms-plugin-auth-mysql.jar "C:\Program Files\Wowza Media Systems\Wowza Media Server {VERSION}\lib"
Be sure to replace {VERSION} above with the version of Wowza you're running, like "3.0.2".

Edit your Wowza Application's Configuration File

After you've moved the JAR to Wowza's library folder, (you should probably double check to make sure that it's there) you need to modify your application's configuration file to include the module. For our example here, we'll presume that you'll be installing the module to an application named "live".

The configuration file for the live application should be at:

/usr/local/WowzaMediaServer/conf/live/Application.xml

The configuration file for the live application should be at:

/Library/WowzaMediaServer/conf/live/Application.xml

The configuration file for the live application should be at:

C:\Program Files\Wowza Media Systems\Wowza Media Server {VERSION}\conf\live\Application.xml

Open up this file in your favorite text editor.

Locate the end of the <Module> element, toward the bottom of the document. The XQuery path to this element is: Root/Application/Modules.

Insert the following <Module> element to the end of the list of modules:

<Module>
    <Name>wms-plugin-auth-mysql</Name>
    <Description>MySQL Authentication Module for Wowza</Description>
    <Class>com.tkassembled.wowza.plugins.authmysql.ModuleAuthMySQL</Class>
</Module>

Your Application.xml file should now look somewhat like this:

<?xml version="1.0"?>
<Root>
    <Application>
        <Connections>
            <AutoAccept>true</AutoAccept>
            <AllowDomains></AllowDomains>
        </Connections>
        <Streams>
            <StreamType>live</StreamType>
            <StorageDir>${com.wowza.wms.context.VHostConfigHome}/content</StorageDir>
            <KeyDir>${com.wowza.wms.context.VHostConfigHome}/keys</KeyDir>
            <LiveStreamPacketizers></LiveStreamPacketizers>
            <DVRPacketizers></DVRPacketizers>
            <Properties></Properties>
        </Streams>
        <HTTPStreamers>cupertinostreaming,smoothstreaming,sanjosestreaming</HTTPStreamers>
        <DVRStores></DVRStores>            
        <SharedObjects>
            <StorageDir></StorageDir>
        </SharedObjects>
        <Client>
            <IdleFrequency>-1</IdleFrequency>
            <Access>
                <StreamReadAccess>*</StreamReadAccess>
                <StreamWriteAccess>*</StreamWriteAccess>
                <StreamAudioSampleAccess></StreamAudioSampleAccess>
                <StreamVideoSampleAccess></StreamVideoSampleAccess>
                <SharedObjectReadAccess>*</SharedObjectReadAccess>
                <SharedObjectWriteAccess>*</SharedObjectWriteAccess>
            </Access>
        </Client>
        <RTP>
            <Authentication>
                <PublishMethod>digest</PublishMethod>
                <PlayMethod>digest</PlayMethod>
            </Authentication>
            <AVSyncMethod>senderreport</AVSyncMethod>
            <MaxRTCPWaitTime>12000</MaxRTCPWaitTime>
            <IdleFrequency>75</IdleFrequency>
            <RTSPSessionTimeout>90000</RTSPSessionTimeout>
            <RTSPMaximumPendingWriteBytes>0</RTSPMaximumPendingWriteBytes>
            <RTSPBindIpAddress></RTSPBindIpAddress>
            <RTSPConnectionIpAddress>0.0.0.0</RTSPConnectionIpAddress>
            <RTSPOriginIpAddress>127.0.0.1</RTSPOriginIpAddress>
            <IncomingDatagramPortRanges>*</IncomingDatagramPortRanges>
            <Properties></Properties>
        </RTP>
        <MediaCaster>
            <Properties></Properties>
        </MediaCaster>
        <MediaReader>
            <Properties></Properties>
        </MediaReader>
        <MediaWriter>
            <Properties></Properties>
        </MediaWriter>
        <LiveStreamPacketizer>
            <Properties></Properties>
        </LiveStreamPacketizer>
        <HTTPStreamer>
            <Properties></Properties>
        </HTTPStreamer>
        <DVRPacketizer>
            <Properties></Properties>
        </DVRPacketizer>
        <DVRStore>
            <Properties></Properties>
        </DVRStore>
        <Repeater>
            <OriginURL></OriginURL>
            <QueryString><![CDATA[]]></QueryString>
        </Repeater> 
        <Modules>
            <Module>
                <Name>base</Name>
                <Description>Base</Description>
                <Class>com.wowza.wms.module.ModuleCore</Class>
            </Module>
            <Module>
                <Name>flvplayback</Name>
                <Description>FLVPlayback</Description>
                <Class>com.wowza.wms.module.ModuleFLVPlayback</Class>
            </Module>
            <!-- 
                Here's our authentication module. 
                Please note that the <Name> and <Description don't matter at all,
                it's the <Class> that counts. The <Class> must match the following
                _exactly_. 
            -->
            <Module>
                <Name>wms-plugin-auth-mysql</Name>
                <Description>MySQL Authentication Module</Description>
                <Class>com.tkassembled.wowza.plugins.authmysql.ModuleAuthMySQL</Class>
            </Module>
        </Modules>
        <Properties>
        </Properties>
    </Application>
</Root>

Done! The plugin has been installed to your Wowza Application! Now, it's time to configure it.

wms-plugin-auth-mysql offers a lot of configuration options to tailor it to your needs:

Name Default Description
auth.mysql.username root The MySQL username to use when attempting to connect to the MySQL server.
auth.mysql.password "" (Empty String) The MySQL password to use when attepmting to connect to the MySQL server.
auth.mysql.database [Required] The name of the MySQL database which contains your authentication table.
auth.mysql.table [Required] The name of the MySQL table within your database which is used as your authentication table.
auth.mysql.host localhost The domain name or IP address of the server running MySQL. If MySQL is running locally, leave this as "localhost".
auth.mysql.port (Integer) 3306 The port which MySQL is running on. Usually, this is 3306.
auth.mysql.field.username username The name of the "username" column in your table. If you use email addresses to log in and your email addres column is called "email_address", set this property to "email_address". If you use a column called "login" as your username, set this to "login", etc.
auth.mysql.field.password password The name of the "password" column in your table.
auth.mysql.security.type connect

The name of the security type/level to enforce for clients. This can be either connect, publish, play, or none. Explanations below:

connect The strictest security method. Clients which do not authenticate on connection or which fail authentication are rejected. This means that no one except authenticated users can connect to your application. Nobody connects, publishes, or plays any streams without a valid username and password.
publish This is probably the security method you're looking for. This will allow anonymous users to play streams, but will require a login when publishing streams. Clients who aren't authenticated which try to publish will be dropped.
play This method allows anonymous users to publish streams, but not to play them. In order to play streams, a client must be authenticated. If not, they'll be dropped.
none No security whatsoever. Think of this setting as the off switch. Sometimes it's nice to turn security off to test things; this is why this setting is here.
auth.mysql.hash.method none

The hash method to apply to the user's password before checking it against the database. If you hash your passwords as you should, you can use this option to make sure that comparisons work. Accepted values are md5, sha1, sha256, sha512, and none. Explanations below:

md5 Applies the MD5 hash algorithm to your passwords before checking them against the database.
sha1 Applies the SHA-1 hash algorithm to your passwords before checking them against the databas.
sha256 Applies the SHA-256 hash algorithm to your passwords before checking them against the database.
sha512 Applies the SHA-512 hash algorithm to your passwords before checking them against the database.
none Applies no hash algorithm to your passwords before checking them against the database.
auth.mysql.http.enabled true Should we attempt to authenticate all HTTP playback streams as well? This option is enabled by default. In order to playback HTTP streams, users will need to pass a username and password variable in the URL:
http://servername.com:1935/vod/mp4:myStream/playlist.m3u8?username=username&password=password

These properties are added to the bottom of your Wowza Application's configuration file at the XQuery path Root/Application/Properties. They follow the following format:

<Property>
    <Name>property name</Name>
    <Value>property value</Value>
    <Type>can be Integer or String</Type>
</Property>

To make things a bit easier, here's a configuration file you can take and modify to your needs:

<?xml version="1.0"?>
<Root>
    <Application>
        <Connections>
            <AutoAccept>true</AutoAccept>
            <AllowDomains></AllowDomains>
        </Connections>
        <Streams>
            <StreamType>default</StreamType>
            <StorageDir>${com.wowza.wms.context.VHostConfigHome}/content</StorageDir>
            <KeyDir>${com.wowza.wms.context.VHostConfigHome}/keys</KeyDir>
            <LiveStreamPacketizers></LiveStreamPacketizers>
            <DVRPacketizers></DVRPacketizers>
            <Properties></Properties>
        </Streams>
        <HTTPStreamers>cupertinostreaming,smoothstreaming,sanjosestreaming</HTTPStreamers>
        <DVRStores></DVRStores>            
        <SharedObjects>
            <StorageDir></StorageDir>
        </SharedObjects>
        <Client>
            <IdleFrequency>-1</IdleFrequency>
            <Access>
                <StreamReadAccess>*</StreamReadAccess>
                <StreamWriteAccess>*</StreamWriteAccess>
                <StreamAudioSampleAccess></StreamAudioSampleAccess>
                <StreamVideoSampleAccess></StreamVideoSampleAccess>
                <SharedObjectReadAccess>*</SharedObjectReadAccess>
                <SharedObjectWriteAccess>*</SharedObjectWriteAccess>
            </Access>
        </Client>
        <RTP>
            <Authentication>
                <PublishMethod>digest</PublishMethod>
                <PlayMethod>digest</PlayMethod>
            </Authentication>
            <AVSyncMethod>senderreport</AVSyncMethod>
            <MaxRTCPWaitTime>12000</MaxRTCPWaitTime>
            <IdleFrequency>75</IdleFrequency>
            <RTSPSessionTimeout>90000</RTSPSessionTimeout>
            <RTSPMaximumPendingWriteBytes>0</RTSPMaximumPendingWriteBytes>
            <RTSPBindIpAddress></RTSPBindIpAddress>
            <RTSPConnectionIpAddress>0.0.0.0</RTSPConnectionIpAddress>
            <RTSPOriginIpAddress>127.0.0.1</RTSPOriginIpAddress>
            <IncomingDatagramPortRanges>*</IncomingDatagramPortRanges>
            <Properties></Properties>
        </RTP>
        <MediaCaster>
            <Properties></Properties>
        </MediaCaster>
        <MediaReader>
            <Properties></Properties>
        </MediaReader>
        <MediaWriter>
            <Properties></Properties>
        </MediaWriter>
        <LiveStreamPacketizer>
            <Properties></Properties>
        </LiveStreamPacketizer>
        <HTTPStreamer>
            <Properties></Properties>
        </HTTPStreamer>
        <DVRPacketizer>
            <Properties></Properties>
        </DVRPacketizer>
        <DVRStore>
            <Properties></Properties>
        </DVRStore>
        <Repeater>
            <OriginURL></OriginURL>
            <QueryString><![CDATA[]]></QueryString>
        </Repeater> 
        <Modules>
            <Module>
                <Name>base</Name>
                <Description>Base</Description>
                <Class>com.wowza.wms.module.ModuleCore</Class>
            </Module>
            <Module>
                <Name>flvplayback</Name>
                <Description>FLVPlayback</Description>
                <Class>com.wowza.wms.module.ModuleFLVPlayback</Class>
            </Module>
            <!-- 
                Here's our authentication module. 
                Please note that the <Name> and <Description don't matter at all,
                it's the <Class> that counts. The <Class> must match the following
                _exactly_. 
            -->
            <Module>
                <Name>authmysql</Name>
                <Description>MySQL Authentication Module</Description>
                <Class>com.tkassembled.wowza.plugins.authmysql.ModuleAuthMySQL</Class>
            </Module>
        </Modules>
        <Properties>
            <Property>
                <!--
                    The MySQL username to use when attempting to connect to the 
                    database. Change <Value> to your MySQL username.
                -->
                <Name>auth.mysql.username</Name>
                <Value>mysqlusername</Value>
            </Property>
            <Property>
                <!--
                    The MySQL password to use when attempting to connect to the
                    database. Change <Value> to your MySQL password.
                -->
                <Name>auth.mysql.password</Name>
                <Value>mysqlpassword</Value>
            </Property>
            <Property>
                <!--
                    The MySQL _database_ to use when issuing queries. Note that 
                    this is _not_ the same as 'auth.mysql.table' below. This 
                    property refers to the database to use, where 'auth.mysql.table'
                    refers to the table to use. Change <Value> to your MySQL database
                    name.
                -->
                <Name>auth.mysql.database</Name>
                <Value>wowzatestdatabase</Value>
            </Property>
            <Property>
                <!--
                    The MySQL _table_ to use when issuing queries. Change <Value>
                    to the name of your MySQL authentication table. 
                -->    
                <Name>auth.mysql.table</Name>
                <Value>wowzatesttable</Value>
            </Property>
            <Property>
                <!-- 
                    The host of the MySQL server. If you're running MySQL locally,
                    leave this as 'localhost' or '127.0.0.1'. If you're running
                    MySQL remotely, then you'll need to change this to the IP or
                    DNS name of the server hosting MySQL. Change <Value> to the
                    IP or domain name of the server running MySQL.
                -->
                <Name>auth.mysql.host</Name>
                <Value>localhost</Value>
            </Property>
            <Property>
                <!-- 
                    The port that MySQL is running on. Usually, this is 3306.
                    Change <Value> to the port that your MySQL server is running
                    on. 
                -->
                <Name>auth.mysql.port</Name>
                <Value>3306</Value>
                <Type>Integer</Type>
            </Property>
            <Property>
                <!-- 
                    The field/column in the database table to use when looking up 
                    usernames. For example, for a table that looks like this:
                        
                        create table users (id int auto increment primary key,
                            uname varchar,
                            password varchar);

                    ...you'd set this value to 'uname', which is the name of
                    the field/column in the database which designates a unique
                    username. Change <Value> to the name of the column/field
                    in your database table which indicates a user's login.
                -->
                <Name>auth.mysql.field.username</Name>
                <Value>username</Value>
            </Property>
            <Property>
                <!-- 
                    The field/column in the database table to use when looking up
                    user passwords. For example, for a table that looks like this:

                        create table users (id int auto increment primary key,
                            username varchar,
                            pass varchar);

                    ...you'd set this value to 'pass', which is the name of the
                    field/column in the database which designates a user's password.
                    Change <Value> to the name of the column/field in your database
                    table which indicates a user's password.
                -->
                <Name>auth.mysql.field.password</Name>
                <Value>password</Value>
            </Property>
            <Property>
                <!-- 
                    Stream security method. 
                    One of the following: connect, play, publish, none
                    
                    connect: This option indicates that authentication will be
                        always be required immediately on server connection. This basically
                        means that NOBODY will be able to connect to your application
                        without a valid username and password. No user will be able to
                        play or publish streams without a login. Clients will be 
                        disconnected immediately if they fail to login.
                        Highest level of security.

                    play: This option indicates that authentication will be 
                        required for playing streams. Publishing will not require
                        a login, but playback will. Clients that attempt to play
                        a stream without being authenticated will be disconnected.

                    publish: This option indicates that authentication will be
                        required for publishing streams. Playback will not require
                        a login, but publishing will. Clients that attempt to publish
                        a stream without being authenticated will be disconnected.
                        This is probably the option that you want. 

                    none: This option turns off authentication altogether. 

                    Change <Value> to be either connect, play, publish, or none. 
                -->
                <Name>auth.mysql.security.type</Name>
                <Value>publish</Value>
            </Property>
            <Property>
                <!--
                    The password hashing method to apply to the password before 
                    issuing a SQL select. 
                    Can be any one of the following values: md5, sha1, sha256,
                    sha512, none

                        md5: Will apply MD5 hash to the password before the select.

                        sha1: Will apply SHA-1 hash to the password before the select.

                        sha256: Will apply SHA-256 hash to the password before the select.

                        sha512: Will apply SHA-512 hash to the password before the select.

                        none: Won't apply any transformations to the password before the select.

                    Change <Value> to be either md5, sha1, sha256, sha512, or none.
                -->
                <Name>auth.mysql.hash.method</Name>
                <Value>md5</Value>
            </Property>
        </Properties>
    </Application>
</Root>

From Scratch

If you're writing your own player, you'll want to pass the username and password when connecting to Wowza like so in your ActionScript:

var connection:NetConnection = new NetConnection();
// add listeners, etc...
connection.connect("rtmp://example.com/live", "username", "password");

Alternatively, if you want to put them in the RTMP url, do this:

var connection:NetConnection = new NetConnection();
// add listeners, etc...
connection.connect("rtmp://example.com/live/?username=username&password=password");

Using FlowPlayer

In your JavaScript, when instantiating FlowPlayer, simply configure your player passing the username and password through JavaScript to FlowPlayer:

flowplayer("flowplayer.swf", {
    clip: {
        url: "streamName",
        netConnectionUrl: "rtmp://example.com/live/",
        connectionArgs: ["username", "password"],
        provider: "rtmp"
    }
});

Alternatively, you can pass the username and password in the netConnectionUrl:

flowplayer("flowplayer.swf", {
    clip: {
        url: "streamName",
        netConnectionUrl: "rtmp://example.com/live/?username=username&password=password",
        provider: "rtmp"
    }
});

Using JW Player

In your JavaScript, when instantiating JW Player, pass the username and password as URL variables in your RTMP string:

jwplayer("mediaspace").setup({
    flashplayer: "jwplayer.swf",
    file: "streamName",
    streamer: "rtmp://example.com/live/?username=username&password=password",
    controlbar: "bottom",
    width: '470',
    height: '290'
});

Using Flash Media Live Encoder

In the "FMS URL" field in Flash Media Live Encoder (FMLE), pass the username and password as URL variables:

rtmp://example.com/live/?username=username&password=password

Logging integration with Wowza is seamless with wms-plugin-auth-mysql. The module usess Wowza's native Log4j support and by default only prints important information such as warnings and errors. When users try to connect to your server and fail to authenticate, the module will generate a warning log about the attempt. Also, if a misconfiguration occurs in the properties, the module will report the error in Wowza's logs. You should always be advised about who's trying to access your server, and with this module, you always will be.

In addition, by setting Wowza's logging threshold to DEBUG, you'll be able to see even more relevant information about the library.

wms-plugin-auth-mysql licenses come in three flavors: Personal, Business, and Enterprise.

Name Server Count Ideal For Price
Personal 1-3 Servers Startup business and smaller organizations not needing a lot of media servers. $100.00
Business 3-10 Servers Larger businesses or small streaming providers. $500.00
Enterprise Unlimited Servers Enterprises, CDNs, or developers who need an unlimited amount of servers. $1000.00