Esempio n. 1
0
def create_authn_request(relay_state, selected_idp, required_loa, force_authn=False):

    kwargs = {
        "force_authn": str(force_authn).lower(),
    }

    # LOA
    current_app.logger.debug('Requesting AuthnContext {}'.format(required_loa))
    loa_uri = current_app.config.authentication_context_map[required_loa]
    requested_authn_context = RequestedAuthnContext(
        authn_context_class_ref=AuthnContextClassRef(text=loa_uri), comparison='exact'
    )
    kwargs['requested_authn_context'] = requested_authn_context

    # Authn algorithms
    kwargs['sign_alg'] = current_app.config.authn_sign_alg
    kwargs['digest_alg'] = current_app.config.authn_digest_alg

    client = Saml2Client(current_app.saml2_config)
    try:
        session_id, info = client.prepare_for_authenticate(
            entityid=selected_idp, relay_state=relay_state, binding=BINDING_HTTP_REDIRECT, **kwargs
        )
    except TypeError:
        current_app.logger.error('Unable to know which IdP to use')
        raise

    oq_cache = OutstandingQueriesCache(session)
    oq_cache.set(session_id, relay_state)
    return info
Esempio n. 2
0
def requested_authn_context(class_ref, comparison="minimum"):
    if not isinstance(class_ref, list):
        class_ref = [class_ref]
    return RequestedAuthnContext(authn_context_class_ref=[
        AuthnContextClassRef(text=i) for i in class_ref
    ],
                                 comparison=comparison)
Esempio n. 3
0
def get_authn_request(config, session, came_from, selected_idp,
                      required_loa=None, force_authn=False):
    # Request the right AuthnContext for workmode
    # (AL1 for 'personal', AL2 for 'helpdesk' and AL3 for 'admin' by default)
    if required_loa is None:
        required_loa = config.get('required_loa', {})
        workmode = config.get('workmode', 'personal')
        required_loa = required_loa.get(workmode, '')
    logger.debug('Requesting AuthnContext {!r}'.format(required_loa))
    kwargs = {
        "requested_authn_context": RequestedAuthnContext(
            authn_context_class_ref=AuthnContextClassRef(
                text=required_loa
            )
        ),
        "force_authn": str(force_authn).lower(),
    }

    client = Saml2Client(get_saml2_config(config['SAML2_SETTINGS_MODULE']))
    try:
        (session_id, info) = client.prepare_for_authenticate(
            entityid=selected_idp,
            relay_state=came_from,
            binding=BINDING_HTTP_REDIRECT,
            **kwargs
        )
    except TypeError:
        logger.error('Unable to know which IdP to use')
        raise

    oq_cache = OutstandingQueriesCache(session)
    oq_cache.set(session_id, came_from)
    return info
Esempio n. 4
0
    def _create_idp_response(
            self,
            authn_request_id='2aaaeb7692471eb4ba00d5546877a7fd',
            cls=Response):
        issue_instant = datetime.utcnow().isoformat() + 'Z'
        not_before = (datetime.utcnow() -
                      timedelta(minutes=5)).isoformat() + 'Z'
        not_on_or_after = (datetime.utcnow() +
                           timedelta(minutes=5)).isoformat() + 'Z'
        issuer = Issuer(format=NAMEID_FORMAT_ENTITY, text='http://nohost/auth')
        signature = pre_signature_part(
            's2998eb2e03b5006acb0a931d0fb558b0e4ec360c7')
        status = Status(status_code=StatusCode(value=STATUS_SUCCESS))
        subject_confirmation_data = SubjectConfirmationData(
            not_on_or_after=not_on_or_after,
            in_response_to=authn_request_id,
            recipient='http://nohost/')
        subject_confirmation = SubjectConfirmation(
            method=SCM_BEARER,
            subject_confirmation_data=subject_confirmation_data)
        subject = Subject(name_id=NameID(text='AABVSVesMLYDiHtowyX4MDu6UopU',
                                         format=NAMEID_FORMAT_TRANSIENT),
                          subject_confirmation=subject_confirmation)
        conditions = Conditions(not_before=not_before,
                                not_on_or_after=not_on_or_after,
                                audience_restriction=AudienceRestriction(
                                    Audience('http://nohost/')),
                                one_time_use=OneTimeUse())
        authn_context = AuthnContext(authn_context_decl_ref=AuthnContextClassRef(
            'urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport'
        ))
        authn_statement = AuthnStatement(authn_instant=issue_instant,
                                         authn_context=authn_context,
                                         session_index=self.session_index)
        attribute_statement = attribute_statement_from_string(
            self.attribute_xml)
        assertion = Assertion(
            id='s2bb879ef893d1b27fb90903e7c7e2779a3e7502c1',
            version='2.0',
            issue_instant=issue_instant,
            issuer=issuer,
            subject=subject,
            conditions=conditions,
            authn_statement=authn_statement,
            attribute_statement=attribute_statement,
        )

        return cls(id='s2998eb2e03b5006acb0a931d0fb558b0e4ec360c7',
                   in_response_to=authn_request_id,
                   version='2.0',
                   issue_instant=issue_instant,
                   destination='http://nohost/',
                   issuer=issuer,
                   signature=signature,
                   status=status,
                   assertion=assertion)
Esempio n. 5
0
    def load_sso_kwargs_authn_context(self, sso_kwargs):
        # this would work when https://github.com/IdentityPython/pysaml2/pull/807
        ac = getattr(self.conf, '_sp_requested_authn_context', {})

        # this works even without https://github.com/IdentityPython/pysaml2/pull/807
        # hopefully to be removed soon !
        if not ac:
            scs = getattr(settings, 'SAML_CONFIG', {}).get('service',
                                                           {}).get('sp', {})
            ac = scs.get('requested_authn_context', {})
        # end transitional things to be removed soon !

        if ac:
            sso_kwargs["requested_authn_context"] = RequestedAuthnContext(
                authn_context_class_ref=[
                    AuthnContextClassRef(ac['authn_context_class_ref']),
                ],
                comparison=ac.get('comparison', "minimum"),
            )
Esempio n. 6
0
File: sp.py Progetto: rohe/actester
    def _redirect_to_auth(self,
                          _cli,
                          entity_id,
                          came_from,
                          vorg_name="",
                          dont_send=False):
        try:
            _binding, destination = _cli.pick_binding("single_sign_on_service",
                                                      self.bindings,
                                                      "idpsso",
                                                      entity_id=entity_id)
            logger.debug("binding: %s, destination: %s" %
                         (_binding, destination))
            if "accr" in self.kwargs:
                kwargs = {
                    "requested_authn_context":
                    RequestedAuthnContext(
                        authn_context_class_ref=AuthnContextClassRef(
                            text=self.kwargs["accr"]))
                }
            else:
                kwargs = {}

            req = _cli.create_authn_request(destination,
                                            vorg=vorg_name,
                                            **kwargs)

            _rstate = rndstr()
            self.cache.relay_state[_rstate] = came_from
            ht_args = _cli.apply_binding(_binding,
                                         "%s" % req,
                                         destination,
                                         relay_state=_rstate)
            _sid = req.id
            SESSIONDB[_sid] = self.kwargs
            logger.debug("ht_args: %s" % ht_args)
        except Exception, exc:
            logger.exception(exc)
            resp = ServiceError("Failed to construct the AuthnRequest: %s" %
                                exc)
            return resp(self.environ, self.start_response)
Esempio n. 7
0
def test_authn_request_with_acs_by_index():
    # ACS index and location from SP metadata in servera.xml.
    ACS_INDEX = '4'
    ACS_LOCATION = 'http://lingon.catalogix.se:8087/another/path'

    # Create SP using the configuration found in servera_conf.py.
    sp = Saml2Client(config_file="servera_conf")

    # Generate an authn request object that uses AssertionConsumerServiceIndex
    # instead of AssertionConsumerServiceURL. The index with label ACS_INDEX
    # exists in the SP metadata in servera.xml.
    request_id, authn_request = sp.create_authn_request(
        sp.config.entityid, assertion_consumer_service_index=ACS_INDEX)

    assert authn_request.requested_authn_context.authn_context_class_ref == [
        AuthnContextClassRef(accr) for accr in sp.config.getattr(
            "requested_authn_context").get("authn_context_class_ref")
    ]
    assert authn_request.requested_authn_context.comparison == (
        sp.config.getattr("requested_authn_context").get("comparison"))

    # Make sure the authn_request contains AssertionConsumerServiceIndex.
    acs_index = getattr(authn_request, 'assertion_consumer_service_index',
                        None)
    assert acs_index == ACS_INDEX

    # Create IdP.
    with closing(Server(config_file="idp_all_conf")) as idp:
        # Ask the IdP to pick out the binding and destination from the
        # authn_request.
        binding, destination = idp.pick_binding("assertion_consumer_service",
                                                request=authn_request)

        # Make sure the IdP pick_binding method picks the correct location
        # or destination based on the ACS index in the authn request.
        assert destination == ACS_LOCATION
Esempio n. 8
0
def requested_authn_context(class_ref, comparison="minimum"):
    return RequestedAuthnContext(
        authn_context_class_ref=[AuthnContextClassRef(text=class_ref)],
        comparison=comparison)
Esempio n. 9
0
def authn_context_class_ref(ref):
    return AuthnContext(authn_context_class_ref=AuthnContextClassRef(text=ref))
Esempio n. 10
0
    def create_authn_request(
        self,
        destination,
        vorg="",
        scoping=None,
        binding=BINDING_HTTP_POST,
        nameid_format=None,
        service_url_binding=None,
        message_id=0,
        consent=None,
        extensions=None,
        sign=None,
        sign_prepare=None,
        sign_alg=None,
        digest_alg=None,
        allow_create=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 sign_alg: The request signature algorithm
        :param digest_alg: The request digest algorithm
        :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

        requested_authn_context = (kwargs.pop("requested_authn_context", None)
                                   or self.config.getattr(
                                       "requested_authn_context", "sp") or {})
        if isinstance(requested_authn_context, RequestedAuthnContext):
            args["requested_authn_context"] = requested_authn_context
        elif isinstance(requested_authn_context, Mapping):
            requested_authn_context_accrs = requested_authn_context.get(
                "authn_context_class_ref", [])
            requested_authn_context_comparison = requested_authn_context.get(
                "comparison", "exact")
            if requested_authn_context_accrs:
                args["requested_authn_context"] = RequestedAuthnContext(
                    authn_context_class_ref=[
                        AuthnContextClassRef(accr)
                        for accr in requested_authn_context_accrs
                    ],
                    comparison=requested_authn_context_comparison,
                )
        else:
            logger.warning({
                "message":
                "Cannot process requested_authn_context",
                "requested_authn_context":
                requested_authn_context,
                "type_of_requested_authn_context":
                type(requested_authn_context),
            })

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

            if isinstance(_item, _msg.child_class(param)):
                args[param] = _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")

        msg = self._message(
            AuthnRequest,
            destination,
            message_id,
            consent,
            extensions,
            sign,
            sign_prepare,
            sign_alg=sign_alg,
            digest_alg=digest_alg,
            protocol_binding=binding,
            scoping=scoping,
            nsprefix=nsprefix,
            **args,
        )

        return msg