utils.py 3.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. # Copyright (C) 2012 Yaco Sistemas (http://www.yaco.es)
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. from django.conf import settings
  15. from django.core.exceptions import ImproperlyConfigured
  16. # from django.utils.module_loading import import_string
  17. # from djangosaml2.acs_failures import exception_failure
  18. from saml2.s_utils import UnknownSystemEntity
  19. def get_custom_setting(name, default=None):
  20. return getattr(settings, name, default)
  21. def available_idps(config, langpref=None):
  22. if langpref is None:
  23. langpref = "en"
  24. idps = set()
  25. for metadata_name, metadata in config.metadata.metadata.items():
  26. result = metadata.any('idpsso_descriptor', 'single_sign_on_service')
  27. if result:
  28. idps = idps.union(set(result.keys()))
  29. return dict([(idp, config.metadata.name(idp, langpref)) for idp in idps])
  30. def get_idp_sso_supported_bindings(idp_entity_id=None, config=None):
  31. """Returns the list of bindings supported by an IDP
  32. This is not clear in the pysaml2 code, so wrapping it in a util"""
  33. if config is None:
  34. # avoid circular import
  35. from djangosaml2.conf import get_config
  36. config = get_config()
  37. # load metadata store from config
  38. meta = getattr(config, 'metadata', {})
  39. # if idp is None, assume only one exists so just use that
  40. if idp_entity_id is None:
  41. # .keys() returns dict_keys in python3.5+
  42. try:
  43. idp_entity_id = list(available_idps(config).keys())[0]
  44. except IndexError:
  45. raise ImproperlyConfigured("No IdP configured!")
  46. try:
  47. return meta.service(idp_entity_id, 'idpsso_descriptor', 'single_sign_on_service').keys()
  48. except UnknownSystemEntity:
  49. return []
  50. def get_location(http_info):
  51. """Extract the redirect URL from a pysaml2 http_info object"""
  52. assert 'headers' in http_info
  53. headers = http_info['headers']
  54. assert len(headers) == 1
  55. header_name, header_value = headers[0]
  56. assert header_name == 'Location'
  57. return header_value
  58. def fail_acs_response(request, *args, **kwargs):
  59. """ Serves as a common mechanism for ending ACS in case of any SAML related failure.
  60. Handling can be configured by setting the SAML_ACS_FAILURE_RESPONSE_FUNCTION as
  61. suitable for the project.
  62. The default behavior uses SAML specific template that is rendered on any ACS error,
  63. but this can be simply changed so that PermissionDenied exception is raised instead.
  64. """
  65. # failure_function = import_string(get_custom_setting('SAML_ACS_FAILURE_RESPONSE_FUNCTION',
  66. # 'djangosaml2.acs_failures.template_failure'))
  67. from djangosaml2.acs_failures import exception_failure
  68. failure_function = exception_failure
  69. return failure_function(request, *args, **kwargs)