Statistics
| Branch: | Tag: | Revision:

root / snf-app / synnefo / aai / middleware.py @ 38d247df

History | View | Annotate | Download (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 django.utils.cache import patch_vary_headers
33
from synnefo.db.models import SynnefoUser
34
from synnefo.aai.shibboleth import Tokens, register_shibboleth_user
35
import time
36

    
37
DONT_CHECK = getattr(settings, "AAI_SKIP_AUTH_URLS", ['/api', '/invitations/login'])
38

    
39
class SynnefoAuthMiddleware(object):
40

    
41
    def process_request(self, request):
42

    
43
        for path in DONT_CHECK:
44
            if request.path.startswith(path):
45
                return
46

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

    
55
        token = None
56

    
57
        # Try to find token in a cookie
58
        token = request.COOKIES.get('X-Auth-Token', None)
59

    
60
        # Try to find token in request header
61
        if not token:
62
            token = request.META.get('HTTP_X_AUTH_TOKEN', None)
63

    
64
        if token:
65
            # token was found, retrieve user from backing store
66
            try:
67
                user = SynnefoUser.objects.get(auth_token=token)
68

    
69
            except SynnefoUser.DoesNotExist:
70
                return HttpResponseRedirect(settings.LOGIN_URL)
71
            # check user's auth token validity
72
            if (time.time() -
73
                time.mktime(user.auth_token_expires.timetuple())) > 0:
74
                # the user's token has expired, prompt to re-login
75
                return HttpResponseRedirect(settings.LOGIN_URL)
76

    
77
            request.user = user
78
            return
79

    
80
        # token was not found but user authenticated by Shibboleth
81
        if Tokens.SHIB_EPPN in request.META and \
82
           Tokens.SHIB_SESSION_ID in request.META:
83
            try:
84
                user = SynnefoUser.objects.get(uniq=request.META[Tokens.SHIB_EPPN])
85
                return self._redirect_shib_auth_user(user)
86
            except SynnefoUser.DoesNotExist:
87
                if register_shibboleth_user(request.META):
88
                    user = SynnefoUser.objects.get(uniq=request.META[Tokens.SHIB_EPPN])
89
                    return self._redirect_shib_auth_user(user)
90
                else:
91
                    return HttpResponseRedirect(settings.LOGIN_URL)
92

    
93
        if settings.TEST and 'TEST-AAI' in request.META:
94
            return HttpResponseRedirect(settings.LOGIN_URL)
95

    
96
        if request.path.endswith(settings.LOGIN_URL):
97
            # avoid redirect loops
98
            return
99
        else:
100
            # no authentication info found in headers, redirect back
101
            return HttpResponseRedirect(settings.LOGIN_URL)
102

    
103
    def process_response(self, request, response):
104
        # Tell proxies and other interested parties that the request varies
105
        # based on X-Auth-Token, to avoid caching of results
106
        patch_vary_headers(response, ('X-Auth-Token',))
107
        return response
108

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

    
112
        response = HttpResponse()
113
        response.set_cookie('X-Auth-Token', value=user.auth_token,
114
                            expires=expire_fmt, path='/')
115
        response['X-Auth-Token'] = user.auth_token
116
        response['Location'] = settings.APP_INSTALL_URL
117
        response.status_code = 302
118
        return response
119

    
120

    
121
def add_url_exception(url):
122
    if not url in DONT_CHECK:
123
        DONT_CHECK.append(url)