def check_yubikey_pass(passw): """ if the Token has set a PIN the user must also enter the PIN for authentication! This checks the output of a yubikey in AES mode without providing the serial number. The first 12 (of 44) or 16 of 48) characters are the tokenid, which is stored in the tokeninfo yubikey.tokenid or the prefix yubikey.prefix. :param passw: The password that consist of the static yubikey prefix and the otp :type passw: string :return: True/False and the User-Object of the token owner :rtype: dict """ opt = {} res = False token_list = [] # strip the yubico OTP and the PIN prefix = passw[:-32][-16:] from privacyidea.lib.token import get_tokens from privacyidea.lib.token import check_token_list # See if the prefix matches the serial number if prefix[:2] != "vv" and prefix[:2] != "cc": try: # Keep the backward compatibility serialnum = "UBAM" + modhex_decode(prefix) for i in range(1, 3): s = "{0!s}_{1!s}".format(serialnum, i) toks = get_tokens(serial=s, tokentype='yubikey') token_list.extend(toks) except TypeError as exx: # pragma: no cover log.error("Failed to convert serialnumber: {0!r}".format(exx)) # Now, we see, if the prefix matches the new version if not token_list: # If we did not find the token via the serial number, we also # search for the yubikey.prefix in the tokeninfo. token_candidate_list = get_tokens( tokentype='yubikey', tokeninfo={"yubikey.prefix": prefix}) token_list.extend(token_candidate_list) if not token_list: opt['action_detail'] = ( "The prefix {0!s} could not be found!".format(prefix)) return res, opt (res, opt) = check_token_list(token_list, passw, allow_reset_all_tokens=True) return res, opt
def check_yubikey_pass(passw): """ if the Token has set a PIN the user must also enter the PIN for authentication! This checks the output of a yubikey in AES mode without providing the serial number. The first 12 (of 44) or 16 of 48) characters are the tokenid, which is stored in the tokeninfo yubikey.tokenid or the prefix yubikey.prefix. :param passw: The password that consist of the static yubikey prefix and the otp :type passw: string :return: True/False and the User-Object of the token owner :rtype: dict """ opt = {} res = False token_list = [] # strip the yubico OTP and the PIN prefix = passw[:-32][-16:] from privacyidea.lib.token import get_tokens from privacyidea.lib.token import check_token_list # See if the prefix matches the serial number if prefix[:2] != "vv" and prefix[:2] != "cc": try: # Keep the backward compatibility serialnum = "UBAM" + modhex_decode(prefix) for i in range(1, 3): s = "{0!s}_{1!s}".format(serialnum, i) toks = get_tokens(serial=s, tokentype='yubikey') token_list.extend(toks) except TypeError as exx: # pragma: no cover log.error("Failed to convert serialnumber: {0!r}".format(exx)) # Now, we see, if the prefix matches the new version if not token_list: # If we did not find the token via the serial number, we also # search for the yubikey.prefix in the tokeninfo. token_candidate_list = get_tokens(tokentype='yubikey', tokeninfo={"yubikey.prefix": prefix}) token_list.extend(token_candidate_list) if not token_list: opt['action_detail'] = ("The prefix {0!s} could not be found!".format( prefix)) return res, opt (res, opt) = check_token_list(token_list, passw, allow_reset_all_tokens=True) return res, opt
def check_yubikey_pass(passw): """ if the Token has set a PIN the user must also enter the PIN for authentication! This checks the output of a yubikey in AES mode without providing the serial number. The first 12 (of 44) or 16 of 48) characters are the tokenid, which is stored in the tokeninfo. :param passw: The password that consist of the static yubikey prefix and the otp :type passw: string :return: True/False and the User-Object of the token owner :rtype: dict """ opt = {} res = False token_list = [] # strip the yubico OTP and the PIN modhex_serial = passw[:-32][-16:] try: serialnum = "UBAM" + modhex_decode(modhex_serial) except TypeError as exx: # pragma: no cover log.error("Failed to convert serialnumber: %r" % exx) return res, opt # build list of possible yubikey tokens serials = [serialnum] for i in range(1, 3): serials.append("%s_%s" % (serialnum, i)) from privacyidea.lib.token import get_tokens from privacyidea.lib.token import check_token_list for serial in serials: tokenobject_list = get_tokens(serial=serial) token_list.extend(tokenobject_list) if len(token_list) == 0: opt['action_detail'] = ("The serial %s could not be found!" % serialnum) return res, opt (res, opt) = check_token_list(token_list, passw) return res, opt
def check_yubikey_pass(passw): """ if the Token has set a PIN the user must also enter the PIN for authentication! This checks the output of a yubikey in AES mode without providing the serial number. The first 12 (of 44) or 16 of 48) characters are the tokenid, which is stored in the tokeninfo. :param passw: The password that consist of the static yubikey prefix and the otp :type passw: string :return: True/False and the User-Object of the token owner :rtype: dict """ opt = {} res = False token_list = [] # strip the yubico OTP and the PIN modhex_serial = passw[:-32][-16:] try: serialnum = "UBAM" + modhex_decode(modhex_serial) except TypeError as exx: # pragma: no cover log.error("Failed to convert serialnumber: %r" % exx) return res, opt # build list of possible yubikey tokens serials = [serialnum] for i in range(1, 3): serials.append("%s_%s" % (serialnum, i)) from privacyidea.lib.token import get_tokens from privacyidea.lib.token import check_token_list for serial in serials: tokenobject_list = get_tokens(serial=serial) token_list.extend(tokenobject_list) if not token_list: opt['action_detail'] = ("The serial %s could not be found!" % serialnum) return res, opt (res, opt) = check_token_list(token_list, passw) return res, opt
def test_34_check_token_list(self): # We can not authenticate with an unknown type # Such a token will not be returned by get_tokens... db_token = Token("serial72", tokentype="unknown") db_token.save() # set a matching OTP PIN for our hotp token set_pin("hotptoken", "hotppin40") tokenobject_list = get_tokens() # the HOTP token has the correct PIN but wrong otp value # The failcounter is increased hotp_tokenobject = get_tokens(serial="hotptoken")[0] hotp_tokenobject.set_pin("hotppin") hotp_tokenobject.save() old_failcount = hotp_tokenobject.token.failcount res, reply = check_token_list(tokenobject_list, "hotppin40123456") self.assertFalse(res) failcount = hotp_tokenobject.token.failcount self.assertTrue(failcount == old_failcount + 1, (old_failcount, failcount)) # if there is no token with at least a correct pin, we increase all # failcounters hotp_tokenobject = get_tokens(serial="hotptoken")[0] old_failcount = hotp_tokenobject.token.failcount res, reply = check_token_list(tokenobject_list, "everythingiswrong") self.assertFalse(res) failcount = hotp_tokenobject.token.failcount self.assertTrue(failcount == old_failcount + 1, (old_failcount, failcount)) # Now we do some successful auth with the HOTP token tokenobject_list = get_tokens(serial="hotptoken") """ Truncated Count Hexadecimal Decimal HOTP 0 4c93cf18 1284755224 755224 1 41397eea 1094287082 287082 2 82fef30 137359152 359152 3 66ef7655 1726969429 969429 4 61c5938a 1640338314 338314 5 33c083d4 868254676 254676 6 7256c032 1918287922 287922 7 4e5b397 82162583 162583 8 2823443f 673399871 399871 9 2679dc69 645520489 520489 10 403154 11 481090 12 868912 13 736127 """ hotp_tokenobject = tokenobject_list[0] old_counter = hotp_tokenobject.token.count res, reply = check_token_list(tokenobject_list, "hotppin399871") self.assertTrue(res) # check if the counter increased self.assertTrue(old_counter < hotp_tokenobject.token.count, (old_counter, hotp_tokenobject.token.count)) # but was it also increased in the database? tokenobject_list_new = get_tokens(serial="hotptoken") hotp_tokenobject_new = tokenobject_list_new[0] self.assertTrue(old_counter < hotp_tokenobject_new.token.count, (old_counter, hotp_tokenobject.token.count)) # False authentication old_failcount = hotp_tokenobject.token.failcount res, reply = check_token_list(tokenobject_list, "hotppin000000") self.assertFalse(res) # check the failcounter increased self.assertTrue(old_failcount + 1 == hotp_tokenobject.token.failcount) # Successful auth. The failcount needs to be resetted res, reply = check_token_list(tokenobject_list, "hotppin520489") self.assertTrue(res) self.assertTrue(hotp_tokenobject.token.failcount == 0) # Now we disable the hotp_tokenobject. If the token is disabled, # we must not be able to authenticate anymore with this very token. # But if the OTP value is valid, the counter is increased, anyway! old_counter = hotp_tokenobject.token.count hotp_tokenobject.enable(False) res, reply = check_token_list(tokenobject_list, "hotppin403154") self.assertFalse(res) self.assertTrue("Token is disabled" in reply.get("message")) self.assertEqual(old_counter + 1, hotp_tokenobject.token.count) # enable the token again hotp_tokenobject.enable(True)
def check_yubikey_pass(passw): """ This only works without a PIN! This checks the output of a yubikey in AES mode without providing the serial number. The first 12 (of 44) or 16 of 48) characters are the tokenid, which is stored in the tokeninfo. :param passw: The password that consist of the static yubikey prefix and the otp :type passw: string :return: True/False and the User-Object of the token owner :rtype: dict """ opt = {} res = False token_list = [] # strip the yubico OTP and the PIN modhex_serial = passw[:-32][-16:] try: serialnum = "UBAM" + modhex_decode(modhex_serial) except TypeError as exx: # pragma: no cover log.error("Failed to convert serialnumber: %r" % exx) return res, opt # build list of possible yubikey tokens serials = [serialnum] for i in range(1, 3): serials.append("%s_%s" % (serialnum, i)) from privacyidea.lib.token import get_tokens from privacyidea.lib.token import check_token_list for serial in serials: tokenobject_list = get_tokens(serial=serial) token_list.extend(tokenobject_list) if len(token_list) == 0: opt['action_detail'] = ("The serial %s could not be found!" % serialnum) return res, opt # FIXME if the Token has set a PIN and the User does not want # to enter the PIN # for authentication, we need to do something different here... # and avoid PIN checking in __checkToken. # We could pass an "option" to __checkToken. (res, opt) = check_token_list(token_list, passw) # Now we need to get the user # TODO: Migration #if res is not False and 'serial' in c.audit: # serial = c.audit.get('serial', None) # if serial is not None: # user = getTokenOwner(serial) # c.audit['user'] = user.login # c.audit['realm'] = user.realm # opt = {} # opt['user'] = user.login # opt['realm'] = user.realm # opt['serial'] = serial return res, opt