User Authentication Using mySQL and JDBC

Hi,

I would like to restrict access to files on the server to registered users and need some kind of login module. I have the users details in a mysql database on a seperate server but I am not sure how to go about accessing the database from wowza. any help would be appreciated.

Thanks.

Roger.

I downloaded the JDBC driver from mysql from here:

http://dev.mysql.com/downloads/connector/j/5.0.html

Unzip and driver archive and drop the driver mysql-connector-java-5.0.5-bin.jar into the Wowza Pro lib folder [install-dir]/lib.

The serverside Java code would look something like this:

package com.mycompany.wms.dbtest;
import java.sql.*;
import com.wowza.wms.application.*;
import com.wowza.wms.amf.*;
import com.wowza.wms.client.*;
import com.wowza.wms.module.*;
import com.wowza.wms.request.*;
public class DBTest extends ModuleBase 
{
	static public void onConnect(IClient client, RequestFunction function,
			AMFDataList params) 
	{
		
		String userName = getParamString(params, PARAM1);
		String password = getParamString(params, PARAM2);
		// preload the driver class
		try 
		{
			Class.forName("com.mysql.jdbc.Driver").newInstance(); 
		} 
		catch (Exception e) 
		{ 
			getLogger().error("Error loading: com.mysql.jdbc.Driver: "+e.toString());
		} 
		
		Connection conn = null;
		try 
		{
			conn = DriverManager.getConnection("jdbc:mysql://localhost/test?user=monty&password=greatsqldb");
			Statement stmt = null;
			ResultSet rs = null;
			try 
			{
				stmt = conn.createStatement();
				rs = stmt.executeQuery("SELECT count(*) as userCount FROM users where username = '"+userName+"' and password = '"+password+"'");
				if (rs.next() == true)
				{
				    if (rs.getInt("userCount") > 0)
					{
						client.acceptConnection();
					}
				}
			} 
			catch (SQLException sqlEx) 
			{
				getLogger().error("sqlexecuteException: " + sqlEx.toString());
			} 
			finally 
			{
				// it is a good idea to release
				// resources in a finally{} block
				// in reverse-order of their creation
				// if they are no-longer needed
				if (rs != null) 
				{
					try 
					{
						rs.close();
					} 
					catch (SQLException sqlEx) 
					{
						rs = null;
					}
				}
				if (stmt != null) 
				{
					try 
					{
						stmt.close();
					} 
					catch (SQLException sqlEx) 
					{
						stmt = null;
					}
				}
			}
			conn.close();
		} 
		catch (SQLException ex) 
		{
			// handle any errors
			System.out.println("SQLException: " + ex.getMessage());
			System.out.println("SQLState: " + ex.getSQLState());
			System.out.println("VendorError: " + ex.getErrorCode());
		}
		getLogger().info("onConnect: " + client.getClientId());
	}
	static public void onConnectAccept(IClient client) 
	{
		getLogger().info("onConnectAccept: " + client.getClientId());
	}
	static public void onConnectReject(IClient client) 
	{
		getLogger().info("onConnectReject: " + client.getClientId());
	}
	static public void onDisconnect(IClient client) 
	{
		getLogger().info("onDisconnect: " + client.getClientId());
	}
}

Then edit your Application.xml and add a reference to this new module to the section and set Connections/AutoAccept to false.

Charlie

This example just passess the user credentials through the NetConnection.connect call. So in this example the connect call would look like:

var nc:NetConnection = new NetConnection();
nc.connect(url, userName, password);

Charlie

Are you passing the username and password as part of the connect command?

Client side code:

var nc:NetConnection = new NetConnection();
var userName:String = "charlie";
var password:String = "mypassword";
nc.connect("rtmp://localhost/myapplication", userName, password);

The java.lang.reflect.InvocationTargetException just means that there was an error somewhere in the onConnect method that was not caught by a try/catch block. The only part of this code that is not surrounded in a try/catch blocks is the place where it resolves the userName and password from the connect command.

One other thing you can try is to surround all the code in the method with the try/catch block that looks like this:

static public void onConnect(IClient client, RequestFunction function, AMFDataList params) 
{
	try
	{
	    //put all the code of the method here
	}
	catch (Exception e)
	{
	    System.out.println("ERROR: "+e.toString());
	    e.printStackTrace();
	}
}

Charlie

I am pretty sure that client.rejectConnection(String); is not being called. Can you try a simple onConnect handler just to verify:

static public void onConnect(IClient client, RequestFunction function, AMFDataList params)
{
	client.rejectConnection("Testing");
}

I think you will find that its working.

Charlie

I just tried it myself and it works great. I did the following.

Created this server side module:

package com.wowza.wms.plugin.test.module;
import com.wowza.wms.amf.*;
import com.wowza.wms.client.*;
import com.wowza.wms.module.*;
import com.wowza.wms.request.*;
import com.wowza.wms.stream.*;
import com.wowza.wms.application.*;
import com.wowza.wms.sharedobject.*;
public class ModuleInternalTest extends ModuleBase
{
	public static void onConnect(IClient client, RequestFunction function, AMFDataList params)
	{
	    getLogger().info("REJECT");
	    client.rejectConnection();
	}
}

Added this bit of XML to end of the list of my conf/Application.xml file:

<Module>
	<Name>test</Name>
	<Description>test</Description>
	<Class>com.wowza.wms.plugin.test.module.ModuleInternalTest</Class>
</Module>

Connected to the server and the connection was rejected. Are you sure your code is being called? Did you add the entry to the proper Application.xml file? Do you add your entry at the end of the list?

If you still can’t get it to work, send me your Java files and zip up and send me your conf folder.

Charlie

I think the problem is the log entry that is generating:

INFO server comment - onConnect: false

Try edit the Application.xml file for this application and make sure the only modules defined for this application are:

<Modules>
	<Module>
		<Name>base</Name>
		<Description>Base</Description>
		<Class>com.wowza.wms.module.ModuleCore</Class>
	</Module>
	<Module>
		<Name>properties</Name>
		<Description>Properties</Description>
		<Class>com.wowza.wms.module.ModuleProperties</Class>
	</Module>
	<Module>
		<Name>logging</Name>
		<Description>Client Logging</Description>
		<Class>com.wowza.wms.module.ModuleClientLogging</Class>
	</Module>
	<Module>
		<Name>test</Name>
		<Description>test</Description>
		<Class>com.wowza.wms.plugin.test.module.ModuleInternalTest</Class>
	</Module>
</Modules>

The way the module stuff works is that it will call the event handlers in the order in which the modules are defined in the Application.xml. So maybe there is another module that is calling acceptConnection after the rejectConnection.

I realize that I keep hammering you with the same answer that it works. I am pretty confident that it works. I apologize. I am not sure what else to do. I do believe it is something on your end. So do send me your [install-dir]/conf folder zipped up along with your Java code so I can take a look. Send it to charlie@wowza.com.

Charlie

I am not sure exactly which post you are referring to but if it is the JDBC one than it is this line:

conn = DriverManager.getConnection("jdbc:mysql://localhost/test?user=monty&password=greatsqldb");

The database name is test.

Charlie

I too would like to authenticate users from a MySQL database in addition to adding an entry to a table when a video is done recording. Thanks for posting your example code. Question. How are the user credentials passed to WMS? Can they be passed from a flash object? PHP? Are there some docs I can study to get an idea of the communication between Flash and WMS?

Hello, i have used these examples to port an existing FMS system and setup server-side authetication on Wowza however i get a java.lang.reflect.InvocationTargetException error and the connection is always accepted. There is no further information that i can get out of this to help me debug. Do you have any advice on this?

thanks

Hash

Ok thanks for the info. Instead of actually sending a username and password i wanted to modify the function to receive a single session_id token.

nc.connect(serverUrl,_root.token)

and in the module

...
static public void onConnect(IClient client, RequestFunction function, AMFDataList params) 
	{
	String token = getParamString(params, PARAM1);
	//String password = getParamString(params, PARAM2);
...

The idea being that the login is done independently and a live session table is looked up to make sure that only active and authorised sessions can access the streams.

Can you see where the error might be?

thanks

Hash

Hi i’ve worked through this issue but now i have a strange problem.

Regardless of whether the sql result leads to an acceptConnection or rejectConnection (which i added as an else condition), the flash client is still able to stream. How do i ensure that the client cannot stream if the connection is not authorised?

Log as follows:

INFO session connect-pending 125.54.xxx.xxx -
INFO server comment - Reject Connection (I added this)
INFO server comment - onConnect: 86830892
INFO server comment - onConnect: false
INFO session connect 125.54.xxx.xxx -
INFO server comment - onConnectAccept: 86830892
INFO stream create - -

AutoAccept is set to false on server and application.

thanks

Hash

Hi i have tested using the method described above and it still accepts the connection. Note that i have Wowza running on port 1936 for testing.

Log as follows:

INFO application app-start _definst_ -
INFO session connect-pending 125.54.xxx.xxx -
INFO server comment - onConnect: false
INFO session connect 125.54.xxx.xxx -
INFO server comment - onConnectAccept: 581738787

and here is the code in the flash client

nc.onStatus = function(info) {
	trace("Level: "+info.level+" Code: "+info.code);
	if (info.code == "NetConnection.Connect.Success") {
		trace("--- connected to: " + this.uri);
                          //do something
	} else if (info.code == "NetConnection.Connect.Rejected") {
		//do something
	}
};

Please advise on what might be going wrong.

Thanks

Hash

Yes the code is being executed because the log indicates so. Unfortunately it failed again:

INFO session connect-pending 125.54.xxx.xxx -
INFO server comment - REJECT
INFO server comment - onConnect: false
INFO session connect 125.54.xxx.xxx -

and the Flash client info.code response is as before

Level: status Code: NetConnection.Connect.Success

Note also that we have to have FMS running on port 1935 at the moment but i can’t imagine how that could interfere.

thanks

Hash

Hi you are absolutely right, i was calling the bwcheck module after the authentication module. I reordered the module list and the connection is being rejected as expected.

Thanks for the support.

hi again

my question migth be stupid or just i didn"t opened my eyes…how to select the database to connect ? no problem for issuing the mysql request, but i didn’t see any code that defines the db to connect to ? can you help ?

another question, regarding java synthax in fact:

i took your code (the first main one of that post) and i renammed the function updateStats.

What i want to do is to call updateStats(username,userid,time); from within a onDisconnect function…the ide returns me the following error where i’m calling updateStats:

The method updateStats(IClient, RequestFunction, AMFDataList) in the type MainModule

is not applicable for the arguments (IClient, String)

so i guess this is a question of datas passed to the function but after different tries it appears i didn’t really know how to handle this…i understand that i would have to call update like that:

updateStats(client,updateStats,name,id,time) or what else…but i can’t get the correct synthax…if you can provide me some infos about that

Thanks again !

thx !

gabriel

You need to compile this with the Wowza IDE:

http://wowza.com/ide.html

The IDE will compile your .Java source file to a jar file in the Wowza lib folder. Then you can the module reference in the Application.xml

Richard

Another approach is use querystring with streamer.

streamer = rtmp://[wowza-address]:1935/[app-name]?richard&pwd

Then do:

String[] auth = client.getQueryStr().split("&");
username = auth[0];
password = auth[1];

https://www.wowza.com/docs/how-to-do-file-based-rtmp-authentication-with-url-query-strings-onconnectauthenticate2

Richard

Hi i try to create my own class on my Wowza server with my file in:

/usr/local/WowzaMediaServer/lib/ModuleInternalTest.class

package com.wowza.wms.plugin.test.module;

import com.wowza.wms.amf.*;
import com.wowza.wms.client.*;
import com.wowza.wms.module.*;
import com.wowza.wms.request.*;
import com.wowza.wms.stream.*;
import com.wowza.wms.application.*;
import com.wowza.wms.sharedobject.*;

public class ModuleInternalTest extends ModuleBase
{
        public void onConnect(IClient client, RequestFunction function,AMFDataList params) {

                int clientCount = client.getApplication().getConnectionCounter().getTotal();
                if (clientCount > 2)
                {
                        getLogger().info("REJECT");
                        client.rejectConnection();
                }
                else
                {
                        getLogger().info("CONNECTION");
                }
        }
}

In my console i type:

jar cvf ModuleInternalTest.jar ModuleInternalTest.class

And in my /conf/test/Application.xml i’ve got :

  <Module>
    <Name>test</Name>
    <Description>test</Description>
    <Class>com.wowza.wms.plugin.test.ModuleInternalTest</Class>
  </Module>

When i launch my Wowza serveur i’ve got in my log (when i’ve a client connected on my test application)

ERROR server comment - loadModFunctions: java.lang.ClassNotFoundException: com.wowza.wms.plugin.test.ModuleInternalTest
java.lang.ClassNotFoundException: com.wowza.wms.plugin.test.ModuleInternalTest
	at java.net.URLClassLoader$1.run(URLClassLoader.java:217)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.net.URLClassLoader.findClass(URLClassLoader.java:205)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:323)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:268)
	at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:336)
	at java.lang.Class.forName0(Native Method)
	at java.lang.Class.forName(Class.java:186)
	at com.wowza.wms.util.ModuleUtils.addModuleToApp(Unknown Source)
	at com.wowza.wms.util.ApplicationUtils.loadModules(Unknown Source)
	at com.wowza.wms.util.ApplicationUtils.loadConfigFile(Unknown Source)
	at com.wowza.wms.application.ApplicationInstance.loadConfig(Unknown Source)
	at com.wowza.wms.application.ApplicationInstance.<init>(Unknown Source)
	at com.wowza.wms.application.Application.getAppInstance(Unknown Source)
	at com.wowza.wms.module.ModuleConnect.connect(Unknown Source)
	at com.wowza.wms.request.RequestProcessFunctions.processFunctions(Unknown Source)
	at com.wowza.wms.request.RTMPRequestAdapter.service(Unknown Source)
	at com.wowza.wms.server.ServerHandler.serviceRequest(Unknown Source)
	at com.wowza.wms.server.ServerHandler.handleMessageReceived(Unknown Source)
	at com.wowza.wms.server.ServerHandler.messageReceived(Unknown Source)
	at com.wowza.wms.server.ServerHandlerThreadedSession.run(Unknown Source)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
	at java.lang.Thread.run(Thread.java:636)
INFO server comment

I’m not shure about my java class… I try to understand how it’s works :wink:

Note : I’m on Wowza 2.0

Thanks,

Best regards,

Probably you have to purchase JWPlayer to get the .fla file to edit. If you look in the Wowza examples folder, there are several Flash players which include the source.