1
1
"""authentik storage backends"""
2
2
3
3
import os
4
- from urllib .parse import parse_qsl , urlsplit
4
+ from urllib .parse import parse_qsl , urlsplit , urlunsplit
5
5
6
6
from django .conf import settings
7
7
from django .core .exceptions import SuspiciousOperation
@@ -74,7 +74,6 @@ def security_token(self, value: str):
74
74
75
75
def _normalize_name (self , name ):
76
76
try :
77
-
78
77
return safe_join (self .location , connection .schema_name , name )
79
78
except ValueError :
80
79
raise SuspiciousOperation (f"Attempted access to '{ name } ' denied." ) from None
@@ -89,24 +88,60 @@ def url(self, name, parameters=None, expire=None, http_method=None):
89
88
90
89
params ["Bucket" ] = self .bucket .name
91
90
params ["Key" ] = name
92
- url = self .bucket .meta .client .generate_presigned_url (
93
- "get_object" ,
94
- Params = params ,
95
- ExpiresIn = expire ,
96
- HttpMethod = http_method ,
97
- )
98
91
99
- if self .custom_domain :
100
- # Key parameter can't be empty. Use "/" and remove it later.
101
- params ["Key" ] = "/"
102
- root_url_signed = self .bucket .meta .client .generate_presigned_url (
103
- "get_object" , Params = params , ExpiresIn = expire
92
+ # Get the client and configure endpoint URL if custom_domain is set
93
+ client = self .bucket .meta .client
94
+
95
+ # Save original endpoint URL if we need to restore it
96
+ original_endpoint_url = getattr (client ._endpoint , "host" , None )
97
+
98
+ try :
99
+ # If custom domain is set, configure the endpoint URL
100
+ if self .custom_domain :
101
+ scheme = "https" if self .secure_urls else "http"
102
+ custom_endpoint = f"{ scheme } ://{ self .custom_domain } "
103
+
104
+ # Set the endpoint URL temporarily for this request
105
+ client ._endpoint .host = custom_endpoint
106
+
107
+ # Generate the presigned URL using the correctly configured client
108
+ url = client .generate_presigned_url (
109
+ "get_object" ,
110
+ Params = params ,
111
+ ExpiresIn = expire ,
112
+ HttpMethod = http_method ,
104
113
)
105
- # Remove signing parameter and previously added key "/".
106
- root_url = self ._strip_signing_parameters (root_url_signed )[:- 1 ]
107
- # Replace bucket domain with custom domain.
108
- custom_url = f"{ self .url_protocol } //{ self .custom_domain } /"
109
- url = url .replace (root_url , custom_url )
114
+
115
+ # If using custom domain, we need to handle the path correctly
116
+ if self .custom_domain and self .bucket .name in url :
117
+ # Parse the generated URL
118
+ split_url = urlsplit (url )
119
+
120
+ # Get the path from the S3 URL
121
+ s3_path = split_url .path
122
+
123
+ # Remove the leading bucket name from the path if it's present
124
+ bucket_prefix = f"/{ self .bucket .name } "
125
+ if s3_path .startswith (bucket_prefix ):
126
+ final_path = s3_path [len (bucket_prefix ) :]
127
+ else :
128
+ final_path = s3_path
129
+
130
+ # Create the custom domain URL with the corrected path and query parameters
131
+ url = urlunsplit (
132
+ (
133
+ split_url .scheme ,
134
+ self .custom_domain ,
135
+ final_path ,
136
+ split_url .query ,
137
+ split_url .fragment ,
138
+ )
139
+ )
140
+
141
+ finally :
142
+ # Restore the original endpoint URL if we changed it
143
+ if self .custom_domain and original_endpoint_url :
144
+ client ._endpoint .host = original_endpoint_url
110
145
111
146
if self .querystring_auth :
112
147
return url
0 commit comments