• How to do file-based authentication with RTMP client and credentials in querystring of NetConnection connect RTMP URL

    This is a file based, username/password authentication method that you can use with Flash applications and encoders that make RTMP connections to Wowza Server.

    The difference in this version 2 from the original is only that username and password are added to connection url as querystring, instead of paramaters of NetConnection.connect. This method can be used as an alternative to ModuleRTMPAuthenticate method in the Wowza MediaSecurity AddOn for encoders that do not support username/password authentication.

    Code:
    package com.wowza.wms.plugin.collection.module;
    
    import java.io.*;
    import java.util.*;
    
    import com.wowza.util.*;
    import com.wowza.wms.amf.*;
    import com.wowza.wms.application.*;
    import com.wowza.wms.authentication.*;
    import com.wowza.wms.authentication.file.*;
    import com.wowza.wms.client.*;
    import com.wowza.wms.module.*;
    import com.wowza.wms.request.*;
    import com.wowza.wms.util.*;
    import com.wowza.wms.vhost.*;
    
    public class ModuleOnConnectAuthenticate2 extends ModuleBase
    { 
    	public static final String AUTHPASSWORDFILEPATH = "${com.wowza.wms.context.VHostConfigHome}/conf/connect.password";
    	private File passwordFile = null;
    	private String usernamePasswordProviderClass = null;
    
    	public void onAppStart(IApplicationInstance appInstance)
    	{
    		WMSProperties props = appInstance.getProperties();
    				
    		String passwordFileStr = props.getPropertyStr("rtmpAuthenticateFile", AUTHPASSWORDFILEPATH);
    		this.usernamePasswordProviderClass = props.getPropertyStr("usernamePasswordProviderClass", this.usernamePasswordProviderClass);
    		if (passwordFileStr != null)
    		{
    			Map<String, String> envMap = new HashMap<String, String>();
    			
    			IVHost vhost = appInstance.getVHost();
    			envMap.put("com.wowza.wms.context.VHost", vhost.getName());
    			envMap.put("com.wowza.wms.context.VHostConfigHome", vhost.getHomePath());
    			envMap.put("com.wowza.wms.context.Application", appInstance.getApplication().getName());
    			envMap.put("com.wowza.wms.context.ApplicationInstance", appInstance.getName());
    
    			passwordFileStr = SystemUtils.expandEnvironmentVariables(passwordFileStr, envMap);
    			passwordFile = new File(passwordFileStr);
    		}
    		
    		if (passwordFile != null)
    			getLogger().info("ModuleOnConnectAuthenticate: Authorization password file: "+passwordFile.getAbsolutePath());
    		if (usernamePasswordProviderClass != null)
    			getLogger().info("ModuleOnConnectAuthenticate: Authorization password class: "+usernamePasswordProviderClass);
    	}
    
    public void onConnect(IClient client, RequestFunction function, AMFDataList params)
    {
    	boolean isAuthenticated = false;
    	
    	String username = null;
    	String password = null;
    	
    	try
    	{
    		while(true)
    		{
    			getLogger().info("size: " + params.size());
    			
    			String[] auth = client.getQueryStr().split("&");
    			
    			username = auth[0];
    			password = auth[1];
    				
    				if (username == null || password == null)
    					break;
    								
    				IAuthenticateUsernamePasswordProvider filePtr = null;
    				if (usernamePasswordProviderClass != null)
    					filePtr = AuthenticationUtils.createUsernamePasswordProvider(usernamePasswordProviderClass);
    				else if (passwordFile != null)
    					filePtr = AuthenticationPasswordFiles.getInstance().getPasswordFile(passwordFile);
    				
    				if (filePtr == null)
    					break;
    
    				filePtr.setClient(client);
    
    				String userPassword = filePtr.getPassword(username);
    				if (userPassword == null)
    					break;
    
    				if (!userPassword.equals(password))
    					break;
    				
    				isAuthenticated = true;
    				break;
    			}
    		}
    		catch(Exception e)
    		{
    			getLogger().error("ModuleOnConnectAuthenticate.onConnect: "+e.toString());
    			isAuthenticated = false;
    		}
    		
    		if (!isAuthenticated)
    			client.rejectConnection("Authentication Failed["+client.getClientId()+"]: "+username);
    		else
    			client.acceptConnection();
    	}
    }
    A compiled version of this module is included in the Wowza Modules Collection. Download and unzip the collection, then copy /lib/wms-plugin-collection.jar from the package to the Wowza /lib folder. Then restart Wowza.

    To use this module
    1. Create a text file [install-dir]/conf folder named connect.password, then add a line with a username and password separate with a space for each user:

      [install-dir]/conf/connect.password:
      user1 pass1
      user2 pass2
    2. Add the following Module to the Modules list of the Application.xml you want to authenticate:

      Code:
      <Module> 
      <Name>moduleOnConnectAuthenticate2</Name> 
      <Description>ModuleOnConnectAuthenticate2</Description> 
      <Class>com.wowza.wms.plugin.collection.module.ModuleOnConnectAuthenticate2</Class> 
      </Module>
    3. Modify the NetConnection.connect statement in the Flash application to pass a username and password, something like this:
      Code:
      netconnection.connect("rtmp://[wowza-address]/[app-name]?user1&pass1");




    Comments 23 Comments
    1. Lam-Strim -
      Hi,
      Can I use this with FMLE ?
      netconnection.connect("rtmp://[wowza-address]/[app-name]?user1&pass1");

      I can't make it work with this url : rtmp://[wowza-address]/[app-name]?user1&pass1

      Thank you
    1. rrlanham -
      This will work with FMLE. But ModuleRTMPAuthenticate in the MediaSecurity Addon is a better choice

      http://www.wowzamedia.com/forums/con...ation-and-more)

      Or this older method, which similarly uses querystring:
      http://www.wowzamedia.com/forums/con...for-Publishing

      Richard
    1. Lam-Strim -
      Sorry I'm not sure to understand all.

      I already use ModuleRTMPAuthenticate but I want to avoid enter name and password each time I connect with FMLE.
      So it would be good to put the user/password in the URL (I guess that it's what is called "querystring")

      Is the ModuleOnConnectAuthenticate2 in conflict with ModuleRTMPAuthenticate (it doesn't work on fmle for me)

      I cannot use ModuleSecureURLParams as I need to keep ModuleRTMPAuthenticate (other users need it).

      What do you recommend please?
    1. rrlanham -
      I don't really understand what you want to do and what the constraints are. You could use ModuleOnConnectAuthenticate2 (or ModuleSecureURLParams) or ModuelRTMPAuthenticate, not sure about combining. I think it will have to be one or the other.

      Richard
    1. laurosdorneles -
      Hi Richard, using this solution ModuleOnConnectAuthenticate2 I also need to pass user and password to play the stream. Is that correct? Where can I find examples on setting up a solution with ModuleOnConnectAuthenticate2, secure token and rtmpe, all together? Thanks.
    1. rrlanham -
      ModuleOnConnectAuthenticate2 uses onConnect handler to authenticate, which runs when a Flash RTMP client does netconnection.connect, it does not run when you play a stream.

      I don't have an example of that combo, but you should be able to add this Module in to an application with SecureToken also enabled, separately.

      Richard
    1. Teamplaya -
      Hello, I'm playing with IAuthenticateUsernamePasswordProvider.
      Everything works fine with RTSP/RTMP. There is a fileptr.setCliet and .setRTPSession.
      My problem is the following:
      I'm trying to add a onHTTPSessionCreate for IHTTPStreamerSession.

      But there is no possibility to set IHTTPStreamerSession on filePtr.
      So how can i add the Client like filePtr.setClient() ???

      Do i have to set filePtr.setClient() , when i', using IHTTPStreamerSession?

      Please help

      Code:
      	
      REMOVED
    1. rrlanham -
      No, sorry, it won't work. There is no IClient in that context

      Richard
    1. Teamplaya -
      What it wont work? This is just your answer ? IT HAS TO WORK!

      Then just correct the IAuthenticateUsernamePasswordProvider that i can use the HTTPSession.

      Whats up? I dont get it. Wowza costs so much and this is what you have to say? "It won't work" ? Really ?
      Its ridicilous.
      RTSP and RTMP are working fine ! "Base class for implementing HTTP and RTSP based custom authentication class."
    1. rrlanham -
      You can do DB look up in onHTTPSessionCreate without IAuthenticateUsernamePasswordProvider.

      IAuthenticateUsernamePasswordProvider works with ModuleRTMPAuthenticate. IClient is the server-side of a Flash RTMP client NetConnection, which is not involved in HTTP sessions.

      Richard
    1. Teamplaya -
      I dont know what are you talking about.
      I dont want to use a Database? Is that so hard to understand?

      I want a authentication just like rtmp/rtsp with a user-password file (like connect.password).
      Please give me the possibility to check user/password thru a userfile (IHTTPSession based!) !
    1. rrlanham -
      There is an example of doing file based look-up here:
      http://www.wowza.com/forums/content....nnect-RTMP-URL

      The above involves onConnect, which is also Flash RTMP only, but you can take the file look-up part out and add to the onHTTPSession handler.

      Richard
    1. Teamplaya -
      lol are you kidding? This is exactly what i have done ! look in the sample code i provided above.
      The problem is i cant assign the Ihttpsession to filePtr.setClient(client);!!!!
      So how do i set the client in fileptr witch ihttpsession?....

      "How can we authenticate HTTP to a similar connect.password file then ?"
    1. rrlanham -
      This works for me:

      Code:
      package test;
      
      import java.io.File;
      import java.util.HashMap;
      import java.util.Map;
      
      import com.wowza.util.SystemUtils;
      import com.wowza.wms.httpstreamer.model.IHTTPStreamerSession;
      import com.wowza.wms.module.*;
      import com.wowza.wms.util.AuthenticationUtils;
      import com.wowza.wms.vhost.IVHost;
      import com.wowza.wms.application.*;
      import com.wowza.wms.authentication.IAuthenticateUsernamePasswordProvider;
      import com.wowza.wms.authentication.file.AuthenticationPasswordFiles;
      
      public class ModuleAccessControlHTTPStreaming extends ModuleBase
      {
      	public static final String AUTHPASSWORDFILEPATH = "${com.wowza.wms.context.VHostConfigHome}/conf/connect.password";
      	private File passwordFile = null;
      	private String usernamePasswordProviderClass = null;
      	
      	public void onAppStart(IApplicationInstance appInstance)
      	{
      		WMSProperties props = appInstance.getProperties();
      				
      		String passwordFileStr = props.getPropertyStr("rtmpAuthenticateFile", AUTHPASSWORDFILEPATH);
      		this.usernamePasswordProviderClass = props.getPropertyStr("usernamePasswordProviderClass", this.usernamePasswordProviderClass);
      		if (passwordFileStr != null)
      		{
      			Map<String, String> envMap = new HashMap<String, String>();
      			
      			IVHost vhost = appInstance.getVHost();
      			envMap.put("com.wowza.wms.context.VHost", vhost.getName());
      			envMap.put("com.wowza.wms.context.VHostConfigHome", vhost.getHomePath());
      			envMap.put("com.wowza.wms.context.Application", appInstance.getApplication().getName());
      			envMap.put("com.wowza.wms.context.ApplicationInstance", appInstance.getName());
      
      			passwordFileStr = SystemUtils.expandEnvironmentVariables(passwordFileStr, envMap);
      			passwordFile = new File(passwordFileStr);
      		}
      		
      		if (passwordFile != null)
      			getLogger().info("ModuleOnConnectAuthenticate: Authorization password file: "+passwordFile.getAbsolutePath());
      		if (usernamePasswordProviderClass != null)
      			getLogger().info("ModuleOnConnectAuthenticate: Authorization password class: "+usernamePasswordProviderClass);
      	}
      	
      	public void onHTTPSessionCreate(IHTTPStreamerSession httpSession)
      	{
      		boolean isGood = true;
      		
      		String ipAddressClient = httpSession.getIpAddress();
      		String ipAddressServer = httpSession.getServerIp();
      		String queryStr = httpSession.getQueryStr();
      		String referrer = httpSession.getReferrer();
      		String cookieStr = httpSession.getCookieStr();
      		String userAgent = httpSession.getUserAgent();
      		
      		boolean isAuthenticated = false;
      		
      		String username = null;
      		String password = null;
      		
      		try
      		{
      			while(true)
      			{
      				//getLogger().info("size: " + params.size());
      				
      				String[] auth = queryStr.split("&");
      				
      				username = auth[0];
      				password = auth[1];
      					
      					if (username == null || password == null)
      						break;
      									
      					IAuthenticateUsernamePasswordProvider filePtr = null;
      					if (usernamePasswordProviderClass != null)
      						filePtr = AuthenticationUtils.createUsernamePasswordProvider(usernamePasswordProviderClass);
      					else if (passwordFile != null)
      						filePtr = AuthenticationPasswordFiles.getInstance().getPasswordFile(passwordFile);
      					
      					if (filePtr == null)
      						break;
      
      					//filePtr.setClient(client);
      
      					String userPassword = filePtr.getPassword(username);
      					if (userPassword == null)
      						break;
      
      					if (!userPassword.equals(password))
      						break;
      					
      					isAuthenticated = true;
      					break;
      				}
      			}
      			catch(Exception e)
      			{
      				isAuthenticated = false;
      			}
      			
      			if (!isAuthenticated)
      				httpSession.rejectSession();
      			else
      				httpSession.acceptSession();
      		
      		
      		
      		IApplicationInstance appInstance = httpSession.getAppInstance();
      		String streamName = httpSession.getStreamName();
      		
      		// Here you can use the request and session information above to determine 
      		// if you want to reject the connection
      		// isGood = true/false;
      		
      		getLogger().info("ModuleAccessControlHTTPStreaming.onHTTPSessionCreate["+appInstance.getContextStr()+":"+streamName+"]: accept:"+isGood);
      		
      		if (!isGood)
      			httpSession.rejectSession();
      	}
      }
      Richard
    1. Teamplaya -
      Thanks Richard, even my example was successfull!
      In the first place i wanted to know if it is necessary to set the Client if i'm using the IHttpSession with IAuthenticateUsernamePasswordProvider.
      Now i know that it doesnt.
      I'm sorry for my language, if you want you can clear up the comments here.
      Thanks!
    1. rrlanham -
      Cool, np, thanks for the update. Glad it's working

      Richard
    1. briand123 -
      Unlike the RTMPAuthenticate module, this ModuleOnConnectAuthenticate2 requires a user and password to not only for a publish connection, but also for the play connection. I just want to protect the publish. How can this be modified to only require user/passwd for publish connection? Would the onConnect method be able to distinguish that based on the client type somehow (i.e. FMLE vs JW player, etc.) If so, how?

      Thanks,
      Brian
    1. roger_l -
      Hi,

      To do this, in the onConnect method, you would need to detect the user-agent of connection type to see if it is a publisher or player. If a player then you would just return from the method. If a publisher then you would go through the authentication. It would be a good idea, once authenticated, to set a client property to indicate the publisher has been authenticated and then override the publish method and check the property there. This will catch any unknown user-agents.

      The Hot-link denial module shows a method to detect encoders. It actually does the opposite to this module where it allows encoders and blocks player connections based on the player location.

      Roger.
    1. briand123 -
      Thanks Roger. Makes sense and I understand clearly after looking at the hot link module. The only thing I have to figure out yet is how to create a new property in the IClient object to remember this client was authenticated during the onConnect so it can be checked on the onPublish method.
      Regards,
      Brian
    1. rrlanham -
      This is how:

      Code:
      client.getAppInstance().getProperties().setProperty("var", "val");
      
      // later, elsewhere, you can now do this:	
      String var = client.getAppInstance().getProperties().getPropertyStr("var");
      Richard