# -*- coding: utf-8 -*-
# vim:fenc=utf-8

# This file is part of the  X2Go Project - https://www.x2go.org
# Copyright (C) 2012-2020 by Mike Gabriel <mike.gabriel@das-netzwerkteam.de>
#
# X2Go Session Broker is free software; you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# X2Go Session Broker is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program; if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.

"""\
Module providing a function for handling BasicAuth request processing.

"""

# modules
import base64

def require_basic_auth(realm, validate_callback):
    """\
    Handler for ``http(s)://``  BasisAuth processing.

    This function is used as a decorator for web request handler classes
    (such as tornado.web.RequestHandler).

    :param realm: authentication realm
    :type realm: ``str``
    :param validate_callback: callback function for validating credentials
    :type validate_callback: ``func``

    :returns: authentication :func:`execute()` function (or ``False``)
    :rtype: ``func`` or ``bool``

    """

    def require_basic_auth_decorator(handler_class):
        def wrap_execute(handler_execute):
            def require_basic_auth(handler, kwargs):

                def create_auth_header():
                    handler.set_status(401)
                    handler.set_header('WWW-Authenticate', 'Basic realm="{realm}"'.format(realm=realm))
                    handler._transforms = []
                    handler.finish()

                kwargs['basicauth_user'], access = validate_callback('check-credentials', 'FALSE')
                if access:
                    kwargs['basicauth_pass'] = 'anonymous access granted'
                    return True

                auth_header = handler.request.headers.get('Authorization')
                if auth_header is None or not auth_header.startswith('Basic '):
                    create_auth_header()
                else:
                    auth_decoded = base64.decodestring(auth_header[6:].encode()).decode()
                    username, kwargs['basicauth_pass'] = [ s for s in auth_decoded.split(':', 2) ]
                    kwargs['basicauth_user'], access = validate_callback(username, kwargs['basicauth_pass'])
                    if access:
                        return True
                    else:
                        create_auth_header()

            def _execute(self, transforms, *args, **kwargs):
                if not require_basic_auth(self, kwargs):
                    return False
                return handler_execute(self, transforms, *args, **kwargs)

            return _execute

        handler_class._execute = wrap_execute(handler_class._execute)
        return handler_class

    return require_basic_auth_decorator
