Beispiel #1
0
 def realms(self, upstream_affordances=None, downstream_affordances=None):
     upstream_affordances, downstream_affordances = \
         self._normalized_affordances(upstream_affordances,
                                      downstream_affordances)
     return _frozenuset(self._realms(upstream_affordances=
                                         upstream_affordances,
                                     downstream_affordances=
                                         downstream_affordances)) \
            & upstream_affordances.realms \
            & downstream_affordances.realms
Beispiel #2
0
    def assert_cors_preflight_accepted_response(self, response, **kwargs):

        super(TestCorsPreflight, self)\
         .assert_cors_preflight_accepted_response(response, **kwargs)

        response_allowed_origins_header = \
            response.headers['Access-Control-Allow-Origin']
        response_allowed_origins = \
            _frozenuset('*' if response_allowed_origins_header == '*'
                            else (token.strip()
                                  for token
                                  in response_allowed_origins_header
                                      .split(',')))
        self.assertIn(self.cors_origin, response_allowed_origins)
Beispiel #3
0
    def ensure_auth(self, loc, realms='*', provisionsets='*', algorithms='*'):

        """Ensure authentication

        This method returns successfully if the request includes authentication
        information wherein the realm, security provisions, and algorithm
        satisfy the affordances of the authentication space defined for the
        given *loc*.  If additional *realms*, *provisionsets*, or *algorithms*
        are given, then those are applied as additional constraints beyond
        those imposed by the authentication space's affordances.

        .. note::
            Normally, the caller should not handle the
            :class:`bedframe.Unauthenticated <bedframe._exc.Unauthenticated>`
            exception or any of its subclasses
            (:class:`bedframe.AuthTokensNotGiven
            <bedframe._exc.AuthTokensNotGiven>` and
            :class:`bedframe.AuthTokensNotAccepted
            <bedframe._exc.AuthTokensNotAccepted>`).  These exceptions should
            be handled by the :class:`bedframe.WebServiceImpl
            <bedframe._services.WebServiceImpl>` so that it can respond
            accordingly.  To test whether the current request has appropriate
            authentication information, use :meth:`has_auth`.

        :param realms:
            Allowed realms.  This should be a subset of the realms afforded by
            the authentication space defined for the given *loc*.
        :type realms: ~u{str}

        :param provisionsets:
            Allowed security provision sets.  This should be a superset of the
            provision sets afforded by the authentication space defined for the
            given *loc*.
        :type provisionsets:
            ~\ :class:`~bedframe.auth._provisions.ProvisionSetSet`

        :param algorithms:
            Allowed algorithms.  This should be a subset of the
            algorithms afforded by the authentication space defined for the
            given *loc*.
        :type algorithms:
            ~u{:class:`~bedframe.auth._algorithms.Algorithm`}

        :raise bedframe.AuthTokenNotGiven:
            Raised if the request does not include an authentication token.

        :raise bedframe.AuthTokenNotAccepted:
            Raised if the request includes an authentication token that was not
            accepted by the authenticator.

        """

        if self.has_auth(loc=loc, realms=realms, provisionsets=provisionsets,
                         algorithms=algorithms):
            return

        affordances = \
            _affordances.AffordanceSet\
             (realms=(realms if realms is not None else '*'),
              provisionsets=(provisionsets if provisionsets is not None
                                           else '*'),
              algorithms=(algorithms if algorithms is not None else '*'))

        space = self.spaces.get(loc, None)

        def logmessage():
            message = 'authentication required at {}'.format(loc)
            if space:
                message += ' in space {}'.format(space)
            if affordances != _affordances.FrozenAffordanceSet.max():
                message += ' with {}'.format(affordances)
            return message
        self.logger.cond((_logging.DEBUG, logmessage))

        if algorithms:
            algorithms = _frozenuset(algorithms) & _frozenuset(self.algorithms)
        else:
            algorithms = _frozenuset(self.algorithms)
        clerks = _frozenuset(self.clerks)
        scanners = _frozenuset(self.scanners)
        supplicants = _frozenuset(self.supplicants)
        if space:
            algorithms = space.algorithms() & algorithms
            clerks = space.clerks & clerks
            scanners = space.scanners & scanners
            supplicants = space.supplicants & supplicants

        if space:
            affordances = space.affordances(upstream=affordances).unfrozen()
        else:
            affordances = _affordances.ProcessAffordanceSet.max()
        affordances.inputs = '*'
        affordances.outputs = '*'
        general_affordances = affordances.general
        general_affordances.require_nonempty()
        self.logger.cond((_logging.DEBUG,
                          lambda: 'given affordances {}'
                                   .format(general_affordances)))

        # filter connectors by general affordances
        resolution_affordances = \
            _affordances.ProcessProspectiveAffordanceSet\
             .from_general(affordances)
        algorithms_list = \
            [algorithm for algorithm in algorithms
             if algorithm.supports_affordances(upstream=affordances)]
        resolution_affordances.algorithms = algorithms_list
        resolution_affordances.clerks = \
            [clerk for clerk in clerks
             if clerk.supports_affordances(upstream=affordances)]
        resolution_affordances.scanners = \
            [scanner for scanner in scanners
             if scanner.supports_affordances(upstream=affordances)]
        resolution_affordances.supplicants = \
            [supplicant for supplicant in supplicants
             if supplicant.supports_affordances(upstream=affordances)]

        for connector_type in ('algorithm', 'clerk', 'scanner', 'supplicant'):
            if not getattr(resolution_affordances, connector_type + 's'):
                raise _exc.Error('no {} meets the necessary affordances {}'
                                  .format(connector_type, affordances))

        self.logger.cond((_logging.DEBUG,
                          lambda: 'considering algorithms {}'
                                   .format(resolution_affordances.algorithms)))
        self.logger.cond((_logging.DEBUG,
                          lambda: 'considering clerks {}'
                                   .format(resolution_affordances.clerks)))
        self.logger.cond((_logging.DEBUG,
                          lambda: 'considering scanners {}'
                                   .format(resolution_affordances.scanners)))
        self.logger\
            .cond((_logging.DEBUG,
                   lambda: 'considering supplicants {}'
                            .format(resolution_affordances.supplicants)))

        prospective_affordances = resolution_affordances.copy()
        prospective_affordances.outputs = ((),)
        prospective_affordances.scanners = \
            resolution_affordances.scanners.copy()
        scanned_auth_info = None
        for scanner in resolution_affordances.scanners:
            try:
                scanned_auth_info = \
                    scanner.process_tokens(affordances=resolution_affordances)
            except _exc.NoValidTokensScanned:
                pass
            else:
                scanned_tokens = scanned_auth_info.tokens
                message = 'scanner {} recognized tokens {}'
                self.logger\
                    .cond((_logging.INSECURE,
                           lambda: message.format(scanner, scanned_tokens)),
                          (_logging.DEBUG,
                           lambda: message.format(scanner,
                                                  scanned_tokens.keys())))
                prospective_affordances.outputs.add(scanned_tokens.frozen())
        if not prospective_affordances.scanners:
            prospective_affordances.scanners = resolution_affordances.scanners
        if not prospective_affordances.outputs:
            prospective_affordances.outputs.add(())

        prospective_affordances, phase = \
            self._best_resolved_prospective_affordances_and_phase\
             (prospective_affordances)

        if prospective_affordances is None:
            raise _exc.Error('cannot resolve an acceptable authentication'
                              ' process')
        prospective_affordances.require_nonempty()

        if scanned_auth_info:
            auth_info = scanned_auth_info
        else:
            auth_info = _info.RequestAuthInfo()

        prospective_affordances = prospective_affordances.unfrozen()
        self._update_afforded_tokens_from_auth_info(prospective_affordances,
                                                    auth_info)

        prospective_affordances.require_nonempty()
        prospective_affordances.require_finite(exceptions=('outputs'))

        realm = iter(prospective_affordances.realms).next()
        algorithm = iter(prospective_affordances.algorithms).next()
        clerk = iter(prospective_affordances.clerks).next()
        scanner = iter(prospective_affordances.scanners).next()
        supplicant = iter(prospective_affordances.supplicants).next()
        process_affordances = prospective_affordances.general

        auth_info.space = space
        auth_info.realm = realm
        auth_info.algorithm = algorithm
        auth_info.clerk = clerk
        auth_info.scanner = scanner
        auth_info.supplicant = supplicant

        self.logger.cond((_logging.DEBUG,
                          lambda: 'chose realm {}'.format(realm)))
        self.logger.cond((_logging.DEBUG,
                          lambda: 'chose algorithm {!r}'.format(algorithm)))
        self.logger.cond((_logging.DEBUG,
                          lambda: 'chose clerk {!r}'.format(clerk)))
        self.logger.cond((_logging.DEBUG,
                          lambda: 'chose scanner {!r}'.format(scanner)))
        self.logger.cond((_logging.DEBUG,
                          lambda: 'chose supplicant {!r}'.format(supplicant)))

        self.logger.cond((_logging.DEBUG,
                          lambda: 'starting authentication with phase {} and'
                                   ' affordances {}'
                                   .format(phase, process_affordances)))
        unauth_exc = None
        unauth_traceback = None
        try:
            auth_info = self._process_phase(phase,
                                            clerk=clerk,
                                            scanner=scanner,
                                            supplicant=supplicant,
                                            affordances=process_affordances,
                                            auth_info=auth_info)
        except _bedframe_exc.Unauthenticated as unauth_exc:
            unauth_traceback = _sys.exc_info()[2]

        self.current_auth_info = auth_info

        message = 'final info {}'
        self.logger\
            .cond((_logging.INSECURE,
                   lambda: message.format(auth_info.repr(insecure=True))),
                  (_logging.DEBUG,
                   lambda: message.format(auth_info.repr(insecure=False))))

        if unauth_exc:
            raise unauth_exc, None, unauth_traceback

        affordances = process_affordances.general
        if auth_info.verified:
            clerk.confirm_auth_info(auth_info, affordances=affordances)

            if not auth_info.accepted:
                raise _bedframe_exc.AuthTokensNotAccepted(affordances=affordances)

        else:
            # FIXME
            raise _exc.Error