Inconsistent SignatureDoesNotMatch Amazon S3 con django-pipeline, s3boto y almacenamientos

Tengo 2 archivos comstackdos por django-pipeline junto con s3boto: master.css y master.js. Se establecen en “Público” en mis cubos. Sin embargo, cuando accedo a ellos, a veces se sirve master.css, a veces falla con SignatureDoesNotMatch. Lo mismo con master.js. Esto no sucede en Chrome. ¿Qué podría faltar?

EDIT : Ahora también sucede en Chrome.

También me pasó a mí … Tardé unas horas en encontrarlo, pero finalmente lo descubrí. Resulta que si la firma correcta es:

ssCNsAOxLf5vA80ldAI3M0CU2% 2Bw =

Entonces AWS NO aceptará:

ssCNsAOxLf5vA80ldAI3M0CU2 + w =

Donde la única diferencia es la traducción de% 2B a ‘+’.

S3BotoStorage en realidad lo produce correctamente, pero la encoding ocurre en CachedFilesMixin en la línea final del método url ( return unquote(final_url) ). Para solucionarlo, obtuve un nuevo CachedFilesMixin para deshacer el “daño” (debo mencionar que no sé por qué existe esta falta de cotización en primer lugar, por lo que deshacerlo podría causar otros problemas)

 class MyCachedFilesMixin(CachedFilesMixin): def url(self, *a, **kw): s = super(MyCachedFilesMixin, self).url(*a, **kw) if isinstance(s, unicode): s = s.encode('utf-8', 'ignore') scheme, netloc, path, qs, anchor = urlparse.urlsplit(s) path = urllib.quote(path, '/%') qs = urllib.quote_plus(qs, ':&=') return urlparse.urlunsplit((scheme, netloc, path, qs, anchor)) 

Donde utilicé el código que encontré aquí .

Espero que esto ayude…

Tuve un problema similar que causó errores SignatureDoesNotMatch al descargar archivos usando una URL firmada con S3 y la biblioteca HTTP de python solicita.

Mi problema terminó siendo un tipo de contenido malo. La documentación en AWS sobre Autenticación de solicitudes REST me ayudó a resolverlo, y tiene ejemplos en Python.

Estuve luchando con esto por un tiempo, y no me gustó la idea de estropearme con CachedFilesMixin (me pareció una exageración).

Hasta que se emita una solución adecuada a la plataforma django, he encontrado que citar la firma dos veces es una buena opción. Sé que no es bonito, pero funciona y es simple.

Así que tendrás que hacer algo como esto:

 signature = urllib.quote_plus(signature.strip()) signature = urllib.quote_plus(signature.strip()) 

¡Espero eso ayude!

Este artículo en Flask es un buen recurso para obtener las firmas correctas: https://devcenter.heroku.com/articles/s3-upload-python

 @app.route('/sign_s3/') def sign_s3(): AWS_ACCESS_KEY = os.environ.get('AWS_ACCESS_KEY_ID') AWS_SECRET_KEY = os.environ.get('AWS_SECRET_ACCESS_KEY') S3_BUCKET = os.environ.get('S3_BUCKET') object_name = request.args.get('s3_object_name') mime_type = request.args.get('s3_object_type') expires = int(time.time()+10) amz_headers = "x-amz-acl:public-read" put_request = "PUT\n\n%s\n%d\n%s\n/%s/%s" % (mime_type, expires, amz_headers, S3_BUCKET, object_name) signature = base64.encodestring(hmac.new(AWS_SECRET_KEY,put_request, sha).digest()) signature = urllib.quote_plus(signature.strip()) url = 'https://%s.s3.amazonaws.com/%s' % (S3_BUCKET, object_name) return json.dumps({ 'signed_request': '%s?AWSAccessKeyId=%s&Expires=%d&Signature=%s' % (url, AWS_ACCESS_KEY, expires, signature), 'url': url })