Projet

Général

Profil

0001-misc-fix-locking-in-clean_nonces-47122.patch

Benjamin Dauvergne, 29 septembre 2020 14:39

Télécharger (4,21 ko)

Voir les différences:

Subject: [PATCH] misc: fix locking in clean_nonces (#47122)

 tests/test_api.py       | 23 ++++++++++++++++-------
 wcs/qommon/publisher.py | 24 ++++++++++--------------
 2 files changed, 26 insertions(+), 21 deletions(-)
tests/test_api.py
296 296
    assert [x['slug'] for x in output.json['user_roles']] == ['foo-bar']
297 297

  
298 298

  
299
def test_is_url_signed_check_nonce(pub, local_user):
299
def test_is_url_signed_check_nonce(pub, local_user, freezer):
300 300
    ORIG = 'xxx'
301 301
    KEY = 'xxx'
302 302

  
......
306 306
    # test clean_nonces do not bark when nonces directory is empty
307 307
    if os.path.exists(os.path.join(pub.app_dir, 'nonces')):
308 308
        shutil.rmtree(os.path.join(pub.app_dir, 'nonces'))
309
    pub.clean_nonces()
309
    pub.clean_nonces(now=0)
310
    nonce_dir = os.path.join(pub.app_dir, 'nonces')
311
    assert not os.path.exists(nonce_dir) or not os.listdir(nonce_dir)
310 312
    signed_url = sign_url('?format=json&orig=%s&email=%s'
311 313
                          % (ORIG, urllib.quote(local_user.email)), KEY)
312 314
    req = HTTPRequest(None, {'SCRIPT_NAME': '/',
......
322 324
        is_url_signed()
323 325
    assert exc_info.value.public_msg == 'nonce already used'
324 326
    # test that clean nonces works
325
    assert os.listdir(os.path.join(pub.app_dir, 'nonces'))
326
    pub.clean_nonces(delta=0)
327
    assert os.listdir(os.path.join(pub.app_dir, 'nonces'))
328
    pub.clean_nonces(delta=0, now=time.time() + 2 * DEFAULT_DURATION)
329
    assert not os.listdir(os.path.join(pub.app_dir, 'nonces'))
327
    pub.clean_nonces()
328
    assert os.listdir(nonce_dir)
329

  
330
    # 80 seconds in the future, nothing should be cleaned
331
    freezer.move_to(datetime.timedelta(seconds=80))
332
    pub.clean_nonces()
333
    assert os.listdir(nonce_dir)
334

  
335
    # 90 seconds in the future, nonces should be removed
336
    freezer.move_to(datetime.timedelta(seconds=10))
337
    pub.clean_nonces()
338
    assert not os.listdir(nonce_dir)
330 339

  
331 340

  
332 341
def test_get_user_compat_endpoint(pub, local_user):
wcs/qommon/publisher.py
62 62
import logging.handlers
63 63
from . import logger
64 64
from . import storage
65
from .vendor import locket
65 66

  
66 67

  
67 68
class ImmediateRedirectException(Exception):
......
571 572

  
572 573
    def clean_nonces(self, delta=60, now=None):
573 574
        nonce_dir = os.path.join(get_publisher().app_dir, 'nonces')
574
        now = now or time.time()
575 575
        if not os.path.exists(nonce_dir):
576 576
            return
577 577
        cleaning_lock_file = os.path.join(self.app_dir, 'cleaning_nonces.lock')
578
        fd = os.open(cleaning_lock_file, os.O_RDONLY | os.O_CREAT, 0o666)
579 578
        try:
580
            fcntl.flock(fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
581
        except IOError:
582
            # lock is currently held, that is fine.
583
            return
584
        try:
585
            for nonce in os.listdir(nonce_dir):
586
                nonce_path = os.path.join(nonce_dir, nonce)
587
                # we need delta so that os.utime in is_url_signed has time to update file timestamp
588
                if delta < now - os.stat(nonce_path)[8]:
589
                    os.unlink(nonce_path)
590
        finally:
591
            os.close(fd)
579
            now = now or time.time()
580
            with locket.lock_file(cleaning_lock_file, timeout=0):
581
                for nonce in os.listdir(nonce_dir):
582
                    nonce_path = os.path.join(nonce_dir, nonce)
583
                    # we need delta so that os.utime in is_url_signed has time to update file timestamp
584
                    if delta < now - os.stat(nonce_path)[8]:
585
                        os.unlink(nonce_path)
586
        except locket.LockError:
587
            pass
592 588

  
593 589
    def clean_sessions(self):
594 590
        cleaning_lock_file = os.path.join(self.app_dir, 'cleaning_sessions.lock')
595
-