def setUp(self): # Use a the gateway definition for configuring the provider identifier = "mySmppGW" id = set_smsgateway(identifier, self.provider_module, description="test", options=self.config) self.assertTrue(id > 0) self.provider = create_sms_instance(identifier=identifier) self.assertEqual(type(self.provider), SmppSMSProvider)
def test_00_errors(self): # No smsgateway defined s = SmppSMSProvider() self.assertRaises(SMSError, s.submit_message, "phone", "message") # No host defined set_smsgateway("missing_host", self.provider_module, options={"SMSC_PORT": "1234"}) p = create_sms_instance(identifier="missing_host") self.assertRaises(SMSError, p.submit_message, "phone", "message") delete_smsgateway("missing_host") # No port defined set_smsgateway("missing_port", self.provider_module, options={"SMSC_HOST": "1.1.1.1"}) p = create_sms_instance(identifier="missing_port") self.assertRaises(SMSError, p.submit_message, "phone", "message") delete_smsgateway("missing_port")
def test_02_create_modify_delete_smsgateway_configuration(self): identifier = "myGW" provider_module = "privacyidea.lib.smsprovider.HTTPSmsPrpvoder" id = set_smsgateway(identifier, provider_module, description="test", options={"HTTP_METHOD": "POST", "URL": "example.com"}) self.assertTrue(id > 0) gw = get_smsgateway(id=id) self.assertEqual(gw[0].description, "test") # update the description set_smsgateway(identifier, provider_module, description="This is a sensible description") gw = get_smsgateway(id=id) self.assertEqual(gw[0].description, "This is a sensible description") # update some options set_smsgateway(identifier, provider_module, options={"HTTP_METHOD": "POST", "URL": "example.com", "new key": "value"}) gw = get_smsgateway(id=id) self.assertEqual(len(gw[0].option_dict), 3) self.assertEqual(gw[0].option_dict.get("HTTP_METHOD"), "POST") self.assertEqual(gw[0].option_dict.get("URL"), "example.com") self.assertEqual(gw[0].option_dict.get("new key"), "value") # delete a single option r = delete_smsgateway_option(id, "URL") gw = get_smsgateway(id=id) self.assertEqual(len(gw[0].option_dict), 2) self.assertEqual(gw[0].option_dict.get("HTTP_METHOD"), "POST") self.assertEqual(gw[0].option_dict.get("URL"), None) self.assertEqual(gw[0].option_dict.get("new key"), "value") # finally delete the gateway definition r = delete_smsgateway(identifier) self.assertEqual(r, id) # delete successful? gw = get_smsgateway() self.assertEqual(len(gw), 0)
def test_08_smsgateway_success(self): responses.add(responses.POST, self.url) identifier = "mySMS" provider_module = "privacyidea.lib.smsprovider.SipgateSMSProvider" \ ".SipgateSMSProvider" id = set_smsgateway(identifier, provider_module, description="test", options=self.config) self.assertTrue(id > 0) sms = create_sms_instance(identifier) r = sms.submit_message("123456", "Hello") self.assertTrue(r)
def test_03_sendsms(self): # setup realms self.setUp_user_realms() r = set_smsgateway(identifier="myGW", providermodule="privacyidea.lib.smsprovider." "SmtpSMSProvider.SmtpSMSProvider", options={ "SMTPIDENTIFIER": "myserver", "MAILTO": "*****@*****.**" }) self.assertTrue(r > 0) smtpmock.setdata(response={"*****@*****.**": (200, "OK")}, support_tls=False) g = FakeFlaskG() audit_object = FakeAudit() audit_object.audit_data["serial"] = "123456" g.logged_in_user = {"user": "******", "role": "admin", "realm": ""} g.audit_object = audit_object builder = EnvironBuilder(method='POST', data={'serial': "OATH123456"}, headers={}) env = builder.get_environ() # Set the remote address so that we can filter for it env["REMOTE_ADDR"] = "10.0.0.1" g.client_ip = env["REMOTE_ADDR"] req = Request(env) req.all_data = {"serial": "SomeSerial", "user": "******"} req.User = User("cornelius", self.realm1) resp = Response() resp.data = """{"result": {"value": true}}""" options = { "g": g, "request": req, "response": resp, "handler_def": { "options": { "smsconfig": "myGW" } } } un_handler = UserNotificationEventHandler() res = un_handler.do("sendsms", options=options) self.assertTrue(res)
def test_03_create_instance_by_identifier(self): # SMS gateway definition identifier = "myGW" provider_module = "privacyidea.lib.smsprovider.HttpSMSProvider" \ ".HttpSMSProvider" id = set_smsgateway(identifier, provider_module, description="test", options={"HTTP_METHOD": "POST", "URL": "example.com"}) self.assertTrue(id > 0) sms = create_sms_instance(identifier) self.assertEqual(sms.smsgateway.option_dict.get("URL"), "example.com") self.assertEqual(sms.smsgateway.option_dict.get("HTTP_METHOD"), "POST")
def test_02_fail(self): # The script returns a failing rcode identifier = "myScriptSMS" config = {"background": SCRIPT_WAIT, "script": "fail.sh"} provider_module = "privacyidea.lib.smsprovider.ScriptSMSProvider" \ ".ScriptSMSProvider" id = set_smsgateway(identifier, provider_module, description="test", options=config) self.assertTrue(id > 0) sms = ScriptSMSProvider(smsgateway=get_smsgateway(identifier)[0], directory=self.directory) self.assertRaises(SMSError, sms.submit_message, "123456", "Hello") delete_smsgateway(identifier)
def test_03_create_instance_by_identifier(self): # SMS gateway definition identifier = "myGW" provider_module = "privacyidea.lib.smsprovider.HttpSMSProvider" \ ".HttpSMSProvider" id = set_smsgateway(identifier, provider_module, description="test", options={"HTTP_METHOD": "POST", "URL": "example.com"}) self.assertTrue(id > 0) sms = create_sms_instance(identifier) self.assertEqual(sms.smsgateway.option_dict.get("URL"), "example.com") self.assertEqual(sms.smsgateway.option_dict.get("HTTP_METHOD"), "POST")
def test_02_success(self): # the script runs successfully identifier = "myScriptSMS" config = {"background": SCRIPT_WAIT, "script": "success.sh"} provider_module = "privacyidea.lib.smsprovider.ScriptSMSProvider" \ ".ScriptSMSProvider" id = set_smsgateway(identifier, provider_module, description="test", options=config) self.assertTrue(id > 0) sms = ScriptSMSProvider(smsgateway=get_smsgateway(identifier)[0], directory=self.directory) r = sms.submit_message("123456", "Hello") self.assertTrue(r) delete_smsgateway(identifier)
def test_08_smsgateway_success(self): identifier = "mySMS" provider_module = "privacyidea.lib.smsprovider.SmppSMSProvider" \ ".SmppSMSProvider" id = set_smsgateway(identifier, provider_module, description="test", options=self.config) self.assertTrue(id > 0) sms = create_sms_instance(identifier) try: r = sms.submit_message("123456", "Hello") self.assertTrue(r) except: r = False self.assertFalse(r)
def test_08_smsgateway_success(self): r = add_smtpserver("myServer", "1.2.3.4", sender="*****@*****.**") self.assertTrue(r > 0) smtpmock.setdata(response={"*****@*****.**": (200, "OK")}) identifier = "myMail" provider_module = "privacyidea.lib.smsprovider.SmtpSMSProvider" \ ".SmtpSMSProvider" id = set_smsgateway(identifier, provider_module, description="test", options={"SMTPIDENTIFIER": "myServer", "MAILTO": "*****@*****.**", "SUBJECT": "{phone}", "BODY": "{otp}"}) self.assertTrue(id > 0) sms = create_sms_instance(identifier) r = sms.submit_message("123456", "Halo") self.assertTrue(r)
def test_08_smsgateway_success(self): r = add_smtpserver("myServer", "1.2.3.4", sender="*****@*****.**") self.assertTrue(r > 0) smtpmock.setdata(response={"*****@*****.**": (200, "OK")}) identifier = "myMail" provider_module = "privacyidea.lib.smsprovider.SmtpSMSProvider" \ ".SmtpSMSProvider" id = set_smsgateway(identifier, provider_module, description="test", options={"SMTPIDENTIFIER": "myServer", "MAILTO": "*****@*****.**", "SUBJECT": "{phone}", "BODY": "{otp}"}) self.assertTrue(id > 0) sms = create_sms_instance(identifier) r = sms.submit_message("123456", "Halo") self.assertTrue(r)
def test_03_sendsms(self): # setup realms self.setUp_user_realms() r = set_smsgateway(identifier="myGW", providermodule="privacyidea.lib.smsprovider." "SmtpSMSProvider.SmtpSMSProvider", options={"SMTPIDENTIFIER": "myserver", "MAILTO": "*****@*****.**"}) self.assertTrue(r > 0) smtpmock.setdata(response={"*****@*****.**": (200, "OK")}, support_tls=False) g = FakeFlaskG() audit_object = FakeAudit() audit_object.audit_data["serial"] = "123456" g.logged_in_user = {"user": "******", "role": "admin", "realm": ""} g.audit_object = audit_object builder = EnvironBuilder(method='POST', data={'serial': "OATH123456"}, headers={}) env = builder.get_environ() # Set the remote address so that we can filter for it env["REMOTE_ADDR"] = "10.0.0.1" g.client_ip = env["REMOTE_ADDR"] req = Request(env) req.all_data = {"serial": "SomeSerial", "user": "******"} options = {"g": g, "request": req, "smsconfig": "myGW"} un_handler = UserNotificationEventHandler() res = un_handler.do("sendsms", options=options) self.assertTrue(res)
def test_01_fail_no_script(self): # The script does not exist identifier = "myScriptSMS" config = { "background": SCRIPT_WAIT, "script": "sms-script-does-not-exist.sh" } provider_module = "privacyidea.lib.smsprovider.ScriptSMSProvider" \ ".ScriptSMSProvider" id = set_smsgateway(identifier, provider_module, description="test", options=config) self.assertTrue(id > 0) sms = ScriptSMSProvider(smsgateway=get_smsgateway(identifier)[0], directory=self.directory) self.assertRaises(SMSError, sms.submit_message, "123456", "Hello") delete_smsgateway(identifier) # We bail out, fi no smsgateway definition is given! sms = ScriptSMSProvider(directory=self.directory) self.assertRaises(SMSError, sms.submit_message, "123456", "Hello")
def test_10_new_smsgateway(self): identifier = "myGW" provider_module = "privacyidea.lib.smsprovider.HttpSMSProvider" \ ".HttpSMSProvider" id = set_smsgateway(identifier, provider_module, description="test", options={"HTTP_METHOD": "POST", "URL": "http://example.com", "RETURN_SUCCESS": "ID", "text": "{otp}", "phone": "{phone}"}) self.assertTrue(id > 0) sms = create_sms_instance(identifier) responses.add(responses.POST, "http://example.com", body=self.success_body) # Here we need to send the SMS r = sms.submit_message("123456", "Hello") self.assertTrue(r) delete_smsgateway(identifier)
def test_10_new_smsgateway(self): identifier = "myGW" provider_module = "privacyidea.lib.smsprovider.HttpSMSProvider" \ ".HttpSMSProvider" id = set_smsgateway(identifier, provider_module, description="test", options={"HTTP_METHOD": "POST", "URL": "http://example.com", "RETURN_SUCCESS": "ID", "text": "{otp}", "phone": "{phone}"}) self.assertTrue(id > 0) sms = create_sms_instance(identifier) responses.add(responses.POST, "http://example.com", body=self.success_body) # Here we need to send the SMS r = sms.submit_message("123456", "Hello") self.assertTrue(r) delete_smsgateway(identifier)
def set_gateway(): """ This creates a new SMS gateway definition or updates an existing one. :jsonparam name: The unique identifier of the SMS gateway definition :jsonparam module: The providermodule name :jsonparam description: An optional description of the definition :jsonparam options.*: Additional options for the provider module (module specific) """ param = request.all_data identifier = getParam(param, "name", optional=False) providermodule = getParam(param, "module", optional=False) description = getParam(param, "description", optional=True) options = {} for k, v in param.iteritems(): if k.startswith("option."): options[k[7:]] = v res = set_smsgateway(identifier, providermodule, description, options=options) g.audit_object.log({"success": True, "info": res}) return send_result(res)
def test_02_create_modify_delete_smsgateway_configuration(self): identifier = "myGW" provider_module = "privacyidea.lib.smsprovider.HttpSMSProvider.HttpSMSProvider" id = set_smsgateway(identifier, provider_module, description="test", options={ "HTTP_METHOD": "POST", "URL": "example.com" }, headers={ "Authorization": "QWERTZ", "BANANA": "will be eaten" }) self.assertTrue(id > 0) gw = get_smsgateway(id=id) self.assertEqual(gw[0].description, "test") # update the description set_smsgateway(identifier, provider_module, description="This is a sensible description") gw = get_smsgateway(id=id) self.assertEqual(gw[0].description, "This is a sensible description") # update some options set_smsgateway(identifier, provider_module, options={ "HTTP_METHOD": "POST", "URL": "example.com", "IDENTICAL_KEY": "new option" }, headers={ "Authorization": "ValueChanged", "IDENTICAL_KEY": "new header", "URL": "URL_in_headers" }) gw = get_smsgateway(id=id) self.assertEqual(len(gw[0].option_dict), 3) self.assertEqual(gw[0].option_dict.get("HTTP_METHOD"), "POST") self.assertEqual(gw[0].option_dict.get("URL"), "example.com") self.assertEqual(gw[0].option_dict.get("IDENTICAL_KEY"), "new option") self.assertEqual(gw[0].header_dict.get("Authorization"), "ValueChanged") self.assertEqual(gw[0].header_dict.get("BANANA"), None) self.assertEqual(gw[0].header_dict.get("IDENTICAL_KEY"), "new header") self.assertEqual(gw[0].header_dict.get("URL"), "URL_in_headers") # delete a single option r = delete_smsgateway_option(id, "URL") gw = get_smsgateway(id=id) self.assertEqual(len(gw[0].option_dict), 2) self.assertEqual(gw[0].option_dict.get("HTTP_METHOD"), "POST") self.assertEqual(gw[0].option_dict.get("URL"), None) self.assertEqual(gw[0].option_dict.get("IDENTICAL_KEY"), "new option") # delete a single header r = delete_smsgateway_header(id, "IDENTICAL_KEY") gw = get_smsgateway(id=id) self.assertEqual(gw[0].header_dict.get("IDENTICAL_KEY"), None) # delete a single header via generic function r = delete_smsgateway_key_generic(id, "URL", Type="header") gw = get_smsgateway(id=id) self.assertEqual(gw[0].header_dict.get("URL"), None) # finally delete the gateway definition r = delete_smsgateway(identifier) self.assertEqual(r, id) # delete successful? gw = get_smsgateway() self.assertEqual(len(gw), 0)
def test_01_push_token_reorder_list(self): """ * Policy push_wait * The user has two tokens. SPASS and Push with the same PIN. A /validate/check request is sent with this PIN. The PIN could trigger a challenge response with the Push, but since the token list is reordered and the Spass token already successfully authenticates, the push token is not evaluated anymore. """ # 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},{4!s}={5!s}".format( PUSH_ACTION.FIREBASE_CONFIG, self.firebase_config_name, PUSH_ACTION.REGISTRATION_URL, REGISTRATION_URL, PUSH_ACTION.TTL, TTL)) # 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 spass token for user init_token({ "serial": "spass01", "type": "spass", "pin": "otppin" }, user=User("selfservice", self.realm1)) # 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.assertEqual("spass", toks[1].type) # authenticate with spass 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.assertTrue(data.get("result").get("value")) # successful auth with spass self.assertEqual("spass", data.get("detail").get("type")) remove_token(self.serial_push) remove_token("spass01") delete_policy("push1") delete_policy("push2")
def test_01_create_token(self): db_token = Token(self.serial1, tokentype="push") db_token.save() token = PushTokenClass(db_token) self.assertEqual(token.token.serial, self.serial1) self.assertEqual(token.token.tokentype, "push") self.assertEqual(token.type, "push") class_prefix = token.get_class_prefix() self.assertEqual(class_prefix, "PIPU") self.assertEqual(token.get_class_type(), "push") # Test to do the 2nd step, although the token is not yet in clientwait self.assertRaises(ParameterError, token.update, { "otpkey": "1234", "pubkey": "1234", "serial": self.serial1 }) # Run enrollment step 1 token.update({"genkey": 1}) # Now the token is in the state clientwait, but insufficient parameters would still fail self.assertRaises(ParameterError, token.update, {"otpkey": "1234"}) self.assertRaises(ParameterError, token.update, { "otpkey": "1234", "pubkey": "1234" }) # Unknown config self.assertRaises(ParameterError, token.get_init_detail, params={"firebase_config": "bla"}) fb_config = { FIREBASE_CONFIG.REGISTRATION_URL: "http://test/ttype/push", FIREBASE_CONFIG.JSON_CONFIG: CLIENT_FILE, FIREBASE_CONFIG.TTL: 10, FIREBASE_CONFIG.API_KEY: "1", FIREBASE_CONFIG.APP_ID: "2", FIREBASE_CONFIG.PROJECT_NUMBER: "3", FIREBASE_CONFIG.PROJECT_ID: "4" } # Wrong JSON file self.assertRaises( ConfigAdminError, set_smsgateway, "fb1", u'privacyidea.lib.smsprovider.FirebaseProvider.FirebaseProvider', "myFB", fb_config) # Wrong Project number fb_config[FIREBASE_CONFIG.JSON_CONFIG] = FIREBASE_FILE self.assertRaises( ConfigAdminError, set_smsgateway, "fb1", u'privacyidea.lib.smsprovider.FirebaseProvider.FirebaseProvider', "myFB", fb_config) # Missing APP_ID self.assertRaises( ConfigAdminError, set_smsgateway, "fb1", u'privacyidea.lib.smsprovider.FirebaseProvider.FirebaseProvider', "myFB", { FIREBASE_CONFIG.REGISTRATION_URL: "http://test/ttype/push", FIREBASE_CONFIG.JSON_CONFIG: CLIENT_FILE, FIREBASE_CONFIG.TTL: 10, FIREBASE_CONFIG.API_KEY: "1", FIREBASE_CONFIG.PROJECT_NUMBER: "3", FIREBASE_CONFIG.PROJECT_ID: "4" }) # Missing API_KEY_IOS self.assertRaises( ConfigAdminError, set_smsgateway, "fb1", u'privacyidea.lib.smsprovider.FirebaseProvider.FirebaseProvider', "myFB", { FIREBASE_CONFIG.REGISTRATION_URL: "http://test/ttype/push", FIREBASE_CONFIG.JSON_CONFIG: CLIENT_FILE, FIREBASE_CONFIG.TTL: 10, FIREBASE_CONFIG.APP_ID_IOS: "1", FIREBASE_CONFIG.PROJECT_NUMBER: "3", FIREBASE_CONFIG.PROJECT_ID: "4" }) # Everything is fine fb_config[FIREBASE_CONFIG.PROJECT_ID] = "test-123456" r = set_smsgateway( "fb1", u'privacyidea.lib.smsprovider.FirebaseProvider.FirebaseProvider', "myFB", fb_config) self.assertTrue(r > 0) detail = token.get_init_detail( params={"firebase_config": self.firebase_config_name}) self.assertEqual(detail.get("serial"), self.serial1) self.assertEqual(detail.get("rollout_state"), "clientwait") enrollment_credential = detail.get("enrollment_credential") self.assertTrue("pushurl" in detail) self.assertFalse("otpkey" in detail) # Run enrollment step 2 token.update({ "enrollment_credential": enrollment_credential, "serial": self.serial1, "fbtoken": "firebasetoken", "pubkey": self.smartphone_public_key_pem_urlsafe }) self.assertEqual(token.get_tokeninfo("firebase_token"), "firebasetoken") self.assertEqual(token.get_tokeninfo("public_key_smartphone"), self.smartphone_public_key_pem_urlsafe) self.assertTrue( token.get_tokeninfo("public_key_server").startswith( u"-----BEGIN RSA PUBLIC KEY-----\n"), token.get_tokeninfo("public_key_server")) parsed_server_pubkey = serialization.load_pem_public_key( to_bytes(token.get_tokeninfo("public_key_server")), default_backend()) self.assertIsInstance(parsed_server_pubkey, RSAPublicKey) self.assertTrue( token.get_tokeninfo("private_key_server").startswith( u"-----BEGIN RSA PRIVATE KEY-----\n"), token.get_tokeninfo("private_key_server")) parsed_server_privkey = serialization.load_pem_private_key( to_bytes(token.get_tokeninfo("private_key_server")), None, default_backend()) self.assertIsInstance(parsed_server_privkey, RSAPrivateKey) detail = token.get_init_detail() self.assertEqual(detail.get("rollout_state"), "enrolled") augmented_pubkey = "-----BEGIN RSA PUBLIC KEY-----\n{}\n-----END RSA PUBLIC KEY-----\n".format( detail.get("public_key")) parsed_stripped_server_pubkey = serialization.load_pem_public_key( to_bytes(augmented_pubkey), default_backend()) self.assertEqual(parsed_server_pubkey.public_numbers(), parsed_stripped_server_pubkey.public_numbers()) remove_token(self.serial1)
def test_02_api_enroll(self): self.authenticate() # Failed enrollment due to missing policy with self.app.test_request_context('/token/init', method='POST', data={ "type": "push", "genkey": 1 }, headers={'Authorization': self.at}): res = self.app.full_dispatch_request() self.assertNotEqual(res.status_code, 200) error = res.json.get("result").get("error") self.assertEqual( error.get("message"), "Missing enrollment policy for push token: push_firebase_configuration" ) self.assertEqual(error.get("code"), 303) r = set_smsgateway( self.firebase_config_name, u'privacyidea.lib.smsprovider.FirebaseProvider.FirebaseProvider', "myFB", { FIREBASE_CONFIG.REGISTRATION_URL: "http://test/ttype/push", FIREBASE_CONFIG.TTL: 10, FIREBASE_CONFIG.API_KEY: "1", FIREBASE_CONFIG.APP_ID: "2", FIREBASE_CONFIG.PROJECT_NUMBER: "3", FIREBASE_CONFIG.PROJECT_ID: "test-123456", FIREBASE_CONFIG.JSON_CONFIG: FIREBASE_FILE }) self.assertTrue(r > 0) set_policy("push1", scope=SCOPE.ENROLL, action="{0!s}={1!s}".format(PUSH_ACTION.FIREBASE_CONFIG, self.firebase_config_name)) # 1st step with self.app.test_request_context('/token/init', method='POST', data={ "type": "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. Failing with wrong serial number with self.app.test_request_context( '/ttype/push', method='POST', data={ "serial": "wrongserial", "pubkey": self.smartphone_public_key_pem_urlsafe, "fbtoken": "firebaseT" }): res = self.app.full_dispatch_request() self.assertTrue(res.status_code == 404, res) status = res.json.get("result").get("status") self.assertFalse(status) error = res.json.get("result").get("error") self.assertEqual( error.get("message"), "No token with this serial number in the rollout state 'clientwait'." ) # 2nd step. Fails with missing enrollment credential with self.app.test_request_context( '/ttype/push', method='POST', data={ "serial": serial, "pubkey": self.smartphone_public_key_pem_urlsafe, "fbtoken": "firebaseT", "enrollment_credential": "WRonG" }): res = self.app.full_dispatch_request() self.assertTrue(res.status_code == 400, res) status = res.json.get("result").get("status") self.assertFalse(status) error = res.json.get("result").get("error") self.assertEqual( error.get("message"), "ERR905: Invalid enrollment credential. You are not authorized to finalize this token." ) # 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)
def test_02_api_enroll(self): self.authenticate() # Failed enrollment due to missing policy with self.app.test_request_context('/token/init', method='POST', data={"type": "push", "genkey": 1}, headers={'Authorization': self.at}): res = self.app.full_dispatch_request() self.assertNotEqual(res.status_code, 200) error = json.loads(res.data.decode("utf8")).get("result").get("error") self.assertEqual(error.get("message"), "Missing enrollment policy for push token: push_firebase_configuration") self.assertEqual(error.get("code"), 303) r = set_smsgateway(self.firebase_config_name, u'privacyidea.lib.smsprovider.FirebaseProvider.FirebaseProvider', "myFB", {FIREBASE_CONFIG.REGISTRATION_URL: "http://test/ttype/push", FIREBASE_CONFIG.TTL: 10, FIREBASE_CONFIG.API_KEY: "1", FIREBASE_CONFIG.APP_ID: "2", FIREBASE_CONFIG.PROJECT_NUMBER: "3", FIREBASE_CONFIG.PROJECT_ID: "test-123456", FIREBASE_CONFIG.JSON_CONFIG: FIREBASE_FILE}) self.assertTrue(r > 0) set_policy("push1", scope=SCOPE.ENROLL, action="{0!s}={1!s}".format(PUSH_ACTION.FIREBASE_CONFIG, self.firebase_config_name)) # 1st step with self.app.test_request_context('/token/init', method='POST', data={"type": "push", "genkey": 1}, headers={'Authorization': self.at}): res = self.app.full_dispatch_request() self.assertEqual(res.status_code, 200) detail = json.loads(res.data.decode('utf8')).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. Failing with wrong serial number with self.app.test_request_context('/ttype/push', method='POST', data={"serial": "wrongserial", "pubkey": self.smartphone_public_key_pem_urlsafe, "fbtoken": "firebaseT"}): res = self.app.full_dispatch_request() self.assertTrue(res.status_code == 404, res) status = json.loads(res.data.decode('utf8')).get("result").get("status") self.assertFalse(status) error = json.loads(res.data.decode('utf8')).get("result").get("error") self.assertEqual(error.get("message"), "No token with this serial number in the rollout state 'clientwait'.") # 2nd step. Fails with missing enrollment credential with self.app.test_request_context('/ttype/push', method='POST', data={"serial": serial, "pubkey": self.smartphone_public_key_pem_urlsafe, "fbtoken": "firebaseT", "enrollment_credential": "WRonG"}): res = self.app.full_dispatch_request() self.assertTrue(res.status_code == 400, res) status = json.loads(res.data.decode('utf8')).get("result").get("status") self.assertFalse(status) error = json.loads(res.data.decode('utf8')).get("result").get("error") self.assertEqual(error.get("message"), "ERR905: Invalid enrollment credential. You are not authorized to finalize this token.") # 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 = json.loads(res.data.decode('utf8')).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)
def test_01_create_token(self): db_token = Token(self.serial1, tokentype="push") db_token.save() token = PushTokenClass(db_token) self.assertEqual(token.token.serial, self.serial1) self.assertEqual(token.token.tokentype, "push") self.assertEqual(token.type, "push") class_prefix = token.get_class_prefix() self.assertEqual(class_prefix, "PIPU") self.assertEqual(token.get_class_type(), "push") # Test to do the 2nd step, although the token is not yet in clientwait self.assertRaises(ParameterError, token.update, {"otpkey": "1234", "pubkey": "1234", "serial": self.serial1}) # Run enrollment step 1 token.update({"genkey": 1}) # Now the token is in the state clientwait, but insufficient parameters would still fail self.assertRaises(ParameterError, token.update, {"otpkey": "1234"}) self.assertRaises(ParameterError, token.update, {"otpkey": "1234", "pubkey": "1234"}) # Unknown config self.assertRaises(ParameterError, token.get_init_detail, params={"firebase_config": "bla"}) fb_config = {FIREBASE_CONFIG.REGISTRATION_URL: "http://test/ttype/push", FIREBASE_CONFIG.JSON_CONFIG: CLIENT_FILE, FIREBASE_CONFIG.TTL: 10, FIREBASE_CONFIG.API_KEY: "1", FIREBASE_CONFIG.APP_ID: "2", FIREBASE_CONFIG.PROJECT_NUMBER: "3", FIREBASE_CONFIG.PROJECT_ID: "4"} # Wrong JSON file self.assertRaises(ConfigAdminError, set_smsgateway, "fb1", u'privacyidea.lib.smsprovider.FirebaseProvider.FirebaseProvider', "myFB", fb_config) # Wrong Project number fb_config[FIREBASE_CONFIG.JSON_CONFIG] = FIREBASE_FILE self.assertRaises(ConfigAdminError, set_smsgateway, "fb1", u'privacyidea.lib.smsprovider.FirebaseProvider.FirebaseProvider', "myFB", fb_config) # Missing APP_ID self.assertRaises(ConfigAdminError, set_smsgateway, "fb1", u'privacyidea.lib.smsprovider.FirebaseProvider.FirebaseProvider', "myFB", {FIREBASE_CONFIG.REGISTRATION_URL: "http://test/ttype/push", FIREBASE_CONFIG.JSON_CONFIG: CLIENT_FILE, FIREBASE_CONFIG.TTL: 10, FIREBASE_CONFIG.API_KEY: "1", FIREBASE_CONFIG.PROJECT_NUMBER: "3", FIREBASE_CONFIG.PROJECT_ID: "4"}) # Missing API_KEY_IOS self.assertRaises(ConfigAdminError, set_smsgateway, "fb1", u'privacyidea.lib.smsprovider.FirebaseProvider.FirebaseProvider', "myFB", {FIREBASE_CONFIG.REGISTRATION_URL: "http://test/ttype/push", FIREBASE_CONFIG.JSON_CONFIG: CLIENT_FILE, FIREBASE_CONFIG.TTL: 10, FIREBASE_CONFIG.APP_ID_IOS: "1", FIREBASE_CONFIG.PROJECT_NUMBER: "3", FIREBASE_CONFIG.PROJECT_ID: "4"}) # Everything is fine fb_config[FIREBASE_CONFIG.PROJECT_ID] = "test-123456" r = set_smsgateway("fb1", u'privacyidea.lib.smsprovider.FirebaseProvider.FirebaseProvider', "myFB", fb_config) self.assertTrue(r > 0) detail = token.get_init_detail(params={"firebase_config": self.firebase_config_name}) self.assertEqual(detail.get("serial"), self.serial1) self.assertEqual(detail.get("rollout_state"), "clientwait") enrollment_credential = detail.get("enrollment_credential") self.assertTrue("pushurl" in detail) self.assertFalse("otpkey" in detail) # Run enrollment step 2 token.update({"enrollment_credential": enrollment_credential, "serial": self.serial1, "fbtoken": "firebasetoken", "pubkey": self.smartphone_public_key_pem_urlsafe}) self.assertEqual(token.get_tokeninfo("firebase_token"), "firebasetoken") self.assertEqual(token.get_tokeninfo("public_key_smartphone"), self.smartphone_public_key_pem_urlsafe) self.assertTrue(token.get_tokeninfo("public_key_server").startswith(u"-----BEGIN RSA PUBLIC KEY-----\n"), token.get_tokeninfo("public_key_server")) parsed_server_pubkey = serialization.load_pem_public_key( to_bytes(token.get_tokeninfo("public_key_server")), default_backend()) self.assertIsInstance(parsed_server_pubkey, RSAPublicKey) self.assertTrue(token.get_tokeninfo("private_key_server").startswith(u"-----BEGIN RSA PRIVATE KEY-----\n"), token.get_tokeninfo("private_key_server")) parsed_server_privkey = serialization.load_pem_private_key( to_bytes(token.get_tokeninfo("private_key_server")), None, default_backend()) self.assertIsInstance(parsed_server_privkey, RSAPrivateKey) detail = token.get_init_detail() self.assertEqual(detail.get("rollout_state"), "enrolled") augmented_pubkey = "-----BEGIN RSA PUBLIC KEY-----\n{}\n-----END RSA PUBLIC KEY-----\n".format( detail.get("public_key")) parsed_stripped_server_pubkey = serialization.load_pem_public_key( to_bytes(augmented_pubkey), default_backend()) self.assertEqual(parsed_server_pubkey.public_numbers(), parsed_stripped_server_pubkey.public_numbers()) remove_token(self.serial1)
def test_02_api_push_poll(self): r = set_smsgateway( self.firebase_config_name, u'privacyidea.lib.smsprovider.FirebaseProvider.FirebaseProvider', "myFB", FB_CONFIG_VALS) self.assertGreater(r, 0) # create a new push token tokenobj = self._create_push_token() serial = tokenobj.get_serial() # set PIN tokenobj.set_pin("pushpin") tokenobj.add_user(User("cornelius", self.realm1)) # We mock the ServiceAccountCredentials, since we can not directly contact the Google API with mock.patch( 'privacyidea.lib.smsprovider.FirebaseProvider.service_account.Credentials' '.from_service_account_file') as mySA: # alternative: side_effect instead of return_value mySA.return_value = _create_credential_mock() # add responses, to simulate the communication to firebase responses.add( responses.POST, 'https://fcm.googleapis.com/v1/projects/test-123456/messages:send', body="""{}""", content_type="application/json") # Send the first authentication request to trigger the challenge. # No push notification is submitted to firebase, but a challenge is created anyway with self.app.test_request_context('/validate/check', method='POST', data={ "user": "******", "realm": self.realm1, "pass": "******" }): res = self.app.full_dispatch_request() self.assertTrue(res.status_code == 400, res) jsonresp = res.json self.assertFalse(jsonresp.get("result").get("status")) self.assertEqual( jsonresp.get("result").get("error").get("code"), 401) self.assertEqual( jsonresp.get("result").get("error").get("message"), "ERR401: Failed to submit message to Firebase service.") # first create a signature ts = datetime.utcnow().isoformat() sign_string = u"{serial}|{timestamp}".format(serial=serial, timestamp=ts) sig = self.smartphone_private_key.sign(sign_string.encode('utf8'), padding.PKCS1v15(), hashes.SHA256()) # now check that we receive the challenge when polling with self.app.test_request_context('/ttype/push', method='GET', data={ "serial": serial, "timestamp": ts, "signature": b32encode(sig) }): res = self.app.full_dispatch_request() # check that the serial was set in flask g (via before_request in ttype.py) self.assertTrue(self.app_context.g.serial, serial) self.assertTrue(res.status_code == 200, res) self.assertTrue(res.json['result']['status']) chall = res.json['result']['value'][0] self.assertTrue(chall) challenge = chall["nonce"] # This is what the smartphone answers. # create the signature: sign_data = "{0!s}|{1!s}".format(challenge, serial) signature = b32encode_and_unicode( self.smartphone_private_key.sign(sign_data.encode("utf-8"), padding.PKCS1v15(), hashes.SHA256())) # Answer the challenge with self.app.test_request_context('/ttype/push', method='POST', data={ "serial": serial, "nonce": challenge, "signature": signature }): res = self.app.full_dispatch_request() self.assertTrue(res.status_code == 200, res) self.assertTrue(res.json['result']['status']) self.assertTrue(res.json['result']['value'])
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")