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 = json.loads(response.data) 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.DELETE, ACTION_TYPE.DISABLE, ACTION_TYPE.ENABLE, ACTION_TYPE.UNASSIGN]: if serial: if action.lower() == ACTION_TYPE.SET_TOKENREALM: realm = handler_options.get("realm") only_realm = 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=True) elif action.lower() == ACTION_TYPE.DELETE: log.info("Delete token {0!s}".format(serial)) remove_token(serial=serial) elif action.lower() == ACTION_TYPE.DISABLE: log.info("Disable token {0!s}".format(serial)) enable_token(serial, enable=False) elif action.lower() == ACTION_TYPE.ENABLE: log.info("Enable token {0!s}".format(serial)) enable_token(serial, enable=True) elif action.lower() == ACTION_TYPE.UNASSIGN: log.info("Unassign token {0!s}".format(serial)) unassign_token(serial) 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") t = init_token({"type": handler_options.get("tokentype"), "genkey": 1, "realm": handler_options.get("realm", "")}) log.info("New token {0!s} enrolled.".format(t.token.serial)) return ret
def test_05_user_can_disable_token(self): self.authenticate_selfservice_user() # User can not disable a token, that does not belong to him. with self.app.test_request_context( '/token/disable/{0!s}'.format(self.foreign_serial), method='POST', headers={'Authorization': self.at_user}): res = self.app.full_dispatch_request() self.assertEqual(res.status_code, 404) response = json.loads(res.data.decode('utf8')) self.assertFalse(response["result"]["status"]) tokenobject = get_tokens(serial=self.foreign_serial)[0] self.assertTrue(tokenobject.token.active, tokenobject.token.active) # User disables his token with self.app.test_request_context( '/token/disable/{0!s}'.format(self.my_serial), method='POST', headers={'Authorization': self.at_user}): res = self.app.full_dispatch_request() self.assertTrue(res.status_code == 200, res) response = json.loads(res.data.decode('utf8')) self.assertTrue( response.get("result").get("value"), response.get("result")) tokenobject = get_tokens(serial=self.my_serial)[0] self.assertFalse(tokenobject.token.active, tokenobject.token.active) # User enables his token with self.app.test_request_context( '/token/enable/{0!s}'.format(self.my_serial), method='POST', headers={'Authorization': self.at_user}): res = self.app.full_dispatch_request() self.assertTrue(res.status_code == 200, res) response = json.loads(res.data.decode('utf8')) self.assertTrue( response.get("result").get("value"), response.get("result")) tokenobject = get_tokens(serial=self.my_serial)[0] self.assertTrue(tokenobject.token.active, tokenobject.token.active) # User can not enable foreign token enable_token(self.foreign_serial, enable=False) # Is token disabled? tokenobject = get_tokens(serial=self.foreign_serial)[0] self.assertFalse(tokenobject.token.active, tokenobject.token.active) with self.app.test_request_context( '/token/enable/{0!s}'.format(self.foreign_serial), method='POST', headers={'Authorization': self.at_user}): res = self.app.full_dispatch_request() self.assertEqual(res.status_code, 404) response = json.loads(res.data.decode('utf8')) self.assertFalse(response["result"]["status"]) # token still inactive tokenobject = get_tokens(serial=self.foreign_serial)[0] self.assertFalse(tokenobject.token.active, tokenobject.token.active)
def test_45_check_realm_pass(self): # create a bunch of tokens in the realm # disabled token serial = "inactive" init_token({"serial": serial, "otpkey": self.otpkey, "pin": serial}, User("cornelius", self.realm1)) enable_token(serial, False) # not assigned token serial = "not_assigned" init_token({"serial": serial, "otpkey": self.otpkey, "pin": serial}, tokenrealms=[self.realm1]) # a normal token serial = "assigned" init_token({"serial": serial, "otpkey": self.otpkey, "pin": serial}, User("cornelius", self.realm1)) # check if the tokens were created accordingly tokens = get_tokens(realm=self.realm1, tokentype="hotp", assigned=False, serial="not_assigned") self.assertEqual(len(tokens), 1) tokens = get_tokens(realm=self.realm1, tokentype="hotp", active=False, serial="inactive") self.assertEqual(len(tokens), 1) tokens = get_tokens(realm=self.realm1, tokentype="hotp", active=True, assigned=True, serial="assigned") self.assertEqual(len(tokens), 1) # an inactive token does not match r = check_realm_pass(self.realm1, "inactive" + "287082") self.assertEqual(r[0], False) # The remaining tokens are checked, but the pin does not match, # so we get "wrong otp pin" self.assertEqual(r[1].get("message"), "wrong otp pin") # an unassigned token does not match r = check_realm_pass(self.realm1, "unassigned" + "287082") self.assertEqual(r[0], False) # The remaining tokens are checked, but the pin does not match, # so we get "wrong otp pin" self.assertEqual(r[1].get("message"), "wrong otp pin") # a token assigned to a user does match r = check_realm_pass(self.realm1, "assigned" + "287082") # One token in the realm matches the pin and the OTP value self.assertEqual(r[0], True) # The remaining tokens are checked, but the pin does not match, # so we get "wrong otp pin" self.assertEqual(r[1].get("message"), "matching 1 tokens")
def test_12_challenge_response_sms(self): # set a chalresp policy for SMS with self.app.test_request_context('/policy/pol_chal_resp', data={'action': "challenge_response=sms", 'scope': "authentication", 'realm': '', 'active': True}, method='POST', headers={'Authorization': self.at}): res = self.app.full_dispatch_request() self.assertTrue(res.status_code == 200, res) result = json.loads(res.data).get("result") self.assertTrue(result["status"] is True, result) self.assertTrue('"setPolicy pol_chal_resp": 1' in res.data, res.data) serial = "CHALRESP2" pin = "chalresp2" # create a token and assign to the user init_token({"serial": serial, "type": "sms", "otpkey": self.otpkey, "phone": "123456", "pin": pin}, user=User("cornelius", self.realm1)) # create the challenge by authenticating with the OTP PIN with self.app.test_request_context('/validate/check', method='POST', data={"user": "******", "pass": pin}): res = self.app.full_dispatch_request() self.assertTrue(res.status_code == 200, res) result = json.loads(res.data).get("result") detail = json.loads(res.data).get("detail") self.assertFalse(result.get("value")) self.assertTrue("The PIN was correct, " "but the SMS could not be sent" in detail.get("message")) transaction_id = detail.get("transaction_id") # disable the token. The detail->message should be empty r = enable_token(serial=serial, enable=False) self.assertEqual(r, True) with self.app.test_request_context('/validate/check', method='POST', data={"user": "******", "pass": pin}): res = self.app.full_dispatch_request() self.assertTrue(res.status_code == 200, res) result = json.loads(res.data).get("result") detail = json.loads(res.data).get("detail") self.assertFalse(result.get("value")) self.assertEqual(detail.get("message"), "Token is disabled") # delete the token remove_token(serial=serial)
def test_21_validate_disabled(self): # test a user with two tokens and otppin=userstore. # One token is disabled. But the user must be able to login with the # 2nd token # user disableduser, realm: self.realm2, passwd: superSecret set_policy(name="disalbed", scope=SCOPE.AUTH, action="%s=%s" % (ACTION.OTPPIN, "userstore")) # enroll two tokens r = init_token({"type": "spass", "serial": "spass1d"}, user=User("disableduser", self.realm2)) r = init_token({"type": "spass", "serial": "spass2d"}, user=User("disableduser", self.realm2)) # disable first token r = enable_token("spass1d", False) self.assertEqual(r, True) # Check that the user still can authenticate with the 2nd token with self.app.test_request_context('/validate/check', method='POST', data={"user": "******", "realm": self.realm2, "pass": "******"}): res = self.app.full_dispatch_request() self.assertTrue(res.status_code == 200, res) result = json.loads(res.data).get("result") self.assertEqual(result.get("value"), True) # disable 2nd token r = enable_token("spass2d", False) r = enable_token("spass1d") self.assertEqual(r, True) # Check that the user still can authenticate with the first token with self.app.test_request_context('/validate/check', method='POST', data={"user": "******", "realm": self.realm2, "pass": "******"}): res = self.app.full_dispatch_request() self.assertTrue(res.status_code == 200, res) result = json.loads(res.data).get("result") self.assertEqual(result.get("value"), True) delete_policy("disabled")
def modify_token(username, realm, ttype): app = create_app(config_name="production", config_file="/etc/privacyidea/pi.cfg", silent=True) with app.app_context(): user_obj = User(username, realm) if user_obj: # Get all active tokens of this types from this user toks = get_tokens(user=user_obj, tokentype=ttype, active=True) # Delete all SMS tokens. for tok_obj in toks: serial = tok_obj.token.serial if ACTION == "delete": tok_obj.delete_token() else: enable_token(serial, False) with open(LOGFILE, "a") as f: f.write(u"{0!s}, {1!s}, {2!s}, {3!s}, {4!s}\n".format( datetime.datetime.now().strftime("%Y-%m-%dT%H:%M"), args.username, args.realm, ACTION, serial))
def test_21_enable_disable(self): serial = "enable" tokenobject = init_token({"serial": serial, "otpkey": "1234567890123456"}) # an active token does not need to be enabled r = enable_token(serial) self.assertTrue(r == 0, r) r = enable_token(serial, enable=False) self.assertTrue(r == 1, r) self.assertTrue(tokenobject.token.active == False, tokenobject.token.active) self.assertFalse(is_token_active(serial)) r = enable_token(serial) self.assertTrue(r == 1, r) self.assertTrue(is_token_active(serial)) remove_token(serial) self.assertTrue(is_token_active(serial) is None) self.assertRaises(ParameterError, enable_token)
def test_21_enable_disable(self): serial = "enable" tokenobject = init_token({ "serial": serial, "otpkey": "1234567890123456" }) # an active token does not need to be enabled r = enable_token(serial) self.assertTrue(r == 0, r) r = enable_token(serial, enable=False) self.assertTrue(r == 1, r) self.assertTrue(tokenobject.token.active == False, tokenobject.token.active) self.assertFalse(is_token_active(serial)) r = enable_token(serial) self.assertTrue(r == 1, r) self.assertTrue(is_token_active(serial)) remove_token(serial) self.assertTrue(is_token_active(serial) is None) self.assertRaises(ParameterError, enable_token)
def test_05_user_can_disable_token(self): self.authenticate_selfserive_user() # User can not disable a token, that does not belong to him. with self.app.test_request_context('/token/disable/%s' % self.foreign_serial, method='POST', headers={'Authorization': self.at_user}): res = self.app.full_dispatch_request() self.assertTrue(res.status_code == 200, res) response = json.loads(res.data) self.assertFalse(response.get("result").get("value"), response.get("result")) tokenobject = get_tokens(serial=self.foreign_serial)[0] self.assertTrue(tokenobject.token.active, tokenobject.token.active) # User disables his token with self.app.test_request_context('/token/disable/%s' % self.my_serial, method='POST', headers={'Authorization': self.at_user}): res = self.app.full_dispatch_request() self.assertTrue(res.status_code == 200, res) response = json.loads(res.data) self.assertTrue(response.get("result").get("value"), response.get("result")) tokenobject = get_tokens(serial=self.my_serial)[0] self.assertFalse(tokenobject.token.active, tokenobject.token.active) # User enables his token with self.app.test_request_context('/token/enable/%s' % self.my_serial, method='POST', headers={'Authorization': self.at_user}): res = self.app.full_dispatch_request() self.assertTrue(res.status_code == 200, res) response = json.loads(res.data) self.assertTrue(response.get("result").get("value"), response.get("result")) tokenobject = get_tokens(serial=self.my_serial)[0] self.assertTrue(tokenobject.token.active, tokenobject.token.active) # User can not enable foreign token enable_token(self.foreign_serial, enable=False) # Is token disabled? tokenobject = get_tokens(serial=self.foreign_serial)[0] self.assertFalse(tokenobject.token.active, tokenobject.token.active) with self.app.test_request_context('/token/enable/%s' % self.foreign_serial, method='POST', headers={'Authorization': self.at_user}): res = self.app.full_dispatch_request() self.assertTrue(res.status_code == 200, res) response = json.loads(res.data) self.assertTrue(response.get("result").get("value") == 0, response.get("result")) # token still inactive tokenobject = get_tokens(serial=self.foreign_serial)[0] self.assertFalse(tokenobject.token.active, tokenobject.token.active)
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
def test_03_unfinished_enrolled_push_token(self): """ * The user has a push token where the enrollment process was not completed A /validate/check request is sent with this PIN. """ # set policy set_policy("push2", scope=SCOPE.ENROLL, action="{0!s}={1!s},{2!s}={3!s}".format( PUSH_ACTION.FIREBASE_CONFIG, self.firebase_config_name, PUSH_ACTION.REGISTRATION_URL, REGISTRATION_URL)) # Create push config r = set_smsgateway( self.firebase_config_name, u'privacyidea.lib.smsprovider.FirebaseProvider.FirebaseProvider', "myFB", FB_CONFIG_VALS) self.assertTrue(r > 0) # create push token for user # 1st step with self.app.test_request_context('/token/init', method='POST', data={ "type": "push", "pin": "otppin", "user": "******", "realm": self.realm1, "serial": self.serial_push, "genkey": 1 }, headers={'Authorization': self.at}): res = self.app.full_dispatch_request() self.assertEqual(res.status_code, 200) detail = res.json.get("detail") serial = detail.get("serial") self.assertEqual(detail.get("rollout_state"), "clientwait") self.assertTrue("pushurl" in detail) # check that the new URL contains the serial number self.assertTrue( "&serial=PIPU" in detail.get("pushurl").get("value")) self.assertTrue("appid=" in detail.get("pushurl").get("value")) self.assertTrue("appidios=" in detail.get("pushurl").get("value")) self.assertTrue("apikeyios=" in detail.get("pushurl").get("value")) self.assertFalse("otpkey" in detail) enrollment_credential = detail.get("enrollment_credential") # We skip the 2nd step of the enrollment! # But we activate the token on purpose! enable_token(self.serial_push) # authenticate with push with self.app.test_request_context('/validate/check', method='POST', data={ "user": "******", "realm": self.realm1, "pass": "******" }): res = self.app.full_dispatch_request() self.assertEqual(res.status_code, 200) data = res.json self.assertFalse(data.get("result").get("value")) detail = data.get("detail") self.assertEqual(detail.get("message"), "Token is not yet enrolled") remove_token(self.serial_push) delete_policy("push2")
def test_02_push_token_do_not_wait_if_disabled(self): """ * Policy push_wait * The user has two tokens. HOTP chal-resp and Push with the same PIN. * But in this case, the push token is disabled. * The user should get the response immediately. A /validate/check request is sent with this PIN. The PIN will only trigger the HOTP, push will not wait, since it is disabled. """ # set policy set_policy("push1", action="{0!s}=20".format(PUSH_ACTION.WAIT), scope=SCOPE.AUTH) set_policy("push2", scope=SCOPE.ENROLL, action="{0!s}={1!s},{2!s}={3!s}".format( PUSH_ACTION.FIREBASE_CONFIG, self.firebase_config_name, PUSH_ACTION.REGISTRATION_URL, REGISTRATION_URL)) set_policy("chalresp", action="{0!s}=hotp".format(ACTION.CHALLENGERESPONSE), scope=SCOPE.AUTH) # Create push config r = set_smsgateway( self.firebase_config_name, u'privacyidea.lib.smsprovider.FirebaseProvider.FirebaseProvider', "myFB", FB_CONFIG_VALS) self.assertTrue(r > 0) # create push token for user # 1st step with self.app.test_request_context('/token/init', method='POST', data={ "type": "push", "pin": "otppin", "user": "******", "realm": self.realm1, "serial": self.serial_push, "genkey": 1 }, headers={'Authorization': self.at}): res = self.app.full_dispatch_request() self.assertEqual(res.status_code, 200) detail = res.json.get("detail") serial = detail.get("serial") self.assertEqual(detail.get("rollout_state"), "clientwait") self.assertTrue("pushurl" in detail) # check that the new URL contains the serial number self.assertTrue( "&serial=PIPU" in detail.get("pushurl").get("value")) self.assertTrue("appid=" in detail.get("pushurl").get("value")) self.assertTrue("appidios=" in detail.get("pushurl").get("value")) self.assertTrue("apikeyios=" in detail.get("pushurl").get("value")) self.assertFalse("otpkey" in detail) enrollment_credential = detail.get("enrollment_credential") # 2nd step: as performed by the smartphone with self.app.test_request_context( '/ttype/push', method='POST', data={ "enrollment_credential": enrollment_credential, "serial": serial, "pubkey": self.smartphone_public_key_pem_urlsafe, "fbtoken": "firebaseT" }): res = self.app.full_dispatch_request() self.assertTrue(res.status_code == 200, res) detail = res.json.get("detail") # still the same serial number self.assertEqual(serial, detail.get("serial")) self.assertEqual(detail.get("rollout_state"), "enrolled") # Now the smartphone gets a public key from the server augmented_pubkey = "-----BEGIN RSA PUBLIC KEY-----\n{}\n-----END RSA PUBLIC KEY-----\n".format( detail.get("public_key")) parsed_server_pubkey = serialization.load_pem_public_key( to_bytes(augmented_pubkey), default_backend()) self.assertIsInstance(parsed_server_pubkey, RSAPublicKey) pubkey = detail.get("public_key") # Now check, what is in the token in the database toks = get_tokens(serial=serial) self.assertEqual(len(toks), 1) token_obj = toks[0] self.assertEqual(token_obj.token.rollout_state, u"enrolled") self.assertTrue(token_obj.token.active) tokeninfo = token_obj.get_tokeninfo() self.assertEqual(tokeninfo.get("public_key_smartphone"), self.smartphone_public_key_pem_urlsafe) self.assertEqual(tokeninfo.get("firebase_token"), u"firebaseT") self.assertEqual( tokeninfo.get("public_key_server").strip().strip( "-BEGIN END RSA PUBLIC KEY-").strip(), pubkey) # The token should also contain the firebase config self.assertEqual(tokeninfo.get(PUSH_ACTION.FIREBASE_CONFIG), self.firebase_config_name) # create HOTP token for user init_token( { "serial": "hotp01", "type": "hotp", "pin": "otppin", "otpkey": self.otpkey }, user=User("selfservice", self.realm1)) # disable the push token enable_token(self.serial_push, False) # check, if the user has two tokens, now toks = get_tokens(user=User("selfservice", self.realm1)) self.assertEqual(2, len(toks)) self.assertEqual("push", toks[0].type) self.assertFalse(toks[0].is_active()) self.assertEqual("hotp", toks[1].type) # authenticate with hotp with self.app.test_request_context('/validate/check', method='POST', data={ "user": "******", "realm": self.realm1, "pass": "******" }): res = self.app.full_dispatch_request() self.assertEqual(res.status_code, 200) data = res.json self.assertFalse(data.get("result").get("value")) # This is the auth-request for the HOTP token detail = data.get("detail") multi_challenge = detail.get("multi_challenge") self.assertEqual(multi_challenge[0].get("type"), "hotp") self.assertEqual(multi_challenge[0].get("serial"), "hotp01") self.assertEqual("interactive", multi_challenge[0].get("client_mode")) remove_token(self.serial_push) remove_token("hotp01") delete_policy("push1") delete_policy("push2") delete_policy("chalresp")
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 = json.loads(response.data) 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]: if serial: if action.lower() == ACTION_TYPE.SET_TOKENREALM: realm = handler_options.get("realm") only_realm = 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=True) elif action.lower() == ACTION_TYPE.DELETE: log.info("Delete token {0!s}".format(serial)) remove_token(serial=serial) elif action.lower() == ACTION_TYPE.DISABLE: log.info("Disable token {0!s}".format(serial)) enable_token(serial, enable=False) elif action.lower() == ACTION_TYPE.ENABLE: log.info("Enable token {0!s}".format(serial)) enable_token(serial, enable=True) elif action.lower() == ACTION_TYPE.UNASSIGN: log.info("Unassign token {0!s}".format(serial)) unassign_token(serial) elif action.lower() == ACTION_TYPE.SET_DESCRIPTION: log.info("Set description of token {0!s}".format(serial)) set_description(serial, handler_options.get( "description", "")) elif action.lower() == ACTION_TYPE.SET_VALIDITY: log.info("Set validity period for token {0!s}".format( serial)) 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)) 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") if handler_options.get("user") in ["1", 1, True]: user = self._get_tokenowner(request) else: user = None t = init_token({"type": handler_options.get("tokentype"), "genkey": 1, "realm": handler_options.get("realm", "")}, user=user) log.info("New token {0!s} enrolled.".format(t.token.serial)) return ret
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 = json.loads(response.data) 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]: 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 = 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=True) 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: s_now = datetime.datetime.now(tzlocal()).strftime(AUTH_DATE_FORMAT) set_description(serial, (handler_options.get("description") or "").format(current_time=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: s_now = datetime.datetime.now(tzlocal()).strftime(AUTH_DATE_FORMAT) add_tokeninfo(serial, handler_options.get("key"), (handler_options.get("value") or "").format( current_time=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_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)) 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 or otherwise # will fail to enroll. # TODO: Other tokentypes will require additional parameters if tokentype == "sms": init_param['phone'] = user.get_user_phone( phone_type='mobile') if not init_param['phone']: log.warning("Enrolling SMS token. But the user " "{0!s} has no mobile number!".format(user)) elif tokentype == "email": 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)) 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
def test_45_check_realm_pass(self): # create a bunch of tokens in the realm # disabled token serial = "inactive" init_token({ "serial": serial, "otpkey": self.otpkey, "pin": serial }, User("cornelius", self.realm1)) enable_token(serial, False) # not assigned token serial = "not_assigned" init_token({ "serial": serial, "otpkey": self.otpkey, "pin": serial }, tokenrealms=[self.realm1]) # a normal token serial = "assigned" init_token({ "serial": serial, "otpkey": self.otpkey, "pin": serial }, User("cornelius", self.realm1)) # check if the tokens were created accordingly tokens = get_tokens(realm=self.realm1, tokentype="hotp", assigned=False, serial="not_assigned") self.assertEqual(len(tokens), 1) tokens = get_tokens(realm=self.realm1, tokentype="hotp", active=False, serial="inactive") self.assertEqual(len(tokens), 1) tokens = get_tokens(realm=self.realm1, tokentype="hotp", active=True, assigned=True, serial="assigned") self.assertEqual(len(tokens), 1) # an inactive token does not match r = check_realm_pass(self.realm1, "inactive" + "287082") self.assertEqual(r[0], False) # The remaining tokens are checked, but the pin does not match, # so we get "wrong otp pin" self.assertEqual(r[1].get("message"), "wrong otp pin") # an unassigned token does not match r = check_realm_pass(self.realm1, "unassigned" + "287082") self.assertEqual(r[0], False) # The remaining tokens are checked, but the pin does not match, # so we get "wrong otp pin" self.assertEqual(r[1].get("message"), "wrong otp pin") # a token assigned to a user does match r = check_realm_pass(self.realm1, "assigned" + "287082") # One token in the realm matches the pin and the OTP value self.assertEqual(r[0], True) # The remaining tokens are checked, but the pin does not match, # so we get "wrong otp pin" self.assertEqual(r[1].get("message"), "matching 1 tokens")
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 = json.loads(response.data) 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 ]: 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 = 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=True) 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: s_now = datetime.datetime.now().strftime(AUTH_DATE_FORMAT) set_description(serial, (handler_options.get("description") or "").format( current_time=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: s_now = datetime.datetime.now().strftime(AUTH_DATE_FORMAT) add_tokeninfo(serial, handler_options.get("key"), (handler_options.get("value") or "").format( current_time=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_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)) 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 or otherwise # will fail to enroll. # TODO: Other tokentypes will require additional parameters if tokentype == "sms": init_param['phone'] = user.get_user_phone( phone_type='mobile') if not init_param['phone']: log.warning("Enrolling SMS token. But the user " "{0!s} has no mobile number!".format(user)) elif tokentype == "email": 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)) 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
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.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.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!") 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)) 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)) 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