Esempio n. 1
0
def validate_otp(token, **kwargs):
    """
    Validate newly setup OTP token

    Variables:
    token     => Current token for temporary OTP sercret key

    Arguments:
    None

    Data Block:
    None

    Result example:
    {
     "success": true
    }
    """
    uname = kwargs['user']['uname']
    user_data = STORAGE.user.get(uname)

    try:
        token = int(token)
    except ValueError:
        return make_api_response({'success': False},
                                 err="This is not a valid OTP token",
                                 status_code=400)

    secret_key = flsk_session.pop('temp_otp_sk', None)
    if secret_key and get_totp_token(secret_key) == token:
        user_data.otp_sk = secret_key
        STORAGE.user.save(uname, user_data)
        return make_api_response({'success': True})
    else:
        flsk_session['temp_otp_sk'] = secret_key
        return make_api_response({'success': False},
                                 err="OTP token does not match secret key",
                                 status_code=400)
Esempio n. 2
0
    def do_user(self, args):
        """
        Perform operation on a user in the system

        Usage:
            user list
                 show        <uname>
                 disable     <uname>
                 enable      <uname>
                 set_admin   <uname>
                 unset_admin <uname>
                 remove      <uname>
                 set_otp     <uname>
                 unset_otp   <uname>
                 show_otp    <uname>

        Actions:
            list         List all the users
            show         Describe a user
            disable      Disable a user
            enable       Enable a user
            set_admin    Grant a user admin privileges
            unset_admin  Revoke a user's admin privileges
            remove       Remove a user
            set_otp      Generate a new random OTP secret key for user
            unset_otp    Remove OTP Secret Token
            show_otp     Show current OTP Token

        Parameters:
            <uname>      Username of the user to perform the action on


        Examples:
            # Disable user 'user'
            user disable user
        """
        valid_actions = [
            'list', 'show', 'disable', 'enable', 'remove', 'set_admin',
            'unset_admin', 'set_otp', 'unset_otp', 'show_otp'
        ]
        args = self._parse_args(args)

        if len(args) == 1:
            action_type = args[0]
            item_id = None
        elif len(args) == 2:
            action_type, item_id = args
        else:
            self._print_error("Wrong number of arguments for user command.")
            return

        if action_type not in valid_actions:
            self._print_error("Invalid action for user command.")
            return

        users = self.datastore.get_collection('user')

        if action_type == 'list':
            for key in users.keys():
                self.logger.info(key)
            return
        if item_id:
            item = users.get(item_id)
            if item is None:
                self.logger.warn(f"{item_id} does not exist")
                return
        else:
            self._print_error("Invalid command parameters")
            return

        if action_type == 'show':
            output = io.StringIO()
            yaml.safe_dump(item.as_primitives(), output)
            self.logger.info(output.getvalue())
        elif action_type == 'disable':
            item.is_active = False
            users.save(item_id, item)
            self.logger.info(f"{item_id} was disabled")
        elif action_type == 'enable':
            item.is_active = True
            users.save(item_id, item)
            self.logger.info(f"{item_id} was enabled")
        elif action_type == 'set_admin':
            if 'admin' not in item.type:
                item.type.append('admin')
                users.save(item_id, item)
            self.logger.info(f"Granted admin privileges to {item_id}")
        elif action_type == 'unset_admin':
            if 'admin' in item.type:
                item.type.remove('admin')
                users.save(item_id, item)
            self.logger.info(f"Admin privileges revoked for {item_id}")
        elif action_type == 'remove':
            users.delete(item_id)
            self.logger.info(f"User '{item_id}' removed.")
        elif action_type == 'unset_otp':
            item.otp_sk = None
            users.save(item_id, item)
            self.logger.info(f"{item_id} OTP secret key was removed")
        elif action_type == 'set_otp':
            item.otp_sk = generate_random_secret()
            users.save(item_id, item)
            self.logger.info(f"{item_id} OTP secret key is now: {item.otp_sk}")
        elif action_type == 'show_otp':
            if item.otp_sk:
                try:
                    while True:
                        self.logger.info(
                            '\r{!s} OTP Token:   {:06d}   {:░<30}'.format(
                                item_id, get_totp_token(item.otp_sk),
                                "█" * int(time.time() % 30)),
                            end=''),
                        sys.__stdout__.flush()
                        time.sleep(1)
                except KeyboardInterrupt:
                    self.logger.info('')
            else:
                self.logger.warn(f"2FA not enabled for user {item_id}")
def validate_2fa(username, otp_token, state, webauthn_auth_resp, storage):
    security_token_enabled = False
    otp_enabled = False
    security_token_error = False
    otp_error = False
    report_errors = False

    # Get user
    user_data = storage.user.get(username)

    # Test Security Tokens
    if config.auth.allow_security_tokens:
        security_tokens = user_data.security_tokens

        credentials = [AttestedCredentialData(websafe_decode(x)) for x in security_tokens.values()]
        if credentials:
            # Security tokens are enabled for user
            security_token_enabled = True
            report_errors = True
            if state and webauthn_auth_resp:
                data = cbor.decode(bytes(webauthn_auth_resp))
                credential_id = data['credentialId']
                client_data = ClientData(data['clientDataJSON'])
                auth_data = AuthenticatorData(data['authenticatorData'])
                signature = data['signature']

                try:
                    server.authenticate_complete(state, credentials, credential_id, client_data, auth_data, signature)
                    return
                except Exception:
                    security_token_error = True

    # Test OTP
    if config.auth.allow_2fa:
        otp_sk = user_data.otp_sk
        if otp_sk:
            # OTP is enabled for user
            otp_enabled = True
            report_errors = True
            if otp_token:
                if get_totp_token(otp_sk) != otp_token:
                    otp_error = True
                else:
                    return

    if report_errors:
        if security_token_error:
            # Wrong response to challenge
            raise AuthenticationException("Wrong Security Token")
        elif otp_error:
            # Wrong token provided
            raise AuthenticationException("Wrong OTP token")
        elif security_token_enabled:
            # No challenge/response provided and security tokens are enabled
            raise AuthenticationException("Wrong Security Token")
        elif otp_enabled:
            # No OTP Token provided and OTP is enabled
            raise AuthenticationException("Wrong OTP token")

        # This should never hit
        raise AuthenticationException("Unknown 2FA Authentication error")
Esempio n. 4
0
    def do_user(self, args):
        """
        Perform operation on a user in the system

        Usage:
            user list
                 show        <uname>
                 disable     <uname>
                 enable      <uname>
                 set_admin   <uname>
                 unset_admin <uname>
                 remove      <uname>
                 set_otp     <uname>
                 unset_otp   <uname>
                 show_otp    <uname>

        Actions:
            list         List all the users
            show         Describe a user
            disable      Disable a user
            enable       Enable a user
            set_admin    Make a user admin
            unset_admin  Remove admin priviledges to a user
            remove       Remove a user
            set_otp      Generate a new random OTP secret key for user
            unset_otp    Remove OTP Secret Token
            show_otp     Show current OTP Token

        Parameters:
            <uname>      Username of the user to perform the action on


        Examples:
            # Disable user 'user'
            user disable user
        """
        valid_actions = ['list', 'show', 'disable', 'enable', 'remove',
                         'set_admin', 'unset_admin', 'set_otp', 'unset_otp', 'show_otp']
        args = self._parse_args(args)

        if len(args) == 1:
            action_type = args[0]
            item_id = None
        elif len(args) == 2:
            action_type, item_id = args
        else:
            self._print_error("Wrong number of arguments for user command.")
            return

        if action_type not in valid_actions:
            self._print_error("Invalid action for user command.")
            return

        users = self.datastore.get_collection('user')

        if action_type == 'list':
            for key in users.keys():
                self.logger.info(key)
        elif action_type == 'show' and item_id:
            self.logger.info(pformat(users.get(item_id, as_obj=False)))
        elif action_type == 'disable' and item_id:
            item = users.get(item_id)
            if item:
                item.is_active = False
                users.save(item_id, item)
                self.logger.info(f"{item_id} was disabled")
            else:
                self.logger.warn(f"{item_id} does not exist")
        elif action_type == 'enable' and item_id:
            item = users.get(item_id)
            if item:
                item.is_active = True
                users.save(item_id, item)
                self.logger.info(f"{item_id} was enabled")
            else:
                self.logger.warn(f"{item_id} does not exist")
        elif action_type == 'set_admin' and item_id:
            item = users.get(item_id)
            if item:
                if 'admin' not in item.type:
                    item.type.append('admin')
                users.save(item_id, item)
                self.logger.info(f"{item_id} was added admin priviledges")
            else:
                self.logger.warn(f"{item_id} does not exist")
        elif action_type == 'unset_admin' and item_id:
            item = users.get(item_id)
            if item:
                item.type.pop('admin', None)
                users.save(item_id, item)
                self.logger.info(f"{item_id} was removed admin priviledges")
            else:
                self.logger.warn(f"{item_id} does not exist")
        elif action_type == 'remove' and item_id:
            users.delete(item_id)
            self.logger.info(f"User '{item_id}' removed.")
        elif action_type == 'unset_otp' and item_id:
            item = users.get(item_id, as_obj=False)
            if item:
                item.pop('otp_sk', None)
                users.save(item_id, item)
                self.logger.info(f"{item_id} OTP secret key was removed")
            else:
                self.logger.warn(f"{item_id} does not exist")
        elif action_type == 'set_otp' and item_id:
            item = users.get(item_id)
            if item:
                item.otp_sk = generate_random_secret()
                users.save(item_id, item)
                self.logger.info(f"{item_id} OTP secret key is now: {item.otp_sk}")
            else:
                self.logger.warn(f"{item_id} does not exist")
        elif action_type == 'show_otp' and item_id:
            item = users.get(item_id)
            if item:
                if item.otp_sk:
                    while True:
                        self.logger.info('\r%s OTP Token:   %06d   %s%s' % (item_id, get_totp_token(item.otp_sk),
                                                                            "█" * int(time.time() % 30),
                                                                            "░" * (29 - int(time.time() % 30)))),
                        sys.__stdout__.flush()

                        time.sleep(1)
                else:
                    self.logger.warn(f"2FA not enabled for user {item_id}")
            else:
                self.logger.warn(f"{item_id} does not exist")
        else:
            self._print_error("Invalid command parameters")