Volto - Lead Image of private content is not shown in block for authenticated

I created a block that shows the Lead Image of a content. It generates the following image:

<img class="my-class" src="/folder/content/@@images/image" alt="">

This image is not seen by an authenticated user if /folder/content is not published. A permission error occurs but the user is authenticated. Isn't the authentication token passed in this request? If the user publishes the content, the image becomes visible.

hum, I see that the auth token is passed in the request. So it's a problem between Volto and Plone. I see a permission error in Plone:

Traceback (innermost last):

Module ZPublisher.WSGIPublisher, line 167, in transaction_pubevents
Module ZPublisher.WSGIPublisher, line 376, in publish_module
Module ZPublisher.WSGIPublisher, line 255, in publish
Module ZPublisher.BaseRequest, line 515, in traverse
Module ZPublisher.BaseRequest, line 340, in traverseName
Module plone.namedfile.scaling, line 383, in publishTraverse
Module plone.namedfile.scaling, line 448, in guarded_orig_image
zExceptions.unauthorized.Unauthorized: You are not allowed to access 'image' in this context

can you enable verbose security? Maybe you'll end up here:

It happened to me recently. I tried to create an intranet with all folders private but I had to publish the first level folder otherwise users got Unauthorized when saving (they can edit, but saving lead to the error).
Check also if the linkintegrity came in, because it tries to """ traverse to given path and find the upmost object """ in:

I enabled verbose security and it showed the following error:

2022-05-12 11:50:44,728 ERROR   [Zope.SiteErrorLog:35][waitress-3] Unauthorized: http://localhost:8080/Plone/++api++/nova-noticia/@@images/image
Traceback (innermost last):
  Module ZPublisher.WSGIPublisher, line 167, in transaction_pubevents
  Module ZPublisher.WSGIPublisher, line 376, in publish_module
  Module ZPublisher.WSGIPublisher, line 255, in publish
  Module ZPublisher.BaseRequest, line 515, in traverse
  Module ZPublisher.BaseRequest, line 340, in traverseName
  Module plone.namedfile.scaling, line 383, in publishTraverse
  Module plone.namedfile.scaling, line 448, in guarded_orig_image
  Module AccessControl.ImplPython, line 768, in guarded_getattr
  Module AccessControl.ImplPython, line 710, in aq_validate
  Module AccessControl.ImplPython, line 598, in validate
  Module AccessControl.ImplPython, line 480, in validate
  Module AccessControl.ImplPython, line 847, in raiseVerbose
zExceptions.unauthorized.Unauthorized: Your user account does not have the required permission.  Access to 'image' of (FolderishNewsItem at /Plone/nova-noticia) denied. Your user account, Anonymous User, exists at (unknown). Access requires Access_contents_information_Permission, granted to the following roles: ['Contributor', 'Editor', 'Manager', 'Owner', 'Reader', 'Site Administrator']. Your roles in this context are ['Anonymous']

Even though I am logged in as Manager this error occurs. It seems that Volto doesn't pass the auth token to Plone.

In my case, I'm just trying to show the image. I'm not saving the content. I'm not trying to delete the content either. So I don't think it's related to linkintegrity.

1 Like

I confirmed that Volto passes the authentication token to Plone. I tried with curl and I couldn't access it either:

$ curl -u admin:admin http://localhost:8080/Plone/+api++/nova-noticia/@@images/image -H "Accept: application/json"
{
  "message": "You are not allowed to access 'image' in this context",
  "type": "Unauthorized"
}

This seems to be some security rule. @mauritsvanrees @tisto do you know anything about it?

1 Like

At least in your curl line, it looks like the user auth is not valid.

Most likely not the problem, but

There is a typo here. It should be ++api++

Also, if you use the ++api++ traversal, you do not need to pass the header -H "Accept: application/json"

Hey @wesleybl in fact that block you are trying to create is already in core:

It should work the way you we trying. The ++api++ traversal puts the "Accept: application/json" for you, so it's not required. Keep an eye to the typo @ericof pointed out.

However, the recommended way to access the backend images/files are using the passthrough that the Volto SSR server provides. So you can safely use it in your src html properties without further ado.

in this case, you were doing right, because the only requisite is that you use the SSR server to request it, so the relative path is fine.

See:

The flattenToAppURL helper is used to strip down the API URL and convert it to relative (ready to use by the SSR server).

Maybe the problems with security have another reason to be?

1 Like

@tiberiuichim in fact, this error occurs both in the curl request and in the Volto request. But in both cases the user exists and is a Manager. So this is weird for me.

Hi @ericof ! I did not know that. But the result was the same:

$ curl -u admin:admin http://localhost:8080/Plone/++api++/nova-noticia/@@images/image
{
  "message": "You are not allowed to access 'image' in this context",
  "type": "Unauthorized"
}

@sneridagh the Lead Image block is meant to be used on the object that contains the image. What I'm trying to do is a highlight block for the portal home.

In the Lead Image block, the image is loaded in private objects, because we are in the object that contains the image and so we have properties.image, being possible to call properties.image.dowload, as you showed above. Even the url generated by properties.image.dowload has the format:

<img class="" src="/nova-noticia/@@images/451655fa-3676-4763-b794-5806c11f6e19.png" alt="ffgfg">

But as I showed, not even with the curl command I can access the image.

@mauritsvanrees what is preventing url access:

http://localhost:8080/Plone/++api++/nova-noticia/@@images/image

even with User Manager is this commit:

When I use the previous code:

value = getattr(self.context, name)

I can access the url. Is this a security issue? Is there a way to access the image?

The URL should not have ++api++ in it. The api traverser is used for "plone.restapi api endpoints", things that return JSON. When running in development, Volto includes a proxy that serves the @@image bytes through the nodejs server, but in production you will probably serve those bits by connecting the backend Plone server to the HTTP server (nginx, apache), and use rewrite rules for that.

2 Likes

The url that is in the html generated by Volto does not have ++api++. It looks like this:

<img class="my-class" src="/folder/content/@@images/image" alt="">

I only did the test with ++api++, because I saw that Volto makes this request to Plone.

Is there any documentation on this?

But even accessing Plone directly, we still have permission issues:

$ curl -u admin:admin http://localhost:8080/Plone/nova-noticia/@@images/image
{"error_type": "Unauthorized"}

I created a classic Plone site (coredev buildout), and a test type with two image fields. I added a private instance. Accessing as anonymous fails:

$ curl http://localhost:8080/Plone/++api++/seeing-double/@@images/image_1/preview
{
  "message": "You are not allowed to access 'image_1' in this context",
  "type": "Unauthorized"
}

Accessing as Manager works:

$ curl -u admin:admin -o out.jpeg http://localhost:8080/Plone/++api++/seeing-double/@@images/image_1/preview
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  935k  100  935k    0     0  65.2M      0 --:--:-- --:--:-- --:--:-- 65.2M
$ ls -lh out.jpeg 
-rw-r--r--  1 maurits  staff   936K 16 May 16:30 out.jpeg

So it seems to work fine from this point of view.
I might be missing something Volto related.

I tested it with News Item in Plone Classic and had the same problem. What version of plone.namedfile were you using? The problem occurs with plone.namedfile 6.0.0a3 (Plone 6.0.0a4).

I used the same versions. Trying it again now, with this buildout:

[buildout]
extends = https://dist.plone.org/release/6.0.0a4/versions.cfg
parts = instance

[instance]
recipe = plone.recipe.zope2instance
user = admin:admin
eggs =
    Plone

and then:

python3.9 -mvenv .
pip install -r https://dist.plone.org/release/6.0.0a4/requirements.txt
bin/buildout
bin/instance fg

Create a classic Plone Site, go to news folder add News Item with an image, leave this private. The following then works fine for me:

curl -u admin:admin http://localhost:8080/Plone/++api++/news/item
curl -u admin:admin -o foo.jpeg http://localhost:8080/Plone/news/item/@@images/76095987-012b-4331-8721-86dc11b56ea4.jpeg
curl -u admin:admin -o foo.jpeg http://localhost:8080/Plone/++api++/news/item/@@images/76095987-012b-4331-8721-86dc11b56ea4.jpeg
curl -u admin:admin -o foo.jpeg http://localhost:8080/Plone/++api++/news/item/@@images/image/thumb

As anonymous I get Unauthorized, which is what I expect:

curl http://localhost:8080/Plone/++api++/news/item/@@images/76095987-012b-4331-8721-86dc11b56ea4.jpeg
{
  "message": "You are not allowed to access 'image' in this context",
  "type": "Unauthorized"
}

These URLS worked for me too. The URL that is giving the problem is when I try to get the image in its original size:

$ curl -u admin:admin http://localhost:8080/Plone/news/item/@@images/image
{"error_type": "Unauthorized"}

Note that I am not using the -o parameter.

Ah, right, now I see what you mean and why it goes wrong. The code uses guarded_getattr in the publishTraverse method. In that method you are always anonymous. We should restore the original code indeed.
Well, it should be a small method just like guarded_orig_image, maybe get_orig_image. Then other code (for example for images in tiles) can override it where needed.

I checked: with the restored code, admin can get the image, and anonymous still not. So that is good.

1 Like

@tiberiuichim There is a problem when requesting images of private content directly to the backend:

Any tips?

@wesleybl I just stumbled upon this. You were correct... something is wrong with a Plone 6 backend.

Did you go farther with your investigations? @mauritsvanrees so did we changed something in the backend? In Plone 5 the workaround worked well the last years.

@sneridagh the issue of images of private content not appearing for authenticated users has been fixed in:

This fix is in plone.namedfile 6.0.0a4. It wasn't a problem with Volto but with Plone.

However, I'm still intrigued when @tiberiuichim suggests to access images directly in Plone, even using Volto:

It looks like there was an attempt to do this in the frontend docker, but we have problems passing the token from the webserver to Plone, and the authenticated user cannot access the image without going through Volto. To see:

Do you know anything about it?

1 Like