Can't protect a page against public access

Hi all and a happy and successful 2025!

I have a site with version 3.1.0 and only a single context (web). There is a page, not visible in the menu, not reachable via a link, not listed in the sitemap. You can reach it only via a URL you need to know.

I followed the known tutorials:
https://docs.modx.com/3.x/en/building-sites/client-proofing/security/security-tutorials/making-member-only-pages
and

and also read this old forums post:

For me all seems correct: a resource group was created. The “private” resource is assigned to this group. I have a user group with a singel user. The resource group ha access to context “web” for member role (9999) with policy “resource”.

All permissions have been flushed, all users have been logged out the cache of the site has been cleared also the browser cache.
Nevertheless, I can access the page directly via its URL.

What can I do, where might there be faults?

Do you test it while being logged in to the MODX manager? If you’re a sudo user, this might affect the result.
Did you test it in a new private browser window or a different browser?

I was logged out and cleared the cache and the cookies.
I tested it in private windows and different browsers. All the same result.
(It’s crazy, I know.)

It’s potentially a bug in MODX 3.1.0 (which would be very bad).
I have to look further into it, but something seems to be wrong.

1 Like

It’s the first time I try to protect pages, therefore I tried the process multiple times with different names for resource groups, user groups and so on. Always the same result.

Yes something is weird.
It works when I try it in MODx 3.0.6, but the same process in MODX 3.1.0 fails.
Unfortunately I haven’t figured out yet what breaks the protection of the page.

I was afraid that I was being too stupid. But it’s good to know that it’s probably a bug in the system after all. And good that it has now been discovered.

There doesn’t seem to be a bug after all.
In my case, it was just a caching issue and after clearing the cache, it works now as expected.

As you did clear the cache, it’s probably a different issue.

Your user group (anonymous), does it have any access permissions to the resource group?

I cleared the cache via the system, via FTP and via data manager of the provider.

The user group “anonymous” doesn’t have any permissions to the defined resource group. There is only a single access permission defined for a single created user. Later this user gets a login page but now I want to test protecting pages to all frontend users as a first step.

Can you check the cache file of your protected resource in the cache folder:
core/cache/resource/web/resources/<id>.cache.php (<id> is the resource ID).
Is there a section 'policyCache' => in this file that contains more than an empty array?


Only user groups have permissions.
So you have a user group, that has access to the resource group (Access Policy = Resource; Context = web) and a user is a member of this group?


When you put tags like these on your protected resource and request it, what is the output?

User-ID: [[!+modx.user.id]]<hr>
Log-in status: [[!+modx.user.id:isloggedin:is=`1`:then=`logged in`:else=`NOT logged in`]]

Is the user ID = 0 and the status “NOT logged in”?

The cache file of the (not) protected resource has a section policyCache with an array that’s not empty (two sub-arrays).

Ok, you’re right: the user group has the permission and the group has a single user.
And the user group has access to the resource group with Access Policy = Resource and Context = web.

And yes: the User-ID is 0, the status is “NOT logged in”.

These screenshots look all OK. This should work.


What’s the exact content here?


What output does this tag generate when used on the ‘protected’ page?

[[!+modx.user.id:memberof=`Protected`:then=`member of 'Protected'`:else=`NO member of 'Protected'`]]

If you run an uncached snippet with code like this

<?php
$output = '';
if ($modx->resource->checkPolicy('load')) {
   $output .= "Has 'load' permission. ";
} else {
    $output .= "NO 'load' permission. ";
}

if ($modx->resource->checkPolicy('view')) {
   $output .= "Has 'view' permission. ";
} else {
    $output .= "NO 'view' permission. ";
}
return $output;

does it output that your anonymous user has both these permissions?

The content of the section in this cache file is:

  'policyCache' => 
  array (
    'MODX\\Revolution\\modAccessResourceGroup' => 
    array (
      5 => 
      array (
        0 => 
        array (
          'principal' => 1,
          'authority' => 9999,
          'policy' => 
          array (
            'add_children' => true,
            'create' => true,
            'copy' => true,
            'delete' => true,
            'list' => true,
            'load' => true,
            'move' => true,
            'publish' => true,
            'remove' => true,
            'save' => true,
            'steal_lock' => true,
            'undelete' => true,
            'unpublish' => true,
            'view' => true,
          ),
        ),
        1 => 
        array (
          'principal' => 6,
          'authority' => 9999,
          'policy' => 
          array (
            'add_children' => true,
            'create' => true,
            'copy' => true,
            'delete' => true,
            'list' => true,
            'load' => true,
            'move' => true,
            'publish' => true,
            'remove' => true,
            'save' => true,
            'steal_lock' => true,
            'undelete' => true,
            'unpublish' => true,
            'view' => true,
          ),
        ),
      ),
    ),
  ),

Hm, the output of the tag above is:

NO member of 'Protected'

The snippet returns:

Has 'load' permission. Has 'view' permission.

I’m really confused.

These settings look correct. The user groups 1 (Administrator) and 6 (Protected) have access to the resource group. The anonymous user group doesn’t.

So why has an anonymous user load and view permission?


If you give the (anonymous) user group “Load Only” permission to the resource group (which is the recommend policy for this group), does that change anything?


Are you sure you really see the protected resource Test (168)?
By default (if you have no access), it redirects to the error page (which is the home-page by default).
Did you set up specific pages for the error page and unauthorized page?

Very strange. In the ACLs for “anonymous” there is set only the “Load Only” permission (I didn’t change it).

Now I deleted the cache file of the protected resource, reloaded the resource and checked the snippet again. It says again “Has ‘load’ permission. Has ‘view’ permission.”

Yes, I see the resource 168 (the alias as the file name is correct), error page is the home page and also the unauthorized page is the same.

Ok, enough for today. Tomorrow I will test the same procedure with a site at the same provider. And then again with a third site at another provider.

Your screenshot shows the “Contexts” vertical tab.
Try adding your resource group “Protected” in the vertical tab “Resource Groups” (with the Access Policy = “Load Only”).

In the cache file of the resource, this should then add a new section to the 'policyCache' => :

...
0 => 
array (
    'principal' => 0,
    'authority' => 9999,
    'policy' => 
    array (
    'load' => true,
    ),
),
...

The URL you see in the address bar of the browser, is not necessarily the page that is shown.
When a user doesn’t have access permission, the content in the browser window is from the unauthorized/error page, but the URL (in the address bar) stays the same.

Hi, the resource group tab for Protected was right with an access policy “Resource”. I changed it now to “Load Only”.

Then I checked the cache file. There is no new section for “anonymous” (0), only the section for Protected (6) has changed to

...
array (
          'principal' => 6,
          'authority' => 9999,
          'policy' => 
          array (
            'list' => false,
            'load' => true,
            'remove' => false,
            'save' => false,
            'view' => false,
          ),
),
...

And yes, you are right, the URL shows the page but the content should be from the error/unauthorized page. But here I see the content of the “protected” page. And that meens it’s unprotected.

Later I will test the procedure with two other sites.

Same provider, second site with MODX 3.1.0 (i.e. same system), same procedure:
Result is correct, test page is protected.

Deleted test user, resource group, user group on the first site. Cleared cache internally and via FTP. Set up the procedure again like at the second site.
Result failed: test page unprotected.

Difference:

User-ID: [[!+modx.user.id]]

gives back “User-ID: 1” at the second site with protected page (for me logged in) but gives back “User-ID: 0” at the first site with unprotected page. What does this mean?

This is the ID of the user that makes the request.
(The user ID is shown in the manager under manager/?a=security/user in the first column of the grid.)

“User-ID: 1” means that the default user “admin” made the request.
“User-ID: 0” means that the request is from an anonymous user.


You want to test your configuration with the anonymous user, to see if the page access is restricted for users that are not logged in.