N°1260 MySQL TLS connection : exception if the opened connection is not in TLS whereas TLS parameters were used to open it

SVN:trunk[5312]
This commit is contained in:
Pierre Goiffon
2018-02-08 14:21:58 +00:00
parent 5a2576bc29
commit b032299b05
3 changed files with 105 additions and 15 deletions

View File

@@ -29,7 +29,15 @@ require_once(APPROOT.'core/kpi.class.inc.php');
class MySQLException extends CoreException
{
public function __construct($sIssue, $aContext, $oException = null)
/**
* MySQLException constructor.
*
* @param string $sIssue
* @param array $aContext
* @param \Exception $oException
* @param \mysqli $oMysqli to use when working with a custom mysqli instance
*/
public function __construct($sIssue, $aContext, $oException = null, $oMysqli = null)
{
if ($oException != null)
{
@@ -37,6 +45,12 @@ class MySQLException extends CoreException
$this->code = $oException->getCode();
$aContext['mysql_error'] = $oException->getMessage();
}
else if ($oMysqli != null)
{
$aContext['mysql_errno'] = $oMysqli->errno;
$this->code = $oMysqli->errno;
$aContext['mysql_error'] = $oMysqli->error;
}
else
{
$aContext['mysql_errno'] = CMDBSource::GetErrNo();
@@ -47,10 +61,20 @@ class MySQLException extends CoreException
}
}
/**
* Class MySQLQueryHasNoResultException
*
* @since 2.5
*/
class MySQLQueryHasNoResultException extends MySQLException
{
}
/**
* Class MySQLHasGoneAwayException
*
* @since iTop 2.5
* @since 2.5
* @see itop bug 1195
* @see https://dev.mysql.com/doc/refman/5.7/en/gone-away.html
*/
@@ -151,7 +175,7 @@ class CMDBSource
self::$m_sDBSSLCipher = empty($sSSLCipher) ? null : $sSSLCipher;
self::$m_oMysqli = self::GetMysqliInstance($sServer, $sUser, $sPwd, $sSource, $sSSLKey, $sSSLCert, $sSSLCA,
$sSSLCaPath, $sSSLCipher);
$sSSLCaPath, $sSSLCipher, true);
}
/**
@@ -164,13 +188,14 @@ class CMDBSource
* @param string $sSSLCA
* @param string $sSSLCaPath
* @param string $sSSLCipher
* @param boolean $bCheckSslAfterConnection
*
* @return \mysqli
* @throws \MySQLException
*/
public static function GetMysqliInstance(
$sServer, $sUser, $sPwd, $sSource = '', $sSSLKey = null, $sSSLCert = null, $sSSLCA = null, $sSSLCaPath = null,
$sSSLCipher = null
$sSSLCipher = null, $bCheckSslAfterConnection = false
) {
$oMysqli = null;
@@ -204,6 +229,14 @@ class CMDBSource
array('host' => $sServer, 'user' => $sUser), $e);
}
if ($bCheckSslAfterConnection
&& self::IsDbConnectionUsingSsl($sSSLKey, $sSSLCert, $sSSLCA)
&& !self::IsOpenedDbConnectionUsingSsl($oMysqli))
{
throw new MySQLException("Connection to the database is not encrypted whereas it was opened using TLS parameters",
null, null, $oMysqli);
}
if (!empty($sSource))
{
try
@@ -277,6 +310,55 @@ class CMDBSource
return (!empty($sSSLKey) && !empty($sSSLCert) && !empty($sSSLCA));
}
/**
* <p>A DB connection can be opened transparently (no errors thrown) without being encrypted, whereas the TLS
* parameters were used.<br>
* This method can be called to ensure that the DB connection really uses TLS.
*
* <p>We're using this object connection : {@link self::$m_oMysqli}
*
* @param \mysqli $oMysqli
*
* @return boolean true if the connection was really established using TLS
* @throws \MySQLException
*
* @uses IsMySqlVarNonEmpty
*/
private static function IsOpenedDbConnectionUsingSsl($oMysqli)
{
if (self::$m_oMysqli == null)
{
self::$m_oMysqli = $oMysqli;
}
$bNonEmptySslVersionVar = self::IsMySqlVarNonEmpty('ssl_version');
$bNonEmptySslCipherVar = self::IsMySqlVarNonEmpty('ssl_cipher');
return ($bNonEmptySslVersionVar && $bNonEmptySslCipherVar);
}
/**
* @param $sVarName
*
* @return bool
* @throws \MySQLException
*
* @uses SHOW STATUS queries
*/
private static function IsMySqlVarNonEmpty($sVarName)
{
try
{
$sResult = self::QueryToScalarCol("SHOW SESSION STATUS LIKE '$sVarName'", 1);
}
catch (MySQLQueryHasNoResultException $e)
{
$sResult = null;
}
return (!empty($sResult));
}
public static function SetCharacterSet($sCharset = 'utf8', $sCollation = 'utf8_general_ci')
{
if (strlen($sCharset) > 0)
@@ -542,13 +624,13 @@ class CMDBSource
/**
* @param string $sSql
* @param int $iCol beginning at 0
*
* @return string[] first line of results
* @throws \MySQLException if query cannot be processed, or no result found
*
* @uses \mysqli_result->fetch_array
* @return string corresponding cell content on the first line
* @throws \MySQLException
* @throws \MySQLQueryHasNoResultException
*/
public static function QueryToScalar($sSql)
public static function QueryToScalar($sSql, $iCol = 0)
{
$oKPI = new ExecutionKPI();
try
@@ -565,20 +647,22 @@ class CMDBSource
{
throw new MySQLException('Failed to issue SQL query', array('query' => $sSql));
}
if ($aRow = $oResult->fetch_array(MYSQLI_BOTH))
{
$res = $aRow[0];
$res = $aRow[$iCol];
}
else
{
$oResult->free();
throw new MySQLException('Found no result for query', array('query' => $sSql));
throw new MySQLQueryHasNoResultException('Found no result for query', array('query' => $sSql));
}
$oResult->free();
return $res;
}
/**
* @param string $sSql
*
@@ -612,6 +696,13 @@ class CMDBSource
return $aData;
}
/**
* @param string $sSql
* @param int $col
*
* @return array
* @throws \MySQLException
*/
public static function QueryToCol($sSql, $col)
{
$aColumn = array();

View File

@@ -245,7 +245,7 @@ class iTopMutex
$sSSLCipher = $this->sDBSSLCipher;
$this->hDBLink = CMDBSource::GetMysqliInstance($sServer, $sUser, $sPwd, $sSource, $sSSLKey, $sSSLCert, $sSSLCA,
$sSSLCaPath, $sSSLCipher);
$sSSLCaPath, $sSSLCipher, false);
if (!$this->hDBLink)
{

View File

@@ -534,8 +534,7 @@ if (class_exists('ZipArchive')) // The setup must be able to start even if the "
try
{
$oMysqli = CMDBSource::GetMysqliInstance($sServer, $sUser, $sPwd, $sSource, $sSSLKey, $sSSLCert,
$sSSLCA, sSSLCaPath,
$sSSLCipher);
$sSSLCA, $sSSLCaPath, $sSSLCipher, false);
if ($oMysqli->connect_errno)
{