Example #1
0
    def get(self, request, *args, **kwargs):
        """
        As a credential requestor, /login accepts up to three optional
        parameters:

        1. ``service``: the identifier of the application the client is
           accessing. In most cases this will be a URL.
        2. ``renew``: requires a client to present credentials regardless of
           any existing single sign-on session. If set, its value should be
           "true".
        3. ``gateway``: causes the client to not be prompted for credentials.
           If a single sign-on session already exists, the user will be logged
           in. Otherwise, the user is simply forwarded to the service, if
           specified. If set, its value should be "true".
        """
        service = request.GET.get('service')
        renew = request.GET.get('renew')
        gateway = request.GET.get('gateway')
        warned = request.GET.get('warned')

        if renew:
            logger.debug("Renew request received by credential requestor")
            self.logout_user(request)
            login = add_query_params(reverse('cas_login'),
                                     {'service': service})
            logger.debug("Redirecting to %s" % login)
            return redirect(login)
        elif gateway and service:
            logger.debug("Gateway request received by credential requestor")
            if request.user.is_authenticated():
                if self.warn_user() and not warned:
                    return redirect(add_query_params(reverse('cas_warn'),
                                                     {'service': service,
                                                      'gateway': gateway}))
                st = ServiceTicket.objects.create_ticket(service=service,
                                                         user=request.user)
                service = add_query_params(service, {'ticket': st.ticket})
            logger.debug("Redirecting to %s" % service)
            return redirect(service)
        elif request.user.is_authenticated():
            if service:
                logger.debug("Service ticket request received "
                             "by credential requestor")
                if self.warn_user() and not warned:
                    return redirect(add_query_params(reverse('cas_warn'),
                                                     {'service': service}))
                st = ServiceTicket.objects.create_ticket(service=service,
                                                         user=request.user)
                service = add_query_params(service, {'ticket': st.ticket})
                logger.debug("Redirecting to %s" % service)
                return redirect(service)
            else:
                messages.success(request,
                                 _("You are logged in as %s") % request.user)
        return super(LoginView, self).get(request, *args, **kwargs)
Example #2
0
 def form_valid(self, form):
     service = form.cleaned_data.get('service')
     gateway = form.cleaned_data.get('gateway')
     return redirect(add_query_params(reverse('cas_login'),
                                      {'service': service,
                                       'gateway': gateway,
                                       'warned': 'true'}))
Example #3
0
    def validate_pgturl(self, pgturl, pgtid, pgtiou):
        """
        Verify the provided proxy callback URL. This verification process
        requires three steps:

        1. The URL scheme must be HTTPS
        2. The SSL certificate must be valid and its name must match that
           of the service
        3. The callback URL must respond with a 200 or 3xx response code

        It is not required for validation that 3xx redirects be followed.
        """
        # Ensure the scheme is HTTPS before proceeding
        if not is_scheme_https(pgturl):
            raise InternalError("Proxy callback %s is not HTTPS" % pgturl)

        # Connect to proxy callback URL, checking the SSL certificate
        pgturl = add_query_params(pgturl, {'pgtId': pgtid, 'pgtIou': pgtiou})
        try:
            verify = os.environ.get('REQUESTS_CA_BUNDLE', True)
            r = requests.get(pgturl, verify=verify)
        except (requests.exceptions.ConnectionError,
                requests.exceptions.SSLError) as e:
            raise InternalError("Proxy callback %s returned %s" % (pgturl, e))

        # Check the returned HTTP status code
        try:
            r.raise_for_status()
        except requests.exceptions.HTTPError as e:
            raise InternalError("Proxy callback %s returned %s" % (pgturl, e))
Example #4
0
    def valid_response(self, form):

        login(self.request, form.user)
        logger.info("Single sign-on session started for %s" % form.user)

        if form.cleaned_data.get('warn'):
            self.request.session['warn'] = True

        service = self.request.REQUEST.get('service')
        if service:
            st = ServiceTicket.objects.create_ticket(service=service,
                                                     user=self.request.user,
                                                     primary=True)
            if not is_valid_service_url(service):
                data = dict(state=False, error=u'permission denied')
            else:
                cross_domain_urls = get_service_login_urls_with_ticket(service, self.request.user)
                params = {'ticket': st.ticket}
                next_page = self.request.REQUEST.get('next', '')
                if next_page and is_valid_service_url(next_page):
                    params['next'] = next_page
                redirect_to = add_query_params(service, params=params)
                data = dict(state=True, redirect_to=redirect_to, cross_domain_urls=cross_domain_urls)
        else:
            data = dict(state=False)
        return data
Example #5
0
 def test_login_view_invalid_service(self):
     """
     When called with an invalid service URL, the view should
     return a 302 Redirect to the InvalidService View.
     """
     response = self.client.get(reverse('cas_login'), {'service': self.service_url, 'gateway': 'true'})
     self.assertRedirects(response, add_query_params(reverse('cas_invalid_service'), {'service': self.service_url}), target_status_code=403)
Example #6
0
    def validate_callback(self, service, pgturl, pgtid, pgtiou):
        """Verify the provided proxy callback URL."""
        if not proxy_allowed(service):
            raise UnauthorizedServiceProxy("%s is not authorized to use proxy authentication" % service)

        if not is_scheme_https(pgturl):
            raise InvalidProxyCallback("Proxy callback %s is not HTTPS" % pgturl)

        if not proxy_callback_allowed(service, pgturl):
            raise InvalidProxyCallback("%s is not an authorized proxy callback URL" % pgturl)

        # Verify that the SSL certificate is valid
        verify = os.environ.get('REQUESTS_CA_BUNDLE', True)
        try:
            requests.get(pgturl, verify=verify, timeout=5)
        except requests.exceptions.SSLError:
            raise InvalidProxyCallback("SSL certificate validation failed for proxy callback %s" % pgturl)
        except requests.exceptions.RequestException as e:
            raise InvalidProxyCallback(e)

        # Callback certificate appears valid, so send the ticket strings
        pgturl = add_query_params(pgturl, {'pgtId': pgtid, 'pgtIou': pgtiou})
        try:
            response = requests.get(pgturl, verify=verify, timeout=5)
        except requests.exceptions.RequestException as e:
            raise InvalidProxyCallback(e)

        try:
            response.raise_for_status()
        except requests.exceptions.HTTPError as e:
            raise InvalidProxyCallback("Proxy callback %s returned %s" % (pgturl, e))
Example #7
0
    def validate_callback(self, service, pgturl, pgtid, pgtiou):
        """Verify the provided proxy callback URL."""
        if not proxy_allowed(service):
            raise UnauthorizedServiceProxy("%s is not authorized to use proxy authentication" % service)

        if not is_scheme_https(pgturl):
            raise InvalidProxyCallback("Proxy callback %s is not HTTPS" % pgturl)

        if not proxy_callback_allowed(service, pgturl):
            raise InvalidProxyCallback("%s is not an authorized proxy callback URL" % pgturl)

        # Verify that the SSL certificate is valid
        verify = os.environ.get('REQUESTS_CA_BUNDLE', True)
        try:
            requests.get(pgturl, verify=verify, timeout=5)
        except requests.exceptions.SSLError:
            raise InvalidProxyCallback("SSL certificate validation failed for proxy callback %s" % pgturl)
        except requests.exceptions.RequestException as e:
            raise InvalidProxyCallback(e)

        # Callback certificate appears valid, so send the ticket strings
        pgturl = add_query_params(pgturl, {'pgtId': pgtid, 'pgtIou': pgtiou})
        try:
            response = requests.get(pgturl, verify=verify, timeout=5)
        except requests.exceptions.RequestException as e:
            raise InvalidProxyCallback(e)

        try:
            response.raise_for_status()
        except requests.exceptions.HTTPError as e:
            raise InvalidProxyCallback("Proxy callback %s returned %s" % (pgturl, e))
Example #8
0
    def validate_callback(self, service, pgturl, pgtid, pgtiou):
        """Verify the provided proxy callback URL."""
        if not get_config(service, 'PROXY_ALLOW'):
            raise UnauthorizedServiceProxy("%s is not authorized to use proxy authentication" % service)

        if not is_scheme_https(pgturl):
            raise InvalidProxyCallback("Proxy callback %s is not HTTPS" % pgturl)

        if not is_valid_proxy_callback(service, pgturl):
            raise InvalidProxyCallback("%s is not an authorized proxy callback URL" % pgturl)

        # Check the proxy callback URL and SSL certificate
        pgturl_params = add_query_params(pgturl, {'pgtId': pgtid, 'pgtIou': pgtiou})
        verify = os.environ.get('REQUESTS_CA_BUNDLE', True)
        try:
            r = requests.get(pgturl_params, verify=verify, timeout=3.0)
        except requests.exceptions.SSLError:
            msg = "SSL cert validation failed for proxy callback %s" % pgturl
            raise InvalidProxyCallback(msg)
        except requests.exceptions.ConnectionError:
            msg = "Error connecting to proxy callback %s" % pgturl
            raise InvalidProxyCallback(msg)
        except requests.exceptions.Timeout:
            msg = "Timeout connecting to proxy callback %s" % pgturl
            raise InvalidProxyCallback(msg)

        # Check the returned HTTP status code
        try:
            r.raise_for_status()
        except requests.exceptions.HTTPError as e:
            msg = "Proxy callback %s returned %s" % (pgturl, e)
            raise InvalidProxyCallback(msg)
Example #9
0
 def get(self, request, *args, **kwargs):
     service = request.GET.get('service')
     ticket = request.GET.get('ticket')
     msg = _("Do you want to access %s as %s?") % (clean_service_url(service),
                                                   request.user)
     messages.info(request, msg)
     kwargs['service'] = add_query_params(service, {'ticket': ticket})
     return super(WarnView, self).get(request, *args, **kwargs)
Example #10
0
 def test_add_query_params_unicode(self):
     """
     When Unicode parameters are provided, ``add_query_params()``
     should encode them appropriately.
     """
     params = {'unicode1': u'ä', u'unicode²': 'b'}
     url = add_query_params('http://www.example.com/', params)
     self.assertIn('unicode1=%C3%A4', url)
     self.assertIn('unicode%C2%B2=b', url)
Example #11
0
 def test_add_query_params_unicode(self):
     """
     When Unicode parameters are provided, ``add_query_params()``
     should encode them appropriately.
     """
     params = {'unicode1': u'ä', u'unicode²': 'b'}
     url = add_query_params('http://www.example.com/', params)
     self.assertIn('unicode1=%C3%A4', url)
     self.assertIn('unicode%C2%B2=b', url)
Example #12
0
    def get(self, request, *args, **kwargs):
        service = request.GET.get('service')
        ticket = request.GET.get('ticket')

        if not service or not is_valid_service_url(service):
            return redirect('cas_login')

        msg = _("Do you want to access %(service)s as %(user)s?") % {
                'service': clean_service_url(service),
                'user': request.user}
        messages.info(request, msg)
        kwargs['service'] = add_query_params(service, {'ticket': ticket})
        return super(WarnView, self).get(request, *args, **kwargs)
Example #13
0
def get_service_login_urls_with_ticket(exclude_url, user):
    """
    :param exclude_url: service url excluded
    :param user: generate `ServiceTicket` for `user`
    :return: MAMA_CAS_VALID_SERVICES login urls with ticket exclude `exclude_url`
    """
    urls = []
    for service in get_service_urls(exclude_url):
        st = ServiceTicket.objects.create_ticket(service=service,
                                                 user=user)
        url = urljoin(service, '/accounts/login/')
        urls.append(add_query_params(url, params={'ticket': st.ticket}))
    return urls
Example #14
0
    def test_add_query_params(self):
        """
        When called with a URL and a dict of parameters,
        ``add_query_params()`` should insert the parameters into the
        original URL.
        """
        url = 'http://www.example.com/?test3=blue'
        params = {'test1': 'red', 'test2': '', 'test3': 'indigo'}
        url = add_query_params(url, params)

        self.assertIn('test1=red', url)
        # Parameters with empty values should be ignored
        self.assertNotIn('test2=', url)
        # Existing parameters with the same name should be overwritten
        self.assertIn('test3=indigo', url)
Example #15
0
    def test_add_query_params(self):
        """
        When called with a URL and a dict of parameters,
        ``add_query_params()`` should insert the parameters into the
        original URL.
        """
        url = 'http://www.example.com/?test3=blue'
        params = {'test1': 'red', 'test2': '', 'test3': 'indigo'}
        url = add_query_params(url, params)

        self.assertIn('test1=red', url)
        # Parameters with empty values should be ignored
        self.assertNotIn('test2=', url)
        # Existing parameters with the same name should be overwritten
        self.assertIn('test3=indigo', url)
Example #16
0
    def validate_callback(self, service, pgturl, pgtid, pgtiou):
        """Verify the provided proxy callback URL."""
        if not can_proxy_authentication(service):
            raise UnauthorizedServiceProxy(
                "%s is not authorized to use proxy authentication" % service)

        if not is_scheme_https(pgturl):
            raise InvalidProxyCallback("Proxy callback %s is not HTTPS" %
                                       pgturl)

        if not is_valid_proxy_callback(service, pgturl):
            raise InvalidProxyCallback(
                "%s is not an authorized proxy callback URL" % pgturl)

        # Check the proxy callback URL and SSL certificate
        pgturl_params = add_query_params(pgturl, {
            'pgtId': pgtid,
            'pgtIou': pgtiou
        })
        verify = os.environ.get('REQUESTS_CA_BUNDLE', True)
        try:
            r = requests.get(pgturl_params, verify=verify, timeout=3.0)
        except requests.exceptions.SSLError:
            msg = "SSL cert validation failed for proxy callback %s" % pgturl
            raise InvalidProxyCallback(msg)
        except requests.exceptions.ConnectionError:
            msg = "Error connecting to proxy callback %s" % pgturl
            raise InvalidProxyCallback(msg)
        except requests.exceptions.Timeout:
            msg = "Timeout connecting to proxy callback %s" % pgturl
            raise InvalidProxyCallback(msg)

        # Check the returned HTTP status code
        try:
            r.raise_for_status()
        except requests.exceptions.HTTPError as e:
            msg = "Proxy callback %s returned %s" % (pgturl, e)
            raise InvalidProxyCallback(msg)
Example #17
0
    def form_valid(self, form):
        """
        (2.2) As a credential acceptor, /login requires two parameters:

        1. ``username``: the username provided by the client
        2. ``password``: the password provided by the client

        If authentication is successful, the single sign-on session is
        created. If a service is provided, a ``ServiceTicket`` is
        created and the client is redirected to the service URL with
        the ``ServiceTicket`` included. If no service is provided, the
        login page is redisplayed with a message indicating a
        successful login.

        If authentication fails, the login form is redisplayed with an
        error message describing the reason for failure.

        The credential acceptor accepts one optional parameter:

        1. ``warn``: causes the user to be prompted when successive
           authentication attempts occur within the single sign-on
           session.
        """
        login(self.request, form.user)
        logger.info("Single sign-on session started for %s" % form.user)

        if form.cleaned_data.get('warn'):
            self.request.session['warn'] = True

        service = form.cleaned_data.get('service')
        if service:
            st = ServiceTicket.objects.create_ticket(service=service,
                                                     user=self.request.user,
                                                     primary=True)
            service = add_query_params(service, {'ticket': st.ticket})
            logger.debug("Redirecting to %s" % service)
            return redirect(service)
        return redirect(reverse('cas_login'))
Example #18
0
    def validate_callback(self, url, pgtid, pgtiou):
        """
        Verify the provided proxy callback URL. This verification process
        requires three steps:

        1. The URL scheme must be HTTPS
        2. The SSL certificate must be valid and its name must match that
           of the service
        3. The callback URL must respond with a 200 or 3xx response code

        It is not required for validation that 3xx redirects be followed.
        """
        # Ensure the scheme is HTTPS before proceeding
        if not is_scheme_https(url):
            raise InvalidProxyCallback("Proxy callback %s is not HTTPS" % url)

        # Connect to proxy callback URL, checking the SSL certificate
        url_params = add_query_params(url, {'pgtId': pgtid, 'pgtIou': pgtiou})
        verify = os.environ.get('REQUESTS_CA_BUNDLE', True)
        try:
            r = requests.get(url_params, verify=verify, timeout=3.0)
        except requests.exceptions.SSLError:
            msg = "SSL cert validation failed for proxy callback %s" % url
            raise InvalidProxyCallback(msg)
        except requests.exceptions.ConnectionError:
            msg = "Error connecting to proxy callback %s" % url
            raise InvalidProxyCallback(msg)
        except requests.exceptions.Timeout:
            msg = "Timeout connecting to proxy callback %s" % url
            raise InvalidProxyCallback(msg)

        # Check the returned HTTP status code
        try:
            r.raise_for_status()
        except requests.exceptions.HTTPError as e:
            msg = "Proxy callback %s returned %s" % (url, e)
            raise InvalidProxyCallback(msg)
Example #19
0
    def validate_callback(self, url, pgtid, pgtiou):
        """
        Verify the provided proxy callback URL. This verification process
        requires three steps:

        1. The URL scheme must be HTTPS
        2. The SSL certificate must be valid and its name must match that
           of the service
        3. The callback URL must respond with a 200 or 3xx response code

        It is not required for validation that 3xx redirects be followed.
        """
        # Ensure the scheme is HTTPS before proceeding
        if not is_scheme_https(url):
            raise InvalidProxyCallback("Proxy callback %s is not HTTPS" % url)

        # Connect to proxy callback URL, checking the SSL certificate
        url_params = add_query_params(url, {'pgtId': pgtid, 'pgtIou': pgtiou})
        verify = os.environ.get('REQUESTS_CA_BUNDLE', True)
        try:
            r = requests.get(url_params, verify=verify, timeout=3.0)
        except requests.exceptions.SSLError:
            msg = "SSL cert validation failed for proxy callback %s" % url
            raise InvalidProxyCallback(msg)
        except requests.exceptions.ConnectionError:
            msg = "Error connecting to proxy callback %s" % url
            raise InvalidProxyCallback(msg)
        except requests.exceptions.Timeout:
            msg = "Timeout connecting to proxy callback %s" % url
            raise InvalidProxyCallback(msg)

        # Check the returned HTTP status code
        try:
            r.raise_for_status()
        except requests.exceptions.HTTPError as e:
            msg = "Proxy callback %s returned %s" % (url, e)
            raise InvalidProxyCallback(msg)
Example #20
0
    def form_valid(self, form):
        """
        As a credential acceptor, /login takes two required parameters:

        1. ``username``: the username provided by the client
        2. ``password``: the password provided by the client

        If authentication is successful, the user is logged in which creates
        the single sign-on session. If a service is provided, a corresponding
        ``ServiceTicket`` is created, and the user is redirected to the
        service URL. If no service is provided, the user is redirected back
        to the login page with a message indicating a successful login.

        If authentication fails, the login form is redisplayed with an
        appropriate error message displayed indicating the reason for failure.

        The credential acceptor also accepts one optional parameter:

        1. ``warn``: causes user input to be required whenever an
           authentication attempt occurs within the single sign-on session.
        """
        auth.login(self.request, form.user)
        logger.info("Single sign-on session started for %s" % self.request.user)

        if form.cleaned_data.get('warn'):
            self.request.session['warn'] = True

        service = form.cleaned_data.get('service')
        if service:
            st = ServiceTicket.objects.create_ticket(service=service,
                                                     user=self.request.user,
                                                     primary=True)
            service = add_query_params(service, {'ticket': st.ticket})
            logger.debug("Redirecting to %s" % service)
            return redirect(service)
        return redirect(reverse('cas_login'))