craftcms / cms

Build bespoke content experiences with Craft.
https://craftcms.com
Other
3.26k stars 633 forks source link

Not authorized to reorder structure entries #2772

Open ghost opened 6 years ago

ghost commented 6 years ago

Description

Somehow I can't reorder structure entries on our staging server. In the red bar a message appears with an unknow error occured. Seems like a bug. I am logged in as a administrator/super user.

Stack trace

2018-04-18 17:24:16 [217.100.226.36][1][1rprs6qtr941te0urqodf1tqgc][error][yii\web\HttpException:403] yii\web\ForbiddenHttpException: User is not authorized to perform this action in /var/www/vhosts/site.com/httpdocs/vendor/craftcms/cms/src/web/Controller.php:187
Stack trace:
#0 /var/www/vhosts/site.com/httpdocs/vendor/craftcms/cms/src/controllers/StructuresController.php(67): craft\web\Controller->requireAuthorization('editStructure:3')
#1 /var/www/vhosts/site.com/httpdocs/vendor/yiisoft/yii2/base/BaseObject.php(109): craft\controllers\StructuresController->init()
#2 /var/www/vhosts/site.com/httpdocs/vendor/yiisoft/yii2/base/Controller.php(86): yii\base\BaseObject->__construct(Array)
#3 [internal function]: yii\base\Controller->__construct('structures', Object(craft\web\Application), Array)
#4 /var/www/vhosts/site.com/httpdocs/vendor/yiisoft/yii2/di/Container.php(375): ReflectionClass->newInstanceArgs(Array)
#5 /var/www/vhosts/site.com/httpdocs/vendor/yiisoft/yii2/di/Container.php(156): yii\di\Container->build('craft\\controlle...', Array, Array)
#6 /var/www/vhosts/site.com/httpdocs/vendor/yiisoft/yii2/BaseYii.php(345): yii\di\Container->get('craft\\controlle...', Array)
#7 /var/www/vhosts/site.com/httpdocs/vendor/yiisoft/yii2/base/Module.php(642): yii\BaseYii::createObject('craft\\controlle...', Array)
#8 /var/www/vhosts/site.com/httpdocs/vendor/yiisoft/yii2/base/Module.php(596): yii\base\Module->createControllerByID('structures')
#9 /var/www/vhosts/site.com/httpdocs/vendor/yiisoft/yii2/base/Module.php(522): yii\base\Module->createController('move-element')
#10 /var/www/vhosts/site.com/httpdocs/vendor/craftcms/cms/src/web/Application.php(267): yii\base\Module->runAction('structures/move...', Array)
#11 /var/www/vhosts/site.com/httpdocs/vendor/craftcms/cms/src/web/Application.php(515): craft\web\Application->runAction('structures/move...', Array)
#12 /var/www/vhosts/site.com/httpdocs/vendor/craftcms/cms/src/web/Application.php(251): craft\web\Application->_processActionRequest(Object(craft\web\Request))
#13 /var/www/vhosts/site.com/httpdocs/vendor/yiisoft/yii2/base/Application.php(386): craft\web\Application->handleRequest(Object(craft\web\Request))
#14 /var/www/vhosts/site.com/httpdocs/web/index.php(21): yii\base\Application->run()
#15 {main}

Additional info

brandonkelly commented 6 years ago

Weird. Is it working on any other environments for you? Do you have any config settings in config/general.php that are unique to the staging environment?

ghost commented 6 years ago

Sorry for my late reaction. I hoped that an update would solve the problem.. but no luck. The config settings are identical. I guess something to do with the database? (I was developing this website on a RC version)

For example: as an admin I can create a new user, but i can't link a new user to a user-group. An error message appears "Only administrators are authorized"..?

brandonkelly commented 6 years ago

Any chance we can get access to the server? If so you can send credentials to support@craftcms.com.

ghost commented 6 years ago

Thanks, mail has been sent.

Emkaytoo commented 6 years ago

I referenced a similar error in #2958 (I searched like 5 or 6 different queries to find duplicates but didn't see any that matched my queries. Sorry.)

askogrand commented 6 years ago

I am experiencing the same error. Almost identical setup on staging, where we can re-order, but cannot reorder on production.

jasonandres commented 6 years ago

I have the same issue, the stack trace is the same.

2018-06-07 15:38:46 [205.250.0.226][1][-][error][yii\web\HttpException:403] yii\web\ForbiddenHttpException: User is not authorized to perform this action in /usr/share/craftsites/wildhorse/vendor/craftcms/cms/src/web/Controller.php:214

Application Info

brandonkelly commented 6 years ago

@beeldr @Emkaytoo @askogrand @jasonandres Are your production environments load-balanced? Are you aware of whether each of the servers storing session data in the same place, regardless of web server?

askogrand commented 6 years ago

Yes, they are load balanced. They are storing session data in their respective projects memcached cloud servers. They do not share the same one.

brandonkelly commented 6 years ago

I think that’s your issue. Permission to modify structures is stored in the PHP session. So when this happens, it’s probably because the Ajax request to modify the structure is hitting a different web server than the one that initially authorized the action.

If you’re going to use load-balanced web servers, you need to make sure that they share the same PHP session, by pointing them to the same Redis/Memcached server.

askogrand commented 6 years ago

Production and staging are different sites. Different memcaches. Their respective dynos all use the same memcache server. I apologize if my answer was confusing.

jasonandres commented 6 years ago

@brandonkelly Our sites are running on a single instance, and we are not utilizing Redis/Memcached.

brandonkelly commented 6 years ago

If any of you can give us an admin account + FTP access to your server where this is happening, that would be super helpful. We’re not able to reproduce.

askogrand commented 6 years ago

@brandonkelly has anyone provided anything to you yet? Id give you access to our admin, but we are running on heroku, so no FTP. We do have a bugsnag accout, however.

brandonkelly commented 6 years ago

Not yet. Having access to the environment will be critical. Could be SSH instead if FTP isn’t an option.

askogrand commented 6 years ago

@jasonandres Any chance you can get your creds to Brandon? Ive tried with our environment, but Im afraid the heroku/load balancing is obfuscating the issue. @beeldr, maybe you can share creds as well?

jasonandres commented 6 years ago

@brandonkelly We moved our staging environment from a single instance to load balanced instances running on Amazon ECS, with EFS for client assets and Aurora MySQL using the same Dockerfile for the build and now we don't have this issue, we can re-order entries just fine.

Unfortunately we torn down the other staging environment so we no longer have access to that.

jasonschock commented 6 years ago

Same issue today on Fortrabbit's Pro tier. Works locally.

Anyone resolve this?

It seems to be specific to the POST <DOMAIN>/index.php?p=admin/actions/structures/move-element call. I see tons of other ajax requests happening with a 200 response, but when I try to reorder, I get a 403.

If I force-clear the cache in Chrome, reorder succeeds on the first try. All subsequent trie then fail with a 403.

pr1ntr commented 5 years ago

I get this error from a single docker container. No load balancer. I am using a bridge network driver for the docker-compose setup

kristoferblack commented 5 years ago

I'm having the same issue on on Fortrabbit Pro tier that @jasonschock is having. Reorder attempts results in a 403.

jasonschock commented 5 years ago

FWIW, I solved my issue with this Craft plugin: https://github.com/fortrabbit/yii-memcached. FortRabbit Pro stack is multi-node. You need to use memcache for shared session storage; by default, you get PHP's file session store.

arifje commented 5 years ago

Also having this problem right now, but; it happens in Chrome (OSX) only, and it's working in Firefox and other browsers.

The difference with Chrome is that we have multiple (development) sites opened in tabs, with different domains. Maybe that has something to do with it.

Craft CMS 3.1.25 PHP 7.2 No loadbalancing, single server / domain / ip.

Logs;

Screenshot 2019-05-08 at 11 26 22

ryanpcmcquen commented 4 years ago

We are affected by this issue on Craft 3.3.20.1.

brandonkelly commented 4 years ago

We have seen this happen as a result of the defaultCookieDomain config setting getting changed. In that case, clearing browser caches will solve it.

emblematiq commented 4 years ago

Getting the same error on a multiple dyno setup in Heroku. Moving to a single dyno solves it. Does anyone have an example on how to set up redis or memcached on Heroku? Thanks in advance.

brandonkelly commented 4 years ago

@emblematiq Connecting Craft to Redis is a matter of swapping out the cache and session components with those provided by the yii2-redis library. You can find examples on https://docs.craftcms.com/v3/config/app.html.

VitaliiTsilnyk commented 2 years ago

Happened to me as well, indeed after changing the defaultCookieDomain setting. Clearing browser local storage and cookies resolved the issue.

If this helps, this is what I discovered during my debugging: Traced it back to this line in StructuresController.php. Which then calls this function. Where $this->owner->get($this->authAccessParam) returns null. Tried to change this line to $this->requirePermission('editStructure:' . $structureId); just to see what happens and it started to work as expected.

JonGoldmanPlaybill commented 2 years ago

This has been plaguing us in multiple environments. We get the 403 error in production and in our lower environments. All are using Redis for both cache and session. Production has multiple heads, lower env's do not. Lower Env's share a Redis server in AWS Elasticache, production is separate. Have tried all of the following solutions, only 1 works but is not sustainable in production:

I have seen some mention of storing cache and session in separate databases (separating databases in Redis, according to the creator, is a bad idea). Is it possible to have a different Redis host for sessions and cache? Would this have any effect on the issue?

UPDATE: I tried @VitaliiTsilnyk solution above and it works now. Is this now a PR for Craft? I do not know if previously clearing my cookies had anything to do with this. But I do know that my team's CP url is a subdomain of the main url for the site (e.g., cms.[domain].com). The lower envs are not using a different cookie domain to my knowledge.

angrybrad commented 2 years ago

@JonGoldmanPlaybill you probably need to set https://craftcms.com/docs/3.x/config/config-settings.html#defaultcookiedomain to .domain.com (notice the preceding .)

JonGoldmanPlaybill commented 2 years ago

@angrybrad Unfortunately I tried setting to both dev.[domain].com and .[domain].com (cleared cookies and cache both times before trying). My redeploy via AWS Codepipeline restored the regular code that I had hacked from @VitaliiTsilnyk idea. Server Error 403 on both attempts to reorder categories.

A note that not only is this already using Redis with a unique prefix for sessions and cache, it also is not a multi-user head- the dev instance is a single instance, using a lower env Redis from AWS ElastiCache, and it's own RDS DB server.

VitaliiTsilnyk commented 2 years ago

Please note that my idea is just an idea, not an actual solution. I was just playing around trying to fix the bug before finding this issue. I have no idea why requireAuthorization is being used instead of requirePermission, but probably there are reasons for that.

JonGoldmanPlaybill commented 2 years ago

@VitaliiTsilnyk Thank you for that. I'm less concerned in this case, because in order to even get to the CP login in the first place in our environment, you have to get past a load balancer that requires SSO Authentication. So there are two layers of authentication protecting that avenue in. I would also note that your idea is the only method that has worked, besides resorting to non-KeyStore-based session caching.

brandonkelly commented 2 years ago

There aren’t any permissions named editStructure:…. So changing that line to requirePermission() would only work if you are using an admin account, where all permissions are assumed to be granted.

We use session-based authorization here because the Structures service doesn’t know which specific permissions should be checked. So it just expects a prior controller to authorize it via the session.

JonGoldmanPlaybill commented 2 years ago

@brandonkelly Understood. Which explains why when I made that change it worked, because I am on an admin account. But I'm using the same account with the previous function call, which is what confuses me for the 403. I would understand if it was a perms issue, but with a full admin I shouldn't encounter 403s from Craft.

JonGoldmanPlaybill commented 2 years ago

@brandonkelly, also, as far as I can see, there is no controller in the way here, or any to give prior auth. This is not just any structure, but we are editing the order of categories, which we don't interfere with to my knowledge.

brandonkelly commented 2 years ago

I would understand if it was a perms issue, but with a full admin I shouldn't encounter 403s from Craft.

Session-based authorization doesn’t care if you’re an admin, unlike user permissions. So that’s why switching it to a permission check fixed it for you, even though the permission doesn’t exist.

Ultimately this is either a cookie issue or an environmental issue, where your environment is not persisting PHP session data across requests.

JonGoldmanPlaybill commented 2 years ago

@brandonkelly Actually it turned out that this was due to a data validation failure in the category. There was an illegal value that had been migrated in to a Category class and the Category Entries could not be saved. Once the data issue was corrected, then the adding of a prefix that differed between the session and cache in Redis seems to have solved the issue.

brandonkelly commented 2 years ago

Huh strange, but glad you got it sorted!

JonGoldmanPlaybill commented 2 years ago

@brandonkelly Just as a future FYI, the field was a "Color" field type and the illegal value was #black. We went into the table and replaced all the #black with #000000. Suddenly we could re-order. I figured this when I went into a category entry and tried to save it (to see if the index was maybe corrupted) and it popped an illegal value error.