1 | ''' |
---|
2 | BSD Licence |
---|
3 | Copyright (c) 2012, Science & Technology Facilities Council (STFC) |
---|
4 | All rights reserved. |
---|
5 | |
---|
6 | Redistribution and use in source and binary forms, with or without modification, |
---|
7 | are permitted provided that the following conditions are met: |
---|
8 | |
---|
9 | * Redistributions of source code must retain the above copyright notice, |
---|
10 | this list of conditions and the following disclaimer. |
---|
11 | * Redistributions in binary form must reproduce the above copyright notice, |
---|
12 | this list of conditions and the following disclaimer in the documentation |
---|
13 | and/or other materials provided with the distribution. |
---|
14 | * Neither the name of the Science & Technology Facilities Council (STFC) |
---|
15 | nor the names of its contributors may be used to endorse or promote |
---|
16 | products derived from this software without specific prior written permission. |
---|
17 | |
---|
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
---|
19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
---|
20 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
---|
21 | PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS |
---|
22 | BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, |
---|
23 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
---|
24 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
---|
25 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
---|
26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
---|
27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
---|
28 | |
---|
29 | Created on 2 Nov 2012 |
---|
30 | |
---|
31 | @author: mnagni |
---|
32 | ''' |
---|
33 | from paste.auth.auth_tkt import AuthTicket |
---|
34 | from django.conf import settings |
---|
35 | from django.db.utils import DatabaseError |
---|
36 | from dj_security.exception import DSJOpenIDNotFoundError |
---|
37 | from dj_security.encoder import SecurityEncoder |
---|
38 | from django.shortcuts import render_to_response, redirect |
---|
39 | |
---|
40 | from userdb_model.models import User |
---|
41 | |
---|
42 | import socket |
---|
43 | import urlparse |
---|
44 | import base64 |
---|
45 | import logging |
---|
46 | |
---|
47 | # Get an instance of a logger |
---|
48 | LOGGER = logging.getLogger(__name__) |
---|
49 | |
---|
50 | class DJS_Middleware(object): |
---|
51 | """ |
---|
52 | Validates if the actual user is authenticated agains a |
---|
53 | given authentication service. |
---|
54 | Actually the middleware intercepts all the requests submitted |
---|
55 | to the underlying Django application and verifies if the presence |
---|
56 | or not of a valid paste cookie in the request. |
---|
57 | """ |
---|
58 | |
---|
59 | def process_request(self, request): |
---|
60 | pass |
---|
61 | |
---|
62 | def process_response(self, request, response): |
---|
63 | session = getattr(request, 'session', None) |
---|
64 | |
---|
65 | if not session: |
---|
66 | return response |
---|
67 | |
---|
68 | if request.GET.get('r') and getattr(request, 'session', None): |
---|
69 | request.session['r'] = request.GET.get('r') |
---|
70 | |
---|
71 | if '/complete/' not in request.path: |
---|
72 | request.session['done'] = False |
---|
73 | return response |
---|
74 | |
---|
75 | if request.path == '/account/signin/complete/' and not request.session.get('done', False): |
---|
76 | return _encode_authenticated_response(request) |
---|
77 | |
---|
78 | if request.path == '/account/signin/complete/' and request.session.get('done', False): |
---|
79 | return response |
---|
80 | |
---|
81 | remote_ip = _calculate_remote_ip(base64.b64decode(request.session.get('r'))) |
---|
82 | LOGGER.debug("responding to remote_ip: %s" % (remote_ip)) |
---|
83 | username = session.get('openid').openid |
---|
84 | user = get_user_byopenid(username) |
---|
85 | |
---|
86 | token = AuthTicket( |
---|
87 | getattr(settings, 'SHARED_SECRET', 'sharedsecret'), |
---|
88 | username, |
---|
89 | remote_ip, |
---|
90 | user_data = '{"userkey": "%s"}' % (user.userkey)) |
---|
91 | LOGGER.debug("Created authTicket for %s from %s" % (username, remote_ip)) |
---|
92 | response.set_cookie('auth_tkt', |
---|
93 | token.cookie_value(), |
---|
94 | domain = getattr(settings, 'COOKIE_DOMAIN', None)) |
---|
95 | LOGGER.debug("Set authTicket in response for %s from %s" % (username, remote_ip)) |
---|
96 | return response |
---|
97 | |
---|
98 | |
---|
99 | def _calculate_remote_ip(url_path): |
---|
100 | remote_url = urlparse.urlparse(url_path) |
---|
101 | LOGGER.debug("calculating remote_ip for %s" % (str(remote_url))) |
---|
102 | port = 80 |
---|
103 | host = None |
---|
104 | if remote_url.netloc: |
---|
105 | host = remote_url.netloc |
---|
106 | elif remote_url.path: |
---|
107 | host = remote_url.path |
---|
108 | |
---|
109 | if not host: |
---|
110 | return None |
---|
111 | |
---|
112 | if ':' in host: |
---|
113 | host, port = host.split(':') |
---|
114 | addrinfo = socket.getaddrinfo(host, int(port)) |
---|
115 | LOGGER.debug("%s has remote_ip %s" % (url_path, addrinfo[0][-1][0])) |
---|
116 | return addrinfo[0][-1][0] |
---|
117 | |
---|
118 | def get_user_byopenid(openid): |
---|
119 | """ |
---|
120 | Returns a tbusers row specified by `openid` |
---|
121 | - String **userkey** |
---|
122 | a user |
---|
123 | """ |
---|
124 | try: |
---|
125 | return User.objects.get(openid=openid) |
---|
126 | except DatabaseError as ex: |
---|
127 | logging.error("Openid: %s - Not Found" % openid) |
---|
128 | raise DSJOpenIDNotFoundError(ex) |
---|
129 | |
---|
130 | def _encode_authenticated_response(request, context = {}): |
---|
131 | request.session['done'] = True |
---|
132 | redirect_parameter = getattr(settings, 'REDIRECT_URL', 'r') |
---|
133 | context['redirect_url'] = base64.b64decode(request.session.get(redirect_parameter, '')) |
---|
134 | return render_to_response('logged_in.html', context) |
---|