3.3 Now something More Complicated - Authentication
Keywords: modpython

#
3.3 Now something More Complicated - Authentication

Now that you know how to write a primitive handler, let's try something more complicated.

Let's say we want to password-protect this directory. We want the login to be "spam", and the password to be "eggs".

First, we need to tell Apache to call our authentication handler when authentication is needed. We do this by adding the `PythonAuthenHandler`. So now our config looks like this:

      <Directory /mywebdir>
          AddHandler python-program .py
          PythonHandler myscript
          PythonAuthenHandler myscript
      </Directory>

Notice that the same script is specified for two different handlers. This is fine, because if you remember, mod_python will look for different functions within that script for the different handlers.

Next, we need to tell Apache that we are using Basic HTTP authentication, and only valid users are allowed (this is fairly basic Apache stuff, so I'm not going to go into details here). Our config looks like this now:

      <Directory /mywebdir>
          AddHandler python-program .py
          PythonHandler myscript
          PythonAuthenHandler myscript
          AuthType Basic
          AuthName "Restricted Area"
          require valid-user
      </Directory>

Now we need to write an authentication handler function in myscript.py. A basic authentication handler would look like this:

      def authenhandler(req):

          pw = req.get_basic_auth_pw()
          user = req.connection.user
          if user == "spam" and pw == "eggs":
              return apache.OK
          else:
              return apache.HTTP_UNAUTHORIZED

Let's look at this line by line:

-       def authenhandler(req):

  This is the handler function declaration. This one is called `authenhandler` because, as we already described above, mod_python takes the name of the directive (`PythonAuthenHandler`), drops the word "Python" and converts it lower case.

-           pw = req.get_basic_auth_pw()

  This is how we obtain the password. The basic HTTP authentication transmits the password in base64 encoded form to make it a little bit less obvious. This function decodes the password and returns it as a string.

-           user = req.connection.user

  This is how you obtain the username that the user entered. In case you're wondering, the `connection` member of the `Request` object is an object that contains information specific to a connection. With HTTP Keep-Alive, a single connection can serve multiple requests.

  NOTE: The two lines above MUST be in that order. The reason is that `connection.user` is assigned a value by the `get_basic_auth_pw()` function. If you try to use the `connection.user` value without calling `get_basic_auth_pw()` first, it will be `None`.

-           if user == "spam" and pw == "eggs":
                return apache.OK

  We compare the values provided by the user, and if they are what we were expecting, we tell Apache to go ahead and proceed by returning `apache.OK`. Apache will then proceed to the next handler. (which in this case would be `handler()` if it's a `.py` file).

-           else:
                return apache.HTTP_UNAUTHORIZED

  Else, we tell Apache to return `HTTP_UNAUTHORIZED` to the client.