Exemple #1
0
        txaio.start_logging(level='info')
    log = make_logger()

    # forward requested authid and key filename to ClientSession
    extra = {
        'channel_binding': options.channel_binding,

        # this is optional
        'authid': options.authid,

        # the private key is required
        'key': options.key
    }
    print("Connecting to {}: requesting realm={}, authid={}".format(
        options.url, options.realm, options.authid))

    tls_config = {
        "hostname": "localhost",
        # "certificate": "client.crt",
        # "key": "client.key",
        "ca_certificates": ["intermediate.cert.pem", "ca.cert.pem"]
    }
    cert_options = _create_tls_client_context(tls_config, '.crossbar', log)

    # connect to router and run ClientSession
    runner = ApplicationRunner(url=options.url,
                               realm=options.realm,
                               extra=extra,
                               ssl=cert_options)
    runner.run(ClientSession)
Exemple #2
0
    def run_context(self, ctx, command=None):

        # cfg contains the command lines options and arguments that
        # click collected for us
        cfg = ctx.obj
        cmd = ctx.command.name

        self.log.info('{klass}.run_context: running shell command "{cmd}"',
                      klass=self.__class__.__name__,
                      cmd=cmd)

        yes_to_all = cfg.yes_to_all if hasattr(cfg, 'yes_to_all') else False

        # if cmd not in ['auth', 'shell']:
        #    raise click.ClickException('"{}" command can only be run in shell'.format(cmd))

        if self._output_verbosity == Application.OUTPUT_VERBOSITY_VERBOSE:
            click.echo('Crossbar.io Shell: {}'.format(
                style_ok('v{}'.format(__version__))))

        # load user profile and key for given profile name
        key, profile = self.load_profile(dotdir=cfg.dotdir,
                                         profile=cfg.profile,
                                         yes_to_all=yes_to_all,
                                         verbose=(ctx.command.name == 'init'))

        if ctx.command.name == 'init':
            return

        # set the Fabric URL to connect to from the profile or default
        url = profile.url or 'wss://fabric.crossbario.com'

        # users always authenticate with the user_id from the key, which
        # filled from the email the user provided
        authid = key.user_id

        # the realm can be set from command line, env var, the profile
        # or can be None, which means the user will be joined to the global
        # Crossbar.io users realm ('com.crossbario.fabric')
        realm = cfg.realm or profile.realm or None

        # the authrole can be set from command line, env var, the profile
        # or can be None, in which case the role is chosen automatically
        # from the list of roles the user us authorized for
        authrole = cfg.role or profile.role or None

        # this will be fired when the ShellClient below actually has joined
        # the respective realm on Crossbar.io (either the global users
        # realm, or a management realm the user has a role on)
        done = txaio.create_future()

        url_is_secure, _, _, _, _, _ = parse_url(url)

        extra = {
            # these are forward on the actual client connection
            'authid': authid,
            'authrole': authrole,

            # these are native Python object and only used client-side
            'key': key.key,
            'done': done,
            'command': command,

            # WAMP-cryptosign authentication: TLS channel binding
            'channel_binding': 'tls-unique' if url_is_secure else None,
        }

        cert_options = None
        if profile.tls_hostname:
            self.log.info(
                'Setting up TLS context (server CA/intermediate certificates, etc) from profile:'
            )
            tls_config = {
                'hostname': profile.tls_hostname,
                'ca_certificates': profile.tls_certificates
            }
            cert_options = _create_tls_client_context(tls_config, '.crossbar',
                                                      self.log)

        # for the "auth" command, forward additional command line options
        if ctx.command.name == 'auth':
            # user provides authentication code to verify
            extra['activation_code'] = cfg.code

            # user requests sending of a new authentication code (while an old one is still pending)
            extra['request_new_activation_code'] = cfg.new_code

        # this is the WAMP ApplicationSession that connects the CLI to Crossbar.io
        self.session = client.ShellClient(ComponentConfig(realm, extra))

        runner = ApplicationRunner(url, realm, ssl=cert_options)

        if self._output_verbosity == Application.OUTPUT_VERBOSITY_VERBOSE:
            click.echo('Connecting to {} ..'.format(url))

        connect_done = runner.run(self.session, start_reactor=False)

        def on_connect_success(res):
            self.log.info('{klass}.on_connect_success(res={res})',
                          klass=self.__class__.__name__,
                          res=pformat(res))

        def on_connect_error(err):
            self.log.warn('{klass}.on_connect_error(err={err})',
                          klass=self.__class__.__name__,
                          err=err)

            if isinstance(err, Failure):
                err = err.value

            txaio.reject(done, err)

            # raise SystemExit(1)

        txaio.add_callbacks(connect_done, on_connect_success, on_connect_error)

        def on_success(res):
            self.log.info('{klass}.on_success(res={res})',
                          klass=self.__class__.__name__,
                          res=pformat(res))

            session_details, result = res

            if cmd == 'auth':

                self._print_welcome(url, session_details)

            elif cmd == 'shell':

                # click.clear()
                self._print_welcome(url, session_details)

                # FIXME:

                # prompt_kwargs = {
                #     'history': self._history,
                # }
                #
                # from crossbar.shell import repl
                #
                # shell_task = loop.create_task(
                #     repl.repl(
                #         ctx,
                #         get_bottom_toolbar_tokens=self._get_bottom_toolbar_tokens,
                #         # get_prompt_tokens=self._get_prompt_tokens,
                #         style=self._style,
                #         prompt_kwargs=prompt_kwargs))
                #
                # try:
                #     loop.run_until_complete(shell_task)
                # except Exception as e:
                #     print(e)

            else:
                if result:
                    self._output_result(result)

        def on_error(err):
            self.log.warn('{klass}.on_error(err={err})',
                          klass=self.__class__.__name__,
                          err=err)

            if isinstance(err, Failure):
                err = err.value

            if isinstance(err, ApplicationError):

                self.log.warn('{message} - {error}',
                              message=err.args[0] if err.args else '',
                              error=err.error)

                # some ApplicationErrors are actually signaling progress
                # in the authentication flow, some are real errors

                exit_code = None

                if err.error.startswith('fabric.auth-failed.'):
                    error = err.error.split('.')[2]
                    message = err.args[0]

                    if error == 'new-user-auth-code-sent':

                        click.echo(
                            '\nThanks for registering! {}'.format(message))
                        click.echo(
                            style_ok(
                                'Please check your inbox and run "crossbar shell auth --code <THE CODE YOU GOT BY EMAIL>.\n'
                            ))

                    elif error == 'registered-user-auth-code-sent':

                        click.echo('\nWelcome back! {}'.format(message))
                        click.echo(
                            style_ok(
                                'Please check your inbox and run "crossbar shell auth --code <THE CODE YOU GOT BY EMAIL>.\n'
                            ))

                    elif error == 'pending-activation':

                        click.echo()
                        click.echo(style_ok(message))
                        click.echo()
                        click.echo(
                            'Tip: to activate, run "crossbar shell auth --code <THE CODE YOU GOT BY EMAIL>"'
                        )
                        click.echo(
                            'Tip: you can request sending a new code with "crossbar shell auth --new-code"'
                        )
                        click.echo()

                    elif error == 'no-pending-activation':

                        exit_code = 1
                        click.echo()
                        click.echo(
                            style_error('{} [{}]'.format(message, err.error)))
                        click.echo()

                    elif error == 'email-failure':

                        exit_code = 1
                        click.echo()
                        click.echo(
                            style_error('{} [{}]'.format(message, err.error)))
                        click.echo()

                    elif error == 'invalid-activation-code':

                        exit_code = 1
                        click.echo()
                        click.echo(
                            style_error('{} [{}]'.format(message, err.error)))
                        click.echo()

                    else:

                        exit_code = 1
                        click.echo(style_error('{}'.format(error)))
                        click.echo(style_error(message))

                elif err.error.startswith('crossbar.error.'):

                    error = err.error.split('.')[2]
                    message = err.args[0]

                    if error == 'invalid_configuration':

                        click.echo()
                        click.echo(
                            style_error('{} [{}]'.format(message, err.error)))
                        click.echo()
                    else:

                        exit_code = 1
                        click.echo(
                            style_error('{} [{}]'.format(message, err.error)))

                else:

                    click.echo(style_error('{}'.format(err)))
                    exit_code = 1

                if exit_code:
                    raise SystemExit(exit_code)

            else:
                click.echo(style_error('{}'.format(err)))
                raise SystemExit(1)

        txaio.add_callbacks(done, on_success, on_error)

        def doit(reactor):
            return done

        react(doit)