1from django.contrib.auth.models import User, Group, check_password
2from django.contrib.auth import backends
3from django.contrib import auth
4from django import http
5
6from autotest_lib.client.cros import constants
7from autotest_lib.frontend import thread_local
8from autotest_lib.frontend.afe import models, management
9from autotest_lib.server import utils
10
11DEBUG_USER = 'debug_user'
12
13class SimpleAuthBackend(backends.ModelBackend):
14    """
15    Automatically allows any login.  This backend is for use when Apache is
16    doing the real authentication.  Also ensures logged-in user exists in
17    frontend.afe.models.User database.
18    """
19    def authenticate(self, username=None, password=None):
20        try:
21            user = User.objects.get(username=username)
22        except User.DoesNotExist:
23            # password is meaningless
24            user = User(username=username,
25                        password='apache authentication')
26            user.is_staff = True
27            user.save() # need to save before adding groups
28            user.groups.add(Group.objects.get(
29                name=management.BASIC_ADMIN))
30
31        SimpleAuthBackend.check_afe_user(username)
32        return user
33
34
35    @staticmethod
36    def check_afe_user(username):
37        user, created = models.User.objects.get_or_create(login=username)
38        if created:
39            user.save()
40
41    def get_user(self, user_id):
42        try:
43            return User.objects.get(pk=user_id)
44        except User.DoesNotExist:
45            return None
46
47
48class GetApacheUserMiddleware(object):
49    """
50    Middleware for use when Apache is doing authentication.  Looks for
51    REMOTE_USER in headers and passed the username found to
52    thread_local.set_user().  If no such header is found, looks for
53    HTTP_AUTHORIZATION header with username (this allows CLI to authenticate).
54    If neither of those are found, DEBUG_USER is used.
55    """
56
57    def process_request(self, request):
58        # look for a username from Apache
59        user = request.META.get('REMOTE_USER')
60        if user is None:
61            # look for a user in headers.  This is insecure but
62            # it's our temporarily solution for CLI auth.
63            user = request.META.get('HTTP_AUTHORIZATION')
64        if user is None:
65            # no user info - assume we're in development mode
66            user = constants.MOBLAB_USER if utils.is_moblab() else DEBUG_USER
67        thread_local.set_user(user)
68
69
70class ApacheAuthMiddleware(GetApacheUserMiddleware):
71    """
72    Like GetApacheUserMiddleware, but also logs the user into Django's auth
73    system, and replaces the username in thread_local with the actual User model
74    object.
75    """
76
77
78    def process_request(self, request):
79        super(ApacheAuthMiddleware, self).process_request(request)
80        username = thread_local.get_user()
81        thread_local.set_user(None)
82        user_object = auth.authenticate(username=username,
83                                        password='')
84        auth.login(request, user_object)
85        thread_local.set_user(models.User.objects.get(login=username))
86