views.py 6.49 KB
Newer Older
1
from django.http import HttpResponse, JsonResponse, HttpResponseRedirect, HttpResponseNotFound
2
from django.views import View
Calum Mackervoy's avatar
Calum Mackervoy committed
3 4
from django.contrib.auth import get_user_model
from django.contrib.auth.views import LoginView, SuccessURLAllowedHostsMixin
Calum Mackervoy's avatar
Calum Mackervoy committed
5 6
from django.shortcuts import redirect, render
from django.urls import reverse
Calum Mackervoy's avatar
Calum Mackervoy committed
7 8 9 10
from django.utils.http import (
    is_safe_url, urlsafe_base64_decode,
)
from django_registration.backends.activation.views import RegistrationView
11
from djangoldp_account import settings
12

13
from djangoldp_account.endpoints.rp_login import RPLoginCallBackEndpoint, RPLoginEndpoint
14
from djangoldp_account.errors import LDPLoginError
Jean-Baptiste's avatar
Jean-Baptiste committed
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
from oidc_provider.views import userinfo


def userinfocustom(request, *args, **kwargs):
    if request.method == 'OPTIONS':
        response = HttpResponse({}, status=200)
        response['Access-Control-Allow-Origin'] = '*'
        response['Access-Control-Allow-Headers'] = 'Authorization'
        response['Cache-Control'] = 'no-store'
        response['Pragma'] = 'no-cache'

        return response

    return userinfo(request, *args, **kwargs)

30

31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
def check_user(request, *args, **kwargs):
    if request.method == 'OPTIONS':
        response = HttpResponse({}, status=200)
        response['Access-Control-Allow-Origin'] = '*'
        response['Access-Control-Allow-Headers'] = 'Authorization'
        response['Cache-Control'] = 'no-store'
        response['Pragma'] = 'no-cache'

        return response

    if request.user.is_authenticated():
        response = JsonResponse(settings.userinfo({}, request.user))
        try:
            response['User'] = request.user.webid()
        except AttributeError:
            pass
        return response
    else :
        return HttpResponseNotFound()


Calum Mackervoy's avatar
Calum Mackervoy committed
52 53 54 55 56 57 58 59 60 61 62 63 64 65
# auxiliary function to set a user's default_redirect_uri
def _set_default_redirect_uri(user, redirect_uri):
    from django.conf import settings

    if redirect_uri is not None and len(redirect_uri) > 1 and redirect_uri != settings.LOGIN_REDIRECT_URL \
            and hasattr(user, 'default_redirect_uri'):
        try:
            user.default_redirect_uri = redirect_uri
            user.save()
        # if the URL is too long, or invalid, we can just move on
        except:
            pass


Calum Mackervoy's avatar
Calum Mackervoy committed
66 67 68 69 70 71 72 73 74
class RedirectView(View):
    """
    View for managing where to redirect the user after a successful login
    In the event that 'next' is not set (they may be coming from one of multiple front-end apps)

    To use this functionality set LOGIN_REDIRECT_URL to a url which uses this View. Then if the user
    has not set 'next' parameter in the login request, Django will redirect them here
    """
    def get(self, request, *args, **kwargs):
75 76
        if request.user.is_authenticated:
            next = request.user.default_redirect_uri
Calum Mackervoy's avatar
Calum Mackervoy committed
77

78
            # attempt to redirect to the user's default_redirect_uri
79
            if next is not None and len(next) > 1:
80
                return redirect(next, permanent=False)
Calum Mackervoy's avatar
Calum Mackervoy committed
81

82 83 84 85
            # there is no default to fall back on
            # redirect admins to the admin panel
            if request.user.is_superuser:
                return redirect(reverse('admin:index'), permanent=False)
Calum Mackervoy's avatar
Calum Mackervoy committed
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100

        # redirect other users to a page apologising
        return render(request, template_name='registration/lost_user.html')


class LDPAccountLoginView(LoginView):
    """
    Extension of django.contrib.auth.views.LoginView for managing user's default_redirect_uri
    """
    # Save login url as preferred redirect
    def post(self, request, *args, **kwargs):
        return_value = super(LDPAccountLoginView, self).post(request, *args, **kwargs)

        # if the user has 'next' set which is not default, update their preference
        next = request.POST.get('next')
Calum Mackervoy's avatar
Calum Mackervoy committed
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144

        _set_default_redirect_uri(request.user, next)

        return return_value


class LDPAccountRegsitrationView(SuccessURLAllowedHostsMixin, RegistrationView):
    """
    Extension of django-registration's RegistrationView for managing user's default_redirect_uri
    """
    def get_redirect_url(self):
        """Return the user-originating redirect URL if it's safe."""
        redirect_to = self.request.POST.get(
            'next',
            self.request.GET.get('next', '')
        )
        url_is_safe = is_safe_url(
            url=redirect_to,
            allowed_hosts=self.get_success_url_allowed_hosts(),
            require_https=self.request.is_secure(),
        )
        return redirect_to if url_is_safe else ''

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context.update({
            'next': self.get_redirect_url(),
        })
        return context

    def post(self, request, *args, **kwargs):
        return_value = super(LDPAccountRegsitrationView, self).post(request, *args, **kwargs)

        # if the user has 'next' set which is not default, update their preference
        next = request.POST.get('next', '')
        username = request.POST.get('username')

        # fetch the user which should now be created
        try:
            user = get_user_model().objects.get(username=username)
        except get_user_model().DoesNotExist:
            return return_value

        _set_default_redirect_uri(user, next)
Calum Mackervoy's avatar
Calum Mackervoy committed
145 146 147 148

        return return_value


149
class RPLoginView(View):
150
    """
151
    RP authentication workflow
152 153 154
    See https://github.com/solid/webid-oidc-spec/blob/master/example-workflow.md
    Wa're using oid module : https://pyoidc.readthedocs.io/en/latest/examples/rp.html
    """
155
    endpoint_class = RPLoginEndpoint
156 157

    def get(self, request, *args, **kwargs):
158 159 160
        return self.on_request(request)

    def on_request(self, request):
161
        endpoint = self.endpoint_class(request)
162
        try:
163
            endpoint.validate_params()
164

165
            return HttpResponseRedirect(endpoint.op_login_url())
166 167 168 169 170 171 172 173

        except LDPLoginError as error:
            return JsonResponse(error.create_dict(), status=400)

    def post(self, request, *args, **kwargs):
        return self.on_request(request)


174
class RPLoginCallBackView(View):
175
    endpoint_class = RPLoginCallBackEndpoint
176 177

    def get(self, request, *args, **kwargs):
178
        return self.on_request(request)
179

180 181
    def on_request(self, request):
        endpoint = self.endpoint_class(request)
182
        try:
183 184 185 186 187 188 189 190 191
            endpoint.validate_params()

            return HttpResponseRedirect(endpoint.initial_url())

        except LDPLoginError as error:
            return JsonResponse(error.create_dict(), status=400)

    def post(self, request, *args, **kwargs):
        return self.on_request(request)