def get_name_id_format(self, user, authn, resp_args): self.sp['name_id_format'] = resp_args.get('name_id_policy').format idp_name_id_format_list = self.IDP.config.getattr("name_id_format", "idp") # name_id format availability if idp_name_id_format_list and not self.sp['name_id_format']: name_id_format = idp_name_id_format_list[0] elif self.sp['name_id_format'] and not idp_name_id_format_list: name_id_format = self.sp['name_id_format'] elif self.sp['name_id_format'] not in idp_name_id_format_list: return self.handle_error(request, exception=_('SP requested a name_id_format ' 'that is not supported in the IDP')) elif self.sp['name_id_format'] in idp_name_id_format_list: name_id_format = self.sp['name_id_format'] else: name_id_format = NAMEID_FORMAT_UNSPECIFIED # if SP doesn't request a specific name_id_format... if not self.sp['name_id_format']: self.sp['name_id_format'] = name_id_format user_id = self.processor.get_user_id(user, self.sp, self.IDP.config) name_id = NameID(format=name_id_format, sp_name_qualifier=self.sp['id'], text=user_id) return name_id, user_id
def build_authn_response(self, user, authn, resp_args, processor: BaseProcessor, sp_config: dict): """ pysaml2 server.Server.create_authn_response wrapper """ policy = resp_args.get('name_id_policy', None) if policy is None: sp_config['name_id_format'] = NAMEID_FORMAT_UNSPECIFIED else: sp_config['name_id_format'] = policy.format idp_name_id_format_list = self.IDP.config.getattr("name_id_format", "idp") or [NAMEID_FORMAT_UNSPECIFIED] if sp_config['name_id_format'] not in idp_name_id_format_list: raise ImproperlyConfigured(_('SP requested a name_id_format that is not supported in the IDP')) user_id = processor.get_user_id(user, sp_config, self.IDP.config) name_id = NameID(format=sp_config['name_id_format'], sp_name_qualifier=sp_config['id'], text=user_id) authn_resp = self.IDP.create_authn_response( authn=authn, identity=processor.create_identity(user, sp_config.get('attribute_mapping')), name_id=name_id, userid=user_id, sp_entity_id=sp_config['id'], # Signing sign_response=sp_config['config'].get("sign_response") or self.IDP.config.getattr("sign_response", "idp") or False, sign_assertion=sp_config['config'].get("sign_assertion") or self.IDP.config.getattr("sign_assertion", "idp") or False, sign_alg=sp_config['config'].get("signing_algorithm") or getattr(settings, "SAML_AUTHN_SIGN_ALG", xmldsig.SIG_RSA_SHA256), digest_alg=sp_config['config'].get("digest_algorithm") or getattr(settings, "SAML_AUTHN_DIGEST_ALG", xmldsig.DIGEST_SHA256), # Encryption encrypt_assertion=sp_config['config'].get('encrypt_saml_responses') or getattr(settings, 'SAML_ENCRYPT_AUTHN_RESPONSE', False), encrypted_advice_attributes=sp_config['config'].get('encrypt_saml_responses') or getattr(settings, 'SAML_ENCRYPT_AUTHN_RESPONSE', False), **resp_args ) return authn_resp
def build_authn_response(user: User, authn, resp_args, service_provider: ServiceProvider) -> list: # type: ignore """ pysaml2 server.Server.create_authn_response wrapper """ policy = resp_args.get('name_id_policy', None) if policy is None: name_id_format = NAMEID_FORMAT_UNSPECIFIED else: name_id_format = policy.format idp_server = IDP.load() idp_name_id_format_list = idp_server.config.getattr("name_id_format", "idp") or [NAMEID_FORMAT_UNSPECIFIED] if name_id_format not in idp_name_id_format_list: raise ImproperlyConfigured(_('SP requested a name_id_format that is not supported in the IDP: {}').format(name_id_format)) processor: BaseProcessor = service_provider.processor # type: ignore user_id = processor.get_user_id(user, name_id_format, service_provider, idp_server.config) name_id = NameID(format=name_id_format, sp_name_qualifier=service_provider.entity_id, text=user_id) return idp_server.create_authn_response( authn=authn, identity=processor.create_identity(user, service_provider.attribute_mapping), name_id=name_id, userid=user_id, sp_entity_id=service_provider.entity_id, # Signing sign_response=service_provider.sign_response, sign_assertion=service_provider.sign_assertion, sign_alg=service_provider.signing_algorithm, digest_alg=service_provider.digest_algorithm, # Encryption encrypt_assertion=service_provider.encrypt_saml_responses, encrypted_advice_attributes=service_provider.encrypt_saml_responses, **resp_args )
def get(self, request, *args, **kwargs): passed_data = request.POST if request.method == 'POST' else request.GET # get sp information from the parameters try: sp_entity_id = passed_data['sp'] except KeyError as e: return HttpResponseBadRequest(e) try: sp_config = settings.SAML_IDP_SPCONFIG[sp_entity_id] except Exception: raise ImproperlyConfigured("No config for SP %s defined in SAML_IDP_SPCONFIG" % sp_entity_id) binding_out, destination = self.IDP.pick_binding( service="assertion_consumer_service", entity_id=sp_entity_id) processor = self.get_processor(sp_config) # Check if user has access to the service of this SP if not processor.has_access(request.user): raise PermissionDenied("You do not have access to this resource") identity = self.get_identity(processor, request.user, sp_config) req_authn_context = PASSWORD AUTHN_BROKER = AuthnBroker() AUTHN_BROKER.add(authn_context_class_ref(req_authn_context), "") # Construct SamlResponse messages try: name_id_formats = self.IDP.config.getattr("name_id_format", "idp") or [NAMEID_FORMAT_UNSPECIFIED] name_id = NameID(format=name_id_formats[0], text=request.user.username) authn = AUTHN_BROKER.get_authn_by_accr(req_authn_context) sign_response = self.IDP.config.getattr("sign_response", "idp") or False sign_assertion = self.IDP.config.getattr("sign_assertion", "idp") or False authn_resp = self.IDP.create_authn_response( identity=identity, in_response_to="IdP_Initiated_Login", destination=destination, sp_entity_id=sp_entity_id, userid=request.user.username, name_id=name_id, authn=authn, sign_response=sign_response, sign_assertion=sign_assertion, **passed_data) except Exception as excp: return HttpResponseServerError(excp) # Return as html with self-submitting form. http_args = self.IDP.apply_binding( binding=binding_out, msg_str="%s" % authn_resp, destination=destination, relay_state=passed_data['RelayState'], response=True) return HttpResponse(http_args['data'])
def build_authn_response(self, user, authn, resp_args): name_id_formats = [resp_args.get('name_id_policy').format ] or self.IDP.config.getattr( "name_id_format", "idp") or [NAMEID_FORMAT_UNSPECIFIED] authn_resp = self.IDP.create_authn_response( authn=authn, identity=self.processor.create_identity(user, self.sp['config']), userid=self.processor.get_user_id(user, self.sp['config']), name_id=NameID(format=name_id_formats[0], sp_name_qualifier=self.sp['id'], text=self.processor.get_user_id( user, self.sp['config'])), sign_response=self.sp['config'].get("sign_response") or self.IDP.config.getattr("sign_response", "idp") or False, sign_assertion=self.sp['config'].get("sign_assertion") or self.IDP.config.getattr("sign_assertion", "idp") or False, **resp_args) return authn_resp
def get_name_id_format(self, user, authn, resp_args): name_id_format = resp_args.get('name_id_policy') if not name_id_format: logger.warning( 'Missing NAME_ID_FORMAT, rely on: NAMEID_FORMAT_PERSISTENT') self.sp['name_id_format'] = name_id_format.format \ if name_id_format else NAMEID_FORMAT_PERSISTENT idp_name_id_format_list = self.IDP.config.getattr( "name_id_format", "idp") # name_id format availability if idp_name_id_format_list and not self.sp['name_id_format']: name_id_format = idp_name_id_format_list[0] elif self.sp['name_id_format'] and not idp_name_id_format_list: name_id_format = self.sp['name_id_format'] elif self.sp['name_id_format'] not in idp_name_id_format_list: _msg = _('SP requested a name_id_format ' 'that is not supported in the IDP: {}').format( self.sp['name_id_format']) # logger.error(_msg) raise UnavailableRequiredAttributes(_msg) elif self.sp['name_id_format'] in idp_name_id_format_list: name_id_format = self.sp['name_id_format'] else: name_id_format = NAMEID_FORMAT_UNSPECIFIED # if SP doesn't request a specific name_id_format... if not self.sp['name_id_format']: self.sp['name_id_format'] = name_id_format user_id = self.processor.get_user_id(user, self.sp, self.IDP.config) name_id = NameID(format=name_id_format, sp_name_qualifier=self.sp['id'], text=user_id) return name_id, user_id
def get(self, request, *args, **kwargs): binding = request.session.get('Binding', BINDING_HTTP_POST) # Parse incoming request try: req_info = self.IDP.parse_authn_request( request.session['SAMLRequest'], binding) except Exception as excp: return self.handle_error(request, exception=excp) # Signed request for HTTP-REDIRECT if "SigAlg" in request.session and "Signature" in request.session: _certs = self.IDP.metadata.certs(req_info.message.issuer.text, "any", "signing") verified_ok = False for cert in _certs: # TODO implement # if verify_redirect_signature(_info, self.IDP.sec.sec_backend, cert): # verified_ok = True # break pass if not verified_ok: return self.handle_error( request, extra_message="Message signature verification failure", status=400) # Gather response arguments try: resp_args = self.IDP.response_args(req_info.message) except (UnknownPrincipal, UnsupportedBinding) as excp: return self.handle_error(request, exception=excp, status=400) try: sp_config = settings.SAML_IDP_SPCONFIG[resp_args['sp_entity_id']] except Exception: return self.handle_error( request, exception=ImproperlyConfigured( "No config for SP %s defined in SAML_IDP_SPCONFIG" % resp_args['sp_entity_id']), status=400) processor = self.get_processor(resp_args['sp_entity_id'], sp_config) # Check if user has access to the service of this SP if not processor.has_access(request): return self.handle_error( request, exception=PermissionDenied( "You do not have access to this resource"), status=403) identity = self.get_identity(processor, request.user, sp_config) req_authn_context = req_info.message.requested_authn_context or PASSWORD AUTHN_BROKER = AuthnBroker() AUTHN_BROKER.add(authn_context_class_ref(req_authn_context), "") user_id = processor.get_user_id(request.user) # Construct SamlResponse message try: authn_resp = self.IDP.create_authn_response( identity=identity, userid=user_id, name_id=NameID(format=resp_args['name_id_policy'].format, sp_name_qualifier=resp_args['sp_entity_id'], text=user_id), authn=AUTHN_BROKER.get_authn_by_accr(req_authn_context), sign_response=self.IDP.config.getattr("sign_response", "idp") or False, sign_assertion=self.IDP.config.getattr("sign_assertion", "idp") or False, **resp_args) except Exception as excp: return self.handle_error(request, exception=excp, status=500) http_args = self.IDP.apply_binding( binding=resp_args['binding'], msg_str="%s" % authn_resp, destination=resp_args['destination'], relay_state=request.session['RelayState'], response=True) logger.debug('http args are: %s' % http_args) return self.render_response(request, processor, http_args)
def login_process(request): """ View which processes the actual SAML request and returns a self-submitting form with the SAML response. The login_required decorator ensures the user authenticates first on the IdP using 'normal' ways. """ # Construct server with config from settings dict conf = IdPConfig() conf.load(copy.deepcopy(settings.SAML_IDP_CONFIG)) IDP = Server(config=conf) # Parse incoming request try: req_info = IDP.parse_authn_request(request.session['SAMLRequest'], BINDING_HTTP_POST) except Exception as excp: return HttpResponseBadRequest(excp) # TODO this is taken from example, but no idea how this works or whats it does. Check SAML2 specification? # Signed request for HTTP-REDIRECT if "SigAlg" in request.session and "Signature" in request.session: _certs = IDP.metadata.certs(req_info.message.issuer.text, "any", "signing") verified_ok = False for cert in _certs: # TODO implement #if verify_redirect_signature(_info, IDP.sec.sec_backend, cert): # verified_ok = True # break pass if not verified_ok: return HttpResponseBadRequest( "Message signature verification failure") binding_out, destination = IDP.pick_binding( service="assertion_consumer_service", entity_id=req_info.message.issuer.text) # Gather response arguments try: resp_args = IDP.response_args(req_info.message) except (UnknownPrincipal, UnsupportedBinding) as excp: return HttpResponseServerError(excp) try: sp_config = settings.SAML_IDP_SPCONFIG[resp_args['sp_entity_id']] except Exception: raise ImproperlyConfigured( "No config for SP %s defined in SAML_IDP_SPCONFIG" % resp_args['sp_entity_id']) # Create user-specified processor or fallback to all-access base processor processor_string = sp_config.get('processor', None) if processor_string is None: processor = BaseProcessor else: processor_class = import_string(processor_string) processor = processor_class() # Check if user has access to the service of this SP if not processor.has_access(request.user): raise PermissionDenied("You do not have access to this resource") # Create Identity dict (SP-specific) sp_mapping = sp_config.get('attribute_mapping', {'username': '******'}) identity = processor.create_identity(request.user, sp_mapping) # TODO investigate how this works, because I don't get it. Specification? req_authn_context = req_info.message.requested_authn_context or PASSWORD AUTHN_BROKER = AuthnBroker() AUTHN_BROKER.add(authn_context_class_ref(req_authn_context), "") # Construct SamlResponse message try: authn_resp = IDP.create_authn_response( identity=identity, userid=request.user.username, name_id=NameID(format=resp_args['name_id_policy'].format, sp_name_qualifier=destination, text=request.user.username), authn=AUTHN_BROKER.get_authn_by_accr(req_authn_context), sign_response=IDP.config.getattr("sign_response", "idp") or False, sign_assertion=IDP.config.getattr("sign_assertion", "idp") or False, **resp_args) except Exception as excp: return HttpResponseServerError(excp) # Return as html with self-submitting form. http_args = IDP.apply_binding(binding=binding_out, msg_str="%s" % authn_resp, destination=destination, relay_state=request.session['RelayState'], response=True) logger.debug('http args are: %s' % http_args) if processor.enable_multifactor(request.user): # Store http_args in session for after multi factor is complete request.session['saml_data'] = http_args['data'] logger.debug("Redirecting to process_multi_factor") return HttpResponseRedirect(reverse('saml_multi_factor')) else: logger.debug("Performing SAML redirect") return HttpResponse(http_args['data'])
def build_authn_response(self, user, authn, resp_args): """ pysaml2 server.Server.create_authn_response wrapper """ self.sp['name_id_format'] = resp_args.get('name_id_policy').format idp_name_id_format_list = self.IDP.config.getattr("name_id_format", "idp") # name_id format availability if idp_name_id_format_list and not self.sp['name_id_format']: name_id_format = idp_name_id_format_list[0] elif self.sp['name_id_format'] and not idp_name_id_format_list: name_id_format = self.sp['name_id_format'] elif self.sp['name_id_format'] not in idp_name_id_format_list: return self.handle_error(request, exception=_('SP requested a name_id_format ' 'that is not supported in the IDP')) elif self.sp['name_id_format'] in idp_name_id_format_list: name_id_format = self.sp['name_id_format'] else: name_id_format = NAMEID_FORMAT_UNSPECIFIED # if SP doesn't request a specific name_id_format... if not self.sp['name_id_format']: self.sp['name_id_format'] = name_id_format user_id = self.processor.get_user_id(user, self.sp, self.IDP.config) name_id = NameID(format=name_id_format, sp_name_qualifier=self.sp['id'], text=user_id) #user_attrs = self.processor.create_identity(user, self.sp) # Generate request session stuff needed for user agreement screen attrs_to_exclude = self.sp['config'].get('user_agreement_attr_exclude', []) + \ getattr(settings, "SAML_IDP_USER_AGREEMENT_ATTR_EXCLUDE", []) self.request.session['identity'] = { k: v for k, v in self.processor.create_identity(self.request.user, self.sp).items() if k not in attrs_to_exclude } # ASSERTION ENCRYPTED encrypt_response = getattr(settings, 'SAML_ENCRYPT_AUTHN_RESPONSE', False) if 'encrypt_saml_responses' in self.sp['config'].keys(): encrypt_response = self.sp['config'].get('encrypt_saml_responses') encrypt_advice_attributes = getattr(settings, 'SAML_ENCRYPT_ADV_ATTRIBUTES', False) if 'encrypt_advice_attributes' in self.sp['config'].keys(): encrypt_advice_attributes = self.sp['config'].get('encrypt_advice_attributes') authn_resp = self.IDP.create_authn_response( authn=authn, identity=self.request.session['identity'], userid=user_id, name_id=name_id, # signature sign_response=self.sp['config'].get("sign_response") or \ self.IDP.config.getattr("sign_response", "idp") or \ False, sign_assertion=self.sp['config'].get("sign_assertion") or \ self.IDP.config.getattr("sign_assertion", "idp") or \ False, # default will be sha1 in pySAML2 sign_alg=self.sp['config'].get("signing_algorithm") or \ getattr(settings, 'SAML_AUTHN_SIGN_ALG', False), digest_alg=self.sp['config'].get("digest_algorithm") or \ getattr(settings, 'SAML_AUTHN_DIGEST_ALG', False), # Encryption encrypt_assertion=encrypt_response, encrypt_advice_attributes=encrypt_advice_attributes, **resp_args ) # entity categories and other pysaml2 policies could filter out some attributes policy = Policy(restrictions=settings.SAML_IDP_CONFIG['service']['idp'].get('policy')) ava = policy.filter(self.request.session['identity'], self.sp['id'], self.IDP.config.metadata, required=[]) # talking logs self.request.session['authn_log'] = ('SSO AuthnResponse to {} [{}]:' ' {} attrs ({}) on {} ' 'filtered by policy').format(self.sp['id'], self.request.session.get('message_id'), len(ava), ','.join(ava.keys()), len(self.request.session['identity'])) logger.info(self.request.session['authn_log']) # self.request.session['identity'] = ava return authn_resp
def get(self, request, *args, **kwargs): # pylint: disable=missing-function-docstring, too-many-locals, unused-argument passed_data = request.POST if request.method == 'POST' else request.GET # get sp information from the parameters try: sp_entity_id = passed_data['sp'] except KeyError as excp: return self.handle_error(request, exception=excp, status=400) try: # sp_config = SAML_IDP_SPCONFIG[sp_entity_id] sp_config = { 'processor': 'djangosaml2idp.processors.BaseProcessor', 'attribute_mapping': { # DJANGO: SAML 'username': '******', 'email': 'email', 'name': 'first_name', 'is_boss': 'is_admin', 'token': 'token', } } except Exception: # pylint: disable=broad-except return self.handle_error( request, exception=ImproperlyConfigured( "No config for SP %s defined in SAML_IDP_SPCONFIG" % sp_entity_id), status=400) binding_out, destination = self.IDP.pick_binding( service="assertion_consumer_service", entity_id=sp_entity_id) processor = self.get_processor(sp_entity_id, sp_config) # Check if user has access to the service of this SP if not processor.has_access(request): return self.handle_error( request, exception=PermissionDenied( "You do not have access to this resource"), status=403) identity = self.get_identity(processor, request.user, sp_config) req_authn_context = PASSWORD AUTHN_BROKER = AuthnBroker() # pylint: disable=invalid-name AUTHN_BROKER.add(authn_context_class_ref(req_authn_context), "") user_id = processor.get_user_id(request.user) # Construct SamlResponse messages try: name_id_formats = self.IDP.config.getattr( "name_id_format", "idp") or [NAMEID_FORMAT_UNSPECIFIED] name_id = NameID(format=name_id_formats[0], text=user_id) authn = AUTHN_BROKER.get_authn_by_accr(req_authn_context) sign_response = self.IDP.config.getattr("sign_response", "idp") or False sign_assertion = self.IDP.config.getattr("sign_assertion", "idp") or False authn_resp = self.IDP.create_authn_response( identity=identity, in_response_to=None, destination=destination, sp_entity_id=sp_entity_id, userid=user_id, name_id=name_id, authn=authn, sign_response=sign_response, sign_assertion=sign_assertion, **passed_data) except Exception as excp: # pylint: disable=broad-except return self.handle_error(request, exception=excp, status=500) # Return as html with self-submitting form. http_args = self.IDP.apply_binding( binding=binding_out, msg_str="%s" % authn_resp, destination=destination, relay_state=passed_data['RelayState'], response=True) return HttpResponse(http_args['data'])
def get(self, request, *args, **kwargs): # pylint: disable=missing-function-docstring, unused-argument, too-many-locals binding = request.session.get('Binding', BINDING_HTTP_POST) # Parse incoming request try: req_info = self.IDP.parse_authn_request( request.session['SAMLRequest'], binding) except Exception as excp: # pylint: disable=broad-except return self.handle_error(request, exception=excp) # Signed request for HTTP-REDIRECT if "SigAlg" in request.session and "Signature" in request.session: _certs = self.IDP.metadata.certs(req_info.message.issuer.text, "any", "signing") verified_ok = False for cert in _certs: # pylint: disable=unused-variable # TODO implement # if verify_redirect_signature(_info, self.IDP.sec.sec_backend, cert): # verified_ok = True # break pass if not verified_ok: return self.handle_error( request, extra_message="Message signature verification failure", status=400) # Gather response arguments try: resp_args = self.IDP.response_args(req_info.message) except (UnknownPrincipal, UnsupportedBinding) as excp: return self.handle_error(request, exception=excp, status=400) try: # sp_config = SAML_IDP_SPCONFIG[resp_args['sp_entity_id']] sp_config = { 'processor': 'djangosaml2idp.processors.BaseProcessor', 'attribute_mapping': { # DJANGO: SAML 'email': 'email', 'private_email': 'private_email', 'username': '******', 'is_staff': 'is_staff', 'is_superuser': '******', 'token': 'token', }, } except Exception: # pylint: disable=broad-except return self.handle_error( request, exception=ImproperlyConfigured( "No config for SP %s defined in SAML_IDP_SPCONFIG" % resp_args['sp_entity_id']), status=400) processor = self.get_processor(resp_args['sp_entity_id'], sp_config) # Check if user has access to the service of this SP if not processor.has_access(request): return self.handle_error( request, exception=PermissionDenied( "You do not have access to this resource"), status=403) cookie_user = self.cookie_user(request) identity = self.get_identity(processor, cookie_user, sp_config) req_authn_context = req_info.message.requested_authn_context or PASSWORD AUTHN_BROKER = AuthnBroker() # pylint: disable=invalid-name AUTHN_BROKER.add(authn_context_class_ref(req_authn_context), "") user_id = processor.get_user_id(cookie_user) # Construct SamlResponse message try: authn_resp = self.IDP.create_authn_response( identity=identity, userid=user_id, name_id=NameID(format=resp_args['name_id_policy'].format, sp_name_qualifier=resp_args['sp_entity_id'], text=user_id), authn=AUTHN_BROKER.get_authn_by_accr(req_authn_context), sign_response=self.IDP.config.getattr("sign_response", "idp") or False, sign_assertion=self.IDP.config.getattr("sign_assertion", "idp") or False, **resp_args) except Exception as excp: # pylint: disable=broad-except return self.handle_error(request, exception=excp, status=500) http_args = self.IDP.apply_binding( binding=resp_args['binding'], msg_str="%s" % authn_resp, destination=resp_args['destination'], relay_state=request.session['RelayState'], response=True) logger.debug('http args are: %s' % http_args) # pylint: disable=logging-not-lazy return self.render_response(request, processor, http_args)
def build_authn_response(self, user, authn, resp_args): """ pysaml2 server.Server.create_authn_response wrapper """ self.sp['name_id_format'] = resp_args.get('name_id_policy').format idp_name_id_format_list = self.IDP.config.getattr("name_id_format", "idp") # name_id format availability if idp_name_id_format_list and not self.sp['name_id_format']: name_id_format = idp_name_id_format_list[0] elif self.sp['name_id_format'] and not idp_name_id_format_list: name_id_format = self.sp['name_id_format'] elif self.sp['name_id_format'] not in idp_name_id_format_list: return self.handle_error(request, exception=_('SP requested a name_id_format ' 'that is not supported in the IDP')) elif self.sp['name_id_format'] in idp_name_id_format_list: name_id_format = self.sp['name_id_format'] else: name_id_format = NAMEID_FORMAT_UNSPECIFIED # if SP doesn't request a specific name_id_format... if not self.sp['name_id_format']: self.sp['name_id_format'] = name_id_format user_id = self.processor.get_user_id(user, self.sp, self.IDP.config) name_id = NameID(format=self.sp['name_id_format'], sp_name_qualifier=self.sp['id'], text=user_id) user_attrs = self.processor.create_identity(user, self.sp) # ASSERTION ENCRYPTED enrypt_response = getattr(settings, 'SAML_ENCRYPT_AUTHN_RESPONSE', False) if 'encrypt_saml_responses' in self.sp['config'].keys(): enrypt_response = self.sp['config'].get('encrypt_saml_responses') authn_resp = self.IDP.create_authn_response( authn=authn, identity=user_attrs, userid=user_id, name_id=name_id, # signature sign_response=self.sp['config'].get("sign_response") or \ self.IDP.config.getattr("sign_response", "idp") or \ False, sign_assertion=self.sp['config'].get("sign_assertion") or \ self.IDP.config.getattr("sign_assertion", "idp") or \ False, # default will be sha1 in pySAML2 sign_alg=self.sp['config'].get("signing_algorithm") or \ getattr(settings, 'SAML_AUTHN_SIGN_ALG', False), digest_alg=self.sp['config'].get("digest_algorithm") or \ getattr(settings, 'SAML_AUTHN_DIGEST_ALG', False), # Encryption encrypt_assertion=enrypt_response, encrypted_advice_attributes=enrypt_response, **resp_args ) return authn_resp
def get(self, request, *args, **kwargs): # pylint: disable=missing-function-docstring, unused-argument, too-many-locals resp_args = { 'in_response_to': self.IN_RESPONSE_TO, 'sp_entity_id': self.SP_ENTITY_ID, 'name_id_policy': saml.NAMEID_FORMAT_PERSISTENT, 'binding': BINDING_HTTP_POST, 'destination': self.DESTINATION, } sp_config = { 'processor': 'djangosaml2idp.processors.BaseProcessor', 'attribute_mapping': { 'username': '******', 'token': 'token', 'aliyun_sso_roles': self.CUSTOM_CONFIG['role'], 'uid': self.CUSTOM_CONFIG['role_session_name'], 'aliyun_sso_session_duration': self.CUSTOM_CONFIG['session_duration'], }, } processor = self.get_processor(resp_args['sp_entity_id'], sp_config) # Check if user has access to the service of this SP if not processor.has_access(request): return self.handle_error( request, exception=PermissionDenied( "You do not have access to this resource"), status=403) cookie_user = self.cookie_user(request) if not cookie_user.aliyun_sso_role.is_active: # 用户的角色SSO被禁用 return self.handle_error( request, exception=PermissionDenied("Your role SSO has been disabled"), status=403) identity = self.get_identity(processor, cookie_user, sp_config) # print('identity is', identity) AUTHN_BROKER = AuthnBroker() # pylint: disable=invalid-name AUTHN_BROKER.add(authn_context_class_ref(PASSWORD), "") user_id = processor.get_user_id(cookie_user) # Construct SamlResponse message try: app = SAMLAPP.valid_objects.get( entity_id=resp_args['sp_entity_id']) _spsso_descriptor = entity_descriptor_from_string( app.xmldata).spsso_descriptor.pop() # pylint: disable=no-member authn_resp = self.IDP.create_authn_response( identity=identity, userid=user_id, name_id=NameID(format=resp_args['name_id_policy'], sp_name_qualifier=resp_args['sp_entity_id'], text=user_id), authn=AUTHN_BROKER.get_authn_by_accr(PASSWORD), sign_response=getattr(_spsso_descriptor, 'want_response_signed', '') == 'true', sign_assertion=getattr(_spsso_descriptor, 'want_assertions_signed', '') == 'true', **resp_args) except Exception as excp: # pylint: disable=broad-except return self.handle_error(request, exception=excp, status=500) # print('authn_resp is', authn_resp) http_args = self.IDP.apply_binding( binding=resp_args['binding'], msg_str="%s" % authn_resp, destination=resp_args['destination'], response=True) return HttpResponse(http_args['data'])
def get(self, request, *args, **kwargs): # Parse incoming request try: req_info = self.IDP.parse_authn_request(request.session['SAMLRequest'], BINDING_HTTP_POST) except Exception as excp: return HttpResponseBadRequest(excp) # TODO this is taken from example, but no idea how this works or whats it does. Check SAML2 specification? # Signed request for HTTP-REDIRECT if "SigAlg" in request.session and "Signature" in request.session: _certs = self.IDP.metadata.certs(req_info.message.issuer.text, "any", "signing") verified_ok = False for cert in _certs: # TODO implement #if verify_redirect_signature(_info, self.IDP.sec.sec_backend, cert): # verified_ok = True # break pass if not verified_ok: return HttpResponseBadRequest("Message signature verification failure") binding_out, destination = self.IDP.pick_binding(service="assertion_consumer_service", entity_id=req_info.message.issuer.text) # Gather response arguments try: resp_args = self.IDP.response_args(req_info.message) except (UnknownPrincipal, UnsupportedBinding) as excp: return HttpResponseServerError(excp) try: sp_config = settings.SAML_IDP_SPCONFIG[resp_args['sp_entity_id']] except Exception: raise ImproperlyConfigured("No config for SP %s defined in SAML_IDP_SPCONFIG" % resp_args['sp_entity_id']) processor = self.get_processor(sp_config) # Check if user has access to the service of this SP if not processor.has_access(request.user): raise PermissionDenied("You do not have access to this resource") identity = self.get_identity(processor, request.user, sp_config) # TODO investigate how this works, because I don't get it. Specification? req_authn_context = req_info.message.requested_authn_context or PASSWORD AUTHN_BROKER = AuthnBroker() AUTHN_BROKER.add(authn_context_class_ref(req_authn_context), "") # Construct SamlResponse message try: authn_resp = self.IDP.create_authn_response( identity=identity, userid=request.user.username, name_id=NameID(format=resp_args['name_id_policy'].format, sp_name_qualifier=destination, text=request.user.username), authn=AUTHN_BROKER.get_authn_by_accr(req_authn_context), sign_response=self.IDP.config.getattr("sign_response", "idp") or False, sign_assertion=self.IDP.config.getattr("sign_assertion", "idp") or False, **resp_args) except Exception as excp: return HttpResponseServerError(excp) http_args = self.IDP.apply_binding( binding=binding_out, msg_str="%s" % authn_resp, destination=destination, relay_state=request.session['RelayState'], response=True) logger.debug('http args are: %s' % http_args) return self.render_response(request, processor, http_args)