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
def test_is_valid_service_url(self): """ When valid services are configured, ``is_valid_service_url()`` should return ``True`` if the provided URL matches, and ``False`` otherwise. """ self.assertTrue(is_valid_service_url('http://www.example.com')) self.assertFalse(is_valid_service_url('http://www.example.org'))
def test_is_valid_service_url(self): """ When valid services are configured, ``is_valid_service_url()`` should return ``True`` if the provided URL matches, and ``False`` otherwise. """ old_valid_services = getattr(settings, 'MAMA_CAS_VALID_SERVICES', ()) settings.MAMA_CAS_VALID_SERVICES = ('http://.*\.example\.com',) self.assertTrue(is_valid_service_url('http://www.example.com')) self.assertFalse(is_valid_service_url('http://www.example.org')) settings.MAMA_CAS_VALID_SERVICES = old_valid_services
def validate_ticket(self, ticket, service): """ Given a ticket string and service identifier, validate the corresponding ``Ticket``. If validation succeeds, return the ``Ticket``. If validation fails, raise an appropriate error. """ if not ticket: raise InvalidRequest("No ticket string provided") if not service: raise InvalidRequest("No service identifier provided") if not self.model.TICKET_RE.match(ticket): raise InvalidTicket("Ticket string %s is invalid" % ticket) try: t = self.get(ticket=ticket) except self.model.DoesNotExist: raise BadPgt("Ticket %s does not exist" % ticket) if t.is_consumed(): raise InvalidTicket("%s %s has already been used" % (t.name, ticket)) if t.is_expired(): raise InvalidTicket("%s %s has expired" % (t.name, ticket)) if not is_valid_service_url(service): raise InvalidService("Service %s is not a valid %s URL" % (service, t.name)) logger.debug("Validated %s %s" % (t.name, ticket)) return t
def validate_callback(self, url, pgtid, pgtiou): """Verify the provided proxy callback URL.""" if not is_scheme_https(url): raise InvalidProxyCallback("Proxy callback %s is not HTTPS" % url) if not is_valid_service_url(url): raise InvalidProxyCallback("%s is not a valid proxy callback URL" % url) # Check the proxy callback URL and 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)
def validate_ticket(self, ticket, service): """ Given a ticket string, validate the corresponding ``Ticket`` returning the ``Ticket`` if valid. If validation fails, return ``False``. """ if not ticket: raise InvalidRequestError("No ticket string provided") if not service: raise InvalidRequestError("No service identifier provided") if not self.model.TICKET_RE.match(ticket): raise InvalidTicketError("Ticket string %s is invalid" % ticket) title = self.model._meta.verbose_name.title() try: t = self.get(ticket=ticket) except self.model.DoesNotExist: raise BadPGTError("%s %s does not exist" % (title, ticket)) if t.is_consumed(): raise InvalidTicketError("%s %s has already been used" % (title, ticket)) if not is_valid_service_url(service): raise InvalidServiceError("Service %s is not a valid %s URL" % (service, title)) logger.debug("Validated %s %s" % (title, ticket)) return t
def get(self, request, *args, **kwargs): logger.debug("Logout request received for %s" % request.user) self.logout_user(request) url = request.GET.get('url', None) if url and is_valid_service_url(url): messages.success(request, _("The application provided this " "link to follow: %s") % url) return redirect(reverse('cas_login'))
def test_empty_valid_services(self): """ When no valid services are configured, ``is_valid_service_url()`` should return ``True``. """ old_valid_services = getattr(settings, 'MAMA_CAS_VALID_SERVICES', ()) settings.MAMA_CAS_VALID_SERVICES = () self.assertTrue(is_valid_service_url('http://www.example.com')) settings.MAMA_CAS_VALID_SERVICES = old_valid_services
def validate_ticket(self, ticket, service, renew=False, require_https=False): """ Given a ticket string and service identifier, validate the corresponding ``Ticket``. If validation succeeds, return the ``Ticket``. If validation fails, raise an appropriate error. If ``renew`` is ``True``, ``ServiceTicket`` validation will only succeed if the ticket was issued from the presentation of the user's primary credentials. If ``require_https`` is ``True``, ``ServiceTicket`` validation will only succeed if the service URL scheme is HTTPS. """ if not ticket: raise InvalidRequest("No ticket string provided") if not self.model.TICKET_RE.match(ticket): raise InvalidTicket("Ticket string %s is invalid" % ticket) try: t = self.get(ticket=ticket) except self.model.DoesNotExist: raise InvalidTicket("Ticket %s does not exist" % ticket) if t.is_consumed(): raise InvalidTicket("%s %s has already been used" % (t.name, ticket)) if t.is_expired(): raise InvalidTicket("%s %s has expired" % (t.name, ticket)) if not service: raise InvalidRequest("No service identifier provided") if require_https and not is_scheme_https(service): raise InvalidService("Service %s is not HTTPS" % service) if not is_valid_service_url(service): raise InvalidService("Service %s is not a valid %s URL" % (service, t.name)) try: if not match_service(t.service, service): raise InvalidService("%s %s for service %s is invalid for " "service %s" % (t.name, ticket, t.service, service)) except AttributeError: pass try: if renew and not t.is_primary(): raise InvalidTicket("%s %s was not issued via primary " "credentials" % (t.name, ticket)) except AttributeError: pass logger.debug("Validated %s %s" % (t.name, ticket)) return t
def validate_ticket(self, ticket, service, renew=False, require_https=False): """ Given a ticket string and service identifier, validate the corresponding ``Ticket``. If validation succeeds, return the ``Ticket``. If validation fails, raise an appropriate error. If ``renew`` is ``True``, ``ServiceTicket`` validation will only succeed if the ticket was issued from the presentation of the user's primary credentials. If ``require_https`` is ``True``, ``ServiceTicket`` validation will only succeed if the service URL scheme is HTTPS. """ if not ticket: raise InvalidRequest("No ticket string provided") if not self.model.TICKET_RE.match(ticket): raise InvalidTicket("Ticket string %s is invalid" % ticket) try: t = self.get(ticket=ticket) except self.model.DoesNotExist: raise InvalidTicket("Ticket %s does not exist" % ticket) if t.is_consumed(): raise InvalidTicket("%s %s has already been used" % (t.name, ticket)) if t.is_expired(): raise InvalidTicket("%s %s has expired" % (t.name, ticket)) if not service: raise InvalidRequest("No service identifier provided") if require_https and not is_scheme_https(service): raise InvalidService("Service %s is not HTTPS" % service) if not is_valid_service_url(service): raise InvalidService("Service %s is not a valid %s URL" % (service, t.name)) try: if not same_origin(t.service, service): raise InvalidService("%s %s for service %s is invalid for " "service %s" % (t.name, ticket, t.service, service)) except AttributeError: pass try: if renew and not t.is_primary(): raise InvalidTicket("%s %s was not issued via primary " "credentials" % (t.name, ticket)) except AttributeError: pass logger.debug("Validated %s %s" % (t.name, ticket)) return t
def get(self, request, *args, **kwargs): logger.debug("Logout request received for %s" % request.user) self.logout_user(request) url = request.GET.get('url', None) if url and is_valid_service_url(url): if getattr(settings, 'MAMA_CAS_FOLLOW_LOGOUT_URL', False): return redirect(url) msg = _("The application provided this link to follow: %s") % url messages.success(request, msg) return redirect(reverse('cas_login'))
def get(self, request, *args, **kwargs): service = request.GET.get('service') url = request.GET.get('url') follow_url = getattr(settings, 'MAMA_CAS_FOLLOW_LOGOUT_URL', True) self.logout_user(request) if service and follow_url: return redirect(service) elif url and is_valid_service_url(url): if follow_url: return redirect(url) msg = _("The application provided this link to follow: %s") % url messages.success(request, msg) return redirect('cas_login')
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)
def validate_ticket(self, ticket, service=None, renew=False): """ Given a ticket string, validate the corresponding ``Ticket`` returning the ``Ticket`` if valid. If validation fails, return ``False``. If ``service`` is provided and the ticket has a service attribute, the origin of the two services will be compared. Validation will only succeed if the service origins match. if ``renew`` is provided, the validation will only succeed if the ticket was issued from the presentation of the user's primary credentials. """ if not ticket: raise InvalidRequestError("No ticket string provided") if not self.model.TICKET_RE.match(ticket): raise InvalidTicketError("Ticket string %s is invalid" % ticket) title = self.model._meta.verbose_name.title() try: t = self.get(ticket=ticket) except self.model.DoesNotExist: raise InvalidTicketError("%s %s does not exist" % (title, ticket)) if t.is_consumed(): raise InvalidTicketError("%s %s has already been used" % (title, ticket)) t.consume() if t.is_expired(): raise InvalidTicketError("%s %s has expired" % (title, ticket)) if not service: raise InvalidRequestError("No service identifier provided") if not is_valid_service_url(service): raise InvalidServiceError("Service %s is not a valid %s URL" % (service, title)) if not same_origin(t.service, service): raise InvalidServiceError("%s %s for service %s is invalid for service %s" % (title, ticket, t.service, service)) if renew and not t.is_primary(): raise InvalidTicketError("%s %s was not issued via primary credentials" % (title, ticket)) logger.debug("Validated %s %s" % (title, ticket)) return t
def test_empty_valid_services(self): """ When no valid services are configured, ``is_valid_service_url()`` should return ``True``. """ self.assertTrue(is_valid_service_url('http://www.example.com'))