diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/SemanticScuttle/Model/User/SslClientCert.php | 148 | ||||
-rw-r--r-- | src/SemanticScuttle/Service/User.php | 86 | ||||
-rw-r--r-- | src/SemanticScuttle/Service/User/SslClientCert.php | 283 | ||||
-rw-r--r-- | src/SemanticScuttle/header.php | 1 |
4 files changed, 505 insertions, 13 deletions
diff --git a/src/SemanticScuttle/Model/User/SslClientCert.php b/src/SemanticScuttle/Model/User/SslClientCert.php new file mode 100644 index 0000000..383b601 --- /dev/null +++ b/src/SemanticScuttle/Model/User/SslClientCert.php @@ -0,0 +1,148 @@ +<?php +/** + * SemanticScuttle - your social bookmark manager. + * + * PHP version 5. + * + * @category Bookmarking + * @package SemanticScuttle + * @author Christian Weiske <cweiske@cweiske.de> + * @license AGPL http://www.gnu.org/licenses/agpl.html + * @link http://sourceforge.net/projects/semanticscuttle + */ + +/** + * SSL client certificate model. Represents one single client certificate + * + * @category Bookmarking + * @package SemanticScuttle + * @author Christian Weiske <cweiske@cweiske.de> + * @license AGPL http://www.gnu.org/licenses/agpl.html + * @link http://sourceforge.net/projects/semanticscuttle + */ +class SemanticScuttle_Model_User_SslClientCert +{ + public $id; + public $uId; + public $sslSerial; + public $sslClientIssuerDn; + public $sslName; + public $sslEmail; + + + + /** + * Creates and returns a new object and fills it with + * the passed values from the database. + * + * @param array $arCertRow Database row array + * + * @return SemanticScuttle_Model_User_SslClientCert + */ + public static function fromDb($arCertRow) + { + $cert = new self(); + foreach (get_object_vars($cert) as $variable => $dummy) { + if (isset($arCertRow[$variable])) { + $cert->$variable = $arCertRow[$variable]; + } + } + return $cert; + } + + + + /** + * Loads the user's/browser's client certificate information into + * an object and returns it. + * Expects that all information is available. + * Better check with + * SemanticScuttle_Service_User_SslClientCert::hasValidCert() before. + * + * @return SemanticScuttle_Model_User_SslClientCert + * + * @see SemanticScuttle_Service_User_SslClientCert::hasValidCert() + */ + public static function fromCurrentCert() + { + $cert = new self(); + $cert->sslSerial = $_SERVER['SSL_CLIENT_M_SERIAL']; + $cert->sslClientIssuerDn = $_SERVER['SSL_CLIENT_I_DN']; + $cert->sslName = $_SERVER['SSL_CLIENT_S_DN_CN']; + $cert->sslEmail = $_SERVER['SSL_CLIENT_S_DN_Email']; + return $cert; + } + + + + /** + * Tells you if this certificate is the one the user is currently browsing + * with. + * + * @return boolean True if this certificate is the current browser's + */ + public function isCurrent() + { + if (!isset($_SERVER['SSL_CLIENT_M_SERIAL']) + || !isset($_SERVER['SSL_CLIENT_I_DN']) + ) { + return false; + } + + return $this->sslSerial == $_SERVER['SSL_CLIENT_M_SERIAL'] + && $this->sslClientIssuerDn == $_SERVER['SSL_CLIENT_I_DN']; + } + + + + /** + * Checks if this certificate is registered (exists) in the certificate + * array + * + * @param array $arCertificates Array of certificate objects + * + * @return boolean True or false + */ + public function isRegistered($arCertificates) + { + foreach ($arCertificates as $cert) { + if ($cert->equals($this)) { + return true; + } + } + return false; + } + + + + /** + * Deletes this certificate from database + * + * @return boolean True if all went well, false if not + */ + public function delete() + { + $ok = SemanticScuttle_Service_Factory::get('User_SslClientCert') + ->delete($this); + if ($ok) { + $this->id = null; + } + return $ok; + } + + + + /** + * Compares this certificate with the given one. + * + * @param SemanticScuttle_Service_Factory $cert Another user certificate + * + * @return boolean True if both match. + */ + public function equals(SemanticScuttle_Model_User_SslClientCert $cert) + { + return $this->sslSerial == $cert->sslSerial + && $this->sslClientIssuerDn == $cert->sslClientIssuerDn; + } +} +?>
\ No newline at end of file diff --git a/src/SemanticScuttle/Service/User.php b/src/SemanticScuttle/Service/User.php index 072ce85..09a2cb1 100644 --- a/src/SemanticScuttle/Service/User.php +++ b/src/SemanticScuttle/Service/User.php @@ -175,15 +175,30 @@ class SemanticScuttle_Service_User extends SemanticScuttle_DbService return $password; } - function _updateuser($uId, $fieldname, $value) { + /** + * Updates a single field in the user's database row + * + * @param integer $uId ID of the user + * @param string $fieldname Name of table column to change + * @param string $value New value + * + * @return boolean True if all was well, false if not + */ + public function _updateuser($uId, $fieldname, $value) + { $updates = array ($fieldname => $value); - $sql = 'UPDATE '. $this->getTableName() .' SET '. $this->db->sql_build_array('UPDATE', $updates) .' WHERE '. $this->getFieldName('primary') .'='. intval($uId); + $sql = 'UPDATE '. $this->getTableName() + . ' SET '. $this->db->sql_build_array('UPDATE', $updates) + . ' WHERE '. $this->getFieldName('primary') . '=' . intval($uId); // Execute the statement. $this->db->sql_transaction('begin'); - if (!($dbresult = & $this->db->sql_query($sql))) { + if (!($dbresult = $this->db->sql_query($sql))) { $this->db->sql_transaction('rollback'); - message_die(GENERAL_ERROR, 'Could not update user', '', __LINE__, __FILE__, $sql, $this->db); + message_die( + GENERAL_ERROR, 'Could not update user', '', + __LINE__, __FILE__, $sql, $this->db + ); return false; } $this->db->sql_transaction('commit'); @@ -406,6 +421,15 @@ class SemanticScuttle_Service_User extends SemanticScuttle_DbService return $this->currentuserId; } } + + $ssls = SemanticScuttle_Service_Factory::get('User_SslClientCert'); + if ($ssls->hasValidCert()) { + $id = $ssls->getUserIdFromCert(); + if ($id !== false) { + $this->setCurrentUserId($id); + return (int)$_SESSION[$this->getSessionKey()]; + } + } return false; } @@ -660,23 +684,57 @@ class SemanticScuttle_Service_User extends SemanticScuttle_DbService return $uId; } - function updateUser($uId, $password, $name, $email, $homepage, $uContent) { - if (!is_numeric($uId)) - return false; + /** + * Updates the given user + * + * @param integer $uId ID of user to change + * @param string $password Password to use + * @param string $name Realname to use + * @param string $email Email to use + * @param string $homepage User's homepage + * @param string $uContent User note + * + * @return boolean True when all is well, false if not + */ + public function updateUser( + $uId, $password, $name, $email, $homepage, $uContent + ) { + if (!is_numeric($uId)) { + return false; + } // Set up the SQL UPDATE statement. $moddatetime = gmdate('Y-m-d H:i:s', time()); - if ($password == '') - $updates = array ('uModified' => $moddatetime, 'name' => $name, 'email' => $email, 'homepage' => $homepage, 'uContent' => $uContent); - else - $updates = array ('uModified' => $moddatetime, 'password' => $this->sanitisePassword($password), 'name' => $name, 'email' => $email, 'homepage' => $homepage, 'uContent' => $uContent); - $sql = 'UPDATE '. $this->getTableName() .' SET '. $this->db->sql_build_array('UPDATE', $updates) .' WHERE '. $this->getFieldName('primary') .'='. intval($uId); + if ($password == '') { + $updates = array( + 'uModified' => $moddatetime, + 'name' => $name, + 'email' => $email, + 'homepage' => $homepage, + 'uContent' => $uContent + ); + } else { + $updates = array( + 'uModified' => $moddatetime, + 'password' => $this->sanitisePassword($password), + 'name' => $name, + 'email' => $email, + 'homepage' => $homepage, + 'uContent' => $uContent + ); + } + $sql = 'UPDATE '. $this->getTableName() + . ' SET '. $this->db->sql_build_array('UPDATE', $updates) + . ' WHERE '. $this->getFieldName('primary') . '=' . intval($uId); // Execute the statement. $this->db->sql_transaction('begin'); if (!($dbresult = & $this->db->sql_query($sql))) { $this->db->sql_transaction('rollback'); - message_die(GENERAL_ERROR, 'Could not update user', '', __LINE__, __FILE__, $sql, $this->db); + message_die( + GENERAL_ERROR, 'Could not update user', '', + __LINE__, __FILE__, $sql, $this->db + ); return false; } $this->db->sql_transaction('commit'); @@ -685,6 +743,8 @@ class SemanticScuttle_Service_User extends SemanticScuttle_DbService return true; } + + function getAllUsers ( ) { $query = 'SELECT * FROM '. $this->getTableName(); diff --git a/src/SemanticScuttle/Service/User/SslClientCert.php b/src/SemanticScuttle/Service/User/SslClientCert.php new file mode 100644 index 0000000..a6d43be --- /dev/null +++ b/src/SemanticScuttle/Service/User/SslClientCert.php @@ -0,0 +1,283 @@ +<?php +/** + * SemanticScuttle - your social bookmark manager. + * + * PHP version 5. + * + * @category Bookmarking + * @package SemanticScuttle + * @author Christian Weiske <cweiske@cweiske.de> + * @license AGPL http://www.gnu.org/licenses/agpl.html + * @link http://sourceforge.net/projects/semanticscuttle + */ + +/** + * SemanticScuttle SSL client certificate management service + * + * @category Bookmarking + * @package SemanticScuttle + * @author Christian Weiske <cweiske@cweiske.de> + * @license AGPL http://www.gnu.org/licenses/agpl.html + * @link http://sourceforge.net/projects/semanticscuttle + */ +class SemanticScuttle_Service_User_SslClientCert extends SemanticScuttle_DbService +{ + /** + * Creates a new instance, sets database variable and table name. + * + * @param sql_db $db Database object + */ + protected function __construct($db) + { + $this->db = $db; + $this->tablename = $GLOBALS['tableprefix'] .'users_sslclientcerts'; + } + + /** + * Returns the single service instance + * + * @param sql_db $db Database object + * + * @return SemanticScuttle_Service_User + */ + public static function getInstance($db) + { + static $instance; + if (!isset($instance)) { + $instance = new self($db); + } + return $instance; + } + + /** + * Determines if the browser provided a valid SSL client certificate + * + * @return boolean True if the client cert is there and is valid + */ + public function hasValidCert() + { + if (!isset($_SERVER['SSL_CLIENT_M_SERIAL']) + || !isset($_SERVER['SSL_CLIENT_V_END']) + || !isset($_SERVER['SSL_CLIENT_VERIFY']) + || $_SERVER['SSL_CLIENT_VERIFY'] !== 'SUCCESS' + || !isset($_SERVER['SSL_CLIENT_I_DN']) + ) { + return false; + } + + if ($_SERVER['SSL_CLIENT_V_REMAIN'] <= 0) { + return false; + } + + return true; + } + + + + /** + * Registers the currently available SSL client certificate + * with the given user. As a result, the user will be able to login + * using the certifiate + * + * @param integer $uId User ID to attach the client cert to. + * + * @return boolean True if registration was well, false if not. + */ + public function registerCurrentCertificate($uId) + { + $serial = $_SERVER['SSL_CLIENT_M_SERIAL']; + $clientIssuerDn = $_SERVER['SSL_CLIENT_I_DN']; + + $query = 'INSERT INTO ' . $this->getTableName() + . ' '. $this->db->sql_build_array( + 'INSERT', array( + 'uId' => $uId, + 'sslSerial' => $serial, + 'sslClientIssuerDn' => $clientIssuerDn, + 'sslName' => $_SERVER['SSL_CLIENT_S_DN_CN'], + 'sslEmail' => $_SERVER['SSL_CLIENT_S_DN_Email'] + ) + ); + if (!($dbresult = $this->db->sql_query($query))) { + message_die( + GENERAL_ERROR, 'Could not load user for client certificate', + '', __LINE__, __FILE__, $query, $this->db + ); + return false; + } + + return true; + } + + + + /** + * Takes values from the currently available SSL client certificate + * and adds the available profile data to the user. + * + * @param integer $uId User ID to attach the client cert to. + * + * @return array Array of profile data that were registered. + * Database column name as key, new value as value + */ + public function updateProfileFromCurentCert($uId) + { + $arData = array(); + + if (isset($_SERVER['SSL_CLIENT_S_DN_CN']) + && trim($_SERVER['SSL_CLIENT_S_DN_CN']) != '' + ) { + $arData['name'] = trim($_SERVER['SSL_CLIENT_S_DN_CN']); + } + + if (count($arData)) { + $us = SemanticScuttle_Service_Factory::get('User'); + foreach ($arData as $column => $value) { + $us->_updateuser($uId, $column, $value); + } + } + return $arData; + } + + + + /** + * Tries to detect the user ID from the SSL client certificate passed + * to the web server. + * + * @return mixed Integer user ID if the certificate is valid and + * assigned to a user, boolean false otherwise + */ + public function getUserIdFromCert() + { + if (!$this->hasValidCert()) { + return false; + } + + $serial = $_SERVER['SSL_CLIENT_M_SERIAL']; + $clientIssuerDn = $_SERVER['SSL_CLIENT_I_DN']; + + $query = 'SELECT uId' + . ' FROM ' . $this->getTableName() + . ' WHERE sslSerial = \'' . $this->db->sql_escape($serial) . '\'' + . ' AND sslClientIssuerDn = \'' + . $this->db->sql_escape($clientIssuerDn) + . '\''; + if (!($dbresult = $this->db->sql_query($query))) { + message_die( + GENERAL_ERROR, 'Could not load user for client certificate', + '', __LINE__, __FILE__, $query, $this->db + ); + return false; + } + + $row = $this->db->sql_fetchrow($dbresult); + $this->db->sql_freeresult($dbresult); + + if (!$row) { + return false; + } + return (int)$row['uId']; + } + + + + /** + * Fetches the certificate with the given ID from database. + * + * @param integer $id Certificate ID in database + * + * @return SemanticScuttle_Model_User_SslClientCert Certificate object + * or null if not found + */ + public function getCert($id) + { + $query = 'SELECT * FROM ' . $this->getTableName() + . ' WHERE id = ' . (int)$id; + if (!($dbresult = $this->db->sql_query($query))) { + message_die( + GENERAL_ERROR, 'Could not load SSL client certificate', + '', __LINE__, __FILE__, $query, $this->db + ); + return null; + } + + if ($row = $this->db->sql_fetchrow($dbresult)) { + $cert = SemanticScuttle_Model_User_SslClientCert::fromDb($row); + } else { + $cert = null; + } + $this->db->sql_freeresult($dbresult); + return $cert; + } + + + + /** + * Fetches all registered certificates for the user from the database + * and returns it. + * + * @return array Array with all certificates for the user. Empty if + * there are none, SemanticScuttle_Model_User_SslClientCert + * objects otherwise. + */ + public function getUserCerts($uId) + { + $query = 'SELECT * FROM ' . $this->getTableName() + . ' WHERE uId = ' . (int)$uId + . ' ORDER BY sslSerial DESC'; + if (!($dbresult = $this->db->sql_query($query))) { + message_die( + GENERAL_ERROR, 'Could not load SSL client certificates', + '', __LINE__, __FILE__, $query, $this->db + ); + return array(); + } + + $certs = array(); + while ($row = $this->db->sql_fetchrow($dbresult)) { + $certs[] = SemanticScuttle_Model_User_SslClientCert::fromDb($row); + } + $this->db->sql_freeresult($dbresult); + return $certs; + } + + + + /** + * Deletes a SSL client certificate. + * No security checks are made here. + * + * @param mixed $cert Certificate object or certificate database id. + * Objects are of type + * SemanticScuttle_Model_User_SslClientCert + * + * @return boolean True if all went well, false if it could not be deleted + */ + public function delete($cert) + { + if ($cert instanceof SemanticScuttle_Model_User_SslClientCert) { + $id = (int)$cert->id; + } else { + $id = (int)$cert; + } + + if ($id === 0) { + return false; + } + + $query = 'DELETE FROM ' . $this->getTableName() + .' WHERE id = ' . $id; + + if (!($dbresult = $this->db->sql_query($query))) { + message_die( + GENERAL_ERROR, 'Could not delete user certificate', + '', __LINE__, __FILE__, $query, $this->db + ); + return false; + } + + return true; + } +} +?>
\ No newline at end of file diff --git a/src/SemanticScuttle/header.php b/src/SemanticScuttle/header.php index e931594..b0705b0 100644 --- a/src/SemanticScuttle/header.php +++ b/src/SemanticScuttle/header.php @@ -84,6 +84,7 @@ require_once 'SemanticScuttle/Service/Factory.php'; require_once 'SemanticScuttle/functions.php'; require_once 'SemanticScuttle/Model/Bookmark.php'; require_once 'SemanticScuttle/Model/UserArray.php'; +require_once 'SemanticScuttle/Model/User/SslClientCert.php'; if (count($GLOBALS['serviceoverrides']) > 0 && !defined('UNIT_TEST_MODE') |