Statistics
| Branch: | Tag: | Revision:

root / snf-common / synnefo / lib / astakos.py @ 784dcbdb

History | View | Annotate | Download (7 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 74d988b0 Christos Stavrakakis
from urlparse import urlparse
37 74d988b0 Christos Stavrakakis
from urllib import unquote
38 8acb1f97 Kostas Papadimitriou
from django.utils import simplejson as json
39 8acb1f97 Kostas Papadimitriou
40 27cfa807 Vangelis Koukis
from synnefo.lib.pool.http import get_http_connection
41 27cfa807 Vangelis Koukis
42 83204389 Kostas Papadimitriou
logger = logging.getLogger(__name__)
43 8acb1f97 Kostas Papadimitriou
44 74d988b0 Christos Stavrakakis
45 c700f742 Sofia Papagiannaki
def retry(howmany):
46 c700f742 Sofia Papagiannaki
    def execute(func):
47 c700f742 Sofia Papagiannaki
        def f(*args, **kwargs):
48 c700f742 Sofia Papagiannaki
            attempts = 0
49 cd5033bd Sofia Papagiannaki
            while True:
50 c700f742 Sofia Papagiannaki
                try:
51 c700f742 Sofia Papagiannaki
                    return func(*args, **kwargs)
52 c700f742 Sofia Papagiannaki
                except Exception, e:
53 cd5033bd Sofia Papagiannaki
                    is_last_attempt = attempts == howmany - 1
54 cd5033bd Sofia Papagiannaki
                    if is_last_attempt:
55 cd5033bd Sofia Papagiannaki
                        raise e
56 c700f742 Sofia Papagiannaki
                    if e.args:
57 c700f742 Sofia Papagiannaki
                        status = e.args[-1]
58 050485bd Sofia Papagiannaki
                        # In case of Unauthorized response
59 050485bd Sofia Papagiannaki
                        # or Not Found return directly
60 c700f742 Sofia Papagiannaki
                        if status == 401 or status == 404:
61 c700f742 Sofia Papagiannaki
                            raise e
62 c700f742 Sofia Papagiannaki
                    attempts += 1
63 c700f742 Sofia Papagiannaki
        return f
64 c700f742 Sofia Papagiannaki
    return execute
65 c700f742 Sofia Papagiannaki
66 74d988b0 Christos Stavrakakis
67 890c2065 Sofia Papagiannaki
def call(token, url, headers={}, body=None, method='GET'):
68 c700f742 Sofia Papagiannaki
    p = urlparse(url)
69 d65af928 Kostas Papadimitriou
70 8acb1f97 Kostas Papadimitriou
    kwargs = {}
71 c700f742 Sofia Papagiannaki
    kwargs['headers'] = headers
72 8acb1f97 Kostas Papadimitriou
    kwargs['headers']['X-Auth-Token'] = token
73 890c2065 Sofia Papagiannaki
    if body:
74 890c2065 Sofia Papagiannaki
        kwargs['body'] = body
75 74d988b0 Christos Stavrakakis
        kwargs['headers'].setdefault('content-type',
76 74d988b0 Christos Stavrakakis
                                     'application/octet-stream')
77 890c2065 Sofia Papagiannaki
    kwargs['headers'].setdefault('content-length', len(body) if body else 0)
78 890c2065 Sofia Papagiannaki
79 27cfa807 Vangelis Koukis
    conn = get_http_connection(p.netloc, p.scheme)
80 27cfa807 Vangelis Koukis
    try:
81 890c2065 Sofia Papagiannaki
        conn.request(method, p.path + '?' + p.query, **kwargs)
82 27cfa807 Vangelis Koukis
        response = conn.getresponse()
83 27cfa807 Vangelis Koukis
        headers = response.getheaders()
84 74d988b0 Christos Stavrakakis
        headers = dict((unquote(h), unquote(v)) for h, v in headers)
85 27cfa807 Vangelis Koukis
        length = response.getheader('content-length', None)
86 27cfa807 Vangelis Koukis
        data = response.read(length)
87 27cfa807 Vangelis Koukis
        status = int(response.status)
88 27cfa807 Vangelis Koukis
    finally:
89 27cfa807 Vangelis Koukis
        conn.close()
90 d65af928 Kostas Papadimitriou
91 8acb1f97 Kostas Papadimitriou
    if status < 200 or status >= 300:
92 27cfa807 Vangelis Koukis
        raise Exception(data, status)
93 83204389 Kostas Papadimitriou
94 8acb1f97 Kostas Papadimitriou
    return json.loads(data)
95 8acb1f97 Kostas Papadimitriou
96 c700f742 Sofia Papagiannaki
97 050485bd Sofia Papagiannaki
def authenticate(
98 7bffb0bd Kostas Papadimitriou
        token, authentication_url='http://127.0.0.1:8000/im/authenticate',
99 7bffb0bd Kostas Papadimitriou
        usage=False):
100 7bffb0bd Kostas Papadimitriou
101 7bffb0bd Kostas Papadimitriou
    if usage:
102 7bffb0bd Kostas Papadimitriou
        authentication_url += "?usage=1"
103 7bffb0bd Kostas Papadimitriou
104 c700f742 Sofia Papagiannaki
    return call(token, authentication_url)
105 c700f742 Sofia Papagiannaki
106 7bffb0bd Kostas Papadimitriou
107 c700f742 Sofia Papagiannaki
@retry(3)
108 890c2065 Sofia Papagiannaki
def get_displaynames(
109 050485bd Sofia Papagiannaki
        token,
110 890c2065 Sofia Papagiannaki
        uuids,
111 890c2065 Sofia Papagiannaki
        url='http://127.0.0.1:8000/user_catalogs',
112 050485bd Sofia Papagiannaki
        override_users={}):
113 0308f3a7 Sofia Papagiannaki
114 890c2065 Sofia Papagiannaki
    if override_users:
115 74d988b0 Christos Stavrakakis
        return dict((u, u) for u in uuids)
116 0308f3a7 Sofia Papagiannaki
117 c700f742 Sofia Papagiannaki
    try:
118 890c2065 Sofia Papagiannaki
        data = call(
119 74d988b0 Christos Stavrakakis
            token, url,  headers={'content-type': 'application/json'},
120 74d988b0 Christos Stavrakakis
            body=json.dumps({'uuids': uuids}), method='POST')
121 e31e4274 Sofia Papagiannaki
    except:
122 e31e4274 Sofia Papagiannaki
        raise
123 c700f742 Sofia Papagiannaki
    else:
124 890c2065 Sofia Papagiannaki
        return data.get('uuid_catalog')
125 c700f742 Sofia Papagiannaki
126 c700f742 Sofia Papagiannaki
127 c700f742 Sofia Papagiannaki
@retry(3)
128 890c2065 Sofia Papagiannaki
def get_uuids(
129 050485bd Sofia Papagiannaki
        token,
130 890c2065 Sofia Papagiannaki
        displaynames,
131 890c2065 Sofia Papagiannaki
        url='http://127.0.0.1:8000/user_catalogs',
132 050485bd Sofia Papagiannaki
        override_users={}):
133 890c2065 Sofia Papagiannaki
134 050485bd Sofia Papagiannaki
    if override_users:
135 74d988b0 Christos Stavrakakis
        return dict((u, u) for u in displaynames)
136 0308f3a7 Sofia Papagiannaki
137 c700f742 Sofia Papagiannaki
    try:
138 890c2065 Sofia Papagiannaki
        data = call(
139 74d988b0 Christos Stavrakakis
            token, url, headers={'content-type': 'application/json'},
140 74d988b0 Christos Stavrakakis
            body=json.dumps({'displaynames': displaynames}), method='POST')
141 e31e4274 Sofia Papagiannaki
    except:
142 e31e4274 Sofia Papagiannaki
        raise
143 c700f742 Sofia Papagiannaki
    else:
144 890c2065 Sofia Papagiannaki
        return data.get('displayname_catalog')
145 890c2065 Sofia Papagiannaki
146 74d988b0 Christos Stavrakakis
147 890c2065 Sofia Papagiannaki
def get_user_uuid(
148 890c2065 Sofia Papagiannaki
        token,
149 890c2065 Sofia Papagiannaki
        displayname,
150 890c2065 Sofia Papagiannaki
        url='http://127.0.0.1:8000/user_catalogs',
151 890c2065 Sofia Papagiannaki
        override_users={}):
152 890c2065 Sofia Papagiannaki
153 890c2065 Sofia Papagiannaki
    if not displayname:
154 890c2065 Sofia Papagiannaki
        return
155 890c2065 Sofia Papagiannaki
156 890c2065 Sofia Papagiannaki
    displayname_dict = get_uuids(token, [displayname], url, override_users)
157 890c2065 Sofia Papagiannaki
    return displayname_dict.get(displayname)
158 890c2065 Sofia Papagiannaki
159 890c2065 Sofia Papagiannaki
160 890c2065 Sofia Papagiannaki
def get_displayname(
161 890c2065 Sofia Papagiannaki
        token,
162 890c2065 Sofia Papagiannaki
        uuid,
163 890c2065 Sofia Papagiannaki
        url='http://127.0.0.1:8000/user_catalogs',
164 890c2065 Sofia Papagiannaki
        override_users={}):
165 890c2065 Sofia Papagiannaki
166 890c2065 Sofia Papagiannaki
    if not uuid:
167 890c2065 Sofia Papagiannaki
        return
168 c700f742 Sofia Papagiannaki
169 890c2065 Sofia Papagiannaki
    uuid_dict = get_displaynames(token, [uuid], url, override_users)
170 890c2065 Sofia Papagiannaki
    return uuid_dict.get(uuid)
171 c700f742 Sofia Papagiannaki
172 74d988b0 Christos Stavrakakis
173 7bffb0bd Kostas Papadimitriou
def user_for_token(token, authentication_url, override_users, usage=False):
174 8acb1f97 Kostas Papadimitriou
    if not token:
175 8acb1f97 Kostas Papadimitriou
        return None
176 d65af928 Kostas Papadimitriou
177 8acb1f97 Kostas Papadimitriou
    if override_users:
178 8acb1f97 Kostas Papadimitriou
        try:
179 050485bd Sofia Papagiannaki
            return {'uuid': override_users[token].decode('utf8')}
180 8acb1f97 Kostas Papadimitriou
        except:
181 8acb1f97 Kostas Papadimitriou
            return None
182 d65af928 Kostas Papadimitriou
183 8acb1f97 Kostas Papadimitriou
    try:
184 7bffb0bd Kostas Papadimitriou
        return authenticate(token, authentication_url, usage=usage)
185 1055f3c6 Sofia Papagiannaki
    except Exception, e:
186 1055f3c6 Sofia Papagiannaki
        # In case of Unauthorized response return None
187 1055f3c6 Sofia Papagiannaki
        if e.args and e.args[-1] == 401:
188 1055f3c6 Sofia Papagiannaki
            return None
189 1055f3c6 Sofia Papagiannaki
        raise e
190 8acb1f97 Kostas Papadimitriou
191 74d988b0 Christos Stavrakakis
192 050485bd Sofia Papagiannaki
def get_user(
193 050485bd Sofia Papagiannaki
        request,
194 050485bd Sofia Papagiannaki
        authentication_url='http://127.0.0.1:8000/im/authenticate',
195 050485bd Sofia Papagiannaki
        override_users={},
196 7bffb0bd Kostas Papadimitriou
        fallback_token=None,
197 7bffb0bd Kostas Papadimitriou
        usage=False):
198 8acb1f97 Kostas Papadimitriou
    request.user = None
199 8acb1f97 Kostas Papadimitriou
    request.user_uniq = None
200 d65af928 Kostas Papadimitriou
201 8acb1f97 Kostas Papadimitriou
    # Try to find token in a parameter or in a request header.
202 050485bd Sofia Papagiannaki
    user = user_for_token(
203 7bffb0bd Kostas Papadimitriou
        request.GET.get('X-Auth-Token'), authentication_url, override_users,
204 7bffb0bd Kostas Papadimitriou
        usage=usage)
205 8acb1f97 Kostas Papadimitriou
    if not user:
206 050485bd Sofia Papagiannaki
        user = user_for_token(
207 050485bd Sofia Papagiannaki
            request.META.get('HTTP_X_AUTH_TOKEN'),
208 050485bd Sofia Papagiannaki
            authentication_url,
209 7bffb0bd Kostas Papadimitriou
            override_users,
210 7bffb0bd Kostas Papadimitriou
            usage=usage)
211 8acb1f97 Kostas Papadimitriou
    if not user:
212 050485bd Sofia Papagiannaki
        user = user_for_token(
213 7bffb0bd Kostas Papadimitriou
            fallback_token, authentication_url, override_users,
214 7bffb0bd Kostas Papadimitriou
            usage=usage)
215 6b5b443b Antony Chazapis
    if not user:
216 83204389 Kostas Papadimitriou
        logger.warning("Cannot retrieve user details from %s",
217 83204389 Kostas Papadimitriou
                       authentication_url)
218 7bffb0bd Kostas Papadimitriou
        return None
219 d65af928 Kostas Papadimitriou
220 74d988b0 Christos Stavrakakis
    # use user uuid, instead of email, keep email/displayname reference
221 74d988b0 Christos Stavrakakis
    # to user_id
222 83204389 Kostas Papadimitriou
    request.user_uniq = user['uuid']
223 8acb1f97 Kostas Papadimitriou
    request.user = user
224 890c2065 Sofia Papagiannaki
    request.user_id = user.get('displayname')
225 83204389 Kostas Papadimitriou
    return user
226 d65af928 Kostas Papadimitriou
227 d65af928 Kostas Papadimitriou
228 d65af928 Kostas Papadimitriou
def get_token_from_cookie(request, cookiename):
229 d65af928 Kostas Papadimitriou
    """
230 d65af928 Kostas Papadimitriou
    Extract token from the cookie name provided. Cookie should be in the same
231 d65af928 Kostas Papadimitriou
    form as astakos service sets its cookie contents::
232 d65af928 Kostas Papadimitriou

233 d65af928 Kostas Papadimitriou
        <user_uniq>|<user_token>
234 d65af928 Kostas Papadimitriou
    """
235 d65af928 Kostas Papadimitriou
    try:
236 d65af928 Kostas Papadimitriou
        cookie_content = unquote(request.COOKIES.get(cookiename, None))
237 d65af928 Kostas Papadimitriou
        return cookie_content.split("|")[1]
238 d65af928 Kostas Papadimitriou
    except AttributeError:
239 d65af928 Kostas Papadimitriou
        pass
240 d65af928 Kostas Papadimitriou
241 d65af928 Kostas Papadimitriou
    return None