Bypassing the MODX Manager Login III

Using a single plugin to create and authenticate users


In the previous two articles, we saw how to bypass the MODX Manager login and create users if they are not already in the database. We used two separate plugins to do the job, but it's just as easy to do it with one plugin attached to both OnBeforeManagerLogin and OnManagerAuthentication. We'll see how to do that in this article.


Which System Event Fired?

This is easy because when the code of any plugin executes, MODX sets the name of the current event in $modx->event->name. All we need is to combine the code from the two plugins in a switch statement like the one below


The New Plugin Code

We'll put the code of our two previous plugins inside a single switch statement. It's a good idea to put the code sections in the order that the plugins fire. It's not necessary, but it makes it easier to follow what's happening. We'll also set the users to active once they're authenticated by your custom code.

We've also added an $output variable to clean up the code so we can set the output at the end of the plugin (except for the return in the first section if the user is already in the database).

<?php



/* Get the event name */
$eventName = $modx->event->name;

/* Run the code appropriate to the event */
switch($eventName) {
    case 'OnBeforeManagerLogin':

        /* Return if the user is already in the database */
        /** @var $username string */

        $existingUser = $modx->getObject('modUser', array ('username' => $username));
        if ($existingUser) {
           $modx->event->_output = false; /* allow login */
           return;
        }

        /* Generate a random, 50 character password */
        $password = "";
        for($i=0;$i<50;$i++) {
            $password .= chr( (mt_rand(1, 36) <= 26) ? mt_rand(97, 122) : mt_rand(48, 57 ));
        }

        /* Create the new user */

        $fields = array(
            'username' => $username,
            'password' => $password,
            'blocked' => '0',
            'email' => 'nobody@nowhere.com',
            'passwordnotifymethod' => 'x',
        );

        $usr = $modx->newObject('modUser');
        $usr->fromArray($fields);
        if (! $usr->save()) {
            $modx->log(modX::LOG_LEVEL_ERROR, '[OnBeforeManagerLogin] Could not save user');
            $output = true; /* prevent login */
        } else {
            $output = false;
        }
        break;


    case 'OnManagerAuthentication':
        $authenticated = false;

        /* Your authentication code here sets $authenticated to true if the
           user should be allowed to log in */

        /* Set authentic user to active if not already active */
        if ($authenticated) {
            if (! $user->get('active')) {
                $user->set('active', '1');
                $user->save();
            }
        }

        $output = (bool)$authenticated;
        break;
}

$modx->event->_output = $output;
return;

We did not send a value for the active field. It defaults to false and we could have set the user to active by sending a value of '1', but it's usually better to do that in the second part of the code, after the user has been authenticated by your custom method. That way, the users who are not valid users will remain inactive.


Cleaning Up

As I mentioned in the previous article, one down side to this method is that every user who tries to log in will end up as a user in the database (even if the attempted login is from a bot). Those users will remain as inactive and will never be allowed to log in, but they're still there unless you remove them. As a reminder, here is the simple utility snippet that will remove all inactive users.

/* Utility snippet to remove inactive users */
$users = $modx->getCollection('modUser', array('active' => false));
foreach ($users as $user) {
    $user->remove();
}



Comments (0)


Please login to comment.

  (Login)