示例#1
0
def fill_vaction(vaction):
    vaction.oid = uuid.uuid4()
    vaction.created = np.datetime64(time_ns(), 'ns')
    vaction.vtype = random.randint(1, 4)
    vaction.vstatus = random.randint(1, 4)
    vaction.vcode = generate_activation_code()
    vaction.verified_oid = uuid.uuid4()
    vaction.verified_data = {
        'f1': os.urandom(32),
        'f2': random.randint(1, 100),
        'f3': list(range(10)),
        'f4': generate_activation_code()
    }
示例#2
0
def fill_token(token):
    token.oid = uuid.uuid4()
    token.atype = 1
    token.status = 1
    token.created = datetime.utcnow()
    token.completed = None
    token.code = util.generate_activation_code()
    token.email = '*****@*****.**'
    token.pubkey = binascii.b2a_hex(os.urandom(32)).decode()
示例#3
0
文件: _web.py 项目: yankos/crossbar
def page_xbr_submit_onboard():
    session['site_area'] = 'landing'
    session['site-page'] = None
    # ImmutableMultiDict([
    #   ('onboard_member_name', 'oberstet'),
    #   ('onboard_member_email', '*****@*****.**'),
    #   ('onboard_wallet_type', 'imported'),
    #   ('onboard_wallet_address', '0x6231eECbA6e7983efe5ce6d16972E16cCcD97CE7'),
    #   ('onboard_accept_eula', 'on')
    # ])
    onboard_member_name = request.form.get('onboard_member_name', None)
    onboard_member_email = request.form.get('onboard_member_email', None)
    onboard_wallet_type = request.form.get('onboard_wallet_type', None)
    onboard_wallet_address = request.form.get('onboard_wallet_address', None)
    onboard_accept_eula = request.form.get('onboard_accept_eula', None)

    print('page_xbr_submit_onboard:')
    print('  onboard_member_name', onboard_member_name)
    print('  onboard_member_email', onboard_member_email)
    print('  onboard_wallet_type', onboard_wallet_type)
    print('  onboard_wallet_address', onboard_wallet_address)
    print('  onboard_accept_eula', onboard_accept_eula)

    if onboard_wallet_type not in Account.WALLET_TYPE_FROM_STRING:
        return render_template(
            'xbr_onboard_submit_error.html',
            onboard_member_error='Invalid wallet type "{}"'.format(
                onboard_wallet_type))
    else:
        onboard_wallet_type = Account.WALLET_TYPE_FROM_STRING[
            onboard_wallet_type]

    if onboard_accept_eula != 'on':
        return render_template('xbr_onboard_submit_error.html',
                               onboard_member_error='EULA must be accepted')

    # eg, onboard_wallet_address = 0x6231eECbA6e7983efe5ce6d16972E16cCcD97CE7
    if len(onboard_wallet_address) != 42:
        return render_template(
            'xbr_onboard_submit_error.html',
            onboard_member_error='Invalid wallet address "{}"'.format(
                onboard_wallet_address))

    try:
        onboard_wallet_address = binascii.a2b_hex(onboard_wallet_address[2:])
    except:
        return render_template(
            'xbr_onboard_submit_error.html',
            onboard_member_error='Invalid wallet address "{}"'.format(
                onboard_wallet_address))

    if not validate_email(onboard_member_email, check_mx=False, verify=False):
        return render_template(
            'xbr_onboard_submit_error.html',
            onboard_member_error='Invalid email address "{}"'.format(
                onboard_member_email))

    if not is_valid_username(onboard_member_name):
        return render_template(
            'xbr_onboard_submit_error.html',
            onboard_member_error=
            'Invalid username "{}" - must be a string matching the regular expression {}'
            .format(onboard_member_name, _USERNAME_PAT_STR))

    db = app.config['DB']
    schema = app.config['DBSCHEMA']

    with db.begin() as txn:
        account_oid = schema.idx_accounts_by_username[txn, onboard_member_name]
        if account_oid:
            return render_template(
                'xbr_onboard_submit_error.html',
                onboard_member_error='Username "{}" already exists'.format(
                    onboard_member_name))

    vaction_oid = uuid.uuid4()
    vaction_code = generate_activation_code()
    mailgw = app.config['MAILGUN']
    try:
        mailgw.send_onboard_verification(onboard_member_email, vaction_oid,
                                         vaction_code)
    except Exception as e:
        return render_template(
            'xbr_onboard_submit_error.html',
            onboard_member_error=
            'Failed to submit email via mailgun (exception {})'.format(e))

    on_success_url = '{}/member'.format(app.config['WEBSITE_URL'])
    on_error_url = None
    verified_data = {
        'onboard_member_name': onboard_member_name,
        'onboard_member_email': onboard_member_email,
        'onboard_wallet_type': onboard_wallet_type,
        'onboard_wallet_address': onboard_wallet_address,
        'on_success_url': on_success_url,
        'on_error_url': on_error_url,
    }

    with db.begin(write=True) as txn:
        # double check (again) for username collision, as the mailgun email submit happens async in above after
        # we initially checked for collision
        account_oid = schema.idx_accounts_by_username[txn, onboard_member_name]
        if account_oid:
            return render_template(
                'xbr_onboard_submit_error.html',
                onboard_member_error='Username "{}" already exists'.format(
                    onboard_member_name))

        vaction = VerifiedAction()
        vaction.oid = vaction_oid
        vaction.created = np.datetime64(time_ns(), 'ns')
        vaction.vtype = VerifiedAction.VERIFICATION_TYPE_ONBOARD_MEMBER
        vaction.vstatus = VerifiedAction.VERIFICATION_STATUS_PENDING
        vaction.vcode = vaction_code
        # vaction.verified_oid = None
        vaction.verified_data = verified_data

        schema.verified_actions[txn, vaction.oid] = vaction

    return render_template('xbr_onboard_submit_success.html',
                           onboard_member_email=onboard_member_email,
                           vaction_oid=vaction_oid)
示例#4
0
    async def _auth_user(self,
                         realm,
                         authid,
                         authrole,
                         pubkey,
                         activation_code=None,
                         request_new_activation_code=False):
        """
        Authenticate a Crossbar.io user.

        For a user that is not yet registered, or a user key not yet associated
        with a user, this will raise an ApplicationError signaling the state
        of the registration process.
        """
        self.log.debug(
            'authenticating user for realm={realm}, authid={authid}, authrole={authrole}, pubkey={pubkey}, activation_code={activation_code}, request_new_activation_code={request_new_activation_code}',
            realm=realm,
            authid=authid,
            authrole=authrole,
            pubkey=pubkey,
            activation_code=activation_code,
            request_new_activation_code=request_new_activation_code)

        # we must protect against this!
        if activation_code and not authid:
            raise ApplicationError(
                Authenticator.ERROR_AUTH_INVALID_PARAMETERS,
                Authenticator.ERROR_AUTH_INVALID_PARAMETERS_MSG)

        # get activation for authid/pubkey pair (this will succeed when the user is registered and
        # the pubkey is associated with the user - the 99% case)
        activation = None
        with self._db.begin() as txn:
            oid = self._schema.idx_act_tokens_by_authid_pubkey[txn,
                                                               authid + pubkey]
            if oid:
                activation = self._schema.activation_tokens[txn, oid]

        # if the activation is still pending, allow to reset it and we will send
        # a new activation code
        if activation and activation.status == ActivationStatus.PENDING and request_new_activation_code:
            with self._db.begin(write=True) as txn:
                oid = self._schema.idx_act_tokens_by_authid_pubkey[txn,
                                                                   authid +
                                                                   pubkey]
                if oid:
                    del self._schema.activation_tokens[txn, oid]
                else:
                    raise Exception('no such activation')
            activation = None

        # get user (if any)
        user = None
        if authid:
            with self._db.begin() as txn:
                oid = self._schema.idx_users_by_email[txn, authid]
                if oid:
                    user = self._schema.users[txn, oid]

        is_new_user = user is None

        self.log.debug(
            'authenticating user={user}, is_new_user={is_new_user}, activation={activation}',
            user=user,
            is_new_user=is_new_user,
            activation=activation)

        if realm is None or realm == 'com.crossbario.fabric':
            realm = Authenticator.GLOBAL_USER_REALM
            authrole = Authenticator.GLOBAL_USER_REALM_USER_ROLE
        else:
            if authrole is None:
                authrole = 'owner'

        # superusers are treated special ..
        if pubkey in self._superusers:
            auth = {
                'pubkey': pubkey,
                'realm': realm,
                'authid': 'superuser',
                'role': authrole,
                'extra': None,
                'cache': False
            }
            self.log.info(
                hl('SUPERUSER authenticated (realm={}, authid={}, authrole={})'
                   .format(auth['realm'], auth['authid'], auth['role']),
                   color='green',
                   bold=True))
            return auth

        # if there is no activation yet, create/store a new one
        elif not activation:

            # check for user provided an activation code, though there is no activation currently
            if activation_code:
                raise ApplicationError(
                    Authenticator.ERROR_AUTH_NO_PENDING_ACT,
                    Authenticator.ERROR_AUTH_NO_PENDING_ACT_MSG)

            # ok, create a new activation in the database
            activation = ActivationToken()
            activation.oid = uuid.uuid4()
            activation.atype = ActivationType.REGISTRATION if is_new_user else ActivationType.LOGIN
            activation.created = datetime.utcnow()
            # activation.activated = None
            activation.code = util.generate_activation_code()
            activation.status = ActivationStatus.PENDING
            activation.email = authid
            activation.pubkey = pubkey

            with self._db.begin(write=True) as txn:
                self._schema.activation_tokens[txn,
                                               activation.oid] = activation

            if is_new_user:
                # send user message with activation code
                await self._messenger.send_user_registration_mail(
                    authid, activation.code)
                self.log.info(
                    'User registration mail sent to {authid} with activation code {activation_code}',
                    authid=hlid(authid),
                    activation_code=hl(activation.code, color='red',
                                       bold=True))

                # deny authentication by raising an error and providing feedback to client
                raise ApplicationError(
                    Authenticator.ERROR_AUTH_NEW_USER,
                    Authenticator.ERROR_AUTH_NEW_USER_MSG.format(email=authid),
                    email=authid)
            else:
                # send user message with activation code
                await self._messenger.send_user_login_mail(
                    authid, activation.code)
                self.log.info(
                    'User login mail sent to {authid} with activation code {activation_code}',
                    authid=hlid(authid),
                    activation_code=hl(activation.code, color='red',
                                       bold=True))

                # deny authentication by raising an error and providing feedback to client
                raise ApplicationError(
                    Authenticator.ERROR_AUTH_REGISTERED_USER,
                    Authenticator.ERROR_AUTH_REGISTERED_USER_MSG.format(
                        email=authid),
                    email=authid)
        else:

            self.log.debug('Activation found in database:\n{activation}',
                           activation=activation)

            if activation.status == ActivationStatus.ACTIVE:

                # ok, so the user's public key is known and active .. the 99% case

                # user provided an activation code, though there is no activation currently
                if activation_code:
                    raise ApplicationError(
                        Authenticator.ERROR_AUTH_NO_PENDING_ACT,
                        Authenticator.ERROR_AUTH_NO_PENDING_ACT_MSG)

                # .. if the user wants to join the global users realm, allow that,
                # but ignore any authrole that might have been requested
                if realm is None or realm == Authenticator.GLOBAL_USER_REALM:
                    auth = {
                        'pubkey': pubkey,
                        'realm': Authenticator.GLOBAL_USER_REALM,
                        'authid': authid,
                        'role': Authenticator.GLOBAL_USER_REALM_USER_ROLE,
                        'extra': None,
                        'cache': False
                    }
                    self.log.info(
                        'Found user {authid} with active pubkey, authenticating for global user realm',
                        authid=authid)

                    return auth

                # .. if the user wants to join a specific (management) realm, we need to check more ..
                else:
                    user_roles = None
                    with self._db.begin() as txn:
                        user_oid = self._schema.idx_users_by_email[txn, authid]
                        if user_oid:
                            mrealm_oid = self._schema.idx_mrealms_by_name[
                                txn, realm]
                            if mrealm_oid:
                                user_roles = self._schema.users_mrealm_roles[
                                    txn, (user_oid, mrealm_oid)]
                                self.log.info('user roles {user_roles}',
                                              user_roles=user_roles)
                            else:
                                self.log.info('no mrealm with name "{realm}"',
                                              realm=realm)
                        else:
                            self.log.info('no user for authid "{authid}"',
                                          authid=authid)

                    if not user_roles:
                        raise Exception(
                            'no realm "{}" or user not permitted'.format(
                                realm))
                    else:
                        self.log.info(
                            'user has {roles} roles on realm {realm}',
                            roles=user_roles.roles,
                            realm=realm)

                    if authrole is None:
                        # the user did not request a specific role, so take the first one?
                        # or take the role with the highest privileges? or lowest? FIXME
                        authrole = min(
                            user_roles.roles
                        )  # the minimum is the _highest_ permission (OWNER=1)
                    else:
                        MAP = {
                            'owner': UserRole.OWNER,
                            'admin': UserRole.ADMIN,
                            'user': UserRole.USER,
                            'guest': UserRole.GUEST,
                        }
                        authrole = MAP.get(authrole, None)

                    # the user requested a specific role: check that the role is in the
                    # list of permitted roles the user may take on the management realm
                    if authrole not in user_roles.roles:
                        raise Exception(
                            'not authorized for role {}'.format(authrole))

                    # map the integer authrole to a string
                    MAP = {
                        UserRole.OWNER: 'owner',
                        UserRole.ADMIN: 'admin',
                        UserRole.USER: '******',
                        UserRole.GUEST: 'guest',
                    }
                    authrole = MAP.get(authrole, None)

                    auth = {
                        'pubkey': pubkey,
                        'realm': realm,
                        'authid': authid,
                        'role': authrole,
                        'extra': None,
                        'cache': False
                    }
                    self.log.info('auth=\n{auth}', auth=auth)

                    self.log.info(
                        'Authenticated CF user with pubkey {pubkey}.. as authid "{authid}" on realm "{realm}"',
                        authid=authid,
                        realm=realm,
                        pubkey=pubkey[:16])

                    return auth

            elif activation.status == ActivationStatus.PENDING:

                now = datetime.utcnow()

                passed_secs = (now - activation.created).total_seconds()
                passed_secs_str = humanize.naturaldelta(passed_secs)

                if not activation_code:
                    raise ApplicationError(
                        Authenticator.ERROR_AUTH_PENDING_ACT,
                        Authenticator.ERROR_AUTH_PENDING_ACT_MSG.format(
                            passed_secs_str))

                if activation_code != activation.code:
                    msg = 'code does not match pending one'
                    raise ApplicationError(
                        Authenticator.ERROR_AUTH_INVALID_ACT_CODE,
                        Authenticator.ERROR_AUTH_INVALID_ACT_CODE_MSG.format(
                            msg))

                # check if the activation is expired (15min). if so, delete it, and bail out
                if passed_secs > (60 * 15):

                    with self._db.begin(write=True) as txn:
                        oid = self._schema.idx_act_tokens_by_authid_pubkey[
                            txn, authid + pubkey]
                        if oid:
                            del self._schema.activation_tokens[txn, oid]
                        else:
                            raise Exception('no such activation')

                    msg = 'code created {} ago has expired'.format(
                        passed_secs_str)
                    raise ApplicationError(
                        Authenticator.ERROR_AUTH_INVALID_ACT_CODE,
                        Authenticator.ERROR_AUTH_INVALID_ACT_CODE_MSG.format(
                            msg))

                # sanitize the stored activation info against what the client provided
                if activation.atype not in [
                        ActivationType.LOGIN, ActivationType.REGISTRATION
                ]:
                    msg = 'activation type "{}" is not for user login/registration.'.format(
                        activation.atype)
                    raise ApplicationError(
                        Authenticator.ERROR_AUTH_INVALID_ACT_CODE,
                        Authenticator.ERROR_AUTH_INVALID_ACT_CODE_MSG.format(
                            msg))

                if activation.email != authid:
                    msg = 'email associated with activation code does not match authid provided by client.'
                    raise ApplicationError(
                        Authenticator.ERROR_AUTH_INVALID_ACT_CODE,
                        Authenticator.ERROR_AUTH_INVALID_ACT_CODE_MSG.format(
                            msg))

                if activation.pubkey != pubkey:
                    msg = 'pubkey associated with activation code does not match pubkey provided by client.'
                    raise ApplicationError(
                        Authenticator.ERROR_AUTH_INVALID_ACT_CODE,
                        Authenticator.ERROR_AUTH_INVALID_ACT_CODE_MSG.format(
                            msg))

                activation.status = ActivationStatus.ACTIVE
                activation.activated = now

                # create user
                if is_new_user:
                    user = User()
                    user.oid = uuid.uuid4()
                    user.email = authid
                    user.registered = datetime.utcnow()

                    with self._db.begin(write=True) as txn:
                        self._schema.users[txn, user.oid] = user

                    self.log.info('New user stored in database:\n{user}',
                                  user=user)
                else:
                    self.log.info('User already stored in database:\n{user}',
                                  user=user)

                # update user-pubkey activation
                with self._db.begin(write=True) as txn:
                    oid = self._schema.idx_act_tokens_by_authid_pubkey[txn,
                                                                       authid +
                                                                       pubkey]
                    if oid:
                        self._schema.activation_tokens[txn, oid] = activation
                    else:
                        raise Exception('no such activation')

                # immediately auth user on global users realm
                auth = {
                    'pubkey': pubkey,
                    'realm': Authenticator.GLOBAL_USER_REALM,
                    'authid': authid,
                    'role': Authenticator.GLOBAL_USER_REALM_USER_ROLE,
                    'extra': None,
                    'cache': False
                }

                self.log.info(
                    'found principal for public key {pubkey} of {authid}',
                    pubkey=pubkey,
                    authid=auth['authid'])

                return auth

            else:
                raise Exception(
                    'internal error: unprocessed activation status {}'.format(
                        activation.status))
示例#5
0
 def test_parse_valid_activation_codes(self):
     for i in range(20):
         code = generate_activation_code()
         parsed_code = parse_activation_code(code)
         self.assertTupleEqual(tuple(code.split('-')), parsed_code.groups())
示例#6
0
    async def onJoin(self, details):
        self.log.debug("Connected:  {details}", details=details)

        self._cnt_received = 0
        N = 100

        def on_event(evt, counter, value3=None, details=None):
            self._cnt_received += 1
            if self._cnt_received % N == 0:
                self.log.info('Received {cnt} events so far ..',
                              cnt=self._cnt_received)

        sub = await self.subscribe(on_event,
                                   'com.example.geoservice.',
                                   options=SubscribeOptions(
                                       match='prefix', details_arg='details'))

        self.log.debug(
            'Subscribed to "com.example.geoservice." with prefix match: {sub}',
            sub=sub)

        self._cnt_sent = 0
        N = 100
        publish_options = PublishOptions(
            acknowledge=False,
            exclude_me=False,
            exclude=[1, 2, 3],
            exclude_authid=['badguy1', 'badguy2'],
            exclude_authrole=['hacker', 'fool'],
            # eligible=[1, 2, 3],
            # eligible_authid=['anonymous'],
            eligible_authrole=['anonymous'])

        while True:
            for j in range(10):
                category = random.choice(
                    ['alert', 'warning', 'info', 'ad', 'other'])
                x = random.randint(0, 100)
                y = random.randint(0, 100)
                value1 = os.urandom(16)
                value2 = random.random()
                value3 = util.generate_activation_code()

                evt = {
                    'category': category,
                    'x': x,
                    'y': y,
                    'value1': value1,
                    'value2': value2,
                    'value3': value3,
                    'i': self._cnt_sent,
                    'j': j,
                }
                topic = 'com.example.geoservice.{}.{}.{}'.format(
                    category, x, y)

                # self.publish(topic, evt, self._cnt_sent, value3=value3)
                # await self.publish(topic, evt, self._cnt_sent, value3=value3, options=publish_options)
                self.publish(topic,
                             evt,
                             self._cnt_sent,
                             value3=value3,
                             options=publish_options)

                self._cnt_sent += 1
                if self._cnt_sent % N == 0:
                    self.log.info('published {cnt} events ..',
                                  cnt=self._cnt_sent)

            await sleep(.1)