├── LICENSE
├── README.md
├── php
├── auth.php
├── changepass.php
├── common.php
├── login.html
├── login.php
├── logout.php
├── nginx.conf
├── profile.php
├── reg.php
├── register.html
├── resethash.php
└── showhash.php
└── python
├── auth.py
├── config.py
└── nginx.conf
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Nesseref/Orc
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # nginx-rtmp-auth
2 | Backend for handling nginx rtmp module stream authentication
3 |
4 | Note: the fun nginx/rtmp stuff is in auth.php/auth.py and nginx.conf. Everything else is a very bare-bones set of scripts to manage user tasks (user registration, id hash/password changes, etc) that could be easily replicated with practically any other web scripting language capable of interaction with a database.
5 |
6 | For that matter, the auth scripts could be easily replicated in practically anything else that is capable of database interaction (or, really, even just reading from a .htpassword style file). All the script really needs to do is process a request, check and see if the query string constitutes a valid set of credentials and, if so, return a HTTP 200 and, if not, return a HTTP 400. If you're interested in an authentication system for your nginx rtmp server and posess non-trivial programming experience, this project should be viewed as more of an example than a drop-in solution.
7 |
8 | See https://github.com/Nesseref/html5-livestreaming for an example of using the python side of this project to provide authentication for an HTML5 (HLS with JS web player) environment.
9 |
10 | # PHP
11 | **Note:** the PHP web stuff (i.e. not auth.php) is intended as an example of the sort of frontend functionality that can be constructed to interface with the authentication backend. Do **_not_** use these scripts in production, as they were not designed for actual use.
12 |
13 | Requirements:
14 | - Nginx with RTMP module (https://github.com/arut/nginx-rtmp-module)
15 | - a MySQL server
16 | - FastCGI
17 | - PHP with MySQLi extension
18 |
19 | Server-side configuration:
20 | - Set nginx.conf as the live nginx conf (location of file depends on system)
21 | - Set the web root to an appropriate value
22 | - Adjust worker_connections to a sane value for the platform
23 | - Set worker_processes to 1 to work around an issue in the nginx-rtmp module
24 | - Set the name of the rtmp server application block to whatever is desired (defaults to "stream")
25 | - Place the .php/.html files in the web root and adjust the on_publish directive url to reflect the location of auth.php
26 | - Set MySQL-related variables in common.php ($host, $username, $password, $dbname, $usertablename)
27 | - Set the non-MySQL-related variables in common.php ($streamurl (the URL to stream to minus the id hash at the end, i.e. "rtmp://DOMAIN/stream?" assuming the rtmp server application block name of "stream"), $baseurl (the URL of the web stuff, i.e. if the main page is served at http://stream.frogbox.es and each other page is at the same directory level as the index, the baseurl would be "http://stream.frogbox.es"))
28 | - Ensure the MySQL server is accepting connections from the user specified in common.php and the user specified in common.php has the correct privileges to read from the defined users table
29 | - Configure the users table
30 | - The following schema are expected (but easily changed):
31 | - username VARCHAR(64)
32 | - email VARCHAR(64)
33 | - password VARCHAR(64)
34 | - idhash VARCHAR(64)
35 | - Other columns may be added as required
36 |
37 | # Python/Flask
38 | Requirements:
39 | - Nginx with RTMP module (https://github.com/arut/nginx-rtmp-module)
40 | - a PostgreSQL server
41 | - Flask, Flask API
42 | - psycopg2
43 |
44 | Server-side configuration:
45 | - Set nginx.conf as the live nginx conf (location of file depends on system)
46 | - Set the web root to an appropriate value
47 | - Set worker_processes to 1 to work around an issue in the nginx-rtmp module
48 | - Set the name of the rtmp server application block to whatever is desired (defaults to "stream")
49 | - Adjust the on_publish directive URL to reflect where the auth script is being served from (e.g. with the Flask development server, the URL would be http://localhost:5000/auth)
50 | - Set PostgreSQL-related variables in config.py (host, username, password, database, usertablename)
51 | - Ensure the PostgreSQL server is accepting connections from the user specified in common.py and the user specified in common.py has the correct privileges to read from the defined users table
52 | - Configure the users table
53 | - The following schema are expected (but easily changed):
54 | - username VARCHAR(64)
55 | - email VARCHAR(64)
56 | - password VARCHAR(64)
57 | - idhash VARCHAR(64)
58 | - Other columns may be added as required
59 |
60 | # Non-specific
61 |
62 | Broadcaster-side configuration (assuming OBS):
63 | - Under Broadcast Settings, set Custom as the streaming service
64 | - Set server to "rtmp://DOMAIN/stream?IDHASH" (assumes default rtmp server application block name of "stream")
65 | - This is referred to as "Stream RTMP URL" in the PHP web stuff
66 | - Set play path to USERNAME
67 |
68 | Player-side configuration:
69 | - The RTMP URL will be in the format "rtmp://DOMAIN/stream/USERNAME" (assumes default rtmp server application block name of "stream")
70 |
71 | Known issues:
72 | - OBS Studio (aka OBS MultiPlatform aka OBS Linux/Mac) versions <0.11.4 mangle variables defined in the server/stream URL when passing them to nginx, meaning that information sent that way (i.e. idhash) cannot be accessed by the authentication script
73 |
--------------------------------------------------------------------------------
/php/auth.php:
--------------------------------------------------------------------------------
1 | getMessage());
12 | die("Database error!");
13 | }
14 |
15 |
16 | if(empty($_GET['name']) || empty($_GET['swfurl']))
17 | {
18 | http_response_code(401);
19 | die();
20 | }
21 | else
22 | {
23 | if( !preg_match($pattern, $_GET['swfurl'], $matches) )
24 | {
25 | trigger_error("Validation error, swfurl did not match pattern.");
26 | http_response_code(401);
27 | die("Validation error");
28 | }
29 | }
30 |
31 | try
32 | {
33 | $sth = $dbh->prepare("SELECT idhash FROM :table WHERE username = :username");
34 | $sth->execute( array( 'table' => $usertablename, 'username' => $_GET['name'] ) );
35 | $res = $sth->fetch();
36 | } catch(PDOException $e)
37 | {
38 | trigger_error($e->getMessage());
39 | http_response_code(401);
40 | die("Query error");
41 | }
42 |
43 | $row = $res;
44 |
45 | if ($matches[1] == $row['idhash'])
46 | {
47 | http_response_code(200);
48 | die();
49 | } else {
50 | http_response_code(402);
51 | die();
52 | }
53 | ?>
54 |
--------------------------------------------------------------------------------
/php/changepass.php:
--------------------------------------------------------------------------------
1 | getMessage());
12 | die("Database error!");
13 | }
14 |
15 | if( empty( $_SESSION["username"] ) )
16 | {
17 | header("location: login.html");
18 | exit(); // some clients don't follow redirects, so the rest of the code will execute without an exit()
19 | }
20 |
21 | if ( empty( $_POST["oldpass"] ) || empty( $_POST["newpass"] ) )
22 | {
23 | echo "Empty required field";
24 | echo "
Go back";
25 | die();
26 | }
27 |
28 | $uname = $_SESSION["username"];
29 | $oldpass = hash('sha256', $_POST["oldpass"]);
30 | $newpass = hash('sha256', $_POST["newpass"]);
31 |
32 | try
33 | {
34 | $sth = $dbh->prepare( "UPDATE $usertablename SET password=:newPassword WHERE username=:uname AND password=:oldPassword" );
35 | $sth->execute( array( 'newPassword' => $newpass, "oldPassword" => $newpass, 'uname' => $uname ) );
36 | } catch(PDOException $e )
37 | {
38 | echo "Incorrect old password";
39 | echo "
Go back";
40 | trigger_error( $e->getMessage() );
41 | die();
42 | }
43 | header("Location: /profile.php");
44 | exit();
45 | ?>
46 |
--------------------------------------------------------------------------------
/php/common.php:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/php/login.html:
--------------------------------------------------------------------------------
1 |
2 |