astakos.py 5.28 KB
Newer Older
Kostas Papadimitriou's avatar
Kostas Papadimitriou committed
1
# Copyright 2011-2012 GRNET S.A. All rights reserved.
2
#
Kostas Papadimitriou's avatar
Kostas Papadimitriou committed
3
4
5
# Redistribution and use in source and binary forms, with or
# without modification, are permitted provided that the following
# conditions are met:
6
#
Kostas Papadimitriou's avatar
Kostas Papadimitriou committed
7
8
9
#   1. Redistributions of source code must retain the above
#      copyright notice, this list of conditions and the following
#      disclaimer.
10
#
Kostas Papadimitriou's avatar
Kostas Papadimitriou committed
11
12
13
14
#   2. Redistributions in binary form must reproduce the above
#      copyright notice, this list of conditions and the following
#      disclaimer in the documentation and/or other materials
#      provided with the distribution.
15
#
Kostas Papadimitriou's avatar
Kostas Papadimitriou committed
16
17
18
19
20
21
22
23
24
25
26
27
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
28
#
Kostas Papadimitriou's avatar
Kostas Papadimitriou committed
29
30
31
32
33
# The views and conclusions contained in the software and
# documentation are those of the authors and should not be
# interpreted as representing official policies, either expressed
# or implied, of GRNET S.A.

34
35
import logging

36
from astakosclient import AstakosClient
37
38
from astakosclient.errors import (Unauthorized, NoUUID, NoUserName,
                                  AstakosClientException)
39

Kostas Papadimitriou's avatar
Kostas Papadimitriou committed
40

41
def user_for_token(token, astakos_auth_url, logger=None):
42
    if token is None:
Kostas Papadimitriou's avatar
Kostas Papadimitriou committed
43
        return None
44
45
    client = AstakosClient(token, astakos_auth_url,
                           retry=2, use_pool=True, logger=logger)
Kostas Papadimitriou's avatar
Kostas Papadimitriou committed
46
    try:
47
        return client.get_user_info()
48
49
    except Unauthorized:
        return None
Kostas Papadimitriou's avatar
Kostas Papadimitriou committed
50

51

52
def get_user(request, astakos_auth_url, fallback_token=None, logger=None):
Kostas Papadimitriou's avatar
Kostas Papadimitriou committed
53
54
    request.user = None
    request.user_uniq = None
55

Kostas Papadimitriou's avatar
Kostas Papadimitriou committed
56
    # Try to find token in a parameter or in a request header.
57
    user = user_for_token(
58
        request.GET.get('X-Auth-Token'), astakos_auth_url, logger)
Kostas Papadimitriou's avatar
Kostas Papadimitriou committed
59
    if not user:
60
        user = user_for_token(
61
            request.META.get('HTTP_X_AUTH_TOKEN'), astakos_auth_url, logger)
62
    if not user:
63
        user = user_for_token(
64
            fallback_token, astakos_auth_url, logger)
Kostas Papadimitriou's avatar
Kostas Papadimitriou committed
65
    if not user:
66
        return None
67

68
69
    # use user uuid, instead of email, keep email/displayname reference
    # to user_id
70
    request.user_uniq = user['uuid']
Kostas Papadimitriou's avatar
Kostas Papadimitriou committed
71
    request.user = user
72
    request.user_id = user.get('displayname')
73
    return user
74
75


76
77
78
class UserCache(object):
    """uuid<->displayname user 'cache'"""

79
80
    def __init__(self, astakos_auth_url, astakos_token,
                 split=100, logger=None):
81
82
83
84
        if logger is None:
            logger = logging.getLogger(__name__)
        self.logger = logger

85
86
        self.astakos = AstakosClient(astakos_token, astakos_auth_url,
                                     retry=2, use_pool=True, logger=logger)
87
88
89
90
91
92
93
94
        self.users = {}

        self.split = split
        assert(self.split > 0), "split must be positive"

    def fetch_names(self, uuid_list):
        total = len(uuid_list)
        split = self.split
95
        count = 0
96
97
98
99

        for start in range(0, total, split):
            end = start + split
            try:
100
101
                names = \
                    self.astakos.service_get_usernames(uuid_list[start:end])
102
103
                count += len(names)

104
                self.users.update(names)
105
            except AstakosClientException:
106
                pass
107
108
109
110
111
112
113
114
115
            except Exception as err:
                self.logger.error("Unexpected error while fetching "
                                  "user display names: %s" % repr(err))

        diff = (total - count)
        assert(diff >= 0), "fetched more displaynames than requested"

        if diff:
            self.logger.debug("Failed to fetch %d displaynames", diff)
116
117

    def get_uuid(self, name):
118
119
        uuid = name

120
121
        if not name in self.users:
            try:
122
                uuid = self.astakos.service_get_uuid(name)
123
124
125
126
127
128
129
130
131
            except NoUUID:
                self.logger.debug("Failed to fetch uuid for %s", name)
            except AstakosClientException:
                pass
            except Exception as err:
                self.logger.error("Unexpected error while fetching "
                                  "user uuid %s: %s" % (name, repr(err)))
            finally:
                self.users[name] = uuid
132
133
134
135

        return self.users[name]

    def get_name(self, uuid):
136
        name = "-"
137
138
139

        if not uuid in self.users:
            try:
140
                name = self.astakos.service_get_username(uuid)
141
142
143
144
145
146
147
148
149
150
            except NoUserName:
                self.logger.debug("Failed to fetch display name for %s", uuid)
            except AstakosClientException:
                pass
            except Exception as err:
                self.logger.error("Unexpected error while fetching "
                                  "user displayname %s: %s"
                                  % (uuid, repr(err)))
            finally:
                self.users[uuid] = name
151
152

        return self.users[uuid]