Example #1
0
def on_waptclient_connect():
    try:
        uuid = request.args.get('uuid', None)
        if not uuid:
            raise EWaptForbiddden('Missing source host uuid')
        allow_unauthenticated_connect = app.conf.get(
            'allow_unauthenticated_connect', False)
        if not allow_unauthenticated_connect:
            try:
                token_gen = get_secured_token_generator()
                token_data = token_gen.loads(request.args['token'])
                uuid = token_data.get('uuid', None)
                if not uuid:
                    raise EWaptAuthenticationFailure('Bad host UUID')
                if token_data['server_uuid'] != get_server_uuid():
                    raise EWaptAuthenticationFailure('Bad server UUID')
            except Exception as e:
                raise EWaptAuthenticationFailure(
                    u'SocketIO connection not authorized, invalid token: %s' %
                    e)
            logger.info(
                u'Socket.IO connection from wapt client sid %s (uuid: %s fqdn:%s)'
                % (request.sid, uuid, token_data.get('computer_fqdn')))
        else:
            logger.info(
                u'Unauthenticated Socket.IO connection from wapt client sid %s (uuid: %s)'
                % (request.sid, uuid))

        with WaptDB():
            # update the db
            with wapt_db.atomic() as trans:
                # stores sid in database
                hostcount = Hosts.update(
                    server_uuid=get_server_uuid(),
                    listening_protocol='websockets',
                    listening_address=request.sid,
                    listening_timestamp=datetime2isodate(),
                    last_seen_on=datetime2isodate()).where(
                        Hosts.uuid == uuid).execute()
                # if not known, reject the connection
                if hostcount == 0:
                    raise EWaptForbiddden('Host is not registered')

            session['uuid'] = uuid
        return True

    except Exception as e:
        if 'uuid' in session:
            session.pop('uuid')
        logger.warning(
            u'SocketIO connection refused for uuid %s, sid %s: %s, instance %s'
            % (uuid, request.sid, e, app.conf.get('application_root')))
        disconnect()
        return False
Example #2
0
def on_wapt_pong():
    uuid = None
    try:
        uuid = session.get('uuid')
        if not uuid:
            logger.critical(u'SocketIO %s connected but no host uuid in session: asking connected host to reconnect' % (request.sid))
            emit('wapt_force_reconnect')
            return False
        else:
            logger.debug(u'Socket.IO pong from wapt client sid %s (uuid: %s)' % (request.sid, session.get('uuid',None)))
            # stores sid in database
            try:
                if wapt_db.is_closed():
                    wapt_db.connect()
                with wapt_db.atomic() as trans:
                    hostcount = Hosts.update(
                        server_uuid=get_server_uuid(),
                        listening_timestamp=datetime2isodate(),
                        listening_protocol='websockets',
                        listening_address=request.sid,
                        reachable='OK',
                    ).where(Hosts.uuid == uuid).execute()
                    # if not known, reject the connection
                    if hostcount == 0:
                        logger.warning(u'SocketIO sid %s connected but no match in database for uuid %s : asking to reconnect' % (request.sid,uuid))
                        emit('wapt_force_reconnect')
                        return False
            finally:
                if not wapt_db.is_closed():
                    wapt_db.close()
            return True
    except Exception as e:
        logger.critical(u'SocketIO pong error for uuid %s and sid %s : %s, instance: %s' % (uuid,request.sid,traceback.format_exc(),app.conf.get('application_root')))
        return False
Example #3
0
def proxy_host_request(request, action):
    """Proxy a waptconsole action to wapt clients using websockets

    Args:
        uuid: can be a list or a single uuid
        notify_user: 0/1
        notify_server: 0/1

    Returns:
        dict:
            'result':
                'success' (list)
                'errors' (list)
            'msg' (str)
            'success'(bool)
            'request_time' (float)
            'error_code'
    """
    try:
        start_time = time.time()
        all_args = {k: v for k, v in request.args.iteritems()}
        if request.json:
            all_args.update(request.json)

        uuids = ensure_list(all_args['uuid'])
        del(all_args['uuid'])
        timeout = float(request.args.get('timeout', app.conf.get('clients_read_timeout', 5)))

        result = dict(success=[], errors=[])
        tasks = []
        for uuid in uuids:
            try:
                host_data = Hosts\
                    .select(Hosts.uuid, Hosts.computer_fqdn,
                            Hosts.server_uuid,
                            Hosts.listening_address,
                            Hosts.listening_port,
                            Hosts.listening_protocol,
                            Hosts.listening_timestamp,
                            )\
                    .where((Hosts.server_uuid == get_server_uuid()) & (Hosts.uuid == uuid) & (~Hosts.listening_address.is_null()) & (Hosts.listening_protocol == 'websockets'))\
                    .dicts()\
                    .first(1)

                if host_data and host_data.get('listening_address', None):
                    msg = u''
                    logger.info(
                        'Launching %s with args %s for %s at address %s...' %
                        (action, all_args, uuid, host_data['listening_address']))

                    args = dict(all_args)
                    sid = host_data['listening_address']
                    computer_fqdn = host_data['computer_fqdn']

                    def emit_action(sid, uuid, action, action_args, computer_fqdn, timeout=5):
                        try:
                            got_result = []

                            def result_callback(data):
                                got_result.append(data)

                            logger.debug(u'Emit %s to %s (%s)' % (action, uuid, computer_fqdn))
                            socketio.emit(action, action_args, room=sid, callback=result_callback)
                            # wait for asynchronous answer...
                            wait_loop = timeout * 20
                            while not got_result:
                                wait_loop -= 1
                                if wait_loop < 0:
                                    raise EWaptTimeoutWaitingForResult(u'Timeout, client did not send result within %s s' % timeout)
                                socketio.sleep(0.05)

                            # action succedded
                            result['success'].append(
                                dict(
                                    uuid=uuid,
                                    msg=msg,
                                    computer_fqdn=computer_fqdn,
                                    result=got_result[0],
                                ))
                        except Exception as e:
                            result['errors'].append(
                                dict(
                                    uuid=uuid,
                                    msg='%s' % repr(e),
                                    computer_fqdn='',
                                ))
                    if sid:
                        tasks.append(socketio.start_background_task(
                            emit_action, sid=sid, uuid=uuid, action=action, action_args=args, computer_fqdn=computer_fqdn))

                else:
                    result['errors'].append(
                        dict(
                            uuid=uuid,
                            msg=u'Host %s is not registered or not connected wia websockets' % uuid,
                            computer_fqdn='',
                        ))
            except Exception as e:
                result['errors'].append(
                    dict(
                        uuid=uuid,
                        msg=u'Host %s error %s' % (uuid, repr(e)),
                        computer_fqdn='',
                    ))

        # wait for all background tasks to terminate or timeout...
        # assume the timeout should be longer if more hosts to perform
        wait_loop = timeout * len(tasks)
        while True:
            running = [t for t in tasks if t.is_alive()]
            if not running:
                break
            wait_loop -= 1
            if wait_loop < 0:
                break
            socketio.sleep(0.05)

        msg = ['Success : %s, Errors: %s' % (len(result['success']), len(result['errors']))]
        if result['errors']:
            msg.extend(['%s: %s' % (e['computer_fqdn'], e['msg'])
                        for e in result['errors']])

        return make_response(result,
                             msg='\n- '.join(msg),
                             success=len(result['success']) > 0,
                             request_time=time.time() - start_time)
    except Exception as e:
        return make_response_from_exception(e)
Example #4
0
File: auth.py Project: fabadja/WAPT
def check_auth( username=None, password = None, request = None,
                session=None, methods=['admin','ldap','session']):
    """This function is called to check if a username /
    password combination is valid or to get already authenticated username
    from session argument.

    If no username or password, use session.authorization header if available.

    Args:
        username (str):
        password (str):
        request (Flask.Request) : request where to lookup authrization basic header
        session (Flask.Session) where to lookup session user
        methods (list of str) : list of auth method to try until one is successfull
                               'session': use current session user if it matches username
                               'admin':
                               'ldap':
                               'kerb':
                               'ssl':
                               'passwd':



    Returns:
        dict (auth_method = auth_method,user=auth_user,auth_date=auth_date)
             None if auth is not successfull

    """
    if username is None and password is None and request is not None and request.authorization:
        username = request.authorization.username
        password = request.authorization.password

    auth_method = None
    auth_user = None
    auth_date = None

    assert(isinstance(methods,list))

    for method in methods:
        if method == 'session' and session:
            session_user = session.get('user',None)
            if session_user and (username is None or username == session_user):
                auth_user = session_user
                auth_date = session.get('auth_date',None)
                auth_method = method
                logger.debug(u'User %s authenticated using session cookie' % (username,))

        elif method == 'passwd' and valid_username(username) and username != app.conf['wapt_user'] and password is not None:
                # local htpasswd user/passwd file for add_host registration action
                if app.conf.get('htpasswd_path'):
                    htpasswd_users = HtpasswdFile(app.conf.get('htpasswd_path'))
                    if htpasswd_users.verify(username,password):
                        auth_method = method
                        auth_user = username
                        auth_date = datetime.datetime.utcnow().isoformat()
                        logger.debug(u'User %s authenticated using htpasswd %s' % (username,htpasswd_users))
                    else:
                        logger.debug(u'user %s htpasswd %s verification failed' % (username,htpasswd_users))

        elif method == 'admin' and valid_username(username) and app.conf['wapt_user'] == username and password is not None:
                pbkdf2_sha256_ok = False
                pass_sha512_crypt_ok = False
                pass_bcrypt_crypt_ok = False

                if '$pbkdf2-sha256$' in app.conf['wapt_password']:
                    pbkdf2_sha256_ok = pbkdf2_sha256.verify(password, app.conf['wapt_password'])
                elif sha512_crypt.identify(app.conf['wapt_password']):
                    pass_sha512_crypt_ok = sha512_crypt.verify(
                        password,
                        app.conf['wapt_password'])
                else:
                    try:
                        if bcrypt.identify(app.conf['wapt_password']):
                            pass_bcrypt_crypt_ok = bcrypt.verify(
                                password,
                                app.conf['wapt_password'])
                    except Exception:
                        pass

                if pbkdf2_sha256_ok or pass_sha512_crypt_ok or pass_bcrypt_crypt_ok:
                    auth_method = method
                    auth_user = username
                    auth_date = datetime.datetime.utcnow().isoformat()
                else:
                    logger.debug(u'wapt admin passwd verification failed')

        elif method == 'token':
            # token auth
            token_secret_key = app.conf['secret_key']
            if token_secret_key:
                # check if there is a valid token in the password
                try:
                    token_gen = get_secured_token_generator(token_secret_key)
                    # check if there is a Bearer, else use Basic / password
                    authorization = request.headers.get('Authorization')
                    if authorization and authorization.startswith('Bearer '):
                        token_data = token_gen.loads(authorization.split(' ',1)[1])
                    elif password is not None:
                        token_data = token_gen.loads(password)
                    else:
                        raise EWaptAuthenticationFailure('No token')

                    uuid = token_data.get('uuid', token_data.get('user',None))
                    if not uuid:
                        raise EWaptAuthenticationFailure('Bad token UUID')
                    if token_data['server_uuid'] != get_server_uuid():
                        raise EWaptAuthenticationFailure('Bad server UUID')
                    auth_method = method
                    auth_user = uuid
                    auth_date =  datetime.datetime.fromtimestamp(token_data['iat']).isoformat()
                    logger.debug(u'User %s authenticated using token' % (uuid,))
                except Exception as e:
                    logger.debug(u'Token verification failed : %s' % repr(e))
                    pass

        elif method == 'kerb' and app.conf['use_kerberos']:
            # with nginx kerberos module, auth user name is stored as Basic auth in the
            # 'Authorisation' header with password 'bogus_auth_gss_passwd'

            # Kerberos auth negociated by nginx
            if username != '' and password == 'bogus_auth_gss_passwd':
                authenticated_user = username.lower().replace('$', '')
                auth_method = method
                auth_user = authenticated_user
                auth_date = datetime.datetime.utcnow().isoformat()
                logger.debug(u'User %s authenticated using kerberos' % (authenticated_user,))

        elif method == 'ldap' and valid_username(username) and password is not None:
            if auth_module_ad is not None and (app.conf['wapt_user'] != username and
                    auth_module_ad.check_credentials_ad(app.conf, username, password)):
                auth_method = method
                auth_user = username
                auth_date = datetime.datetime.utcnow().isoformat()
                logger.debug(u'User %s authenticated using LDAP' % (username,))

        # nginx ssl auth.
        elif method == 'ssl' and request and app.conf['use_ssl_client_auth'] and request.headers.get('X-Ssl-Authenticated', None) == 'SUCCESS':
            dn = request.headers.get('X-Ssl-Client-Dn', None)
            if dn:
                auth_method = method
                # strip CN= if no other suffix.
                if dn.upper().startswith('CN='):
                    auth_user = dn.split('=',1)[1]
                else:
                    auth_user = dn
                auth_date = datetime.datetime.utcnow().isoformat()
                logger.debug(u'User %s authenticated using SSL client certificate' % (dn,))

        if auth_method and auth_user:
            break

    #only session and admin methods are ok for the embedded wapt admin password based account.
    if auth_method and auth_user and (auth_user != app.conf['wapt_user'] or auth_method in ('session','admin')):
        return dict(auth_method = auth_method,user=auth_user,auth_date=auth_date)
    else:
        return None