Implement support for Apache mod_session module

This commit add hooks to mod_wsgi so it can be configured to be a provider to mod_session. This implements all 4 methods listed in Issue #185 of the old bug tracker (https://code.google.com/p/modwsgi/issues/detail?id=185).

If you look at the diff, you will see a lot of modifications on wsgi_hook_check_user_id. In reality, I didn't touch this method. The problem occurred because I reused a lot of the code used to call a python method.

I used the 4 new hooks to secure a web server using one Django app. I wanted the users to use a Django form to log in instead of a browser pop-up. I used mod_auth_form and didn't want to stock the username / password values into an encrypted cookie or database. Since the mod is dependant on a very strict session support, I had to simulate an authentication with a username / password (in reality, I'm using Django session cookie to authenticate the user).

The Apache config I used is :
```
    WSGIScriptAlias /app /home/user/myapp/app.wsgi
    <Location />
        AuthType Form
        AuthFormProvider wsgi
        AuthName "RQ"
        AuthFormLoginRequiredLocation /app/accounts/login/?next=%{REQUEST_URI}
        WSGIAuthUserScript /home/user/myapp/auth.wsgi
        Session On
        WSGISessionScript /home/user/myapp/auth.wsgi
        Require valid-user
    </Location>

    <Location /app/accounts/login>
        Require all granted
    </Location>
```

Here's a description of the four python methods that must be created to support sessions :

1. *load_session* : Receives an AuthObject. Returns a string (the encoded session). A value of None means there is no saved session.
2. *decode_session* : Receives an AuthObject and a string (the encoded session). Returns a dictionary of strings as key / values (no other types are supported). A return value of None means an Error.
3. *encode_session* : Receives an AuthObject and a dictionary of strings as key / values. Returns either a string (the encoded session) or None if the hook must be DECLINED.
4. *save_session* : Receives an AuthObject and a string (the encoded session). Returns either True if the session was saved successfully, False if there was an error or None if the hook must be DECLINED.

Full example (django implementation) :
```
# -*- coding: utf-8 -*-

import sys
import os

APACHE_AUTH_KEY = u"AUTH_NAME"
APACHE_USER_KEY = u"user"
APACHE_PASS_KEY = u"pw"

sys.path.insert(0, os.path.dirname(__file__))
os.environ['DJANGO_SETTINGS_MODULE'] = 'myapp.settings'

def __get_apache_keys_(environ):
    user_key = APACHE_USER_KEY
    pw_key = APACHE_PASS_KEY
    if APACHE_AUTH_KEY in environ:
        authname = environ[APACHE_AUTH_KEY]
        if authname is not None:
            user_key = authname + u"-" + user_key
            pw_key = authname + u"-" + pw_key

    return (user_key, pw_key)

def __get_session_id_(environ):
    from django.conf import settings
    from django.http import parse_cookie

    if u"HTTP_COOKIE" in environ:
        cookies = parse_cookie(environ[u"HTTP_COOKIE"])
        if settings.SESSION_COOKIE_NAME in cookies:
            return cookies[settings.SESSION_COOKIE_NAME]

def __get_session_(environ):
    from django.contrib.sessions.models import Session

    s = None

    session_id = __get_session_id_(environ)
    if session_id is not None:
        try:
            s = Session.objects.get(pk = session_id)
        except Session.DoesNotExists:
            pass

    return s

def __encode_data_(data):
    from importlib import import_module
    from django.conf import settings

    SessionStore = import_module(settings.SESSION_ENGINE).SessionStore
    s = SessionStore()
    return s.encode(data)

def __decode_data_(data):
    from importlib import import_module
    from django.conf import settings

    SessionStore = import_module(settings.SESSION_ENGINE).SessionStore
    s = SessionStore()
    return s.decode(data)

def check_password(environ, username, password):
    s = __get_session_(environ)
    session_data = s.get_decoded()

    from django.contrib.auth import SESSION_KEY
    if SESSION_KEY in session_data and session_data[SESSION_KEY] is not None:
        from django.contrib.auth import get_user_model
        UserModel = get_user_model()

        try:
            user = UserModel.objects.get(pk = session_data[SESSION_KEY])
            return True
        except UserModel.DoesNotExist:
            pass

    return False

def load_session(environ):
    s = __get_session_(environ)
    if s is not None:
        return s.session_data

def decode_session(environ, data):
    session_data = __decode_data_(data)

    (user_key, pw_key) = __get_apache_keys_(environ)
    if user_key not in session_data:
        from django.contrib.auth import SESSION_KEY
        from django.contrib.auth import get_user_model
        UserModel = get_user_model()

        user = None
        if SESSION_KEY in session_data:
            uid = session_data[SESSION_KEY]
            if uid is not None:
                try:
                    user = UserModel.objects.get(pk = uid)
                except UserModel.DoesNotExist:
                    pass

        if user is not None:
            session_data[user_key] = user.get_username()
            if pw_key not in session_data:
                session_data[pw_key] = u"<fake>"

    return {k.encode(u"utf-8"):v.encode(u"utf-8") for (k,v) in session_data.iteritems() if no$

def encode_session(environ, data):
    (user_key, pw_key) = __get_apache_keys_(environ)
    if user_key in data:
        del data[user_key]
    if pw_key in data:
        del data[pw_key]

    s = __get_session_(environ)
    session_data = __decode_data_(s.session_data)
    for key in data:
        if not key.startswith(u"_"):
            session_data[key] = data[key]

    return __encode_data_(session_data)

def save_session(environ, data):
    s = __get_session_(environ)
    if s is not None:
        s.session_data = data
        s.save()
        return True

    return False
```

To avoid overriding django values, we can also ignore session saving :
```
def encode_session(environ, data):
    pass

def save_session(environ, data):
    pass
```