Exemplo n.º 1
0
    def redirect_to_auth(self, _cli, entity_id, came_from, sigalg=None):
        try:
            # Picks a binding to use for sending the Request to the IDP
            _binding, destination = _cli.pick_binding("single_sign_on_service",
                                                      self.bindings,
                                                      "idpsso",
                                                      entity_id=entity_id)
            logger.debug("binding: %s, destination: %s", _binding, destination)
            # Binding here is the response binding that is which binding the
            # IDP should use to return the response.
            acs = _cli.config.getattr("endpoints",
                                      "sp")["assertion_consumer_service"]
            # just pick one
            endp, return_binding = acs[0]
            logger.debug("Binding response to: {}, {}".format(
                return_binding, endp))

            extensions = None
            cert = None
            logger.debug("cli config: {}".format(dir(_cli.config)))
            if _cli.config.generate_cert_func is not None:
                cert_str, req_key_str = _cli.config.generate_cert_func()
                cert = {"cert": cert_str, "key": req_key_str}
                spcertenc = SPCertEnc(x509_data=ds.X509Data(
                    x509_certificate=ds.X509Certificate(text=cert_str)))
                extensions = Extensions(extension_elements=[
                    element_to_extension_element(spcertenc)
                ])

            req_id, req = _cli.create_authn_request(
                destination,
                binding=return_binding,
                extensions=extensions,
                nameid_format=NAMEID_FORMAT_PERSISTENT)
            _rstate = rndstr()
            self.cache.relay_state[_rstate] = came_from
            apply_binding_kwargs = dict(relay_state=_rstate)
            if sigalg:
                apply_binding_kwargs['sigalg'] = sigalg
            ht_args = _cli.apply_binding(_binding, "%s" % req, destination,
                                         **apply_binding_kwargs)
            _sid = req_id

            if cert is not None:
                self.cache.outstanding_certs[_sid] = cert

        except Exception as exc:
            logger.exception(exc)
            resp = ServiceError("Failed to construct the AuthnRequest: %s" %
                                exc)
            return resp

        # remember the request
        self.cache.outstanding_queries[_sid] = came_from
        return self.response(_binding, ht_args, do_not_start_response=True)
Exemplo n.º 2
0
def sp_initiated():
    saml_client = saml_client_for(
        current_app.config.get('SECURITY_SAML_IDP_METADATA').split(',')[0])

    faa = FAAALevel(
        text=str(current_app.config.get('SECURITY_SAML_FAAALEVEL')))

    spcertenc = RequestedAttributes([
        RequestedAttribute(
            name="http://interop.gov.pt/MDC/Cidadao/CorreioElectronico",
            name_format="urn:oasis:names:tc:SAML:2.0:attrname-format:uri",
            is_required='True'),
        RequestedAttribute(
            name="http://interop.gov.pt/MDC/Cidadao/NICCifrado",
            name_format="urn:oasis:names:tc:SAML:2.0:attrname-format:uri",
            is_required='False'),
        RequestedAttribute(
            name="http://interop.gov.pt/MDC/Cidadao/NomeProprio",
            name_format="urn:oasis:names:tc:SAML:2.0:attrname-format:uri",
            is_required='False'),
        RequestedAttribute(
            name="http://interop.gov.pt/MDC/Cidadao/NomeApelido",
            name_format="urn:oasis:names:tc:SAML:2.0:attrname-format:uri",
            is_required='False')
    ])

    extensions = Extensions(extension_elements=[
        element_to_extension_element(faa),
        element_to_extension_element(spcertenc)
    ])

    args = {
        'binding': BINDING_HTTP_POST,
        'relay_state': 'dWRhdGEtZ291dnB0',
        'sign': True,
        'force_authn': 'true',
        'is_passive': 'false',
        'nameid_format': '',
        'extensions': extensions
    }

    reqid, info = saml_client.prepare_for_authenticate(**args)
    response = info['data']
    return response
Exemplo n.º 3
0
def saml_logout():
    saml_client = saml_client_for(
        current_app.config.get('SECURITY_SAML_IDP_METADATA').split(',')[0])
    nid = NameID(format=NAMEID_FORMAT_UNSPECIFIED,
                 text="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified")

    logout_url = LogoutUrl(
        text=url_for("saml.saml_logout_postback", _external=True))
    destination = current_app.config.get('SECURITY_SAML_FA_URL')

    extensions = Extensions(extension_elements=[logout_url])

    req_id, logout_request = saml_client.create_logout_request(
        name_id=nid,
        destination=destination,
        issuer_entity_id=current_app.config.get('SECURITY_SAML_ENTITY_ID'),
        sign=True,
        consent="urn:oasis:names:tc:SAML:2.0:logout:user",
        extensions=extensions)

    post_message = http_form_post_message(message=logout_request,
                                          location=destination)
    return post_message['data']
Exemplo n.º 4
0
    def challenge(self, environ, _status, _app_headers, _forget_headers):
        _cli = self.saml_client

        if "REMOTE_USER" in environ:
            name_id = decode(environ["REMOTE_USER"])

            _cli = self.saml_client
            path_info = environ["PATH_INFO"]

            if "samlsp.logout" in environ:
                responses = _cli.global_logout(name_id)
                return self._handle_logout(responses)

        if "samlsp.pending" in environ:
            response = environ["samlsp.pending"]
            if isinstance(response, HTTPRedirection):
                response.headers += _forget_headers
            return response

        # logger = environ.get('repoze.who.logger','')

        # Which page was accessed to get here
        came_from = construct_came_from(environ)
        environ["myapp.came_from"] = came_from
        logger.debug("[sp.challenge] RelayState >> '%s'", came_from)

        # Am I part of a virtual organization or more than one ?
        try:
            vorg_name = environ["myapp.vo"]
        except KeyError:
            try:
                vorg_name = _cli.vorg._name
            except AttributeError:
                vorg_name = ""

        logger.info("[sp.challenge] VO: %s", vorg_name)

        # If more than one idp and if none is selected, I have to do wayf
        (done, response) = self._pick_idp(environ, came_from)
        # Three cases: -1 something went wrong or Discovery service used
        #               0 I've got an IdP to send a request to
        #               >0 ECP in progress
        logger.debug("_idp_pick returned: %s", done)
        if done == -1:
            return response
        elif done > 0:
            self.outstanding_queries[done] = came_from
            return ECP_response(response)
        else:
            entity_id = response
            logger.info("[sp.challenge] entity_id: %s", entity_id)
            # Do the AuthnRequest
            _binding = BINDING_HTTP_REDIRECT
            try:
                srvs = _cli.metadata.single_sign_on_service(
                    entity_id, _binding)
                logger.debug("srvs: %s", srvs)
                dest = srvs[0]["location"]
                logger.debug("destination: %s", dest)

                extensions = None
                cert = None

                if _cli.config.generate_cert_func is not None:
                    cert_str, req_key_str = _cli.config.generate_cert_func()
                    cert = {"cert": cert_str, "key": req_key_str}
                    spcertenc = SPCertEnc(x509_data=ds.X509Data(
                        x509_certificate=ds.X509Certificate(text=cert_str)))
                    extensions = Extensions(extension_elements=[
                        element_to_extension_element(spcertenc)
                    ])

                if _cli.authn_requests_signed:
                    _sid = sid()
                    req_id, msg_str = _cli.create_authn_request(
                        dest,
                        vorg=vorg_name,
                        sign=_cli.authn_requests_signed,
                        message_id=_sid,
                        extensions=extensions,
                    )
                    _sid = req_id
                else:
                    req_id, req = _cli.create_authn_request(
                        dest,
                        vorg=vorg_name,
                        sign=False,
                        extensions=extensions,
                    )
                    msg_str = "%s" % req
                    _sid = req_id

                if cert is not None:
                    self.outstanding_certs[_sid] = cert

                ht_args = _cli.apply_binding(
                    _binding,
                    msg_str,
                    destination=dest,
                    relay_state=came_from,
                    sign=_cli.authn_requests_signed,
                )

                logger.debug("ht_args: %s", ht_args)
            except Exception as exc:
                logger.exception(exc)
                raise Exception("Failed to construct the AuthnRequest: %s" %
                                exc)

            try:
                ret = _cli.config.getattr("endpoints",
                                          "sp")["discovery_response"][0][0]
                if (environ["PATH_INFO"]) in ret and ret.split(
                        environ["PATH_INFO"])[1] == "":
                    query = parse.parse_qs(environ["QUERY_STRING"])
                    sid = query["sid"][0]
                    came_from = self.outstanding_queries[sid]
            except:
                pass
            # remember the request
            self.outstanding_queries[_sid] = came_from

            if not ht_args["data"] and ht_args["headers"][0][0] == "Location":
                logger.debug("redirect to: %s", ht_args["headers"][0][1])
                return HTTPSeeOther(headers=ht_args["headers"])
            else:
                return ht_args["data"]
Exemplo n.º 5
0
    def create_authn_request(self,
                             destination,
                             vorg="",
                             scoping=None,
                             binding=saml2.BINDING_HTTP_POST,
                             nameid_format=None,
                             service_url_binding=None,
                             message_id=0,
                             consent=None,
                             extensions=None,
                             sign=None,
                             allow_create=None,
                             sign_prepare=False,
                             sign_alg=None,
                             digest_alg=None,
                             **kwargs):
        """ Creates an authentication request.

        :param destination: Where the request should be sent.
        :param vorg: The virtual organization the service belongs to.
        :param scoping: The scope of the request
        :param binding: The protocol to use for the Response !!
        :param nameid_format: Format of the NameID
        :param service_url_binding: Where the reply should be sent dependent
            on reply binding.
        :param message_id: The identifier for this request
        :param consent: Whether the principal have given her consent
        :param extensions: Possible extensions
        :param sign: Whether the request should be signed or not.
        :param sign_prepare: Whether the signature should be prepared or not.
        :param allow_create: If the identity provider is allowed, in the course
            of fulfilling the request, to create a new identifier to represent
            the principal.
        :param kwargs: Extra key word arguments
        :return: tuple of request ID and <samlp:AuthnRequest> instance
        """
        client_crt = None
        if "client_crt" in kwargs:
            client_crt = kwargs["client_crt"]

        args = {}

        if self.config.getattr('hide_assertion_consumer_service', 'sp'):
            args["assertion_consumer_service_url"] = None
            binding = None
        else:
            try:
                args["assertion_consumer_service_url"] = kwargs[
                    "assertion_consumer_service_urls"][0]
                del kwargs["assertion_consumer_service_urls"]
            except KeyError:
                try:
                    args["assertion_consumer_service_url"] = kwargs[
                        "assertion_consumer_service_url"]
                    del kwargs["assertion_consumer_service_url"]
                except KeyError:
                    try:
                        args["assertion_consumer_service_index"] = str(
                            kwargs["assertion_consumer_service_index"])
                        del kwargs["assertion_consumer_service_index"]
                    except KeyError:
                        if service_url_binding is None:
                            service_urls = self.service_urls(binding)
                        else:
                            service_urls = self.service_urls(
                                service_url_binding)
                        args["assertion_consumer_service_url"] = service_urls[
                            0]

        try:
            args["provider_name"] = kwargs["provider_name"]
        except KeyError:
            if binding == BINDING_PAOS:
                pass
            else:
                args["provider_name"] = self._my_name()

        # Allow argument values either as class instances or as dictionaries
        # all of these have cardinality 0..1
        _msg = AuthnRequest()
        for param in [
                "scoping", "requested_authn_context", "conditions", "subject"
        ]:
            try:
                _item = kwargs[param]
            except KeyError:
                pass
            else:
                del kwargs[param]
                # either class instance or argument dictionary
                if isinstance(_item, _msg.child_class(param)):
                    args[param] = _item
                elif isinstance(_item, dict):
                    args[param] = RequestedAuthnContext(**_item)
                else:
                    raise ValueError("%s or wrong type expected %s" %
                                     (_item, param))

        try:
            args["name_id_policy"] = kwargs["name_id_policy"]
            del kwargs["name_id_policy"]
        except KeyError:
            if allow_create is None:
                allow_create = self.config.getattr(
                    "name_id_format_allow_create", "sp")
                if allow_create is None:
                    allow_create = "false"
                else:
                    if allow_create is True:
                        allow_create = "true"
                    else:
                        allow_create = "false"

            if nameid_format == "":
                name_id_policy = None
            else:
                if nameid_format is None:
                    nameid_format = self.config.getattr("name_id_format", "sp")

                    # If no nameid_format has been set in the configuration
                    # or passed in then transient is the default.
                    if nameid_format is None:
                        nameid_format = NAMEID_FORMAT_TRANSIENT

                    # If a list has been configured or passed in choose the
                    # first since NameIDPolicy can only have one format specified.
                    elif isinstance(nameid_format, list):
                        nameid_format = nameid_format[0]

                    # Allow a deployer to signal that no format should be specified
                    # in the NameIDPolicy by passing in or configuring the string 'None'.
                    elif nameid_format == 'None':
                        nameid_format = None

                name_id_policy = samlp.NameIDPolicy(allow_create=allow_create,
                                                    format=nameid_format)

            if name_id_policy and vorg:
                try:
                    name_id_policy.sp_name_qualifier = vorg
                    name_id_policy.format = saml.NAMEID_FORMAT_PERSISTENT
                except KeyError:
                    pass
            args["name_id_policy"] = name_id_policy

        try:
            nsprefix = kwargs["nsprefix"]
        except KeyError:
            nsprefix = None

        try:
            force_authn = kwargs['force_authn']
        except KeyError:
            force_authn = self.config.getattr('force_authn', 'sp')
        finally:
            if force_authn:
                args['force_authn'] = 'true'

        conf_sp_type = self.config.getattr('sp_type', 'sp')
        conf_sp_type_in_md = self.config.getattr('sp_type_in_metadata', 'sp')
        if conf_sp_type and conf_sp_type_in_md is False:
            if not extensions:
                extensions = Extensions()
            item = sp_type.SPType(text=conf_sp_type)
            extensions.add_extension_element(item)

        requested_attrs = self.config.getattr('requested_attributes', 'sp')
        if requested_attrs:
            if not extensions:
                extensions = Extensions()

            attributemapsmods = []
            for modname in attributemaps.__all__:
                attributemapsmods.append(getattr(attributemaps, modname))

            items = []
            for attr in requested_attrs:
                friendly_name = attr.get('friendly_name')
                name = attr.get('name')
                name_format = attr.get('name_format')
                is_required = str(attr.get('required', False)).lower()

                if not name and not friendly_name:
                    raise ValueError(
                        "Missing required attribute: '{}' or '{}'".format(
                            'name', 'friendly_name'))

                if not name:
                    for mod in attributemapsmods:
                        try:
                            name = mod.MAP['to'][friendly_name]
                        except KeyError:
                            continue
                        else:
                            if not name_format:
                                name_format = mod.MAP['identifier']
                            break

                if not friendly_name:
                    for mod in attributemapsmods:
                        try:
                            friendly_name = mod.MAP['fro'][name]
                        except KeyError:
                            continue
                        else:
                            if not name_format:
                                name_format = mod.MAP['identifier']
                            break

                items.append(
                    requested_attributes.RequestedAttribute(
                        is_required=is_required,
                        name_format=name_format,
                        friendly_name=friendly_name,
                        name=name))

            item = requested_attributes.RequestedAttributes(
                extension_elements=items)
            extensions.add_extension_element(item)

        if kwargs:
            _args, extensions = self._filter_args(AuthnRequest(), extensions,
                                                  **kwargs)
            args.update(_args)

        try:
            del args["id"]
        except KeyError:
            pass

        if sign is None:
            sign = self.authn_requests_signed

        if (sign and self.sec.cert_handler.generate_cert()) or \
                        client_crt is not None:
            with self.lock:
                self.sec.cert_handler.update_cert(True, client_crt)
                if client_crt is not None:
                    sign_prepare = True
                return self._message(AuthnRequest,
                                     destination,
                                     message_id,
                                     consent,
                                     extensions,
                                     sign,
                                     sign_prepare,
                                     protocol_binding=binding,
                                     scoping=scoping,
                                     nsprefix=nsprefix,
                                     sign_alg=sign_alg,
                                     digest_alg=digest_alg,
                                     **args)
        return self._message(AuthnRequest,
                             destination,
                             message_id,
                             consent,
                             extensions,
                             sign,
                             sign_prepare,
                             protocol_binding=binding,
                             scoping=scoping,
                             nsprefix=nsprefix,
                             sign_alg=sign_alg,
                             digest_alg=digest_alg,
                             **args)
Exemplo n.º 6
0
    def create_authn_request(self,
                             destination,
                             vorg="",
                             scoping=None,
                             binding=saml2.BINDING_HTTP_POST,
                             nameid_format=None,
                             service_url_binding=None,
                             message_id=0,
                             consent=None,
                             extensions=None,
                             sign=None,
                             allow_create=None,
                             sign_prepare=False,
                             sign_alg=None,
                             digest_alg=None,
                             requested_attributes=None,
                             **kwargs):
        """ Creates an authentication request.

        :param destination: Where the request should be sent.
        :param vorg: The virtual organization the service belongs to.
        :param scoping: The scope of the request
        :param binding: The protocol to use for the Response !!
        :param nameid_format: Format of the NameIDPolicy
        :param service_url_binding: Where the reply should be sent dependent
            on reply binding.
        :param message_id: The identifier for this request
        :param consent: Whether the principal have given her consent
        :param extensions: Possible extensions
        :param sign: Whether the request should be signed or not.
        :param sign_prepare: Whether the signature should be prepared or not.
        :param allow_create: If the identity provider is allowed, in the course
            of fulfilling the request, to create a new identifier to represent
            the principal.
        :param requested_attributes: A list of dicts which define attributes to
            be used as eIDAS Requested Attributes for this request. If not
            defined the configuration option requested_attributes will be used,
            if defined. The format is the same as the requested_attributes
            configuration option.
        :param kwargs: Extra key word arguments
        :return: either a tuple of request ID and <samlp:AuthnRequest> instance
                 or a tuple of request ID and str when sign is set to True
        """
        args = {}

        # AssertionConsumerServiceURL
        # AssertionConsumerServiceIndex
        hide_assertion_consumer_service = self.config.getattr(
            'hide_assertion_consumer_service', 'sp')
        assertion_consumer_service_url = (
            kwargs.pop("assertion_consumer_service_urls", [None])[0]
            or kwargs.pop("assertion_consumer_service_url", None))
        assertion_consumer_service_index = kwargs.pop(
            "assertion_consumer_service_index", None)
        service_url = (self.service_urls(service_url_binding or binding)
                       or [None])[0]
        if hide_assertion_consumer_service:
            args["assertion_consumer_service_url"] = None
            binding = None
        elif assertion_consumer_service_url:
            args[
                "assertion_consumer_service_url"] = assertion_consumer_service_url
        elif assertion_consumer_service_index:
            args[
                "assertion_consumer_service_index"] = assertion_consumer_service_index
        elif service_url:
            args["assertion_consumer_service_url"] = service_url

        # ProviderName
        provider_name = kwargs.get("provider_name")
        if not provider_name and binding != BINDING_PAOS:
            provider_name = self._my_name()
        args["provider_name"] = provider_name

        # Allow argument values either as class instances or as dictionaries
        # all of these have cardinality 0..1
        _msg = AuthnRequest()
        for param in [
                "scoping", "requested_authn_context", "conditions", "subject"
        ]:
            _item = kwargs.pop(param, None)
            if not _item:
                continue

            if isinstance(_item, _msg.child_class(param)):
                args[param] = _item
            elif isinstance(_item, dict):
                args[param] = RequestedAuthnContext(**_item)
            else:
                raise ValueError(
                    "Wrong type for param {name}".format(name=param))

        # NameIDPolicy
        nameid_policy_format_config = self.config.getattr(
            "name_id_policy_format", "sp")
        nameid_policy_format = (nameid_format or nameid_policy_format_config
                                or None)

        allow_create_config = self.config.getattr(
            "name_id_format_allow_create", "sp")
        allow_create = (
            None
            # SAML 2.0 errata says AllowCreate MUST NOT be used for transient ids
            if nameid_policy_format == NAMEID_FORMAT_TRANSIENT
            else allow_create if allow_create else str(
                bool(allow_create_config)).lower())

        name_id_policy = (
            kwargs.pop("name_id_policy", None) if "name_id_policy" in kwargs
            else None if not nameid_policy_format else samlp.NameIDPolicy(
                allow_create=allow_create, format=nameid_policy_format))

        if name_id_policy and vorg:
            name_id_policy.sp_name_qualifier = vorg
            name_id_policy.format = nameid_policy_format or NAMEID_FORMAT_PERSISTENT

        args["name_id_policy"] = name_id_policy

        # eIDAS SPType
        conf_sp_type = self.config.getattr('sp_type', 'sp')
        conf_sp_type_in_md = self.config.getattr('sp_type_in_metadata', 'sp')
        if conf_sp_type and conf_sp_type_in_md is False:
            if not extensions:
                extensions = Extensions()
            item = sp_type.SPType(text=conf_sp_type)
            extensions.add_extension_element(item)

        # eIDAS RequestedAttributes
        requested_attrs = (requested_attributes
                           or self.config.getattr('requested_attributes', 'sp')
                           or [])
        if requested_attrs:
            req_attrs_node = create_requested_attribute_node(
                requested_attrs, self.config.attribute_converters)
            if not extensions:
                extensions = Extensions()
            extensions.add_extension_element(req_attrs_node)

        # ForceAuthn
        force_authn = str(
            kwargs.pop("force_authn", None)
            or self.config.getattr("force_authn", "sp")).lower() in [
                "true", "1"
            ]
        if force_authn:
            kwargs["force_authn"] = "true"

        if kwargs:
            _args, extensions = self._filter_args(AuthnRequest(), extensions,
                                                  **kwargs)
            args.update(_args)
        args.pop("id", None)

        client_crt = kwargs.get("client_crt")
        nsprefix = kwargs.get("nsprefix")
        sign = self.authn_requests_signed if sign is None else sign

        if (sign and self.sec.cert_handler.generate_cert()
            ) or client_crt is not None:
            with self.lock:
                self.sec.cert_handler.update_cert(True, client_crt)
                if client_crt is not None:
                    sign_prepare = True
                msg = self._message(
                    AuthnRequest,
                    destination,
                    message_id,
                    consent,
                    extensions,
                    sign,
                    sign_prepare,
                    protocol_binding=binding,
                    scoping=scoping,
                    nsprefix=nsprefix,
                    sign_alg=sign_alg,
                    digest_alg=digest_alg,
                    **args,
                )
        else:
            msg = self._message(
                AuthnRequest,
                destination,
                message_id,
                consent,
                extensions,
                sign,
                sign_prepare,
                protocol_binding=binding,
                scoping=scoping,
                nsprefix=nsprefix,
                sign_alg=sign_alg,
                digest_alg=digest_alg,
                **args,
            )

        return msg
Exemplo n.º 7
0
from saml2.sigver import read_cert_from_file
from pathutils import full_path

__author__ = 'roland'

conf = config.SPConfig()
conf.load_file("server_conf")
client = Saml2Client(conf)

# place a certificate in an authn request
cert = read_cert_from_file(full_path("test.pem"), "pem")

spcertenc = SPCertEnc(x509_data=ds.X509Data(
    x509_certificate=ds.X509Certificate(text=cert)))

extensions = Extensions(
    extension_elements=[element_to_extension_element(spcertenc)])

req_id, req = client.create_authn_request(
    "http://www.example.com/sso",
    "urn:mace:example.com:it:tek",
    nameid_format=saml.NAMEID_FORMAT_PERSISTENT,
    message_id="666",
    extensions=extensions)

print req

# Get a certificate from an authn request

xml = "%s" % req

parsed = authn_request_from_string(xml)
Exemplo n.º 8
0
    def create_authn_request(self, destination, vorg="", scoping=None,
            binding=saml2.BINDING_HTTP_POST,
            nameid_format=None,
            service_url_binding=None, message_id=0,
            consent=None, extensions=None, sign=None,
            allow_create=None, sign_prepare=False, sign_alg=None,
            digest_alg=None, **kwargs):
        """ Creates an authentication request.

        :param destination: Where the request should be sent.
        :param vorg: The virtual organization the service belongs to.
        :param scoping: The scope of the request
        :param binding: The protocol to use for the Response !!
        :param nameid_format: Format of the NameID
        :param service_url_binding: Where the reply should be sent dependent
            on reply binding.
        :param message_id: The identifier for this request
        :param consent: Whether the principal have given her consent
        :param extensions: Possible extensions
        :param sign: Whether the request should be signed or not.
        :param sign_prepare: Whether the signature should be prepared or not.
        :param allow_create: If the identity provider is allowed, in the course
            of fulfilling the request, to create a new identifier to represent
            the principal.
        :param kwargs: Extra key word arguments
        :return: either a tuple of request ID and <samlp:AuthnRequest> instance
                 or a tuple of request ID and str when sign is set to True
        """
        client_crt = None
        if "client_crt" in kwargs:
            client_crt = kwargs["client_crt"]

        args = {}

        if self.config.getattr('hide_assertion_consumer_service', 'sp'):
            args["assertion_consumer_service_url"] = None
            binding = None
        else:
            try:
                args["assertion_consumer_service_url"] = kwargs[
                    "assertion_consumer_service_urls"][0]
                del kwargs["assertion_consumer_service_urls"]
            except KeyError:
                try:
                    args["assertion_consumer_service_url"] = kwargs[
                        "assertion_consumer_service_url"]
                    del kwargs["assertion_consumer_service_url"]
                except KeyError:
                    try:
                        args["assertion_consumer_service_index"] = str(
                            kwargs["assertion_consumer_service_index"])
                        del kwargs["assertion_consumer_service_index"]
                    except KeyError:
                        if service_url_binding is None:
                            service_urls = self.service_urls(binding)
                        else:
                            service_urls = self.service_urls(service_url_binding)
                        args["assertion_consumer_service_url"] = service_urls[0]

        try:
            args["provider_name"] = kwargs["provider_name"]
        except KeyError:
            if binding == BINDING_PAOS:
                pass
            else:
                args["provider_name"] = self._my_name()

        # Allow argument values either as class instances or as dictionaries
        # all of these have cardinality 0..1
        _msg = AuthnRequest()
        for param in ["scoping", "requested_authn_context", "conditions",
                      "subject"]:
            try:
                _item = kwargs[param]
            except KeyError:
                pass
            else:
                del kwargs[param]
                # either class instance or argument dictionary
                if isinstance(_item, _msg.child_class(param)):
                    args[param] = _item
                elif isinstance(_item, dict):
                    args[param] = RequestedAuthnContext(**_item)
                else:
                    raise ValueError("%s or wrong type expected %s" % (_item,
                                                                       param))

        try:
            args["name_id_policy"] = kwargs["name_id_policy"]
            del kwargs["name_id_policy"]
        except KeyError:
            if allow_create is None:
                allow_create = self.config.getattr("name_id_format_allow_create", "sp")
                if allow_create is None:
                    allow_create = "false"
                else:
                    if allow_create is True:
                        allow_create = "true"
                    else:
                        allow_create = "false"

            if nameid_format == "":
                name_id_policy = None
            else:
                if nameid_format is None:
                    nameid_format = self.config.getattr("name_id_format", "sp")

                    # If no nameid_format has been set in the configuration
                    # or passed in then transient is the default.
                    if nameid_format is None:
                        nameid_format = NAMEID_FORMAT_TRANSIENT

                    # If a list has been configured or passed in choose the
                    # first since NameIDPolicy can only have one format specified.
                    elif isinstance(nameid_format, list):
                        nameid_format = nameid_format[0]

                    # Allow a deployer to signal that no format should be specified
                    # in the NameIDPolicy by passing in or configuring the string 'None'.
                    elif nameid_format == 'None':
                        nameid_format = None

                name_id_policy = samlp.NameIDPolicy(allow_create=allow_create,
                                                    format=nameid_format)

            if name_id_policy and vorg:
                try:
                    name_id_policy.sp_name_qualifier = vorg
                    name_id_policy.format = saml.NAMEID_FORMAT_PERSISTENT
                except KeyError:
                    pass
            args["name_id_policy"] = name_id_policy

        try:
            nsprefix = kwargs["nsprefix"]
        except KeyError:
            nsprefix = None

        try:
            force_authn = kwargs['force_authn']
        except KeyError:
            force_authn = self.config.getattr('force_authn', 'sp')
        finally:
            if force_authn:
                args['force_authn'] = 'true'

        conf_sp_type = self.config.getattr('sp_type', 'sp')
        conf_sp_type_in_md = self.config.getattr('sp_type_in_metadata', 'sp')
        if conf_sp_type and conf_sp_type_in_md is False:
            if not extensions:
                extensions = Extensions()
            item = sp_type.SPType(text=conf_sp_type)
            extensions.add_extension_element(item)

        requested_attrs = self.config.getattr('requested_attributes', 'sp')
        if requested_attrs:
            if not extensions:
                extensions = Extensions()

            attributemapsmods = []
            for modname in attributemaps.__all__:
                attributemapsmods.append(getattr(attributemaps, modname))

            items = []
            for attr in requested_attrs:
                friendly_name = attr.get('friendly_name')
                name = attr.get('name')
                name_format = attr.get('name_format')
                is_required = str(attr.get('required', False)).lower()

                if not name and not friendly_name:
                    raise ValueError(
                        "Missing required attribute: '{}' or '{}'".format(
                            'name', 'friendly_name'))

                if not name:
                    for mod in attributemapsmods:
                        try:
                            name = mod.MAP['to'][friendly_name]
                        except KeyError:
                            continue
                        else:
                            if not name_format:
                                name_format = mod.MAP['identifier']
                            break

                if not friendly_name:
                    for mod in attributemapsmods:
                        try:
                            friendly_name = mod.MAP['fro'][name]
                        except KeyError:
                            continue
                        else:
                            if not name_format:
                                name_format = mod.MAP['identifier']
                            break

                items.append(requested_attributes.RequestedAttribute(
                    is_required=is_required,
                    name_format=name_format,
                    friendly_name=friendly_name,
                    name=name))

            item = requested_attributes.RequestedAttributes(
                extension_elements=items)
            extensions.add_extension_element(item)

        if kwargs:
            _args, extensions = self._filter_args(AuthnRequest(), extensions,
                                                  **kwargs)
            args.update(_args)

        try:
            del args["id"]
        except KeyError:
            pass

        if sign is None:
            sign = self.authn_requests_signed

        if (sign and self.sec.cert_handler.generate_cert()) or \
                        client_crt is not None:
            with self.lock:
                self.sec.cert_handler.update_cert(True, client_crt)
                if client_crt is not None:
                    sign_prepare = True
                return self._message(AuthnRequest, destination, message_id,
                                     consent, extensions, sign, sign_prepare,
                                     protocol_binding=binding,
                                     scoping=scoping, nsprefix=nsprefix,
                                     sign_alg=sign_alg, digest_alg=digest_alg,
                                     **args)
        return self._message(AuthnRequest, destination, message_id, consent,
                             extensions, sign, sign_prepare,
                             protocol_binding=binding,
                             scoping=scoping, nsprefix=nsprefix,
                             sign_alg=sign_alg, digest_alg=digest_alg, **args)