1e8819cdf80ca0e0602d22551a50f970aa68e108dmblighfrom django.contrib.auth.models import User, Group, check_password
2a5288b4bb2b09aafe914d0b7d5aab79a7e433eafshowardfrom django.contrib.auth import backends
3e8819cdf80ca0e0602d22551a50f970aa68e108dmblighfrom django.contrib import auth
4e8819cdf80ca0e0602d22551a50f970aa68e108dmblighfrom django import http
5e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh
6e0b08e6170b57f90262726eb7f04e059cb47419cHsinyu Chaofrom autotest_lib.client.cros import constants
7a5288b4bb2b09aafe914d0b7d5aab79a7e433eafshowardfrom autotest_lib.frontend import thread_local
8a5288b4bb2b09aafe914d0b7d5aab79a7e433eafshowardfrom autotest_lib.frontend.afe import models, management
985f4c36b14448d8fd707b34107c7688f13f258f2Simran Basifrom autotest_lib.server import utils
10e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh
11e8819cdf80ca0e0602d22551a50f970aa68e108dmblighDEBUG_USER = 'debug_user'
12e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh
13a5288b4bb2b09aafe914d0b7d5aab79a7e433eafshowardclass SimpleAuthBackend(backends.ModelBackend):
140afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski    """
150afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski    Automatically allows any login.  This backend is for use when Apache is
160afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski    doing the real authentication.  Also ensures logged-in user exists in
170afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski    frontend.afe.models.User database.
180afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski    """
190afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski    def authenticate(self, username=None, password=None):
200afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski        try:
210afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski            user = User.objects.get(username=username)
220afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski        except User.DoesNotExist:
230afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski            # password is meaningless
240afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski            user = User(username=username,
250afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski                        password='apache authentication')
260afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski            user.is_staff = True
270afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski            user.save() # need to save before adding groups
280afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski            user.groups.add(Group.objects.get(
290afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski                name=management.BASIC_ADMIN))
30e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh
310afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski        SimpleAuthBackend.check_afe_user(username)
320afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski        return user
33e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh
34e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh
350afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski    @staticmethod
360afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski    def check_afe_user(username):
373dd47c247147ca6920b222d43a8eb6ee54209c8fshoward        user, created = models.User.objects.get_or_create(login=username)
383dd47c247147ca6920b222d43a8eb6ee54209c8fshoward        if created:
393dd47c247147ca6920b222d43a8eb6ee54209c8fshoward            user.save()
40e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh
410afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski    def get_user(self, user_id):
420afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski        try:
430afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski            return User.objects.get(pk=user_id)
440afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski        except User.DoesNotExist:
450afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski            return None
46e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh
47e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh
486f1593c98487664a6c330a638e6645dc39b4aca3showardclass GetApacheUserMiddleware(object):
490afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski    """
500afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski    Middleware for use when Apache is doing authentication.  Looks for
516f1593c98487664a6c330a638e6645dc39b4aca3showard    REMOTE_USER in headers and passed the username found to
526f1593c98487664a6c330a638e6645dc39b4aca3showard    thread_local.set_user().  If no such header is found, looks for
536f1593c98487664a6c330a638e6645dc39b4aca3showard    HTTP_AUTHORIZATION header with username (this allows CLI to authenticate).
546f1593c98487664a6c330a638e6645dc39b4aca3showard    If neither of those are found, DEBUG_USER is used.
550afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski    """
56e8819cdf80ca0e0602d22551a50f970aa68e108dmbligh
570afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski    def process_request(self, request):
580afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski        # look for a username from Apache
590afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski        user = request.META.get('REMOTE_USER')
600afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski        if user is None:
610afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski            # look for a user in headers.  This is insecure but
620afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski            # it's our temporarily solution for CLI auth.
630afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski            user = request.META.get('HTTP_AUTHORIZATION')
640afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski        if user is None:
650afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski            # no user info - assume we're in development mode
6685f4c36b14448d8fd707b34107c7688f13f258f2Simran Basi            user = constants.MOBLAB_USER if utils.is_moblab() else DEBUG_USER
676f1593c98487664a6c330a638e6645dc39b4aca3showard        thread_local.set_user(user)
686f1593c98487664a6c330a638e6645dc39b4aca3showard
696f1593c98487664a6c330a638e6645dc39b4aca3showard
706f1593c98487664a6c330a638e6645dc39b4aca3showardclass ApacheAuthMiddleware(GetApacheUserMiddleware):
716f1593c98487664a6c330a638e6645dc39b4aca3showard    """
726f1593c98487664a6c330a638e6645dc39b4aca3showard    Like GetApacheUserMiddleware, but also logs the user into Django's auth
736f1593c98487664a6c330a638e6645dc39b4aca3showard    system, and replaces the username in thread_local with the actual User model
746f1593c98487664a6c330a638e6645dc39b4aca3showard    object.
756f1593c98487664a6c330a638e6645dc39b4aca3showard    """
766f1593c98487664a6c330a638e6645dc39b4aca3showard
77a79583c946ce95ba0b30f5ec2de58ff13f1006d0showard
786f1593c98487664a6c330a638e6645dc39b4aca3showard    def process_request(self, request):
796f1593c98487664a6c330a638e6645dc39b4aca3showard        super(ApacheAuthMiddleware, self).process_request(request)
806f1593c98487664a6c330a638e6645dc39b4aca3showard        username = thread_local.get_user()
81a79583c946ce95ba0b30f5ec2de58ff13f1006d0showard        thread_local.set_user(None)
826f1593c98487664a6c330a638e6645dc39b4aca3showard        user_object = auth.authenticate(username=username,
830afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski                                        password='')
840afbb6369aa5aa9a75ea67dd9e95ec4b21c0c181jadmanski        auth.login(request, user_object)
856f1593c98487664a6c330a638e6645dc39b4aca3showard        thread_local.set_user(models.User.objects.get(login=username))
86