File: /var/www/apklausos/application/core/plugins/Authdb/Authdb.php
<?php
class Authdb extends AuthPluginBase
{
protected $storage = 'DbStorage';
protected $_onepass = null;
protected static $description = 'Core: Database authentication + exports';
protected static $name = 'LimeSurvey internal database';
/** @inheritdoc This plugin doesn't have any public methods */
public $allowedPublicMethods = array();
public function init()
{
/**
* Here you should handle subscribing to the events your plugin will handle
*/
$this->subscribe('createNewUser');
$this->subscribe('beforeLogin');
$this->subscribe('newLoginForm');
$this->subscribe('afterLoginFormSubmit');
$this->subscribe('remoteControlLogin');
$this->subscribe('newUserSession');
$this->subscribe('beforeDeactivate');
// Now register for the core exports
$this->subscribe('listExportPlugins');
$this->subscribe('listExportOptions');
$this->subscribe('newExport');
}
/**
* Create a DB user
*
* @return void
*/
public function createNewUser()
{
if (!Permission::model()->hasGlobalPermission('users', 'create')) {
return;
}
$oEvent = $this->getEvent();
$preCollectedUserArray = $oEvent->get('preCollectedUserArray', []);
$expires = null;
$status = true;
if (empty($preCollectedUserArray)) {
// Do nothing if the user to be added is not DB type
if (flattenText(Yii::app()->request->getPost('user_type')) != 'DB') {
return;
}
$new_user = flattenText(Yii::app()->request->getPost('new_user'), false, true);
$new_email = flattenText(Yii::app()->request->getPost('new_email'), false, true);
$new_full_name = flattenText(Yii::app()->request->getPost('new_full_name'), false, true);
$presetPassword = null;
if (Yii::app()->request->getPost('status')) {
$status = flattenText(Yii::app()->request->getPost('status'), false, true);
}
if (Yii::app()->request->getPost('expires')) {
$expires = flattenText(Yii::app()->request->getPost('expires'), false, true);
}
} else {
$new_user = flattenText($preCollectedUserArray['users_name']);
$new_email = flattenText($preCollectedUserArray['email']);
$new_full_name = flattenText($preCollectedUserArray['full_name']);
$presetPassword = flattenText($preCollectedUserArray['password']);
if (!empty($preCollectedUserArray['status'])) {
$status = $preCollectedUserArray['status'];
}
if (!empty($preCollectedUserArray['expires'])) {
$expires = $preCollectedUserArray['expires'];
}
}
if (!LimeMailer::validateAddress($new_email)) {
$oEvent->set('errorCode', self::ERROR_INVALID_EMAIL);
$oEvent->set('errorMessageTitle', gT("Failed to add user"));
$oEvent->set('errorMessageBody', gT("The email address is not valid."));
return;
}
$new_pass = $presetPassword ?? createPassword();
$iNewUID = User::insertUser($new_user, $new_pass, $new_full_name, Yii::app()->session['loginID'], $new_email, $expires, $status);
if (!$iNewUID) {
$oEvent->set('errorCode', self::ERROR_ALREADY_EXISTING_USER);
$oEvent->set('errorMessageTitle', '');
$oEvent->set('errorMessageBody', gT("Failed to add user"));
return;
}
@Permission::model()->setGlobalPermission($iNewUID, 'auth_db');
$oEvent->set('newUserID', $iNewUID);
$oEvent->set('newPassword', $new_pass);
$oEvent->set('newEmail', $new_email);
$oEvent->set('newFullName', $new_full_name);
$oEvent->set('errorCode', self::ERROR_NONE);
}
public function beforeDeactivate()
{
$this->getEvent()->set('success', false);
// Optionally set a custom error message.
$this->getEvent()->set('message', gT('Core plugin can not be disabled.'));
}
public function beforeLogin()
{
// We can skip the login form here and set username/password etc.
$request = $this->api->getRequest();
if (!is_null($request->getParam('onepass'))) {
// We have a one time password, skip the login form
$this->setOnePass($request->getParam('onepass'));
$this->setUsername($request->getParam('user'));
$this->setAuthPlugin(); // This plugin will handle authentication and skips the login form
}
}
/**
* Get the onetime password (if set)
*
* @return string|null
*/
protected function getOnePass()
{
return $this->_onepass;
}
public function newLoginForm()
{
$sUserName = '';
$sPassword = '';
if (Yii::app()->getConfig("demoMode") === true && Yii::app()->getConfig("demoModePrefill") === true) {
$sUserName = Yii::app()->getConfig("defaultuser");
$sPassword = Yii::app()->getConfig("defaultpass");
}
$this->getEvent()->getContent($this)
->addContent(CHtml::tag('span', array(), "<label for='user'>" . gT("Username") . "</label>" . CHtml::textField('user', $sUserName, array('size' => 240, 'maxlength' => 240, 'class' => "form-control ls-important-field"))))
->addContent(CHtml::tag('span', array(), "<label for='password'>" . gT("Password") . "</label>" . CHtml::passwordField('password', $sPassword, array('size' => 240, 'maxlength' => 240, 'class' => "form-control ls-important-field"))));
}
public function newUserSession()
{
// Do nothing if this user is not Authdb type
$identity = $this->getEvent()->get('identity');
if ($identity->plugin != 'Authdb') {
return;
}
// Here we do the actual authentication
$username = $this->getUsername();
$password = $this->getPassword();
$onepass = $this->getOnePass();
$user = $this->api->getUserByName($username);
if ($user === null) {
$user = $this->api->getUserByEmail($username);
if (is_object($user)) {
$this->setUsername($user->users_name);
}
}
if ($user !== null && $user->uid != 1 && !Permission::model()->hasGlobalPermission('auth_db', 'read', $user->uid)) {
$this->setAuthFailure(self::ERROR_AUTH_METHOD_INVALID, gT('Internal database authentication method is not allowed for this user'));
return;
}
if ($user === null) {
$this->setAuthFailure(self::ERROR_USERNAME_INVALID);
return;
}
if ($user !== null && ($username != $user->users_name && $username != $user->email)) {
// Control of equality for uppercase/lowercase with mysql
$this->setAuthFailure(self::ERROR_USERNAME_INVALID);
return;
}
if ($user->isExpired()) {
// TODO: Should we show the actual error? Taking a conservative approach of not revealing the actual cause for now.
$this->setAuthFailure(self::ERROR_USERNAME_INVALID);
return;
}
if ($onepass != '' && $this->api->getConfigKey('use_one_time_passwords') && hash('sha256', $onepass) == $user->one_time_pw) {
$user->one_time_pw = '';
$user->save();
$this->setAuthSuccess($user);
return;
}
if (!$user->checkPassword($password)) {
$this->setAuthFailure(self::ERROR_PASSWORD_INVALID);
return;
}
$this->setAuthSuccess($user);
}
/**
* Set the onetime password
*
* @param string $onepass
* @return Authdb
*/
protected function setOnePass($onepass)
{
$this->_onepass = $onepass;
return $this;
}
// Now the export part:
public function listExportOptions()
{
$event = $this->getEvent();
$type = $event->get('type');
switch ($type) {
case 'csv':
$event->set('label', gT("CSV"));
$event->set('default', true);
break;
case 'xls':
$label = gT("Microsoft Excel");
if (!function_exists('iconv')) {
$label .= '<font class="warningtitle">' . gT("(Iconv Library not installed)") . '</font>';
}
$event->set('label', $label);
break;
case 'doc':
$event->set('label', gT("Microsoft Word"));
$event->set('onclick', 'document.getElementById("answers-long").checked=true;document.getElementById("answers-short").disabled=true;');
break;
case 'pdf':
$event->set('label', gT("PDF"));
break;
case 'html':
$event->set('label', gT("HTML"));
break;
case 'json':
$event->set('label', gT("JSON"));
break;
default:
break;
}
}
/**
* Registers this export type
*/
public function listExportPlugins()
{
$event = $this->getEvent();
$exports = $event->get('exportplugins');
// Yes we overwrite existing classes if available
$className = get_class($this);
$exports['csv'] = $className;
$exports['xls'] = $className;
$exports['pdf'] = $className;
$exports['html'] = $className;
$exports['json'] = $className;
$exports['doc'] = $className;
$event->set('exportplugins', $exports);
}
/**
* Returns the required IWriter
*/
public function newExport()
{
$event = $this->getEvent();
$type = $event->get('type');
switch ($type) {
case "doc":
$writer = new DocWriter();
break;
case "xls":
$writer = new ExcelWriter();
break;
case "pdf":
$writer = new PdfWriter();
break;
case "html":
$writer = new HtmlWriter();
break;
case "json":
$writer = new JsonWriter();
break;
case "csv":
default:
$writer = new CsvWriter();
break;
}
$event->set('writer', $writer);
}
/**
* @inheritdoc
*/
public static function getAuthMethodName()
{
// Using string literal here so it can be picked by translation bot
return gT('LimeSurvey internal database');
}
}