Using Django within ASP.NET web sites

Created 24th January, 2009 09:36 (UTC), last edited 5th February, 2009 08:26 (UTC)

Django and ASP.NET are very different web application systems, but that doesn't mean that they can't play nicely together.

Probably the most obvious integration mechanism is just to have them share the same database back end. Databases tend to make good integration points, they can be accessed easily from any number of platforms and programming languages and their use as an integration is very well understood. The big problem with them is that either the business logic must be implemented in each system that integrates to the database or it must be implemented within the database server. Neither of these is much fun.

What we wanted to do was to re-use the Django web interfaces that we'd built for human interaction for a back office system and allow us to reuse them easily for customer facing functionality in the ASP.NET web site. The basic layers that are needed to do something like this comprise (from bottom to top):

  1. Service authentication — make sure that the ASP.NET code making the calls to Django is the application that we have written and not something else.
  2. User authentication — make sure that the user browsing on the ASP.NET web site is one that is allowed to use the Django functionality we're re-exposing.
  3. An RPC mechanism — this needs to handle the basics of how data is moved between Django and ASP.NET.
  4. Definitions of specific services — the use cases that need to be supported must be split down into specific interactions (services) between the two systems and each of these must be defined in terms of data flow and authorisation requirements.

In order to solve these we re-used as much of the core Django and ASP.NET functionality as possible and added in a number of standard FOST.3™ components (at the ASP.NET end) and some new Fost 4 components at the Python/Django end. We also decided to go with a REST like mechanism based on JSON due to its simplicity and speed & ease of implementation (and we had a lot of pre-built components that already dealt perfectly with it).

Service authentication

The first part of the puzzle is to ensure that the requests that come in to Django actually do originate from the ASP.NET service and not some other place. In order to do this we copied the SHA1/HMAC based authentication scheme that Amazon AWS uses for S3.

The mechanism is based on three main components:

  • A public key used to identify the service (also called the service API key).
  • A secret key used to authenticate the service (also called the secret key).
  • A cryptographic digest used to ensure that the request has not been tampered with.

These things taken together mean that we can be sure that the every command that Django sees comes from the trusted ASP.NET web site and that the request has not been tampered with.

In addition a time stamp is used to limit the scope of replay attacks. Whereas Amazon uses fifteen minutes, we cut this down to fifteen seconds as both end points will be on servers under our control and we can ensure much closer clock synchronisation than Amazon can as they take requests from any machine anywhere on the internet.

User authentication

Most of the things that we need to do across the link between the two web sites is to allow the customers to manage their accounts, purchase services and to configure the services that they have bought. This means that although the user will ultimately be logging on to a page on the ASP.NET web site, the credentials must also control what that user can do within Django.

Although the authentication service itself runs on the next layer up (the RPC layer), we need to be able to authenticate a specified Django user from the ASP.NET site.

The authentication service actually runs within the next layer up of the stack — the RPC layer. Once the user has been authenticated then the ASP.NET site sends the user name that Django is to use for the user account.

The mechanism we used for this assumes that ASP.NET is trusted not to lie — as we control both end points this is fine for us, but if you want to allow for third party end points to connect to your system you will want to handle better security for this. What you don't want to do though is to force the ASP.NET site to remember the user's password and pass it with each request — sooner or later that will go wrong and you'll regret it.

The header that is used to send the user name is part of the HMAC digest so cannot be tampered with.

Remote Procedure Calls

The next layer up is the actual interchange of information between the two systems. Django owns its own data, and this means that if the ASP.NET site wants any it must request that data from Django. It also means that it must Django to make any persistent changes by writing them into the database.

In order to keep things a little simpler we only use GET and POST — GET is used for any request for data, POST is used for any update request (this includes create and delete, although we don't actually allow the ASP.NET site to delete data). We could have used PUT for creation, but felt that it would only serve to confuse matters.

For GET we pass the parameters either within the URL itself, or as a URL query. For POST we always send the body as a JSON object. This gives us better flexibility than the normal POST encoding allows for. When a response is sent back to ASP.NET that will always be as JSON as well. We use Jayrock to handle the JSON parsing and generation from ASP.NET.

User authentication

In order to handle this we provide a service that allows the ASP.NET web site to request an authentication check on a user name and password combination. In order to reduce coupling between the two systems we send the password to the authentication service using plain text — normally this is a terrible idea, but there are two mitigating circumstances:

  1. The password has already been passed from the browser to the ASP.NET server in the clear (unless it uses HTTPS).
  2. The service transport is always HTTPS as we use the ForceHTTPS Django middleware.

We do however insist on the use of POST rather than GET in order to ensure that the query parameters won't end up in web server log files.

Service definitions

The simplest mechanism to manage is that an end point service appears at a specific URL, uses either GET or POST (and if POST what the body must contain) and the JSON data structure sent back in response.

For example, a very simple user authentication end point might look like this:

Service URL
/rest/authenticate/
Method
POST
POST body
{ "username": "some_name", "password": "silly password" }
Response

An object containing a “success” member indicating success or failure, i.e. one of the two bodies:

{ "success": true }

or

{ "success": false }

Note that the response and requests should ideally be wrapped inside JSON objects or arrays. This allows the API to be extended later on without upsetting older server and client end points.


Categories: