Skip to content

Commit e8806c4

Browse files
committed
feat: custom AzureStorage class
Inherit from original AzureStorage (from django-storages) and override the url-method to strip away sas-token from the url. Refs: KK-1509
1 parent 692b1b8 commit e8806c4

3 files changed

Lines changed: 75 additions & 0 deletions

File tree

utils/storage.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
from urllib.parse import urlparse, urlunparse
2+
3+
from storages.backends.azure_storage import AzureStorage
4+
5+
6+
class AzureStorageWithoutQuerystringAuth(AzureStorage):
7+
"""
8+
Extends AzureStorage to strip the SAS token from URLs, matching the
9+
behaviour of the S3 and GCS backends in django-storages with querystring_auth=False.
10+
"""
11+
12+
def url(self, name, expire=None, parameters=None, mode="r"):
13+
sas_url = super().url(name, expire=expire, parameters=parameters, mode=mode)
14+
parsed_url = urlparse(sas_url)
15+
return urlunparse(parsed_url._replace(query=""))

utils/tests/__init__.py

Whitespace-only changes.

utils/tests/test_storage.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
from unittest.mock import patch
2+
3+
import pytest
4+
from django.conf import settings
5+
from django.test import override_settings
6+
from django.utils.module_loading import import_string
7+
from storages.backends.azure_storage import AzureStorage
8+
9+
from utils.storage import AzureStorageWithoutQuerystringAuth
10+
11+
SAS_URL = (
12+
"https://myaccount.blob.core.windows.net/mycontainer/myfile.jpg"
13+
"?sv=2021-06-08&se=2026-01-01T00%3A00%3A00Z&sr=b&sp=r&sig=FAKESIG"
14+
)
15+
CLEAN_URL = "https://myaccount.blob.core.windows.net/mycontainer/myfile.jpg"
16+
17+
18+
def _make_storage(model=AzureStorageWithoutQuerystringAuth, **overrides):
19+
"""Return an AzureStorageWithoutQuerystringAuth with minimal required settings."""
20+
kwargs = dict(
21+
account_name="myaccount",
22+
account_key="123454567",
23+
azure_container="mycontainer",
24+
expiration_secs=3600,
25+
)
26+
kwargs.update(overrides)
27+
return model(**kwargs)
28+
29+
30+
@pytest.mark.parametrize(
31+
"model, expected_url",
32+
[
33+
(AzureStorage, SAS_URL),
34+
(AzureStorageWithoutQuerystringAuth, CLEAN_URL),
35+
],
36+
)
37+
@patch.object(AzureStorage, "url", return_value=SAS_URL)
38+
def test_url_querystring_auth(mock_url, model, expected_url):
39+
storage = _make_storage(model=model)
40+
result = storage.url("myfile.jpg")
41+
42+
assert result == expected_url
43+
44+
45+
@patch.object(AzureStorage, "url", return_value=SAS_URL)
46+
def test_url_querystring_auth_false_no_query_string_in_parent_url(mock_url):
47+
storage = _make_storage()
48+
result = storage.url("myfile.jpg")
49+
50+
assert result == CLEAN_URL
51+
assert "?" not in result
52+
53+
54+
@override_settings(
55+
STORAGES_DEFAULT_BACKEND="utils.storage.AzureStorageWithoutQuerystringAuth"
56+
)
57+
def test_default_storage_uses_azure_without_querystring_auth():
58+
backend_class = import_string(settings.STORAGES_DEFAULT_BACKEND)
59+
assert issubclass(backend_class, AzureStorage)
60+
assert backend_class is AzureStorageWithoutQuerystringAuth

0 commit comments

Comments
 (0)