Revision 35c82779

b/pithos/im/api.py
1
from traceback import format_exc
2
from time import time, mktime
3
from django.conf import settings
4
from django.http import HttpResponse
5
from django.utils import simplejson as json
6

  
7
from pithos.im.faults import BadRequest, Unauthorized, ServiceUnavailable
8
from pithos.im.models import User
9

  
10
import datetime
11

  
12
def render_fault(request, fault):
13
    if settings.DEBUG or settings.TEST:
14
        fault.details = format_exc(fault)
15
    
16
    request.serialization = 'text'
17
    data = '\n'.join((fault.message, fault.details)) + '\n'
18
    response = HttpResponse(data, status=fault.code)
19
    return response
20

  
21
def update_response_headers(response):
22
    response['Content-Type'] = 'application/json; charset=UTF-8'
23
    response['Content-Length'] = len(response.content)
24

  
25
def authenticate(request):
26
    # Normal Response Codes: 204
27
    # Error Response Codes: serviceUnavailable (503)
28
    #                       badRequest (400)
29
    #                       unauthorised (401)
30
    try:
31
        if request.method != 'GET':
32
            raise BadRequest('Method not allowed.')
33
        x_auth_token = request.META.get('HTTP_X_AUTH_TOKEN')
34
        if not x_auth_token:
35
            return render_fault(request, BadRequest('Missing X-Auth-Token'))
36
        
37
        try:
38
            user = User.objects.get(auth_token=x_auth_token)
39
        except User.DoesNotExist, e:
40
            return render_fault(request, Unauthorized('Invalid X-Auth-Token')) 
41
        
42
        # Check if the is active.
43
        if user.state != 'ACTIVE':
44
            return render_fault(request, Unauthorized('User inactive'))
45
        
46
        # Check if the token has expired.
47
        if (time() - mktime(user.auth_token_expires.timetuple())) > 0:
48
            return render_fault(request, Unauthorized('Authentication expired'))
49
        
50
        response = HttpResponse()
51
        response.status=204
52
        user_info = user.__dict__
53
        for k,v in user_info.items():
54
            if isinstance(v,  datetime.datetime):
55
                user_info[k] = v.strftime('%a, %d-%b-%Y %H:%M:%S %Z')
56
        user_info.pop('_state')
57
        response.content = json.dumps(user_info)
58
        update_response_headers(response)
59
        return response
60
    except BaseException, e:
61
        fault = ServiceUnavailable('Unexpected error')
62
        return render_fault(request, fault)
b/pithos/im/faults.py
1
# Copyright 2011 GRNET S.A. All rights reserved.
2
# 
3
# Redistribution and use in source and binary forms, with or
4
# without modification, are permitted provided that the following
5
# conditions are met:
6
# 
7
#   1. Redistributions of source code must retain the above
8
#      copyright notice, this list of conditions and the following
9
#      disclaimer.
10
# 
11
#   2. Redistributions in binary form must reproduce the above
12
#      copyright notice, this list of conditions and the following
13
#      disclaimer in the documentation and/or other materials
14
#      provided with the distribution.
15
# 
16
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
# POSSIBILITY OF SUCH DAMAGE.
28
# 
29
# The views and conclusions contained in the software and
30
# documentation are those of the authors and should not be
31
# interpreted as representing official policies, either expressed
32
# or implied, of GRNET S.A.
33

  
34
def camelCase(s):
35
    return s[0].lower() + s[1:]
36

  
37
class Fault(Exception):
38
    def __init__(self, message='', details='', name=''):
39
        Exception.__init__(self, message, details, name)
40
        self.message = message
41
        self.details = details
42
        self.name = name or camelCase(self.__class__.__name__)
43

  
44
class BadRequest(Fault):
45
    code = 400
46

  
47
class Unauthorized(Fault):
48
    code = 401
49

  
50
class ServiceUnavailable(Fault):
51
    code = 503
b/pithos/im/urls.py
100 100
        (r'^login/twitter/?$', 'twitter.login'),
101 101
        (r'^login/twitter/authenticated/?$', 'twitter.authenticated')
102 102
    )
103

  
104
urlpatterns += patterns('pithos.im.api',
105
    (r'^authenticate/?$', 'authenticate')
106
)
107
    
b/pithos/lib/client.py
932 932
        headers[quote(k)] = quote(v, safe='/=,:@ *"') if type(v) == types.StringType else v
933 933
    return headers
934 934

  
935
def _handle_response(response, verbose, debug):
935
def _handle_response(response, verbose=False, debug=False):
936 936
    headers = response.getheaders()
937 937
    headers = dict((unquote(h), unquote(v)) for h,v in headers)
938 938
    
......
952 952
        raise Fault(data, int(response.status))
953 953
    
954 954
    #print '**',  response.status, headers, data, '\n'
955
    return response.status, headers, data
955
    return response.status, headers, data
956

  
957
def authenticate(authentication_host, token):
958
    con = HTTPConnection(authentication_host)
959
    kwargs = {}
960
    kwargs['headers'] = {}
961
    kwargs['headers']['X-Auth-Token'] = token
962
    kwargs['headers']['Content-Length'] = 0
963
    
964
    path = '/im/authenticate'
965
    con.request('GET', path, **kwargs)
966
    response = con.getresponse()
967
    return _handle_response(response)
b/pithos/middleware/auth.py
33 33

  
34 34
from time import time, mktime
35 35
from urllib import quote, unquote
36
from django.conf import settings
37
from django.utils import simplejson as json
36 38

  
37 39
from pithos.im.models import User
38

  
40
from pithos.lib.client import authenticate, Fault
39 41

  
40 42
def get_user_from_token(token):
43
    if not token:
44
        return None
45
    
46
    host = settings.AUTHENTICATION_HOST
41 47
    try:
42
        return User.objects.get(auth_token=token)
43
    except User.DoesNotExist:
48
        status, headers, user = authenticate(host, token)
49
        return json.loads(user)
50
    except Fault, f:
44 51
        return None
45 52

  
46

  
47 53
class AuthMiddleware(object):
48 54
    def process_request(self, request):
49
        request.user = None
50
        request.user_uniq = None
51
        
52
        # Try to find token in a parameter, in a request header, or in a cookie.
53
        user = get_user_from_token(request.GET.get('X-Auth-Token'))
54
        if not user:
55
            user = get_user_from_token(request.META.get('HTTP_X_AUTH_TOKEN'))
56
        if not user:
57
            # Back from an im login target.
58
            if request.GET.get('user', None):
59
                token = request.GET.get('token', None)
60
                if token:
61
                    request.set_auth_cookie = True
62
                user = get_user_from_token(token)
55
        try:
56
            host, port = settings.AUTHENTICATION_HOST.split(':')
57
            if request.META['SERVER_NAME'] and request.META['SERVER_PORT'] == port:
58
                #bypass authentication
59
                #if it is an authentication request
60
                return
61
            
62
            request.user = None
63
            request.user_uniq = None
64
            
65
            # Try to find token in a parameter, in a request header, or in a cookie.
66
            user = get_user_from_token(request.GET.get('X-Auth-Token'))
67
            if not user:
68
                user = get_user_from_token(request.META.get('HTTP_X_AUTH_TOKEN'))
63 69
            if not user:
64
                cookie_value = unquote(request.COOKIES.get('_pithos2_a', ''))
65
                if cookie_value and '|' in cookie_value:
66
                    token = cookie_value.split('|', 1)[1]
70
                # Back from an im login target.
71
                if request.GET.get('user', None):
72
                    token = request.GET.get('token', None)
73
                    if token:
74
                        request.set_auth_cookie = True
67 75
                    user = get_user_from_token(token)
68
        if not user:
69
            return
70
        
71
        # Check if the is active.
72
        if user.state != 'ACTIVE':
73
            return
74
        
75
        # Check if the token has expired.
76
        if (time() - mktime(user.auth_token_expires.timetuple())) > 0:
77
            return
78
        
79
        request.user = user
80
        request.user_uniq = user.uniq
76
                if not user:
77
                    cookie_value = unquote(request.COOKIES.get('_pithos2_a', ''))
78
                    if cookie_value and '|' in cookie_value:
79
                        token = cookie_value.split('|', 1)[1]
80
                        user = get_user_from_token(token)
81
            if not user:
82
                return
83
            
84
            request.user = user
85
            request.user_uniq = user['uniq']
86
        except Exception, e:
87
            print e
81 88
    
82 89
    def process_response(self, request, response):
83 90
        if getattr(request, 'user', None) and getattr(request, 'set_auth_cookie', False):
b/pithos/settings.d/00-apps.conf
25 25
    'pithos.ui',
26 26
    'south'
27 27
)
28

  
29
#where astakos is hosted
30
AUTHENTICATION_HOST = '127.0.0.1:10000'

Also available in: Unified diff