Esempio n. 1
0
def setup_otp(**kwargs):
    """
    Setup OTP for the currently logged in user

    Variables:
    None

    Arguments: 
    None

    Data Block:
    None

    Result example:
    {
     "qrcode": <qrcode binary>,
     "otp_url": 'otpauth://totp/Assemblyline:{uname}?secret={secret_key}&issuer={site}',
     "secret_key": <SECRET KEY>
    }
    """
    uname = kwargs['user']['uname']

    user_data = STORAGE.user.get(uname)
    if user_data.otp_sk is not None:
        return make_api_response("",
                                 err="OTP already set for this user",
                                 status_code=400)

    secret_key = generate_random_secret()
    otp_url = 'otpauth://totp/{site}:{uname}?secret={secret_key}&issuer={site}'.format(
        uname=uname, secret_key=secret_key, site=config.ui.fqdn)
    qc_stream = BytesIO()
    temp_qrcode = pyqrcode.create(otp_url)
    temp_qrcode.svg(qc_stream, scale=3)

    flsk_session['temp_otp_sk'] = secret_key

    return make_api_response({
        'qrcode': qc_stream.getvalue().decode('utf-8'),
        'otp_url': otp_url,
        'secret_key': secret_key
    })
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}")
Esempio n. 3
0
def login(**_):
    """
    Login the user onto the system
    
    Variables:
    None
    
    Arguments: 
    None
    
    Data Block:
    {
     "user": <UID>,
     "password": <ENCRYPTED_PASSWORD>,
     "otp": <OTP_TOKEN>,
     "apikey": <ENCRYPTED_APIKEY>,
     "webauthn_auth_resp": <RESPONSE_TO_CHALLENGE_FROM_WEBAUTHN>
    }

    Result example:
    {
     "username": <Logged in user>, # Username for the logged in user
     "privileges": ["R", "W"],     # Different privileges that the user will get for this session
     "session_duration": 60        # Time after which this session becomes invalid
                                   #   Note: The timer reset after each call
    }
    """
    data = request.json
    if not data:
        data = request.values

    user = data.get('user', None)
    password = data.get('password', None)
    apikey = data.get('apikey', None)
    webauthn_auth_resp = data.get('webauthn_auth_resp', None)
    oauth_provider = data.get('oauth_provider', None)
    oauth_token = data.get('oauth_token', None)

    if config.auth.oauth.enabled and oauth_provider:
        oauth = current_app.extensions.get('authlib.integrations.flask_client')
        provider = oauth.create_client(oauth_provider)

        if provider:
            redirect_uri = f'https://{request.host}/login.html?provider={oauth_provider}'
            return provider.authorize_redirect(redirect_uri=redirect_uri)

    try:
        otp = int(data.get('otp', 0) or 0)
    except Exception:
        raise AuthenticationException('Invalid OTP token')

    if (user and password) or (user and apikey) or (user and oauth_token):
        auth = {
            'username': user,
            'password': password,
            'otp': otp,
            'webauthn_auth_resp': webauthn_auth_resp,
            'apikey': apikey,
            'oauth_token': oauth_token
        }

        logged_in_uname = None
        ip = request.headers.get("X-Forwarded-For", request.remote_addr)
        try:
            logged_in_uname, priv = default_authenticator(
                auth, request, flsk_session, STORAGE)
            session_duration = config.ui.session_duration
            cur_time = now()
            xsrf_token = generate_random_secret()
            current_session = {
                'duration': session_duration,
                'ip': ip,
                'privileges': priv,
                'time': int(cur_time) - (int(cur_time) % session_duration),
                'user_agent': request.headers.get("User-Agent", None),
                'username': logged_in_uname,
                'xsrf_token': xsrf_token
            }
            session_id = hashlib.sha512(
                str(current_session).encode("UTF-8")).hexdigest()
            current_session['expire_at'] = cur_time + session_duration
            flsk_session['session_id'] = session_id
            KV_SESSION.add(session_id, current_session)
            return make_api_response(
                {
                    "username": logged_in_uname,
                    "privileges": priv,
                    "session_duration": session_duration
                },
                cookies={'XSRF-TOKEN': xsrf_token})
        except AuthenticationException as wpe:
            uname = auth.get('username', '(None)')
            LOGGER.warning(
                f"Authentication failure. (U:{uname} - IP:{ip}) [{wpe}]")
            return make_api_response("", err=str(wpe), status_code=401)
        finally:
            if logged_in_uname:
                LOGGER.info(
                    f"Login successful. (U:{logged_in_uname} - IP:{ip})")

    return make_api_response(
        "", "Not enough information to proceed with authentication", 401)
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")