def get_multi_otp(self, count=0, epoch_start=0, epoch_end=0, curTime=None): ''' return a dictionary of multiple future OTP values of the HOTP/HMAC token :param count: how many otp values should be returned :type count: int :return: tuple of status: boolean, error: text and the OTP dictionary ''' log.debug("[get_multi_otp] begin. Get a dictionary of multiple future OTP values for: count: %r, epoch_start: %r, epoch_end: %r, curTime: %r" % (count, epoch_start, epoch_end, curTime)) otp_dict = {"type" : "HMAC", "otp": {}} ret = False error = "No count specified" try: otplen = int(self.token.LinOtpOtpLen) except ValueError as ex: log.error("[get_multi_otp]: Could not convert otplen - value error %r " % (ex)) raise Exception(ex) secretHOtp = self.token.getHOtpKey() hmac2Otp = HmacOtp(secretHOtp, self.getOtpCount(), otplen, self.getHashlib(self.hashlibStr)) log.debug("[get_multi_otp] retrieving %i OTP values for token %s" % (count, hmac2Otp)) if count > 0: for i in range(count): otpval = hmac2Otp.generate(self.getOtpCount() + i, inc_counter=False) otp_dict["otp"][i] = otpval ret = True log.debug("[get_multi_otp] end. dictionary of multiple future OTP is: otp_dict: %r - status: %r - error %r" % (ret, error, otp_dict)) return (ret, error, otp_dict)
def _calc_otp(self, input_data): """ Calculates an otp by using an hmac algorithm with seed and input_data :param input_data: data used in hmac :return: otp value """ # get otp length from stored token in database try: otp_length = int(self.token.LinOtpOtpLen) except ValueError as value_error_ex: log.exception('[getOTP]: Could not convert otplen - value error ' '%r' % (value_error_ex)) raise value_error_ex # get otp for data using secret object and hotp algorithm secret_object = self._get_secret_object() hmac_otp_obj = HmacOtp(secret_object, input_data, otp_length, self.getHashlib(self.hashlibStr)) otp_value = hmac_otp_obj.generate(inc_counter=False) return otp_value
def getNextOtp(self): ''' access the nex validf otp :return: otpval :rtype: string ''' log.debug("[getNextOtp] begin. starting to look for the next otp") try: ### TODO - replace tokenLen otplen = int(self.token.LinOtpOtpLen) except ValueError as ex: log.error("[getNextOtp] ValueError %r" % ex) raise Exception(ex) secret_obj = self.token.getHOtpKey() counter = self.token.getOtpCounter() #log.debug("serial: %s",serialNum) hmac2otp = HmacOtp(secret_obj, counter, otplen) nextotp = hmac2otp.generate(counter + 1) log.debug("[getNextOtp] end. got the next otp value: nextOtp %r" % nextotp) return nextotp
def getOtp(self, curTime=None): ''' get the next OTP value :return: next otp value :rtype: string ''' log.debug("[getOtp] begin. Get the next OTP value for: curTime: %r" % (curTime)) try: otplen = int(self.token.LinOtpOtpLen) except ValueError as ex: log.error("[getOtp]: Could not convert otplen - value error %r " % (ex)) raise Exception(ex) self.hashlibStr = self.getFromTokenInfo("hashlib", 'sha1') secretHOtp = self.token.getHOtpKey() hmac2Otp = HmacOtp(secretHOtp, self.getOtpCount(), otplen, self.getHashlib(self.hashlibStr)) otpval = hmac2Otp.generate(inc_counter=False) pin = self.token.getPin() combined = "%s%s" % (otpval, pin) if getFromConfig("PrependPin") == "True": combined = "%s%s" % (pin, otpval) log.debug( "[getOtp] end. Return opt is: (pin: %r, otpval: %r, combined: %r) " % (pin, otpval, combined)) return (1, pin, otpval, combined)
def _getNextOtp(self): """ access the nex valid otp :return: otpval :rtype: string """ LOG.debug("[getNextOtp] begin. starting to look for the next otp") try: otplen = int(self.token.LinOtpOtpLen) except ValueError as ex: LOG.error("[getNextOtp] ValueError %r" % ex) raise Exception(ex) secret_obj = self.token.getHOtpKey() counter = self.token.getOtpCounter() #log.debug("serial: %s",serialNum) hmac2otp = HmacOtp(secret_obj, counter, otplen) nextotp = hmac2otp.generate(counter + 1) LOG.debug("[getNextOtp] end. got the next otp value: nextOtp %r" % nextotp) return nextotp
def _getNextOtp(self): """ access the nex valid otp :return: otpval :rtype: string """ LOG.debug("[getNextOtp] begin. starting to look for the next otp") try: otplen = int(self.token.LinOtpOtpLen) except ValueError as ex: LOG.error("[getNextOtp] ValueError %r" % ex) raise Exception(ex) secObj = self._get_secret_object() counter = self.token.getOtpCounter() #log.debug("serial: %s",serialNum) hmac2otp = HmacOtp(secObj, counter, otplen) nextotp = hmac2otp.generate(counter + 1) LOG.debug("[getNextOtp] end. got the next otp value: nextOtp %r" % nextotp) return nextotp
def get_otp(self, counter): """ Get next otp value with the given data used as counter for hotp algorithm :param counter: data to give as counter into the hotp algorithm :type counter: base64 encoded string :return: otp value """ # get otp length from stored token in database try: otp_length = int(self.token.LinOtpOtpLen) except ValueError as value_error_ex: log.exception('[getOTP]: Could not convert otplen - value error ' '%r' % (value_error_ex)) raise value_error_ex # get otp for data using secret object and hotp algorithm secret_object = self._get_secret_object() hmac_otp_obj = HmacOtp(secret_object, counter, otp_length, self.getHashlib(self.hashlibStr)) otp_value = hmac_otp_obj.generate(inc_counter=False) return otp_value
def get_multi_otp(self, count=0, epoch_start=0, epoch_end=0, curTime=None): ''' return a dictionary of multiple future OTP values of the HOTP/HMAC token :param count: how many otp values should be returned :type count: int :return: tuple of status: boolean, error: text and the OTP dictionary ''' otp_dict = {"type": "HMAC", "otp": {}} ret = False error = "No count specified" try: otplen = int(self.token.LinOtpOtpLen) except ValueError as ex: log.exception( "[get_multi_otp]: Could not convert otplen - value error %r " % (ex)) raise Exception(ex) s_count = self.getOtpCount() secObj = self._get_secret_object() hmac2Otp = HmacOtp(secObj, s_count, otplen, self.getHashlib(self.hashlibStr)) if count > 0: for i in range(count): otpval = hmac2Otp.generate(s_count + i, inc_counter=False) otp_dict["otp"][s_count + i] = otpval ret = True return (ret, error, otp_dict)
def getNextOtp(self): ''' access the nex validf otp :return: otpval :rtype: string ''' log.debug("[getNextOtp] begin. starting to look for the next otp") try: # ## TODO - replace tokenLen otplen = int(self.token.LinOtpOtpLen) except ValueError as ex: log.exception("[getNextOtp] ValueError %r" % ex) raise Exception(ex) secObj = self._get_secret_object() counter = self.token.getOtpCounter() # log.debug("serial: %s",serialNum) hmac2otp = HmacOtp(secObj, counter, otplen) nextotp = hmac2otp.generate(counter + 1) log.debug("[getNextOtp] end. got the next otp value: nextOtp %r" % nextotp) return nextotp
def getOtp(self, curTime=None): ''' get the next OTP value :return: next otp value :rtype: string ''' try: otplen = int(self.token.LinOtpOtpLen) except ValueError as ex: log.exception( "[getOtp]: Could not convert otplen - value error %r " % (ex)) raise Exception(ex) self.hashlibStr = self.getFromTokenInfo("hashlib", 'sha1') secObj = self._get_secret_object() hmac2Otp = HmacOtp(secObj, self.getOtpCount(), otplen, self.getHashlib(self.hashlibStr)) otpval = hmac2Otp.generate(inc_counter=False) pin = self.getPin() combined = "%s%s" % (otpval, pin) if getFromConfig("PrependPin") == "True": combined = "%s%s" % (pin, otpval) return (1, pin, otpval, combined)
def getOtp(self, curTime=None): ''' get the next OTP value :return: next otp value :rtype: string ''' res = (-1, 0, 0, 0) otplen = int(self.token.LinOtpOtpLen) secObj = self._get_secret_object() self.hashlibStr = self.getFromTokenInfo("hashlib", "sha1") or 'sha1' timeStepping = int(self.getFromTokenInfo("timeStep", 30) or 30) shift = int(self.getFromTokenInfo("timeShift", 0) or 0) hmac2Otp = HmacOtp(secObj, self.getOtpCount(), otplen, self.getHashlib(self.hashlibStr)) tCounter = self.time2float(datetime.datetime.now()) if curTime: tCounter = self.time2float(curTime) ## we don't need to round here as we have alread float counter = int(((tCounter - shift) / timeStepping)) otpval = hmac2Otp.generate(counter=counter, inc_counter=False) pin = self.getPin() combined = "%s%s" % (otpval, pin) if getFromConfig("PrependPin") == "True": combined = "%s%s" % (pin, otpval) return (1, pin, otpval, combined)
def getOtp(self, curTime=None): ''' get the next OTP value :return: next otp value :rtype: string ''' log.debug("[getOtp] begin. Get the next OTP value for: curTime: %r" % (curTime)) try: otplen = int(self.token.LinOtpOtpLen) except ValueError as ex: log.error("[getOtp]: Could not convert otplen - value error %r " % (ex)) raise Exception(ex) self.hashlibStr = self.getFromTokenInfo("hashlib", 'sha1') secretHOtp = self.token.getHOtpKey() hmac2Otp = HmacOtp(secretHOtp, self.getOtpCount(), otplen, self.getHashlib(self.hashlibStr)) otpval = hmac2Otp.generate(inc_counter=False) pin = self.token.getPin() combined = "%s%s" % (otpval, pin) if getFromConfig("PrependPin") == "True" : combined = "%s%s" % (pin, otpval) log.debug("[getOtp] end. Return opt is: (pin: %r, otpval: %r, combined: %r) " % (pin, otpval, combined)) return (1, pin, otpval, combined)
def resync(self, otp1, otp2, options=None): """ resync the token based on two otp values - external method to do the resync of the token :param otp1: the first otp value :type otp1: string :param otp2: the second otp value :type otp2: string :param options: optional token specific parameters :type options: dict or None :return: counter or -1 if otp does not exist :rtype: int """ ret = False try: otplen = int(self.token.LinOtpOtpLen) except ValueError as ex: log.debug("[resync] otplen ValueError: %r ret: %r ", ex, ret) raise self.hashlibStr = self.getFromTokenInfo("hashlib", "sha1") secObj = self._get_secret_object() counter = self.token.getOtpCounter() syncWindow = self.token.getSyncWindow() # log.debug("serial: %s",serialNum) hmac2Otp = HmacOtp(secObj, counter, otplen, self.getHashlib(self.hashlibStr)) counter = hmac2Otp.checkOtp(otp1, syncWindow) if counter == -1: log.debug("[resync] exit. First counter (-1) not found ret: %r", ret) return ret nextOtp = hmac2Otp.generate(counter + 1) if nextOtp != otp2: log.debug( "[resync] exit. Failed to verify second otp: nextOtp:" " %r != otp2: %r ret: %r", nextOtp, otp2, ret, ) return ret ret = True self.incOtpCounter(counter + 1, True) log.debug("Resync was successful") return ret
def get_multi_otp(self, count=0, epoch_start=0, epoch_end=0, curTime=None): ''' return a dictionary of multiple future OTP values of the HOTP/HMAC token :param count: how many otp values should be returned :type count: int :return: tuple of status: boolean, error: text and the OTP dictionary ''' log.debug( "[get_multi_otp] begin. Get a dictionary of multiple future OTP values for: count: %r, epoch_start: %r, epoch_end: %r, curTime: %r" % (count, epoch_start, epoch_end, curTime)) otp_dict = {"type": "TOTP", "otp": {}} ret = False error = "No count specified" try: otplen = int(self.token.LinOtpOtpLen) except ValueError: return ret secretHOtp = self.token.getHOtpKey() self.hashlibStr = self.getFromTokenInfo("hashlib", "sha1") timeStepping = int(self.getFromTokenInfo("timeStep", 30)) shift = int(self.getFromTokenInfo("timeShift", 0)) hmac2Otp = HmacOtp(secretHOtp, self.getOtpCount(), otplen, self.getHashlib(self.hashlibStr)) tCounter = self.time2float(datetime.datetime.now()) if curTime: tCounter = self.time2float(curTime) ## we don't need to round here as we have alread float counter = int(((tCounter - shift) / timeStepping)) otp_dict["shift"] = shift otp_dict["timeStepping"] = timeStepping if count > 0: for i in range(0, count): otpval = hmac2Otp.generate(counter=counter + i, inc_counter=False) timeCounter = ((counter + i) * timeStepping) + shift otp_dict["otp"][counter + i] = { 'otpval': otpval, 'time': datetime.datetime.fromtimestamp(timeCounter).strftime( "%Y-%m-%d %H:%M:%S"), } ret = True log.debug( "[get_multi_otp] end. dictionary of multiple future OTP is: otp_dict: %r - status: %r - error %r" % (ret, error, otp_dict)) return (ret, error, otp_dict)
def resync(self, otp1, otp2, options=None, pin=None): ''' resync the token based on two otp values - external method to do the resync of the token :param otp1: the first otp value :type otp1: string :param otp2: the second otp value :type otp2: string :param options: optional token specific parameters :type options: dict or None :return: counter or -1 if otp does not exist :rtype: int ''' log.debug( "[resync] .begin. Resync the token based on: %r, anOtpVal: %r, options: %r" % (otp1, otp2, options)) ret = False try: otplen = int(self.token.LinOtpOtpLen) except ValueError as ex: log.debug("[resync] otplen ValueError: %r ret: %r " % (ex, ret)) raise Exception(ex) self.hashlibStr = self.getFromTokenInfo("hashlib", 'sha1') secretHOtp = self.token.getHOtpKey(pin) counter = self.token.getOtpCounter() syncWindow = self.token.getSyncWindow() #log.debug("serial: %s",serialNum) hmac2Otp = HmacOtp(secretHOtp, counter, otplen, self.getHashlib(self.hashlibStr)) counter = hmac2Otp.checkOtp(otp1, syncWindow) if counter == -1: log.debug("[resync] exit. First counter (-1) not found ret: %r" % (ret)) return ret nextOtp = hmac2Otp.generate(counter + 1) if nextOtp != otp2: log.debug( "[resync] exit. Failed to verify second otp: nextOtp: %r != otp2: %r ret: %r" % (nextOtp, otp2, ret)) return ret ret = True self.incOtpCounter(counter + 1, True) log.debug("[resync] end. resync was successful: ret: %r" % (ret)) return ret
def get_otp(self, counter: int) -> str: """ calculate the otp from a given counter :param counter: a given counter :return: the otp string """ hmac = HmacOtp(digits=self.otplen, hashfunc=self.hashlib) return hmac.generate(counter=counter, key=binascii.unhexlify(self.otpkey))
def get_multi_otp(self, count=0, epoch_start=0, epoch_end=0, curTime=None): """ return a dictionary of multiple future OTP values of the HOTP/HMAC token :param count: how many otp values should be returned :type count: int :return: tuple of status: boolean, error: text and the OTP dictionary """ otp_dict = {"type": "TOTP", "otp": {}} ret = False error = "No count specified" try: otplen = int(self.token.LinOtpOtpLen) except ValueError: return ret secObj = self._get_secret_object() self.hashlibStr = self.getFromTokenInfo("hashlib", "sha1") or "sha1" timeStepping = int(self.getFromTokenInfo("timeStep", 30) or 30) shift = int(self.getFromTokenInfo("timeShift", 0) or 0) hmac2Otp = HmacOtp( secObj, self.getOtpCount(), otplen, self.getHashlib(self.hashlibStr), ) tCounter = self.time2float(datetime.datetime.utcnow()) if curTime: tCounter = self.time2float(curTime) counter = int((tCounter - shift) // timeStepping) otp_dict["shift"] = shift otp_dict["timeStepping"] = timeStepping if count > 0: for i in range(0, count): otpval = hmac2Otp.generate(counter=counter + i, inc_counter=False) timeCounter = ((counter + i) * timeStepping) + shift otp_dict["otp"][counter + i] = { "otpval": otpval, "time": datetime.datetime.utcfromtimestamp(timeCounter).strftime( "%Y-%m-%d %H:%M:%S"), } ret = True return (ret, error, otp_dict)
def checkOtp(self, anOtpVal, counter, window, options=None): ''' checkOtp - validate the token otp against a given otpvalue :param anOtpVal: the to be verified otpvalue :type anOtpVal: string :param counter: the counter state, that should be verified :type counter: int :param window: the counter +window, which should be checked :type window: int :param options: the dict, which could contain token specific info :type options: dict :return: the counter state or -1 :rtype: int ''' log.debug( "[checkOtp] begin. Validate the token otp: anOtpVal: %r ,counter: %r,window: %r, options: %r " % (anOtpVal, counter, window, options)) res = -1 try: otplen = int(self.getOtpLen()) except ValueError as ex: log.exception( '[checkOtp] failed to initialize otplen: ValueError %r %r' % (ex, self.token.LinOtpOtpLen)) raise Exception(ex) try: self.hashlibStr = self.getFromTokenInfo("hashlib", 'sha1') except Exception as ex: log.exception('[checkOtp] failed to initialize hashlibStr: %r' % (ex)) raise Exception(ex) secretHOtp = self.token.getHOtpKey() #serialNum = self.token.LinOtpTokenSerialnumber #log.debug("serial: %s",serialNum) hmac2Otp = HmacOtp(secretHOtp, counter, otplen, self.getHashlib(self.hashlibStr)) res = hmac2Otp.checkOtp(anOtpVal, window) if -1 == res: res = self.autosync(hmac2Otp, anOtpVal) log.debug("[checkOtp] end. otp verification result was: res %r" % (res)) return res
def get_multi_otp(self, count=0, epoch_start=0, epoch_end=0, curTime=None): ''' return a dictionary of multiple future OTP values of the HOTP/HMAC token :param count: how many otp values should be returned :type count: int :return: tuple of status: boolean, error: text and the OTP dictionary ''' log.debug("[get_multi_otp] begin. Get a dictionary of multiple future OTP values for: count: %r, epoch_start: %r, epoch_end: %r, curTime: %r" % (count, epoch_start, epoch_end, curTime)) otp_dict = {"type" : "TOTP", "otp": {}} ret = False error = "No count specified" try: otplen = int(self.token.LinOtpOtpLen) except ValueError: return ret secretHOtp = self.token.getHOtpKey() self.hashlibStr = self.getFromTokenInfo("hashlib", "sha1") timeStepping = int(self.getFromTokenInfo("timeStep", 30)) shift = int(self.getFromTokenInfo("timeShift", 0)) hmac2Otp = HmacOtp(secretHOtp, self.getOtpCount(), otplen, self.getHashlib(self.hashlibStr)) tCounter = self.time2float(datetime.datetime.now()) if curTime: tCounter = self.time2float(curTime) ## we don't need to round here as we have alread float counter = int(((tCounter - shift) / timeStepping)) otp_dict["shift"] = shift otp_dict["timeStepping"] = timeStepping if count > 0: for i in range(0, count): otpval = hmac2Otp.generate(counter=counter + i, inc_counter=False) timeCounter = ((counter + i) * timeStepping) + shift otp_dict["otp"][ counter + i] = { 'otpval' : otpval, 'time' : datetime.datetime.fromtimestamp(timeCounter).strftime("%Y-%m-%d %H:%M:%S"), } ret = True log.debug("[get_multi_otp] end. dictionary of multiple future OTP is: otp_dict: %r - status: %r - error %r" % (ret, error, otp_dict)) return (ret, error, otp_dict)
def resync(self, otp1, otp2, options=None): ''' resync the token based on two otp values - external method to do the resync of the token :param otp1: the first otp value :type otp1: string :param otp2: the second otp value :type otp2: string :param options: optional token specific parameters :type options: dict or None :return: counter or -1 if otp does not exist :rtype: int ''' log.debug("[resync] .begin. Resync the token based on: %r, anOtpVal: %r, options: %r" % (otp1, otp2, options)) ret = False try: otplen = int(self.token.LinOtpOtpLen) except ValueError as ex: log.debug("[resync] otplen ValueError: %r ret: %r " % (ex, ret)) raise Exception(ex) self.hashlibStr = self.getFromTokenInfo("hashlib", 'sha1') secretHOtp = self.token.getHOtpKey() counter = self.token.getOtpCounter() syncWindow = self.token.getSyncWindow() #log.debug("serial: %s",serialNum) hmac2Otp = HmacOtp(secretHOtp, counter, otplen, self.getHashlib(self.hashlibStr)) counter = hmac2Otp.checkOtp(otp1, syncWindow) if counter == -1: log.debug("[resync] exit. First counter (-1) not found ret: %r" % (ret)) return ret nextOtp = hmac2Otp.generate(counter + 1) if nextOtp != otp2: log.debug("[resync] exit. Failed to verify second otp: nextOtp: %r != otp2: %r ret: %r" % (nextOtp, otp2, ret)) return ret ret = True self.incOtpCounter(counter + 1, True) log.debug("[resync] end. resync was successful: ret: %r" % (ret)) return ret
def get_otp(key, counter, digits=8, hashfunc=sha1): """ calculate otp from a given counter :param key: the token seed in hexlified format :param counter: the given counter == time equivalent :param digits: number of digits in the otp :param hashfunc: the hash method used in the hmac calculation :return: otp value """ hmac = LinHmacOTP(digits=digits, hashfunc=hashfunc) otp = hmac.generate(counter=counter, key=binascii.unhexlify(key)) return otp
def check_otp_exist(self, otp, window=10, user=None, autoassign=False): """ checks if the given OTP value is/are values of this very token. This is used to autoassign and to determine the serial number of a token. :param otp: the to be verified otp value :type otp: string :param window: the lookahead window for the counter :type window: int :return: counter or -1 if otp does not exist :rtype: int """ res = -1 try: otplen = int(self.token.LinOtpOtpLen) counter = int(self.token.LinOtpCount) except ValueError as ex: log.warning( "[check_otp_exist] a value error occurred while converting: " "otplen %r, counter %r : ValueError: %r ret: %r ", self.token.LinOtpOtpLen, self.token.LinOtpCount, ex, res, ) return res self.hashlibStr = self.getFromTokenInfo("hashlib", "sha1") secObj = self._get_secret_object() hmac2Otp = HmacOtp(secObj, counter, otplen, self.getHashlib(self.hashlibStr)) res = hmac2Otp.checkOtp(otp, window) if res >= 0: # As usually the counter is increased in auth.validate.checkUserPass, we # need to do this manually here: self.incOtpCounter(res) if res == -1: msg = "otp counter %r was not found" % otp else: msg = "otp counter %r was found" % otp return res
def calc_totp_OTP(key, digits=6, timestep=30): ''' :param key: the otpkey secret :param digits: the number of to be returned digits :param timestep: the time stepping 60 or 30 sec :return: the otp value as string ''' htoken = HmacOtp(digits=digits) counter = int((time.time() / timestep) + 0.5) otp = htoken.generate(counter=counter, key=binascii.unhexlify(key)) return otp
def check_otp_exist(self, otp, window=10): ''' checks if the given OTP value is/are values of this very token. This is used to autoassign and to determine the serial number of a token. :param otp: the to be verified otp value :type otp: string :param window: the lookahead window for the counter :type window: int :return: counter or -1 if otp does not exist :rtype: int ''' log.debug( "[check_otp_exist] begin. checks if the given OTP value exists: otp %r, window %r " % (otp, window)) res = -1 try: otplen = int(self.token.LinOtpOtpLen) counter = int(self.token.LinOtpCount) except ValueError as ex: log.warning( "[check_otp_exist] a value error occurred while converting: otplen %r, counter %r : ValueError: %r ret: %r " % (self.token.LinOtpOtpLen, self.token.LinOtpCount, ex, res)) return res self.hashlibStr = self.getFromTokenInfo("hashlib", "sha1") secretHOtp = self.token.getHOtpKey() hmac2Otp = HmacOtp(secretHOtp, counter, otplen, self.getHashlib(self.hashlibStr)) res = hmac2Otp.checkOtp(otp, window) if res >= 0: # As usually the counter is increased in lib.token.checkUserPass, we # need to do this manually here: self.incOtpCounter(res) if res == -1: msg = "otp counter %r was not found" % otp else: msg = "otp counter %r was found" % otp log.debug("[check_otp_exist] end. %r: res %r" % (msg, res)) return res
def checkOtp(self, anOtpVal, counter, window, options=None): """ checkOtp - validate the token otp against a given otpvalue :param anOtpVal: the to be verified otpvalue :type anOtpVal: string :param counter: the counter state, that should be verified :type counter: int :param window: the counter +window, which should be checked :type window: int :param options: the dict, which could contain token specific info :type options: dict :return: the counter state or -1 :rtype: int """ res = -1 try: otplen = int(self.getOtpLen()) except ValueError as ex: log.error( "[checkOtp] failed to initialize otplen: ValueError %r %r", ex, self.token.LinOtpOtpLen, ) raise try: self.hashlibStr = self.getFromTokenInfo("hashlib", "sha1") except Exception as ex: log.error("[checkOtp] failed to initialize hashlibStr: %r", ex) raise secObj = self._get_secret_object() hmac2Otp = HmacOtp(secObj, counter, otplen, self.getHashlib(self.hashlibStr)) res = hmac2Otp.checkOtp(anOtpVal, window) if -1 == res: res = self.autosync(hmac2Otp, anOtpVal) return res
def checkOtp(self, anOtpVal, counter, window, options=None): ''' checkOtp - validate the token otp against a given otpvalue :param anOtpVal: the to be verified otpvalue :type anOtpVal: string :param counter: the counter state, that should be verified :type counter: int :param window: the counter +window, which should be checked :type window: int :param options: the dict, which could contain token specific info :type options: dict :return: the counter state or -1 :rtype: int ''' log.debug("[checkOtp] begin. Validate the token otp: anOtpVal: %r ,counter: %r,window: %r, options: %r " % (anOtpVal, counter, window, options)) res = -1 try: otplen = int(self.getOtpLen()) except ValueError as ex: log.exception('[checkOtp] failed to initialize otplen: ValueError %r %r' % (ex, self.token.LinOtpOtpLen)) raise Exception(ex) try: self.hashlibStr = self.getFromTokenInfo("hashlib", 'sha1') except Exception as ex: log.exception('[checkOtp] failed to initialize hashlibStr: %r' % (ex)) raise Exception(ex) secretHOtp = self.token.getHOtpKey() #serialNum = self.token.LinOtpTokenSerialnumber #log.debug("serial: %s",serialNum) hmac2Otp = HmacOtp(secretHOtp, counter, otplen, self.getHashlib(self.hashlibStr)) res = hmac2Otp.checkOtp(anOtpVal, window) if -1 == res: res = self.autosync(hmac2Otp, anOtpVal) log.debug("[checkOtp] end. otp verification result was: res %r" % (res)) return res
def check_otp_exist(self, otp, window=10, user=None, autoassign=False): ''' checks if the given OTP value is/are values of this very token. This is used to autoassign and to determine the serial number of a token. :param otp: the to be verified otp value :type otp: string :param window: the lookahead window for the counter :type window: int :return: counter or -1 if otp does not exist :rtype: int ''' log.debug("[check_otp_exist] begin. checks if the given OTP value exists: otp %r, window %r " % (otp, window)) res = -1 try: otplen = int(self.token.LinOtpOtpLen) counter = int(self.token.LinOtpCount) except ValueError as ex: log.warning("[check_otp_exist] a value error occurred while converting: otplen %r, counter %r : ValueError: %r ret: %r " % (self.token.LinOtpOtpLen, self.token.LinOtpCount, ex, res)) return res self.hashlibStr = self.getFromTokenInfo("hashlib", "sha1") secObj = self._get_secret_object() hmac2Otp = HmacOtp(secObj, counter, otplen, self.getHashlib(self.hashlibStr)) res = hmac2Otp.checkOtp(otp, window) if res >= 0: # As usually the counter is increased in auth.validate.checkUserPass, we # need to do this manually here: self.incOtpCounter(res) if res == -1: msg = "otp counter %r was not found" % otp else: msg = "otp counter %r was found" % otp log.debug("[check_otp_exist] end. %r: res %r" % (msg, res)) return res
def get_multi_otp(self, count=0, epoch_start=0, epoch_end=0, curTime=None): ''' return a dictionary of multiple future OTP values of the HOTP/HMAC token :param count: how many otp values should be returned :type count: int :return: tuple of status: boolean, error: text and the OTP dictionary ''' log.debug( "[get_multi_otp] begin. Get a dictionary of multiple future OTP values for: count: %r, epoch_start: %r, epoch_end: %r, curTime: %r" % (count, epoch_start, epoch_end, curTime)) otp_dict = {"type": "HMAC", "otp": {}} ret = False error = "No count specified" try: otplen = int(self.token.LinOtpOtpLen) except ValueError as ex: log.error( "[get_multi_otp]: Could not convert otplen - value error %r " % (ex)) raise Exception(ex) secretHOtp = self.token.getHOtpKey() hmac2Otp = HmacOtp(secretHOtp, self.getOtpCount(), otplen, self.getHashlib(self.hashlibStr)) log.debug("[get_multi_otp] retrieving %i OTP values for token %s" % (count, hmac2Otp)) if count > 0: for i in range(count): otpval = hmac2Otp.generate(self.getOtpCount() + i, inc_counter=False) otp_dict["otp"][i] = otpval ret = True log.debug( "[get_multi_otp] end. dictionary of multiple future OTP is: otp_dict: %r - status: %r - error %r" % (ret, error, otp_dict)) return (ret, error, otp_dict)
def calcOTP(key, counter=0, digits=6, typ=None): ''' as we have to use this method in a not class related function this function is extracted :param key: the otpkey secret :param counter: the related counter :param digits: the number of to be returned digits :return: the otp value as string ''' htoken = HmacOtp(digits=digits) if typ == 'totp': log.debug("waiting for next time slot") timestep = 30 time.sleep(timestep + 1) counter = int((time.time() / timestep) + 0.5) otp = htoken.generate(counter=counter, key=binascii.unhexlify(key)) return otp
def test_compliance(self): """assure that the HamcOTP class is compilant""" for test_vector in TestVectors: key = test_vector["key"] hash_func = test_vector["hash"] step = test_vector["timeStep"] otps = test_vector["otps"] for test_set in otps: # ---------------------------------------------------------- -- # tupple (59, '94287082', '1970-01-01 00:00:59') seconds, otpvalue, timestr = test_set # ---------------------------------------------------------- -- # read the time format and conert it to seconds time = datetime.strptime(timestr, "%Y-%m-%d %H:%M:%S") time_delta = time - unix_start_time assert seconds == time_delta.total_seconds() # ---------------------------------------------------------- -- # verify the otp for the given seconds / counter counter = int(seconds / step) hmac = LinHmacOtp(digits=len(otpvalue), hashfunc=hash_func) lin_otp = hmac.generate( counter=counter, key=binascii.unhexlify(key) ) assert otpvalue == lin_otp
def getOtp(self, curTime=None): ''' get the next OTP value :return: next otp value :rtype: string ''' log.debug("[getOtp] begin. Get the next OTP value for: curTime: %r" % (curTime)) res = (-1, 0, 0, 0) otplen = int(self.token.LinOtpOtpLen) secretHOtp = self.token.getHOtpKey() self.hashlibStr = self.getFromTokenInfo("hashlib", "sha1") timeStepping = int(self.getFromTokenInfo("timeStep", 30)) shift = int(self.getFromTokenInfo("timeShift", 0)) hmac2Otp = HmacOtp(secretHOtp, self.getOtpCount(), otplen, self.getHashlib(self.hashlibStr)) tCounter = self.time2float(datetime.datetime.now()) if curTime: tCounter = self.time2float(curTime) ## we don't need to round here as we have alread float counter = int(((tCounter - shift) / timeStepping)) otpval = hmac2Otp.generate(counter=counter, inc_counter=False) pin = self.token.getPin() combined = "%s%s" % (otpval, pin) if getFromConfig("PrependPin") == "True": combined = "%s%s" % (pin, otpval) log.debug( "[getOtp] end. Return opt is: (pin: %r, otpval: %r, combined: %r) " % (pin, otpval, combined)) return (1, pin, otpval, combined)
def getNextOtp(self): """ access the nex validf otp :return: otpval :rtype: string """ try: # ## TODO - replace tokenLen otplen = int(self.token.LinOtpOtpLen) except ValueError as ex: log.error("[getNextOtp] ValueError %r", ex) raise ex secObj = self._get_secret_object() counter = self.token.getOtpCounter() hmac2otp = HmacOtp(secObj, counter, otplen) nextotp = hmac2otp.generate(counter + 1) return nextotp
def getOtp(self, curTime=None): ''' get the next OTP value :return: next otp value :rtype: string ''' log.debug("[getOtp] begin. Get the next OTP value for: curTime: %r" % (curTime)) res = (-1, 0, 0, 0) otplen = int(self.token.LinOtpOtpLen) secretHOtp = self.token.getHOtpKey() self.hashlibStr = self.getFromTokenInfo("hashlib", "sha1") timeStepping = int(self.getFromTokenInfo("timeStep", 30)) shift = int(self.getFromTokenInfo("timeShift", 0)) hmac2Otp = HmacOtp(secretHOtp, self.getOtpCount(), otplen, self.getHashlib(self.hashlibStr)) tCounter = self.time2float(datetime.datetime.now()) if curTime: tCounter = self.time2float(curTime) ## we don't need to round here as we have alread float counter = int(((tCounter - shift) / timeStepping)) otpval = hmac2Otp.generate(counter=counter, inc_counter=False) pin = self.token.getPin() combined = "%s%s" % (otpval, pin) if getFromConfig("PrependPin") == "True" : combined = "%s%s" % (pin, otpval) log.debug("[getOtp] end. Return opt is: (pin: %r, otpval: %r, combined: %r) " % (pin, otpval, combined)) return (1, pin, otpval, combined)
def checkOtp(self, anOtpVal, counter, window, options=None): ''' checkOtp - validate the token otp against a given otpvalue :param anOtpVal: the to be verified otpvalue @type anOtpVal: string :param counter: the counter state, that should be verified :type counter: int :param window: the counter +window, which should be checked :type window: int :param options: the dict, which could contain token specific info :type options: dict :return: the counter state or -1 :rtype: int ''' log.debug("[checkOtp] begin. Validate the token otp: anOtpVal: %r ,\ counter: %r,window: %r, options: %r " % (anOtpVal, counter, window, options)) try: otplen = int(self.token.LinOtpOtpLen) except ValueError as e: raise e secretHOtp = self.token.getHOtpKey() self.hashlibStr = self.getFromTokenInfo("hashlib", self.hashlibStr) timeStepping = int(self.getFromTokenInfo("timeStep", self.timeStep)) window = int(self.getFromTokenInfo("timeWindow", self.timeWindow)) shift = int(self.getFromTokenInfo("timeShift", self.timeShift)) ## oldCounter we have to remove one, as the normal otp handling will increment oCount = self.getOtpCount() - 1 initTime = -1 if options != None and type(options) == dict: initTime = int(options.get('initTime', -1)) if oCount < 0: oCount = 0 log.debug("[checkOTP] timestep: %i, timeWindow: %i, timeShift: %i" % (timeStepping, window, shift)) inow = int(time.time()) T0 = time.time() + shift if initTime != -1: T0 = int(initTime) log.debug("[checkOTP] T0 : %i" % T0) counter = self._time2counter_(T0, timeStepping=timeStepping) otime = self._getTimeFromCounter(oCount, timeStepping=timeStepping) ttime = self._getTimeFromCounter(counter, timeStepping=timeStepping) log.debug("[checkOTP] last log: %r :: %r" % (oCount, otime)) log.debug("[checkOTP] counter : %r :: %r <==> %r" % (counter, ttime, datetime.datetime.now())) log.debug("[checkOTP] shift : %r " % (shift)) hmac2Otp = HmacOtp(secretHOtp, counter, otplen, self.getHashlib(self.hashlibStr)) res = hmac2Otp.checkOtp(anOtpVal, int (window / timeStepping), symetric=True) log.debug("[checkOTP] comparing the result %i to the old counter %i." % (res, oCount)) if res != -1 and oCount != 0 and res <= oCount: if initTime == -1: log.warning("[checkOTP] a previous OTP value was used again!\n former tokencounter: %i, presented counter %i" % (oCount, res)) res = -1 return res if -1 == res : ## autosync: test if two consecutive otps have been provided res = self.autosync(hmac2Otp, anOtpVal) if res != -1: ## on success, we have to save the last attempt self.setOtpCount(counter) # # here we calculate the new drift/shift between the server time and the tokentime # tokentime = self._counter2time_(res, timeStepping) tokenDt = datetime.datetime.fromtimestamp(tokentime / 1.0) nowDt = datetime.datetime.fromtimestamp(inow / 1.0) lastauth = self._counter2time_(oCount, timeStepping) lastauthDt = datetime.datetime.fromtimestamp(lastauth / 1.0) log.debug("[checkOTP] last auth : %r" % (lastauthDt)) log.debug("[checkOTP] tokentime : %r" % (tokenDt)) log.debug("[checkOTP] now : %r" % (nowDt)) log.debug("[checkOTP] delta : %r" % (tokentime - inow)) new_shift = (tokentime - inow) log.debug("[checkOTP] the counter %r matched. New shift: %r" % (res, new_shift)) self.addToTokenInfo('timeShift', new_shift) log.debug("[checkOtp] end. otp verification result was: res %r" % (res)) return res
def test_scenario01(self): """Tests Scenario 01 (https://wally/projects/linotp/wiki/TestingTest_Szenario_01)""" driver = self.driver ### 1. UserIdResolver anlegen ### CA001_cert = \ """-----BEGIN CERTIFICATE----- MIIDcjCCAtugAwIBAgIQVSU6NwMTmKNI6t3WcjY6uTANBgkqhkiG9w0BAQUFADBC MRUwEwYKCZImiZPyLGQBGRYFbG9jYWwxGTAXBgoJkiaJk/IsZAEZFglsc2V4cGVy dHMxDjAMBgNVBAMTBUNBMDAxMB4XDTA1MDQxMTE2NDgzOVoXDTQwMDQxMTE2NTY1 MFowQjEVMBMGCgmSJomT8ixkARkWBWxvY2FsMRkwFwYKCZImiZPyLGQBGRYJbHNl eHBlcnRzMQ4wDAYDVQQDEwVDQTAwMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC gYEAqlWLfYK+dExjG+Qa/jpYjSo3EQnweQ7azacosa+xsrTMfDV5wLgMBSclCTX2 i/35VRg282Bh7hKCZifOBnAxjCBIHMpHQmW9c0T/GpeWSOQ1x0KeKrZ4PRj5oHEv /uDJ7q2HlWXgRQo6NR75yDGLpsAWk64TyQ/I4f2vlC+AtjMCAyPS46OCAWcwggFj MBMGCSsGAQQBgjcUAgQGHgQAQwBBMAsGA1UdDwQEAwIBhjAPBgNVHRMBAf8EBTAD AQH/MB0GA1UdDgQWBBTCY8rVNcU/NGvgZxaPmO+Kz8bG4TCB/AYDVR0fBIH0MIHx MIHuoIHroIHohoGwbGRhcDovLy9DTj1DQTAwMSxDTj1sc2V4czAxLENOPUNEUCxD Tj1QdWJsaWMlMjBLZXklMjBTZXJ2aWNlcyxDTj1TZXJ2aWNlcyxDTj1Db25maWd1 cmF0aW9uLERDPWxzZXhwZXJ0cyxEQz1sb2NhbD9jZXJ0aWZpY2F0ZVJldm9jYXRp b25MaXN0P2Jhc2U/b2JqZWN0Q2xhc3M9Y1JMRGlzdHJpYnV0aW9uUG9pbnSGM2h0 dHA6Ly9sc2V4czAxLmxzZXhwZXJ0cy5sb2NhbC9DZXJ0RW5yb2xsL0NBMDAxLmNy bDAQBgkrBgEEAYI3FQEEAwIBADANBgkqhkiG9w0BAQUFAAOBgQBa+RGoezCgJS5W PFCPy9BWqZr7iRimfRGBDqHpYDCPDtgec2fKCZ+u4jfwuTisZ7UOoiM1iEvkw0hH Z7R1pz4Yd6E074kS/fe6u7U+9L3dmSUjFvO3gkLKtHKbhQi0NA+EHMRrPsQQemLm gYzNiYwtvAu74Q+eTC6R5Uf0hOlFig== -----END CERTIFICATE-----""" # Create LDAP UserIdResolver ldap_name = "SE_scenario01_ldap" ldap_expected_users = ['bach', 'beethoven', 'berlioz', 'brahms', 'debussy', u'dvořák', 'haydn', 'mozart', u'حافظ', u'郎'] ldap_num_expected_users = len(ldap_expected_users) ldap_id_resolver = LdapUserIdResolver( ldap_name, driver, self.base_url, uri="ldaps://blackdog", certificate=CA001_cert, basedn="ou=people,dc=blackdog,dc=office,dc=lsexperts,dc=de", # You may also use cn="Wolfgang Amadeus Mozart" binddn=u'cn="عبد الحليم حافظ",ou=people,dc=blackdog,dc=office,dc=lsexperts,dc=de', password="******", preset_ldap=True ) time.sleep(1) # Create SQL UserIdResolver sql_name = "SE_scenario01_sql" sql_server = "blackdog" sql_database = "userdb" sql_user = "******" sql_password = "******" sql_table = "user" sql_limit = "500" sql_encoding = "latin1" sql_expected_users = ["corny", "kay", "eric", u"knöt"] sql_num_expected_users = len(sql_expected_users) sql_id_resolver = SqlUserIdResolver(sql_name, driver, self.base_url, sql_server, sql_database, sql_user, sql_password, sql_table, sql_limit, sql_encoding) time.sleep(1) # Create realm for all resolvers resolvers_realm1 = [ldap_id_resolver] realm_name1 = "SE_scenario01_realm1" realm1 = Realm(realm_name1, resolvers_realm1) realm1.create(driver, self.base_url) time.sleep(1) resolvers_realm2 = [sql_id_resolver] realm_name2 = "SE_scenario01_realm2" realm2 = Realm(realm_name2, resolvers_realm2) realm2.create(driver, self.base_url) time.sleep(1) ### 2. Im Management Webinterface testen, dass alle Benutzer sichtbar sind ### user_view = UserView(driver, self.base_url, realm_name1) self.assertEqual(ldap_num_expected_users, user_view.get_num_users(), "Not the expected number of users") for user in ldap_expected_users: self.assertTrue(user_view.user_exists(user), "User '" + user + "' should exist.") time.sleep(1) user_view = UserView(driver, self.base_url, realm_name2) self.assertEqual(sql_num_expected_users, user_view.get_num_users(), "Not the expected number of users") for user in sql_expected_users: self.assertTrue(user_view.user_exists(user), "User '" + user + "' should exist.") ### 3. eToken.xml ueber das Webinterface importieren ### seed_oath137332 = "ff06df50017d3b981cfbc4ec4d374040164d8d19" seed_oath137332_bin = binascii.unhexlify(seed_oath137332) file_content = """<Tokens> <Token serial="00040008CFA5"> <CaseModel>5</CaseModel> <Model>101</Model> <ProductionDate>02/19/2009</ProductionDate> <ProductName>Safeword Alpine</ProductName> <Applications> <Application ConnectorID="{ab1397d2-ddb6-4705-b66e-9f83f322deb9}"> <Seed>123412354</Seed> <MovingFactor>1</MovingFactor> </Application> </Applications> </Token> <Token serial="00040008CFA52"> <CaseModel>5</CaseModel> <Model>101</Model> <ProductionDate>02/19/2009</ProductionDate> <ProductName>Safeword Alpine</ProductName> <Applications> <Application ConnectorID="{ab1397d2-ddb6-4705-b66e-9f83f322deb9}"> <Seed>123456</Seed> <MovingFactor>1</MovingFactor> </Application> </Applications> </Token> <Token serial="oath137332"> <CaseModel>5</CaseModel> <Model>101</Model> <ProductionDate>02/19/2009</ProductionDate> <ProductName>Safeword Alpine</ProductName> <Applications> <Application ConnectorID="{ab1397d2-ddb6-4705-b66e-9f83f322deb1}"> <Seed>""" + seed_oath137332 + """</Seed> <MovingFactor>1</MovingFactor> </Application> </Applications> </Token> <Token serial="oath12482B"> <CaseModel>5</CaseModel> <Model>101</Model> <ProductionDate>02/19/2009</ProductionDate> <ProductName>Safeword Alpine</ProductName> <Applications> <Application ConnectorID="{ab1397d2-ddb6-4705-b66e-9f83f322deb2}"> <Seed>6ec1d0e9915a2bebf84745b318e39e481249c1eb</Seed> <MovingFactor>1</MovingFactor> </Application> </Applications> </Token> </Tokens>""" TokenImport(driver, self.base_url, "safenet", file_content, None) serial_token_bach = "oath137332" test1_realm = realm_name1.lower() ### 4. Im Management Webinterface nun eine Policy anlegen ### Policy(driver, self.base_url, "SE_scenario01", "selfservice", "enrollMOTP, setOTPPIN, setMOTPPIN, resync, disable ", test1_realm) ### 5. eToken zuweisen ### user_view = UserView(driver, self.base_url, test1_realm) user_view.select_user("bach") token_view = TokenView(driver, self.base_url) token_view.select_token(serial_token_bach) driver.find_element_by_id("button_assign").click() time.sleep(2) driver.find_element_by_id("pin1").clear() driver.find_element_by_id("pin1").send_keys("1234") driver.find_element_by_id("pin2").clear() driver.find_element_by_id("pin2").send_keys("1234") driver.find_element_by_id("button_setpin_setpin").click() time.sleep(1) ### 6. Remote Token zuweisen ### user_view = UserView(driver, self.base_url, test1_realm) user_view.select_user("debussy") remote_token = RemoteToken(driver=self.driver, base_url=self.base_url, url="https://billybones", remote_serial="LSSP0002F653", pin="1234", remote_otp_length=6, ) serial_token_debussy = remote_token.serial remote_token_otp = "666666" time.sleep(1) ### 7. Spass-Token zuweisen ### user_view = UserView(driver, self.base_url, test1_realm) user_view.select_user("beethoven") spass_token = SpassToken( driver=self.driver, base_url=self.base_url, pin=u"beethovenspass#ñô", description="SPass Token enrolled with Selenium" ) serial_token_beethoven = spass_token.serial time.sleep(1) ### 8. Selfservice mOTP ### motp_key = "1234123412341234" motp_pin = "1234" driver.get(self.base_url + "/account/login") driver.find_element_by_id("login").clear() driver.find_element_by_id("login").send_keys("mozart@" + test1_realm) driver.find_element_by_id("password").clear() driver.find_element_by_id("password").send_keys("Test123!") driver.find_element_by_id("password").submit() # Submits the form time.sleep(1) driver.find_element_by_id("motp_secret").clear() driver.find_element_by_id("motp_secret").send_keys(motp_key) driver.find_element_by_id("motp_s_pin1").clear() driver.find_element_by_id("motp_s_pin1").send_keys(motp_pin) driver.find_element_by_id("motp_s_pin2").clear() driver.find_element_by_id("motp_s_pin2").send_keys(motp_pin) driver.find_element_by_id("motp_self_desc").clear() driver.find_element_by_id("motp_self_desc").send_keys("Selenium self enrolled") driver.find_element_by_id("button_register_motp").click() time.sleep(1) alert_box_text = driver.find_element_by_id("alert_box_text").text m = re.match( r""" .*? Token\ enrolled\ successfully .*? [sS]erial(\ number)?: # 'serial:' or 'Serial number:' \s* (?P<serial>\w+) # For example: LSMO0001222C """, alert_box_text, re.DOTALL | re.VERBOSE ) self.assertTrue( m is not None, "alert_box_text does not match regex. Possibly the token was not enrolled properly. %r" % alert_box_text ) serial_token_mozart = m.group('serial') self.driver.find_element_by_xpath("//button[@type='button' and ancestor::div[@aria-describedby='alert_box']]").click() driver.find_element_by_link_text("Logout").click() ### 9. Alle 4 Benutzer melden sich im selfservice Portal an und setzen die PIN user_token_dict = { "bach": serial_token_bach, "debussy": serial_token_debussy, "mozart": serial_token_mozart, "beethoven": serial_token_beethoven } for user in user_token_dict: driver.get(self.base_url + "/account/login") driver.find_element_by_id("login").clear() driver.find_element_by_id("login").send_keys("%s@%s" % (user, test1_realm)) driver.find_element_by_id("password").clear() driver.find_element_by_id("password").send_keys("Test123!") driver.find_element_by_id("password").submit() driver.find_element_by_xpath("//div[@id='tabs']/ul/li/a/span[text()='set PIN']").click() time.sleep(1) # driver.find_element_by_css_selector('#tokenDiv > ul > li > a').click() driver.find_element_by_id('tokenDiv').find_element_by_partial_link_text(user_token_dict[user]).click() driver.find_element_by_id("pin1").clear() driver.find_element_by_id("pin1").send_keys(user + "newpin") driver.find_element_by_id("pin2").clear() driver.find_element_by_id("pin2").send_keys(user + "newpin") driver.find_element_by_id("button_setpin").click() time.sleep(1) self.assertEqual("PIN set successfully", self.close_alert_and_get_its_text()) driver.find_element_by_link_text("Logout").click() ### 10. Authentisierung der 4 Benutzer ### validate = Validate(self.http_protocol, self.http_host, self.http_username, self.http_password) # Validate HOTP Token - bach hotp = HmacOtp() for counter in range(0, 20): otp = "bachnewpin" + hotp.generate(counter=counter, key=seed_oath137332_bin) access_granted, _ = validate.validate(user="******" + test1_realm, password=otp) self.assertTrue(access_granted, "OTP: " + otp + " for user " + "bach@" + test1_realm + " returned False") access_granted, _ = validate.validate(user="******" + test1_realm, password="******") self.assertFalse(access_granted, "OTP: 1234111111 should be False for user bach") # Validate Remote token - debussy access_granted, _ = validate.validate(user="******" + test1_realm, password="******" + remote_token_otp) self.assertTrue(access_granted, "OTP: " + remote_token_otp + " for user " + "debussy@" + test1_realm + " returned False") access_granted, _ = validate.validate(user="******" + test1_realm, password="******") self.assertFalse(access_granted, "OTP: 1234111111 should be False for user debussy") # Validate Spass token - beethoven access_granted, _ = validate.validate(user="******" + test1_realm, password="******") self.assertTrue(access_granted, "OTP: " + "beethovennewpin" + " for user " + "beethoven@" + test1_realm + " returned False") access_granted, _ = validate.validate(user="******" + test1_realm, password="******") self.assertFalse(access_granted, "OTP: randominvalidpin should be False for user beethoven") # Validate mOTP token - mozart current_epoch = time.time() motp_otp = calculate_motp( epoch=current_epoch, key=motp_key, pin=motp_pin ) access_granted, _ = validate.validate(user="******" + test1_realm, password="******" + motp_otp) self.assertTrue(access_granted, "OTP: " + motp_otp + " for user " + "mozart@" + test1_realm + " returned False") motp_otp = calculate_motp( epoch=current_epoch - 4000, key=motp_key, pin=motp_pin ) access_granted, _ = validate.validate(user="******" + test1_realm, password="******" + motp_otp) self.assertFalse(access_granted, "OTP: mozartnewpin%s should be False for user mozart" % motp_otp) ### 11. mOTP Pin im selfservice ändern ### driver.get(self.base_url + "/account/login") driver.find_element_by_id("login").clear() driver.find_element_by_id("login").send_keys("%s@%s" % ("mozart", test1_realm)) driver.find_element_by_id("password").clear() driver.find_element_by_id("password").send_keys("Test123!") driver.find_element_by_id("password").submit() driver.find_element_by_xpath("//div[@id='tabs']/ul/li/a/span[text()='set mOTP PIN']").click() time.sleep(1) driver.find_element_by_id('tokenDiv').find_element_by_link_text(serial_token_mozart).click() driver.find_element_by_id("mpin1").clear() new_motp_pin = "5588" driver.find_element_by_id("mpin1").send_keys(new_motp_pin) driver.find_element_by_id("mpin2").clear() driver.find_element_by_id("mpin2").send_keys(new_motp_pin) driver.find_element_by_id("button_setmpin").click() time.sleep(1) self.assertEqual("mOTP PIN set successfully", self.close_alert_and_get_its_text()) driver.find_element_by_link_text("Logout").click() time.sleep(10) # otherwise next mOTP value might not be valid current_epoch = time.time() motp_otp = calculate_motp( epoch=current_epoch, key=motp_key, pin=new_motp_pin ) access_granted, _ = validate.validate(user="******" + test1_realm, password="******" + motp_otp) self.assertTrue(access_granted, "OTP: mozartnewpin" + motp_otp + " for user " + "mozart@" + test1_realm + " returned False") ### 12. Token Resynchronisierung ### # Bach 'presses' his token more than 10 times and fails to authenticate counter = 50 # was 19 hotp = HmacOtp() otp = "bachnewpin" + hotp.generate(counter=counter, key=seed_oath137332_bin) access_granted, _ = validate.validate(user="******" + test1_realm, password=otp) self.assertFalse(access_granted, "OTP: %s should be False for user bach" % otp) driver.get(self.base_url + "/account/login") driver.find_element_by_id("login").clear() driver.find_element_by_id("login").send_keys("%s@%s" % ("bach", test1_realm)) driver.find_element_by_id("password").clear() driver.find_element_by_id("password").send_keys("Test123!") driver.find_element_by_id("password").submit() driver.find_element_by_xpath("//div[@id='tabs']/ul/li/a/span[text()='Resync Token']").click() time.sleep(1) driver.find_element_by_id('tokenDiv').find_element_by_link_text(serial_token_bach).click() otp1 = hotp.generate(counter=counter + 1, key=seed_oath137332_bin) otp2 = hotp.generate(counter=counter + 2, key=seed_oath137332_bin) driver.find_element_by_id("otp1").clear() driver.find_element_by_id("otp1").send_keys(otp1) driver.find_element_by_id("otp2").clear() driver.find_element_by_id("otp2").send_keys(otp2) driver.find_element_by_id("button_resync").click() time.sleep(1) self.assertEqual("Token resynced successfully", self.close_alert_and_get_its_text()) driver.find_element_by_link_text("Logout").click() # Should be able to authenticate again otp = "bachnewpin" + hotp.generate(counter=counter + 3, key=seed_oath137332_bin) access_granted, _ = validate.validate(user="******" + test1_realm, password=otp) self.assertTrue(access_granted, "OTP: %s should be True for user bach" % otp) ### 13. Ein Benutzer debussy deaktiviert seinen Token im Selfservice portal und versucht sich anzumelden. ### driver.get(self.base_url + "/account/login") driver.find_element_by_id("login").clear() driver.find_element_by_id("login").send_keys("%s@%s" % ("debussy", test1_realm)) driver.find_element_by_id("password").clear() driver.find_element_by_id("password").send_keys("Test123!") driver.find_element_by_id("password").submit() driver.find_element_by_xpath("//div[@id='tabs']/ul/li/a/span[text()='Disable Token']").click() time.sleep(1) driver.find_element_by_id('tokenDiv').find_element_by_link_text(serial_token_debussy).click() driver.find_element_by_id("button_disable").click() time.sleep(1) self.assertEqual("Token disabled successfully", self.close_alert_and_get_its_text()) driver.find_element_by_link_text("Logout").click() # debussy should be unable to authenticate access_granted, _ = validate.validate(user="******" + test1_realm, password="******" + remote_token_otp) self.assertFalse(access_granted, "OTP: debussynewpin" + remote_token_otp + "should be False for user debussy") ### 14. Der Admin entsperrt diesen Token, der Benutzer debussy kann sich wieder anmelden. ### driver.get(self.base_url + "/manage") time.sleep(1) token_view = TokenView(driver, self.base_url) token_view.select_token(serial_token_debussy) driver.find_element_by_id("button_enable").click() time.sleep(1) # debussy should be able to authenticate access_granted, _ = validate.validate(user="******" + test1_realm, password="******" + remote_token_otp) self.assertTrue(access_granted, "OTP: debussynewpin" + remote_token_otp + "should be True for user debussy")
def test_otppin_3(self): """ Test policy otppin=3 (ignore_pin) : TestRail C1910 First we do some authentications with user a with otppin=3. Then we change the policy, that only users from a specific resolver (user B) get through with otppin=3. """ # Define user A user_a = "bach" user_a_pw = "Test123!" user_a_realm = self.two_resolvers_realm_name user_a_token_pin = "1234" # Define user B user_b = "kay" user_b_pw = "test123!" user_b_realm = self.two_resolvers_realm_name user_b_token_pin = "" user_b_token_key = "3132333435363738393031323334353637383930" # Unhexlify for hotp.generate method user_b_token_seed_bin = binascii.unhexlify(user_b_token_key) # Create Token self.user_view.select_user(user_b) HotpToken(self.driver, self.base_url, pin=user_b_token_pin, hmac_key=user_b_token_key) ############################### ## # First some tests with user A ## ############################### # Create policy Policy(self.manage_ui, "otppin3", "authentication", "otppin=3", "*", "*") # user = "******" # Create event based HMAC token # Tokens were imported by self.import_tokens() self.user_view.select_realm(user_a_realm) self.user_view.select_user(user_a) # Unhexlify for hotp.generate method seed_oath137332_bin = binascii.unhexlify(self.seed_oath137332) # Assign token to user # Set a pin self.token_view.assign_token(self.serial_oath137332, user_a_token_pin) # authentication tests # - PIN+OTP -> successfully # - PW+OTP -> successfully # - nonsense+OTP -> successfully # - OTP -> successfully # - wront OTP -> fails hotp_a = HmacOtp() # PIN+OTP -> success otp = user_a_token_pin + \ hotp_a.generate(counter=0, key=seed_oath137332_bin) access_granted, _ = self.validate.validate(user=user_a + "@" + user_a_realm, password=otp) self.assertTrue(access_granted, "OTPPIN=3, PIN+OTP: " + otp + " for user " + user_a + "@" + user_a_realm + " returned False") # PW+OTP -> success otp = user_a_pw + \ hotp_a.generate(counter=1, key=seed_oath137332_bin) access_granted, _ = self.validate.validate(user=user_a + "@" + user_a_realm, password=otp) self.assertTrue(access_granted, "OTPPIN=3, PW+OTP: " + otp + " for user " + user_a + "@" + user_a_realm + " returned False") # nonsense+OTP -> success otp = "nonsense" + \ hotp_a.generate(counter=2, key=seed_oath137332_bin) access_granted, _ = self.validate.validate(user=user_a + "@" + user_a_realm, password=otp) self.assertTrue(access_granted, "OTPPIN=3, nonsense+OTP: " + otp + " for user " + user_a + "@" + user_a_realm + " returned False") # OTP -> success otp = hotp_a.generate(counter=3, key=seed_oath137332_bin) access_granted, _ = self.validate.validate(user=user_a + "@" + user_a_realm, password=otp) self.assertTrue(access_granted, "OTPPIN=3, OTP: " + otp + " for user " + user_a + "@" + user_a_realm + " returned False") # wrong OTP -> fails otp = "111111" access_denied, _ = self.validate.validate(user=user_a + "@" + user_a_realm, password=otp) self.assertFalse(access_denied, "OTPPIN=3, wrong OTP: " + otp + " for user " + user_a + "@" + user_a_realm + " returned True") ########################### # # Bring user B into game # # change policy # user = resolverB: # # So the ignore_pin should # should only affect users # in resolverB # ########################### # Change policy Policy(self.manage_ui, "otppin3", "authentication", "otppin=3", "*", # realm data.sql_resolver["name"] + ":") # pick specific resolver hotp_b = HmacOtp() # PIN+OTP -> success otp = user_b_token_pin + \ hotp_b.generate(counter=0, key=user_b_token_seed_bin) access_granted, _ = self.validate.validate(user=user_b + "@" + user_b_realm, password=otp) self.assertTrue(access_granted, "OTPPIN=3, PIN+OTP: " + otp + " for user " + user_b + "@" + user_b_realm + " returned False") # PW+OTP -> success otp = user_b_pw + \ hotp_b.generate(counter=1, key=user_b_token_seed_bin) access_granted, _ = self.validate.validate(user=user_b + "@" + user_b_realm, password=otp) self.assertTrue(access_granted, "OTPPIN=3, PW+OTP: " + otp + " for user " + user_b + "@" + user_b_realm + " returned False") # OTP -> success otp = hotp_b.generate(counter=2, key=user_b_token_seed_bin) access_granted, _ = self.validate.validate(user=user_b + "@" + user_b_realm, password=otp) self.assertTrue(access_granted, "OTPPIN=3, OTP: " + otp + " for user " + user_b + "@" + user_b_realm + " returned False") # wrong OTP -> fails otp = "111111" access_denied, _ = self.validate.validate(user=user_b + "@" + user_b_realm, password=otp) self.assertFalse(access_denied, "OTPPIN=3, wrong OTP: " + otp + " for user " + user_b + "@" + user_b_realm + " returned False") # Back to user A and try to authenticate # with changed policy! # OTP -> fails otp = hotp_a.generate(counter=4, inc_counter=False, key=seed_oath137332_bin) access_denied, _ = self.validate.validate(user=user_a + "@" + user_a_realm, password=otp) self.assertFalse(access_denied, "OTPPIN=3, OTP: " + otp + " for user " + user_a + "@" + user_a_realm + " returned True") # PIN+OTP -> success otp = user_a_token_pin + \ hotp_a.generate(counter=4, key=seed_oath137332_bin) access_granted, _ = self.validate.validate(user=user_a + "@" + user_a_realm, password=otp) self.assertTrue(access_granted, "OTPPIN=3, PIN+OTP: " + otp + " for user " + user_a + "@" + user_a_realm + " returned False")
def get_otp(key, counter=None, digits=8): hmac = HmacOtp(digits=digits, hashfunc=sha1) return hmac.generate(counter=counter, key=binascii.unhexlify(key))
def test_scenario01(self): """ Scenario01 (https://wally/projects/linotp/wiki/TestingTest_Szenario_01) """ driver = self.driver token_view = self.manage_ui.token_view user_view = self.manage_ui.user_view selfservice = SelfService(self.driver, self.base_url) # reset all views self.reset_resolvers_and_realms() self.manage_ui.policy_view.clear_policies() token_view.delete_all_tokens() self._announce_test("1. UserIdResolver anlegen") # Create LDAP UserIdResolver ldap_data = data.musicians_ldap_resolver ldap_resolver = self.useridresolver_manager.create_resolver(ldap_data) # Create SQL UserIdResolver sql_data = data.sql_resolver sql_resolver = self.useridresolver_manager.create_resolver(sql_data) self.useridresolver_manager.close() # Create realm for all resolvers realm_name1 = "SE_scenario01_realm1" realm_name2 = "SE_scenario01_realm2" self.realm_manager.create(realm_name1, [ldap_resolver]) self.realm_manager.create(realm_name2, [sql_resolver]) self.realm_manager.close() self._announce_test( "2. In Management Webinterface, check that all users are visible") self.check_users(realm_name1, ldap_data) self.check_users(realm_name2, sql_data) self._announce_test("3. eToken.xml ueber das Webinterface importieren") token_import_aladdin = TokenImportAladdin(self.manage_ui) aladdin_xml_path = os.path.join(self.manage_ui.test_data_dir, 'aladdin.xml') err_import = token_import_aladdin.do_import(file_content=None, file_path=aladdin_xml_path) # There shouldn't raise an error self.assertFalse(err_import, "Error during Aladdin token import!") token_import_aladdin = TokenImportAladdin(self.manage_ui) err_import = token_import_aladdin.do_import( file_path=os.path.join(self.manage_ui.test_data_dir, 'wrong_token.xml')) # There shouldn't raise an error self.assertTrue(err_import, "Successful import of wrong Aladdin token file!") serial_token_bach = "oath137332" test1_realm = realm_name1.lower() self._announce_test( "4. Im Management Webinterface nun eine Policy anlegen") Policy(self.manage_ui, "SE_scenario01", "selfservice", "enrollMOTP, setOTPPIN, setMOTPPIN, resync, disable ", test1_realm) self._announce_test("5. eToken zuweisen") user_view.select_realm(test1_realm) user_view.select_user("bach") token_view.assign_token(serial_token_bach, "1234") self._announce_test("6. Remote Token zuweisen") user_view.select_user("debussy") remote_token = RemoteToken(driver=self.driver, base_url=self.base_url, url="https://billybones", remote_serial="LSSP0002F653", pin="1234", remote_otp_length=6, ) serial_token_debussy = remote_token.serial self._announce_test("7. Spass-Token zuweisen") user_view.select_user("beethoven") spass_token = SpassToken( driver=self.driver, base_url=self.base_url, pin=u"beethovenspass#ñô", description="SPass Token enrolled with Selenium" ) serial_token_beethoven = spass_token.serial self._announce_test("8. Selfservice mOTP") motp_key = "1234123412341234" motp_pin = "1234" selfservice.login("mozart", "Test123!", test1_realm) driver.find_element_by_id("motp_secret").clear() driver.find_element_by_id("motp_secret").send_keys(motp_key) driver.find_element_by_id("motp_s_pin1").clear() driver.find_element_by_id("motp_s_pin1").send_keys(motp_pin) driver.find_element_by_id("motp_s_pin2").clear() driver.find_element_by_id("motp_s_pin2").send_keys(motp_pin) driver.find_element_by_id("motp_self_desc").clear() driver.find_element_by_id("motp_self_desc").send_keys( "Selenium self enrolled") driver.find_element_by_id("button_register_motp").click() alert_box_text = driver.find_element_by_id("alert_box_text").text m = re.match( r""" .*? Token\ enrolled\ successfully .*? [sS]erial(\ number)?: # 'serial:' or 'Serial number:' \s* (?P<serial>\w+) # For example: LSMO0001222C """, alert_box_text, re.DOTALL | re.VERBOSE ) self.assertTrue( m is not None, "alert_box_text does not match regex. Possibly the token was not enrolled properly. %r" % alert_box_text ) serial_token_mozart = m.group('serial') self.driver.find_element_by_xpath( "//button[@type='button' and ancestor::div[@aria-describedby='alert_box']]").click() driver.find_element_by_link_text("Logout").click() self._announce_test( "9. Alle 4 Benutzer melden sich im selfservice Portal an und setzen die PIN") user_token_dict = { "bach": serial_token_bach, "debussy": serial_token_debussy, "mozart": serial_token_mozart, "beethoven": serial_token_beethoven } for user, token in user_token_dict.iteritems(): selfservice.login(user, "Test123!", test1_realm) selfservice.set_pin(token, user + "newpin") selfservice.logout() self._announce_test("10. Authentisierung der 4 Benutzer ###") validate = Validate(self.http_protocol, self.http_host, self.http_port, self.http_username, self.http_password) # seed is also set in testdata/aladdin.xml seed_oath137332 = "ff06df50017d3b981cfbc4ec4d374040164d8d19" seed_oath137332_bin = binascii.unhexlify(seed_oath137332) # Validate HOTP Token - bach hotp = HmacOtp() for counter in range(0, 20): otp = "bachnewpin" + \ hotp.generate(counter=counter, key=seed_oath137332_bin) access_granted, _ = validate.validate(user="******" + test1_realm, password=otp) self.assertTrue(access_granted, "OTP: " + otp + " for user " + "bach@" + test1_realm + " returned False") access_granted, _ = validate.validate(user="******" + test1_realm, password="******") self.assertFalse( access_granted, "OTP: 1234111111 should be False for user bach") # Validate Remote token - debussy # deactivated remote token test while no remote linotp integration # server is available ''' remote_token_otp = "666666" access_granted, _ = validate.validate(user="******" + test1_realm, password="******" + remote_token_otp) self.assertTrue(access_granted, "OTP: " + remote_token_otp + " for user " + "debussy@" + test1_realm + " returned False") access_granted, _ = validate.validate(user="******" + test1_realm, password="******") self.assertFalse(access_granted, "OTP: 1234111111 should be False for user debussy")''' # Validate Spass token - beethoven access_granted, _ = validate.validate(user="******" + test1_realm, password="******") self.assertTrue(access_granted, "OTP: " + "beethovennewpin" + " for user " + "beethoven@" + test1_realm + " returned False") access_granted, _ = validate.validate(user="******" + test1_realm, password="******") self.assertFalse( access_granted, "OTP: randominvalidpin should be False for user beethoven") # Validate mOTP token - mozart current_epoch = time.time() motp_otp = calculate_motp( epoch=current_epoch, key=motp_key, pin=motp_pin ) access_granted, _ = validate.validate(user="******" + test1_realm, password="******" + motp_otp) time.sleep(1) self.assertTrue(access_granted, "OTP: " + motp_otp + " for user " + "mozart@" + test1_realm + " returned False") motp_otp = calculate_motp( epoch=current_epoch - 4000, key=motp_key, pin=motp_pin ) access_granted, _ = validate.validate(user="******" + test1_realm, password="******" + motp_otp) self.assertFalse( access_granted, "OTP: mozartnewpin%s should be False for user mozart" % motp_otp) self._announce_test("11. mOTP Pin im selfservice ändern") new_motp_pin = "5588" selfservice.login("mozart", "Test123!", test1_realm) selfservice.set_motp_pin(token, new_motp_pin) selfservice.logout() time.sleep(10) # otherwise next mOTP value might not be valid current_epoch = time.time() motp_otp = calculate_motp( epoch=current_epoch, key=motp_key, pin=new_motp_pin ) access_granted, _ = validate.validate(user="******" + test1_realm, password="******" + motp_otp) self.assertTrue(access_granted, "OTP: mozartnewpin" + motp_otp + " for user " + "mozart@" + test1_realm + " returned False") self._announce_test("12. Token Resynchronisierung") # Bach 'presses' his token more than 10 times and fails to authenticate counter = 50 # was 19 hotp = HmacOtp() otp = "bachnewpin" + \ hotp.generate(counter=counter, key=seed_oath137332_bin) access_granted, _ = validate.validate(user="******" + test1_realm, password=otp) self.assertFalse( access_granted, "OTP: %s should be False for user bach" % otp) selfservice.login("bach", "Test123!", test1_realm) otp1 = hotp.generate(counter=counter + 1, key=seed_oath137332_bin) otp2 = hotp.generate(counter=counter + 2, key=seed_oath137332_bin) selfservice.resync_token(serial_token_bach, otp1, otp2) selfservice.logout() # Should be able to authenticate again otp = "bachnewpin" + \ hotp.generate(counter=counter + 3, key=seed_oath137332_bin) access_granted, _ = validate.validate(user="******" + test1_realm, password=otp) self.assertTrue( access_granted, "OTP: %s should be True for user bach" % otp) self._announce_test( "13. Benutzer beethoven deaktiviert seinen Token im Selfservice portal und versucht sich anzumelden.") selfservice.login("beethoven", "Test123!", test1_realm) selfservice.disable_token(serial_token_beethoven) selfservice.logout() # beethoven should be unable to authenticate access_granted, _ = validate.validate(user="******" + test1_realm, password="******") self.assertFalse( access_granted, "OTP: beethovennewpin should be False for user beethoven") self._announce_test( "14. Der Admin entsperrt diesen Token, der Benutzer beethoven kann sich wieder anmelden.") token_view.open() token_view.select_token(serial_token_beethoven) driver.find_element_by_id("button_enable").click() time.sleep(1) # beethoven should be able to authenticate access_granted, _ = validate.validate(user="******" + test1_realm, password="******") self.assertTrue( access_granted, "OTP: beethovennewpin should be able to authenticate after re-enabled token.")
def test_scenario01(self): """Tests Scenario 01 (https://wally/projects/linotp/wiki/TestingTest_Szenario_01)""" driver = self.driver token_view = self.manage_ui.token_view user_view = self.manage_ui.user_view selfservice = SelfService(self.driver, self.base_url) # reset all views self.reset_resolvers_and_realms() self.manage_ui.policy_view.clear_policies() token_view.delete_all_tokens() self._announce_test("1. UserIdResolver anlegen") # Create LDAP UserIdResolver ldap_data = data.musicians_ldap_resolver ldap_resolver = self.useridresolver_manager.create_resolver(ldap_data) # Create SQL UserIdResolver sql_data = data.sql_resolver sql_resolver = self.useridresolver_manager.create_resolver(sql_data) self.useridresolver_manager.close() # Create realm for all resolvers realm_name1 = "SE_scenario01_realm1" realm_name2 = "SE_scenario01_realm2" self.realm_manager.create(realm_name1, [ldap_resolver]) self.realm_manager.create(realm_name2, [sql_resolver]) self.realm_manager.close() self._announce_test( "2. In Management Webinterface, check that all users are visible") self.check_users(realm_name1, ldap_data) self.check_users(realm_name2, sql_data) self._announce_test("3. eToken.xml ueber das Webinterface importieren") seed_oath137332 = "ff06df50017d3b981cfbc4ec4d374040164d8d19" seed_oath137332_bin = binascii.unhexlify(seed_oath137332) file_content = """<Tokens> <Token serial="00040008CFA5"> <CaseModel>5</CaseModel> <Model>101</Model> <ProductionDate>02/19/2009</ProductionDate> <ProductName>Safeword Alpine</ProductName> <Applications> <Application ConnectorID="{ab1397d2-ddb6-4705-b66e-9f83f322deb9}"> <Seed>123412354</Seed> <MovingFactor>1</MovingFactor> </Application> </Applications> </Token> <Token serial="00040008CFA52"> <CaseModel>5</CaseModel> <Model>101</Model> <ProductionDate>02/19/2009</ProductionDate> <ProductName>Safeword Alpine</ProductName> <Applications> <Application ConnectorID="{ab1397d2-ddb6-4705-b66e-9f83f322deb9}"> <Seed>123456</Seed> <MovingFactor>1</MovingFactor> </Application> </Applications> </Token> <Token serial="oath137332"> <CaseModel>5</CaseModel> <Model>101</Model> <ProductionDate>02/19/2009</ProductionDate> <ProductName>Safeword Alpine</ProductName> <Applications> <Application ConnectorID="{ab1397d2-ddb6-4705-b66e-9f83f322deb1}"> <Seed>""" + seed_oath137332 + """</Seed> <MovingFactor>1</MovingFactor> </Application> </Applications> </Token> <Token serial="oath12482B"> <CaseModel>5</CaseModel> <Model>101</Model> <ProductionDate>02/19/2009</ProductionDate> <ProductName>Safeword Alpine</ProductName> <Applications> <Application ConnectorID="{ab1397d2-ddb6-4705-b66e-9f83f322deb2}"> <Seed>6ec1d0e9915a2bebf84745b318e39e481249c1eb</Seed> <MovingFactor>1</MovingFactor> </Application> </Applications> </Token> </Tokens>""" TokenImport(driver, self.base_url, "safenet", file_content, None) serial_token_bach = "oath137332" test1_realm = realm_name1.lower() self._announce_test( "4. Im Management Webinterface nun eine Policy anlegen") Policy(self.manage_ui, "SE_scenario01", "selfservice", "enrollMOTP, setOTPPIN, setMOTPPIN, resync, disable ", test1_realm) self._announce_test("5. eToken zuweisen") user_view.select_realm(test1_realm) user_view.select_user("bach") token_view.assign_token(serial_token_bach, "1234") self._announce_test("6. Remote Token zuweisen") user_view.select_user("debussy") remote_token = RemoteToken( driver=self.driver, base_url=self.base_url, url="https://billybones", remote_serial="LSSP0002F653", pin="1234", remote_otp_length=6, ) serial_token_debussy = remote_token.serial self._announce_test("7. Spass-Token zuweisen") user_view.select_user("beethoven") spass_token = SpassToken( driver=self.driver, base_url=self.base_url, pin=u"beethovenspass#ñô", description="SPass Token enrolled with Selenium") serial_token_beethoven = spass_token.serial self._announce_test("8. Selfservice mOTP") motp_key = "1234123412341234" motp_pin = "1234" selfservice.login("mozart", "Test123!", test1_realm) driver.find_element_by_id("motp_secret").clear() driver.find_element_by_id("motp_secret").send_keys(motp_key) driver.find_element_by_id("motp_s_pin1").clear() driver.find_element_by_id("motp_s_pin1").send_keys(motp_pin) driver.find_element_by_id("motp_s_pin2").clear() driver.find_element_by_id("motp_s_pin2").send_keys(motp_pin) driver.find_element_by_id("motp_self_desc").clear() driver.find_element_by_id("motp_self_desc").send_keys( "Selenium self enrolled") driver.find_element_by_id("button_register_motp").click() alert_box_text = driver.find_element_by_id("alert_box_text").text m = re.match( r""" .*? Token\ enrolled\ successfully .*? [sS]erial(\ number)?: # 'serial:' or 'Serial number:' \s* (?P<serial>\w+) # For example: LSMO0001222C """, alert_box_text, re.DOTALL | re.VERBOSE) self.assertTrue( m is not None, "alert_box_text does not match regex. Possibly the token was not enrolled properly. %r" % alert_box_text) serial_token_mozart = m.group('serial') self.driver.find_element_by_xpath( "//button[@type='button' and ancestor::div[@aria-describedby='alert_box']]" ).click() driver.find_element_by_link_text("Logout").click() self._announce_test( "9. Alle 4 Benutzer melden sich im selfservice Portal an und setzen die PIN" ) user_token_dict = { "bach": serial_token_bach, "debussy": serial_token_debussy, "mozart": serial_token_mozart, "beethoven": serial_token_beethoven } for user, token in user_token_dict.iteritems(): selfservice.login(user, "Test123!", test1_realm) selfservice.set_pin(token, user + "newpin") selfservice.logout() self._announce_test("10. Authentisierung der 4 Benutzer ###") validate = Validate(self.http_protocol, self.http_host, self.http_port, self.http_username, self.http_password) # Validate HOTP Token - bach hotp = HmacOtp() for counter in range(0, 20): otp = "bachnewpin" + \ hotp.generate(counter=counter, key=seed_oath137332_bin) access_granted, _ = validate.validate(user="******" + test1_realm, password=otp) self.assertTrue( access_granted, "OTP: " + otp + " for user " + "bach@" + test1_realm + " returned False") access_granted, _ = validate.validate(user="******" + test1_realm, password="******") self.assertFalse(access_granted, "OTP: 1234111111 should be False for user bach") # Validate Remote token - debussy # deactivated remote token test while no remote linotp integration # server is available ''' remote_token_otp = "666666" access_granted, _ = validate.validate(user="******" + test1_realm, password="******" + remote_token_otp) self.assertTrue(access_granted, "OTP: " + remote_token_otp + " for user " + "debussy@" + test1_realm + " returned False") access_granted, _ = validate.validate(user="******" + test1_realm, password="******") self.assertFalse(access_granted, "OTP: 1234111111 should be False for user debussy")''' # Validate Spass token - beethoven access_granted, _ = validate.validate(user="******" + test1_realm, password="******") self.assertTrue( access_granted, "OTP: " + "beethovennewpin" + " for user " + "beethoven@" + test1_realm + " returned False") access_granted, _ = validate.validate(user="******" + test1_realm, password="******") self.assertFalse( access_granted, "OTP: randominvalidpin should be False for user beethoven") # Validate mOTP token - mozart current_epoch = time.time() motp_otp = calculate_motp(epoch=current_epoch, key=motp_key, pin=motp_pin) access_granted, _ = validate.validate(user="******" + test1_realm, password="******" + motp_otp) time.sleep(1) self.assertTrue( access_granted, "OTP: " + motp_otp + " for user " + "mozart@" + test1_realm + " returned False") motp_otp = calculate_motp(epoch=current_epoch - 4000, key=motp_key, pin=motp_pin) access_granted, _ = validate.validate(user="******" + test1_realm, password="******" + motp_otp) self.assertFalse( access_granted, "OTP: mozartnewpin%s should be False for user mozart" % motp_otp) self._announce_test("11. mOTP Pin im selfservice ändern") new_motp_pin = "5588" selfservice.login("mozart", "Test123!", test1_realm) selfservice.set_motp_pin(token, new_motp_pin) selfservice.logout() time.sleep(10) # otherwise next mOTP value might not be valid current_epoch = time.time() motp_otp = calculate_motp(epoch=current_epoch, key=motp_key, pin=new_motp_pin) access_granted, _ = validate.validate(user="******" + test1_realm, password="******" + motp_otp) self.assertTrue( access_granted, "OTP: mozartnewpin" + motp_otp + " for user " + "mozart@" + test1_realm + " returned False") self._announce_test("12. Token Resynchronisierung") # Bach 'presses' his token more than 10 times and fails to authenticate counter = 50 # was 19 hotp = HmacOtp() otp = "bachnewpin" + \ hotp.generate(counter=counter, key=seed_oath137332_bin) access_granted, _ = validate.validate(user="******" + test1_realm, password=otp) self.assertFalse(access_granted, "OTP: %s should be False for user bach" % otp) selfservice.login("bach", "Test123!", test1_realm) otp1 = hotp.generate(counter=counter + 1, key=seed_oath137332_bin) otp2 = hotp.generate(counter=counter + 2, key=seed_oath137332_bin) selfservice.resync_token(serial_token_bach, otp1, otp2) selfservice.logout() # Should be able to authenticate again otp = "bachnewpin" + \ hotp.generate(counter=counter + 3, key=seed_oath137332_bin) access_granted, _ = validate.validate(user="******" + test1_realm, password=otp) self.assertTrue(access_granted, "OTP: %s should be True for user bach" % otp) self._announce_test( "13. Benutzer beethoven deaktiviert seinen Token im Selfservice portal und versucht sich anzumelden." ) selfservice.login("beethoven", "Test123!", test1_realm) selfservice.disable_token(serial_token_beethoven) selfservice.logout() # beethoven should be unable to authenticate access_granted, _ = validate.validate(user="******" + test1_realm, password="******") self.assertFalse( access_granted, "OTP: beethovennewpin should be False for user beethoven") self._announce_test( "14. Der Admin entsperrt diesen Token, der Benutzer beethoven kann sich wieder anmelden." ) token_view.open() token_view.select_token(serial_token_beethoven) driver.find_element_by_id("button_enable").click() time.sleep(1) # beethoven should be able to authenticate access_granted, _ = validate.validate(user="******" + test1_realm, password="******") self.assertTrue( access_granted, "OTP: beethovennewpin should be able to authenticate after re-enabled token." )
def resync(self, otp1, otp2, options=None): ''' resync the token based on two otp values - external method to do the resync of the token :param otp1: the first otp value :type otp1: string :param otp2: the second otp value :type otp2: string :param options: optional token specific parameters :type options: dict or None :return: counter or -1 if otp does not exist :rtype: int ''' log.debug("[resync] .begin. Resync the token based on: %r, anOtpVal: %r, options: %r" % (otp1, otp2, options)) ret = False try: otplen = int(self.token.LinOtpOtpLen) except ValueError: return ret secretHOtp = self.token.getHOtpKey() self.hashlibStr = self.getFromTokenInfo("hashlib", 'sha1') timeStepping = int(self.getFromTokenInfo("timeStep", 30)) shift = int(self.getFromTokenInfo("timeShift", 0)) try: window = int(self.token.LinOtpSyncWindow) * timeStepping except: window = 10 * timeStepping log.debug("[resync] timestep: %r, syncWindow: %r, timeShift: %r" % (timeStepping, window, shift)) T0 = time.time() + shift log.debug("[resync] T0 : %i" % T0) counter = int((T0 / timeStepping) + 0.5) # T = (Current Unix time - T0) / timeStepping log.debug("[resync] counter (current time): %i" % counter) oCount = self.getOtpCount() log.debug("[resync] tokenCounter: %r" % oCount) log.debug("[resync] now checking window %s, timeStepping %s" % (window, timeStepping)) # check 2nd value hmac2Otp = HmacOtp(secretHOtp, counter, otplen, self.getHashlib(self.hashlibStr)) log.debug("[resync] %s in otpkey: %s " % (otp2, secretHOtp)) res2 = hmac2Otp.checkOtp(otp2, int (window / timeStepping), symetric=True) #TEST -remove the 10 log.debug("[resync] res 2: %r" % res2) # check 1st value hmac2Otp = HmacOtp(secretHOtp, counter - 1, otplen, self.getHashlib(self.hashlibStr)) log.debug("[resync] %s in otpkey: %s " % (otp1, secretHOtp)) res1 = hmac2Otp.checkOtp(otp1, int (window / timeStepping), symetric=True) #TEST -remove the 10 log.debug("[resync] res 1: %r" % res1) if res1 < oCount: # A previous OTP value was used again! log.warning("[resync] a previous OTP value was used again! tokencounter: %i, presented counter %i" % (oCount, res1)) res1 = -1 if res1 != -1 and res1 + 1 == res2: # here we calculate the new drift/shift between the server time and the tokentime tokentime = (res2 + 0.5) * timeStepping currenttime = T0 - shift new_shift = (tokentime - currenttime) log.debug("[resync] the counters %r and %r matched. New shift: %r" % (res1, res2, new_shift)) self.addToTokenInfo('timeShift', new_shift) # The OTP value that was used for resync must not be used again! self.setOtpCount(res2 + 1) ret = True if ret == True: msg = "resync was successful" else: msg = "resync was not successful" log.debug("[resync] end. %s: ret: %r" % (msg, ret)) return ret
def test_scenario01(self): """ Scenario01 (https://wally/projects/linotp/wiki/TestingTest_Szenario_01) """ driver = self.testcase.driver token_view = self.testcase.manage_ui.token_view user_view = self.testcase.manage_ui.user_view token_enroll = self.testcase.manage_ui.token_enroll selfservice = SelfService(self.testcase) # reset all views self.testcase.reset_resolvers_and_realms() self.testcase.manage_ui.policy_view.clear_policies() token_view.delete_all_tokens() self._announce_test("1. UserIdResolver anlegen") # Create LDAP UserIdResolver ldap_data = data.musicians_ldap_resolver ldap_resolver = self.testcase.useridresolver_manager.create_resolver( ldap_data) # Create SQL UserIdResolver sql_data = data.sql_resolver sql_resolver = self.testcase.useridresolver_manager.create_resolver( sql_data) self.testcase.useridresolver_manager.close() # Create realm for all resolvers realm_name1 = "SE_scenario01_realm1" realm_name2 = "SE_scenario01_realm2" self.testcase.realm_manager.create(realm_name1, [ldap_resolver]) self.testcase.realm_manager.create(realm_name2, [sql_resolver]) self.testcase.realm_manager.close() self._announce_test( "2. In Management Webinterface, check that all users are visible") self.check_users(realm_name1, ldap_data) self.check_users(realm_name2, sql_data) self._announce_test("3. eToken.xml ueber das Webinterface importieren") token_import_aladdin = TokenImportAladdin(self.testcase.manage_ui) aladdin_xml_path = os.path.join(self.testcase.manage_ui.test_data_dir, "aladdin.xml") token_import_aladdin.do_import(file_path=aladdin_xml_path) serial_token_bach = "oath137332" test1_realm = realm_name1.lower() self._announce_test( "4. Im Management Webinterface nun eine Policy anlegen") Policy( self.testcase.manage_ui, "SE_scenario01", "selfservice", "enrollMOTP, setOTPPIN, setMOTPPIN, resync, disable ", test1_realm, ) self._announce_test("5. eToken zuweisen") user_view.select_realm(test1_realm) user_view.select_user("bach") token_view.assign_token(serial_token_bach, "1234") self._announce_test("6. Remote Token zuweisen") user_view.select_user("debussy") serial_token_debussy = token_enroll.create_remote_token( url="https://billybones", remote_serial="LSSP0002F653", pin="1234", remote_otp_length=6, ) self._announce_test("7. Spass-Token zuweisen") user_view.select_user("beethoven") beethoven_token_password = "******" serial_token_beethoven = token_enroll.create_static_password_token( password=beethoven_token_password, description="Password Token enrolled with Selenium", ) self._announce_test("8. Selfservice mOTP") motp_key = "1234123412341234" motp_pin = "1234" selfservice.open() selfservice.login("mozart", "Test123!", test1_realm) driver.find_element(By.ID, "motp_secret").clear() driver.find_element(By.ID, "motp_secret").send_keys(motp_key) driver.find_element(By.ID, "motp_s_pin1").clear() driver.find_element(By.ID, "motp_s_pin1").send_keys(motp_pin) driver.find_element(By.ID, "motp_s_pin2").clear() driver.find_element(By.ID, "motp_s_pin2").send_keys(motp_pin) driver.find_element(By.ID, "motp_self_desc").clear() driver.find_element( By.ID, "motp_self_desc").send_keys("Selenium self enrolled") driver.find_element(By.ID, "button_register_motp").click() alert_box_text = driver.find_element(By.ID, "alert_box_text").text m = re.match( r""" .*? Token\ enrolled\ successfully .*? [sS]erial(\ number)?: # 'serial:' or 'Serial number:' \s* (?P<serial>\w+) # For example: LSMO0001222C """, alert_box_text, re.DOTALL | re.VERBOSE, ) assert m is not None, ( "alert_box_text does not match regex. Possibly the token was not enrolled properly. %r" % alert_box_text) serial_token_mozart = m.group("serial") self.testcase.driver.find_element( By.XPATH, "//button[@type='button' and ancestor::div[@aria-describedby='alert_box']]", ).click() selfservice.logout() self._announce_test( "9. Alle 4 Benutzer melden sich im selfservice Portal an und setzen die PIN" ) user_token_dict = { "bach": serial_token_bach, "debussy": serial_token_debussy, "mozart": serial_token_mozart, "beethoven": serial_token_beethoven, } for user, token in user_token_dict.items(): selfservice.login(user, "Test123!", test1_realm) selfservice.set_pin(token, user + "newpin") selfservice.logout() self._announce_test("10. Authentisierung der 4 Benutzer ###") validate = Validate( self.testcase.http_protocol, self.testcase.http_host, self.testcase.http_port, self.testcase.http_username, self.testcase.http_password, ) # seed is also set in testdata/aladdin.xml seed_oath137332 = "ff06df50017d3b981cfbc4ec4d374040164d8d19" seed_oath137332_bin = binascii.unhexlify(seed_oath137332) # Validate HOTP Token - bach hotp = HmacOtp() for counter in range(0, 4): otp = "bachnewpin" + hotp.generate(counter=counter, key=seed_oath137332_bin) access_granted, _ = validate.validate(user="******" + test1_realm, password=otp) assert access_granted, ("OTP: " + otp + " for user " + "bach@" + test1_realm + " returned False") access_granted, _ = validate.validate(user="******" + test1_realm, password="******") assert (not access_granted ), "OTP: 1234111111 should be False for user bach" # Validate Remote token - debussy # deactivated remote token test while no remote linotp integration # server is available ''' remote_token_otp = "666666" access_granted, _ = validate.validate(user="******" + test1_realm, password="******" + remote_token_otp) assert access_granted is True, "OTP: " + remote_token_otp + " for user " + "debussy@" + test1_realm + " returned False" access_granted, _ = validate.validate(user="******" + test1_realm, password="******") assert access_granted is False, "OTP: 1234111111 should be False for user debussy"''' # Validate Spass token - beethoven # Correct PIN + password = success access_granted, _ = validate.validate( user="******" + test1_realm, password="******" + beethoven_token_password, ) assert access_granted, ("OTP: " + "beethovennewpin" + " for user " + "beethoven@" + test1_realm + " returned False") # wrong PIN + empty password = fail access_granted, _ = validate.validate(user="******" + test1_realm, password="******") assert (not access_granted ), "OTP: randominvalidpin should be False for user beethoven" # correct PIN + wrong password = fail access_granted, _ = validate.validate( user="******" + test1_realm, password="******" + "wrongpassword", ) assert (not access_granted ), "beethoven should not auth with wrong token password" # Password without pin = fail access_granted, _ = validate.validate( user="******" + test1_realm, password=beethoven_token_password) assert (not access_granted ), "beethoven should not auth with password and old pin" # Correct PIN + password = success (again) access_granted, _ = validate.validate( user="******" + test1_realm, password="******" + beethoven_token_password, ) assert access_granted, ("OTP: " + "beethovennewpin" + " for user " + "beethoven@" + test1_realm + " returned False") time.sleep(2) # Validate mOTP token - mozart current_epoch = time.time() motp_otp = calculate_motp(epoch=current_epoch, key=motp_key, pin=motp_pin) access_granted, _ = validate.validate(user="******" + test1_realm, password="******" + motp_otp) time.sleep(1) assert access_granted, ("OTP: " + motp_otp + " for user " + "mozart@" + test1_realm + " returned False") motp_otp = calculate_motp(epoch=current_epoch - 4000, key=motp_key, pin=motp_pin) access_granted, _ = validate.validate(user="******" + test1_realm, password="******" + motp_otp) assert not access_granted, ( "OTP: mozartnewpin%s should be False for user mozart" % motp_otp) self._announce_test("11. mOTP Pin im selfservice ändern") new_motp_pin = "5588" selfservice.open() selfservice.login("mozart", "Test123!", test1_realm) selfservice.set_motp_pin(serial_token_mozart, new_motp_pin) selfservice.logout() time.sleep(10) # otherwise next mOTP value might not be valid current_epoch = time.time() motp_otp = calculate_motp(epoch=current_epoch, key=motp_key, pin=new_motp_pin) access_granted, _ = validate.validate(user="******" + test1_realm, password="******" + motp_otp) assert access_granted, ("OTP: mozartnewpin" + motp_otp + " for user " + "mozart@" + test1_realm + " returned False") self._announce_test("12. Token Resynchronisierung") # Bach 'presses' his token more than 10 times and fails to authenticate counter = 50 # was 19 hotp = HmacOtp() otp = "bachnewpin" + hotp.generate(counter=counter, key=seed_oath137332_bin) access_granted, _ = validate.validate(user="******" + test1_realm, password=otp) assert not access_granted, ("OTP: %s should be False for user bach" % otp) selfservice.login("bach", "Test123!", test1_realm) otp1 = hotp.generate(counter=counter + 1, key=seed_oath137332_bin) otp2 = hotp.generate(counter=counter + 2, key=seed_oath137332_bin) selfservice.resync_token(serial_token_bach, otp1, otp2) selfservice.logout() # Should be able to authenticate again otp = "bachnewpin" + hotp.generate(counter=counter + 3, key=seed_oath137332_bin) access_granted, _ = validate.validate(user="******" + test1_realm, password=otp) assert access_granted, "OTP: %s should be True for user bach" % otp self._announce_test( "13. Benutzer beethoven deaktiviert seinen Token im Selfservice portal und versucht sich anzumelden." ) selfservice.login("beethoven", "Test123!", test1_realm) selfservice.disable_token(serial_token_beethoven) selfservice.logout() # beethoven should be unable to authenticate access_granted, _ = validate.validate( user="******" + test1_realm, password="******" + beethoven_token_password, ) assert (not access_granted ), "OTP: beethovennewpin should be False for user beethoven" self._announce_test( "14. Der Admin entsperrt diesen Token, der Benutzer beethoven kann sich wieder anmelden." ) token_view.open() token_view.enable_token(serial_token_beethoven) # beethoven should be able to authenticate access_granted, _ = validate.validate( user="******" + test1_realm, password="******" + beethoven_token_password, ) assert ( access_granted ), "OTP: beethovennewpin should be able to authenticate after re-enabled token."
def checkOtp(self, anOtpVal, counter, window, options=None): ''' checkOtp - validate the token otp against a given otpvalue :param anOtpVal: the to be verified otpvalue @type anOtpVal: string :param counter: the counter state, that should be verified :type counter: int :param window: the counter +window, which should be checked :type window: int :param options: the dict, which could contain token specific info :type options: dict :return: the counter state or -1 :rtype: int ''' try: otplen = int(self.token.LinOtpOtpLen) except ValueError as e: raise e secObj = self._get_secret_object() self.hashlibStr = self.getFromTokenInfo("hashlib", self.hashlibStr) or 'sha1' timeStepping = int( self.getFromTokenInfo("timeStep", self.timeStep) or 30) window = int( self.getFromTokenInfo("timeWindow", self.timeWindow) or 180) shift = int(self.getFromTokenInfo("timeShift", self.timeShift) or 0) ## oldCounter we have to remove one, as the normal otp handling will increment oCount = self.getOtpCount() - 1 initTime = -1 if options is not None and type(options) == dict: initTime = int(options.get('initTime', -1)) if oCount < 0: oCount = 0 log.debug("[checkOTP] timestep: %i, timeWindow: %i, timeShift: %i" % (timeStepping, window, shift)) inow = int(time.time()) T0 = time.time() + shift if initTime != -1: T0 = int(initTime) counter = self._time2counter_(T0, timeStepping=timeStepping) hmac2Otp = HmacOtp(secObj, counter, otplen, self.getHashlib(self.hashlibStr)) res = hmac2Otp.checkOtp(anOtpVal, int(window / timeStepping), symetric=True) if res != -1 and oCount != 0 and res <= oCount: if initTime == -1: log.warning( "[checkOTP] a previous OTP value was used again!\n former tokencounter: %i, presented counter %i" % (oCount, res)) res = -1 return res if -1 == res: ## autosync: test if two consecutive otps have been provided res = self.autosync(hmac2Otp, anOtpVal) if res != -1: ## on success, we have to save the last attempt self.setOtpCount(counter) # # here we calculate the new drift/shift between the server time and the tokentime # tokentime = self._counter2time_(res, timeStepping) tokenDt = datetime.datetime.fromtimestamp(tokentime / 1.0) nowDt = datetime.datetime.fromtimestamp(inow / 1.0) # reverse time mapping: # from time to counter to timeStepping mapped timeslot lastauth = self._counter2time_(oCount, timeStepping) lastauthDt = datetime.datetime.fromtimestamp(lastauth / 1.0) log.debug("[checkOTP] last auth : %r" % (lastauthDt)) log.debug("[checkOTP] tokentime : %r" % (tokenDt)) log.debug("[checkOTP] now : %r" % (nowDt)) log.debug("[checkOTP] delta : %r" % (tokentime - inow)) inow_counter = self._time2counter_(inow, timeStepping) inow_token_time = self._counter2time_(inow_counter, timeStepping) new_shift = (tokentime - inow_token_time) log.debug("[checkOTP] the counter %r matched. New shift: %r" % (res, new_shift)) self.addToTokenInfo('timeShift', new_shift) log.debug("[checkOtp] end. otp verification result was: res %r" % (res)) return res
def test_scenario01(self): """Tests Scenario 01 (https://wally/projects/linotp/wiki/TestingTest_Szenario_01)""" driver = self.driver self.reset_resolvers_and_realms() self._announce_test("1. UserIdResolver anlegen") # Create LDAP UserIdResolver ldap_data = data.musicians_ldap_resolver ldap_expected_users = ['bach', 'beethoven', 'berlioz', 'brahms', 'debussy', u'dvořák', 'haydn', 'mozart', u'حافظ', u'郎'] ldap_num_expected_users = len(ldap_expected_users) ldap_resolver = self.useridresolver_manager.create_resolver(ldap_data) # Create SQL UserIdResolver sql_data = data.sql_resolver sql_resolver = self.useridresolver_manager.create_resolver(sql_data) sql_expected_users = ["corny", "kay", "eric", u"knöt"] sql_num_expected_users = len(sql_expected_users) # Create realm for all resolvers realm_name1 = "SE_scenario01_realm1" realm_name2 = "SE_scenario01_realm2" self.realm_manager.create(realm_name1, [ldap_resolver]) self.realm_manager.create(realm_name2, [sql_resolver]) self._announce_test("2. In Management Webinterface, check that all users are visible") user_view = UserView(driver, self.base_url, realm_name1) self.assertEqual(ldap_num_expected_users, user_view.get_num_users(), "Not the expected number of users") for user in ldap_expected_users: self.assertTrue(user_view.user_exists(user), "User '" + user + "' should exist.") user_view = UserView(driver, self.base_url, realm_name2) self.assertEqual(sql_num_expected_users, user_view.get_num_users(), "Not the expected number of users") for user in sql_expected_users: self.assertTrue(user_view.user_exists(user), "User '" + user + "' should exist.") self._announce_test("3. eToken.xml ueber das Webinterface importieren") seed_oath137332 = "ff06df50017d3b981cfbc4ec4d374040164d8d19" seed_oath137332_bin = binascii.unhexlify(seed_oath137332) file_content = """<Tokens> <Token serial="00040008CFA5"> <CaseModel>5</CaseModel> <Model>101</Model> <ProductionDate>02/19/2009</ProductionDate> <ProductName>Safeword Alpine</ProductName> <Applications> <Application ConnectorID="{ab1397d2-ddb6-4705-b66e-9f83f322deb9}"> <Seed>123412354</Seed> <MovingFactor>1</MovingFactor> </Application> </Applications> </Token> <Token serial="00040008CFA52"> <CaseModel>5</CaseModel> <Model>101</Model> <ProductionDate>02/19/2009</ProductionDate> <ProductName>Safeword Alpine</ProductName> <Applications> <Application ConnectorID="{ab1397d2-ddb6-4705-b66e-9f83f322deb9}"> <Seed>123456</Seed> <MovingFactor>1</MovingFactor> </Application> </Applications> </Token> <Token serial="oath137332"> <CaseModel>5</CaseModel> <Model>101</Model> <ProductionDate>02/19/2009</ProductionDate> <ProductName>Safeword Alpine</ProductName> <Applications> <Application ConnectorID="{ab1397d2-ddb6-4705-b66e-9f83f322deb1}"> <Seed>""" + seed_oath137332 + """</Seed> <MovingFactor>1</MovingFactor> </Application> </Applications> </Token> <Token serial="oath12482B"> <CaseModel>5</CaseModel> <Model>101</Model> <ProductionDate>02/19/2009</ProductionDate> <ProductName>Safeword Alpine</ProductName> <Applications> <Application ConnectorID="{ab1397d2-ddb6-4705-b66e-9f83f322deb2}"> <Seed>6ec1d0e9915a2bebf84745b318e39e481249c1eb</Seed> <MovingFactor>1</MovingFactor> </Application> </Applications> </Token> </Tokens>""" TokenImport(driver, self.base_url, "safenet", file_content, None) serial_token_bach = "oath137332" test1_realm = realm_name1.lower() self._announce_test("4. Im Management Webinterface nun eine Policy anlegen") Policy(driver, self.base_url, "SE_scenario01", "selfservice", "enrollMOTP, setOTPPIN, setMOTPPIN, resync, disable ", test1_realm) self._announce_test("5. eToken zuweisen") user_view = UserView(driver, self.base_url, test1_realm) user_view.select_user("bach") token_view = TokenView(self) token_view.assign_token(serial_token_bach, "1234") self._announce_test("6. Remote Token zuweisen") user_view = UserView(driver, self.base_url, test1_realm) user_view.select_user("debussy") remote_token = RemoteToken(driver=self.driver, base_url=self.base_url, url="https://billybones", remote_serial="LSSP0002F653", pin="1234", remote_otp_length=6, ) serial_token_debussy = remote_token.serial remote_token_otp = "666666" self._announce_test("7. Spass-Token zuweisen") user_view = UserView(driver, self.base_url, test1_realm) user_view.select_user("beethoven") spass_token = SpassToken( driver=self.driver, base_url=self.base_url, pin=u"beethovenspass#ñô", description="SPass Token enrolled with Selenium" ) serial_token_beethoven = spass_token.serial self._announce_test("8. Selfservice mOTP") motp_key = "1234123412341234" motp_pin = "1234" driver.get(self.base_url + "/account/login") driver.find_element_by_id("login").clear() driver.find_element_by_id("login").send_keys("mozart@" + test1_realm) driver.find_element_by_id("password").clear() driver.find_element_by_id("password").send_keys("Test123!") driver.find_element_by_id("password").submit() # Submits the form driver.find_element_by_id("motp_secret").clear() driver.find_element_by_id("motp_secret").send_keys(motp_key) driver.find_element_by_id("motp_s_pin1").clear() driver.find_element_by_id("motp_s_pin1").send_keys(motp_pin) driver.find_element_by_id("motp_s_pin2").clear() driver.find_element_by_id("motp_s_pin2").send_keys(motp_pin) driver.find_element_by_id("motp_self_desc").clear() driver.find_element_by_id("motp_self_desc").send_keys("Selenium self enrolled") driver.find_element_by_id("button_register_motp").click() alert_box_text = driver.find_element_by_id("alert_box_text").text m = re.match( r""" .*? Token\ enrolled\ successfully .*? [sS]erial(\ number)?: # 'serial:' or 'Serial number:' \s* (?P<serial>\w+) # For example: LSMO0001222C """, alert_box_text, re.DOTALL | re.VERBOSE ) self.assertTrue( m is not None, "alert_box_text does not match regex. Possibly the token was not enrolled properly. %r" % alert_box_text ) serial_token_mozart = m.group('serial') self.driver.find_element_by_xpath("//button[@type='button' and ancestor::div[@aria-describedby='alert_box']]").click() driver.find_element_by_link_text("Logout").click() self._announce_test("9. Alle 4 Benutzer melden sich im selfservice Portal an und setzen die PIN") user_token_dict = { "bach": serial_token_bach, "debussy": serial_token_debussy, "mozart": serial_token_mozart, "beethoven": serial_token_beethoven } for user in user_token_dict: driver.get(self.base_url + "/account/login") driver.find_element_by_id("login").clear() driver.find_element_by_id("login").send_keys("%s@%s" % (user, test1_realm)) driver.find_element_by_id("password").clear() driver.find_element_by_id("password").send_keys("Test123!") driver.find_element_by_id("password").submit() driver.find_element_by_xpath("//div[@id='tabs']/ul/li/a/span[text()='set PIN']").click() time.sleep(1) # driver.find_element_by_css_selector('#tokenDiv > ul > li > a').click() driver.find_element_by_id('tokenDiv').find_element_by_partial_link_text(user_token_dict[user]).click() driver.find_element_by_id("pin1").clear() driver.find_element_by_id("pin1").send_keys(user + "newpin") driver.find_element_by_id("pin2").clear() driver.find_element_by_id("pin2").send_keys(user + "newpin") driver.find_element_by_id("button_setpin").click() time.sleep(1) self.assertEqual("PIN set successfully", self.close_alert_and_get_its_text()) driver.find_element_by_link_text("Logout").click() self._announce_test("10. Authentisierung der 4 Benutzer ###") validate = Validate(self.http_protocol, self.http_host, self.http_port, self.http_username, self.http_password) # Validate HOTP Token - bach hotp = HmacOtp() for counter in range(0, 20): otp = "bachnewpin" + hotp.generate(counter=counter, key=seed_oath137332_bin) access_granted, _ = validate.validate(user="******" + test1_realm, password=otp) self.assertTrue(access_granted, "OTP: " + otp + " for user " + "bach@" + test1_realm + " returned False") access_granted, _ = validate.validate(user="******" + test1_realm, password="******") self.assertFalse(access_granted, "OTP: 1234111111 should be False for user bach") # Validate Remote token - debussy access_granted, _ = validate.validate(user="******" + test1_realm, password="******" + remote_token_otp) self.assertTrue(access_granted, "OTP: " + remote_token_otp + " for user " + "debussy@" + test1_realm + " returned False") access_granted, _ = validate.validate(user="******" + test1_realm, password="******") self.assertFalse(access_granted, "OTP: 1234111111 should be False for user debussy") # Validate Spass token - beethoven access_granted, _ = validate.validate(user="******" + test1_realm, password="******") self.assertTrue(access_granted, "OTP: " + "beethovennewpin" + " for user " + "beethoven@" + test1_realm + " returned False") access_granted, _ = validate.validate(user="******" + test1_realm, password="******") self.assertFalse(access_granted, "OTP: randominvalidpin should be False for user beethoven") # Validate mOTP token - mozart current_epoch = time.time() motp_otp = calculate_motp( epoch=current_epoch, key=motp_key, pin=motp_pin ) access_granted, _ = validate.validate(user="******" + test1_realm, password="******" + motp_otp) self.assertTrue(access_granted, "OTP: " + motp_otp + " for user " + "mozart@" + test1_realm + " returned False") motp_otp = calculate_motp( epoch=current_epoch - 4000, key=motp_key, pin=motp_pin ) access_granted, _ = validate.validate(user="******" + test1_realm, password="******" + motp_otp) self.assertFalse(access_granted, "OTP: mozartnewpin%s should be False for user mozart" % motp_otp) self._announce_test("11. mOTP Pin im selfservice ändern") driver.get(self.base_url + "/account/login") driver.find_element_by_id("login").clear() driver.find_element_by_id("login").send_keys("%s@%s" % ("mozart", test1_realm)) driver.find_element_by_id("password").clear() driver.find_element_by_id("password").send_keys("Test123!") driver.find_element_by_id("password").submit() driver.find_element_by_xpath("//div[@id='tabs']/ul/li/a/span[text()='set mOTP PIN']").click() driver.find_element_by_id('tokenDiv').find_element_by_link_text(serial_token_mozart).click() driver.find_element_by_id("mpin1").clear() new_motp_pin = "5588" driver.find_element_by_id("mpin1").send_keys(new_motp_pin) driver.find_element_by_id("mpin2").clear() driver.find_element_by_id("mpin2").send_keys(new_motp_pin) driver.find_element_by_id("button_setmpin").click() self.assertEqual("mOTP PIN set successfully", self.close_alert_and_get_its_text()) driver.find_element_by_link_text("Logout").click() time.sleep(10) # otherwise next mOTP value might not be valid current_epoch = time.time() motp_otp = calculate_motp( epoch=current_epoch, key=motp_key, pin=new_motp_pin ) access_granted, _ = validate.validate(user="******" + test1_realm, password="******" + motp_otp) self.assertTrue(access_granted, "OTP: mozartnewpin" + motp_otp + " for user " + "mozart@" + test1_realm + " returned False") self._announce_test("12. Token Resynchronisierung") # Bach 'presses' his token more than 10 times and fails to authenticate counter = 50 # was 19 hotp = HmacOtp() otp = "bachnewpin" + hotp.generate(counter=counter, key=seed_oath137332_bin) access_granted, _ = validate.validate(user="******" + test1_realm, password=otp) self.assertFalse(access_granted, "OTP: %s should be False for user bach" % otp) driver.get(self.base_url + "/account/login") driver.find_element_by_id("login").clear() driver.find_element_by_id("login").send_keys("%s@%s" % ("bach", test1_realm)) driver.find_element_by_id("password").clear() driver.find_element_by_id("password").send_keys("Test123!") driver.find_element_by_id("password").submit() driver.find_element_by_xpath("//div[@id='tabs']/ul/li/a/span[text()='Resync Token']").click() driver.find_element_by_id('tokenDiv').find_element_by_link_text(serial_token_bach).click() otp1 = hotp.generate(counter=counter + 1, key=seed_oath137332_bin) otp2 = hotp.generate(counter=counter + 2, key=seed_oath137332_bin) driver.find_element_by_id("otp1").clear() driver.find_element_by_id("otp1").send_keys(otp1) driver.find_element_by_id("otp2").clear() driver.find_element_by_id("otp2").send_keys(otp2) driver.find_element_by_id("button_resync").click() self.assertEqual("Token resynced successfully", self.close_alert_and_get_its_text()) driver.find_element_by_link_text("Logout").click() # Should be able to authenticate again otp = "bachnewpin" + hotp.generate(counter=counter + 3, key=seed_oath137332_bin) access_granted, _ = validate.validate(user="******" + test1_realm, password=otp) self.assertTrue(access_granted, "OTP: %s should be True for user bach" % otp) self._announce_test("13. Ein Benutzer debussy deaktiviert seinen Token im Selfservice portal und versucht sich anzumelden.") driver.get(self.base_url + "/account/login") driver.find_element_by_id("login").clear() driver.find_element_by_id("login").send_keys("%s@%s" % ("debussy", test1_realm)) driver.find_element_by_id("password").clear() driver.find_element_by_id("password").send_keys("Test123!") driver.find_element_by_id("password").submit() driver.find_element_by_xpath("//div[@id='tabs']/ul/li/a/span[text()='Disable Token']").click() driver.find_element_by_id('tokenDiv').find_element_by_link_text(serial_token_debussy).click() driver.find_element_by_id("button_disable").click() self.assertEqual("Token disabled successfully", self.close_alert_and_get_its_text()) driver.find_element_by_link_text("Logout").click() # debussy should be unable to authenticate access_granted, _ = validate.validate(user="******" + test1_realm, password="******" + remote_token_otp) self.assertFalse(access_granted, "OTP: debussynewpin" + remote_token_otp + "should be False for user debussy") self._announce_test("14. Der Admin entsperrt diesen Token, der Benutzer debussy kann sich wieder anmelden.") driver.get(self.base_url + "/manage") token_view = TokenView(self) token_view.select_token(serial_token_debussy) driver.find_element_by_id("button_enable").click() # debussy should be able to authenticate access_granted, _ = validate.validate(user="******" + test1_realm, password="******" + remote_token_otp) self.assertTrue(access_granted, "OTP: debussynewpin" + remote_token_otp + "should be True for user debussy")
def test_otppin_3(self): """ Test policy otppin=3 (ignore_pin) : TestRail C1910 First we do some authentications with user a with otppin=3. Then we change the policy, that only users from a specific resolver (user B) get through with otppin=3. """ # Define user A user_a = "bach" user_a_pw = "Test123!" user_a_realm = self.two_resolvers_realm_name user_a_token_pin = "1234" # Define user B user_b = "kay" user_b_pw = "test123!" user_b_realm = self.two_resolvers_realm_name user_b_token_pin = "" user_b_token_key = "3132333435363738393031323334353637383930" # Unhexlify for hotp.generate method user_b_token_seed_bin = binascii.unhexlify(user_b_token_key) # Create Token self.user_view.select_user(user_b) self.manage_ui.token_enroll.create_hotp_token( pin=user_b_token_pin, hmac_key=user_b_token_key) ############################### ## # First some tests with user A ## ############################### # Create policy Policy(self.manage_ui, "otppin3", "authentication", "otppin=3", "*", "*") # user = "******" # Create event based HMAC token # Tokens were imported by self.import_tokens() self.user_view.select_realm(user_a_realm) self.user_view.select_user(user_a) # Unhexlify for hotp.generate method seed_oath137332_bin = binascii.unhexlify(self.seed_oath137332) # Assign token to user # Set a pin self.token_view.assign_token(self.serial_oath137332, user_a_token_pin) # authentication tests # - PIN+OTP -> successfully # - PW+OTP -> successfully # - nonsense+OTP -> successfully # - OTP -> successfully # - wront OTP -> fails hotp_a = HmacOtp() # PIN+OTP -> success otp = user_a_token_pin + \ hotp_a.generate(counter=0, key=seed_oath137332_bin) access_granted, _ = self.validate.validate(user=user_a + "@" + user_a_realm, password=otp) assert access_granted, "OTPPIN=3, PIN+OTP: " + otp + " for user " + \ user_a + "@" + user_a_realm + " returned False" # PW+OTP -> success otp = user_a_pw + \ hotp_a.generate(counter=1, key=seed_oath137332_bin) access_granted, _ = self.validate.validate(user=user_a + "@" + user_a_realm, password=otp) assert access_granted, "OTPPIN=3, PW+OTP: " + otp + " for user " + \ user_a + "@" + user_a_realm + " returned False" # nonsense+OTP -> success otp = "nonsense" + \ hotp_a.generate(counter=2, key=seed_oath137332_bin) access_granted, _ = self.validate.validate(user=user_a + "@" + user_a_realm, password=otp) assert access_granted, "OTPPIN=3, nonsense+OTP: " + otp + " for user " + \ user_a + "@" + user_a_realm + " returned False" # OTP -> success otp = hotp_a.generate(counter=3, key=seed_oath137332_bin) access_granted, _ = self.validate.validate(user=user_a + "@" + user_a_realm, password=otp) assert access_granted, "OTPPIN=3, OTP: " + otp + " for user " + \ user_a + "@" + user_a_realm + " returned False" # wrong OTP -> fails otp = "111111" access_denied, _ = self.validate.validate(user=user_a + "@" + user_a_realm, password=otp) assert not access_denied, "OTPPIN=3, wrong OTP: " + otp + " for user " + \ user_a + "@" + user_a_realm + " returned True" ########################### # # Bring user B into game # # change policy # user = resolverB: # # So the ignore_pin should # should only affect users # in resolverB # ########################### # Change policy Policy(self.manage_ui, "otppin3", "authentication", "otppin=3", "*", # realm data.sql_resolver["name"] + ":") # pick specific resolver hotp_b = HmacOtp() # PIN+OTP -> success otp = user_b_token_pin + \ hotp_b.generate(counter=0, key=user_b_token_seed_bin) access_granted, _ = self.validate.validate(user=user_b + "@" + user_b_realm, password=otp) assert access_granted, "OTPPIN=3, PIN+OTP: " + otp + " for user " + \ user_b + "@" + user_b_realm + " returned False" # PW+OTP -> success otp = user_b_pw + \ hotp_b.generate(counter=1, key=user_b_token_seed_bin) access_granted, _ = self.validate.validate(user=user_b + "@" + user_b_realm, password=otp) assert access_granted, "OTPPIN=3, PW+OTP: " + otp + " for user " + \ user_b + "@" + user_b_realm + " returned False" # OTP -> success otp = hotp_b.generate(counter=2, key=user_b_token_seed_bin) access_granted, _ = self.validate.validate(user=user_b + "@" + user_b_realm, password=otp) assert access_granted, "OTPPIN=3, OTP: " + otp + " for user " + \ user_b + "@" + user_b_realm + " returned False" # wrong OTP -> fails otp = "111111" access_denied, _ = self.validate.validate(user=user_b + "@" + user_b_realm, password=otp) assert not access_denied, "OTPPIN=3, wrong OTP: " + otp + " for user " + \ user_b + "@" + user_b_realm + " returned False" # Back to user A and try to authenticate # with changed policy! # OTP -> fails otp = hotp_a.generate(counter=4, inc_counter=False, key=seed_oath137332_bin) access_denied, _ = self.validate.validate(user=user_a + "@" + user_a_realm, password=otp) assert not access_denied, "OTPPIN=3, OTP: " + otp + " for user " + \ user_a + "@" + user_a_realm + " returned True" # PIN+OTP -> success otp = user_a_token_pin + \ hotp_a.generate(counter=4, key=seed_oath137332_bin) access_granted, _ = self.validate.validate(user=user_a + "@" + user_a_realm, password=otp) assert access_granted, "OTPPIN=3, PIN+OTP: " + otp + " for user " + \ user_a + "@" + user_a_realm + " returned False"
def resync(self, otp1, otp2, options=None): ''' resync the token based on two otp values - external method to do the resync of the token :param otp1: the first otp value :type otp1: string :param otp2: the second otp value :type otp2: string :param options: optional token specific parameters :type options: dict or None :return: counter or -1 if otp does not exist :rtype: int ''' ret = False try: otplen = int(self.token.LinOtpOtpLen) except ValueError: return ret secObj = self._get_secret_object() self.hashlibStr = self.getFromTokenInfo("hashlib", 'sha1') timeStepping = int(self.getFromTokenInfo("timeStep", 30)) shift = int(self.getFromTokenInfo("timeShift", 0)) try: window = int(self.token.LinOtpSyncWindow) * timeStepping except: window = 10 * timeStepping log.debug("[resync] timestep: %r, syncWindow: %r, timeShift: %r" % (timeStepping, window, shift)) T0 = time.time() + shift log.debug("[resync] T0 : %i" % T0) counter = int((T0 / timeStepping) + 0.5) # T = (Current Unix time - T0) / timeStepping log.debug("[resync] counter (current time): %i" % counter) oCount = self.getOtpCount() log.debug("[resync] tokenCounter: %r" % oCount) log.debug("[resync] now checking window %s, timeStepping %s" % (window, timeStepping)) # check 2nd value hmac2Otp = HmacOtp(secObj, counter, otplen, self.getHashlib(self.hashlibStr)) log.debug("[resync] %s in otpkey: %s " % (otp2, secObj)) res2 = hmac2Otp.checkOtp(otp2, int(window / timeStepping), symetric=True) #TEST -remove the 10 log.debug("[resync] res 2: %r" % res2) # check 1st value hmac2Otp = HmacOtp(secObj, counter - 1, otplen, self.getHashlib(self.hashlibStr)) log.debug("[resync] %s in otpkey: %s " % (otp1, secObj)) res1 = hmac2Otp.checkOtp(otp1, int(window / timeStepping), symetric=True) #TEST -remove the 10 log.debug("[resync] res 1: %r" % res1) if res1 < oCount: # A previous OTP value was used again! log.warning( "[resync] a previous OTP value was used again! tokencounter: %i, presented counter %i" % (oCount, res1)) res1 = -1 if res1 != -1 and res1 + 1 == res2: # here we calculate the new drift/shift between the server time and the tokentime tokentime = (res2 + 0.5) * timeStepping currenttime = T0 - shift new_shift = (tokentime - currenttime) log.debug( "[resync] the counters %r and %r matched. New shift: %r" % (res1, res2, new_shift)) self.addToTokenInfo('timeShift', new_shift) # The OTP value that was used for resync must not be used again! self.setOtpCount(res2 + 1) ret = True if ret is True: msg = "resync was successful" else: msg = "resync was not successful" log.debug(msg) return ret