Yubico / python-yubico

Python code to talk to YubiKeys
https://developers.yubico.com/python-yubico/
BSD 2-Clause "Simplified" License
229 stars 33 forks source link

Repeated YubiKey reconnection when using Python3-Yubico and Python3-pyudev #46

Open yaiqsa opened 4 years ago

yaiqsa commented 4 years ago

I'm working on a Python3 script where I monitor if a specific YubiKey is connected. To do this I run a pyudev monitor that looks for any hidraw device(like keyboards, mice, and YubiKeys) and then calls the yubico.find_yubikey() function. The idea is that I don't want to poll every few seconds, but first wait for hid connectivity. The issue is that when i do so, the YubiKey immediately reconnects, resulting in an endless loop.

For me it doesn't always happen, to trigger this behaviour I sometimes have to plug one key in and out a few times, or when i plug in multiple ones it seems to trigger more often. I included the code and the result this had for me below.

Please correct me if this is problem is not a result of the Yubico library.

I tested this with the following specs: YubiKey: 4.2.6 and 4.2.6 Nano (both with vendor id 1050 and product id 407) OS: Debian Buster (10.3) and Raspbian Buster (10.3) Python version: 3.7.3 pyudev version: python3-pyudev_0.21.0-1 Yubico version: python3-yubico_1.3.3-0.2

Code:

#!/usr/bin/env python3
import pyudev, yubico
from usb.core import USBError

def get_yubikey_serial() -> int:
    try:
        YK = yubico.find_yubikey()
        serial = YK.serial() 
        print('yubikey connected, serial= %i' % serial)
        del YK
        return serial
    except yubico.yubico_exception.YubicoError as e:
        print('no yubikey connected')
        return 0
    except USBError as e:
        print('get_yubikey_serial() threw: ' + str(e))
        return 1

context = pyudev.Context()
monitor = pyudev.Monitor.from_netlink(context)
monitor.filter_by('hidraw') 
lastdevice = 'hidraw-2'

for device in iter(monitor.poll, None):
    if device.sys_name[:6] == 'hidraw':
        if abs(int(device.sys_name[6:]) - int(lastdevice[6:])) == 1 : continue
        lastdevice = device.sys_name
        get_yubikey_serial()

Output:

yubikey connected, serial= 4130312
yubikey connected, serial= 4130312
yubikey connected, serial= 4130312
yubikey connected, serial= 4130312
yubikey connected, serial= 4130312
yubikey connected, serial= 4130312
get_yubikey_serial() threw: [Errno 32] Pipe error
get_yubikey_serial() threw: [Errno 32] Pipe error
no yubikey connected
no yubikey connected
no yubikey connected
no yubikey connected
no yubikey connected
no yubikey connected