auth-functions.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  1. <?php
  2. trait AuthFunctions
  3. {
  4. public function testing()
  5. {
  6. return 'wasssup';
  7. }
  8. public function checkPlexToken($token = '')
  9. {
  10. try {
  11. if (($token !== '')) {
  12. $url = 'https://plex.tv/users/account.json';
  13. $headers = array(
  14. 'X-Plex-Token' => $token,
  15. 'Content-Type' => 'application/json',
  16. 'Accept' => 'application/json'
  17. );
  18. $response = Requests::get($url, $headers);
  19. if ($response->success) {
  20. return json_decode($response->body, true);
  21. }
  22. } else {
  23. return false;
  24. }
  25. } catch (Requests_Exception $e) {
  26. $this->writeLog('success', 'Plex Token Check Function - Error: ' . $e->getMessage(), SYSTEM);
  27. }
  28. return false;
  29. }
  30. public function checkPlexUser($username)
  31. {
  32. try {
  33. if (!empty($this->config['plexToken'])) {
  34. $url = 'https://plex.tv/api/users';
  35. $headers = array(
  36. 'X-Plex-Token' => $this->config['plexToken'],
  37. );
  38. $response = Requests::get($url, $headers);
  39. if ($response->success) {
  40. libxml_use_internal_errors(true);
  41. $userXML = simplexml_load_string($response->body);
  42. if (is_array($userXML) || is_object($userXML)) {
  43. $usernameLower = strtolower($username);
  44. foreach ($userXML as $child) {
  45. if (isset($child['username']) && strtolower($child['username']) == $usernameLower || isset($child['email']) && strtolower($child['email']) == $usernameLower) {
  46. $this->writeLog('success', 'Plex User Check - Found User on Friends List', $username);
  47. $machineMatches = false;
  48. if ($this->config['plexStrictFriends']) {
  49. foreach ($child->Server as $server) {
  50. if ((string)$server['machineIdentifier'] == $this->config['plexID']) {
  51. $machineMatches = true;
  52. }
  53. }
  54. } else {
  55. $machineMatches = true;
  56. }
  57. if ($machineMatches) {
  58. $this->writeLog('success', 'Plex User Check - User Approved for Login', $username);
  59. return true;
  60. } else {
  61. $this->writeLog('error', 'Plex User Check - User not Approved User', $username);
  62. }
  63. }
  64. }
  65. }
  66. }
  67. }
  68. return false;
  69. } catch (Requests_Exception $e) {
  70. $this->writeLog('error', 'Plex User Check Function - Error: ' . $e->getMessage(), $username);
  71. }
  72. return false;
  73. }
  74. public function plugin_auth_plex($username, $password)
  75. {
  76. try {
  77. $usernameLower = strtolower($username);
  78. //Login User
  79. $url = 'https://plex.tv/users/sign_in.json';
  80. $headers = array(
  81. 'Accept' => 'application/json',
  82. 'Content-Type' => 'application/x-www-form-urlencoded',
  83. 'X-Plex-Product' => 'Organizr',
  84. 'X-Plex-Version' => '2.0',
  85. 'X-Plex-Client-Identifier' => $this->config['uuid'],
  86. );
  87. $data = array(
  88. 'user[login]' => $username,
  89. 'user[password]' => $password,
  90. );
  91. $options = array('timeout' => 30);
  92. $response = Requests::post($url, $headers, $data, $options);
  93. if ($response->success) {
  94. $json = json_decode($response->body, true);
  95. if ((is_array($json) && isset($json['user']) && isset($json['user']['username'])) && strtolower($json['user']['username']) == $usernameLower || strtolower($json['user']['email']) == $usernameLower) {
  96. if ((!empty($this->config['plexAdmin']) && (strtolower($this->config['plexAdmin']) == strtolower($json['user']['username']) || strtolower($this->config['plexAdmin']) == strtolower($json['user']['email']))) || $this->checkPlexUser($json['user']['username'])) {
  97. return array(
  98. 'username' => $json['user']['username'],
  99. 'email' => $json['user']['email'],
  100. 'image' => $json['user']['thumb'],
  101. 'token' => $json['user']['authToken']
  102. );
  103. }
  104. }
  105. }
  106. return false;
  107. } catch (Requests_Exception $e) {
  108. $this->writeLog('success', 'Plex Auth Function - Error: ' . $e->getMessage(), $username);
  109. }
  110. return false;
  111. }
  112. // Pass credentials to LDAP backend
  113. public function plugin_auth_ldap($username, $password)
  114. {
  115. if (!empty($this->config['authBaseDN']) && !empty($this->config['authBackendHost'])) {
  116. $ad = new \Adldap\Adldap();
  117. // Create a configuration array.
  118. $ldapServers = explode(',', $this->config['authBackendHost']);
  119. $i = 0;
  120. foreach ($ldapServers as $key => $value) {
  121. // Calculate parts
  122. $digest = parse_url(trim($value));
  123. $scheme = strtolower((isset($digest['scheme']) ? $digest['scheme'] : 'ldap'));
  124. $host = (isset($digest['host']) ? $digest['host'] : (isset($digest['path']) ? $digest['path'] : ''));
  125. $port = (isset($digest['port']) ? $digest['port'] : (strtolower($scheme) == 'ldap' ? 389 : 636));
  126. // Reassign
  127. $ldapHosts[] = $host;
  128. $ldapServersNew[$key] = $scheme . '://' . $host . ':' . $port; // May use this later
  129. if ($i == 0) {
  130. $ldapPort = $port;
  131. }
  132. $i++;
  133. }
  134. $config = [
  135. // Mandatory Configuration Options
  136. 'hosts' => $ldapHosts,
  137. 'base_dn' => $this->config['authBaseDN'],
  138. 'username' => (empty($this->config['ldapBindUsername'])) ? null : $this->config['ldapBindUsername'],
  139. 'password' => (empty($this->config['ldapBindPassword'])) ? null : $this->decrypt($this->config['ldapBindPassword']),
  140. // Optional Configuration Options
  141. 'schema' => (($GLOBALS['ldapType'] == '1') ? Adldap\Schemas\ActiveDirectory::class : (($GLOBALS['ldapType'] == '2') ? Adldap\Schemas\OpenLDAP::class : Adldap\Schemas\FreeIPA::class)),
  142. 'account_prefix' => (empty($this->config['authBackendHostPrefix'])) ? null : $this->config['authBackendHostPrefix'],
  143. 'account_suffix' => (empty($this->config['authBackendHostSuffix'])) ? null : $this->config['authBackendHostSuffix'],
  144. 'port' => $ldapPort,
  145. 'follow_referrals' => false,
  146. 'use_ssl' => $this->config['ldapSSL'],
  147. 'use_tls' => $this->config['ldapTLS'],
  148. 'version' => 3,
  149. 'timeout' => 5,
  150. // Custom LDAP Options
  151. 'custom_options' => [
  152. // See: http://php.net/ldap_set_option
  153. //LDAP_OPT_X_TLS_REQUIRE_CERT => LDAP_OPT_X_TLS_HARD
  154. ]
  155. ];
  156. // Add a connection provider to Adldap.
  157. $ad->addProvider($config);
  158. try {
  159. // If a successful connection is made to your server, the provider will be returned.
  160. $provider = $ad->connect();
  161. //prettyPrint($provider);
  162. if ($provider->auth()->attempt($username, $password)) {
  163. try {
  164. // Try and get email from LDAP server
  165. $accountDN = ((empty($this->config['authBackendHostPrefix'])) ? null : $this->config['authBackendHostPrefix']) . $username . ((empty($this->config['authBackendHostSuffix'])) ? null : $this->config['authBackendHostSuffix']);
  166. $record = $provider->search()->findByDnOrFail($accountDN);
  167. $email = $record->getFirstAttribute('mail');
  168. } catch (Adldap\Models\ModelNotFoundException $e) {
  169. // Record wasn't found!
  170. $email = null;
  171. }
  172. // Passed.
  173. return array(
  174. 'email' => $email
  175. );
  176. } else {
  177. // Failed.
  178. return false;
  179. }
  180. } catch (\Adldap\Auth\BindException $e) {
  181. $this->writeLog('error', 'LDAP Function - Error: ' . $e->getMessage(), $username);
  182. // There was an issue binding / connecting to the server.
  183. } catch (Adldap\Auth\UsernameRequiredException $e) {
  184. $this->writeLog('error', 'LDAP Function - Error: ' . $e->getMessage(), $username);
  185. // The user didn't supply a username.
  186. } catch (Adldap\Auth\PasswordRequiredException $e) {
  187. $this->writeLog('error', 'LDAP Function - Error: ' . $e->getMessage(), $username);
  188. // The user didn't supply a password.
  189. }
  190. }
  191. return false;
  192. }
  193. // Ldap Auth Missing Dependency
  194. public function plugin_auth_ldap_disabled()
  195. {
  196. return 'LDAP - Disabled (Dependency: php-ldap missing!)';
  197. }
  198. // Pass credentials to FTP backend
  199. public function plugin_auth_ftp($username, $password)
  200. {
  201. // Calculate parts
  202. $digest = parse_url($this->config['authBackendHost']);
  203. $scheme = strtolower((isset($digest['scheme']) ? $digest['scheme'] : (function_exists('ftp_ssl_connect') ? 'ftps' : 'ftp')));
  204. $host = (isset($digest['host']) ? $digest['host'] : (isset($digest['path']) ? $digest['path'] : ''));
  205. $port = (isset($digest['port']) ? $digest['port'] : 21);
  206. // Determine Connection Type
  207. if ($scheme == 'ftps') {
  208. $conn_id = ftp_ssl_connect($host, $port, 20);
  209. } elseif ($scheme == 'ftp') {
  210. $conn_id = ftp_connect($host, $port, 20);
  211. } else {
  212. return false;
  213. }
  214. // Check if valid FTP connection
  215. if ($conn_id) {
  216. // Attempt login
  217. @$login_result = ftp_login($conn_id, $username, $password);
  218. ftp_close($conn_id);
  219. // Return Result
  220. if ($login_result) {
  221. return true;
  222. } else {
  223. return false;
  224. }
  225. } else {
  226. return false;
  227. }
  228. }
  229. // Pass credentials to Emby Backend
  230. public function plugin_auth_emby_local($username, $password)
  231. {
  232. try {
  233. $url = $this->qualifyURL($this->config['embyURL']) . '/Users/AuthenticateByName';
  234. $headers = array(
  235. 'Authorization' => 'Emby UserId="e8837bc1-ad67-520e-8cd2-f629e3155721", Client="None", Device="Organizr", DeviceId="xxx", Version="1.0.0.0"',
  236. 'Content-Type' => 'application/json',
  237. );
  238. $data = array(
  239. 'Username' => $username,
  240. 'pw' => $password,
  241. 'Password' => sha1($password),
  242. 'PasswordMd5' => md5($password),
  243. );
  244. $response = Requests::post($url, $headers, json_encode($data));
  245. if ($response->success) {
  246. $json = json_decode($response->body, true);
  247. if (is_array($json) && isset($json['SessionInfo']) && isset($json['User']) && $json['User']['HasPassword'] == true) {
  248. // Login Success - Now Logout Emby Session As We No Longer Need It
  249. $headers = array(
  250. 'X-Emby-Token' => $json['AccessToken'],
  251. 'X-Mediabrowser-Token' => $json['AccessToken'],
  252. );
  253. $response = Requests::post($this->qualifyURL($this->config['embyURL']) . '/Sessions/Logout', $headers, array());
  254. if ($response->success) {
  255. return true;
  256. }
  257. }
  258. }
  259. return false;
  260. } catch (Requests_Exception $e) {
  261. $this->writeLog('error', 'Emby Local Auth Function - Error: ' . $e->getMessage(), $username);
  262. }
  263. return false;
  264. }
  265. // Pass credentials to JellyFin Backend
  266. public function plugin_auth_jellyfin($username, $password)
  267. {
  268. try {
  269. $url = $this->qualifyURL($this->config['embyURL']) . '/Users/authenticatebyname';
  270. $headers = array(
  271. 'X-Emby-Authorization' => 'MediaBrowser Client="Organizr Auth", Device="Organizr", DeviceId="orgv2", Version="2.0"',
  272. 'Content-Type' => 'application/json',
  273. );
  274. $data = array(
  275. 'Username' => $username,
  276. 'Pw' => $password
  277. );
  278. $response = Requests::post($url, $headers, json_encode($data));
  279. if ($response->success) {
  280. $json = json_decode($response->body, true);
  281. if (is_array($json) && isset($json['SessionInfo']) && isset($json['User']) && $json['User']['HasPassword'] == true) {
  282. $this->writeLog('success', 'JellyFin Auth Function - Found User and Logged In', $username);
  283. // Login Success - Now Logout JellyFin Session As We No Longer Need It
  284. $headers = array(
  285. 'X-Emby-Authorization' => 'MediaBrowser Client="Organizr Auth", Device="Organizr", DeviceId="orgv2", Version="2.0", Token="' . $json['AccessToken'] . '"',
  286. 'Content-Type' => 'application/json',
  287. );
  288. $response = Requests::post($this->qualifyURL($this->config['embyURL']) . '/Sessions/Logout', $headers, array());
  289. if ($response->success) {
  290. return true;
  291. }
  292. }
  293. }
  294. return false;
  295. } catch (Requests_Exception $e) {
  296. $this->writeLog('error', 'JellyFin Auth Function - Error: ' . $e->getMessage(), $username);
  297. }
  298. return false;
  299. }
  300. // Authenticate against emby connect
  301. public function plugin_auth_emby_connect($username, $password)
  302. {
  303. // Emby disabled EmbyConnect on their API
  304. // https://github.com/MediaBrowser/Emby/issues/3553
  305. //return plugin_auth_emby_local($username, $password);
  306. try {
  307. // Get A User
  308. $connectUserName = '';
  309. $url = $this->qualifyURL($this->config['embyURL']) . '/Users?api_key=' . $this->config['embyToken'];
  310. $response = Requests::get($url);
  311. if ($response->success) {
  312. $json = json_decode($response->body, true);
  313. if (is_array($json)) {
  314. foreach ($json as $key => $value) { // Scan for this user
  315. if (isset($value['ConnectUserName']) && isset($value['ConnectLinkType'])) { // Qualify as connect account
  316. if (strtolower($value['ConnectUserName']) == $username || strtolower($value['Name']) == $username) {
  317. $connectUserName = $value['ConnectUserName'];
  318. $this->writeLog('success', 'Emby Connect Auth Function - Found User', $username);
  319. break;
  320. }
  321. }
  322. }
  323. if ($connectUserName) {
  324. $this->writeLog('success', 'Emby Connect Auth Function - Attempting to Login with Emby ID: ' . $connectUserName, $username);
  325. $connectURL = 'https://connect.emby.media/service/user/authenticate';
  326. $headers = array(
  327. 'Accept' => 'application/json',
  328. 'X-Application' => 'Organizr/2.0'
  329. );
  330. $data = array(
  331. 'nameOrEmail' => $username,
  332. 'rawpw' => $password,
  333. );
  334. $response = Requests::post($connectURL, $headers, $data);
  335. if ($response->success) {
  336. $json = json_decode($response->body, true);
  337. if (is_array($json) && isset($json['AccessToken']) && isset($json['User']) && $json['User']['Name'] == $connectUserName) {
  338. return array(
  339. 'email' => $json['User']['Email'],
  340. //'image' => $json['User']['ImageUrl'],
  341. );
  342. } else {
  343. $this->writeLog('error', 'Emby Connect Auth Function - Bad Response', $username);
  344. }
  345. } else {
  346. $this->writeLog('error', 'Emby Connect Auth Function - 401 From Emby Connect', $username);
  347. }
  348. }
  349. }
  350. }
  351. return false;
  352. } catch (Requests_Exception $e) {
  353. $this->writeLog('error', 'Emby Connect Auth Function - Error: ' . $e->getMessage(), $username);
  354. return false;
  355. }
  356. }
  357. // Authenticate Against Emby Local (first) and Emby Connect
  358. public function plugin_auth_emby_all($username, $password)
  359. {
  360. // Emby disabled EmbyConnect on their API
  361. // https://github.com/MediaBrowser/Emby/issues/3553
  362. $localResult = $this->plugin_auth_emby_local($username, $password);
  363. //return $localResult;
  364. if ($localResult) {
  365. return $localResult;
  366. } else {
  367. return $this->plugin_auth_emby_connect($username, $password);
  368. }
  369. }
  370. }