Home > Back-end >  PhpMyadmin Token Authentification system
PhpMyadmin Token Authentification system

Time:02-24

I recently had the idea to create a login system to PhpMyAdmin with a token created from login credentials stored in a database. The url would look like this :

pma.example.com/index.php?token=WCxuFWj1QtGGapZhfSPS9Eo1Q9q666sR

The token contains 32 randomly generated alphanumeric characters.

So I have an API made in Python with Flask which communicates locally with PhpMyadmin and the different applications with which has two routes:

  1. 127.0.0.1:4040/api/v1/create_token [POST] This request has as JSON argument database_host_id for the MySQL host ID to connect defined in PhpMyAdmin configuration file, database_username which is as written the database user to connect and finally database_host which is the database password. The response have an token argument for the client to receive the new generated token. The JSON sent and received should look like this :
JSON received by the API :
{
  "database_host_id": 1,
  "database_username": "pma",
  "database_password: "4wAyS8",
}

JSON sent to the client:
{
  "token": "WCxuFWj1QtGGapZhfSPS9Eo1Q9q666sR"
}
  1. 127.0.0.1:4040/api/v1/get_database [POST] This request has a JSON argument token to know from which token to retrieve the connection information. So the response will have all this information along with database_host_id, database_username and database_password. The JSON sent and received should look like this :
JSON received by the API :
{
  "token": "WCxuFWj1QtGGapZhfSPS9Eo1Q9q666sR"
}

JSON sent to the client :
{
  "database_host_id": 1,
  "database_username": "pma",
  "database_password: "4wAyS8",
}

It's nice to have an API but if you don't use it, it's useless, so I searched in the source code of PhpMyAdmin how the authentication system worked.

I could understand that :

  • /libraries/common.inc.php This script would at runtime use what is called an AuthPlugin with this piece of code to then be used as a login interface by the various classes:
$auth_plugin = Plugins::getAuthPlugin();
$auth_plugin->authenticate();
  • I went to see what an AuthPlugin was by looking at the different functions associated with this class. I deduced that all the files in libraries/classes/Plugins/Auth were connection plugins and allowed to define the different connection methods for MySQL hosts that we define in the PhpMyAdmin configuration file with $cfg['Servers'][$i]['auth_type']. Knowing that the default authentication type was Cookie, I went to see the contents of the file librairies/classes/Plugins/Auth/AuthenticationCookie.php.

So now I had to modify the AuthenticationCookie.php script so that when token was contained in the URL, it could retrieve the information from the API and then use it to connect to the database associated with that token.

And that's where I get stuck because despite my PHP basics, I can't get what I'm doing to work. I could notice despite my attempts that when I retrieve the token from the URL, it was not at all what was defined, it was as if it was encrypted.

So here are my questions:

  1. Should I encrypt the password even though the API only communicates locally?
  2. Shouldn't I just use the SignOn connection method for my MySQL host?
  3. Is it safe to do what I am trying to do?

Information:

  • PhpMyAdmin version: 5.1.3

I would appreciate any kind of help in my reasoning to do or for any answers to my questions

CodePudding user response:

I finally ended up making a SignOn script associated with my server that gets the token from the URL, asks the API for the token information and then connects with it. It works perfectly.

<?php
/**
 * Single signon for phpMyAdmin
 *
 * This is just example how to use session based single signon with
 * phpMyAdmin, it is not intended to be perfect code and look, only
 * shows how you can integrate this functionality in your application.
 */

declare(strict_types=1);

/* Use cookies for session */

ini_set('session.use_cookies', 'true');
/* Change this to true if using phpMyAdmin over https */
$secure_cookie = false;
/* Need to have cookie visible from parent directory */
session_set_cookie_params(0, '/', '', $secure_cookie, true);
/* Create signon session */
$session_name = 'SignonSession';
session_name($session_name);
// Uncomment and change the following line to match your $cfg['SessionSavePath']
//session_save_path('/foobar');
@session_start();

/* Was data posted? */
if (isset($_REQUEST['token'])) {
    $data = array(
        'token'=> $_REQUEST['token']
    );
    $payload = json_encode($data);
    $curl = curl_init('http://127.0.0.1:4040/api/v1/get_database');
    curl_setopt($curl, CURLOPT_POST, true);
    curl_setopt($curl, CURLOPT_POSTFIELDS, $payload);
    curl_setopt($curl, CURLOPT_HTTPHEADER, array('Content-Type:application/json'));
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
    $response = curl_exec($curl);

    curl_close($curl);

    $response = json_decode($response, true);
    
    /* Store there credentials */
    $_SESSION['PMA_single_signon_user'] = $response->database_username;
    $_SESSION['PMA_single_signon_password'] = $response->database_password;
    $_SESSION['PMA_single_signon_host'] = $_POST['host'];
    $_SESSION['PMA_single_signon_port'] = $_POST['port'];
    /* Update another field of server configuration */
    $_SESSION['PMA_single_signon_cfgupdate'] = ['verbose' => 'Signon test'];
    $_SESSION['PMA_single_signon_HMAC_secret'] = hash('sha1', uniqid(strval(rand()), true));
    $id = session_id();
    /* Close that session */
    @session_write_close();
    /* Redirect to phpMyAdmin (should use absolute URL here!) */
    header('Location: ../index.php');
} else {
    /* Show simple form */
    header('Content-Type: text/html; charset=utf-8');

    echo '<?xml version="1.0" encoding="utf-8"?>' . "\n";
    echo '<!DOCTYPE HTML>
<html lang="en" dir="ltr">
<head>
<link rel="icon" href="../favicon.ico" type="image/x-icon">
<link rel="shortcut icon" href="../favicon.ico" type="image/x-icon">
<meta charset="utf-8">
<title>Loading...</title>
</head>
<body>';

    if (isset($_SESSION['PMA_single_signon_error_message'])) {
        echo '<p >';
        echo $_SESSION['PMA_single_signon_error_message'];
        echo '</p>';
    }

    echo '
<h1>Loading...</h1>
</body>
</html>';
}

I know it's not finished but I plan to improve it. So this is the solution I found.

  • Related