Statistics
| Branch: | Tag: | Revision:

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

History | View | Annotate | Download (6.1 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 7bffb0bd Kostas Papadimitriou
from urllib import quote, unquote, urlencode
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 050485bd Sofia Papagiannaki
                        # In case of Unauthorized response
62 050485bd Sofia Papagiannaki
                        # or Not Found return directly
63 c700f742 Sofia Papagiannaki
                        if status == 401 or status == 404:
64 c700f742 Sofia Papagiannaki
                            raise e
65 c700f742 Sofia Papagiannaki
                    attempts += 1
66 c700f742 Sofia Papagiannaki
        return f
67 c700f742 Sofia Papagiannaki
    return execute
68 c700f742 Sofia Papagiannaki
69 c700f742 Sofia Papagiannaki
def call(token, url, headers={}):
70 c700f742 Sofia Papagiannaki
    p = urlparse(url)
71 d65af928 Kostas Papadimitriou
72 8acb1f97 Kostas Papadimitriou
    kwargs = {}
73 c700f742 Sofia Papagiannaki
    kwargs['headers'] = headers
74 8acb1f97 Kostas Papadimitriou
    kwargs['headers']['X-Auth-Token'] = token
75 8acb1f97 Kostas Papadimitriou
    kwargs['headers']['Content-Length'] = 0
76 d65af928 Kostas Papadimitriou
77 27cfa807 Vangelis Koukis
    conn = get_http_connection(p.netloc, p.scheme)
78 27cfa807 Vangelis Koukis
    try:
79 7bffb0bd Kostas Papadimitriou
        conn.request('GET', p.path + '?' + p.query, **kwargs)
80 27cfa807 Vangelis Koukis
        response = conn.getresponse()
81 27cfa807 Vangelis Koukis
        headers = response.getheaders()
82 27cfa807 Vangelis Koukis
        headers = dict((unquote(h), unquote(v)) for h,v in headers)
83 27cfa807 Vangelis Koukis
        length = response.getheader('content-length', None)
84 27cfa807 Vangelis Koukis
        data = response.read(length)
85 27cfa807 Vangelis Koukis
        status = int(response.status)
86 27cfa807 Vangelis Koukis
    finally:
87 27cfa807 Vangelis Koukis
        conn.close()
88 d65af928 Kostas Papadimitriou
89 8acb1f97 Kostas Papadimitriou
    if status < 200 or status >= 300:
90 27cfa807 Vangelis Koukis
        raise Exception(data, status)
91 83204389 Kostas Papadimitriou
92 8acb1f97 Kostas Papadimitriou
    return json.loads(data)
93 8acb1f97 Kostas Papadimitriou
94 c700f742 Sofia Papagiannaki
95 050485bd Sofia Papagiannaki
def authenticate(
96 7bffb0bd Kostas Papadimitriou
        token, authentication_url='http://127.0.0.1:8000/im/authenticate',
97 7bffb0bd Kostas Papadimitriou
        usage=False):
98 7bffb0bd Kostas Papadimitriou
99 7bffb0bd Kostas Papadimitriou
    if usage:
100 7bffb0bd Kostas Papadimitriou
        authentication_url += "?usage=1"
101 7bffb0bd Kostas Papadimitriou
102 c700f742 Sofia Papagiannaki
    return call(token, authentication_url)
103 c700f742 Sofia Papagiannaki
104 7bffb0bd Kostas Papadimitriou
105 c700f742 Sofia Papagiannaki
@retry(3)
106 050485bd Sofia Papagiannaki
def get_username(
107 050485bd Sofia Papagiannaki
        token,
108 050485bd Sofia Papagiannaki
        uuid,
109 050485bd Sofia Papagiannaki
        url='http://127.0.0.1:8000/im/service/api/v2.0/users',
110 050485bd Sofia Papagiannaki
        override_users={}):
111 050485bd Sofia Papagiannaki
    if override_users:
112 050485bd Sofia Papagiannaki
        return uuid
113 c700f742 Sofia Papagiannaki
    try:
114 c700f742 Sofia Papagiannaki
        data = call(token, url, {'X-User-Uuid': uuid})
115 c700f742 Sofia Papagiannaki
    except Exception, e:
116 c700f742 Sofia Papagiannaki
        raise e
117 c700f742 Sofia Papagiannaki
    else:
118 c700f742 Sofia Papagiannaki
        return data.get('username')
119 c700f742 Sofia Papagiannaki
120 c700f742 Sofia Papagiannaki
121 c700f742 Sofia Papagiannaki
@retry(3)
122 050485bd Sofia Papagiannaki
def get_user_uuid(
123 050485bd Sofia Papagiannaki
        token,
124 050485bd Sofia Papagiannaki
        username,
125 050485bd Sofia Papagiannaki
        url='http://127.0.0.1:8000/im/service/api/v2.0/users',
126 050485bd Sofia Papagiannaki
        override_users={}):
127 050485bd Sofia Papagiannaki
    if override_users:
128 050485bd Sofia Papagiannaki
        return username
129 c700f742 Sofia Papagiannaki
    try:
130 c700f742 Sofia Papagiannaki
        data = call(token, url, {'X-User-Username': username})
131 c700f742 Sofia Papagiannaki
    except Exception, e:
132 c700f742 Sofia Papagiannaki
        raise e
133 c700f742 Sofia Papagiannaki
    else:
134 c700f742 Sofia Papagiannaki
        return data.get('uuid')
135 c700f742 Sofia Papagiannaki
136 c700f742 Sofia Papagiannaki
137 7bffb0bd Kostas Papadimitriou
def user_for_token(token, authentication_url, override_users, usage=False):
138 8acb1f97 Kostas Papadimitriou
    if not token:
139 8acb1f97 Kostas Papadimitriou
        return None
140 d65af928 Kostas Papadimitriou
141 8acb1f97 Kostas Papadimitriou
    if override_users:
142 8acb1f97 Kostas Papadimitriou
        try:
143 050485bd Sofia Papagiannaki
            return {'uuid': override_users[token].decode('utf8')}
144 8acb1f97 Kostas Papadimitriou
        except:
145 8acb1f97 Kostas Papadimitriou
            return None
146 d65af928 Kostas Papadimitriou
147 8acb1f97 Kostas Papadimitriou
    try:
148 7bffb0bd Kostas Papadimitriou
        return authenticate(token, authentication_url, usage=usage)
149 1055f3c6 Sofia Papagiannaki
    except Exception, e:
150 1055f3c6 Sofia Papagiannaki
        # In case of Unauthorized response return None
151 1055f3c6 Sofia Papagiannaki
        if e.args and e.args[-1] == 401:
152 1055f3c6 Sofia Papagiannaki
            return None
153 1055f3c6 Sofia Papagiannaki
        raise e
154 8acb1f97 Kostas Papadimitriou
155 050485bd Sofia Papagiannaki
def get_user(
156 050485bd Sofia Papagiannaki
        request,
157 050485bd Sofia Papagiannaki
        authentication_url='http://127.0.0.1:8000/im/authenticate',
158 050485bd Sofia Papagiannaki
        override_users={},
159 7bffb0bd Kostas Papadimitriou
        fallback_token=None,
160 7bffb0bd Kostas Papadimitriou
        usage=False):
161 8acb1f97 Kostas Papadimitriou
    request.user = None
162 8acb1f97 Kostas Papadimitriou
    request.user_uniq = None
163 d65af928 Kostas Papadimitriou
164 8acb1f97 Kostas Papadimitriou
    # Try to find token in a parameter or in a request header.
165 050485bd Sofia Papagiannaki
    user = user_for_token(
166 7bffb0bd Kostas Papadimitriou
        request.GET.get('X-Auth-Token'), authentication_url, override_users,
167 7bffb0bd Kostas Papadimitriou
        usage=usage)
168 8acb1f97 Kostas Papadimitriou
    if not user:
169 050485bd Sofia Papagiannaki
        user = user_for_token(
170 050485bd Sofia Papagiannaki
            request.META.get('HTTP_X_AUTH_TOKEN'),
171 050485bd Sofia Papagiannaki
            authentication_url,
172 7bffb0bd Kostas Papadimitriou
            override_users,
173 7bffb0bd Kostas Papadimitriou
            usage=usage)
174 8acb1f97 Kostas Papadimitriou
    if not user:
175 050485bd Sofia Papagiannaki
        user = user_for_token(
176 7bffb0bd Kostas Papadimitriou
            fallback_token, authentication_url, override_users,
177 7bffb0bd Kostas Papadimitriou
            usage=usage)
178 6b5b443b Antony Chazapis
    if not user:
179 83204389 Kostas Papadimitriou
        logger.warning("Cannot retrieve user details from %s",
180 83204389 Kostas Papadimitriou
                       authentication_url)
181 7bffb0bd Kostas Papadimitriou
        return None
182 d65af928 Kostas Papadimitriou
183 83204389 Kostas Papadimitriou
    # use user uuid, instead of email, keep email/username reference to user_id
184 83204389 Kostas Papadimitriou
    request.user_uniq = user['uuid']
185 8acb1f97 Kostas Papadimitriou
    request.user = user
186 050485bd Sofia Papagiannaki
    request.user_id = user.get('username')
187 83204389 Kostas Papadimitriou
    return user
188 d65af928 Kostas Papadimitriou
189 d65af928 Kostas Papadimitriou
190 d65af928 Kostas Papadimitriou
def get_token_from_cookie(request, cookiename):
191 d65af928 Kostas Papadimitriou
    """
192 d65af928 Kostas Papadimitriou
    Extract token from the cookie name provided. Cookie should be in the same
193 d65af928 Kostas Papadimitriou
    form as astakos service sets its cookie contents::
194 d65af928 Kostas Papadimitriou

195 d65af928 Kostas Papadimitriou
        <user_uniq>|<user_token>
196 d65af928 Kostas Papadimitriou
    """
197 d65af928 Kostas Papadimitriou
    try:
198 d65af928 Kostas Papadimitriou
        cookie_content = unquote(request.COOKIES.get(cookiename, None))
199 d65af928 Kostas Papadimitriou
        return cookie_content.split("|")[1]
200 d65af928 Kostas Papadimitriou
    except AttributeError:
201 d65af928 Kostas Papadimitriou
        pass
202 d65af928 Kostas Papadimitriou
203 d65af928 Kostas Papadimitriou
    return None