#
# steering, Programme/schedule management for AURA
#
# Copyright (C) 2011-2017, 2020, Ernesto Rico Schmidt
# Copyright (C) 2017-2019, Ingo Leindecker
#
# This program 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.
#
# This program 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, see <http://www.gnu.org/licenses/>.
#

from drf_spectacular.extensions import OpenApiAuthenticationExtension
from drf_spectacular.plumbing import build_bearer_security_scheme_object
from oidc_provider.lib.utils.oauth2 import extract_access_token
from oidc_provider.models import Token
from rest_framework import authentication, exceptions


class OidcOauth2Auth(authentication.BaseAuthentication):
    def authenticate(self, request):
        access_token = extract_access_token(request)

        if not access_token:
            # not this kind of auth
            return None
        oauth2_token = None
        try:
            oauth2_token = Token.objects.get(access_token=access_token)
        except Token.DoesNotExist:
            raise exceptions.AuthenticationFailed("The oauth2 token is invalid")

        if oauth2_token.has_expired():
            raise exceptions.AuthenticationFailed("The oauth2 token has expired")

        return oauth2_token.user, None


class OidcOauth2AuthenticationScheme(OpenApiAuthenticationExtension):
    target_class = "program.auth.OidcOauth2Auth"
    name = "tokenAuth"

    def get_security_definition(self, auto_schema):
        # One might be inclined to return a list here, because the bearer token
        # can also be passed as an `access_token` query parameter.
        # Officially this seems to be supported, but once we return a list
        # the authorization helper in the generated documentation is empty,
        # so we only return the primary mode instead.
        return build_bearer_security_scheme_object("Authorization", "Bearer")

        # This should work, but doesn’t for the reasons above:
        #
        # return [
        #     build_bearer_security_scheme_object("Authorization", "Bearer"),
        #     {
        #         "type": "apiKey",
        #         "in": "query",
        #         "name": "access_token",
        #     }
        # ]