Skip to content

Commit 512766b

Browse files
committed
Added Flask per Pamela
1 parent f4f4894 commit 512766b

File tree

1 file changed

+71
-3
lines changed

1 file changed

+71
-3
lines changed

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

Lines changed: 71 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ author: msangapu-msft
66
ms.author: msangapu
77
ms.assetid: cd1d15d3-2d9e-4502-9f11-a306dac4453a
88
ms.topic: article
9-
ms.date: 06/18/2024
9+
ms.date: 06/21/2024
1010
ms.devlang: csharp
1111
ms.custom: devx-track-csharp, devx-track-extended-java, devx-track-js, devx-track-python
1212
---
@@ -440,7 +440,72 @@ public class ClientCertValidator {
440440

441441
## Python sample
442442

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.
443+
The following Flask and Django Python code samples implement a decorator named `authorize_certificate` that can be used on a 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 ensures that an HTTP response with status code 403 (Forbidden) is returned to the client.
444+
445+
### [Flask](#tab/flask)
446+
447+
```python
448+
from functools import wraps
449+
from datetime import datetime, timezone
450+
from flask import abort, request
451+
from cryptography import x509
452+
from cryptography.x509.oid import NameOID
453+
from cryptography.hazmat.primitives import hashes
454+
455+
456+
def validate_cert(request):
457+
458+
cert_value = request.headers.get('X-ARR-ClientCert')
459+
if cert_value is None:
460+
return False
461+
462+
cert_data = ''.join(['-----BEGIN CERTIFICATE-----\n', cert_value, '\n-----END CERTIFICATE-----\n',])
463+
cert = x509.load_pem_x509_certificate(cert_data.encode('utf-8'))
464+
465+
fingerprint = cert.fingerprint(hashes.SHA1())
466+
if fingerprint != b'12345678901234567890':
467+
return False
468+
469+
subject = cert.subject
470+
subject_cn = subject.get_attributes_for_oid(NameOID.COMMON_NAME)[0].value
471+
if subject_cn != "contoso.com":
472+
return False
473+
474+
issuer = cert.issuer
475+
issuer_cn = issuer.get_attributes_for_oid(NameOID.COMMON_NAME)[0].value
476+
if issuer_cn != "contosoauthority.com":
477+
return False
478+
479+
current_time = datetime.now(timezone.utc)
480+
481+
if current_time < cert.not_valid_before_utc:
482+
return False
483+
484+
if current_time > cert.not_valid_after_utc:
485+
return False
486+
487+
return True
488+
489+
def authorize_certificate(f):
490+
@wraps(f)
491+
def decorated_function(*args, **kwargs):
492+
if not validate_cert(request):
493+
abort(403)
494+
return f(*args, **kwargs)
495+
return decorated_function
496+
```
497+
498+
The following code snippet shows how to use the decorator on a Flask view function.
499+
500+
```python
501+
@app.route('/hellocert')
502+
@authorize_certificate
503+
def hellocert():
504+
print('Request for hellocert page received')
505+
return render_template('index.html')
506+
```
507+
508+
### [Django](#tab/django)
444509

445510
```python
446511
from functools import wraps
@@ -498,7 +563,10 @@ The following code snippet shows how to use the decorator on a Django view funct
498563
```python
499564
@authorize_certificate
500565
def hellocert(request):
501-
#Code omitted
566+
print('Request for hellocert page received')
567+
return render(request, 'hello_azure/index.html')
502568
```
503569

570+
---
571+
504572
[exclusion-paths]: ./media/app-service-web-configure-tls-mutual-auth/exclusion-paths.png

0 commit comments

Comments
 (0)