Exemple #1
0
    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
Exemple #2
0
    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
    )
Exemple #4
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 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
Exemple #6
0
    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
Exemple #7
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)
Exemple #8
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'])
Exemple #9
0
    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)
Exemple #12
0
    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
Exemple #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'])
Exemple #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)