Skip to content

Commit a7c6cc7

Browse files
committed
Add python example to App Service - Configure TLS mutual authentication article
1 parent 63c2c02 commit a7c6cc7

File tree

1 file changed

+65
-2
lines changed

1 file changed

+65
-2
lines changed

articles/app-service/app-service-web-configure-tls-mutual-auth.md

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ author: msangapu-msft
66
ms.author: msangapu
77
ms.assetid: cd1d15d3-2d9e-4502-9f11-a306dac4453a
88
ms.topic: article
9-
ms.date: 12/11/2020
9+
ms.date: 06/18/2024
1010
ms.devlang: csharp
11-
ms.custom: devx-track-csharp, devx-track-extended-java, devx-track-js
11+
ms.custom: devx-track-csharp, devx-track-extended-java, devx-track-js, devx-track-python
1212
---
1313
# Configure TLS mutual authentication for Azure App Service
1414

@@ -438,4 +438,67 @@ public class ClientCertValidator {
438438
}
439439
```
440440

441+
## Python sample
442+
443+
The following Python code implements a decorator named `authorize_certificate` that can be used on a Django view function to permit access only to callers that present a valid client certificate. It expects a PEM formatted certificate in the `X-ARR-ClientCert` header and uses the Python [cryptography](https://pypi.org/project/cryptography/) package to validate the certificate based on its fingerprint (thumbprint), subject common name, issuer common name, and beginning and expiration dates. If validation fails, the decorator raises the Django `PermissionDenied` exception.
444+
445+
```python
446+
from functools import wraps
447+
from datetime import datetime, timezone
448+
from django.core.exceptions import PermissionDenied
449+
from cryptography import x509
450+
from cryptography.x509.oid import NameOID
451+
from cryptography.hazmat.primitives import hashes
452+
453+
454+
def validate_cert(request):
455+
456+
cert_value = request.headers.get('X-ARR-ClientCert')
457+
if cert_value is None:
458+
return False
459+
460+
cert_data = ''.join(['-----BEGIN CERTIFICATE-----\n', cert_value, '\n-----END CERTIFICATE-----\n',])
461+
cert = x509.load_pem_x509_certificate(cert_data.encode('utf-8'))
462+
463+
fingerprint = cert.fingerprint(hashes.SHA1())
464+
if fingerprint != b'12345678901234567890':
465+
return False
466+
467+
subject = cert.subject
468+
subject_cn = subject.get_attributes_for_oid(NameOID.COMMON_NAME)[0].value
469+
if subject_cn != "contoso.com":
470+
return False
471+
472+
issuer = cert.issuer
473+
issuer_cn = issuer.get_attributes_for_oid(NameOID.COMMON_NAME)[0].value
474+
if issuer_cn != "contosoauthority.com":
475+
return False
476+
477+
current_time = datetime.now(timezone.utc)
478+
479+
if current_time < cert.not_valid_before_utc:
480+
return False
481+
482+
if current_time > cert.not_valid_after_utc:
483+
return False
484+
485+
return True
486+
487+
def authorize_certificate(view):
488+
@wraps(view)
489+
def _wrapped_view(request, *args, **kwargs):
490+
if not validate_cert(request):
491+
raise PermissionDenied
492+
return view(request, *args, **kwargs)
493+
return _wrapped_view
494+
```
495+
496+
The following code snippet shows how to use the decorator on a Django view function.
497+
498+
```python
499+
@authorize_certificate
500+
def hellocert(request):
501+
#Code omitted
502+
```
503+
441504
[exclusion-paths]: ./media/app-service-web-configure-tls-mutual-auth/exclusion-paths.png

0 commit comments

Comments
 (0)