Admidio/admidio

View on GitHub
adm_program/system/classes/ModuleLogin.php

Summary

Maintainability
A
3 hrs
Test Coverage
<?php
use Admidio\Exception;
use Admidio\UserInterface\Form;

/**
 * Class with methods to display the login module and handle the input.
 *
 * This class adds some functions that are used in the contacts module to keep the
 * code easy to read and short
 *
 * **Code example**
 * ```
 * // generate html output with available registrations
 * $page = new ModuleContacts('admidio-contacts', $headline);
 * $page->createContentAssignUser();
 * $page->show();
 * ```
 * @copyright The Admidio Team
 * @see https://www.admidio.org/
 * @license https://www.gnu.org/licenses/gpl-2.0.html GNU General Public License v2.0 only
 */
class ModuleLogin
{
    /**
     * Constructor that initialize the class member parameters
     */
    public function __construct()
    {
    }

    /**
     * Create the html content of the login page and add it to the HtmlPage object. Beside the username and password an
     * organization select box could be shown and the flag if auto login should be activated.
     * @param HtmlPage $page Html content will be added to this page.
     * @param string $organizationShortName Optional the organization that should be preselected in the dialog.
     * @throws Exception
     */
    public function addHtmlLogin(HtmlPage $page, string $organizationShortName = '')
    {
        global $gDb, $gSettingsManager, $gL10n, $gCurrentOrganization, $gCurrentSession;

        if ($organizationShortName === '') {
            $organizationShortName = $gCurrentOrganization->getValue('org_shortname');
        }

        // read id of administrator role
        $sql = 'SELECT MIN(rol_id) as rol_id
                  FROM '.TBL_ROLES.'
            INNER JOIN '.TBL_CATEGORIES.'
                    ON cat_id = rol_cat_id
                 WHERE rol_administrator = true
                   AND (  cat_org_id = (SELECT org_id
                                          FROM '.TBL_ORGANIZATIONS.'
                                         WHERE org_shortname = ? /* $gCurrentOrgId */)
                       OR cat_org_id IS NULL )';
        $pdoStatement = $gDb->queryPrepared($sql, array($organizationShortName));

        // create role object for administrator
        $roleAdministrator = new TableRoles($gDb, (int) $pdoStatement->fetchColumn());

        // show link if user has login problems
        if ($gSettingsManager->getBool('enable_password_recovery') && $gSettingsManager->getBool('system_notifications_enabled')) {
            // request to reset the password
            $forgotPasswordLink = ADMIDIO_URL.FOLDER_SYSTEM.'/password_reset.php';
        } elseif ($gSettingsManager->getBool('enable_mail_module') && $roleAdministrator->getValue('rol_mail_this_role') == 3) {
            // show link of message module to send mail to administrator role
            $forgotPasswordLink = SecurityUtils::encodeUrl(ADMIDIO_URL.FOLDER_MODULES.'/messages/messages_write.php', array('role_uuid' => $roleAdministrator->getValue('rol_uuid'), 'subject' => $gL10n->get('SYS_LOGIN_PROBLEMS')));
        } else {
            // show link to send mail with local mail-client to administrator
            $forgotPasswordLink = SecurityUtils::encodeUrl('mailto:'.$gSettingsManager->getString('email_administrator'), array('subject' => $gL10n->get('SYS_LOGIN_PROBLEMS')));
        }

        // show form
        $form = new Form(
            'loginForm',
            'system/login.tpl',
            ADMIDIO_URL.'/adm_program/system/login.php?mode=check',
            $page,
            array('showRequiredFields' => false)
        );

        $form->addInput(
            'usr_login_name',
            $gL10n->get('SYS_USERNAME'),
            '',
            array('maxLength' => 254, 'property' => Form::FIELD_REQUIRED)
        );
        $form->addInput(
            'usr_password',
            $gL10n->get('SYS_PASSWORD'),
            '',
            array(
                'type' => 'password',
                'property' => Form::FIELD_REQUIRED,
                'helpTextId' => '<a href="' . $forgotPasswordLink . '">' . $gL10n->get('SYS_PASSWORD_FORGOTTEN') . '</a>'
            )
        );

        // show selectbox with all organizations of database
        $sql = 'SELECT org_shortname, org_longname
                  FROM '.TBL_ORGANIZATIONS.'
              ORDER BY org_longname, org_shortname';
        $form->addSelectBoxFromSql(
            'org_shortname',
            $gL10n->get('SYS_ORGANIZATION'),
            $gDb,
            $sql,
            array('property' => Form::FIELD_REQUIRED, 'defaultValue' => $organizationShortName)
        );

        $form->addCheckbox('auto_login', $gL10n->get('SYS_REMEMBER_ME'));
        $form->addSubmitButton('btn_login', $gL10n->get('SYS_LOGIN'), array('icon' => 'bi-box-arrow-in-right', 'class' => 'offset-sm-3'));
        $form->addToHtmlPage();
        $gCurrentSession->addFormObject($form);
    }

    /**
     * Check if a user with that username exists and the password is set correct. If the user choose a different
     * organization than the session data will be updated.
     * @return bool Returns **true** if the login data are valid
     * @throws Exception
     */
    public function checkLogin(): bool
    {
        global $gDb, $gCurrentOrganization, $gCurrentOrgId, $gProfileFields, $gCurrentSession, $gSettingsManager;
        global $gMenu, $gCurrentUser, $gCurrentUserId, $gCurrentUserUUID;

        // check form field input and sanitized it from malicious content
        $loginForm = $gCurrentSession->getFormObject($_POST['admidio-csrf-token']);
        $formValues = $loginForm->validate($_POST);

        $postLoginName = ($formValues['usr_login_name'] ?? $formValues['plg_usr_login_name']);
        $postPassword = ($formValues['usr_password'] ?? $formValues['plg_usr_password']);
        $postOrgShortName = ($formValues['org_shortname'] ?? $formValues['plg_org_shortname']);
        $postAutoLogin = ($formValues['auto_login'] ?? $formValues['plg_auto_login']);

        // Search for username
        $sql = 'SELECT usr_id
              FROM ' . TBL_USERS . '
             WHERE UPPER(usr_login_name) = UPPER(?)';
        $userStatement = $gDb->queryPrepared($sql, array($postLoginName));

        if ($userStatement->rowCount() === 0) {
            throw new Exception('SYS_LOGIN_USERNAME_PASSWORD_INCORRECT');
        }

        // if login organization is different to organization of config file then create new session variables
        if ($postOrgShortName !== '' && $postOrgShortName !== $gCurrentOrganization->getValue('org_shortname')) {
            // read organization of config file with their preferences
            $gCurrentOrganization->readDataByColumns(array('org_shortname' => $postOrgShortName));
            $gCurrentOrgId = $gCurrentOrganization->getValue('org_id');

            // read new profile field structure for this organization
            $gProfileFields->readProfileFields($gCurrentOrgId);

            // save new organization id to session
            $gCurrentSession->setValue('ses_org_id', $gCurrentOrgId);
            $gCurrentSession->save();

            // read all settings from the new organization
            $gSettingsManager = new SettingsManager($gDb, $gCurrentOrgId);
        }

        // remove all menu entries
        $gMenu->initialize();

        // create user object
        $gCurrentUser = new User($gDb, $gProfileFields, (int) $userStatement->fetchColumn());
        $gCurrentUserId = $gCurrentUser->getValue('usr_id');
        $gCurrentUserUUID = $gCurrentUser->getValue('usr_uuid');

        return $gCurrentUser->checkLogin($postPassword, $postAutoLogin);
    }
}