示例#1
0
                def _on_success(res):
                    msg = None
                    # it is possible this session has disconnected
                    # while onHello was taking place
                    if self._transport is None:
                        self.log.info(
                            "Client session disconnected during authentication",
                        )
                        return

                    if isinstance(res, types.Accept):
                        custom = {
                            u'x_cb_node_id': self._router_factory._node_id
                        }
                        welcome(res.realm, res.authid, res.authrole,
                                res.authmethod, res.authprovider,
                                res.authextra, custom)

                    elif isinstance(res, types.Challenge):
                        msg = message.Challenge(res.method, res.extra)

                    elif isinstance(res, types.Deny):
                        msg = message.Abort(res.reason, res.message)

                    else:
                        pass

                    if msg:
                        self._transport.send(msg)
示例#2
0
        def test_on_leave_after_bad_challenge(self):
            '''
            onLeave raises error after onChallenge fails
            '''
            session = MockApplicationSession()
            exception = RuntimeError("such challenge")
            session.onLeave = exception_raiser(exception)
            session.onChallenge = exception_raiser(exception)
            # make a challenge (which will fail, and then the
            # subsequent onLeave will also fail)
            msg = message.Challenge("foo")
            session.onMessage(msg)

            self.assertEqual(2, len(session.errors))
            self.assertEqual(exception, session.errors[0][0])
        def test_on_challenge_deferred(self):
            session = MockApplicationSession()
            exception = RuntimeError("such challenge")
            session.onChallenge = async_exception_raiser(exception)
            msg = message.Challenge(u"foo")

            # execute
            session.onMessage(msg)

            # we already handle any onChallenge errors as "abort the
            # connection". So make sure our error showed up in the
            # fake-transport.
            self.assertEqual(0, len(session.errors))
            self.assertEqual(1, len(session._transport.messages))
            reply = session._transport.messages[0]
            self.assertIsInstance(reply, message.Abort)
            self.assertEqual("such challenge", reply.message)
示例#4
0
                def success(res):
                    msg = None

                    if isinstance(res, types.Accept):
                        welcome(self._realm, res.authid, res.authrole, res.authmethod, res.authprovider)

                    elif isinstance(res, types.Challenge):
                        msg = message.Challenge(res.method, res.extra)

                    elif isinstance(res, types.Deny):
                        msg = message.Abort(res.reason, res.message)

                    else:
                        pass

                    if msg:
                        self._transport.send(msg)
示例#5
0
                def success(res):
                    msg = None
                    if isinstance(res, types.Accept):
                        custom = {
                            u'x_cb_node_id': self._router_factory._node_id
                        }
                        welcome(res.realm, res.authid, res.authrole, res.authmethod, res.authprovider, res.authextra, custom)

                    elif isinstance(res, types.Challenge):
                        msg = message.Challenge(res.method, res.extra)

                    elif isinstance(res, types.Deny):
                        msg = message.Abort(res.reason, res.message)

                    else:
                        pass

                    if msg:
                        self._transport.send(msg)
示例#6
0
def send(msg):
    bytes, _ = serializer.serialize(msg)
    l = struct.pack("!I", len(bytes))
    sys.stdout.write(l)
    sys.stdout.write(bytes)


msgs = []

## HELLO
##
roles = [
    role.RolePublisherFeatures(),
    role.RoleSubscriberFeatures(),
    role.RoleCallerFeatures(),
    role.RoleCalleeFeatures()
]

msgs.append(message.Hello("foobar", roles))

## CHALLENGE
##
msgs.append(message.Challenge("cookie"))

## HEARTBEAT
##
msgs.append(message.Heartbeat(3, 7, "throw me away"))

for msg in msgs:
    send(msg)
示例#7
0
    def _process_Hello(self, msg):
        """
        We have received a Hello from the frontend client.

        Now we do any authentication necessary with them and connect
        to our backend.
        """
        self.log.info('{klass}._process_Hello(msg={msg})', klass=self.__class__.__name__, msg=msg)
        self._pending_session_id = util.id()
        self._goodbye_sent = False

        extra_auth_methods = self._controller.personality.EXTRA_AUTH_METHODS

        # allow "Personality" classes to add authmethods
        authmethods = list(extra_auth_methods.keys()) + (msg.authmethods or ['anonymous'])

        # if the client had a reassigned realm during authentication, restore it from the cookie
        if hasattr(self.transport, '_authrealm') and self.transport._authrealm:
            if 'cookie' in authmethods:
                realm = self.transport._authrealm  # noqa
                authextra = self.transport._authextra  # noqa
            elif self.transport._authprovider == 'cookie':
                # revoke authentication and invalidate cookie (will be revalidated if following auth is successful)
                self.transport._authmethod = None
                self.transport._authrealm = None
                self.transport._authid = None
                if hasattr(self.transport, '_cbtid'):
                    self.transport.factory._cookiestore.setAuth(self.transport._cbtid, None, None, None, None, None)
            else:
                pass  # TLS authentication is not revoked here

        # already authenticated, eg via HTTP-cookie or TLS-client-certificate authentication
        if self.transport._authid is not None and (self.transport._authmethod == 'trusted' or self.transport._authprovider in authmethods):
            msg.realm = self.transport._realm
            msg.authid = self.transport._authid
            msg.authrole = self.transport._authrole

        details = types.HelloDetails(
            realm=msg.realm,
            authmethods=authmethods,
            authid=msg.authid,
            authrole=msg.authrole,
            authextra=msg.authextra,
            session_roles=msg.roles,
            pending_session=self._pending_session_id
        )
        auth_config = self._transport_config.get('auth', None)

        # if authentication is _not_ configured, allow anyone to join as "anonymous"!
        if not auth_config:
            # we ignore any details.authid the client might have announced, and use
            # a cookie value or a random value
            if hasattr(self.transport, "_cbtid") and self.transport._cbtid:
                # if cookie tracking is enabled, set authid to cookie value
                authid = self.transport._cbtid
            else:
                # if no cookie tracking, generate a random value for authid
                authid = util.generate_serial_number()
            auth_config = {
                'anonymous': {
                    'type': 'static',
                    'authrole': 'anonymous',
                    'authid': authid,
                }
            }
            self.log.warn('No authentication configured for proxy frontend: using default anonymous access policy for incoming proxy frontend session')

        for authmethod in authmethods:
            # invalid authmethod
            if authmethod not in AUTHMETHOD_MAP and authmethod not in extra_auth_methods:
                self.transport.send(message.Abort(ApplicationError.AUTHENTICATION_FAILED,
                                                  message='authmethod "{}" not allowed'.format(authmethod)))
                return

            # authmethod is valid, but not configured: continue trying other authmethods the client is announcing
            if authmethod not in auth_config:
                continue

            # authmethod not available
            if authmethod not in AUTHMETHOD_MAP and authmethod not in extra_auth_methods:
                self.log.debug("client requested valid, but unavailable authentication method {authmethod}",
                               authmethod=authmethod)
                continue

            # create instance of authenticator using authenticator class for the respective authmethod
            authklass = extra_auth_methods[authmethod] if authmethod in extra_auth_methods else AUTHMETHOD_MAP[authmethod]
            self._pending_auth = authklass(
                self._pending_session_id,
                self.transport._transport_info,
                self._controller,
                auth_config[authmethod],
            )
            try:
                # call into authenticator for processing the HELLO message
                hello_result = self._pending_auth.hello(msg.realm, details)
            except Exception as e:
                self.log.failure()
                self.transport.send(message.Abort(ApplicationError.AUTHENTICATION_FAILED,
                                                  message='Frontend connection accept failed ({})'.format(e)))
                return
            self.log.info('{klass}._process_Hello() processed authmethod "{authmethod}" using {authklass}: {hello_result}',
                          klass=self.__class__.__name__, authmethod=authmethod, authklass=authklass,
                          hello_result=hello_result)

            # if the frontend session is accepted right away (eg when doing "anonymous" authentication), process the
            # frontend accept ..
            if isinstance(hello_result, types.Accept):
                try:
                    # get a backend session mapped to the incoming frontend session
                    session = yield self._accept(hello_result)
                except Exception as e:
                    self.log.failure()
                    self.transport.send(message.Abort(ApplicationError.AUTHENTICATION_FAILED,
                                                      message='Frontend connection accept failed ({})'.format(e)))
                    return

                def _on_backend_joined(session, details):
                    # we now got everything! the frontend is authenticated, and a backend session is associated.
                    msg = message.Welcome(self._session_id,
                                          ProxyFrontendSession.ROLES,
                                          realm=details.realm,
                                          authid=details.authid,
                                          authrole=details.authrole,
                                          authmethod=hello_result.authmethod,
                                          authprovider=hello_result.authprovider,
                                          authextra=dict(details.authextra or {}, **self._custom_authextra))
                    self._backend_session = session
                    self.transport.send(msg)
                    self.log.info('Proxy frontend session WELCOME: session_id={session}, session={session}, session_details={details}',
                                  session_id=hlid(self._session_id), session=self, details=details)

                session.on('join', _on_backend_joined)

            # if the client is required to do an authentication message exchange, answer sending a CHALLENGE message
            elif isinstance(hello_result, types.Challenge):
                self.transport.send(message.Challenge(hello_result.method, extra=hello_result.extra))

            # if the client is denied right away, answer by sending an ABORT message
            elif isinstance(hello_result, types.Deny):
                self.transport.send(message.Abort(hello_result.reason, message=hello_result.message))

            # should not arrive here: internal (logic) error
            else:
                self.transport.send(message.Abort(ApplicationError.AUTHENTICATION_FAILED,
                                                  message='internal error: unexpected authenticator return type {}'.format(type(hello_result))))
            return

        self.transport.send(message.Abort(ApplicationError.NO_AUTH_METHOD, message='no suitable authmethod found'))
示例#8
0
    def _process_Hello(self, msg):
        """
        We have received a Hello from the frontend client.

        Now we do any authentication necessary with them and connect
        to our backend.
        """
        self.log.info('{klass}._process_Hello(msg={msg})', klass=self.__class__.__name__, msg=msg)
        self._pending_session_id = util.id()
        self._goodbye_sent = False

        authmethods = msg.authmethods or ['anonymous']

        details = types.HelloDetails(
            realm=msg.realm,
            authmethods=authmethods,
            authid=msg.authid,
            authrole=msg.authrole,
            authextra=msg.authextra,
            session_roles=msg.roles,
            pending_session=self._pending_session_id
        )
        auth_config = self._transport_config.get('auth', None)

        # allow "Personality" classes to add authmethods
        extra_auth_methods = dict()
        # if self._router_factory._worker:
        #     personality = self._router_factory._worker.personality
        #     extra_auth_methods = personality.EXTRA_AUTH_METHODS

        for authmethod in authmethods:
            # invalid authmethod
            if authmethod not in AUTHMETHOD_MAP and authmethod not in extra_auth_methods:
                self.transport.send(message.Abort(ApplicationError.AUTHENTICATION_FAILED,
                                                  message='authmethod "{}" not allowed'.format(authmethod)))
                return

            # authmethod is valid, but not configured: continue trying other authmethods the client is announcing
            if authmethod not in auth_config:
                continue

            # authmethod not available
            if authmethod not in AUTHMETHOD_MAP and authmethod not in extra_auth_methods:
                self.log.debug("client requested valid, but unavailable authentication method {authmethod}",
                               authmethod=authmethod)
                continue

            PendingAuthKlass = AUTHMETHOD_MAP[authmethod]

            # pending_session_id, transport_info, realm_container, config
            self._pending_auth = PendingAuthKlass(
                self._pending_session_id,
                self.transport._transport_info,

                # FIXME * no_such_role
                self._controller,
                auth_config[authmethod],
            )
            try:
                hello_result = self._pending_auth.hello(msg.realm, details)
            except Exception as e:
                self.log.failure()
                self.transport.send(message.Abort(ApplicationError.AUTHENTICATION_FAILED,
                                                  message='Frontend connection accept failed ({})'.format(e)))
                return
            self.log.info('{klass}._process_Hello() processed authmethod "{authmethod}" using {authklass}: {hello_result}',
                          klass=self.__class__.__name__, authmethod=authmethod, authklass=PendingAuthKlass,
                          hello_result=hello_result)

            if isinstance(hello_result, types.Accept):
                try:
                    session = yield self._accept(hello_result)
                except Exception as e:
                    self.log.failure()
                    self.transport.send(message.Abort(ApplicationError.AUTHENTICATION_FAILED,
                                                      message='Frontend connection accept failed ({})'.format(e)))
                    return

                def _on_backend_joined(session, details):
                    msg = message.Welcome(self._session_id,
                                          ProxyFrontendSession.ROLES,
                                          realm=details.realm,
                                          authid=details.authid,
                                          authrole=details.authrole,
                                          authmethod=hello_result.authmethod,
                                          authprovider=hello_result.authprovider,
                                          authextra=dict(details.authextra or {}, **self._custom_authextra))
                    self._backend_session = session
                    self.transport.send(msg)
                    self.log.info('Proxy frontend session WELCOME: session_id={session}, session={session}, session_details={details}',
                                  session_id=hlid(self._session_id), session=self, details=details)

                session.on('join', _on_backend_joined)
            elif isinstance(hello_result, types.Challenge):
                self.transport.send(message.Challenge(hello_result.method, extra=hello_result.extra))

            elif isinstance(hello_result, types.Deny):
                self.transport.send(message.Abort(hello_result.reason, message=hello_result.message))

            else:
                # should not arrive here: logic error
                self.transport.send(message.Abort(ApplicationError.AUTHENTICATION_FAILED,
                                                  message='internal error: unexpected authenticator return type {}'.format(type(hello_result))))
            return

        self.transport.send(message.Abort(ApplicationError.NO_AUTH_METHOD, message='no suitable authmethod found'))