Statistics
| Branch: | Tag: | Revision:

root / snf-common / synnefo / lib / astakos.py @ cd5033bd

History | View | Annotate | Download (5.6 kB)

1 8acb1f97 Kostas Papadimitriou
# Copyright 2011-2012 GRNET S.A. All rights reserved.
2 d65af928 Kostas Papadimitriou
#
3 8acb1f97 Kostas Papadimitriou
# Redistribution and use in source and binary forms, with or
4 8acb1f97 Kostas Papadimitriou
# without modification, are permitted provided that the following
5 8acb1f97 Kostas Papadimitriou
# conditions are met:
6 d65af928 Kostas Papadimitriou
#
7 8acb1f97 Kostas Papadimitriou
#   1. Redistributions of source code must retain the above
8 8acb1f97 Kostas Papadimitriou
#      copyright notice, this list of conditions and the following
9 8acb1f97 Kostas Papadimitriou
#      disclaimer.
10 d65af928 Kostas Papadimitriou
#
11 8acb1f97 Kostas Papadimitriou
#   2. Redistributions in binary form must reproduce the above
12 8acb1f97 Kostas Papadimitriou
#      copyright notice, this list of conditions and the following
13 8acb1f97 Kostas Papadimitriou
#      disclaimer in the documentation and/or other materials
14 8acb1f97 Kostas Papadimitriou
#      provided with the distribution.
15 d65af928 Kostas Papadimitriou
#
16 8acb1f97 Kostas Papadimitriou
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 8acb1f97 Kostas Papadimitriou
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 8acb1f97 Kostas Papadimitriou
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 8acb1f97 Kostas Papadimitriou
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 8acb1f97 Kostas Papadimitriou
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 8acb1f97 Kostas Papadimitriou
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 8acb1f97 Kostas Papadimitriou
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 8acb1f97 Kostas Papadimitriou
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 8acb1f97 Kostas Papadimitriou
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 8acb1f97 Kostas Papadimitriou
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 8acb1f97 Kostas Papadimitriou
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 8acb1f97 Kostas Papadimitriou
# POSSIBILITY OF SUCH DAMAGE.
28 d65af928 Kostas Papadimitriou
#
29 8acb1f97 Kostas Papadimitriou
# The views and conclusions contained in the software and
30 8acb1f97 Kostas Papadimitriou
# documentation are those of the authors and should not be
31 8acb1f97 Kostas Papadimitriou
# interpreted as representing official policies, either expressed
32 8acb1f97 Kostas Papadimitriou
# or implied, of GRNET S.A.
33 8acb1f97 Kostas Papadimitriou
34 83204389 Kostas Papadimitriou
import logging
35 83204389 Kostas Papadimitriou
36 8acb1f97 Kostas Papadimitriou
from time import time, mktime
37 c700f742 Sofia Papagiannaki
from urlparse import urlparse, urlsplit, urlunsplit
38 8acb1f97 Kostas Papadimitriou
from urllib import quote, unquote
39 8acb1f97 Kostas Papadimitriou
40 8acb1f97 Kostas Papadimitriou
from django.conf import settings
41 8acb1f97 Kostas Papadimitriou
from django.utils import simplejson as json
42 c700f742 Sofia Papagiannaki
from django.utils.http import urlencode
43 8acb1f97 Kostas Papadimitriou
44 27cfa807 Vangelis Koukis
from synnefo.lib.pool.http import get_http_connection
45 27cfa807 Vangelis Koukis
46 83204389 Kostas Papadimitriou
logger = logging.getLogger(__name__)
47 8acb1f97 Kostas Papadimitriou
48 c700f742 Sofia Papagiannaki
def retry(howmany):
49 c700f742 Sofia Papagiannaki
    def execute(func):
50 c700f742 Sofia Papagiannaki
        def f(*args, **kwargs):
51 c700f742 Sofia Papagiannaki
            attempts = 0
52 cd5033bd Sofia Papagiannaki
            while True:
53 c700f742 Sofia Papagiannaki
                try:
54 c700f742 Sofia Papagiannaki
                    return func(*args, **kwargs)
55 c700f742 Sofia Papagiannaki
                except Exception, e:
56 cd5033bd Sofia Papagiannaki
                    is_last_attempt = attempts == howmany - 1
57 cd5033bd Sofia Papagiannaki
                    if is_last_attempt:
58 cd5033bd Sofia Papagiannaki
                        raise e
59 c700f742 Sofia Papagiannaki
                    if e.args:
60 c700f742 Sofia Papagiannaki
                        status = e.args[-1]
61 c700f742 Sofia Papagiannaki
                        # In case of Unauthorized response or Not Found return directly
62 c700f742 Sofia Papagiannaki
                        if status == 401 or status == 404:
63 c700f742 Sofia Papagiannaki
                            raise e
64 c700f742 Sofia Papagiannaki
                    attempts += 1
65 c700f742 Sofia Papagiannaki
        return f
66 c700f742 Sofia Papagiannaki
    return execute
67 c700f742 Sofia Papagiannaki
68 c700f742 Sofia Papagiannaki
def call(token, url, headers={}):
69 c700f742 Sofia Papagiannaki
    p = urlparse(url)
70 d65af928 Kostas Papadimitriou
71 8acb1f97 Kostas Papadimitriou
    kwargs = {}
72 c700f742 Sofia Papagiannaki
    kwargs['headers'] = headers
73 8acb1f97 Kostas Papadimitriou
    kwargs['headers']['X-Auth-Token'] = token
74 8acb1f97 Kostas Papadimitriou
    kwargs['headers']['Content-Length'] = 0
75 d65af928 Kostas Papadimitriou
76 27cfa807 Vangelis Koukis
    conn = get_http_connection(p.netloc, p.scheme)
77 27cfa807 Vangelis Koukis
    try:
78 27cfa807 Vangelis Koukis
        conn.request('GET', p.path, **kwargs)
79 27cfa807 Vangelis Koukis
        response = conn.getresponse()
80 27cfa807 Vangelis Koukis
        headers = response.getheaders()
81 27cfa807 Vangelis Koukis
        headers = dict((unquote(h), unquote(v)) for h,v in headers)
82 27cfa807 Vangelis Koukis
        length = response.getheader('content-length', None)
83 27cfa807 Vangelis Koukis
        data = response.read(length)
84 27cfa807 Vangelis Koukis
        status = int(response.status)
85 27cfa807 Vangelis Koukis
    finally:
86 27cfa807 Vangelis Koukis
        conn.close()
87 d65af928 Kostas Papadimitriou
88 8acb1f97 Kostas Papadimitriou
    if status < 200 or status >= 300:
89 27cfa807 Vangelis Koukis
        raise Exception(data, status)
90 83204389 Kostas Papadimitriou
91 8acb1f97 Kostas Papadimitriou
    return json.loads(data)
92 8acb1f97 Kostas Papadimitriou
93 c700f742 Sofia Papagiannaki
94 c700f742 Sofia Papagiannaki
def authenticate(token, authentication_url='http://127.0.0.1:8000/im/authenticate'):
95 c700f742 Sofia Papagiannaki
    return call(token, authentication_url)
96 c700f742 Sofia Papagiannaki
97 c700f742 Sofia Papagiannaki
@retry(3)
98 c700f742 Sofia Papagiannaki
def get_username(token, uuid, url='http://127.0.0.1:8000/im/service/api/v2.0/users'):
99 c700f742 Sofia Papagiannaki
    try:
100 c700f742 Sofia Papagiannaki
        data = call(token, url, {'X-User-Uuid': uuid})
101 c700f742 Sofia Papagiannaki
    except Exception, e:
102 c700f742 Sofia Papagiannaki
        raise e
103 c700f742 Sofia Papagiannaki
    else:
104 c700f742 Sofia Papagiannaki
        return data.get('username')
105 c700f742 Sofia Papagiannaki
106 c700f742 Sofia Papagiannaki
107 c700f742 Sofia Papagiannaki
@retry(3)
108 c700f742 Sofia Papagiannaki
def get_user_uuid(token, username, url='http://127.0.0.1:8000/im/service/api/v2.0/users'):
109 c700f742 Sofia Papagiannaki
    try:
110 c700f742 Sofia Papagiannaki
        data = call(token, url, {'X-User-Username': username})
111 c700f742 Sofia Papagiannaki
    except Exception, e:
112 c700f742 Sofia Papagiannaki
        raise e
113 c700f742 Sofia Papagiannaki
    else:
114 c700f742 Sofia Papagiannaki
        return data.get('uuid')
115 c700f742 Sofia Papagiannaki
116 c700f742 Sofia Papagiannaki
117 8acb1f97 Kostas Papadimitriou
def user_for_token(token, authentication_url, override_users):
118 8acb1f97 Kostas Papadimitriou
    if not token:
119 8acb1f97 Kostas Papadimitriou
        return None
120 d65af928 Kostas Papadimitriou
121 8acb1f97 Kostas Papadimitriou
    if override_users:
122 8acb1f97 Kostas Papadimitriou
        try:
123 8acb1f97 Kostas Papadimitriou
            return {'uniq': override_users[token].decode('utf8')}
124 8acb1f97 Kostas Papadimitriou
        except:
125 8acb1f97 Kostas Papadimitriou
            return None
126 d65af928 Kostas Papadimitriou
127 8acb1f97 Kostas Papadimitriou
    try:
128 8acb1f97 Kostas Papadimitriou
        return authenticate(token, authentication_url)
129 1055f3c6 Sofia Papagiannaki
    except Exception, e:
130 1055f3c6 Sofia Papagiannaki
        # In case of Unauthorized response return None
131 1055f3c6 Sofia Papagiannaki
        if e.args and e.args[-1] == 401:
132 1055f3c6 Sofia Papagiannaki
            return None
133 1055f3c6 Sofia Papagiannaki
        raise e
134 8acb1f97 Kostas Papadimitriou
135 6b5b443b Antony Chazapis
def get_user(request, authentication_url='http://127.0.0.1:8000/im/authenticate', override_users={}, fallback_token=None):
136 8acb1f97 Kostas Papadimitriou
    request.user = None
137 8acb1f97 Kostas Papadimitriou
    request.user_uniq = None
138 d65af928 Kostas Papadimitriou
139 8acb1f97 Kostas Papadimitriou
    # Try to find token in a parameter or in a request header.
140 8acb1f97 Kostas Papadimitriou
    user = user_for_token(request.GET.get('X-Auth-Token'), authentication_url, override_users)
141 8acb1f97 Kostas Papadimitriou
    if not user:
142 8acb1f97 Kostas Papadimitriou
        user = user_for_token(request.META.get('HTTP_X_AUTH_TOKEN'), authentication_url, override_users)
143 8acb1f97 Kostas Papadimitriou
    if not user:
144 6b5b443b Antony Chazapis
        user = user_for_token(fallback_token, authentication_url, override_users)
145 6b5b443b Antony Chazapis
    if not user:
146 83204389 Kostas Papadimitriou
        logger.warning("Cannot retrieve user details from %s",
147 83204389 Kostas Papadimitriou
                       authentication_url)
148 8acb1f97 Kostas Papadimitriou
        return
149 d65af928 Kostas Papadimitriou
150 83204389 Kostas Papadimitriou
    # use user uuid, instead of email, keep email/username reference to user_id
151 83204389 Kostas Papadimitriou
    request.user_uniq = user['uuid']
152 8acb1f97 Kostas Papadimitriou
    request.user = user
153 83204389 Kostas Papadimitriou
    request.user_id = user['username']
154 83204389 Kostas Papadimitriou
    return user
155 d65af928 Kostas Papadimitriou
156 d65af928 Kostas Papadimitriou
157 d65af928 Kostas Papadimitriou
def get_token_from_cookie(request, cookiename):
158 d65af928 Kostas Papadimitriou
    """
159 d65af928 Kostas Papadimitriou
    Extract token from the cookie name provided. Cookie should be in the same
160 d65af928 Kostas Papadimitriou
    form as astakos service sets its cookie contents::
161 d65af928 Kostas Papadimitriou

162 d65af928 Kostas Papadimitriou
        <user_uniq>|<user_token>
163 d65af928 Kostas Papadimitriou
    """
164 d65af928 Kostas Papadimitriou
    try:
165 d65af928 Kostas Papadimitriou
        cookie_content = unquote(request.COOKIES.get(cookiename, None))
166 d65af928 Kostas Papadimitriou
        return cookie_content.split("|")[1]
167 d65af928 Kostas Papadimitriou
    except AttributeError:
168 d65af928 Kostas Papadimitriou
        pass
169 d65af928 Kostas Papadimitriou
170 d65af928 Kostas Papadimitriou
    return None