Statistics
| Branch: | Tag: | Revision:

root / aai / middleware.py @ ace4bd5d

History | View | Annotate | Download (5.5 kB)

1
# Copyright 2011 GRNET S.A. All rights reserved.
2
#
3
# Redistribution and use in source and binary forms, with or without
4
# modification, are permitted provided that the following conditions
5
# are met:
6
#
7
#   1. Redistributions of source code must retain the above copyright
8
#      notice, this list of conditions and the following disclaimer.
9
#
10
#  2. Redistributions in binary form must reproduce the above copyright
11
#     notice, this list of conditions and the following disclaimer in the
12
#     documentation and/or other materials provided with the distribution.
13
#
14
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
15
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17
# ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
18
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24
# SUCH DAMAGE.
25
#
26
# The views and conclusions contained in the software and documentation are
27
# those of the authors and should not be interpreted as representing official
28
# policies, either expressed or implied, of GRNET S.A.
29

    
30
from django.conf import settings
31
from django.http import HttpResponse, HttpResponseRedirect
32
from synnefo.db.models import SynnefoUser
33
from synnefo.aai.shibboleth import Tokens, register_shibboleth_user
34
import time
35

    
36
class SynnefoAuthMiddleware(object):
37

    
38
    auth_token = "X-Auth-Token"
39
    auth_user  = "X-Auth-User"
40
    auth_key   = "X-Auth-Key"
41

    
42
    def process_request(self, request):
43
        if request.path.startswith('/api/') :
44
            return
45

    
46
        if request.path.startswith('/invitations/login') :
47
            return
48

    
49
        # Special case for testing purposes, delivers the cookie for the
50
        # test user on first access
51
        if settings.BYPASS_AUTHENTICATION and \
52
           request.GET.get('test') is not None:
53
            u = SynnefoUser.objects.get(
54
                auth_token='46e427d657b20defe352804f0eb6f8a2')
55
            return self._redirect_shib_auth_user(user = u)
56

    
57
        token = None
58
        #Try to find token in a cookie
59
        try:
60
            token = request.COOKIES['X-Auth-Token']
61
        except Exception:
62
            pass
63

    
64
        #Try to find token in request header
65
        if not token:
66
            token = request.META.get('HTTP_X_AUTH_TOKEN', None)
67

    
68
        if token:
69
            user = None
70
            #Retrieve user from DB or other caching mechanism
71
            try:
72
                user = SynnefoUser.objects.get(auth_token=token)
73
            except SynnefoUser.DoesNotExist:
74
                return HttpResponseRedirect(settings.APP_INSTALL_URL + settings.LOGIN_PATH)
75

    
76
            #Check user's auth token
77
            if (time.time() -
78
                time.mktime(user.auth_token_expires.timetuple())) > 0:
79
                #The user's token has expired, re-login
80
                return HttpResponseRedirect(settings.APP_INSTALL_URL + settings.LOGIN_PATH)
81

    
82
            request.user = user
83
            return
84

    
85
        #A user authenticated by Shibboleth, must include a uniq id
86
        if Tokens.SIB_EPPN in request.META and Tokens.SIB_SESSION_ID in request.META:
87
            user = None
88
            try:
89
                user = SynnefoUser.objects.get(
90
                    uniq = request.META[Tokens.SIB_EPPN])
91
            except SynnefoUser.DoesNotExist:
92
                pass
93

    
94
            #No user with this id could be found in the database
95
            if user is None:
96
                #Attempt to register the incoming user
97
                if register_shibboleth_user(request.META):
98
                    user = SynnefoUser.objects.get(
99
                        uniq = request.META[Tokens.SIB_EPPN])
100
                    return self._redirect_shib_auth_user(user)
101
                else:
102
                    return HttpResponseRedirect(settings.APP_INSTALL_URL + settings.LOGIN_PATH)
103

    
104
            #User and authentication token valid, user allowed to proceed
105
            return self._redirect_shib_auth_user(user)
106

    
107
        if settings.TEST:
108
            if 'TEST-AAI' in request.META:
109
                return HttpResponseRedirect(settings.APP_INSTALL_URL + settings.LOGIN_PATH)
110
        else:
111
            #Avoid redirect loops
112
            if request.path.endswith(settings.LOGIN_PATH): 
113
                return
114
            else :
115
                #No authentication info found in headers, redirect to Shibboleth
116
                return HttpResponseRedirect(settings.APP_INSTALL_URL + settings.LOGIN_PATH)
117

    
118
    def process_response(self, request, response):
119
        #Tell proxies and other interested parties that the
120
        #request varies based on the auth token, to avoid
121
        #caching of results
122
        response['Vary'] = self.auth_token
123
        return response
124

    
125
    def _redirect_shib_auth_user(self, user):
126
        expire_fmt = user.auth_token_expires.strftime('%a, %d-%b-%Y %H:%M:%S %Z')
127

    
128
        response = HttpResponse()
129

    
130
        response.set_cookie('X-Auth-Token', value=user.auth_token, expires = expire_fmt, path='/')
131
        response[self.auth_token] = user.auth_token
132
        response['Location'] = settings.APP_INSTALL_URL
133
        response.status_code = 302
134
        return response