Password protect entire site

How can I password protect an entire in an easy way? I don’t want to create users, just a password will do.
I found this ‘the easy way’ page, but it doesn’t sound easy at all:
https://modx.com/blog/create-protected-pages-the-easy-way

You can use a .htpasswd file placed above the site root and refer to it in your .htaccess file as…

AuthName "Authorisation Required"
AuthUserFile "/just/above/site/root/.htpasswd"
AuthType Basic
require valid-user
ErrorDocument 401 "Authorisation Required"

You can create a .htpasswd here: Htpasswd Generator – Create htpasswd - hostingcanada.org

There are more sites on the URL, so I’d rather not use htaccess

You only need to add it to the htaccess file of the one site you need to protect

Sorry, that’s not gonna work with the other sites running in the same directory.

I just want to find out how this can be achieved from within MODX.

The thing is - without creating and maintaining sessions [like MODX’s security system does] - any password protection is going to apply only to one page at a time and even if the user left that page and then revisited - they’d need to input the password again.

For instance, replace your [[*content]] tag with this

        [[!are-we-authed:is=`1`:then=`
        	[[*content]]
		`:else=`
			<p>You must provide a password to access this content</p>
			<form method="post" action="[[~[[*id]]]]">
				<input type="password" name="authpw" />
				<input type="submit" value="Go" />
			</form>
		`]]

Create snippet “are-we-authed”:

<?php
if 	(isset($_POST["authpw"])) {
    $pw = $_POST["authpw"];
	if ($pw == "thecorrectpassword") {
		$authed = 1;
	} else {
		$authed = 0;
	}
}

return $authed;

This works in a very simplistic way but I think you’ll very soon find yourself trying to reinvent the wheel [or in this case, MODX’s security system] in order to iron out its many shortcomings.

I know you said you didn’t want to create users - but if you only need a single user / password, why not create it and restrict the content to its group.

You could pre-populate / hide the username field at the login stage and just ask the users for the password.

Still a bit complicated. It would need a massive amount of actions to implement.

Is there no way to password protect a Context?

Hm, this reminded me of PageLocker but that’s a page-specific password.

There used to be a way to password protect a resource group, but I cannot find resource groups anymore in MODX3.

Would it be an option to have an access policy ‘password protect’ so you can select that for the Anonymous user group?

Resource Groups should still be found under the Content menu

I don’t have Resource groups under Contexts.

“Content” menu, not “Contexts”!

resource_groups_modx3

1 Like

You can put a tag for a simple snippet in every template. Call it CheckStatus. Users who are not logged in will be redirected to the login page without seeing the current page.

/* CheckStatus snippet (untested) */

$ctx = $modx->context->get('key');

if (! $modx->user->hasSessionContext($ctx)) {
    $modx->sendRedirect($modx->makeUrl(12, "", "", "full"));
}

Change 12 above to the ID of your Login page.

If you use &redirectTotPrior-1 in the Login snippet tag, users should be returned to the page they were trying to access once they successfully log in.

Put this tag at the top of the “body” section of your templates:

[[!CheckStatus]]

Thanks, but still too much hassle and a bit out of my league. And I don’t have a login page.

Been working on this for 3 days now, a bit frustrating MODX doesn’t offer a policy for this.

Hah. Well, I see. I missed that bit entirely. I thought when you said there are other sites you meant multi context. You can password protect subdirectories just fine with .htaccess or block all IP addressees but a few per directory and then nobody needs a password.

Or you could possibly put the site in maintenance mode and create a user group that has full accesss to unpublished resources but not grant manager context access.

Or you could possibly put the site in maintenance mode and create a user group that has full accesss to unpublished resources but not grant manager context access.

What do you mean with full access? I thought load only is sufficient?
Why unpublished resources? They should be able to see published resources.

I created a user group ‘testers’ but it did’t let me save it; it is asking for a Resource group. I now created a resource group (which is annoyingly comprehensive to litteraly drag and drop every resource in that group. And what about newly created resources?).

I gave that User group Context access to web only with access policy Load only.

The user now gets an acces denied when trying to login.

This is so complicated.

Of all the options above, why did you choose the most complicated one, with resource groups and all?

If your sites are in different subdirectories, what is the problem with using a simple .htaccess file in the subdirectory for the site you want to protect?
There is probably already a .htaccess file in that directory for the friendly URLs, that you could temporarily append to control the access.

What steps do I miss?

I tried every option mentioned above, but they all render errors, empty pages, etc. It feels I’m missing steps.

I also moved the MODX site to a subdir (emptied cache, updated all URL’s in config files), but ended up with empty pages. So it’s a frustrating process, that has been going on for 5 days now.
Wordpress is 3 mins work to setup a password protected website.

Here is some code that is based on the PageLocker extra that Mark linked above. I simplified the code to “protect” the whole site.


Create a new resource with this content, so the users can fill in the password somewhere.

<p>This site is password-protected. Please enter your password.</p>
<form action="" method="post">
    <label for="password">Password:</label>
    <input name="password" type="password" />
    <input type="submit" value="Submit" name="passwordSubmit" />
</form>

Create a new plugin with this code. Tick the checkbox for OnWebPagePrerender. Change the password and the “ID of the resource with the password form” on lines 5 and 6.

<?php
$eventName = $modx->event->name;
switch($eventName) {
    case 'OnWebPagePrerender':
        $sitePW = "mysupersecretpassword"; //CHANGE THIS!
        $formResourceID = 123; //CHANGE THIS!
        
        if (!function_exists("toForm")) {
            // Show Login form
            function toForm($resourceId) {
                global $modx;
                unset($_SESSION['password']);  // make sure password is not still set
                if ($modx->resource->get('id') != $resourceId) { // prevent infinite loop
                    $modx->sendForward($resourceId);
                }
            }
        }
        
        if ($modx->resource->get('id') == $formResourceID) { // no access control for resource with password form
            return;
        }
        
        $userPW = isset($_POST['password']) ? filter_var($_POST['password'], FILTER_SANITIZE_STRING) : '';
        if (!empty($userPW)) { // Form was submitted
            if ($userPW == $sitePW) {
                $_SESSION['loggedin'] = 1;
                return;
            } else { // Doesn't match. Back to the form!
                toForm($formResourceID);      
            }
        }  else { // Form wasn't submitted, so check loggedin in the session
            if ( !isset($_SESSION['loggedin']) || !$_SESSION['loggedin'] === 1 ) {
                toForm($formResourceID);
            } 
        }
        break;
}

This solution is not really secure (uses a plain text password) but to “secure” the site during development it should work. And you don’t have to create any users.

1 Like