How do I decode the X-ARR-ClientCert
header passed by Azure App Service to my Azure Function code?
Example:
- HTTP-triggered, Python Azure Function
- Azure App Service configured to accept client certs
- Requestor sends a client certificate with GET request (per Postman instructions here)
- Azure App Service passes client cert to Function code via a
X-ARR-ClientCert
header
Issue:
- I cannot find documentation on how this header is encoded
- I cannot find an example of how to decode this header using Python
The closest I've got is this code:
import logging
import base64
import azure.functions as func
def main(req: func.HttpRequest) -> func.HttpResponse:
logging.info('####### Python HTTP trigger certificate validation function processing a request. #######')
# Retrieve client cert from headers
req_cert_str = req.headers.get("X-ARR-ClientCert")
req_cert_bytes = base64.b64decode(req_cert_str)
decoded_string = req_cert_bytes.decode('cp1252')
return func.HttpResponse(
decoded_string
)
- Which results in
Status 500 Internal server error
and:
Exception while executing function: Functions.certiFunc <--- Result: Failure Exception: UnicodeDecodeError: 'charmap' codec can't decode byte 0x8d in position 403: character maps to <undefined> Stack: File "/azure-functions-host/workers/python/3.8/LINUX/X64/azure_functions_worker/dispatcher.py", line 343, in _handle__invocation_request call_result = await self._loop.run_in_executor( File "/usr/local/lib/python3.8/concurrent/futures/thread.py", line 57, in run result = self.fn(*self.args, **self.kwargs) File "/azure-functions-host/workers/python/3.8/LINUX/X64/azure_functions_worker/dispatcher.py", line 480, in __run_sync_func return func(**params) File "/home/site/wwwroot/certiFunc/__init__.py", line 14, in main decoded_string = req_cert_bytes.decode('cp1252') File "/usr/local/lib/python3.8/encodings/cp1252.py", line 15, in decode return codecs.charmap_decode(input,errors,decoding_table)
- When substituting
decoded_string = req_cert_bytes.decode('utf-8')
, I get:
Exception while executing function: Functions.certiFunc <--- Result: Failure Exception: UnicodeDecodeError: 'utf-8' codec can't decode byte 0x82 in position 1: invalid start byte Stack: File "/azure-functions-host/workers/python/3.8/LINUX/X64/azure_functions_worker/dispatcher.py", line 343, in _handle__invocation_request call_result = await self._loop.run_in_executor( File "/usr/local/lib/python3.8/concurrent/futures/thread.py", line 57, in run result = self.fn(*self.args, **self.kwargs) File "/azure-functions-host/workers/python/3.8/LINUX/X64/azure_functions_worker/dispatcher.py", line 480, in __run_sync_func return func(**params) File "/home/site/wwwroot/certiFunc/__init__.py", line 14, in main decoded_string = req_cert_bytes.decode('utf-8')
- When running the following (directly decoding the header)...
req_cert_str = req.headers.get("X-ARR-ClientCert")
decoded_string = base64.b64decode(req_cert_str)
...I get a Status 200 Success
but the response is a mashup of binary(?) characters and plain text:
What is the correct method for decoding this header using Python?
Further reading on the Github issue raised here
Since you are adding the client certificate from Postman, it's in DER (binary) format. You can decode the x509 certificate from bytes itself using Python cryptography.
Note: If the certificate was PEM format, you would need to use
x509.load_pem_x509_certificate(req_cert_bytes)