django-storages: Missing S3 authentication url params for some static paths

Hello,

some static paths are being rendered without the S3 authenticatoin url params (AWSAccessKeyId, Signature and Expires). imagen

how should I debug this?

boto3==1.9.205 botocore==1.12.205 Django==2.2.4 django-tinymce==2.8.0 s3transfer==0.2.1

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 5
  • Comments: 15 (1 by maintainers)

Most upvoted comments

All the svg files that are failing for me are referenced via relative url ../ The fonts.css file that is failing internally contains similar ../ relative locations for font files.

Here is an excerpt from admin/css/base.css which is correctly loading.

.addlink {
    padding-left: 16px;
    background: url(../img/icon-addlink.svg) 0 1px no-repeat;
}

.changelink, .inlinechangelink {
    padding-left: 16px;
    background: url(../img/icon-changelink.svg) 0 1px no-repeat;
}

.deletelink {
    padding-left: 16px;
    background: url(../img/icon-deletelink.svg) 0 1px no-repeat;
}

the url(../img/...) files are not resolving. Obviously, they do not have AWS credentials on them so I suspect this css must be re-written. Is there a better way to resolve this issue?

@ajendrex Yes that would solve the issue, and maybe why there’s not more people discussing this issue. In my case it’s a corporate project and there is a lot of resistance to having any public buckets in the account.

Note that this occurs with CSS imports (@import url(...)) as well.

A workaround could be to use a whitelist to set specific files to public-read during upload.

See source for more info.

Here’s a quick example using a custom static-storage class:

from fnmatch import fnmatch  # allows us to use wildcards, simpler than e.g. re
from django.conf import settings
from storages.backends.s3boto3 import S3Boto3Storage
    
WHITELIST = ['admin/css/widgets.css', 'admin/css/fonts.css', 'admin/fonts/*.woff', 'admin/img/*.svg']

class S3StaticStorage(S3Boto3Storage):
    bucket_name = settings.AWS_S3_STATIC_BUCKET_NAME
    default_acl = None  # use S3 bucket default (i.e. private)
    querystring_auth = True  # automatically generate pre-signed urls
    querystring_expire = 3600  # pre-signed urls expire after this many seconds

    def get_object_parameters(self, name):
        """ override the ACL value for whitelisted files """
        object_parameters = super().get_object_parameters(name=name)
        if any(fnmatch(name, pattern) for pattern in WHITELIST):
            object_parameters['ACL'] = 'public-read'
        return object_parameters

So basically this is impossible to fix without actually post-processing (and therefore downloading) each CSS file, which is a time-consuming process when the storage is remote.

The Django ticket referenced above was closed as “wontfix”. I personally think it’s unfortunate and honestly unnecessary, since the only places where django.contrib.admin uses the @import syntax is one import of fonts.css, which is 20 lines of code, from base.css and one import of widgets.css from forms.css. Readability and maintainability of the stylesheets isn’t even an argument in my opinion, since it’s plain old CSS which has never not turned into an unmaintainable dish of spaghetti.

I’m not going to go out of my way to hack this into kinda working, back to local storage it is.

get_object_parameters was added specifically for issues like this, maybe worth a call out in the docs.

@fcaira I loaded fonts from google fonts in the template

{% extends "admin/base.html" %}
{% block extrahead %}
  <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;700&display=swap" rel="stylesheet">
{% endblock %}

And I ignored the fact that icons were no longer loading. In our case we are using standard django css and the icons missing are hardly noticeable .