Browse Source

SSO and Auth backend work

causefx 8 years ago
parent
commit
73bb1cf065

+ 4 - 0
api/config/default.php

@@ -1,6 +1,10 @@
 <?php
 return array(
     'branch' => 'v2-develop',
+	'authType' => 'internal',
+    'authBackend' => '',
+	'authBackendHost' => '',
+	'authBackendDomain' => '',
     'logo' => 'plugins/images/organizr/logo-wide.png',
     'loginWallpaper' => '',
     'title' => 'Organizr V2',

+ 1 - 0
api/functions/api-functions.php

@@ -23,6 +23,7 @@ function login($array){
     		'database' => $GLOBALS['dbLocation'].$GLOBALS['dbName'],
     	]);
         $result = $database->fetch('SELECT * FROM users WHERE username = ? COLLATE NOCASE OR email = ? COLLATE NOCASE',$username,$username);
+		//DB User Verify
         if(password_verify($password, $result['password'])){
             if(createToken($result['username'],$result['email'],$result['image'],$result['group'],$result['group_id'],$GLOBALS['organizrHash'],$days)){
                 writeLoginLog($username, 'success');

+ 170 - 52
api/functions/auth-functions.php

@@ -1,66 +1,184 @@
 <?php
-
+function authRegister($username,$password,$defaults,$email){
+	$defaults = defaultUserGroup();
+	if(createUser($username,$password,$defaults,$email)){
+		writeLog('success', 'Registration Function - A User has registered', $username);
+		if(createToken($username,$email,gravatar($email),$defaults['group'],$defaults['group_id'],$GLOBALS['organizrHash'],1)){
+			writeLoginLog($username, 'success');
+			writeLog('success', 'Login Function - A User has logged in', $username);
+			return true;
+		}
+	}else{
+		writeLog('error', 'Registration Function - An error occured', $username);
+		return 'username taken';
+	}
+}
+function checkPlexUser($username){
+	if(!empty($GLOBALS['plexToken'])){
+		$url = 'https://plex.tv/pms/friends/all';
+		$headers = array(
+			'X-Plex-Token' => $GLOBALS['plexToken'],
+		);
+		$response = Requests::get($url, $headers);
+		if($response->success){
+			libxml_use_internal_errors(true);
+			$userXML = simplexml_load_string($response->body);
+			if (is_array($userXML) || is_object($userXML)) {
+				$usernameLower = strtolower($username);
+				foreach($userXML AS $child) {
+					if(isset($child['username']) && strtolower($child['username']) == $usernameLower || isset($child['email']) && strtolower($child['email']) == $usernameLower) {
+						return true;
+					}
+				}
+			}
+		}
+	}
+	return false;
+}
 function plugin_auth_plex($username, $password) {
-	// Quick out
-	$isAdmin = false;
-	if ((strtolower(PLEXUSERNAME) == strtolower($username)) && $password == PLEXPASSWORD) {
-			writeLog("success", "Admin: ".$username." authenticated as plex Admin");
-		$isAdmin = true;
+	$usernameLower = strtolower($username);
+	if(checkPlexUser($username)){
+		//Login User
+		$url = 'https://plex.tv/users/sign_in.json';
+		$headers = array(
+			'Accept'=> 'application/json',
+			'Content-Type' => 'application/x-www-form-urlencoded',
+			'X-Plex-Product' => 'Organizr',
+			'X-Plex-Version' => '2.0',
+			'X-Plex-Client-Identifier' => '01010101-10101010',
+		);
+		$data = array(
+			'user[login]' => $username,
+			'user[password]' => $password,
+		);
+		$response = Requests::post($url, $headers, $data);
+		if($response->success){
+			$json = json_decode($response->body, true);
+			if ((is_array($json) && isset($json['user']) && isset($json['user']['username'])) && strtolower($json['user']['username']) == $usernameLower || strtolower($json['user']['email']) == $usernameLower) {
+				//writeLog("success", $json['user']['username']." was logged into organizr using plex credentials");
+                return array(
+					'username' => $json['user']['username'],
+					'email' => $json['user']['email'],
+					'image' => $json['user']['thumb'],
+					'token' => $json['user']['authToken']
+				);
+			}
+		}
 	}
+	return false;
+}
+if (function_exists('ldap_connect')){
+	// Pass credentials to LDAP backend
+	function plugin_auth_ldap($username, $password) {
+		$ldapServers = explode(',',AUTHBACKENDHOST);
+		foreach($ldapServers as $key => $value) {
+			// Calculate parts
+			$digest = parse_url(trim($value));
+			$scheme = strtolower((isset($digest['scheme'])?$digest['scheme']:'ldap'));
+			$host = (isset($digest['host'])?$digest['host']:(isset($digest['path'])?$digest['path']:''));
+			$port = (isset($digest['port'])?$digest['port']:(strtolower($scheme)=='ldap'?389:636));
 
-	//Get User List
-	$userURL = 'https://plex.tv/pms/friends/all';
-	$userHeaders = array(
-		'Authorization' => 'Basic '.base64_encode(PLEXUSERNAME.':'.PLEXPASSWORD),
-	);
-	libxml_use_internal_errors(true);
-	$userXML = simplexml_load_string(curl_get($userURL, $userHeaders));
+			// Reassign
+			$ldapServers[$key] = $scheme.'://'.$host.':'.$port;
+		}
 
-	if (is_array($userXML) || is_object($userXML)) {
-		$isUser = false;
-		$usernameLower = strtolower($username);
-		foreach($userXML AS $child) {
-			if(isset($child['username']) && strtolower($child['username']) == $usernameLower || isset($child['email']) && strtolower($child['email']) == $usernameLower) {
-				$isUser = true;
- 				writeLog("success", $usernameLower." was found in plex friends list");
-				break;
+		// returns true or false
+		$ldap = ldap_connect(implode(' ',$ldapServers));
+		if(empty(AUTHBACKENDDOMAINFORMAT)){
+			if ($bind = ldap_bind($ldap, AUTHBACKENDDOMAIN.'\\'.$username, $password)) {
+				writeLog("success", "LDAP authentication success");
+				return true;
+			} else {
+				writeLog("error", "LDAP could not authenticate");
+				return false;
+			}
+		}else{
+			ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, 3);
+			ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0);
+			$bind = @ldap_bind($ldap, sprintf(AUTHBACKENDDOMAINFORMAT, $username), $password);
+			if ($bind) {
+				writeLog("success", "LDAP authentication success");
+				return true;
+			} else {
+				writeLog("error", "LDPA could not authenticate");
+				return false;
 			}
 		}
+  		writeLog("error", "LDAP could not authenticate");
+		return false;
+	}
+}else{
+	// Ldap Auth Missing Dependancy
+	function plugin_auth_ldap_disabled() {
+		return 'LDAP - Disabled (Dependancy: php-ldap missing!)';
+	}
+}
+
+// Pass credentials to FTP backend
+function plugin_auth_ftp($username, $password) {
+	// Calculate parts
+	$digest = parse_url(AUTHBACKENDHOST);
+	$scheme = strtolower((isset($digest['scheme'])?$digest['scheme']:(function_exists('ftp_ssl_connect')?'ftps':'ftp')));
+	$host = (isset($digest['host'])?$digest['host']:(isset($digest['path'])?$digest['path']:''));
+	$port = (isset($digest['port'])?$digest['port']:21);
+
+	// Determine Connection Type
+	if ($scheme == 'ftps') {
+		$conn_id = ftp_ssl_connect($host, $port, 20);
+	} elseif ($scheme == 'ftp') {
+		$conn_id = ftp_connect($host, $port, 20);
+	} else {
+		debug_out('Invalid FTP scheme. Use ftp or ftps');
+  		writeLog("error", "invalid FTP scheme");
+		return false;
+	}
+
+	// Check if valid FTP connection
+	if ($conn_id) {
+		// Attempt login
+		@$login_result = ftp_login($conn_id, $username, $password);
+		ftp_close($conn_id);
+
+		// Return Result
+		if ($login_result) {
+   			writeLog("success", "$username authenticated");
+			return true;
+		} else {
+   			writeLog("error", "$username could not authenticate");
+			return false;
+		}
+	} else {
+		return false;
+	}
+	return false;
+}
 
-		if ($isUser || $isAdmin) {
-			//Login User
-			$connectURL = 'https://plex.tv/users/sign_in.json';
+// Pass credentials to Emby Backend
+function plugin_auth_emby_local($username, $password) {
+	$embyAddress = qualifyURL(EMBYURL);
+
+	$headers = array(
+		'Authorization'=> 'MediaBrowser UserId="e8837bc1-ad67-520e-8cd2-f629e3155721", Client="None", Device="Organizr", DeviceId="xxx", Version="1.0.0.0"',
+		'Content-Type' => 'application/json',
+	);
+	$body = array(
+		'Username' => $username,
+		'Password' => sha1($password),
+		'PasswordMd5' => md5($password),
+	);
+
+	$response = post_router($embyAddress.'/Users/AuthenticateByName', $body, $headers);
+
+	if (isset($response['content'])) {
+		$json = json_decode($response['content'], true);
+		if (is_array($json) && isset($json['SessionInfo']) && isset($json['User']) && $json['User']['HasPassword'] == true) {
+			// Login Success - Now Logout Emby Session As We No Longer Need It
 			$headers = array(
-				'Accept'=> 'application/json',
-				'Content-Type' => 'application/x-www-form-urlencoded',
-				'X-Plex-Product' => 'Organizr',
-				'X-Plex-Version' => '1.0',
-				'X-Plex-Client-Identifier' => '01010101-10101010',
+				'X-Mediabrowser-Token' => $json['AccessToken'],
 			);
-			$body = array(
-				'user[login]' => $username,
-				'user[password]' => $password,
-			);
-			$result = curl_post($connectURL, $body, $headers);
-			if (isset($result['content'])) {
-				$json = json_decode($result['content'], true);
-				if ((is_array($json) && isset($json['user']) && isset($json['user']['username'])) && strtolower($json['user']['username']) == $usernameLower || strtolower($json['user']['email']) == $usernameLower) {
-					writeLog("success", $json['user']['username']." was logged into organizr using plex credentials");
-                    return array(
-						'email' => $json['user']['email'],
-						'image' => $json['user']['thumb'],
-						'token' => $json['user']['authToken'],
-						'type' => $isAdmin ? 'admin' : 'user',
-					);
-				}
-			}else{
-				writeLog("error", "error occured while trying to sign $username into plex");
-			}
-		}else{
-			writeLog("error", "$username is not an authorized PLEX user or entered invalid password");
+			$response = post_router($embyAddress.'/Sessions/Logout', array(), $headers);
+			return true;
 		}
-	}else{
-			writeLog("error", "error occured logging into plex might want to check curl.cainfo=/path/to/downloaded/cacert.pem in php.ini");
 	}
 	return false;
 }

+ 126 - 0
api/functions/organizr-functions.php

@@ -136,6 +136,79 @@ function organizrStatus(){
 	$status['php'] = phpversion();
     return $status;
 }
+function getSettingsMain(){
+	return array(
+		array(
+			'type' => 'select',
+			'name' => 'branch',
+			'label' => 'Branch',
+			'value' => $GLOBALS['branch'],
+			'options' => getBranches()
+		),
+		array(
+			'type' => 'button',
+			'label' => 'Force Install Branch',
+			'class' => 'popup-with-form getPlexTokenSSO',
+			'icon' => 'fa fa-paper-plane',
+			'text' => 'Retrieve'
+		),
+		array(
+			'type' => 'select',
+			'name' => 'authType',
+			'label' => 'Authentication Type',
+			'value' => $GLOBALS['authType'],
+			'options' => getAuthTypes()
+		),
+        array(
+			'type' => 'select',
+			'name' => 'authBackend',
+			'label' => 'Authentication Backend',
+			'value' => $GLOBALS['authBackend'],
+			'options' => getAuthBackends()
+		),
+        array(
+			'type' => 'input',
+			'name' => 'plexToken',
+            'class' => 'plexAuth',
+			'label' => 'Plex Token',
+			'value' => $GLOBALS['plexToken'],
+			'placeholder' => 'Use Get Token Button'
+		),
+		array(
+			'type' => 'button',
+			'label' => 'Get Plex Token',
+			'class' => 'popup-with-form getPlexTokenAuth plexAuth',
+			'icon' => 'fa fa-paper-plane',
+			'text' => 'Retrieve',
+			'href' => '#auth-plex-token-form',
+			'attr' => 'data-effect="mfp-3d-unfold"'
+		),
+		array(
+			'type' => 'input',
+			'name' => 'plexID',
+            'class' => 'plexAuth',
+			'label' => 'Plex Machine',
+			'value' => $GLOBALS['plexID'],
+			'placeholder' => 'Use Get Plex Machine Button'
+		),
+		array(
+			'type' => 'button',
+			'label' => 'Get Plex Machine',
+			'class' => 'popup-with-form getPlexMachineAuth plexAuth',
+			'icon' => 'fa fa-paper-plane',
+			'text' => 'Retrieve',
+			'href' => '#auth-plex-machine-form',
+			'attr' => 'data-effect="mfp-3d-unfold"'
+		),
+		/*array(
+			'type' => 'button',
+			'label' => 'Send Test',
+			'class' => 'phpmSendTestEmail',
+			'icon' => 'fa fa-paper-plane',
+			'text' => 'Send'
+		)*/
+	);
+}
 function getSSO(){
 	return array(
 		array(
@@ -446,6 +519,59 @@ function getThemes(){
 	}
 	return $themes;
 }
+function getBranches(){
+    return array(
+        array(
+            'name' => 'Develeop',
+            'value' => 'v2-develop'
+        ),
+        array(
+            'name' => 'Master',
+            'value' => 'v2-master'
+        )
+    );
+}
+function getAuthTypes(){
+    return array(
+        array(
+            'name' => 'Organizr DB',
+            'value' => 'internal'
+        ),
+        array(
+            'name' => 'Organizr DB + Backend',
+            'value' => 'both'
+        ),
+        array(
+            'name' => 'Backend Only',
+            'value' => 'external'
+        )
+    );
+}
+function getAuthBackends(){
+    $backendOptions = array();
+    $backendOptions[] = array(
+        'name' => 'Choose Backend',
+        'value' => false,
+        'disabled' => true
+    );
+    foreach (array_filter(get_defined_functions()['user'],function($v) { return strpos($v, 'plugin_auth_') === 0; }) as $value) {
+    	$name = str_replace('plugin_auth_','',$value);
+    	if (strpos($name, 'disabled') === false) {
+    		$backendOptions[] = array(
+    			'name' => ucwords(str_replace('_',' ',$name)),
+    			'value' => $name
+    		);
+    	} else {
+    		$backendOptions[] = array(
+    			'name' => $value(),
+    			'value' => 'none',
+    			'disabled' => true,
+    		);
+    	}
+    }
+    ksort($backendOptions);
+    return $backendOptions;
+}
 /*
 function sendEmail($email = null, $username = "Organizr User", $subject, $body, $cc = null, $bcc = null){
 	try {

+ 38 - 0
api/index.php

@@ -124,6 +124,25 @@ switch ($function) {
                 break;
         }
         break;
+	case 'v1_settings_settings_main':
+		switch ($method) {
+			case 'GET':
+				if(qualifyRequest(1)){
+					$result['status'] = 'success';
+					$result['statusText'] = 'success';
+					$result['data'] = $pageSettingsSettingsMain;
+				}else{
+					$result['status'] = 'error';
+					$result['statusText'] = 'API/Token invalid or not set';
+					$result['data'] = null;
+				}
+				break;
+			default:
+				$result['status'] = 'error';
+				$result['statusText'] = 'The function requested is not defined for method: '.$method;
+				break;
+		}
+			break;
     case 'v1_settings_customize_appearance':
         switch ($method) {
             case 'GET':
@@ -584,6 +603,25 @@ switch ($function) {
                 break;
         }
         break;
+    case 'v1_settings_main':
+        switch ($method) {
+            case 'GET':
+                if(qualifyRequest(1)){
+                    $result['status'] = 'success';
+                    $result['statusText'] = 'success';
+                    $result['data'] = getSettingsMain();
+                }else{
+                    $result['status'] = 'error';
+                    $result['statusText'] = 'API/Token invalid or not set';
+                    $result['data'] = null;
+                }
+                break;
+            default:
+                $result['status'] = 'error';
+                $result['statusText'] = 'The function requested is not defined for method: '.$method;
+                break;
+        }
+            break;
     case 'v1_user_edit':
         switch ($method) {
             case 'POST':

+ 17 - 0
api/pages/settings-settings-main.php

@@ -0,0 +1,17 @@
+<?php
+
+$pageSettingsSettingsMain = '
+<script>
+	buildSettingsMain();
+</script>
+<div class="panel bg-theme-dark panel-info">
+    <div class="panel-heading">
+		<span lang="en">Organizr Settings</span>
+	</div>
+    <div class="panel-wrapper collapse in" aria-expanded="true">
+        <div class="panel-body bg-theme-dark">
+            <form id="settings-main-form" class="form-horizontal" onsbumit="return false;"></form>
+        </div>
+    </div>
+</div>
+';

+ 1 - 1
api/pages/settings.php

@@ -111,7 +111,7 @@ $pageSettings = '
                         <ul class="nav customtab2 nav-tabs" role="tablist">
                             <li onclick="changeSettingsMenu(\'Settings::System Settings::About\')" role="presentation" class="active"><a href="#settings-settings-about" aria-controls="home" role="tab" data-toggle="tab" aria-expanded="true"><span class="visible-xs"><i class="ti-info-alt"></i></span><span class="hidden-xs" lang="en"> About</span></a>
                             </li>
-                            <li onclick="changeSettingsMenu(\'Settings::System Settings::Main\')" role="presentation" class=""><a href="#settings-settings-main" aria-controls="home" role="tab" data-toggle="tab" aria-expanded="false"><span class="visible-xs"><i class="ti-settings"></i></span><span class="hidden-xs" lang="en"> Main</span></a>
+                            <li onclick="changeSettingsMenu(\'Settings::System Settings::Main\');loadSettingsPage(\'api/?v1/settings/settings/main\',\'#settings-settings-main\',\'Main Settings\');" role="presentation" class=""><a href="#settings-settings-main" aria-controls="home" role="tab" data-toggle="tab" aria-expanded="false"><span class="visible-xs"><i class="ti-settings"></i></span><span class="hidden-xs" lang="en"> Main</span></a>
                             </li>
                             <li onclick="changeSettingsMenu(\'Settings::System Settings::SSO\');loadSettingsPage(\'api/?v1/settings/settings/sso\',\'#settings-settings-sso\',\'SSO\');" role="presentation" class=""><a href="#settings-settings-sso" aria-controls="home" role="tab" data-toggle="tab" aria-expanded="false"><span class="visible-xs"><i class="ti-receipt"></i></span><span class="hidden-xs" lang="en"> Single Sign-On</span></a>
                             </li>

+ 34 - 1
js/custom.js

@@ -1116,7 +1116,40 @@ $(document).on('change asColorPicker::close', '#sso-form :input', function(e) {
             $('#sso-form :input').prop('disabled', null);
             input.emulateTab();
         },
-        1500
+        2000
+    );
+});
+// MAIN SETTINGS PAGE
+$(document).on('change asColorPicker::close', '#settings-main-form :input', function(e) {
+    var input = $(this);
+    switch ($(this).attr('type')) {
+        case 'switch':
+        case 'checkbox':
+            var value = $(this).prop("checked") ? true : false;
+            break;
+        default:
+            var value = $(this).val();
+    }
+	var post = {
+        api:'api/?v1/update/config',
+        name:$(this).attr("name"),
+        type:$(this).attr("data-type"),
+        value:value,
+        messageTitle:'',
+        messageBody:'Updated Value for '+$(this).parent().parent().find('label').text(),
+        error:'Organizr Function: API Connection Failed'
+    };
+	var callbacks = $.Callbacks();
+    //callbacks.add( buildCustomizeAppearance );
+    settingsAPI(post,callbacks);
+    //disable button then renable
+    $('#settings-main-form :input').prop('disabled', 'true');
+    setTimeout(
+        function(){
+            $('#settings-main-form :input').prop('disabled', null);
+            input.emulateTab();
+        },
+        2000
     );
 });
 $(document).on("click", ".getSSOPlexToken", function () {

+ 46 - 1
js/functions.js

@@ -491,7 +491,8 @@ function selectOptions(options, active){
 	var selectOptions = '';
 	$.each(options, function(i,v) {
 		var selected = (active.toString() == v.value) ? 'selected' : '';
-		selectOptions += '<option '+selected+' value="'+v.value+'">'+v.name+'</option>';
+		var disabled = (v.disabled) ? ' disabled' : '';
+		selectOptions += '<option '+selected+disabled+' value="'+v.value+'">'+v.name+'</option>';
 	});
 	return selectOptions;
 }
@@ -695,6 +696,38 @@ function buildSSOItem(array){
     }
     return ssoItems;
 }
+function buildSettingsMainItem(array){
+    if (Array.isArray(array)) {
+		var count = 0;
+        var preRow = `
+            <!-- FORM GROUP -->
+            <h3 class="box-title" lang="en">Main Settings</h3>
+            <hr class="m-t-0 m-b-40">
+            <div class="row">
+        `;
+        var settingsItems = preRow;
+        $.each(array, function(i,v) {
+			count++;
+
+			if(count%2 !== 0 ){ settingsItems += '<div class="row start">'; };
+            settingsItems += `
+                <!-- INPUT BOX -->
+                <div class="col-md-6 p-b-10">
+                    <div class="form-group">
+                        <label class="control-label col-md-3" lang="en">`+v.label+`</label>
+                        <div class="col-md-9">
+                            `+buildFormItem(v)+`
+                        </div>
+                    </div>
+                </div>
+                <!--/ INPUT BOX -->
+            `;
+			if(count%2 == 0 ){ settingsItems += '</div><!--end-->'; };
+        });
+        settingsItems += '</div>';
+    }
+    return settingsItems;
+}
 function buildImageManagerViewItem(array){
 	var imageListing = '';
 	if (Array.isArray(array)) {
@@ -757,6 +790,18 @@ function buildSSO(){
 	});
 	ajaxloader();
 }
+function buildSettingsMain(){
+	ajaxloader(".content-wrap","in");
+	organizrAPI('GET','api/?v1/settings/main').success(function(data) {
+		var response = JSON.parse(data);
+		console.log(response)
+		$('#settings-main-form').html(buildSettingsMainItem(response.data));
+		;
+	}).fail(function(xhr) {
+		console.error("Organizr Function: API Connection Failed");
+	});
+	ajaxloader();
+}
 function buildUserManagement(){
 	ajaxloader(".content-wrap","in");
 	organizrAPI('GET','api/?v1/user/list').success(function(data) {