Welcome to Django HMAC’s documentation!

This module provides a middleware for HMAC signature Django views. It’s simply designed to check that a client is entitled to access routes, based on the fact that it must possess a copy of the secret key.

Key features:

  • HMAC Middleware
  • HMAC View decorators
  • Multiple keys for more services
  • Service restricted access

Small example

class SignedView(View):

    @decorators.auth
    def get(self, request):
        return HttpResponse("for all services")

    @decorators.auth(only=['userservice'])
    def post(self, request):
        return HttpResponse("Only for user service")

Contents:

Instalation

Install package:

pip install djangohmac

Middleware

To secure all your app with HMAC you can use a middleware.

MIDDLEWARE_CLASSES = (
    # ...
    'djangohmac.middleware.HmacMiddleware',
)

Note

Middleware is applied on all views except the admin!

Decorators

You can specify views which are protected by HMAC by using decorators. You can also pass list of services which have access to the view. If the list is not given all services defined in settings have access.

class SignedView(View):

    @decorators.auth()
    def get(self, request):
        return HttpResponse("For all services")

    @decorators.auth(only=['serviceA'])
    def post(self, request):
        return HttpResponse("Only for service A")

Settings

Single key:
HMAC_SECRET = 'HMAC_SECRET'
Multiple keys:
HMAC_SECRETS = {
    'serviceA': 'HMAC_SERVICE_A_SECRET',
    'serviceB': 'HMAC_SERVICE_B_SECRET'
}
Other settings:
  • HMAC_HEADER: HTTP header where signature is stored (Default: Signature)
  • HMAC_DIGESTMOD: Digest mod (Default: hashlib.sha256)
  • HMAC_DISABLE: Disable or enable HMAC True/False (Default: Enabled)

Examples

The signature is build from a secret key and a request body if exists.

Python

To send valid HMAC signature to a view you can use shmac.make_hmac()

from djangohmac.sign import shmac

sig = shmac.make_hmac()  # generate signature
response = requests.get(
    '/hmac_auth_view',
    headers={hmac.header: sig}
)

To generate signature for particular service:

sig = shmac.make_hmac_for('service', 'request body')
response = requests.get(
    '/hmac_auth_view',
    'request body',
    headers={hmac.header: sig}
)

HTTP

Valid signature is send:

Example request:

GET /api/v1/users HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate
Connection: keep-alive
Host: localdocker:8000
Signature: dXNlcnNlcnZpY2U6RDVyRm5TcnJUUTQyZUttcDIreWhXayttYzZPK0hjRHZjWWFwbW9MeFdjQT0=
User-Agent: HTTPie/0.9.2

Response response:

HTTP/1.0 200 OK
Content-Type: text/html; charset=utf-8
Date: Thu, 15 Oct 2015 09:53:10 GMT
Server: WSGIServer/0.1 Python/2.7.10
Vary: Cookie
X-Frame-Options: SAMEORIGIN
Invalid signature is send:

Response request:

GET /api/v1/users HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate
Connection: keep-alive
Host: localdocker:8000
Signature: blabla
User-Agent: HTTPie/0.9.2

Response response:

HTTP/1.0 403 FORBIDDEN
Content-Type: text/html; charset=utf-8
Date: Thu, 15 Oct 2015 09:53:35 GMT
Server: WSGIServer/0.1 Python/2.7.10
Vary: Cookie
X-Frame-Options: SAMEORIGIN

Django Hmac

djangohmac package

Submodules
djangohmac.decorators module
djangohmac.decorators.auth(func=None, only=None)

Route decorator. Validates an incoming request can access the route function.

Keyword Args:
only (list): Optional list of clients that can access the view
class SignedView(View):

    @decorators.auth
    def get(self, request):
        return HttpResponse("For all services")

    @decorators.auth(only=['serviceA'])
    def post(self, request):
        return HttpResponse("Only for service A")
djangohmac.middleware module
class djangohmac.middleware.HmacMiddleware

Bases: object

Uses global signature HMAC_SECRET defined in settings

process_request(request)
djangohmac.sign module
class djangohmac.sign.Hmac

Bases: object

abort()

Called when validation failed.

Raises:
PermissionDenied()
get_signature(request)

Get signature from djagno requests

Arguments:
request: Django request
Returns:
string: HMAC signature
Raises:
SecretKeyIsNotSet
hmac_disarm
hmac_key
make_hmac(data='', key=None)

Generates HMAC key

Arguments:
data (str): HMAC message key (str): secret key of another app
make_hmac_for(name, data='')

Generates HMAC key for named key

Arguments:
name (str): key name from HMAC_SECRETS dict data (str): HMAC message
Raises:
UnknownKeyName
validate_multiple_signatures(key_name, signature, request)

Validate signature from djagno request. But it takes key from HMAC_SECRETS list

Arguments:
request (request): Django request class only (list): Restricted only for this list of service
Returns:
boolen
Raises:
InvalidSignature
validate_signature(request, only=None)

Validate signate in given request.

Arguments:
request: Django request only: list of keys from HMAC_SECRETS to restrict signatures
Returns:
boolean: True when signature is valid otherwice False
Raises:
InvalidSignature SecretKeyIsNotSet
validate_single_signature(request)

Validate signature from djagno request

Arguments:
request (request): Django request class
Returns:
boolen
Raises:
InvalidSignature
exception djangohmac.sign.HmacException

Bases: exceptions.Exception

exception djangohmac.sign.InvalidSignature

Bases: djangohmac.sign.HmacException

exception djangohmac.sign.SecretKeyIsNotSet

Bases: djangohmac.sign.HmacException

exception djangohmac.sign.UnknownKeyName

Bases: djangohmac.sign.HmacException

djangohmac.sign.decode_string(value)
djangohmac.sign.encode_string(value)
Module contents

Indices and tables