Exemple #1
0
def get_safe_login_redirect_url(request):
    from sso.oauth2.models import allowed_hosts

    redirect_to = get_request_param(request, REDIRECT_FIELD_NAME, '')
    # Ensure the user-originating redirection url is safe.
    # allow external hosts, for redirect after password_create_complete
    if url_has_allowed_host_and_scheme(redirect_to,
                                       allowed_hosts=allowed_hosts()):
        return redirect_to
    else:
        return resolve_url(settings.LOGIN_REDIRECT_URL)
Exemple #2
0
 def get_redirect_url(self):
     """Return the user-originating redirect URL if it's safe."""
     redirect_to = self.request.POST.get(
         self.redirect_field_name,
         self.request.GET.get(self.redirect_field_name, ''))
     url_is_safe = url_has_allowed_host_and_scheme(
         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 ''
Exemple #3
0
 def dispatch(self, request, *args, **kwargs):
     next = request.GET.get('next')
     if next:
         url_is_safe = url_has_allowed_host_and_scheme(
             url=next,
             allowed_hosts=self.get_success_url_allowed_hosts(),
             require_https=self.request.is_secure(),
         )
         if url_is_safe:
             request.session['next'] = next
             request.session['next_expiration'] = datetime.timestamp(datetime.now() + timedelta(minutes=15))
     return super().dispatch(request, *args, **kwargs)
Exemple #4
0
def safelink_callback(attrs, new=False):
    """
    Makes sure that all links to a different domain are passed through a redirection handler
    to ensure there's no passing of referers with secrets inside them.
    """
    url = attrs.get((None, 'href'), '/')
    if not url_has_allowed_host_and_scheme(url, allowed_hosts=None) and not url.startswith('mailto:') and not url.startswith('tel:'):
        signer = signing.Signer(salt='safe-redirect')
        attrs[None, 'href'] = reverse('redirect') + '?url=' + urllib.parse.quote(signer.sign(url))
        attrs[None, 'target'] = '_blank'
        attrs[None, 'rel'] = 'noopener'
    return attrs
Exemple #5
0
 def get_success_url(self):
     from django.utils.http import url_has_allowed_host_and_scheme
     # Copied from django.contrib.auth.views.LoginView.get_success_url
     redirect_to = self.get_redirect_to(use_default=True)
     url_is_safe = url_has_allowed_host_and_scheme(
         url=redirect_to,
         allowed_hosts={self.request.get_host()},
         require_https=self.request.is_secure(),
     )
     if not url_is_safe:
         return resolve_url(settings.LOGIN_REDIRECT_URL)
     return redirect_to
Exemple #6
0
 def dispatch(self, request, *args, **kwargs):
     request.user.is_administrator = request.user.is_superuser
     request.user.is_superuser = False
     request.user.save(update_fields=["is_administrator", "is_superuser"])
     messages.success(
         request, _("You are now an administrator instead of a superuser.")
     )
     params = request.GET.copy()
     url = urllib.parse.unquote(params.pop("next", [""])[0])
     if url and url_has_allowed_host_and_scheme(url, allowed_hosts=None):
         return redirect(url + ("?" + params.urlencode() if params else ""))
     return redirect(reverse("orga:event.list"))
Exemple #7
0
 def test_secure_param_https_urls(self):
     secure_urls = (
         'https://example.com/p',
         'HTTPS://example.com/p',
         '/view/?param=http://example.com',
     )
     for url in secure_urls:
         with self.subTest(url=url):
             self.assertIs(
                 url_has_allowed_host_and_scheme(url, allowed_hosts={'example.com'}, require_https=True),
                 True,
             )
Exemple #8
0
 def test_secure_param_non_https_urls(self):
     insecure_urls = (
         'http://example.com/p',
         'ftp://example.com/p',
         '//example.com/p',
     )
     for url in insecure_urls:
         with self.subTest(url=url):
             self.assertIs(
                 url_has_allowed_host_and_scheme(url, allowed_hosts={'example.com'}, require_https=True),
                 False,
             )
Exemple #9
0
 def get(self, request, *args, **kwargs):
     backend = get_auth_backends()[request.user.auth_backend]
     u = backend.request_authenticate(request)
     if u and u == request.user:
         next_url = backend.get_next_url(request)
         t = int(time.time())
         request.session['pretix_auth_login_time'] = t
         request.session['pretix_auth_last_used'] = t
         if next_url and url_has_allowed_host_and_scheme(next_url, allowed_hosts=None):
             return redirect(next_url)
         return redirect(reverse('control:index'))
     return super().get(request, *args, **kwargs)
Exemple #10
0
    def get_redirect_url(self):
        """
        Return the URL to redirect to when canceling is successful.
        Looks in query string for ?next, ensuring it is on the same domain.
        """
        next = self.request.GET.get(REDIRECT_FIELD_NAME)

        # url_has_allowed_host_and_scheme() will ensure we don't redirect to another domain
        if next and url_has_allowed_host_and_scheme(next, allowed_hosts=settings.ALLOWED_HOSTS):
            return next
        else:
            return self.redirect_url
Exemple #11
0
def safelink_callback(attrs, new=False):
    url = attrs.get((None, 'href'), '/')
    if not url_has_allowed_host_and_scheme(
            url, allowed_hosts=None) and not url.startswith(
                'mailto:') and not url.startswith('tel:'):
        signer = signing.Signer(salt='safe-redirect')
        attrs[None,
              'href'] = reverse('redirect') + '?url=' + urllib.parse.quote(
                  signer.sign(url))
        attrs[None, 'target'] = '_blank'
        attrs[None, 'rel'] = 'noopener'
    return attrs
Exemple #12
0
    def post(self, request, *args, **kwargs):
        r = request.POST.get("webauthn", "")
        valid = False

        if 'webauthn_challenge' in self.request.session and r.startswith('{'):
            challenge = self.request.session['webauthn_challenge']

            resp = json.loads(r)
            try:
                devices = [WebAuthnDevice.objects.get(user=self.request.user, credential_id=resp.get("id"))]
            except WebAuthnDevice.DoesNotExist:
                devices = U2FDevice.objects.filter(user=self.request.user)

            for d in devices:
                try:
                    wu = d.webauthnuser

                    if isinstance(d, U2FDevice):
                        # RP_ID needs to be appId for U2F devices, but we can't
                        # set it that way in U2FDevice.webauthnuser, since that
                        # breaks the frontend part.
                        wu.rp_id = settings.SITE_URL

                    webauthn_assertion_response = webauthn.WebAuthnAssertionResponse(
                        wu,
                        resp,
                        challenge,
                        settings.SITE_URL,
                        uv_required=False  # User Verification
                    )
                    sign_count = webauthn_assertion_response.verify()
                except Exception:
                    logger.exception('U2F login failed')
                else:
                    if isinstance(d, WebAuthnDevice):
                        d.sign_count = sign_count
                        d.save()
                    valid = True
                    break

        valid = valid or self.form.is_valid()

        if valid:
            t = int(time.time())
            request.session['pretix_auth_login_time'] = t
            request.session['pretix_auth_last_used'] = t
            next_url = get_auth_backends()[request.user.auth_backend].get_next_url(request)
            if next_url and url_has_allowed_host_and_scheme(next_url, allowed_hosts=None):
                return redirect(next_url)
            return redirect(reverse('control:index'))
        else:
            messages.error(request, _('The password you entered was invalid, please try again.'))
            return self.get(request, *args, **kwargs)
Exemple #13
0
 def get_redirect_to_url(self):
     redirect_to_url = self.request.POST.get(
         self.redirect_field_name,
         self.request.GET.get(self.redirect_field_name, '')
     )
     url_is_safe = url_has_allowed_host_and_scheme(
         url=redirect_to_url,
         allowed_hosts=self.get_success_url_allowed_hosts(),
         require_https=self.request.is_secure(),
     )
     if url_is_safe:
         self.success_url = redirect_to_url
Exemple #14
0
def _do_next(request, response):
    """See DoNextModelAdmin"""
    if "next" in request.GET:
        if not url_has_allowed_host_and_scheme(
                request.GET["next"], allowed_hosts={request.get_host()}):
            raise DisallowedRedirect
        if "_save" in request.POST:
            return HttpResponseRedirect(request.GET["next"])
        if response is not None:
            return HttpResponseRedirect("{}?{}".format(
                response.url, request.GET.urlencode()))
    return response
Exemple #15
0
    def post(self, request):
        """Carries out the login, redirects to get if it fails"""

        # redirect target on successful login
        next_page = request.POST.get("next", "")

        # redirect target on failed login
        login_page = "{page}?next={next_page}".format(page=reverse("login"),
                                                      next_page=next_page)

        username = request.POST.get("user", None)
        if not username:
            messages.error(request, _("Username missing"))
            return HttpResponseRedirect(login_page)

        password = request.POST.get("pwd", None)
        if not password:
            messages.error(request, _("Password missing"))
            return HttpResponseRedirect(login_page)

        # find the user from the configured login systems, and verify pwd
        user = authenticate(username=username, password=password)

        if not user:
            messages.error(request, _("Wrong username or password."))
            return HttpResponseRedirect(login_page)

        if not user.is_active:
            send_activation_email(user, request)
            messages.error(
                request,
                _("Please activate your account first. "
                  "We have just re-sent your activation email"),
            )
            return HttpResponseRedirect(login_page)

        # set up the user's session
        login(request, user)

        if next_page:

            domain = RequestSite(request).domain
            allowed_hosts = [domain]
            if url_has_allowed_host_and_scheme(next_page, allowed_hosts):
                return HttpResponseRedirect(next_page)

            else:
                # TODO: log a warning that next_page is not
                # considered a safe redirect target
                pass

        return HttpResponseRedirect(DEFAULT_LOGIN_REDIRECT)
Exemple #16
0
    def get_success_url(self):
        """Get success url from redirect field."""
        redirect_to = self.request.POST.get(
            self.redirect_field_name,
            self.request.GET.get(self.redirect_field_name, '/'))

        url_is_safe = url_has_allowed_host_and_scheme(
            url=redirect_to,
            allowed_hosts=(self.request.get_host(), ),
            require_https=self.request.is_secure(),
        )

        return redirect_to if url_is_safe else '/'
Exemple #17
0
def set_semester(request: WSGIRequest) -> HttpResponse:
    redirect_url: Optional[str] = request.POST.get("next") or request.GET.get(
        "next")
    if not url_has_allowed_host_and_scheme(url=redirect_url,
                                           allowed_hosts=request.get_host(),
                                           require_https=True):
        redirect_url = request.META.get("HTTP_REFERER")
        if not url_has_allowed_host_and_scheme(
                url=redirect_url,
                allowed_hosts=request.get_host(),
                require_https=True):
            redirect_url = "/"  # should not happen :)
    if request.method == "POST":
        semester_pk = int(request.POST.get("semester")
                          or -1)  # semester is always present
        try:
            Semester.objects.get(pk=semester_pk)
        except Semester.DoesNotExist:
            pass
        else:
            request.session[SEMESTER_SESSION_KEY] = semester_pk
    return HttpResponseRedirect(redirect_url or "/")
Exemple #18
0
    def get_redirect_url(self):
        """Return URL to redirect the logged in user if the URL is safe."""

        redirect_to = self.request.POST.get(
            # get redirect url from the hidden next field
            self.redirect_field_name,
            self.request.GET.get(self.redirect_field_name, ''))
        url_is_safe = url_has_allowed_host_and_scheme(
            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 signin(r):
    try:
        import urlparse as _urlparse
        from urllib import unquote
    except Exception:
        import urllib.parse as _urlparse
        from urllib.parse import unquote
    next_url = r.GET.get('next', _default_next_url())

    try:
        if 'next=' in unquote(next_url):
            next_url = _urlparse.parse_qs(
                _urlparse.urlparse(unquote(next_url)).query)['next'][0]
    except Exception:
        next_url = r.GET.get('next', _default_next_url())

    # Only permit signin requests where the next_url is a safe URL
    if parse_version(get_version()) >= parse_version('2.0'):
        url_ok = url_has_allowed_host_and_scheme(next_url, None)
    else:
        url_ok = url_has_allowed_host_and_scheme(next_url)

    if not url_ok:
        return HttpResponseRedirect(get_reverse([denied, 'denied', 'django_saml2_auth:denied']))

    r.session['login_next_url'] = next_url

    saml_client = _get_saml_client(get_current_domain(r))
    _, info = saml_client.prepare_for_authenticate()

    redirect_url = None

    for key, value in info['headers']:
        if key == 'Location':
            redirect_url = value
            break

    return HttpResponseRedirect(redirect_url)
Exemple #20
0
 def redirect_to_referer(self, request):
     """
     Redirects the user back to where they come from, unless it is unsafe.
     """
     referer = request.META.get('HTTP_REFERER', '')
     referer_is_safe = url_has_allowed_host_and_scheme(
         url=referer,
         allowed_hosts={request.get_host()},
         require_https=request.is_secure())
     if referer_is_safe:
         next_url = resolve_url(referer)
     else:
         next_url = reverse('admin:index', current_app=self.name)
     return redirect(next_url)
Exemple #21
0
    def get_success_url(self):
        messages.success(self.request, "Thank you for your feedback!")

        if (
            self.source_redirect
            and url_has_allowed_host_and_scheme(
                self.object.source_url, allowed_hosts=None
            )
            and "report_problem" not in self.object.source_url
        ):

            return self.object.source_url
        else:
            return "/"
Exemple #22
0
    def get_redirect_url(self):
        """
        Return the user-originating redirect URL if it's safe.

        Mugged from Django's LoginView down a dark alley.
        """
        redirect_to = self.request.POST.get('next',
                                            self.request.GET.get('next', ''))
        url_is_safe = url_has_allowed_host_and_scheme(
            url=redirect_to,
            allowed_hosts={self.request.get_host()},
            require_https=self.request.is_secure(),
        )
        return redirect_to if url_is_safe else ''
Exemple #23
0
    def post(self, request):
        form = LoginForm(request, data=request.POST)

        if form.is_valid():
            # Check where should the user be redirected
            next_redirect = request.POST.get("next", "")
            if not url_has_allowed_host_and_scheme(
                    url=next_redirect, allowed_hosts=[request.get_host()]):
                next_redirect = reverse("home")

            auth_login(request, form.get_user())
            messages.info(request, "Logged in as {}.".format(request.user))
            return HttpResponseRedirect(next_redirect)

        return render(request, self.template, {"form": form})
Exemple #24
0
def get_success_url(request, redirect_field_name="next", default="/") -> str:
    """
    Return the success URL identified by the given redirect field name in
    the request's POST or GET parameters.  If it is not provided or is unsafe,
    return the given default URL.
    """

    # This is mostly cribbed from django.contrib.auth.views.LoginView.
    redirect_to = request.POST.get(redirect_field_name, request.GET.get(redirect_field_name, ""))
    url_is_safe = url_has_allowed_host_and_scheme(
        url=redirect_to,
        allowed_hosts={request.get_host()},
        require_https=request.is_secure(),
    )
    return redirect_to if url_is_safe else default
Exemple #25
0
 def post(self, request, *args, **kwargs):
     if self._target == self.object.state:
         messages.info(
             request,
             _("Somebody else was faster than you: this submission was already in the state you wanted to change it to."
               ),
         )
     elif self.is_allowed:
         self.do()
     else:
         self.do(force=True)
     url = self.request.GET.get("next")
     if url and url_has_allowed_host_and_scheme(url, allowed_hosts=None):
         return redirect(url)
     return redirect(self.object.orga_urls.base)
Exemple #26
0
def get_safe_url(request, param_name=None, fallback_url=None, url=None):

    url = url or request.GET.get(param_name) or request.POST.get(param_name)

    allowed_hosts = settings.ALLOWED_HOSTS
    require_https = request.is_secure()

    if url:

        if settings.DEBUG:
            # In DEBUG mode the network location part `127.0.0.1:8000` contains
            # a port and fails the validation of `url_has_allowed_host_and_scheme`
            # since it's not a member of `allowed_hosts`:
            # https://github.com/django/django/blob/525274f/django/utils/http.py#L413
            # As a quick fix, we build a new URL without the port.
            from urllib.parse import ParseResult, urlparse

            url_info = urlparse(url)
            url_without_port = ParseResult(
                scheme=url_info.scheme,
                netloc=url_info.hostname,
                path=url_info.path,
                params=url_info.params,
                query=url_info.query,
                fragment=url_info.fragment,
            ).geturl()
            if url_has_allowed_host_and_scheme(url_without_port, allowed_hosts,
                                               require_https):
                return url

        else:
            if url_has_allowed_host_and_scheme(url, allowed_hosts,
                                               require_https):
                return url

    return fallback_url
Exemple #27
0
 def get_next_url(self, request):
     """
     Get the next url from the querystring parameters (?next=/my/next/page).
     If the next parameter is not there, returns the default redirect url
     """
     next_url = request.GET.get("next")
     if not next_url:
         next_url = reverse(magicauth_settings.LOGGED_IN_REDIRECT_URL_NAME)
     if not url_has_allowed_host_and_scheme(
             next_url, allowed_hosts={request.get_host()
                                      }, require_https=True):
         # We are not logging the unsafe URL to prevent code injections in logs
         logger.warning(
             "[MagicAuth] an unsafe URL was used through a login link")
         raise Http404
     return next_url
Exemple #28
0
def is_safe_url(url, request, allowed_hosts=None):
    """Use Django's `url_has_allowed_host_and_scheme()` and pass a configured
    list of allowed hosts and enforce HTTPS.  `allowed_hosts` can be specified."""
    if not allowed_hosts:
        allowed_hosts = (
            settings.DOMAIN,
            urlparse(settings.CODE_MANAGER_URL).netloc,
        )
        if settings.ADDONS_FRONTEND_PROXY_PORT:
            allowed_hosts = allowed_hosts + (
                f'{settings.DOMAIN}:{settings.ADDONS_FRONTEND_PROXY_PORT}', )

    require_https = request.is_secure() if request else False
    return url_has_allowed_host_and_scheme(url,
                                           allowed_hosts=allowed_hosts,
                                           require_https=require_https)
Exemple #29
0
    def login(self, request, extra_context=None):
        """
        Redirects to the site login page for the given HttpRequest.
        """
        redirect_to = request.POST.get(
            REDIRECT_FIELD_NAME, request.GET.get(REDIRECT_FIELD_NAME, ''))
        url_is_allowed = url_has_allowed_host_and_scheme(
            url=redirect_to,
            allowed_hosts={request.get_host()},
            require_https=request.is_secure(),
        )

        if not redirect_to or not url_is_allowed:
            redirect_to = resolve_url(settings.LOGIN_REDIRECT_URL)

        return redirect_to_login(redirect_to)
def _make_return_url(request, next_url):
    """
    Make the return URL based on whether a next_url is present in the url.

    If there is a next_url, verify that the url is safe and allowed before using it. If not, default to the host.
    """
    if next_url:
        if url_has_allowed_host_and_scheme(next_url,
                                           ALLOWED_HOSTS,
                                           require_https=True):
            return UOWS_LOGIN_URL + request.build_absolute_uri(next_url)
        else:
            # the next_url was not safe so don't use it - build from request.path to ignore GET parameters
            return UOWS_LOGIN_URL + request.build_absolute_uri(request.path)
    else:
        return UOWS_LOGIN_URL + request.build_absolute_uri()