CAT-SOOP is a flexible, programmable learning management system based on the Python programming language. https://catsoop.mit.edu
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

113 lines
3.8 KiB

  1. # This file is part of CAT-SOOP
  2. # Copyright (c) 2011-2020 by The CAT-SOOP Developers <catsoop-dev@mit.edu>
  3. #
  4. # This program is free software: you can redistribute it and/or modify it under
  5. # the terms of the GNU Affero General Public License as published by the Free
  6. # Software Foundation, either version 3 of the License, or (at your option) any
  7. # later version.
  8. #
  9. # This program is distributed in the hope that it will be useful, but WITHOUT
  10. # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  11. # FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
  12. # details.
  13. #
  14. # You should have received a copy of the GNU Affero General Public License
  15. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. """
  17. Store ticket, validate ticket, and then return user info if all ok
  18. """
  19. import urllib.parse
  20. import urllib.request
  21. from lxml import etree
  22. from catsoop import debug_log
  23. LOGGER = debug_log.LOGGER
  24. errors = []
  25. def validate_ticket(ticket):
  26. redir_url = "%s/_auth/cas/callback" % cs_url_root
  27. val_url = (
  28. cs_cas_server
  29. + "/serviceValidate"
  30. + "?service="
  31. + urllib.parse.quote(redir_url)
  32. + "&ticket="
  33. + urllib.parse.quote(ticket)
  34. )
  35. try:
  36. ret = urllib.request.urlopen(val_url).read()
  37. except Exception as err:
  38. errors.append("CAS server rejected token request.")
  39. errors.append(str(err))
  40. LOGGER.error(
  41. "[auth.cas.validate] failed to sent validation request to cas server val_url=%s"
  42. % val_url
  43. )
  44. LOGGER.error("[auth.cas.validate] err=%s" % str(err))
  45. ret = ret.decode("utf8")
  46. LOGGER.debug("[auth.cas.validate] cas server returned %s" % ret)
  47. if "cas:serviceResponse" not in ret:
  48. return None
  49. try:
  50. xml = etree.fromstring(ret)
  51. except Exception as err:
  52. LOGGER.error(
  53. "[auth.cas.validate] Failed to parse XML response from CAS server, err=%s"
  54. % str(err)
  55. )
  56. xml = None
  57. if not xml:
  58. return None
  59. LOGGER.debug("xml=%s" % xml)
  60. cas_info = {}
  61. def fillin(xpath, field):
  62. elem = xml.find(xpath)
  63. if elem is not None:
  64. cas_info[field] = elem.text
  65. fillin(".//{http://www.yale.edu/tp/cas}user", "username")
  66. fillin(".//{http://www.yale.edu/tp/cas}email", "email")
  67. fillin(".//{http://www.yale.edu/tp/cas}givenName", "firstname")
  68. fillin(".//{http://www.yale.edu/tp/cas}sn", "lastname")
  69. cas_info["cas_ticket"] = ticket
  70. if cas_info.get("firstname"):
  71. cas_info["name"] = " ".join([cas_info[x] for x in ["firstname", "lastname"]])
  72. return cas_info
  73. ticket = cs_form.get("ticket", None)
  74. cas_info = validate_ticket(ticket)
  75. if cas_info:
  76. LOGGER.info("[auth.cas.validate] cas server validated cas_info=%s" % cas_info)
  77. cs_session_data.update(cas_info)
  78. else:
  79. LOGGER.info("[auth.cas.validate] cas server did not validate ticket")
  80. path = [csm_base_context.cs_url_root] + cs_session_data.get("_cas_path", ["/"])
  81. redirect_location = "/".join(path)
  82. if cs_session_data.get("cs_query_string", ""):
  83. redirect_location += "?" + cs_session_data["cs_query_string"]
  84. if not cas_info:
  85. cs_handler = "passthrough"
  86. cs_content_header = "Could Not Log You In"
  87. cs_content = (
  88. 'You could not be logged in to the system because of the following error:<br/><font color="red">%s</font><p>Click <a href="%s?loginaction=login">here</a> to try again.'
  89. % ("\n".join(errors), redirect_location)
  90. )
  91. cs_footer = cs_footer.replace(cs_base_logo_text, csm_errors.error_500_logo)
  92. # we made it! set session data and redirect to original page
  93. csm_session.set_session_data(globals(), cs_sid, cs_session_data)
  94. csm_cslog.overwrite_log("_extra_info", [], cs_session_data["username"], cas_info)
  95. LOGGER.info("[auth.cas.validate] redirecting to %s" % redirect_location)
  96. cs_handler = "redirect"