Wowza Community

User Authentication

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

Also, add a bunch of log statements to your code so you can see what is happening. It is the best way to figure it out.

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

Looks like you do not have all the required libraries (.jar files) copied into the Wowza Pro [intsall-dir]/lib folder. The class that is missing is org/aspectj/lang/Signature.

Charlie

Hi there,

Assuming that you are using code similar to charlie’s post on page 1 of this thread, add some System.out.println statements to see what is happening.

Statement stmt = null;
ResultSet rs = null;
try 
{
	stmt = conn.createStatement();
	String sql = "SELECT count(*) as userCount FROM users where username = '"+userName+"' and password = '"+password+"'";
	System.out.println("sql: "+sql);
	rs = stmt.executeQuery(sql);
	if (rs.next() == true)
	{
		System.out.println("rs.getInt("userCount"): "+rs.getInt("userCount") );
		if (rs.getInt("userCount") > 0)
		{
			System.out.println("client.acceptConnection()");
			client.acceptConnection();
		}
	}
	else 
	{
		System.out.println("Error - userCount = 0. Rejecting connection");
	}
} 

I have added the sql statement as a seperate string so it can be checked for syntax.

You can also copy and paste the sql into phpmyadmin or another sql client and check it is working as expected.

Try this a see what happens.

Roger.

Hi,

The debug error is happening after the reject so I dont think it is the problem.

Can you post an example of your java code for onConnect, onConnectReject & onConnectAccept.

I have checked out the flash code and it seems to be working ok.

Roger.

try the following. Im not sure if it will work as I am not is a position to test it.

Add a couple of logs to the sql bit of the code to see if the values are getting Through:

		try 
		{
			getLogger().info("userName @ sql: "+userName);
			getLogger().info("password @ sql: "+passpword);
			String sql = "SELECT count(*) as userCount FROM users where username = '"+userName+"' and password = '"+password+"'";
			getLogger().info("sql: "+sql);
			stmt = conn.createStatement(sql);
			rs = stmt.executeQuery();
			if (rs.next() == true) {
				if (rs.getInt("userCount") > 0)
				{
					client.acceptConnection();
				}
			}
		
		} catch (SQLException sqlEx) {

Some more logger info.

		try 
		{
			getLogger().info("userName @ sql: "+userName);
			getLogger().info("password @ sql: "+passpword);
			String sql = "SELECT count(*) as userCount FROM users where username = '"+userName+"' and password = '"+password+"'";
			getLogger().info("sql: "+sql);
			stmt = conn.createStatement(sql);
			rs = stmt.executeQuery();
			getLogger().info("rs: "+rs.toString());
			if (rs.next() == true) {
				getLogger().info("rs returns recordset");
				if (rs.getInt("userCount") > 0)
				{
					getLogger().info("which contains at least 1 record so connection should be accepted");
					client.acceptConnection();
				}
				else
				{
					getLogger().info("but it is empty.  Wrong username or password maybe");
				}
			}
		
		} catch (SQLException sqlEx) {
			getLogger().error("sqlexecuteException: " + sqlEx.toString());
		} 

you can never have too much information.

INFO server comment - userName @ sql: null
INFO server comment - password @ sql: null

This is the username & password from the client params. some reason they are not getting through.

{
String userName = getParamString(params, PARAM1);
String password = getParamString(params, PARAM2);
getLogger().info("params: "+params.toString());
// preload the driver class

Add another logger to the onConnect to see what the params are.

INFO session connect-pending 61.95.197.159 -
INFO server comment - params: AMFDataList:
[0] connect
[1] 1.0
[2] object
{Obj[]: app: "rtplive", flashVer: "WIN 9,0,124,0", swfUrl: "http://72.348.410.254/WOWZA/RTP/nativertp.swf", tcUrl: "rtmp://72.348.410.254/rtplive", fpad: false, capabilities: 15.0, audioCodecs: 1639.0, videoCodecs: 252.0, videoFunction: 1.0 , pageUrl: "http://72.348.410.254/WOWZA/RTP/index.html"}
[3] undefined
[4] undefined

[3] is PARAM1 (username) &

[4] is PARAM2 (password).

add some traces to the flash code to check if these values are set properly.

function connectLivePlayer()
{
if (nc == null)
{
nc = new NetConnection();
nc.connect(serverText.text,User.text,Pwd.text);
trace('User.text: '+User.text);
trace('Pwd.text: '+Pwd.text);
:
:
:

Can you create a new empty flash document and put the following into the actionscript.

var nc:NetConnection = new NetConnection();
nc.onStatus = function(info) {
	for(var i in info) trace(i+": "+info[i]);
}
var conn:String = "rtmp://server-ip/rtplive"; // change to suit
var user:String = "monty"; // I assume thes are the user & pass in the database.
var pass:String = "greatsqldb";
nc.connect(conn, user, pass);

run it with Ctrl-Enter from flash and post what shows in the output panel & the server output again

can you make sure that it is an AS2 flash document and not AS3

Im using flash 8 which the above works.

Is there any server output to go with the above?

Also, have you set up the server to only accept connection from certian IP’s

This mybe why the above doesnt work but you should still see debug code.

You may need to upload it to test.

Double check your fla document again.

I think it is strange that you define a value for User.text & PWD.text but they show as undefined.

Make sure that you have given the text fields that are on the stage an instance name so that you can refer to them in code.

Roger.