def test_get_service_url_correct(self):
        """
        Ensure method behaves properly when redirect_url
        is or is not provided
        """
        request = self.factory.get("/accounts/login/",
                                   data={"next": "/next-page/"})

        result = get_service_url(request)
        expected = "http://testserver/accounts/login/?next=%2Fnext-page%2F"
        self.assertEqual(result, expected)

        result = get_service_url(request, "/alt/target/")
        expected = "http://testserver/accounts/login/?next=%2Falt%2Ftarget%2F"
        self.assertEqual(result, expected)
Ejemplo n.º 2
0
    def test_get_service_url_query_parameters(self):
        """
        Ensure method preserves query parameters
        """
        request = self.factory.get("/origin/?foo=bar", secure=True)
        result = get_service_url(request, "/target/")
        expected = "https://testserver/origin/?foo=bar&next=%2Ftarget%2F"
        assert_urls_equivalent(result, expected, self.assertEqual)

        request = self.factory.get("/origin/", secure=True,
                data={"foo": "bar", "next": "/next-page/?cat=dog"})
        result = get_service_url(request)
        expected = ("https://testserver/origin/?foo=bar"
                "&next=%2Fnext-page%2F%3Fcat%3Ddog")
        assert_urls_equivalent(result, expected, self.assertEqual)
Ejemplo n.º 3
0
def link_from_profile(request, institution):
    """
    Attempts to authenticate a CAS account for the provided
    institution, and links it to the current Uniauth profile
    if successful.
    """
    next_url = request.GET.get('next')
    ticket = request.GET.get('ticket')

    # Ensure there is an institution with the provided slug
    try:
        institution = Institution.objects.get(slug=institution)
    except Institution.DoesNotExist:
        raise Http404

    if not next_url:
        next_url = get_redirect_url(request, use_referer=True)

    # If the user is not already logged into a verified
    # Uniauth account, raise permission denied
    if not request.user.is_authenticated or is_tmp_user(request.user) \
            or is_unlinked_account(request.user):
        raise PermissionDenied("Must be logged in as verified Uniauth user.")

    service_url = get_service_url(request, next_url)
    client = CASClient(version=2,
                       service_url=service_url,
                       server_url=institution.cas_server_url)

    # If a ticket was provided, attempt to authenticate with it
    if ticket:
        user = authenticate(request=request,
                            institution=institution,
                            ticket=ticket,
                            service=service_url)

        # Authentication successful: link to Uniauth profile if
        # the institution account has not been linked yet + proceed
        if user:
            if is_unlinked_account(user):
                merge_model_instances(request.user, [user])
                username_split = get_account_username_split(user.username)
                _add_institution_account(request.user.profile,
                                         username_split[1], username_split[2])

            return HttpResponseRedirect(next_url)

        # Authentication failed: raise permission denied
        else:
            raise PermissionDenied("Verification of CAS ticket failed")

    # If no ticket was provided, redirect to the
    # login URL for the institution's CAS server
    else:
        return HttpResponseRedirect(client.get_login_url())
Ejemplo n.º 4
0
 def test_get_service_url_ignore_ticket(self):
     """
     Ensures ticket is ignored if present as query parameter
     """
     request = self.factory.get("/origin/", secure=True,
             data={"foo": "bar", "next": "/next-page/?cat=dog",
                     "ticket": "FAKE-ticket-456"})
     result = get_service_url(request)
     expected = ("https://testserver/origin/?foo=bar"
             "&next=%2Fnext-page%2F%3Fcat%3Ddog")
     assert_urls_equivalent(result, expected, self.assertEqual)
Ejemplo n.º 5
0
def cas_login(request, institution):
    """
    Redirects to the CAS login URL, or verifies the
    CAS ticket, if provided.

    Accepts the slug of the institution to log in to.
    """
    next_url = request.GET.get('next')
    ticket = request.GET.get('ticket')

    # Ensure there is an institution with the provided slug
    try:
        institution = Institution.objects.get(slug=institution)
    except Institution.DoesNotExist:
        raise Http404

    if not next_url:
        next_url = get_redirect_url(request, use_referer=True)

    # If the user is already authenticated, proceed to next page
    if request.user.is_authenticated:
        return _login_success(request, request.user, next_url)

    service_url = get_service_url(request, next_url)
    client = CASClient(version=2,
                       service_url=service_url,
                       server_url=institution.cas_server_url)

    # If a ticket was provided, attempt to authenticate with it
    if ticket:
        user = authenticate(request=request,
                            institution=institution,
                            ticket=ticket,
                            service=service_url)

        # Authentication successful: setup session + proceed
        if user:
            if not request.session.exists(request.session.session_key):
                request.session.create()
            auth_login(request, user)
            request.session['auth-method'] = "cas-" + institution.slug
            return _login_success(request, user, next_url, ["ticket"])

        # Authentication failed: raise permission denied
        else:
            raise PermissionDenied("Verification of CAS ticket failed.")

    # If no ticket was provided, redirect to the
    # login URL for the institution's CAS server
    else:
        return HttpResponseRedirect(client.get_login_url())
Ejemplo n.º 6
0
def logout(request):
    """
    Logs the user out of their Uniauth account, and
    redirects to the next page, defaulting to the URL
    specified by the UNIAUTH_LOGOUT_REDIRECT_URL setting.

    If no redirect page is set (URL parameter not given
    and UNIAUTH_LOGOUT_REDIRECT_URL is None), renders the
    logout template.

    Also logs the user out of CAS if they logged in
    via CAS, and the UNIAUTH_LOGOUT_CAS_COMPLETELY
    setting is true.
    """
    next_page = request.GET.get('next')
    auth_method = request.session.get('auth-method')

    if not next_page and get_setting('UNIAUTH_LOGOUT_REDIRECT_URL'):
        next_page = get_redirect_url(
            request, get_setting('UNIAUTH_LOGOUT_REDIRECT_URL'))

    # Formally log out user
    auth_logout(request)

    # Determine whether the user logged in through an institution's CAS
    institution = None
    if auth_method and auth_method.startswith("cas-"):
        try:
            institution = Institution.objects.get(slug=auth_method[4:])
        except Institution.DoesNotExist:
            pass

    # If we need to logout an institution's CAS,
    # redirect to that CAS server's logout URL
    if institution and get_setting('UNIAUTH_LOGOUT_CAS_COMPLETELY'):
        redirect_url = urlunparse(
            (get_protocol(request), request.get_host(), next_page
             or reverse('uniauth:logout'), '', '', ''))
        client = CASClient(version=2,
                           service_url=get_service_url(request),
                           server_url=institution.cas_server_url)
        return HttpResponseRedirect(client.get_logout_url(redirect_url))

    # If next page is set, proceed to it
    elif next_page:
        return HttpResponseRedirect(next_page)

    # Otherwise, render the logout view
    else:
        return render(request, 'uniauth/logout.html')