Repository: jschneier/django-storages

Issue:
`AWS_S3_*` environment variables are ignored
It is a regression probably from 705bdb7300642f0c42d823e4e35eb20356579389 in v1.14.

Now these variables are loaded only from Django settings, not from env.

https://github.com/jschneier/django-storages/blob/d0dce62a8a35bd4c75f77d389781424d4f705c07/storages/backends/s3.py#L355-L358

https://django-storages.readthedocs.io/en/latest/backends/amazon-S3.html#authentication-settings

I think `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` still work because boto3 load them.


Discussion:

Resolving patch:
diff --git a/storages/backends/s3.py b/storages/backends/s3.py
--- a/storages/backends/s3.py
+++ b/storages/backends/s3.py
@@ -26,6 +26,7 @@
 from storages.utils import clean_name
 from storages.utils import get_available_overwrite_name
 from storages.utils import is_seekable
+from storages.utils import lookup_env
 from storages.utils import safe_join
 from storages.utils import setting
 from storages.utils import to_bytes
@@ -352,14 +353,26 @@ def get_cloudfront_signer(self, key_id, key):
 
     def get_default_settings(self):
         return {
-            "access_key": setting("AWS_S3_ACCESS_KEY_ID", setting("AWS_ACCESS_KEY_ID")),
+            "access_key": setting(
+                "AWS_S3_ACCESS_KEY_ID",
+                setting(
+                    "AWS_ACCESS_KEY_ID",
+                    lookup_env(["AWS_S3_ACCESS_KEY_ID", "AWS_ACCESS_KEY_ID"]),
+                ),
+            ),
             "secret_key": setting(
-                "AWS_S3_SECRET_ACCESS_KEY", setting("AWS_SECRET_ACCESS_KEY")
+                "AWS_S3_SECRET_ACCESS_KEY",
+                setting(
+                    "AWS_SECRET_ACCESS_KEY",
+                    lookup_env(["AWS_S3_SECRET_ACCESS_KEY", "AWS_SECRET_ACCESS_KEY"]),
+                ),
             ),
             "security_token": setting(
                 "AWS_SESSION_TOKEN", setting("AWS_SECURITY_TOKEN")
             ),
-            "session_profile": setting("AWS_S3_SESSION_PROFILE"),
+            "session_profile": setting(
+                "AWS_S3_SESSION_PROFILE", lookup_env(["AWS_S3_SESSION_PROFILE"])
+            ),
             "file_overwrite": setting("AWS_S3_FILE_OVERWRITE", True),
             "object_parameters": setting("AWS_S3_OBJECT_PARAMETERS", {}),
             "bucket_name": setting("AWS_STORAGE_BUCKET_NAME"),
diff --git a/storages/utils.py b/storages/utils.py
--- a/storages/utils.py
+++ b/storages/utils.py
@@ -109,6 +109,17 @@ def check_location(storage):
         )
 
 
+def lookup_env(names):
+    """
+    Look up for names in environment. Returns the first element
+    found.
+    """
+    for name in names:
+        value = os.environ.get(name)
+        if value:
+            return value
+
+
 def get_available_overwrite_name(name, max_length):
     if max_length is None or len(name) <= max_length:
         return name


Test patch:
diff --git a/tests/test_s3.py b/tests/test_s3.py
--- a/tests/test_s3.py
+++ b/tests/test_s3.py
@@ -1,6 +1,7 @@
 import datetime
 import gzip
 import io
+import os
 import pickle
 import threading
 from textwrap import dedent
@@ -938,6 +939,21 @@ def test_auth_config(self):
             self.assertEqual(storage.access_key, "foo")
             self.assertEqual(storage.secret_key, "boo")
 
+        with mock.patch.dict(
+            os.environ,
+            {"AWS_S3_ACCESS_KEY_ID": "foo", "AWS_S3_SECRET_ACCESS_KEY": "boo"},
+        ):
+            storage = s3.S3Storage()
+            self.assertEqual(storage.access_key, "foo")
+            self.assertEqual(storage.secret_key, "boo")
+
+        with mock.patch.dict(
+            os.environ, {"AWS_ACCESS_KEY_ID": "foo", "AWS_SECRET_ACCESS_KEY": "boo"}
+        ):
+            storage = s3.S3Storage()
+            self.assertEqual(storage.access_key, "foo")
+            self.assertEqual(storage.secret_key, "boo")
+
         storage = s3.S3Storage(access_key="foo", secret_key="boo")
         self.assertEqual(storage.access_key, "foo")
         self.assertEqual(storage.secret_key, "boo")