docs: def validate_service_ticket(self, ticket):
          """
          Validate a CAS service ticket.
  
          Returns (is_valid, user, attribs).
          `is_valid` - boolean
          `attribs` - set of attribute-value tuples.
          """
          app_log = logging.getLogger("tornado.application")
          http_client = AsyncHTTPClient()
          service = self.make_service_url()
          qs_dict = dict(service=service, ticket=ticket)
          qs = urllib.parse.urlencode(qs_dict)
          cas_validate_url = self.authenticator.cas_service_validate_url + "?" + qs
          response = None
          app_log.debug("Validate URL: {0}".format(cas_validate_url))
          try:
              response = yield http_client.fetch(
                  cas_validate_url,
                  method="GET",
                  ca_certs=self.authenticator.cas_client_ca_certs)
              app_log.debug("Response was successful: {0}".format(response))
          except HTTPError as ex:
              app_log.debug("Response was unsuccessful: {0}".format(response))
              return (False, None, None)
          parser = etree.XMLParser()
          root = etree.fromstring(response.body, parser=parser)
          auth_result_elm = root[0]
          is_success = (etree.QName(auth_result_elm).localname == 'authenticationSuccess')
          if not is_success:
              return (False, None, None)
          user_elm = find_child_element(auth_result_elm, "user")
          user = user_elm.text.lower()
          attrib_results = set([])
          attribs = find_child_element(auth_result_elm, "attributes")
          if attribs is None:
              attribs = []
          for attrib in attribs:
              name = etree.QName(attrib).localname
              value = attrib.text
              attrib_results.add((name, value))
          return (True, user, attrib_results)