def update(self, param, reset_failcount=True): """ This is called during initialzaton of the token to add additional attributes to the token object. :param param: dict of initialization parameters :type param: dict :return: nothing """ HotpTokenClass.update(self, param, reset_failcount=reset_failcount) timeStep = param.get("timeStep", get_from_config("totp.timeStep") or 30) timeWindow = param.get("timeWindow", get_from_config("totp.timeWindow") or 180) timeShift = param.get("timeShift", get_from_config("totp.timeShift") or 0) # we support various hashlib methods, but only on create # which is effectively set in the update hashlibStr = param.get("totp.hashlib", get_from_config("totp.hashlib", u'sha1')) self.add_tokeninfo("timeWindow", timeWindow) self.add_tokeninfo("timeShift", timeShift) self.add_tokeninfo("timeStep", timeStep) self.add_tokeninfo("hashlib", hashlibStr)
def test_99_delete_token(self): db_token = Token.query.filter_by(serial=self.serial1).first() token = HotpTokenClass(db_token) token.delete_token() db_token = Token.query.filter_by(serial=self.serial1).first() self.assertTrue(db_token is None, db_token)
def test_07_enable(self): db_token = Token.query.filter_by(serial=self.serial1).first() token = HotpTokenClass(db_token) token.enable(False) self.assertTrue(token.token.active is False) token.enable() self.assertTrue(token.token.active)
def test_27_get_default_settings(self): params = {} logged_in_user = {"user": "******", "realm": "default", "role": "user"} set_policy("pol1", scope=SCOPE.USER, action="hotp_hashlib=sha256," "hotp_otplen=8") pol = PolicyClass() p = HotpTokenClass.get_default_settings(params, logged_in_user=logged_in_user, policy_object=pol) self.assertEqual(p.get("otplen"), "8") self.assertEqual(p.get("hashlib"), "sha256") delete_policy("pol1") # the same should work for an admin user logged_in_user = {"user": "******", "realm": "super", "role": "admin"} set_policy("pol1", scope=SCOPE.ADMIN, action="hotp_hashlib=sha512," "hotp_otplen=8") pol = PolicyClass() p = HotpTokenClass.get_default_settings(params, logged_in_user=logged_in_user, policy_object=pol) self.assertEqual(p.get("otplen"), "8") self.assertEqual(p.get("hashlib"), "sha512") # test check if there is no logged in user p = HotpTokenClass.get_default_settings(params, policy_object=pol) self.assertEqual(p, {}) delete_policy("pol1")
def test_16_init_detail(self): db_token = Token.query.filter_by(serial=self.serial1).first() token = HotpTokenClass(db_token) token.add_init_details("otpkey", "11223344556677889900") detail = token.get_init_detail() self.assertTrue("otpkey" in detail, detail) # but the otpkey must not be written to token.token.info (DB) # As this only writes the OTPkey to the internal init_details dict self.assertTrue("otpkey" not in token.token.get_info(), token.token.get_info()) # Now get the Google Authenticator URL, which we only # get, if a user is specified. detail = token.get_init_detail(user=User("cornelius", self.realm1)) self.assertTrue("otpkey" in detail, detail) otpkey = detail.get("otpkey") self.assertTrue("img" in otpkey, otpkey) self.assertTrue("googleurl" in detail, detail) # some other stuff. r = token.get_QRimage_data({"googleurl": detail.get("googleurl").get( "value")}) self.assertTrue('otpauth://hotp/SE123456?secret=CERDGRCVMZ3YRGIA' '&counter=1' in r[0], r[0]) self.assertRaises(Exception, token.set_init_details, "unvalid value") token.set_init_details({"detail1": "value1"}) self.assertTrue("detail1" in token.get_init_details(), token.get_init_details())
def test_10_get_hashlib(self): # check if functions are returned for hl in ["sha1", "md5", "sha256", "sha512", "sha224", "sha384", "", None]: self.assertTrue(hasattr(HotpTokenClass.get_hashlib(hl), '__call__'), HotpTokenClass.get_hashlib(hl))
def test_03_reset_failcounter(self): db_token = Token.query.filter_by(serial=self.serial1).first() token = HotpTokenClass(db_token) token.token.failcount = 10 token.reset() self.assertTrue(token.token.failcount == 0, token.token.failcount)
def test_21_get_class_info(self): db_token = Token.query.filter_by(serial=self.serial1).first() token = HotpTokenClass(db_token) ti = token.get_class_info() self.assertTrue(ti.get("type") == "hotp", ti) self.assertTrue("policy" in ti, ti) self.assertTrue("title" in ti, ti) self.assertTrue("user" in ti, ti)
def update(self, param, reset_failcount=True): if "otpkey" not in param: param["genkey"] = 1 HotpTokenClass.update(self, param, reset_failcount=reset_failcount) papertoken_count = int(param.get("papertoken_count", DEFAULT_COUNT)) # Now we calculate all the OTP values and add them to the # init_details. Thus they will be returned by token/init. otps = self.get_multi_otp(count=papertoken_count) self.add_init_details("otps", otps[2].get("otp", {}))
def update(self, param, reset_failcount=True): if "otpkey" not in param: param["genkey"] = 1 HotpTokenClass.update(self, param, reset_failcount=reset_failcount) # Now we calculate all the OTP values and add them to the # init_details. Thus they will be returned by token/init. # TODO: We can get the count from a policy otps = self.get_multi_otp(count=100) self.add_init_details("otps", otps[2].get("otp", {}))
def update(self, param, reset_failcount=True): if "otpkey" not in param: param["genkey"] = 1 HotpTokenClass.update(self, param, reset_failcount=reset_failcount) papertoken_count = int(param.get("papertoken_count") or DEFAULT_COUNT) # Now we calculate all the OTP values and add them to the # init_details. Thus they will be returned by token/init. otps = self.get_multi_otp(count=papertoken_count) self.add_init_details("otps", otps[2].get("otp", {}))
def test_05_get_set_realms(self): set_realm(self.realm2) db_token = Token.query.filter_by(serial=self.serial1).first() token = HotpTokenClass(db_token) realms = token.get_realms() self.assertTrue(len(realms) == 1, realms) token.set_realms([self.realm1, self.realm2]) realms = token.get_realms() self.assertTrue(len(realms) == 2, realms)
def test_01_create_token(self): db_token = Token(self.serial1, tokentype="hotp") db_token.save() token = HotpTokenClass(db_token) self.assertTrue(token.token.serial == self.serial1, token) self.assertTrue(token.token.tokentype == "hotp", token.token) self.assertTrue(token.type == "hotp", token) class_prefix = token.get_class_prefix() self.assertTrue(class_prefix == "OATH", class_prefix) self.assertTrue(token.get_class_type() == "hotp", token)
def test_24_challenges(self): db_token = Token.query.filter_by(serial=self.serial1).first() token = HotpTokenClass(db_token) token.update({"otpkey": self.otpkey, "otplen": 6}) token.set_pin("test") token.token.count = 0 token.set_sync_window(10) token.set_count_window(5) self.assertTrue(token.is_challenge_request("test"))
def test_13_check_otp(self): db_token = Token.query.filter_by(serial=self.serial1).first() token = HotpTokenClass(db_token) token.update({"otpkey": self.otpkey, "pin": "test", "otplen": 6}) # OTP does not exist self.assertTrue(token.check_otp_exist("222333") == -1) # OTP does exist res = token.check_otp_exist("969429") self.assertTrue(res == 3, res)
def __init__(self, a_token): """ create a token object :param aToken: instance of the orm db object :type aToken: orm object """ HotpTokenClass.__init__(self, a_token) self.set_type(u"daplug") self.hKeyRequired = True return
def test_15_check_pin(self): db_token = Token.query.filter_by(serial=self.serial1).first() token = HotpTokenClass(db_token) # test the encrypted pin token.set_pin("encrypted", encrypt=True) self.assertTrue(token.check_pin("encrypted")) self.assertFalse(token.check_pin("wrong pin")) # test the hashed pin token.set_pin("test") self.assertTrue(token.check_pin("test")) self.assertFalse(token.check_pin("wrong pin"))
def test_06_set_pin(self): db_token = Token.query.filter_by(serial=self.serial1).first() token = HotpTokenClass(db_token) token.set_pin("hallo") (ph1, pseed) = token.get_pin_hash_seed() # check the database token.set_pin("blubber") ph2 = token.token.pin_hash self.assertTrue(ph1 != ph2) token.set_pin_hash_seed(ph1, pseed)
def test_02_set_user(self): db_token = Token.query.filter_by(serial=self.serial1).first() token = HotpTokenClass(db_token) self.assertTrue(token.token.tokentype == "hotp", token.token.tokentype) self.assertTrue(token.type == "hotp", token.type) token.add_user(User(login="******", realm=self.realm1)) self.assertEqual(token.token.first_owner.resolver, self.resolvername1) self.assertEqual(token.token.first_owner.user_id, "1000") user_object = token.user self.assertTrue(user_object.login == "cornelius", user_object) self.assertTrue(user_object.resolver == self.resolvername1, user_object)
def test_14_split_pin_pass(self): db_token = Token.query.filter_by(serial=self.serial1).first() token = HotpTokenClass(db_token) token.token.otplen = 6 # postpend pin set_prepend_pin(False) _res, pin, value = token.split_pin_pass("222333test") self.assertTrue(pin == "test", pin) self.assertTrue(value == "222333", value) # prepend pin set_prepend_pin(True) _res, pin, value = token.split_pin_pass("test222333") self.assertTrue(pin == "test", pin) self.assertTrue(value == "222333", value)
def check_otp(self, anOtpVal, counter=None, window=None, options=None): """ check the otpval of a token against a given counter and the window :param passw: the to be verified passw/pin :type passw: string :return: counter if found, -1 if not found :rtype: int """ options = options or {} ret = HotpTokenClass.check_otp(self, anOtpVal, counter, window, options) if ret < 0 and is_true(get_from_config("sms.concurrent_challenges")): if options.get("data") == anOtpVal: # We authenticate from the saved challenge ret = 1 if ret >= 0 and self._get_auto_sms(options): message = self._get_sms_text(options) self.inc_otp_counter(ret, reset=False) success, message = self._send_sms(message=message) log.debug("AutoSMS: send new SMS: {0!s}".format(success)) log.debug("AutoSMS: {0!r}".format(message)) return ret
def test_18_challenges(self): db_token = Token.query.filter_by(serial=self.serial1).first() token = HotpTokenClass(db_token) resp = token.is_challenge_response(User(login="******", realm=self.realm1), "test123456") self.assertFalse(resp, resp) resp = token.is_challenge_response(User(login="******", realm=self.realm1), "test123456", options={"transaction_id": "123456789"}) self.assertTrue(resp, resp) # test if challenge is valid C = Challenge("S123455", transaction_id="tid", challenge="Who are you?") C.save()
def test_02_set_user(self): db_token = Token.query.filter_by(serial=self.serial1).first() token = HotpTokenClass(db_token) self.assertTrue(token.token.tokentype == "hotp", token.token.tokentype) self.assertTrue(token.type == "hotp", token.type) token.add_user(User(login="******", realm=self.realm1)) self.assertEqual(token.token.owners.first().resolver, self.resolvername1) self.assertEqual(token.token.owners.first().user_id, "1000") user_object = token.user self.assertTrue(user_object.login == "cornelius", user_object) self.assertTrue(user_object.resolver == self.resolvername1, user_object)
def update(self, param, reset_failcount=True): """ process initialization parameters :param param: dict of initialization parameters :type param: dict :return: nothing """ # specific - phone phone = getParam(param, "phone", required) self.add_tokeninfo("phone", phone) # in case of the sms token, only the server must know the otpkey # thus if none is provided, we let create one (in the TokenClass) if "genkey" not in param and "otpkey" not in param: param['genkey'] = 1 HotpTokenClass.update(self, param, reset_failcount)
def test_20_check_challenge_response(self): db_token = Token.query.filter_by(serial=self.serial1).first() db_token.set_pin("test") token = HotpTokenClass(db_token) r = token.check_challenge_response(user=None, passw="123454") # check empty challenges self.assertTrue(r == -1, r) # create a challenge and match the transaction_id c = Challenge(self.serial1, transaction_id="mytransaction", challenge="Blah, what now?") # save challenge to the database c.save() r = token.check_challenge_response(user=None, passw="123454", options={"state": "mytransaction"}) # The challenge matches, but the OTP does not match! self.assertTrue(r == -1, r)
def test_12_inc_otp_counter(self): db_token = Token.query.filter_by(serial=self.serial1).first() token = HotpTokenClass(db_token) token.set_otp_count(10) self.assertTrue(token.token.count == 10, token.token.count) # increase counter by 1 token.inc_otp_counter() self.assertTrue(token.token.count == 11, token.token.count) # increase counter to 21 Config(Key="DefaultResetFailCount", Value=True).save() token.inc_otp_counter(counter=20) self.assertTrue(token.token.count == 21, token.token.count)
def get_init_detail(self, params=None, user=None): """ to complete the token initialization some additional details should be returned, which are displayed at the end of the token initialization. This is the e.g. the enrollment URL for a Google Authenticator. """ params = params or {} if params.get("totp.hashlib"): params["hashlib"] = params.get("totp.hashlib") response_detail = HotpTokenClass.get_init_detail(self, params, user) return response_detail
def test_28_2step_generation_default(self): serial = "2step" db_token = Token(serial, tokentype="hotp") db_token.save() token = HotpTokenClass(db_token) token.update({"2stepinit": "1"}) # fetch the server component for later tests server_component = binascii.unhexlify(token.token.get_otpkey().getKey()) # generate a 8-byte client component client_component = b'abcdefgh' # construct a secret token.update({"otpkey": binascii.hexlify(client_component)}) # check the generated secret secret = binascii.unhexlify(token.token.get_otpkey().getKey()) # check the correct lengths self.assertEqual(len(server_component), 20) self.assertEqual(len(client_component), 8) self.assertEqual(len(secret), 20) # check the secret has been generated according to the specification expected_secret = pbkdf2(binascii.hexlify(server_component), client_component, 10000, 20) self.assertEqual(secret, expected_secret)
def test_30_2step_otpkeyformat(self): serial = "2step3" db_token = Token(serial, tokentype="hotp") db_token.save() token = HotpTokenClass(db_token) token.update({ "2stepinit": "1", "2step_clientsize": "12", "hashlib": "sha512", }) self.assertEqual(token.token.rollout_state, "clientwait") self.assertEqual(token.get_tokeninfo("2step_clientsize"), "12") # fetch the server component for later tests server_component = binascii.unhexlify( token.token.get_otpkey().getKey()) # generate a 12-byte client component client_component = b'abcdefghijkl' checksum = hashlib.sha1(client_component).digest()[:4] # wrong checksum with warnings.catch_warnings(): warnings.simplefilter('ignore', category=DeprecationWarning) self.assertRaisesRegexp( ParameterError, "Incorrect checksum", token.update, { "otpkey": b32encode_and_unicode(b"\x37" + checksum[1:] + client_component).strip("="), "otpkeyformat": "base32check", }) # construct a secret token.update({ "otpkey": b32encode_and_unicode(checksum + client_component).strip("="), "otpkeyformat": "base32check", # the following values are ignored "2step_serversize": "23", "2step_difficulty": "666666", "2step_clientsize": "13" }) # check the generated secret secret = binascii.unhexlify(token.token.get_otpkey().getKey()) # check the correct lengths self.assertEqual(len(server_component), 64) # because of SHA-512 self.assertEqual(len(client_component), 12) self.assertEqual(len(secret), 64) # because of SHA-512 # check the secret has been generated according to the specification expected_secret = pbkdf2_hmac('sha1', binascii.hexlify(server_component), client_component, 10000, len(secret)) self.assertEqual(secret, expected_secret) self.assertTrue(token.token.active)
def test_16_init_detail(self): db_token = Token.query.filter_by(serial=self.serial1).first() token = HotpTokenClass(db_token) token.add_init_details("otpkey", "11223344556677889900") detail = token.get_init_detail() self.assertTrue("otpkey" in detail, detail) # but the otpkey must not be written to token.token.info (DB) # As this only writes the OTPkey to the internal init_details dict self.assertTrue("otpkey" not in token.token.get_info(), token.token.get_info()) # Now get the Google Authenticator URL, which we only # get, if a user is specified. detail = token.get_init_detail(user=User("cornelius", self.realm1)) self.assertTrue("otpkey" in detail, detail) otpkey = detail.get("otpkey") self.assertTrue("img" in otpkey, otpkey) self.assertTrue("googleurl" in detail, detail) # some other stuff. self.assertRaises(Exception, token.set_init_details, "invalid value") token.set_init_details({"detail1": "value1"}) self.assertTrue("detail1" in token.get_init_details(), token.get_init_details())
def test_27_get_default_settings(self): params = {} logged_in_user = {"user": "******", "realm": "default", "role": "user"} set_policy("pol1", scope=SCOPE.USER, action="hotp_hashlib=sha256," "hotp_otplen=8") pol = PolicyClass() p = HotpTokenClass.get_default_settings(params, logged_in_user=logged_in_user, policy_object=pol) self.assertEqual(p.get("otplen"), "8") self.assertEqual(p.get("hashlib"), "sha256") delete_policy("pol1")
def test_15_status_validation(self): db_token = Token.query.filter_by(serial=self.serial1).first() token = HotpTokenClass(db_token) token.status_validation_fail() token.status_validation_success() d = token.get_vars() self.assertTrue("type" in d, d) self.assertTrue("mode" in d, d) self.assertTrue("token" in d, d)
def test_02_set_user(self): db_token = Token.query.filter_by(serial=self.serial1).first() token = HotpTokenClass(db_token) self.assertTrue(token.token.tokentype == "hotp", token.token.tokentype) self.assertTrue(token.type == "hotp", token.type) token.set_user(User(login="******", realm=self.realm1)) self.assertTrue(token.token.resolver_type == "passwdresolver", token.token.resolver_type) self.assertTrue(token.token.resolver == self.resolvername1, token.token.resolver) self.assertTrue(token.token.user_id == "1000", token.token.user_id) user_object = token.user self.assertTrue(user_object.login == "cornelius", user_object) self.assertTrue(user_object.resolver == self.resolvername1, user_object) token.set_user_identifiers(2000, self.resolvername1, "passwdresolver") self.assertTrue(int(token.token.user_id) == 2000, token.token.user_id)
def get_multi_otp(self, count=0, epoch_start=0, epoch_end=0, curTime=None, timestamp=None): res = HotpTokenClass.get_multi_otp( self, count=count, epoch_start=epoch_start, epoch_end=epoch_end, curTime=curTime, timestamp=timestamp ) # (True, 'OK', {'otp': {0: '755224', 1: '287082', # 2: '359152', 3: '969429', # 4: '338314'}, # 'type': 'hotp'}) # convert the response rdict = {"type": self.get_class_type(), "otp": {}} otp_dict = {} for k, v in res[2].get("otp").items(): rdict["otp"][k] = _digi2daplug(v) return res[0], res[1], rdict
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 """ otp = _daplug2digit(otp) res = HotpTokenClass.check_otp_exist(self, otp, window) return res
def get_multi_otp(self, count=0, epoch_start=0, epoch_end=0, curTime=None, timestamp=None): res = HotpTokenClass.get_multi_otp(self, count=count, epoch_start=epoch_start, epoch_end=epoch_end, curTime=curTime, timestamp=timestamp) # (True, 'OK', {'otp': {0: '755224', 1: '287082', # 2: '359152', 3: '969429', # 4: '338314'}, # 'type': 'hotp'}) # convert the response rdict = {'type': self.get_class_type(), 'otp': {}} otp_dict = {} for k, v in res[2].get('otp').items(): rdict['otp'][k] = _digi2daplug(v) return res[0], res[1], rdict
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 """ n_otp1 = _daplug2digit(otp1) n_otp2 = _daplug2digit(otp2) res = HotpTokenClass.resync(self, n_otp1, n_otp2, options) return res
def check_otp(self, anOtpVal, counter=None, window=None, options=None): """ checkOtp - validate the token otp against a given otpvalue :param anOtpVal: the otpvalue to be verified :type anOtpVal: string, format: efekeiebekeh :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 """ # convert OTP value otp = _daplug2digit(anOtpVal) res = HotpTokenClass.check_otp(self, otp, counter, window, options) return res