diff --git a/lib/security/Esignature.inc.php b/lib/security/Esignature.inc.php new file mode 100644 index 0000000..bd5e882 --- /dev/null +++ b/lib/security/Esignature.inc.php @@ -0,0 +1,221 @@ +. + * + * You can contact KnowledgeTree Inc., PO Box 7775 #87847, San Francisco, + * California 94120-7775, or email info@knowledgetree.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU General Public License version 3. + * + * In accordance with Section 7(b) of the GNU General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * KnowledgeTree" logo and retain the original copyright notice. If the display of the + * logo is not reasonably feasible for technical reasons, the Appropriate Legal Notices + * must display the words "Powered by KnowledgeTree" and retain the original + * copyright notice. + * Contributor( s): ______________________________________ + * + */ + +/** + * This class defines the electronic signatures + * + * @author KnowledgeTree Team + * @package Electronic Signatures + * @version Version 0.1 + */ +class ESignature +{ + /** + * Check whether the electronic signature is enabled + * + * @access private + * @var bool + */ + private $enabled; + + /** + * The number of failed logins on the current action + * + * @access private + * @var integer + */ + private $attempts; + + /** + * Determines whether the user has been locked out of performing write actions. + * This lock will be reset upon logging out of the system. + * + * @access private + * @var bool + */ + private $lock; + + /** + * Contains the error message if the authentication fails + * + * @access private + * @var string + */ + private $error; + + /** + * The object associated with the action - folder_id | Document + * + * @access private + * @var folder_id | Document The Document object or the folder id + */ + private $object = null; + + /** + * Creates the ESignature object + * + * @author KnowledgeTree Team + * @access public + */ + public function __construct() + { + $config = KTConfig::getSingleton(); + $this->enabled = $config->get('e_signatures/enableESignatures', false); + + $this->attempts = isset($_SESSION['esignature_attempts']) ? $_SESSION['esignature_attempts'] : 0; + $this->lock = (isset($_SESSION['esignature_lock']) && $_SESSION['esignature_lock'] == 'true') ? true : false; + } + + public function isEnabled() + { + if($this->enabled){ + return true; + } + return false; + } + + public function isLocked() + { + return $this->lock; + } + + public function getLockMsg() + { + return _kt('System locked. You have exceeded the number of allowed authentication attempts and will not be allowed to perform any write actions during this session.'); + } + + public function getError(){ + return $this->error; + } + + public function setObject($object) + { + $this->object = $object; + } + + public function sign($username, $password, $comment, $action, $type = 'system', $details = null) + { + if(!$this->enabled){ + return true; + } + + if($this->lock){ + $this->error = $this->getLockMsg(); + return false; + } + + switch ($type){ + case 'document': + $comment = _kt('Document').': '.$details.' | '.$comment; + break; + + case 'folder': + $comment = _kt('Folder').': '.$details.' | '.$comment; + break; + + case 'system': + break; + } + + $this->error = _kt('Authentication failed. Please check your username and password and try again.'); + + if(!$this->authenticate($username, $password)){ + // failed attempt - increase count, if count = 3, log and lock + $this->attempts++; + + if($this->attempts >= 3){ + $this->lock = true; + $_SESSION['esignature_lock'] = 'true'; + + $comment = _kt('Electronic Signature - Failed Authentication: ') . $comment; + $this->logTransaction($action, $comment, $type, $details); + + $this->error = $this->getLockMsg(); + } + $_SESSION['esignature_attempts'] = $this->attempts; + + return false; + } + + // set the number of attempts to 0 + $this->attempts = 0; + $_SESSION['esignature_attempts'] = 0; + $this->error = ''; + + // log successful transaction + $comment = _kt('Electronic Signature: ') . $comment; + $this->logTransaction($action, $comment, $type, $details); + return true; + } + + private function logTransaction($action, $comment) + { + $date = date('Y-m-d H:i:s'); + + require_once(KT_LIB_DIR . '/users/userhistory.inc.php'); + $params = array( + 'userid' => $_SESSION['userID'], + 'datetime' => $date, + 'actionnamespace' => $action, + 'comments' => $comment, + 'sessionid' => $_SESSION['sessionID'], + ); + KTUserHistory::createFromArray($params); + } + + private function authenticate($username, $password) + { + // Get the user object + $oUser = User::getByUsername($username); + if(PEAR::isError($oUser) || $oUser == false){ + return false; + } + + // check user is the same as the currently logged in user + if($oUser->iId != $_SESSION['userID']){ + $this->error = _kt('Authentication failed. The username does not match the currently logged in user.'); + return false; + } + + // authenticate + return KTAuthenticationUtil::checkPassword($oUser, $password); + } + +} + +?> \ No newline at end of file diff --git a/lib/templating/kt3template.inc.php b/lib/templating/kt3template.inc.php index 71e428e..767ec54 100644 --- a/lib/templating/kt3template.inc.php +++ b/lib/templating/kt3template.inc.php @@ -133,6 +133,7 @@ class KTPage { $aJS[] = 'thirdpartyjs/extjs/adapter/ext/ext-base.js'; $aJS[] = 'thirdpartyjs/extjs/ext-all.js'; $aJS[] = 'resources/js/search2widget.js'; + $aJS[] = 'resources/js/signature.js'; $this->requireJSResources($aJS); @@ -153,11 +154,13 @@ class KTPage { // FIXME: we lost the getDefaultAction stuff - do we care? // note that key == action. this is _important_, since we crossmatch the breadcrumbs against this for "active" $sBaseUrl = KTUtil::kt_url(); + $heading = _kt('You are attempting to access DMS Administration'); $this->menu = array(); $this->menu['dashboard'] = array('label' => _kt("Dashboard"), 'url' => $sBaseUrl.'/dashboard.php'); $this->menu['browse'] = array('label' => _kt("Browse Documents"), 'url' => $sBaseUrl.'/browse.php'); - $this->menu['administration'] = array('label' => _kt("DMS Administration"), 'url' => $sBaseUrl.'/admin.php'); + $this->menu['administration'] = array('label' => _kt("DMS Administration"), 'url' => '#', + 'onclick' => "javascript: showSignatureForm('{$heading}', 'dms.administration.access', 'system', '{$sBaseUrl}/admin.php', 'redirect');"); //$sBaseUrl.'/admin.php', } diff --git a/plugins/ktcore/KTCorePlugin.php b/plugins/ktcore/KTCorePlugin.php index 944b874..ff9b7bd 100644 --- a/plugins/ktcore/KTCorePlugin.php +++ b/plugins/ktcore/KTCorePlugin.php @@ -354,6 +354,10 @@ class KTCorePlugin extends KTPlugin { _kt('Internationalization'), _kt('View and modify the default language.'), 'admin/configSettings.php', null); + $this->registerAdminPage('securityconfigpage', 'SecurityConfigPageDispatcher', 'config', + _kt('Security'), _kt('View and modify the security settings.'), + 'admin/configSettings.php', null); + // misc $this->registerAdminPage('helpmanagement', 'ManageHelpDispatcher', 'misc', _kt('Edit Help files'), _kt('Change the help files that are displayed to users.'), diff --git a/plugins/ktcore/admin/configSettings.php b/plugins/ktcore/admin/configSettings.php index a23c7b5..20fdbea 100644 --- a/plugins/ktcore/admin/configSettings.php +++ b/plugins/ktcore/admin/configSettings.php @@ -339,4 +339,18 @@ class SearchAndIndexingConfigPageDispatcher extends BaseConfigDispatcher return parent::check(); } } + +class SecurityConfigPageDispatcher extends BaseConfigDispatcher +{ + function check() { + $this->category = 'Security Settings'; + $this->name = _kt('Security Settings'); + + $this->aBreadcrumbs[] = array( + 'url' => $_SERVER['PHP_SELF'], + 'name' => _kt('Security Settings'), + ); + return parent::check(); + } +} ?> diff --git a/plugins/ktstandard/KTElectronicSignatures.php b/plugins/ktstandard/KTElectronicSignatures.php new file mode 100644 index 0000000..c59da51 --- /dev/null +++ b/plugins/ktstandard/KTElectronicSignatures.php @@ -0,0 +1,191 @@ +. + * + * You can contact KnowledgeTree Inc., PO Box 7775 #87847, San Francisco, + * California 94120-7775, or email info@knowledgetree.com. + * + * The interactive user interfaces in modified source and object code versions + * of this program must display Appropriate Legal Notices, as required under + * Section 5 of the GNU General Public License version 3. + * + * In accordance with Section 7(b) of the GNU General Public License version 3, + * these Appropriate Legal Notices must retain the display of the "Powered by + * KnowledgeTree" logo and retain the original copyright notice. If the display of the + * logo is not reasonably feasible for technical reasons, the Appropriate Legal Notices + * must display the words "Powered by KnowledgeTree" and retain the original + * copyright notice. + * Contributor( s): ______________________________________ + * + */ + +require_once('../../config/dmsDefaults.php'); +require_once(KT_LIB_DIR . '/security/Esignature.inc.php'); + +/** + * Class handles the electronic signatures + * + * @author KnowledgeTree Team + * @package Electronic Signatures + */ +class KTElectronicSignatures +{ + /** + * The error returned when attempting to authenticate + * + * @access private + * @var $error + */ + private $error; + + /** + * If the system is locked for the session + * + * @access private + * @var bool + */ + private $lock; + + /** + * If electronic signatures are enabled + * + * @access private + * @var bool + */ + private $enabled; + + /** + * The ESignature object + * + * @access private + * @var ESignature object + */ + private $eSignature; + + /** + * Constructor function for the class + * + * @author KnowledgeTree Team + * @access public + * @return KTElectronicSignatures + */ + public function KTElectronicSignatures() + { + $this->eSignature = new ESignature(); + $this->lock = $this->eSignature->isLocked(); + $this->enabled = $this->eSignature->isEnabled(); + } + + /** + * Returns the form requesting the signature + * + * @author KnowledgeTree Team + * @access public + * @return html + */ + public function getSignatureForm($head) + { + $oTemplating =& KTTemplating::getSingleton(); + $oTemplate = $oTemplating->loadTemplate('ktstandard/signatures/signature_form'); + $aTemplateData = array( + 'head' => $head + ); + + if(!$this->enabled){ + return 'disabled'; + } + + if($this->lock){ + return $this->eSignature->getLockMsg(); + } + return $oTemplate->render($aTemplateData); + } + + /** + * Attempts authentication of the signature + * + * @author KnowledgeTree Team + * @access public + * @param string $username The users username. + * @param string $password The users password. + * @param string $comment A comment on the action performed. + * @return bool True if authenticated | False if rejected + */ + public function authenticateSignature($username, $password, $comment, $action, $type, $details) + { + $result = $this->eSignature->sign($username, $password, $comment, $action, $type, $details); + if(!$result){ + $this->error = $this->eSignature->getError(); + $this->lock = $this->eSignature->isLocked(); + } + return $result; + } + + /** + * Returns the error from the attempted signature + * + * @author KnowledgeTree Team + * @access public + * @return string + */ + public function getError() + { + return $this->error; + } + + /** + * Checks whether the electronic signature system is locked at which point authentication is not allowed. + * + * @author KnowledgeTree Team + * @access public + * @return bool + */ + public function isLocked() + { + return $this->lock; + } +} + +$sign = new KTElectronicSignatures(); + +// User has signed so authenticate the signature +if($_POST['action'] == 'submit'){ + $user = $_POST['sign_username']; + $password = $_POST['sign_password']; + $comment = $_POST['sign_comment']; + $action = $_POST['sign_action']; + $type = $_POST['sign_type']; + $details = $_POST['sign_details']; + + if($sign->authenticateSignature($user, $password, $comment, $action, $type, $details)){ + echo 'success'; + exit; + } + echo $sign->getError(); + if($sign->isLocked()){ + exit; + } +} + +$head = $_POST['head']; +echo $sign->getSignatureForm($head); + +exit; +?> \ No newline at end of file diff --git a/resources/css/kt-framing.css b/resources/css/kt-framing.css index 62432be..aae45e5 100644 --- a/resources/css/kt-framing.css +++ b/resources/css/kt-framing.css @@ -2309,3 +2309,123 @@ body #content #add_dashlet background: #FDFDFD; padding: 2px; } + + +/* ================= Electronic signature popup - override ExtJS CSS ================= */ + +#signature-panel { + background: transparent; +} + +#signature { + background: transparent; +} + +#sign_here { + background: #FFF; + color: #000; + padding: 5px; + padding-bottom: 10px; +} + +#sign_here h2 { + font-size: 110%; + margin-bottom: 5px; +} + +#sign_here .input_field { + margin-bottom: 10px; +} + +#sign_here .required { + margin-left: 0.5em; + padding-left: 10px; + color: transparent; + background: transparent url(../graphics/required.png) center left no-repeat; +} + +#sign_here .descriptiveText { + color: #666; +} + +#sign_here #form_actions a { + border: 1px solid #ccc; + background: #fdfdfd; + color: #333; + font-weight: normal; + padding: 2px; + padding-right: 5px; + text-decoration: none; +} + +.x-window-tl .x-window-header { + color: #FFF; +} + +.x-window-tc { + background: url(../graphics/portlet_bg.png) repeat-x 0 0; + overflow:hidden; + zoom:1; +} + +.x-window-tl { + background: url(../graphics/portlet_corner_topleft.png) no-repeat 0 0; + padding-left:6px; + zoom:1; + z-index:1; + position:relative; +} + +.x-window-tr { + background: url(../graphics/portlet_corner_topright_2.png) no-repeat right 0; + padding-right:6px; +} + +.x-window-bc { + background: #FFF; + zoom:1; +} +.x-window-bl { + border-left:1px solid #AFAFAF; + border-bottom:1px solid #AFAFAF; + background: #FFF; + padding-left:6px; + zoom:1; +} +.x-window-br { + border-right:1px solid #AFAFAF; + background: #FFF; + padding-right:6px; + zoom:1; +} + +.x-window-ml { + border-left:1px solid #AFAFAF; + background: #FFF; + padding-left:6px; + zoom:1; +} +.x-window-mr { + border-right:1px solid #AFAFAF; + background: #FFF; + padding-right:6px; + zoom:1; +} + +.x-window-mc { + border:1px solid #FFF; + border-top:1px solid #FFF; + padding:0; + margin:0; + font: normal 11px tahoma,arial,helvetica,sans-serif; + background:#FFF; +} + +.x-window-body { + border-left:1px solid #FFF; + border-top:1px solid #FFF; + border-bottom:1px solid #FFF; + border-right:1px solid #FFF; + background: transparent; + overflow: auto; +} diff --git a/resources/graphics/portlet_corner_topright_2.png b/resources/graphics/portlet_corner_topright_2.png new file mode 100644 index 0000000..57b9673 --- /dev/null +++ b/resources/graphics/portlet_corner_topright_2.png diff --git a/resources/js/signature.js b/resources/js/signature.js new file mode 100644 index 0000000..54919bf --- /dev/null +++ b/resources/js/signature.js @@ -0,0 +1,128 @@ +var win; +var head; +var request; +var request_type; +var request_details; + +/* +* Create the electronic signature dialog +*/ +var showSignatureForm = function(head, action, type, request, request_type, details){ + createSignature(); + + var sUrl = rootURL + '/plugins/ktstandard/KTElectronicSignatures.php'; + + if(details === undefined) details = ''; + if(request_type === undefined) request_type = 'submit'; + if(type === undefined) type = 'system'; + + this.head = head; + this.request = request; + this.request_type = request_type; + this.request_details = new Array(); + this.request_details[0] = action; + this.request_details[1] = type; + this.request_details[2] = details; + + // create the window + this.win = new Ext.Window({ + applyTo : 'signature', + layout : 'fit', + width : 360, + height : 265, + closeAction :'destroy', + y : 150, + shadow: false, + modal: true + }); + this.win.show(); + + var sUrl = rootURL + '/plugins/ktstandard/KTElectronicSignatures.php'; + var info = document.getElementById('sign_here'); + + Ext.Ajax.request({ + url: sUrl, + success: function(response) { + if(response.responseText == 'disabled'){ + // continue the action + if(this.request_type == 'redirect'){ + window.location.href = this.request; + }else{ + window.document.forms[this.request].submit(); + } + } + info.innerHTML = response.responseText; + }, + failure: function(response) { + alert('Error. Couldn\'t create signature form.'); + }, + params: { + head: head + } + }); +} + +/* +* Create the html required to initialise the signature panel +*/ +var createSignature = function() { + + if(document.getElementById('signature-panel')){ + p = document.getElementById('signature-panel'); + }else { + p = document.getElementById('pageBody').appendChild(document.createElement('div')); + p.id = 'signature-panel'; + } + + inner = '