File: /var/www/apklausos/New/plugins/AuditLog/AuditLog.php
<?php
class AuditLog extends \LimeSurvey\PluginManager\PluginBase {
protected $storage = 'DbStorage';
static protected $description = 'Core: Create an audit log of changes';
static protected $name = 'auditlog';
protected $settings = array(
'AuditLog_Log_UserSave' => array(
'type' => 'checkbox',
'label' => 'Log if a user was modified or created',
'default' => '1',
),
'AuditLog_Log_UserLogin' => array(
'type' => 'checkbox',
'label' => 'Log if a user has logged in successfully',
'default' => '1',
),
'AuditLog_Log_UserLogout' => array(
'type' => 'checkbox',
'label' => 'Log if user has logged out',
'default' => '1',
),
'AuditLog_Log_UserFailedLoginAttempt' => array(
'type' => 'checkbox',
'label' => 'Log if a user login has failed',
'default' => '1',
),
'AuditLog_Log_UserDelete' => array(
'type' => 'checkbox',
'label' => 'Log if a user was deleted',
'default' => '1',
),
'AuditLog_Log_DataEntryCreate' => array(
'type' => 'checkbox',
'label' => 'Log if a survey admin creates a response',
'default' => '1',
),
'AuditLog_Log_DataEntryUpdate' => array(
'type' => 'checkbox',
'label' => 'Log if a survey admin modifies a response',
'default' => '1',
),
'AuditLog_Log_DataEntryDelete' => array(
'type' => 'checkbox',
'label' => 'Log if a survey admin delete a response',
'default' => '1',
),
'AuditLog_Log_DataEntryImport' => array(
'type' => 'checkbox',
'label' => 'Log if a survey admin imports responses',
'default' => '1',
),
'AuditLog_Log_TokenSave' => array(
'type' => 'checkbox',
'label' => 'Log if a survey participant was modified or created',
'default' => '1',
),
'AuditLog_Log_TokenDelete' => array(
'type' => 'checkbox',
'label' => 'Log if a survey participant was deleted',
'default' => '1',
),
'AuditLog_Log_ParticipantSave' => array(
'type' => 'checkbox',
'label' => 'Log if a central database participant was modified or created',
'default' => '1',
),
'AuditLog_Log_ParticipantDelete' => array(
'type' => 'checkbox',
'label' => 'Log if a central database participant was deleted',
'default' => '1',
),
'AuditLog_Log_UserPermissionsChanged' => array(
'type' => 'checkbox',
'label' => 'Log if a user permissions changes',
'default' => '1',
),
'AuditLog_Log_SurveySettings' => array(
'type' => 'checkbox',
'label' => 'Log if a user changes survey settings',
'default' => '1',
),
);
public function init() {
$this->subscribe('beforeSurveySettings');
$this->subscribe('newSurveySettings');
$this->subscribe('beforeSurveySettingsSave');
$this->subscribe('beforeActivate');
$this->subscribe('beforeUserSave');
$this->subscribe('beforeUserDelete');
$this->subscribe('beforePermissionSetSave');
$this->subscribe('beforeDataEntryCreate');
$this->subscribe('beforeDataEntryUpdate');
$this->subscribe('beforeDataEntryDelete');
$this->subscribe('beforeDataEntryImport');
$this->subscribe('beforeTokenSave');
$this->subscribe('beforeTokenDelete');
$this->subscribe('beforeParticipantSave');
$this->subscribe('beforeParticipantDelete');
$this->subscribe('beforeLogout');
$this->subscribe('afterSuccessfulLogin');
$this->subscribe('afterFailedLoginAttempt');
}
/**
* check for setting for a single operation event, login user, save or delete
* @return boolean
*/
private function checkSetting($settingName) {
$pluginsettings = $this->getPluginSettings(true);
// Logging will done if setted to true
return $pluginsettings[$settingName]['current'] == 1;
}
/**
* User logout to the audit log
* @return unknown_type
*/
public function beforeLogout()
{
if (!$this->checkSetting('AuditLog_Log_UserLogout')) {
return;
}
$oUser = $this->api->getCurrentUser();
if ($oUser != false)
{
$iUserID = $oUser->uid;
$oAutoLog = $this->api->newModel($this, 'log');
$oAutoLog->uid=$iUserID;
$oAutoLog->entity='user';
$oAutoLog->entityid=$iUserID;
$oAutoLog->action='beforeLogout';
$oAutoLog->save();
}
}
/**
* Successfull login to the audit log
* @return unknown_type
*/
public function afterSuccessfulLogin()
{
if (!$this->checkSetting('AuditLog_Log_UserLogin')) {
return;
}
$iUserID=$this->api->getCurrentUser()->uid;
$oAutoLog = $this->api->newModel($this, 'log');
$oAutoLog->uid=$iUserID;
$oAutoLog->entity='user';
$oAutoLog->entityid=$iUserID;
$oAutoLog->action='afterSuccessfulLogin';
$oAutoLog->save();
}
/**
* Failed login attempt to the audit log
* @return unknown_type
*/
public function afterFailedLoginAttempt()
{
if (!$this->checkSetting('AuditLog_Log_UserFailedLoginAttempt')) {
return;
}
$event = $this->getEvent();
$identity = $event->get('identity');
$oAutoLog = $this->api->newModel($this, 'log');
$oAutoLog->entity='user';
$oAutoLog->action='afterFailedLoginAttempt';
$aUsername['username'] = $identity->username;
$oAutoLog->newvalues = json_encode($aUsername);
$oAutoLog->save();
}
/**
* Saves permissions changes to the audit log
*/
public function beforePermissionSetSave()
{
if (!$this->checkSetting('AuditLog_Log_UserPermissionsChanged')) {
return;
}
$event = $this->getEvent();
$aNewPermissions=$event->get('aNewPermissions');
$iSurveyID=$event->get('iSurveyID');
$iUserID=$event->get('iUserID');
$oCurrentUser=$this->api->getCurrentUser();
$oOldPermission=$this->api->getPermissionSet($iUserID, $iSurveyID, 'survey');
$sAction='update'; // Permissions are in general only updated (either you have a permission or you don't)
if (count(array_diff_assoc_recursive($aNewPermissions,$oOldPermission)))
{
$oAutoLog = $this->api->newModel($this, 'log');
$oAutoLog->uid=$oCurrentUser->uid;
$oAutoLog->entity='permission';
$oAutoLog->entityid=$iSurveyID;
$oAutoLog->action=$sAction;
$oAutoLog->oldvalues=json_encode(array_diff_assoc_recursive($oOldPermission,$aNewPermissions));
$oAutoLog->newvalues=json_encode(array_diff_assoc_recursive($aNewPermissions,$oOldPermission));
$oAutoLog->fields=implode(',',array_keys(array_diff_assoc_recursive($aNewPermissions,$oOldPermission)));
$oAutoLog->save();
}
}
/**
* Function catches if a response was created
* @return unknown_type
*/
public function beforeDataEntryCreate()
{
$event = $this->getEvent();
$iSurveyID=$event->get('iSurveyID');
if (!$this->checkSetting('AuditLog_Log_DataEntryCreate') || !$this->get('auditing', 'Survey', $iSurveyID, true)) {
return;
}
$oCurrentUser = $this->api->getCurrentUser();
$currentUID = $oCurrentUser ? $oCurrentUser->uid : null;
$aValues = $event->get('oModel')->getAttributes();
if (count($aValues)){
$oAutoLog = $this->api->newModel($this, 'log');
$oAutoLog->uid=$currentUID;
$oAutoLog->entity='survey_' . $iSurveyID;
$oAutoLog->action="create";
$oAutoLog->newvalues=json_encode($aValues);
$oAutoLog->save();
}
}
/**
* Function catches if a response was modified
* @return unknown_type
*/
public function beforeDataEntryUpdate()
{
$event = $this->getEvent();
$iSurveyID=$event->get('iSurveyID');
if (!$this->checkSetting('AuditLog_Log_DataEntryUpdate') || !$this->get('auditing', 'Survey', $iSurveyID, true)) {
return;
}
$oCurrentUser = $this->api->getCurrentUser();
$currentUID = $oCurrentUser ? $oCurrentUser->uid : null;
$oldvalues= $this->api->getResponse($iSurveyID, $event->get('iResponseID'), false);
$aDiffOld = array();
$aDiffNew = array();
foreach ($oldvalues->attributes as $aFieldName => $sValue) {
if (App()->request->getPost($aFieldName) !== null) {
$oldValue = $sValue;
$newValue = App()->request->getPost($aFieldName);
if ($oldValue != $newValue) {
$aDiffOld[$aFieldName] = $oldValue;
$aDiffNew[$aFieldName] = $newValue;
}
}
}
if (count($aDiffOld)){
$oAutoLog = $this->api->newModel($this, 'log');
$oAutoLog->uid=$currentUID;
$oAutoLog->entity='survey_' . $iSurveyID;
$oAutoLog->action="update";
$oAutoLog->entityid=$event->get('iResponseID');
$oAutoLog->oldvalues=json_encode($aDiffOld);
$oAutoLog->newvalues=json_encode($aDiffNew);
$oAutoLog->fields=implode(',',array_keys($aDiffOld));
$oAutoLog->save();
}
}
/**
* Function catches if a response was deleted
* @return unknown_type
*/
public function beforeDataEntryDelete()
{
$event = $this->getEvent();
$iSurveyID=$event->get('iSurveyID');
if (!$this->checkSetting('AuditLog_Log_DataEntryDelete') || !$this->get('auditing', 'Survey', $iSurveyID, true)) {
return;
}
$oCurrentUser = $this->api->getCurrentUser();
$currentUID = $oCurrentUser ? $oCurrentUser->uid : null;
$oldvalues = $this->api->getResponse($iSurveyID, $event->get('iResponseID'), true);
$oAutoLog = $this->api->newModel($this, 'log');
$oAutoLog->uid=$currentUID;
$oAutoLog->entity='survey_' . $iSurveyID;
$oAutoLog->action="delete";
$oAutoLog->entityid=$event->get('iResponseID');
$oAutoLog->oldvalues=json_encode($oldvalues);
$oAutoLog->save();
}
/**
* Log import responses
* @return unknown_type
*/
public function beforeDataEntryImport()
{
$event = $this->getEvent();
$iSurveyID=$event->get('iSurveyID');
if (!$this->checkSetting('AuditLog_Log_DataEntryImport') || !$this->get('auditing', 'Survey', $iSurveyID, true)) {
return;
}
$oCurrentUser = $this->api->getCurrentUser();
$currentUID = $oCurrentUser ? $oCurrentUser->uid : null;
$oModel = $this->getEvent()->get('oModel');
$aValues = $oModel->getAttributes();
if (count($aValues)){
$oAutoLog = $this->api->newModel($this, 'log');
$oAutoLog->uid=$currentUID;
$oAutoLog->entity='survey_' . $iSurveyID;
$oAutoLog->action="import";
$oAutoLog->newvalues=json_encode($aValues);
$oAutoLog->fields=implode(',',array_keys($aValues));
$oAutoLog->save();
}
}
/**
* Function catches if a participant of a particular survey was modified or created
* All data is saved - only the password hash is anonymized for security reasons
*/
public function beforeTokenSave()
{
$event = $this->getEvent();
$iSurveyID=$event->get('iSurveyID');
if (!$this->checkSetting('AuditLog_Log_TokenSave') || !$this->get('auditing', 'Survey', $iSurveyID, false)) {
return;
}
$oNewParticipant=$this->getEvent()->get('model');
$oCurrentUser = $this->api->getCurrentUser();
$currentUID = $oCurrentUser ? $oCurrentUser->uid : null;
if ($oNewParticipant->isNewRecord)
{
$sAction = 'create';
$oldvalues = array();
}
else
{
$sAction = 'update';
$oldvalues= $this->api->getTokenById($iSurveyID, $oNewParticipant->tid)->getAttributes();
}
$newValues=$oNewParticipant->getAttributes();
if (count(array_diff_assoc($newValues,$oldvalues))){
$oAutoLog = $this->api->newModel($this, 'log');
$oAutoLog->uid=$currentUID;
$oAutoLog->entity='token_' . $iSurveyID;
$oAutoLog->action=$sAction;
$oAutoLog->entityid=$newValues['tid'];
$oAutoLog->oldvalues=json_encode(array_diff_assoc($oldvalues,$newValues));
$oAutoLog->newvalues=json_encode(array_diff_assoc($newValues,$oldvalues));
$oAutoLog->fields=implode(',',array_keys(array_diff_assoc($newValues,$oldvalues)));
$oAutoLog->save();
}
}
/**
* Function catches if a participant of a particular survey was modified or created
* All data is saved - only the password hash is anonymized for security reasons
*/
public function beforeTokenDelete()
{
$event = $this->getEvent();
$iSurveyID=$event->get('iSurveyID');
if (!$this->checkSetting('AuditLog_Log_TokenDelete') || !$this->get('auditing', 'Survey', $iSurveyID, true)) {
return;
}
$sTokenIds=$this->getEvent()->get('sTokenIds');
$aTokenIds = explode(',', $sTokenIds);
$oCurrentUser=$this->api->getCurrentUser();
foreach ($aTokenIds as $tokenId)
{
$token = Token::model($iSurveyID)->find('tid=' . $tokenId);
if (!is_null($token))
{
$aValues=$token->getAttributes();
$oAutoLog = $this->api->newModel($this, 'log');
$oAutoLog->uid=$oCurrentUser->uid;
$oAutoLog->entity='token';
$oAutoLog->action='delete';
$oAutoLog->entityid=$aValues['participant_id'];
$oAutoLog->oldvalues=json_encode($aValues);
$oAutoLog->fields=implode(',',array_keys($aValues));
$oAutoLog->save();
}
}
}
/**
* Function catches if a central database participant was modified or created
* All data is saved - only the password hash is anonymized for security reasons
*/
public function beforeParticipantSave()
{
if (!$this->checkSetting('AuditLog_Log_ParticipantSave')) {
return;
}
$oNewParticipant=$this->getEvent()->get('model');
if ($oNewParticipant->isNewRecord)
{
$sAction = 'create';
$aOldValues = array();
}
else
{
$sAction = 'update';
$aOldValues=$this->api->getParticipant($oNewParticipant->participant_id)->getAttributes();
}
$oCurrentUser=$this->api->getCurrentUser();
$aNewValues=$oNewParticipant->getAttributes();
if (count(array_diff_assoc($aNewValues,$aOldValues)))
{
$oAutoLog = $this->api->newModel($this, 'log');
$oAutoLog->uid=$oCurrentUser->uid;
$oAutoLog->entity='participant';
$oAutoLog->action=$sAction;
$oAutoLog->entityid=$aNewValues['participant_id'];
$oAutoLog->oldvalues=json_encode(array_diff_assoc($aOldValues,$aNewValues));
$oAutoLog->newvalues=json_encode(array_diff_assoc($aNewValues,$aOldValues));
$oAutoLog->fields=implode(',',array_keys(array_diff_assoc($aNewValues,$aOldValues)));
$oAutoLog->save();
}
}
/**
* Function catches if a central database participant was modified or created
* All data is saved - only the password hash is anonymized for security reasons
*/
public function beforeParticipantDelete()
{
if (!$this->checkSetting('AuditLog_Log_ParticipantDelete')) {
return;
}
$oNewParticipant=$this->getEvent()->get('model');
$oCurrentUser=$this->api->getCurrentUser();
$aValues=$oNewParticipant->getAttributes();
$oAutoLog = $this->api->newModel($this, 'log');
$oAutoLog->uid=$oCurrentUser->uid;
$oAutoLog->entity='participant';
$oAutoLog->action='delete';
$oAutoLog->entityid=$aValues['participant_id'];
$oAutoLog->oldvalues=json_encode($aValues);
$oAutoLog->fields=implode(',',array_keys($aValues));
$oAutoLog->save();
}
/**
* Function catches if a user was modified or created
* All data is saved - only the password hash is anonymized for security reasons
*/
public function beforeUserSave()
{
if (!$this->checkSetting('AuditLog_Log_UserSave')) {
return;
}
$oUserData=$this->getEvent()->get('model');
$oCurrentUser=$this->api->getCurrentUser();
$aNewValues=$oUserData->getAttributes();
if (!isset($oUserData->uid))
{
$sAction='create';
$aOldValues=array();
// Indicate the password has changed but assign fake hash
$aNewValues['password']='*MASKED*PASSWORD*';
}
else
{
$oOldUser=$this->api->getUser($oUserData->uid);
$sAction='update';
$aOldValues=$oOldUser->getAttributes();
// Postgres delivers bytea fields as streams
if (gettype($aOldValues['password'])=='resource')
{
$aOldValues['password'] = stream_get_contents($aOldValues['password']);
}
// If the password has changed then indicate that it has changed but assign fake hashes
if ($aNewValues['password']!=$aOldValues['password'])
{
$aOldValues['password']='*MASKED*OLD*PASSWORD*';
$aNewValues['password']='*MASKED*NEW*PASSWORD*';
}
}
if (count(array_diff_assoc($aNewValues,$aOldValues)))
{
$oAutoLog = $this->api->newModel($this, 'log');
if ($oCurrentUser) {
$oAutoLog->uid=$oCurrentUser->uid;
}
else {
$oAutoLog->uid='Automatic creation';
}
$oAutoLog->entity='user';
if ($sAction=='update') $oAutoLog->entityid=$oOldUser['uid'];
$oAutoLog->action=$sAction;
$oAutoLog->oldvalues=json_encode(array_diff_assoc($aOldValues,$aNewValues));
$oAutoLog->newvalues=json_encode(array_diff_assoc($aNewValues,$aOldValues));
$oAutoLog->fields=implode(',',array_keys(array_diff_assoc($aNewValues,$aOldValues)));
$oAutoLog->save();
}
}
/**
* Function catches if a user was deleted
* All data is saved - only the password hash is anonymized for security reasons
*/
public function beforeUserDelete()
{
if (!$this->checkSetting('AuditLog_Log_UserDelete')) {
return;
}
$oUserData=$this->getEvent()->get('model');
$oCurrentUser=$this->api->getCurrentUser();
$oOldUser=$this->api->getUser($oUserData->uid);
if ($oOldUser)
{
$aOldValues=$oOldUser->getAttributes();
unset($aOldValues['password']);
$oAutoLog = $this->api->newModel($this, 'log');
$oAutoLog->uid=$oCurrentUser->uid;
$oAutoLog->entity='user';
$oAutoLog->entityid=$oOldUser['uid'];
$oAutoLog->action='delete';
$oAutoLog->oldvalues=json_encode($aOldValues);
$oAutoLog->fields=implode(',',array_keys($aOldValues));
$oAutoLog->save();
}
}
public function beforeActivate()
{
if (!$this->api->tableExists($this, 'log'))
{
$this->api->createTable($this, 'log', array('id'=>'pk',
'created'=>'datetime',
'uid'=>'string',
'entity'=>'string',
'entityid'=>'string',
'action'=>'string',
'fields'=>'text',
'oldvalues'=>'text',
'newvalues'=>'text'));
}
}
/**
* This event is fired by the administration panel to gather extra settings
* available for a survey.
* The plugin should return setting meta data.
*/
public function beforeSurveySettings()
{
$pluginsettings = $this->getPluginSettings(true);
$event = $this->getEvent();
$event->set("surveysettings.{$this->id}", array(
'name' => get_class($this),
'settings' => array(
'auditing' => array(
'type' => 'select',
'options'=>array(0=>'No',
1=>'Yes'),
'default' => 1,
'tab' => 'notification', // @todo: Setting no used yet
'category' => 'Auditing for person-related data', // @todo: Setting no used yet
'label' => 'Audit log for this survey:',
'current' => $this->get('auditing', 'Survey', $event->get('survey'))
)
)
));
}
public function newSurveySettings()
{
$event = $this->getEvent();
foreach ($event->get('settings') as $name => $value)
{
$this->set($name, $value, 'Survey', $event->get('survey'));
}
}
public function beforeSurveySettingsSave()
{
$event = $this->getEvent();
$oModifiedSurvey = $event->get('modifiedSurvey');
$iSurveyID = $oModifiedSurvey->sid;
if (!$this->checkSetting('AuditLog_Log_SurveySettings') || !$this->get('auditing', 'Survey', $iSurveyID, false)) {
return;
}
$oCurrentUser=$this->api->getCurrentUser();
if (!is_null($oModifiedSurvey)) {
$newAttributes = $oModifiedSurvey->getAttributes();
$oldSurvey=Survey::model()->find('sid = :sid', array(':sid' => $iSurveyID));
$oldAttributes= $oldSurvey->getAttributes();
$diff = array_diff_assoc($newAttributes, $oldAttributes);
if (count($diff)>0){
$oAutoLog = $this->api->newModel($this, 'log');
$oAutoLog->uid=$oCurrentUser->uid;
$oAutoLog->entity='survey';
$oAutoLog->entityid=$iSurveyID;
$oAutoLog->action='update';
$oAutoLog->oldvalues=json_encode(array_diff_assoc($oldAttributes, $newAttributes));
$oAutoLog->newvalues=json_encode($diff);
#$oAutoLog->fields=json_encode($diff);
$oAutoLog->fields=implode(',',array_keys($diff));
$oAutoLog->save();
}
}
}
}