def test_43_encryptpin(self): serial = "ENC01" # encrypt pin on init init_token({ "serial": serial, "genkey": 1, "pin": "Hallo", "encryptpin": True }) tokenobj = get_tokens(serial=serial)[0] self.assertEqual(tokenobj.token.pin_hash[0:2], "@@") # set a hashed pin set_pin(serial, "test", encrypt_pin=False) tokenobj = get_tokens(serial=serial)[0] self.assertTrue(tokenobj.token.pin_hash[0:2] != "@@") # set an encrypted PIN set_pin(serial, "test", encrypt_pin=True) tokenobj = get_tokens(serial=serial)[0] self.assertEqual(tokenobj.token.pin_hash[0:2], "@@") # assign the token with a PIN assign_token(serial, User(login="******", realm=self.realm1), pin="WellWell", encrypt_pin=True) # check if pinhash starts with "@@" to indicate the encryption tokenobj = get_tokens(serial=serial)[0] self.assertEqual(tokenobj.token.pin_hash[0:2], "@@")
def test_43_encryptpin(self): serial = "ENC01" # encrypt pin on init init_token({"serial": serial, "genkey": 1, "pin": "Hallo", "encryptpin": True}) tokenobj = get_tokens(serial=serial)[0] self.assertEqual(tokenobj.token.pin_hash[0:2], "@@") # set a hashed pin set_pin(serial, "test", encrypt_pin=False) tokenobj = get_tokens(serial=serial)[0] self.assertTrue(tokenobj.token.pin_hash[0:2] != "@@") # set an encrypted PIN set_pin(serial, "test", encrypt_pin=True) tokenobj = get_tokens(serial=serial)[0] self.assertEqual(tokenobj.token.pin_hash[0:2], "@@") # assign the token with a PIN assign_token(serial, User(login="******", realm=self.realm1), pin="WellWell", encrypt_pin=True) # check if pinhash starts with "@@" to indicate the encryption tokenobj = get_tokens(serial=serial)[0] self.assertEqual(tokenobj.token.pin_hash[0:2], "@@")
def setpin(serial): app = create_app(config_name="production", config_file="/etc/privacyidea/pi.cfg", silent=True) with app.app_context(): # Set global values set_pin(serial, PIN)
def setUp(self): self.setUp_user_realms() # New token for the user "selfservice" Token("hotp1", "hotp", otpkey=self.otpkey, userid=1004, resolver=self.resolvername1, realm=self.realm1).save() # Define HOTP token to be challenge response set_policy(name="pol_cr", scope=SCOPE.AUTH, action="{0!s}=hotp".format(ACTION.CHALLENGERESPONSE)) set_policy(name="webuilog", scope=SCOPE.WEBUI, action="{0!s}=privacyIDEA".format(ACTION.LOGINMODE)) from privacyidea.lib.token import set_pin set_pin("hotp1", "pin")
def test_37_challenge(self): # We create a challenge by first sending the PIN of the HOTP token # then we answer the challenge by sending the OTP. num1 = Challenge.query.filter(Challenge.serial == "hotptoken").count() # The correct PIN will create a challenge r, reply = check_serial_pass("hotptoken", "hotppin") self.assertTrue(r is False, r) num2 = Challenge.query.filter(Challenge.serial == "hotptoken").count() # check that the challenge is created self.assertTrue(num1 + 1 == num2, (num1, num2)) self.assertTrue(type(reply) == dict, reply) transaction_id = reply.get("transaction_id", "") self.assertTrue(len(transaction_id) > 10, reply) # Challenge Response, with the transaction id r, reply = check_serial_pass("hotptoken", "436521", {"transaction_id": transaction_id}) self.assertTrue(r) self.assertTrue( reply.get("message") == "Found matching challenge", reply) # create two tokens with the same OTP Key and the same PIN, so # this token will create the same challenge # creating a challenge will not work! tokenobject = init_token({ "serial": "CHALL001", "type": "hotp", "otpkey": self.otpkey }) tokenobject = init_token({ "serial": "CHALL002", "type": "hotp", "otpkey": self.otpkey }) user = User("cornelius", realm=self.realm1) assign_token("CHALL001", user) assign_token("CHALL002", user) set_pin("CHALL001", "challpin") set_pin("CHALL002", "challpin") r, reply = check_user_pass(user, "challpin") self.assertFalse(r) self.assertTrue( "Multiple tokens to create a challenge found" in reply.get("message"), reply) remove_token("CHALL001") remove_token("CHALL002")
def test_37_challenge(self): # We create a challenge by first sending the PIN of the HOTP token # then we answer the challenge by sending the OTP. num1 = Challenge.query.filter(Challenge.serial == "hotptoken").count() # The correct PIN will create a challenge r, reply = check_serial_pass("hotptoken", "hotppin") self.assertTrue(r is False, r) num2 = Challenge.query.filter(Challenge.serial == "hotptoken").count() # check that the challenge is created self.assertTrue(num1 + 1 == num2, (num1, num2)) self.assertTrue(type(reply) == dict, reply) transaction_id = reply.get("transaction_id","") self.assertTrue(len(transaction_id) > 10, reply) # Challenge Response, with the transaction id r, reply = check_serial_pass("hotptoken", "436521", {"transaction_id": transaction_id}) self.assertTrue(r) self.assertTrue(reply.get("message") == "Found matching challenge", reply) # create two tokens with the same OTP Key and the same PIN, so # this token will create the same challenge # creating a challenge will not work! tokenobject = init_token({"serial": "CHALL001", "type": "hotp", "otpkey": self.otpkey}) tokenobject = init_token({"serial": "CHALL002", "type": "hotp", "otpkey": self.otpkey}) user = User("cornelius", realm=self.realm1) assign_token("CHALL001", user) assign_token("CHALL002", user) set_pin("CHALL001", "challpin") set_pin("CHALL002", "challpin") r, reply = check_user_pass(user, "challpin") self.assertFalse(r) self.assertTrue("Multiple tokens to create a challenge found" in reply.get("message"), reply) remove_token("CHALL001") remove_token("CHALL002")
def test_31_copy_token_pin(self): serial1 = "tcopy1" tobject1 = init_token({"serial": serial1, "genkey": 1}) r = set_pin(serial1, "secret") self.assertTrue(r) serial2 = "tcopy2" tobject2 = init_token({"serial": serial2, "genkey": 1}) r = copy_token_pin(serial1, serial2) self.assertTrue(r) # Now compare the pinhash self.assertTrue(tobject1.token.pin_hash == tobject2.token.pin_hash, "%s <> %s" % (tobject1.token.pin_hash, tobject2.token.pin_hash)) remove_token(serial1) remove_token(serial2)
def test_31_copy_token_pin(self): serial1 = "tcopy1" tobject1 = init_token({"serial": serial1, "genkey": 1}) r = set_pin(serial1, "secret") self.assertTrue(r) serial2 = "tcopy2" tobject2 = init_token({"serial": serial2, "genkey": 1}) r = copy_token_pin(serial1, serial2) self.assertTrue(r) # Now compare the pinhash self.assertTrue( tobject1.token.pin_hash == tobject2.token.pin_hash, "%s <> %s" % (tobject1.token.pin_hash, tobject2.token.pin_hash)) remove_token(serial1) remove_token(serial2)
def test_20_pin_token_so_user(self): serial = "pins" tokenobject = init_token({"serial": serial, "otpkey": "1234567890123456"}) # user parameter is wrong self.assertRaises(ParameterError, set_pin, serial, None, "1234") # user and serial is missing self.assertRaises(ParameterError, set_pin) # now set the pin self.assertTrue(set_pin(serial, "1234") == 1) self.assertTrue(tokenobject.token.check_pin("1234")) self.assertTrue(tokenobject.token.user_pin == "") self.assertTrue(set_pin_user(serial, "1234") == 1) self.assertTrue(tokenobject.token.user_pin != "") self.assertTrue(tokenobject.token.so_pin == "") self.assertTrue(set_pin_so(serial, "1234") == 1) self.assertTrue(tokenobject.token.so_pin != "") remove_token(serial)
def test_20_pin_token_so_user(self): serial = "pins" tokenobject = init_token({ "serial": serial, "otpkey": "1234567890123456" }) # user parameter is wrong self.assertRaises(ParameterError, set_pin, serial, None, "1234") # user and serial is missing self.assertRaises(ParameterError, set_pin) # now set the pin self.assertTrue(set_pin(serial, "1234") == 1) self.assertTrue(tokenobject.token.check_pin("1234")) self.assertTrue(tokenobject.token.user_pin == "") self.assertTrue(set_pin_user(serial, "1234") == 1) self.assertTrue(tokenobject.token.user_pin != "") self.assertTrue(tokenobject.token.so_pin == "") self.assertTrue(set_pin_so(serial, "1234") == 1) self.assertTrue(tokenobject.token.so_pin != "") remove_token(serial)
def test_34_check_token_list(self): # We can not authenticate with an unknown type # Such a token will not be returned by get_tokens... db_token = Token("serial72", tokentype="unknown") db_token.save() # set a matching OTP PIN for our hotp token set_pin("hotptoken", "hotppin40") tokenobject_list = get_tokens() # the HOTP token has the correct PIN but wrong otp value # The failcounter is increased hotp_tokenobject = get_tokens(serial="hotptoken")[0] hotp_tokenobject.set_pin("hotppin") hotp_tokenobject.save() old_failcount = hotp_tokenobject.token.failcount res, reply = check_token_list(tokenobject_list, "hotppin40123456") self.assertFalse(res) failcount = hotp_tokenobject.token.failcount self.assertTrue(failcount == old_failcount + 1, (old_failcount, failcount)) # if there is no token with at least a correct pin, we increase all # failcounters hotp_tokenobject = get_tokens(serial="hotptoken")[0] old_failcount = hotp_tokenobject.token.failcount res, reply = check_token_list(tokenobject_list, "everythingiswrong") self.assertFalse(res) failcount = hotp_tokenobject.token.failcount self.assertTrue(failcount == old_failcount + 1, (old_failcount, failcount)) # Now we do some successful auth with the HOTP token tokenobject_list = get_tokens(serial="hotptoken") """ Truncated Count Hexadecimal Decimal HOTP 0 4c93cf18 1284755224 755224 1 41397eea 1094287082 287082 2 82fef30 137359152 359152 3 66ef7655 1726969429 969429 4 61c5938a 1640338314 338314 5 33c083d4 868254676 254676 6 7256c032 1918287922 287922 7 4e5b397 82162583 162583 8 2823443f 673399871 399871 9 2679dc69 645520489 520489 10 403154 11 481090 12 868912 13 736127 """ hotp_tokenobject = tokenobject_list[0] old_counter = hotp_tokenobject.token.count res, reply = check_token_list(tokenobject_list, "hotppin399871") self.assertTrue(res) # check if the counter increased self.assertTrue(old_counter < hotp_tokenobject.token.count, (old_counter, hotp_tokenobject.token.count)) # but was it also increased in the database? tokenobject_list_new = get_tokens(serial="hotptoken") hotp_tokenobject_new = tokenobject_list_new[0] self.assertTrue(old_counter < hotp_tokenobject_new.token.count, (old_counter, hotp_tokenobject.token.count)) # False authentication old_failcount = hotp_tokenobject.token.failcount res, reply = check_token_list(tokenobject_list, "hotppin000000") self.assertFalse(res) # check the failcounter increased self.assertTrue(old_failcount + 1 == hotp_tokenobject.token.failcount) # Successful auth. The failcount needs to be resetted res, reply = check_token_list(tokenobject_list, "hotppin520489") self.assertTrue(res) self.assertTrue(hotp_tokenobject.token.failcount == 0) # Now we disable the hotp_tokenobject. If the token is disabled, # we must not be able to authenticate anymore with this very token. # But if the OTP value is valid, the counter is increased, anyway! old_counter = hotp_tokenobject.token.count hotp_tokenobject.enable(False) res, reply = check_token_list(tokenobject_list, "hotppin403154") self.assertFalse(res) self.assertTrue("Token is disabled" in reply.get("message")) self.assertEqual(old_counter + 1, hotp_tokenobject.token.count) # enable the token again hotp_tokenobject.enable(True)
def do(self, action, options=None): """ This method executes the defined action in the given event. :param action: :param options: Contains the flask parameters g, request, response and the handler_def configuration :type options: dict :return: """ ret = True g = options.get("g") request = options.get("request") response = options.get("response") content = self._get_response_content(response) handler_def = options.get("handler_def") handler_options = handler_def.get("options", {}) serial = request.all_data.get("serial") or \ content.get("detail", {}).get("serial") or \ g.audit_object.audit_data.get("serial") if action.lower() in [ACTION_TYPE.SET_TOKENREALM, ACTION_TYPE.SET_DESCRIPTION, ACTION_TYPE.DELETE, ACTION_TYPE.DISABLE, ACTION_TYPE.ENABLE, ACTION_TYPE.UNASSIGN, ACTION_TYPE.SET_VALIDITY, ACTION_TYPE.SET_COUNTWINDOW, ACTION_TYPE.SET_TOKENINFO, ACTION_TYPE.SET_FAILCOUNTER, ACTION_TYPE.CHANGE_FAILCOUNTER, ACTION_TYPE.SET_RANDOM_PIN, ACTION_TYPE.DELETE_TOKENINFO]: if serial: log.info("{0!s} for token {1!s}".format(action, serial)) if action.lower() == ACTION_TYPE.SET_TOKENREALM: realm = handler_options.get("realm") only_realm = is_true(handler_options.get("only_realm")) # Set the realm.. log.info("Setting realm of token {0!s} to {1!s}".format( serial, realm)) # Add the token realm set_realms(serial, [realm], add=not only_realm) elif action.lower() == ACTION_TYPE.SET_RANDOM_PIN: # If for any reason we have no value, we default to 6 length = int(handler_options.get("length") or 6) pin = generate_password(size=length) if set_pin(serial, pin): content.setdefault("detail", {})["pin"] = pin options.get("response").data = json.dumps(content) elif action.lower() == ACTION_TYPE.DELETE: remove_token(serial=serial) elif action.lower() == ACTION_TYPE.DISABLE: enable_token(serial, enable=False) elif action.lower() == ACTION_TYPE.ENABLE: enable_token(serial, enable=True) elif action.lower() == ACTION_TYPE.UNASSIGN: unassign_token(serial) elif action.lower() == ACTION_TYPE.SET_DESCRIPTION: description = handler_options.get("description") or "" description, td = parse_time_offset_from_now(description) s_now = (datetime.datetime.now(tzlocal()) + td).strftime( AUTH_DATE_FORMAT) set_description(serial, description.format( current_time=s_now, now=s_now, client_ip=g.client_ip, ua_browser=request.user_agent.browser, ua_string=request.user_agent.string)) elif action.lower() == ACTION_TYPE.SET_COUNTWINDOW: set_count_window(serial, int(handler_options.get("count window", 50))) elif action.lower() == ACTION_TYPE.SET_TOKENINFO: tokeninfo = handler_options.get("value") or "" tokeninfo, td = parse_time_offset_from_now(tokeninfo) s_now = (datetime.datetime.now(tzlocal()) + td).strftime( AUTH_DATE_FORMAT) try: username = request.User.loginname realm = request.User.realm except Exception: username = "******" realm = "N/A" add_tokeninfo(serial, handler_options.get("key"), tokeninfo.format( current_time=s_now, now=s_now, client_ip=g.client_ip, username=username, realm=realm, ua_browser=request.user_agent.browser, ua_string=request.user_agent.string)) elif action.lower() == ACTION_TYPE.DELETE_TOKENINFO: delete_tokeninfo(serial, handler_options.get("key")) elif action.lower() == ACTION_TYPE.SET_VALIDITY: start_date = handler_options.get(VALIDITY.START) end_date = handler_options.get(VALIDITY.END) if start_date: d = parse_date(start_date) set_validity_period_start(serial, None, d.strftime(DATE_FORMAT)) if end_date: d = parse_date(end_date) set_validity_period_end(serial, None, d.strftime(DATE_FORMAT)) elif action.lower() == ACTION_TYPE.SET_FAILCOUNTER: try: set_failcounter(serial, int(handler_options.get("fail counter"))) except Exception as exx: log.warning("Misconfiguration: Failed to set fail " "counter!") elif action.lower() == ACTION_TYPE.CHANGE_FAILCOUNTER: try: token_obj = get_one_token(serial=serial) token_obj.set_failcount( token_obj.token.failcount + int(handler_options.get("change fail counter"))) except Exception as exx: log.warning("Misconfiguration: Failed to increase or decrease fail " "counter!") else: log.info("Action {0!s} requires serial number. But no serial " "number could be found in request.") if action.lower() == ACTION_TYPE.INIT: log.info("Initializing new token") init_param = {"type": handler_options.get("tokentype"), "genkey": 1, "realm": handler_options.get("realm", "")} user = None if is_true(handler_options.get("user")): user = self._get_tokenowner(request) tokentype = handler_options.get("tokentype") # Some tokentypes need additional parameters if handler_options.get("additional_params"): add_params = yaml.safe_load(handler_options.get("additional_params")) if type(add_params) == dict: init_param.update(add_params) if tokentype == "sms": if handler_options.get("dynamic_phone"): init_param["dynamic_phone"] = 1 else: init_param['phone'] = user.get_user_phone( phone_type='mobile', index=0) if not init_param['phone']: log.warning("Enrolling SMS token. But the user " "{0!r} has no mobile number!".format(user)) if handler_options.get("sms_identifier"): init_param["sms.identifier"] = handler_options.get("sms_identifier") elif tokentype == "email": if handler_options.get("dynamic_email"): init_param["dynamic_email"] = 1 else: init_param['email'] = user.info.get("email", "") if not init_param['email']: log.warning("Enrolling EMail token. But the user {0!s}" "has no email address!".format(user)) if handler_options.get("smtp_identifier"): init_param["email.identifier"] = handler_options.get("smtp_identifier") elif tokentype == "motp": init_param['motppin'] = handler_options.get("motppin") t = init_token(param=init_param, user=user) log.info("New token {0!s} enrolled.".format(t.token.serial)) return ret