@@ -33,10 +33,10 @@ class SigV4HTTPXAuth(httpx.Auth):
3333 """HTTPX Auth class that signs requests with AWS SigV4."""
3434
3535 def __init__ (
36- self ,
37- credentials : Credentials ,
38- service : str ,
39- region : str ,
36+ self ,
37+ credentials : Credentials ,
38+ service : str ,
39+ region : str ,
4040 ):
4141 """Initialize SigV4HTTPXAuth.
4242
@@ -123,11 +123,70 @@ async def _handle_error_response(response: httpx.Response) -> None:
123123 raise e
124124
125125
126- async def _inject_metadata_hook (metadata : Dict [str , Any ], request : httpx .Request ) -> None :
126+ def _resign_request_with_sigv4 (
127+ request : httpx .Request ,
128+ region : str ,
129+ service : str ,
130+ profile : Optional [str ] = None ,
131+ ) -> None :
132+ """Re-sign an HTTP request with AWS SigV4 after content modification.
133+
134+ This function removes old signature headers, creates a new signature based on
135+ the current request content, and updates the request headers with the new signature.
136+
137+ Args:
138+ request: The HTTP request object to re-sign (modified in-place)
139+ region: AWS region for SigV4 signing
140+ service: AWS service name for SigV4 signing
141+ profile: AWS profile to use (optional)
142+ """
143+ # Remove old signature headers before re-signing
144+ headers_to_remove = ['Content-Length' , 'x-amz-date' , 'x-amz-security-token' , 'authorization' ]
145+ for header in headers_to_remove :
146+ request .headers .pop (header , None )
147+
148+ # Set the new Content-Length
149+ request .headers ['Content-Length' ] = str (len (request .content ))
150+
151+ logger .info ('Headers after cleanup: %s' , request .headers )
152+
153+ # Get AWS credentials
154+ session = create_aws_session (profile )
155+ credentials = session .get_credentials ()
156+ logger .info ('Re-signing request with credentials for access key: %s' , credentials .access_key )
157+
158+ # Create headers dict for signing, removing connection header like in auth_flow
159+ headers_for_signing = dict (request .headers )
160+ headers_for_signing .pop ('connection' , None ) # Remove connection header for signing
161+
162+ # Create SigV4 signer and AWS request
163+ signer = SigV4Auth (credentials , service , region )
164+ aws_request = AWSRequest (
165+ method = request .method ,
166+ url = str (request .url ),
167+ data = request .content ,
168+ headers = headers_for_signing ,
169+ )
170+
171+ # Sign the request
172+ logger .info ('AWS request before signing: %s' , aws_request .headers )
173+ signer .add_auth (aws_request )
174+ logger .info ('AWS request after signing: %s' , aws_request .headers )
175+
176+ # Update request headers with signed headers
177+ request .headers .update (dict (aws_request .headers ))
178+ logger .info ('Request headers after re-signing: %s' , request .headers )
179+
180+
181+ async def _inject_metadata_hook (
182+ metadata : Dict [str , Any ], region : str , service : str , request : httpx .Request
183+ ) -> None :
127184 """Request hook to inject metadata into MCP calls.
128185
129186 Args:
130187 metadata: Dictionary of metadata to inject into _meta field
188+ region: AWS region for SigV4 re-signing after metadata injection
189+ service: AWS service name for SigV4 re-signing after metadata injection
131190 request: The HTTP request object
132191 """
133192 logger .info ('=== Outgoing Request ===' )
@@ -174,47 +233,9 @@ async def _inject_metadata_hook(metadata: Dict[str, Any], request: httpx.Request
174233 request .stream = ByteStream (new_content )
175234 request ._content = new_content
176235
177- # Remove old signature headers before re-signing
178- del request .headers ['Content-Length' ]
179- del request .headers ['x-amz-date' ]
180- del request .headers ['x-amz-security-token' ]
181- del request .headers ['authorization' ]
182-
183- # Set the new Content-Length AFTER deleting the old one
184- request .headers ['Content-Length' ] = str (len (new_content ))
185-
186- logger .info ('Headers are: %s' , request .headers )
187- service = 'eks-mcp'
188- region = 'us-west-2'
189- session = create_aws_session ()
190- credentials = session .get_credentials ()
191- logger .info ('DEBUG about to sign again: %s' , credentials )
192-
193- # Create headers dict for signing, removing connection header like in auth_flow
194- headers_for_signing = dict (request .headers )
195- headers_for_signing .pop ('connection' , None ) # Remove connection header for signing
196-
197- signer = SigV4Auth (credentials , service , region )
198- aws_request = AWSRequest (
199- method = request .method ,
200- url = str (request .url ),
201- data = request .content ,
202- headers = headers_for_signing ,
203- )
204-
205- # Sign the request with SigV4
206- logger .info ('aws_request before signing: %s' , aws_request .headers )
207- signer .add_auth (aws_request )
208- logger .info ('aws_request after signing: %s' , aws_request .headers )
209-
210- # Update request headers with signed headers (this includes Authorization, x-amz-date, etc.)
211- request .headers ['x-amz-date' ] = aws_request .headers ['x-amz-date' ]
212- request .headers ['x-amz-security-token' ] = aws_request .headers [
213- 'x-amz-security-token'
214- ]
215- request .headers ['Authorization' ] = aws_request .headers ['Authorization' ]
236+ # Re-sign the request with the new content
237+ _resign_request_with_sigv4 (request , region , service )
216238
217- logger .info ('New headers: %s' , request .headers )
218239 logger .info ('Injected metadata into _meta: %s' , body ['params' ]['_meta' ])
219240
220241 except (json .JSONDecodeError , KeyError , TypeError ) as e :
@@ -281,14 +302,14 @@ def create_sigv4_auth(service: str, region: str, profile: Optional[str] = None)
281302
282303
283304def create_sigv4_client (
284- service : str ,
285- region : str ,
286- timeout : Optional [httpx .Timeout ] = None ,
287- profile : Optional [str ] = None ,
288- headers : Optional [Dict [str , str ]] = None ,
289- auth : Optional [httpx .Auth ] = None ,
290- metadata : Optional [Dict [str , Any ]] = None ,
291- ** kwargs : Any ,
305+ service : str ,
306+ region : str ,
307+ timeout : Optional [httpx .Timeout ] = None ,
308+ profile : Optional [str ] = None ,
309+ headers : Optional [Dict [str , str ]] = None ,
310+ auth : Optional [httpx .Auth ] = None ,
311+ metadata : Optional [Dict [str , Any ]] = None ,
312+ ** kwargs : Any ,
292313) -> httpx .AsyncClient :
293314 """Create an httpx.AsyncClient with SigV4 authentication.
294315
@@ -334,6 +355,6 @@ def create_sigv4_client(
334355 ** client_kwargs ,
335356 event_hooks = {
336357 'response' : [_handle_error_response ],
337- 'request' : [partial (_inject_metadata_hook , metadata or {})],
358+ 'request' : [partial (_inject_metadata_hook , metadata or {}, region , service )],
338359 },
339360 )
0 commit comments