Gitlab CSE Unil

authentication.py 3.65 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
from django.contrib.auth import login as auth_login
from django.contrib.auth.models import User
from django.db import IntegrityError

from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed

from .utils import get_request_attp

try:
    from shibauth.models import ShibbUserAttributes
except ImportError:
    ShibbUserAttributes = None


def get_or_create_user(attp_user):
    """
    Try to find an existing user corresponding to the parameters passed by attp_user.
    The first attribute with data in attp_user will be used for lookup
    :param attp_user:
    :return:
    """
    # attp_attr is the name of the attribute in attp_user,
    # model_attr is the corresponding attribute name on the User model,
    # given in attr_choice as (attp_attr, model_attr)
    attr_choice = (('id', 'pk'), ('uniqueId', 'shibbuserattributes__uid'), ('email', 'username'))

    # Lookup the user, using the various attributes
    user = None
    add_uniqueid = False
    for (attp_attr, model_attr) in attr_choice:
        # The attribute was not provided in the message, continue with next attribute
        if not attp_user.get(attp_attr):
            continue

        # If the user cannot be found with the current attribute, try with the next ones
        try:
            user = User.objects.get(**{"{}__iexact".format(model_attr): attp_user.get(attp_attr)})
        except User.DoesNotExist:
            continue

        add_uniqueid = (model_attr != 'shibbuserattributes__uid')
        # user is found, get out of the loop
        break
    user_changed = False

    # If the user could not be found, create it
    if user is None:
        user = User(username=attp_user.get('email'), email=attp_user.get('email'))
        user_changed = True

    # Update User data
    if attp_user.get('first_name') and user.first_name != attp_user['first_name']:  # Update first_name, if provided
        user.first_name = attp_user['first_name']
        user_changed = True

    if attp_user.get('last_name') and user.first_name != attp_user['last_name']:  # Update last_name if provided
        user.last_name = attp_user['last_name']
        user_changed = True

    if attp_user.get('email') and user.email != attp_user['email']:  # Update email and username if provided
        user.email = user.username = attp_user['email']
        user_changed = True

    if user_changed:
        user.save()

    # Save uniqueId if user has not already one and a value is given
    if add_uniqueid and attp_user.get('uniqueId') and ShibbUserAttributes:
        try:
            ShibbUserAttributes.objects.create(user=user, uid=attp_user.get('uniqueId'))
        except IntegrityError:
            pass

    return user


def login_attp_user(request, attp_message, persist=True):
    """
    Authenticate a user based on the data given in attp_message['user']
    The attp_message is considered valid

    :param request:
    :param attp_message:
    :return:
    """
    attp_user = attp_message.get('user')
    if not attp_user:
        return

    user = get_or_create_user(attp_user)
    if request.user.is_anonymous() or request.user != user:
        if persist:
            user.backend = 'django.contrib.auth.backends.ModelBackend'
            auth_login(request, user)
        else:
            request.user = user


class TTPAuthentication(BaseAuthentication):
    """

    """

    def authenticate(self, request):

        attp_message = get_request_attp(request)
        if not attp_message:
            return None

        attp_user = attp_message.get('user')
        if not attp_user:
            return None

        user = get_or_create_user(attp_user)
        return user, None