hestia-sso.php 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. <?php
  2. /* Hestia way to enable support for SSO to PHPmyAdmin */
  3. /* To install please run v-add-sys-pma-sso */
  4. /* Following keys will get replaced when calling v-add-sys-pma-sso */
  5. define("PHPMYADMIN_KEY", "%PHPMYADMIN_KEY%");
  6. define("API_HOST_NAME", "%API_HOST_NAME%");
  7. define("API_HESTIA_PORT", "%API_HESTIA_PORT%");
  8. define("API_KEY", "%API_KEY%");
  9. class Hestia_API {
  10. private $api_url;
  11. public function __construct() {
  12. $this->hostname = "https://" . API_HOST_NAME . ":" . API_HESTIA_PORT . "/api/";
  13. $this->key = API_KEY;
  14. $this->pma_key = PHPMYADMIN_KEY;
  15. }
  16. /* Creates curl request */
  17. public function request($postvars) {
  18. $postdata = http_build_query($postvars);
  19. $curl = curl_init();
  20. curl_setopt($curl, CURLOPT_URL, $this->hostname);
  21. curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
  22. curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
  23. curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
  24. curl_setopt($curl, CURLOPT_POST, true);
  25. curl_setopt($curl, CURLOPT_POSTFIELDS, $postdata);
  26. $answer = curl_exec($curl);
  27. return $answer;
  28. }
  29. /* Creates an new temp user in mysql */
  30. public function create_temp_user($database, $user, $host) {
  31. $post_request = [
  32. "hash" => $this->key,
  33. "returncode" => "no",
  34. "cmd" => "v-add-database-temp-user",
  35. "arg1" => $user,
  36. "arg2" => $database,
  37. "arg3" => "mysql",
  38. "arg4" => $host,
  39. ];
  40. $request = $this->request($post_request);
  41. $json = json_decode($request);
  42. if (json_last_error() == JSON_ERROR_NONE) {
  43. return $json;
  44. } else {
  45. trigger_error("Unable to connect over API please check api connection", E_USER_WARNING);
  46. return false;
  47. }
  48. }
  49. /* Delete an new temp user in mysql */
  50. public function delete_temp_user($database, $user, $dbuser, $host) {
  51. $post_request = [
  52. "hash" => $this->key,
  53. "returncode" => "yes",
  54. "cmd" => "v-delete-database-temp-user",
  55. "arg1" => $user,
  56. "arg2" => $database,
  57. "arg3" => $dbuser,
  58. "arg4" => "mysql",
  59. "arg5" => $host,
  60. ];
  61. $request = $this->request($post_request);
  62. if (is_numeric($request) && $request == 0) {
  63. return true;
  64. } else {
  65. return false;
  66. }
  67. }
  68. public function get_user_ip() {
  69. // Saving user IPs to the session for preventing session hijacking
  70. $user_combined_ip = [];
  71. if ($_SERVER["REMOTE_ADDR"] != $_SERVER["SERVER_ADDR"]) {
  72. $user_combined_ip[] = $_SERVER["REMOTE_ADDR"];
  73. }
  74. if (isset($_SERVER["HTTP_CLIENT_IP"])) {
  75. $user_combined_ip .= "|" . $_SERVER["HTTP_CLIENT_IP"];
  76. }
  77. if (isset($_SERVER["HTTP_X_FORWARDED_FOR"])) {
  78. if ($_SERVER["REMOTE_ADDR"] != $_SERVER["HTTP_X_FORWARDED_FOR"]) {
  79. $user_combined_ip[] = $_SERVER["HTTP_X_FORWARDED_FOR"];
  80. }
  81. }
  82. if (isset($_SERVER["HTTP_FORWARDED_FOR"])) {
  83. if ($_SERVER["REMOTE_ADDR"] != $_SERVER["HTTP_FORWARDED_FOR"]) {
  84. $user_combined_ip[] = $_SERVER["HTTP_FORWARDED_FOR"];
  85. }
  86. }
  87. if (isset($_SERVER["HTTP_X_FORWARDED"])) {
  88. if ($_SERVER["REMOTE_ADDR"] != $_SERVER["HTTP_X_FORWARDED"]) {
  89. $user_combined_ip[] = $_SERVER["HTTP_X_FORWARDED"];
  90. }
  91. }
  92. if (isset($_SERVER["HTTP_FORWARDED"])) {
  93. if ($_SERVER["REMOTE_ADDR"] != $_SERVER["HTTP_FORWARDED"]) {
  94. $user_combined_ip[] = "|" . $_SERVER["HTTP_FORWARDED"];
  95. }
  96. }
  97. if (isset($_SERVER["HTTP_CF_CONNECTING_IP"])) {
  98. if (!empty($_SERVER["HTTP_CF_CONNECTING_IP"])) {
  99. $user_combined_ip[] = $_SERVER["HTTP_CF_CONNECTING_IP"];
  100. }
  101. }
  102. return implode("|", $user_combined_ip);
  103. }
  104. }
  105. /* Need to have cookie visible from parent directory */
  106. session_set_cookie_params(0, "/", "", true, true);
  107. /* Create signon session */
  108. $session_name = "SignonSession";
  109. session_name($session_name);
  110. @session_start();
  111. function session_invalid() {
  112. global $session_name;
  113. //delete all current sessions
  114. session_destroy();
  115. setcookie($session_name, null, -1, "/");
  116. header("Location: " . dirname($_SERVER["PHP_SELF"]) . "/index.php");
  117. die();
  118. }
  119. $api = new Hestia_API();
  120. if (!empty($_GET)) {
  121. if (isset($_GET["logout"])) {
  122. $api->delete_temp_user(
  123. $_SESSION["HESTIA_sso_database"],
  124. $_SESSION["HESTIA_sso_user"],
  125. $_SESSION["PMA_single_signon_user"],
  126. $_SESSION["HESTIA_sso_host"],
  127. );
  128. //remove sessin
  129. session_invalid();
  130. header("Location: " . dirname($_SERVER["PHP_SELF"]) . "/index.php");
  131. die();
  132. } else {
  133. if (isset($_GET["user"]) && isset($_GET["hestia_token"])) {
  134. $database = $_GET["database"];
  135. $user = $_GET["user"];
  136. $host = "localhost";
  137. $token = $_GET["hestia_token"];
  138. if (is_numeric($_GET["exp"])) {
  139. $time = $_GET["exp"];
  140. } else {
  141. $time = 0;
  142. }
  143. if ($time + 60 > time()) {
  144. //note: Possible issues with cloudflare due to ip obfuscation
  145. $ip = $api->get_user_ip();
  146. if (!password_verify($database . $user . $ip . $time . PHPMYADMIN_KEY, $token)) {
  147. trigger_error(
  148. "Access denied: There is a security token mismatch " . $time,
  149. E_USER_WARNING,
  150. );
  151. session_invalid();
  152. die();
  153. session_invalid();
  154. } else {
  155. $id = session_id();
  156. //create a new temp user
  157. $data = $api->create_temp_user($database, $user, $host);
  158. if ($data) {
  159. $_SESSION["PMA_single_signon_user"] = $data->login->user;
  160. $_SESSION["PMA_single_signon_password"] = $data->login->password;
  161. $_SESSION["PMA_single_signon_host"] = $host;
  162. //save database / username to be used for sending logout notification.
  163. $_SESSION["HESTIA_sso_user"] = $user;
  164. $_SESSION["HESTIA_sso_database"] = $database;
  165. $_SESSION["HESTIA_sso_host"] = $host;
  166. @session_write_close();
  167. setcookie($session_name, $id, 0, "/");
  168. header("Location: " . dirname($_SERVER["PHP_SELF"]) . "/index.php");
  169. } else {
  170. session_invalid();
  171. }
  172. die();
  173. }
  174. } else {
  175. trigger_error(
  176. "Link has been expired: System time: " .
  177. time() .
  178. " / Time provided in link: " .
  179. $time,
  180. E_USER_WARNING,
  181. );
  182. session_invalid();
  183. die();
  184. }
  185. }
  186. }
  187. } else {
  188. session_invalid();
  189. die();
  190. }