Skip to main content

Python middleware for working with (client) certificates.

Project description

x509middleware: Working with (client) certificates

This Python package contains middleware classes for working with certificates. Currently it only contains support for extracting client certificates from the ASGI scope and from headers set by a reverse proxy.

Note: The package is rather small but solves an immediate need for some projectes of mine while possibly being generally helpful to other people. As I chose a rather generic package name, patches or pull requests with support for other protocols than ASGI as well as additional functionallty are very welcome.

Installation

$ pip install x509middleware

Requirements

Contents

x509middleware.asgi.ClientCertificateMiddleware

This middlware class will try to find and parse a client certificate for a ASGI http or websocket request. It supports the proposed tls extension to the ASGI protocol as well as pulling the certificate from a header supplied by a reverse proxy your app is deployed behind.

It will set the key scope['client_cert'] to a asn1crypto.x509.Certificate object or None if it can't find or parse a certificate.

Parameters

  • app (async callable) – ...
  • use_tls_extension (bool=True) – ...
  • proxy_header (str=None) – Name of the header to try parsing as a client certificate or None to disable proxy header support. The header value can be line-folded, URL/percent-encoded or base64 encoded as well as in PEM or DER format. The correct way to decode will be detected automatically.

Configuring your reverse proxy

You will need to choose a header name when configuring your reverse proxy as well as the middlware class. Commonly used names are:

  • CLIENT-CERTIETF Draft.
  • X-SSL-CLIENT-CERT
  • X-CLIENT-CERT
  • X-CLIENT-CERTIFICATE
  • X-CLIENT-CRT
  • X-SSL-CERT
  • SSLClientCertb64 – F5 products seem to use or suggest this.
Apache / mod_proxy & mod_headers
ProxyPass / http://127.0.0.1:8000/
RequestHeader unset CLIENT-CERT
RequestHeader set   CLIENT-CERT "%{SSL_CLIENT_CERT}s"
NGINX
location / {
    proxy_pass http://127.0.0.1:8000/;
    proxy_set_header CLIENT-CERT $ssl_client_escaped_cert;
}
HAProxy

Support for passing the certificate as a DER blob is available starting version 1.6-dev1. Since DER is a binary format this needs to be base64 encoded.

backend back
  mode http
  server app 127.0.0.1:8000
  http-request set-header CLIENT-CERT %[ssl_c_der,base64]

Using it in Starlette

from starlette.applications import Starlette
from starlette.config import Config
from starlette.middleware import Middleware
from starlette.responses import Response
from starlette.routing import Route
from x509middleware.asgi import ClientCertificateMiddleware

async def hello_common_name(request):
    client_cert = request.scope.get('client_cert')
    if client_cert:
        cn = client_cert.subject.native['common_name']
    else:
        cn = 'unknown'
    return Response(f'Hello, {cn}!', media_type='text/plain')

config = Config('.env')
app = Starlette(
    routes=[ Route('/', hello_common_name) ],
    middleware=[
        Middleware(
            ClientCertificateMiddleware,
            proxy_header=config('CLIENT_CERT_HEADER', default=None)
        )
    ]
)

Using it directly

from os import environ
from x509middleware.asgi import ClientCertificateMiddleware

async def hello_common_name(scope, receive, send):
    client_cert = scope.get('client_cert')
    if client_cert:
        cn = client_cert.subject.native['common_name']
    else:
        cn = 'unknown'
    await send({
        'type': 'http.response.start',
        'status': 200,
        'headers': [
            (b'content-type', b'text/plain; charset=utf-8'),
        ]
    })
    await send({
        'type': 'http.response.body',
        'body': f'Hello, {cn}!'.encode('utf8'),
    })

app = ClientCertificateMiddleware(
    hello_common_name,
    proxy_header=environ.get('CLIENT_CERT_HEADER'),
)

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

x509middleware-1.1.tar.gz (8.5 kB view details)

Uploaded Source

File details

Details for the file x509middleware-1.1.tar.gz.

File metadata

  • Download URL: x509middleware-1.1.tar.gz
  • Upload date:
  • Size: 8.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.2.0 pkginfo/1.6.1 requests/2.25.1 setuptools/51.0.0 requests-toolbelt/0.9.1 tqdm/4.54.1 CPython/3.9.1

File hashes

Hashes for x509middleware-1.1.tar.gz
Algorithm Hash digest
SHA256 84d9f687665d3c69e8db1f9f001a0a2e05fdd14fdcbf6a5d2ff701a53a624e7d
MD5 1540a4bd93c2b63051627c78460ab98d
BLAKE2b-256 a4da74c26596ec8f5be758838e54878764be2c45ec340a75663b13297d36c1d5

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page