ffmpeg rtmp authentication with SQL database

Hi everyone,

I make my plugin with following code sample:

https://www.wowza.com/docs/how-to-do-user-authentication-for-flash-rtmp-client-using-jdbc-connection-to-mysql-database

According sample

String userName = getParamString(params, PARAM1);

String password = getParamString(params, PARAM2);

But I got null, null (userName, password) when tried to stream video using ffmpeg, for example I used following commands:

~/bin/ffmpeg -re -i /usr/local/WowzaStreamingEngine-4.0.6/content/test1.mp4 -strict -2 -c:v h264 -c:a aac -f flv “rtmp://stream4:test11@localhost:1935/live/myStream”

Or

~/bin/ffmpeg -re -i /usr/local/WowzaStreamingEngine-4.0.6/content/test1.mp4 -strict -2 -c:v h264 -c:a aac -f flv “rtmp://localhost:1935/live/myStream?stream4&test11”

Anytime I got following error:

[rtmp @ 0x3084c20] Unknown connect error (unsupported authentication method?)

[rtmp @ 0x3084c20] Server error: Connection failed: Application rejected connection.

rtmp://stream4:test11@localhost:1935/live/myStream: Unknown error occurred

Do you have any idea how stream video with ffmpeg and user/password?

Thanks,

Andrey

Application.xml for live

false

base

Base

com.wowza.wms.module.ModuleCore

logging

Client Logging

com.wowza.wms.module.ModuleClientLogging

flvplayback

FLVPlayback

com.wowza.wms.module.ModuleFLVPlayback

dbauthmod

PGSQLAUTH

dbauth.DbAuth

Hi,

This thread both reports and resolves a similar problem.

Basically the solution is to use SecureURLParams, a different method of authentication.

Daren

Hi,

Can you change this:

rtmp://localhost:1935/live/myStream?stream4&test11

into this:

rtmp://localhost:1935/live/?stream4&test11/myStream

Then you can use use the client.getQueryStr() in the onConnect function to read the “stream4&test11” query string that was passed in the connection call. In the module, you can read the query string and distinguish between your username and password by using the “&” character as separator.

Zoran

Hi,

You could store a hashed string in the database and then on Wowza side you can take the user’s password, generate the hash sting on-the-fly, using the same logic that was

used when the hash that is stored in the database was created, and then match the two hashed strings. If they match, then the user has provided the correct password.

Zoran

Hi,

This thread both reports and resolves a similar problem.

Basically the solution is to use SecureURLParams, a different method of authentication.

Daren

No, no.

Standart authentication works fine. Add publisher via web interface and it works fine

ffmpeg rtmp://user:pass@ip/live/etc

But it doesn’t work for SQL authentication.

Here is my code sample

public void onConnect(IClient client, RequestFunction function,
			AMFDataList params) {
		getLogger().info("onConnect: DbAuth ");
		String userName = getParamString(params, PARAM1);
		String password = getParamString(params, PARAM2);
		getLogger().info("onConnect: param1 " +userName+ ", param2 "+password);
		
		Connection conn = null;
		try 
		{
			getLogger().info("onConnect: try ");
			conn = DriverManager.getConnection("jdbc:postgresql://localhost/pdb?user=puser&password=p1");
			Statement stmt = null;
			ResultSet rs = null;
			try 
			{
				getLogger().info("onConnect: connect ok ");
				stmt = conn.createStatement();
				rs = stmt.executeQuery("SELECT count(*) as userCount FROM users where login = '"+userName+"' and enc_password = '"+password+"'");
				if (rs.next() == true)
				{
					getLogger().info("onConnect: select ok ");
				    if (rs.getInt("userCount") > 0)
					{
						getLogger().info("onConnect: accept ok ");
						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());
	}

I got null, null for param1 and param2

Hi everyone,

Described sample on your page is incorrect

Incorrect sample:

https://www.wowza.com/docs/how-to-do-user-authentication-for-flash-rtmp-client-using-jdbc-connection-to-mysql-database

Correct sample here:

https://www.wowza.com/docs/how-to-integrate-wowza-user-authentication-with-external-authentication-systems-modulertmpauthenticate

As you see RTMP Auth with SQL is extra different from first sample.

I think you should update your page.

Thanks,

Andrey

Second sample doesn’t works :frowning:

Here is my Application.xml

It accept username/password added via web interface (publisher) as it work w/o my plugin, but don’t accept sql users.

Any ideas?

I looked logs and I don’t see that my Auth function called.

No logs regarding

public class DbSqlAuth extends AuthenticateUsernamePasswordProviderBase
{
	public String getPassword(String username)
	{
		// return password for given username		
		String pwd = null;
		
		WMSLoggerFactory.getLogger(null).info("Authenticate getPassword username: " + username);

Application.XML:

<?xml version="1.0" encoding="UTF-8"?>
<Root version="1">
	<Application>
		<Name>live</Name>
		<AppType>Live</AppType>
		<Description>Default application for live streaming created when Wowza Streaming Engine is installed. Use this application with its default configuration or modify the configuration as needed. You can also copy it to create another live application.</Description>
		<!-- Uncomment to set application level timeout values
		<ApplicationTimeout>60000</ApplicationTimeout>
		<PingTimeout>12000</PingTimeout>
		<ValidationFrequency>8000</ValidationFrequency>
		<MaximumPendingWriteBytes>0</MaximumPendingWriteBytes>
		<MaximumSetBufferTime>60000</MaximumSetBufferTime>
		<MaximumStorageDirDepth>25</MaximumStorageDirDepth>
		-->
		<Connections>
			<AutoAccept>true</AutoAccept>
			<AllowDomains></AllowDomains>
		</Connections>
		<!--
			StorageDir path variables
			
			${com.wowza.wms.AppHome} - Application home directory
			${com.wowza.wms.ConfigHome} - Configuration home directory
			${com.wowza.wms.context.VHost} - Virtual host name
			${com.wowza.wms.context.VHostConfigHome} - Virtual host config directory
			${com.wowza.wms.context.Application} - Application name
			${com.wowza.wms.context.ApplicationInstance} - Application instance name
			
		-->
		<Streams>
			<StreamType>live-lowlatency</StreamType>
			<StorageDir>${com.wowza.wms.context.VHostConfigHome}/content</StorageDir>
			<KeyDir>${com.wowza.wms.context.VHostConfigHome}/keys</KeyDir>
			<!-- LiveStreamPacketizers (separate with commas): cupertinostreamingpacketizer, smoothstreamingpacketizer, sanjosestreamingpacketizer, mpegdashstreamingpacketizer, cupertinostreamingrepeater, smoothstreamingrepeater, sanjosestreamingrepeater, mpegdashstreamingrepeater -->
			<LiveStreamPacketizers>cupertinostreamingpacketizer, mpegdashstreamingpacketizer, sanjosestreamingpacketizer, smoothstreamingpacketizer</LiveStreamPacketizers>
			<!-- Properties defined here will override any properties defined in conf/Streams.xml for any streams types loaded by this application -->
			<Properties>
			</Properties>
		</Streams>
		<Transcoder>
			<!-- To turn on transcoder set to: transcoder -->
			<LiveStreamTranscoder></LiveStreamTranscoder>
			<!-- [templatename].xml or ${SourceStreamName}.xml -->
			<Templates>transcode.xml</Templates>
			<ProfileDir>${com.wowza.wms.context.VHostConfigHome}/transcoder/profiles</ProfileDir>
			<TemplateDir>${com.wowza.wms.context.VHostConfigHome}/transcoder/templates</TemplateDir>
			<Properties>
			</Properties>
		</Transcoder>
		<DVR>
			<!-- As a single server or as an origin, use dvrstreamingpacketizer in LiveStreamPacketizers above -->
			<!-- Or, in an origin-edge configuration, edges use dvrstreamingrepeater in LiveStreamPacketizers above -->
			<!-- As an origin, also add dvrchunkstreaming to HTTPStreamers below -->
			<!-- If this is a dvrstreamingrepeater, define Application/Repeater/OriginURL to point back to the origin -->
			<!-- To turn on DVR recording set Recorders to dvrrecorder.  This works with dvrstreamingpacketizer  -->
			<Recorders></Recorders>
			<!-- As a single server or as an origin, set the Store to dvrfilestorage-->
			<!-- edges should have this empty -->
			<Store></Store>
			<!--  Window Duration is length of live DVR window in seconds.  0 means the window is never trimmed. -->
			<WindowDuration>0</WindowDuration>
			<!-- Storage Directory is top level location where dvr is stored.  e.g. c:/temp/dvr -->
			<StorageDir>${com.wowza.wms.context.VHostConfigHome}/dvr</StorageDir>
			<!-- valid ArchiveStrategy values are append, version, delete -->
			<ArchiveStrategy>append</ArchiveStrategy>
			<!-- Properties for DVR -->
			<Properties>
			</Properties>
		</DVR>
		<TimedText>
			<!-- VOD caption providers (separate with commas): vodcaptionprovidermp4_3gpp, vodcaptionproviderttml, vodcaptionproviderwebvtt,  vodcaptionprovidersrt, vodcaptionproviderscc -->
			<VODTimedTextProviders></VODTimedTextProviders>
			<!-- Properties for TimedText -->
			<Properties>
			</Properties>
		</TimedText>
		<!-- HTTPStreamers (separate with commas): cupertinostreaming, smoothstreaming, sanjosestreaming, mpegdashstreaming, dvrchunkstreaming -->
		<HTTPStreamers>cupertinostreaming, smoothstreaming, sanjosestreaming, mpegdashstreaming</HTTPStreamers>
		<MediaCache>
			<MediaCacheSourceList></MediaCacheSourceList>
		</MediaCache>
		<SharedObjects>
			<StorageDir>${com.wowza.wms.context.VHostConfigHome}/applications/${com.wowza.wms.context.Application}/sharedobjects/${com.wowza.wms.context.ApplicationInstance}</StorageDir>
		</SharedObjects>
		<Client>
			<IdleFrequency>-1</IdleFrequency>
			<Access>
				<StreamReadAccess>*</StreamReadAccess>
				<StreamWriteAccess>*</StreamWriteAccess>
				<StreamAudioSampleAccess></StreamAudioSampleAccess>
				<StreamVideoSampleAccess></StreamVideoSampleAccess>
				<SharedObjectReadAccess>*</SharedObjectReadAccess>
				<SharedObjectWriteAccess>*</SharedObjectWriteAccess>
			</Access>
		</Client>
		<RTP>
			<!-- RTP/Authentication/[type]Methods defined in Authentication.xml. Default setup includes; none, basic, digest -->
			<Authentication>
				<PublishMethod>none</PublishMethod>
				<PlayMethod>none</PlayMethod>
			</Authentication>
			<!-- RTP/AVSyncMethod. Valid values are: senderreport, systemclock, rtptimecode -->
			<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 defined here will override any properties defined in conf/RTP.xml for any depacketizers loaded by this application -->
			<Properties>
			</Properties>
		</RTP>
		<MediaCaster>
			<RTP>
				<RTSP>
					<!-- udp, interleave -->
					<RTPTransportMode>interleave</RTPTransportMode>
				</RTSP>
			</RTP>
			<StreamValidator>
				<Enable>true</Enable>
				<ResetNameGroups>true</ResetNameGroups>
				<StreamStartTimeout>20000</StreamStartTimeout>
				<StreamTimeout>12000</StreamTimeout>
				<VideoStartTimeout>0</VideoStartTimeout>
				<VideoTimeout>0</VideoTimeout>
				<AudioStartTimeout>0</AudioStartTimeout>
				<AudioTimeout>0</AudioTimeout>
				<VideoTCToleranceEnable>false</VideoTCToleranceEnable>
				<VideoTCPosTolerance>3000</VideoTCPosTolerance>
				<VideoTCNegTolerance>-500</VideoTCNegTolerance>
				<AudioTCToleranceEnable>false</AudioTCToleranceEnable>
				<AudioTCPosTolerance>3000</AudioTCPosTolerance>
				<AudioTCNegTolerance>-500</AudioTCNegTolerance>
				<DataTCToleranceEnable>false</DataTCToleranceEnable>
				<DataTCPosTolerance>3000</DataTCPosTolerance>
				<DataTCNegTolerance>-500</DataTCNegTolerance>
				<AVSyncToleranceEnable>false</AVSyncToleranceEnable>
				<AVSyncTolerance>1500</AVSyncTolerance>
				<DebugLog>false</DebugLog>
			</StreamValidator>
			<!-- Properties defined here will override any properties defined in conf/MediaCasters.xml for any MediaCasters loaded by this applications -->
			<Properties>
			</Properties>
		</MediaCaster>
		<MediaReader>
			<!-- Properties defined here will override any properties defined in conf/MediaReaders.xml for any MediaReaders loaded by this applications -->
			<Properties>
			</Properties>
		</MediaReader>
		<MediaWriter>
			<!-- Properties defined here will override any properties defined in conf/MediaWriter.xml for any MediaWriter loaded by this applications -->
			<Properties>
			</Properties>
		</MediaWriter>
		<LiveStreamPacketizer>
			<!-- Properties defined here will override any properties defined in conf/LiveStreamPacketizers.xml for any LiveStreamPacketizers loaded by this applications -->
			<Properties>
			</Properties>
		</LiveStreamPacketizer>
		<HTTPStreamer>
			<!-- Properties defined here will override any properties defined in conf/HTTPStreamers.xml for any HTTPStreamer loaded by this applications -->
			<Properties>
			</Properties>
		</HTTPStreamer>
		<Manager>
			<!-- Properties defined are used by the Manager -->
			<Properties>
			</Properties>
		</Manager>
		<Repeater>
			<OriginURL></OriginURL>
			<QueryString><![CDATA[]]></QueryString>
		</Repeater>
		<StreamRecorder>
			<Properties>
			</Properties>
		</StreamRecorder>
		<Modules>
			<Module>
				<Name>base</Name>
				<Description>Base</Description>
				<Class>com.wowza.wms.module.ModuleCore</Class>
			</Module>
			<Module>
				<Name>logging</Name>
				<Description>Client Logging</Description>
				<Class>com.wowza.wms.module.ModuleClientLogging</Class>
			</Module>
			<Module>
				<Name>flvplayback</Name>
				<Description>FLVPlayback</Description>
				<Class>com.wowza.wms.module.ModuleFLVPlayback</Class>
			</Module>
			<Module>
				<Name>ModuleRTMPAuthenticate</Name>
				<Description>ModuleRTMPAuthenticate</Description>
				<Class>com.wowza.wms.plugin.security.ModuleRTMPAuthenticate</Class>
			</Module>
			<Module>
				<Name>ModuleCoreSecurity</Name>
				<Description>Core Security Module for Applications</Description>
				<Class>com.wowza.wms.security.ModuleCoreSecurity</Class>
			</Module>
		</Modules>
		<!-- Properties defined here will be added to the IApplication.getProperties() and IApplicationInstance.getProperties() collections -->
		<Properties>
			<Property>
				<Name>liveStreamRecordStartOnKeyFrame</Name>
				<Value>true</Value>
				<Type>boolean</Type>
			</Property>
			<Property>
				<Name>securityPublishRequirePassword</Name>
				<Value>true</Value>
				<Type>Boolean</Type>
			</Property>
[B][COLOR="#FF0000"]<Property>
        <Name>usernamePasswordProviderClass</Name>
        <Value>dbsqlauth.DbSqlAuth</Value>
</Property>[/COLOR][/B]
		</Properties>
	</Application>
</Root>

Hi everyone,

Any updates?

Hi,

Problem solved. It was issue with App config. Now it’s fine.

But AuthenticateUsernamePasswordProviderBase getPassword() return password w/o any encryption. So we should store open password in database. It’s not secure. Do you know any way for work with encrypted password for rtmp auth?

Thanks,

Andrey

Hi,

You could store a hashed string in the database and then on Wowza side you can take the user’s password, generate the hash sting on-the-fly, using the same logic that was

used when the hash that is stored in the database was created, and then match the two hashed strings. If they match, then the user has provided the correct password.

Zoran

Hi Zoran,

Could you please provide any additional comments?

rtmp://user:pass@localhost:1935/live/myStream

And getPassword() got open password from database. And after it compare with password from rtmp:// string.

So, do you mean that need send hash in rtmp:// string or some else?

Thanks,

Andrey