Beispiel #1
0
    def handle_authn_request(self, saml_request, relay_state, binding, userid):

        self.authn_req = self.idp.parse_authn_request(saml_request, binding)
        _encrypt_cert = encrypt_cert_from_item(self.authn_req.message)

        self.binding_out, self.destination = self.idp.pick_binding(
                                                                    "assertion_consumer_service",
                                                                    bindings=None,
                                                                    entity_id=self.authn_req.message.issuer.text,
                                                                    request=self.authn_req.message)
        resp_args = self.idp.response_args(self.authn_req.message)
        AUTHN_BROKER = AuthnBroker()
        AUTHN_BROKER.add(authn_context_class_ref(PASSWORD),
                         username_password_authn_dummy,
                         10,
                         "http://test.idp.se")
        AUTHN_BROKER.get_authn_by_accr(PASSWORD)
        resp_args["authn"] = AUTHN_BROKER.get_authn_by_accr(PASSWORD)
        _resp = self.idp.create_authn_response(TestIdP.USERS[userid],
                                               userid=userid,
                                               encrypt_cert=_encrypt_cert,
                                               encrypt_assertion_self_contained=True,
                                               encrypted_advice_attributes=True,
                                               **resp_args)
        kwargs = {}
        http_args = self.idp.apply_binding(BINDING_HTTP_POST,
                                           "%s" % _resp,
                                           self.destination,
                                           relay_state,
                                           response=True,
                                           **kwargs)
        action, body = get_post_action_body(http_args["data"][3])
        return action, urllib.urlencode(body)
Beispiel #2
0
    def outgoing(self, response, org_response, instance):
        """
        An authentication response has been received and now an authentication
        response from this server should be constructed.

        :param response: The Authentication response
        :param instance: SP instance that received the authentication response
        :return: response
        """

        _idp = self.create_SamlIDP(instance.environ, instance.start_response, self.outgoing)

        _state = instance.sp.state[response.in_response_to]
        orig_authn_req, relay_state, req_args = instance.sp.state[_state]

        # The Subject NameID
        try:
            subject = response.get_subject()
        except:
            pass

        resp_args = _idp.idp.response_args(orig_authn_req)


        try:
            _authn_info = response.authn_info()[0]
            AUTHN_BROKER = AuthnBroker()
            AUTHN_BROKER.add(authn_context_class_ref(_authn_info[0]), username_password_authn_dummy, 0, self.issuer)
            _authn = AUTHN_BROKER.get_authn_by_accr(_authn_info[0])
            #_authn = {"class_ref": _authn_info[0], "authn_auth": self.issuer}
        except:
            AUTHN_BROKER = AuthnBroker()
            AUTHN_BROKER.add(authn_context_class_ref(UNSPECIFIED), username_password_authn_dummy, 0, self.issuer)
            _authn = AUTHN_BROKER.get_authn_by_accr(UNSPECIFIED)

        identity = response.ava

        if identity is None and response.response.encrypted_assertion is not None:
            #Add dummy value
            identity = {"uid": "dummyuser"}

        # Will signed the response by default
        resp = _idp.construct_authn_response(identity, userid="dummyuser",
                                             authn=_authn, name_id=None, resp_args=resp_args,
                                             relay_state=relay_state, sign_response=True,
                                             org_resp=response, org_xml_response=org_response)

        return resp
Beispiel #3
0
 def get_authn(self, req_info=None):
     if req_info:
         req_authn_context = req_info.message.requested_authn_context
     else:
          req_authn_context = PASSWORD
     broker = AuthnBroker()
     broker.add(authn_context_class_ref(req_authn_context), "")
     return broker.get_authn_by_accr(req_authn_context)
Beispiel #4
0
    def handle_auth_req(self, saml_request, relay_state, binding, userid,
                        response_binding=BINDING_HTTP_POST):
        """
        Handles a SAML request, validates and creates a SAML response.
        :type saml_request: str
        :type relay_state: str
        :type binding: str
        :type userid: str
        :rtype:

        :param saml_request:
        :param relay_state: RelayState is a parameter used by some SAML protocol implementations to
        identify the specific resource at the resource provider in an IDP initiated single sign on
        scenario.
        :param binding:
        :param userid: The user identification.
        :return: A tuple with
        """
        auth_req = self.parse_authn_request(saml_request, binding)
        binding_out, destination = self.pick_binding(
            'assertion_consumer_service',
            bindings=[response_binding],
            entity_id=auth_req.message.issuer.text, request=auth_req.message)

        resp_args = self.response_args(auth_req.message)
        authn_broker = AuthnBroker()
        authn_broker.add(authn_context_class_ref(PASSWORD), lambda: None, 10,
                         'unittest_idp.xml')
        authn_broker.get_authn_by_accr(PASSWORD)
        resp_args['authn'] = authn_broker.get_authn_by_accr(PASSWORD)

        _resp = self.create_authn_response(self.user_db[userid],
                                           userid=userid,
                                           **resp_args)

        if response_binding == BINDING_HTTP_POST:
            saml_response = base64.b64encode(str(_resp).encode("utf-8"))
            resp = {"SAMLResponse": saml_response, "RelayState": relay_state}
        elif response_binding == BINDING_HTTP_REDIRECT:
            http_args = self.apply_binding(response_binding, '%s' % _resp,
                                           destination, relay_state, response=True)
            resp = dict(parse_qsl(urlparse(dict(http_args["headers"])["Location"]).query))

        return destination, resp
Beispiel #5
0
    def __create_authn_response(self,
                                saml_request,
                                relay_state,
                                binding,
                                userid,
                                response_binding=BINDING_HTTP_POST):
        """
        Handles a SAML request, validates and creates a SAML response but
        does not apply the binding to encode it.
        :type saml_request: str
        :type relay_state: str
        :type binding: str
        :type userid: str
        :rtype: tuple [string, saml2.samlp.Response]

        :param saml_request:
        :param relay_state: RelayState is a parameter used by some SAML
        protocol implementations to identify the specific resource at the
        resource provider in an IDP initiated single sign on scenario.
        :param binding:
        :param userid: The user identification.
        :return: A tuple containing the destination and instance of
        saml2.samlp.Response
        """
        auth_req = self.parse_authn_request(saml_request, binding)
        binding_out, destination = self.pick_binding(
            'assertion_consumer_service',
            bindings=[response_binding],
            entity_id=auth_req.message.issuer.text,
            request=auth_req.message)

        resp_args = self.response_args(auth_req.message)
        authn_broker = AuthnBroker()
        authn_broker.add(authn_context_class_ref(PASSWORD), lambda: None, 10,
                         'unittest_idp.xml')
        authn_broker.get_authn_by_accr(PASSWORD)
        resp_args['authn'] = authn_broker.get_authn_by_accr(PASSWORD)

        resp = self.create_authn_response(self.user_db[userid],
                                          userid=userid,
                                          **resp_args)

        return destination, resp
Beispiel #6
0
    def __create_authn_response(self, saml_request, relay_state, binding,
                                userid, response_binding=BINDING_HTTP_POST):
        """
        Handles a SAML request, validates and creates a SAML response but
        does not apply the binding to encode it.
        :type saml_request: str
        :type relay_state: str
        :type binding: str
        :type userid: str
        :rtype: tuple [string, saml2.samlp.Response]

        :param saml_request:
        :param relay_state: RelayState is a parameter used by some SAML
        protocol implementations to identify the specific resource at the
        resource provider in an IDP initiated single sign on scenario.
        :param binding:
        :param userid: The user identification.
        :return: A tuple containing the destination and instance of
        saml2.samlp.Response
        """
        auth_req = self.parse_authn_request(saml_request, binding)
        binding_out, destination = self.pick_binding(
            'assertion_consumer_service',
            bindings=[response_binding],
            entity_id=auth_req.message.issuer.text, request=auth_req.message)

        resp_args = self.response_args(auth_req.message)
        authn_broker = AuthnBroker()
        authn_broker.add(authn_context_class_ref(PASSWORD), lambda: None, 10,
                         'unittest_idp.xml')
        authn_broker.get_authn_by_accr(PASSWORD)
        resp_args['authn'] = authn_broker.get_authn_by_accr(PASSWORD)

        resp = self.create_authn_response(self.user_db[userid],
                                          userid=userid,
                                          **resp_args)

        return destination, resp
Beispiel #7
0
    def handle_auth_req(self, saml_request, relay_state, binding, userid):
        auth_req = self.parse_authn_request(saml_request, binding)
        binding_out, destination = self.pick_binding(
            'assertion_consumer_service',
            entity_id=auth_req.message.issuer.text, request=auth_req.message)

        resp_args = self.response_args(auth_req.message)
        authn_broker = AuthnBroker()
        authn_broker.add(authn_context_class_ref(PASSWORD), lambda: None, 10,
                         'unittest_idp.xml')
        authn_broker.get_authn_by_accr(PASSWORD)
        resp_args['authn'] = authn_broker.get_authn_by_accr(PASSWORD)

        _resp = self.create_authn_response(self.user_db[userid],
                                           userid=userid,
                                           **resp_args)

        http_args = self.apply_binding(BINDING_HTTP_POST, '%s' % _resp,
                                       destination, relay_state, response=True)
        url = http_args['url']
        saml_response = base64.b64encode(str(_resp).encode("utf-8"))
        resp = {'SAMLResponse': saml_response, 'RelayState': relay_state}
        return url, resp
Beispiel #8
0
    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 excp:
            return self.handle_error(request, exception=excp, status=400)

        try:
            sp_config = settings.SAML_IDP_SPCONFIG[sp_entity_id]
        except Exception:
            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()
        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:
            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'])
Beispiel #9
0
    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)
Beispiel #10
0
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'])
Beispiel #11
0
    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'])
Beispiel #12
0
    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)
Beispiel #13
0
 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'])
Beispiel #14
0
    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)