def testGetAllHistories(): seed = b'\x92[\xcb\xf4\xee5+\xcf\xd4b*%/\xabw8\xd4d\xa2\xf8\xad\xa7U\x19,\xcfS\x12\xa6l\xba"' dbing.setupDbEnv(DB_DIR_PATH) data = { "id": DID, "signer": 0, "signers": [ "NOf6ZghvGNbFc_wr3CC0tKZHz1qWAR4lD5aM-i0zSjw=", "NOf6ZghvGNbFc_wr3CC0tKZHz1qWAR4lD5aM-i0zSjw=" ] } sigs = [help.signResource(json.dumps(data).encode(), SK)] history1 = dbing.saveHistory(DID, data, sigs) vk, sk, did, body = help.genDidHistory(seed, signer=0, numSigners=2) data = json.loads(body) sigs = [help.signResource(json.dumps(data).encode(), sk)] history2 = dbing.saveHistory(did, data, sigs) exp_data = {'data': [history1, history2]} actual_data = dbing.getAllHistories() assert actual_data == exp_data
def testPutPreRotationIsEmpty(client): seed = libnacl.randombytes(libnacl.crypto_sign_SEEDBYTES) vk, sk, did, body = h.genDidHistory(seed, signer=0, numSigners=2) headers = {"Signature": 'signer="{0}"'.format(h.signResource(body, sk))} client.simulate_post(HISTORY_BASE_PATH, body=body, headers=headers) # Add did to database body = json.loads(body) body['changed'] = "2000-01-01T00:00:02+00:00" body['signer'] = 1 body['signers'].append("") headers = { "Signature": 'signer="{0}"; rotation="{1}"'.format( h.signResource(json.dumps(body, ensure_ascii=False).encode(), sk), h.signResource(json.dumps(body, ensure_ascii=False).encode(), sk)) } exp_result = { "title": "Validation Error", "description": "signers keys cannot be empty." } verifyRequest(client.simulate_put, "{0}/{1}".format(HISTORY_BASE_PATH, did), body, headers, exp_result=exp_result, exp_status=falcon.HTTP_400)
def testGetAllOtpBlobs(): seed = b'\x92[\xcb\xf4\xee5+\xcf\xd4b*%/\xabw8\xd4d\xa2\xf8\xad\xa7U\x19,\xcfS\x12\xa6l\xba"' dbing.setupDbEnv(DB_DIR_PATH) data = { "id": DID, "blob": "aj;skldfjaoisfjweoijfoiajfo;iasjvjncowrnoiarejnfoj;csacivnfgo;afiewvajdfvo;hnafddjio;ahjfgoia;ehroi;hs" } sigs = [help.signResource(json.dumps(data).encode(), SK)] otpBlob1 = dbing.saveOtpBlob(DID, data, sigs) vk, sk, did, body = help.genDidHistory(seed, signer=0, numSigners=2) data = { "id": did, "blob": "aj;skldfjaoisfjweoijfoiajfo;iasjvjncowrnoiarejnfoj;csacivnfgo;afiewvajdfvo;hnafddjio;ahjfgoia;ehroi;hs" } sigs = [help.signResource(json.dumps(data).encode(), sk)] otpBlob2 = dbing.saveOtpBlob(did, data, sigs) exp_data = {'data': [otpBlob1, otpBlob2]} actual_data = dbing.getAllOtpBlobs() assert actual_data == exp_data
def testValidPut(client): seed = b'\x92[\xcb\xf4\xee5+\xcf\xd4b*%/\xabw8\xd4d\xa2\xf8\xad\xa7U\x19,\xcfS\x12\xa6l\xba"' # Test Valid rotation event vk, sk, did, body = h.genDidHistory(seed, signer=0, numSigners=2) headers = { "Signature": 'signer="{0}"; rotation="{1}"'.format(h.signResource(body, sk), h.signResource(body, sk)) } client.simulate_post(HISTORY_BASE_PATH, body=body, headers=headers) # Add did to database body = json.loads(body) body['changed'] = "2000-01-01T00:00:01+00:00" body['signer'] = 1 body['signers'].append(body['signers'][0]) headers = { "Signature": 'signer="{0}"; rotation="{1}"'.format( h.signResource( json.dumps(body, ensure_ascii=False).encode('utf-8'), sk), h.signResource( json.dumps(body, ensure_ascii=False).encode('utf-8'), sk)) } exp_result = { "history": { "id": "did:dad:iy67FstqFl_a5e-sni6yAWoj60-1E2RtzmMGjrjHaSY=", "changed": "2000-01-01T00:00:01+00:00", "signer": 1, "signers": [ "iy67FstqFl_a5e-sni6yAWoj60-1E2RtzmMGjrjHaSY=", "iy67FstqFl_a5e-sni6yAWoj60-1E2RtzmMGjrjHaSY=", "iy67FstqFl_a5e-sni6yAWoj60-1E2RtzmMGjrjHaSY=" ] }, "signatures": { "signer": "bu-HIoIp2ZtBqsZtURP_q6rm8WPuDQGtN6maXbDHZbVHJ-QfGpwvXkE-fmi7XymvQJnS9tZXFQ5MPos5u09HDw==", "rotation": "bu-HIoIp2ZtBqsZtURP_q6rm8WPuDQGtN6maXbDHZbVHJ-QfGpwvXkE-fmi7XymvQJnS9tZXFQ5MPos5u09HDw==" } } verifyRequest(client.simulate_put, "{0}/{1}".format(HISTORY_BASE_PATH, did), body, headers, exp_result=exp_result, exp_status=falcon.HTTP_200)
def signatureValidation(reqFunc, url): headers = {"Signature": ""} # Test missing Signature Header body = deepcopy(data) exp_result = { "title": "Authorization Error", "description": "Empty Signature header." } verifyRequest(reqFunc, url, body, headers, exp_result, falcon.HTTP_401) body = json.dumps(data, ensure_ascii=False).encode('utf-8') exp_result = { "title": "Missing header value", "description": "The Signature header is required." } response = reqFunc(url, body=body) assert response.status == falcon.HTTP_400 assert json.loads(response.content) == exp_result # Test missing signer tag in signature header body = deepcopy(data) headers = { "Signature": 'test="' + h.signResource( json.dumps(body, ensure_ascii=False).encode('utf-8'), SK) + '"' } exp_result = { "title": "Authorization Error", "description": "Signature header missing \"signer\" tag and signature." } verifyRequest(reqFunc, url, body, headers, exp_result, falcon.HTTP_401) # Test invalid signature body = deepcopy(data) exp_result = { "title": "Authorization Error", "description": "Could not validate the request body and signature. Unverifiable signature." } headers = { "Signature": 'signer="{0}"'.format( h.signResource( json.dumps(body, ensure_ascii=False).encode('utf-8'), BAD_SK)) } verifyRequest(reqFunc, url, body, headers, exp_result, falcon.HTTP_401)
def testGetAll(client): # setup vk1, sk1, did1, body1 = genOtpBlob() signature1 = h.signResource(body1, sk1) headers = {"Signature": 'signer="{}"'.format(signature1)} client.simulate_post(BLOB_BASE_PATH, body=body1, headers=headers) # Add did to database vk2, sk2, did2, body2 = genOtpBlob() signature2 = h.signResource(body2, sk2) headers = {"Signature": 'signer="{}"'.format(signature2)} client.simulate_post(BLOB_BASE_PATH, body=body2, headers=headers) # Add did to database # Test get all response = client.simulate_get(BLOB_BASE_PATH) resp_data = json.loads(response.content) body1 = json.loads(body1) body2 = json.loads(body2) assert response.status == falcon.HTTP_200 assert "data" in resp_data assert len(resp_data["data"]) == 2 resp_blob1 = resp_data["data"][0] resp_blob2 = resp_data["data"][1] assert resp_blob1["otp_data"]["id"] == body1["id"] or resp_blob2[ "otp_data"]["id"] == body1["id"] assert resp_blob1["otp_data"]["id"] == body2["id"] or resp_blob2[ "otp_data"]["id"] == body2["id"] assert resp_blob1["otp_data"]["id"] == body2["id"] or resp_blob2[ "otp_data"]["id"] == body2["id"] assert resp_blob1["signatures"]["signer"] == signature1 or resp_blob2[ "signatures"]["signer"] == signature1 assert resp_blob1["signatures"]["signer"] == signature2 or resp_blob2[ "signatures"]["signer"] == signature2 # Test offset and limit response = client.simulate_get(BLOB_BASE_PATH, query_string="offset=100&limit=10") exp_result = {} assert response.status == falcon.HTTP_200 assert json.loads(response.content) == exp_result
def testPutValidation(client): seed = b'\x03\xa7w\xa6\x8c\xf3-&\xbf)\xdf\tk\xb5l\xc0-ry\x9bq\xecC\xbd\x1e\xe7\xdd\xe8\xad\x80\x95\x89' # Test that did resource already exists vk, sk, did, body = genOtpBlob(seed) exp_result = {"title": "404 Not Found"} headers = {"Signature": 'signer="{}"'.format(h.signResource(body, sk))} verifyRequest(client.simulate_put, "{0}/{1}".format(BLOB_BASE_PATH, did), json.loads(body), headers, exp_result=exp_result, exp_status=falcon.HTTP_404) # Test url missing did body = deepcopy(data) exp_result = { "title": "Validation Error", "description": "DID value missing from url." } verifyRequest(client.simulate_put, BLOB_BASE_PATH, body, exp_result=exp_result, exp_status=falcon.HTTP_400) # Run basic tests basicValidation(client.simulate_put, PUT_URL) # Test that changed field is greater than previous date vk, sk, did, body = genOtpBlob(seed) headers = {"Signature": 'signer="{}"'.format(h.signResource(body, sk))} client.simulate_post(BLOB_BASE_PATH, body=body, headers=headers) # Add did to database exp_result = { "title": "Validation Error", "description": "\"changed\" field not later than previous update." } verifyRequest(client.simulate_put, "{0}/{1}".format(BLOB_BASE_PATH, did), json.loads(body), headers, exp_result=exp_result, exp_status=falcon.HTTP_400)
def testGetOne(client): url = "{0}/{1}".format(HISTORY_BASE_PATH, DID) # Test that 404 is returned when db is empty response = client.simulate_get(url) assert response.status == falcon.HTTP_404 # Test basic valid Get One body = deepcopy(putData) body['signer'] = 0 body['signers'] = [ "NOf6ZghvGNbFc_wr3CC0tKZHz1qWAR4lD5aM-i0zSjw=", "NOf6ZghvGNbFc_wr3CC0tKZHz1qWAR4lD5aM-i0zSjw=" ] headers = { "Signature": 'signer="{0}"'.format( h.signResource(json.dumps(body, ensure_ascii=False).encode(), SK)) } verifyRequest(client.simulate_post, HISTORY_BASE_PATH, body, headers=headers, exp_status=falcon.HTTP_201) response = client.simulate_get(url) exp_result = { "history": { "id": "did:dad:NOf6ZghvGNbFc_wr3CC0tKZHz1qWAR4lD5aM-i0zSjw=", "changed": "2000-01-01T00:00:00+00:00", "signer": 0, "signers": [ "NOf6ZghvGNbFc_wr3CC0tKZHz1qWAR4lD5aM-i0zSjw=", "NOf6ZghvGNbFc_wr3CC0tKZHz1qWAR4lD5aM-i0zSjw=" ] }, "signatures": { "signer": "xYbxaQtHsrispyZnd_3qf9xqBCXwgBq9pDnFP_5M2v-d-tNarUJeIY1wMeUcDTm808jG0kTwiXu9WApdao8FAA==" } } assert response.status == falcon.HTTP_200 assert json.loads(response.content) == exp_result # Test GET with non existent resource response = client.simulate_get("{0}/{1}".format( HISTORY_BASE_PATH, "did:dad:COf6ZghvGNbFc_wr3CC0tKZHz1qWAR4lD5aM-i0zSjw=")) exp_result = {"title": "404 Not Found"} assert response.status == falcon.HTTP_404 assert json.loads(response.content) == exp_result
def testValidDelete(client): seed = b'\x92[\xcb\xf4\xee5+\xcf\xd4b*%/\xabw8\xd4d\xa2\xf8\xad\xa7U\x19,\xcfS\x12\xa6l\xba"' vk, sk, did, body = h.genDidHistory(seed, signer=0, numSigners=2) url = "{0}/{1}".format(HISTORY_BASE_PATH, did) signature = h.signResource(body, sk) headers = {"Signature": 'signer="{0}"'.format(signature)} client.simulate_post(HISTORY_BASE_PATH, body=body, headers=headers) # Add did to database data = json.dumps({"id": did}, ensure_ascii=False).encode() headers = {"Signature": 'signer="{0}"'.format(h.signResource(data, sk))} response = client.simulate_delete(url, body=data, headers=headers) resp_content = json.loads(response.content) assert response.status == falcon.HTTP_200 assert resp_content["deleted"]["history"] == json.loads(body) assert resp_content["deleted"]["signatures"]["signer"] == signature
def testDeleteHistory(): seed = b'\x92[\xcb\xf4\xee5+\xcf\xd4b*%/\xabw8\xd4d\xa2\xf8\xad\xa7U\x19,\xcfS\x12\xa6l\xba"' vk, sk, did, body = help.genDidHistory(seed, signer=0, numSigners=2) data = json.loads(body) sigs = [help.signResource(json.dumps(data).encode(), sk)] dbing.saveHistory(did, data, sigs) status = dbing.deleteHistory(did) assert status is True assert dbing.getHistory(did) is None
def testDeleteOtpBlob(): data = { "id": DID, "blob": "aj;skldfjaoisfjweoijfoiajfo;iasjvjncowrnoiarejnfoj;csacivnfgo;afiewvajdfvo;hnafddjio;ahjfgoia;ehroi;hs" } sigs = [help.signResource(json.dumps(data).encode(), SK)] dbing.saveOtpBlob(DID, data, sigs) status = dbing.deleteOtpBlob(DID) assert status is True assert dbing.getHistory(DID) is None
def testGetOtpBlob(): dbing.setupDbEnv(DB_DIR_PATH) data = { "id": DID, "blob": "aj;skldfjaoisfjweoijfoiajfo;iasjvjncowrnoiarejnfoj;csacivnfgo;afiewvajdfvo;hnafddjio;ahjfgoia;ehroi;hs" } sigs = [help.signResource(json.dumps(data).encode(), SK)] exp_data = dbing.saveOtpBlob(DID, data, sigs) actual_data = dbing.getOtpBlob(DID) assert actual_data == exp_data
def testGetOne(client): # Test Get One with empty DB response = client.simulate_get("{0}/{1}".format(BLOB_BASE_PATH, DID)) assert response.status == falcon.HTTP_404 # Test basic valid Get One body = deepcopy(data) signature = h.signResource(json.dumps(body).encode(), SK) headers = {"Signature": 'signer="{}"'.format(signature)} client.simulate_post(BLOB_BASE_PATH, body=json.dumps(body).encode(), headers=headers) response = client.simulate_get("{0}/{1}".format(BLOB_BASE_PATH, DID)) exp_result = { "otp_data": { "id": "did:dad:NOf6ZghvGNbFc_wr3CC0tKZHz1qWAR4lD5aM-i0zSjw=", "blob": "AeYbsHot0pmdWAcgTo5sD8iAuSQAfnH5U6wiIGpVNJQQoYKBYrPPxAoIc1i5SHCIDS8KFFgf8i0tDq8XGizaCgo9y" "juKHHNJZFi0QD9K6Vpt6fP0XgXlj8z_4D-7s3CcYmuoWAh6NVtYaf_GWw_2sCrHBAA2mAEsml3thLmu50Dw", "changed": "2000-01-01T00:00:00+00:00" }, "signatures": { "signer": signature } } assert response.status == falcon.HTTP_200 assert json.loads(response.content) == exp_result # Test GET with non existent resource response = client.simulate_get("{0}/{1}".format( BLOB_BASE_PATH, "did:dad:COf6ZghvGNbFc_wr3CC0tKZHz1qWAR4lD5aM-i0zSjw=")) exp_result = {"title": "404 Not Found"} assert response.status == falcon.HTTP_404 assert json.loads(response.content) == exp_result
def testSaveOtpBlob(): dbing.setupDbEnv(DB_DIR_PATH) data = { "id": DID, "blob": "aj;skldfjaoisfjweoijfoiajfo;iasjvjncowrnoiarejnfoj;csacivnfgo;afiewvajdfvo;hnafddjio;ahjfgoia;ehroi;hs" } sigs = [help.signResource(json.dumps(data).encode(), SK)] exp_data = dbing.saveOtpBlob(DID, data, sigs) dbOtpBlob = dbing.dideryDB.open_db(dbing.DB_OTP_BLOB_NAME) with dbing.dideryDB.begin(db=dbOtpBlob, write=True) as txn: actual_data = txn.get(DID.encode()) assert actual_data == json.dumps(exp_data).encode()
def testGetHistory(): dbing.setupDbEnv(DB_DIR_PATH) data = { "id": DID, "signer": 0, "signers": [ "NOf6ZghvGNbFc_wr3CC0tKZHz1qWAR4lD5aM-i0zSjw=", "NOf6ZghvGNbFc_wr3CC0tKZHz1qWAR4lD5aM-i0zSjw=" ] } sigs = [help.signResource(json.dumps(data).encode(), SK)] exp_data = dbing.saveHistory(DID, data, sigs) actual_data = dbing.getHistory(DID) assert actual_data == exp_data
def testPostPreRotationIsEmpty(client): seed = libnacl.randombytes(libnacl.crypto_sign_SEEDBYTES) vk, sk, did, body = h.genDidHistory(seed, signer=0, numSigners=2) body = json.loads(body) body['signers'][1] = "" body = json.dumps(body, ensure_ascii=False, separators=(",", ":")).encode() headers = {"Signature": 'signer="{0}"'.format(h.signResource(body, sk))} response = client.simulate_post(HISTORY_BASE_PATH, body=body, headers=headers) # Add did to database exp_result = { "title": "Validation Error", "description": "signers keys cannot be empty." } assert response.status == falcon.HTTP_400 assert json.loads(response.content) == exp_result
def testSaveHistory(): dbing.setupDbEnv(DB_DIR_PATH) data = { "id": DID, "signer": 0, "signers": [ "NOf6ZghvGNbFc_wr3CC0tKZHz1qWAR4lD5aM-i0zSjw=", "NOf6ZghvGNbFc_wr3CC0tKZHz1qWAR4lD5aM-i0zSjw=" ] } sigs = [help.signResource(json.dumps(data).encode(), SK)] exp_data = dbing.saveHistory(DID, data, sigs) dbHistory = dbing.dideryDB.open_db(dbing.DB_KEY_HISTORY_NAME) with dbing.dideryDB.begin(db=dbHistory, write=True) as txn: actual_data = txn.get(DID.encode()) assert actual_data == json.dumps(exp_data).encode()
def testPutValidation(client): url = "{0}/{1}".format(HISTORY_BASE_PATH, DID) seed = b'\x03\xa7w\xa6\x8c\xf3-&\xbf)\xdf\tk\xb5l\xc0-ry\x9bq\xecC\xbd\x1e\xe7\xdd\xe8\xad\x80\x95\x89' # Test that did resource already exists vk, sk, did, body = h.genDidHistory(seed, signer=1) exp_result = {"title": "404 Not Found"} headers = { "Signature": 'signer="{0}"; rotation="{1}"'.format(h.signResource(body, sk), h.signResource(body, sk)) } verifyRequest(client.simulate_put, "{0}/{1}".format(HISTORY_BASE_PATH, did), json.loads(body), headers, exp_result=exp_result, exp_status=falcon.HTTP_404) # Run basic validation tests basicValidation(client.simulate_put, url, putData) # Test that signers field has three keys body = deepcopy(putData) del body['signers'][3] del body['signers'][2] exp_result = { "title": "Validation Error", "description": "PUT endpoint is for rotation events. Must contain at least the original key, a current signing" " key, and a pre-rotated key." } verifyRequest(client.simulate_put, url, body, exp_result=exp_result, exp_status=falcon.HTTP_400) # Test that signers field has three keys body = deepcopy(putData) body['signers'] = [] exp_result = { "title": "Validation Error", "description": "PUT endpoint is for rotation events. Must contain at least the original key, a current signing" " key, and a pre-rotated key." } verifyRequest(client.simulate_put, url, body, exp_result=exp_result, exp_status=falcon.HTTP_400) # Test that signers field has three keys body = deepcopy(putData) body['signer'] = 0 body['signers'] = [ "NOf6ZghvGNbFc_wr3CC0tKZHz1qWAR4lD5aM-i0zSjw=", "NOf6ZghvGNbFc_wr3CC0tKZHz1qWAR4lD5aM-i0zSjw=" ] verifyRequest(client.simulate_post, HISTORY_BASE_PATH, body, exp_status=falcon.HTTP_201) body = deepcopy(putData) body['changed'] = "2000-01-01T00:00:01+00:00" body['signers'] = [ "NOf6ZghvGNbFc_wr3CC0tKZHz1qWAR4lD5aM-i0zSjw=", "NOf6ZghvGNbFc_wr3CC0tKZHz1qWAR4lD5aM-i0zSjw=", "NOf6ZghvGNbFc_wr3CC0tKZHz1qWAR4lD5aM-i0zSjw=" ] verifyRequest(client.simulate_put, url, body, exp_status=falcon.HTTP_200) # Test that signer field is a valid index into signers field body = deepcopy(putData) body['signer'] = 4 exp_result = { "title": "Validation Error", "description": "\"signer\" cannot reference the first or last key in the \"signers\" field on PUT requests." } verifyRequest(client.simulate_put, url, body, exp_result=exp_result, exp_status=falcon.HTTP_400) # Test that signer is not 0 body = deepcopy(putData) body['signer'] = 0 exp_result = { "title": "Validation Error", "description": "\"signer\" cannot reference the first or last key in the \"signers\" field on PUT requests." } verifyRequest(client.simulate_put, url, body, exp_result=exp_result, exp_status=falcon.HTTP_400) # Test that signers field has a pre-rotated key body = deepcopy(putData) body['signer'] = 3 exp_result = { "title": "Validation Error", "description": "Missing pre rotated key in the signers field." } verifyRequest(client.simulate_put, url, body, exp_result=exp_result, exp_status=falcon.HTTP_400) # Test that the url has a did in it body = deepcopy(putData) exp_result = { "title": "Validation Error", "description": "DID value missing from url." } verifyRequest(client.simulate_put, HISTORY_BASE_PATH, body, exp_result=exp_result, exp_status=falcon.HTTP_400) # Test that changed field is greater than previous date vk, sk, did, body = h.genDidHistory(seed, signer=0, numSigners=4) headers = { "Signature": 'signer="{0}"; rotation="{1}"'.format(h.signResource(body, sk), h.signResource(body, sk)) } client.simulate_post(HISTORY_BASE_PATH, body=body, headers=headers) # Add did to database body = json.loads(body) body['signer'] = 1 headers = { "Signature": 'signer="{0}"; rotation="{1}"'.format( h.signResource( json.dumps(body, ensure_ascii=False).encode('utf-8'), sk), h.signResource( json.dumps(body, ensure_ascii=False).encode('utf-8'), sk)) } exp_result = { "title": "Validation Error", "description": "\"changed\" field not later than previous update." } verifyRequest(client.simulate_put, "{0}/{1}".format(HISTORY_BASE_PATH, did), body, headers, exp_result=exp_result, exp_status=falcon.HTTP_400) # Test that signers field length hasn't changed body['changed'] = "2000-01-01T00:00:01+00:00" headers = { "Signature": 'signer="{0}"; rotation="{1}"'.format( h.signResource( json.dumps(body, ensure_ascii=False).encode('utf-8'), sk), h.signResource( json.dumps(body, ensure_ascii=False).encode('utf-8'), sk)) } exp_result = { "title": "Validation Error", "description": "signers field is missing keys." } verifyRequest(client.simulate_put, "{0}/{1}".format(HISTORY_BASE_PATH, did), body, headers, exp_result=exp_result, exp_status=falcon.HTTP_400) del body['signers'][3] headers = { "Signature": 'signer="{0}"; rotation="{1}"'.format( h.signResource( json.dumps(body, ensure_ascii=False).encode('utf-8'), sk), h.signResource( json.dumps(body, ensure_ascii=False).encode('utf-8'), sk)) } exp_result = { "title": "Validation Error", "description": "signers field is missing keys." } verifyRequest(client.simulate_put, "{0}/{1}".format(HISTORY_BASE_PATH, did), body, headers, exp_result=exp_result, exp_status=falcon.HTTP_400) # Test that previously verified keys have not been changed body['signers'].append("Xq5YqaL6L48pf0fu7IUhL0JRaU2_RxFP0AL43wYn148=") body['signers'].append("Xq5YqaL6L48pf0fu7IUhL0JRaU2_RxFP0AL43wYn148=") headers = { "Signature": 'signer="{0}"; rotation="{1}"'.format( h.signResource( json.dumps(body, ensure_ascii=False).encode('utf-8'), sk), h.signResource( json.dumps(body, ensure_ascii=False).encode('utf-8'), sk)) } exp_result = { "title": "Validation Error", "description": "signers field missing previously verified keys." } verifyRequest(client.simulate_put, "{0}/{1}".format(HISTORY_BASE_PATH, did), body, headers, exp_result=exp_result, exp_status=falcon.HTTP_400) # test that signer field is updated from previous requests seed = libnacl.randombytes(libnacl.crypto_sign_SEEDBYTES) vk, sk, did, body = h.genDidHistory(seed, signer=0, numSigners=2) vk = h.keyToKey64u(vk) headers = { "Signature": 'signer="{0}"; rotation="{1}"'.format(h.signResource(body, sk), h.signResource(body, sk)) } # send inception event client.simulate_post(HISTORY_BASE_PATH, body=body, headers=headers) # Add did to database # rotate once body = json.loads(body) body['changed'] = "2000-01-01T00:00:01+00:00" body['signer'] = 1 body['signers'].append(vk) headers = { "Signature": 'signer="{0}"; rotation="{1}"'.format( h.signResource(json.dumps(body, ensure_ascii=False).encode(), sk), h.signResource(json.dumps(body, ensure_ascii=False).encode(), sk)) } verifyRequest(client.simulate_put, "{0}/{1}".format(HISTORY_BASE_PATH, did), body, headers, exp_status=falcon.HTTP_200) # send updated history with new public key but unchanged signer field body['changed'] = "2000-01-01T00:00:02+00:00" body['signer'] = 1 body['signers'].append(vk) headers = { "Signature": 'signer="{0}"; rotation="{1}"'.format( h.signResource(json.dumps(body, ensure_ascii=False).encode(), sk), h.signResource(json.dumps(body, ensure_ascii=False).encode(), sk)) } exp_result = { "title": "Validation Error", "description": "signer field must be one greater than previous." } verifyRequest(client.simulate_put, "{0}/{1}".format(HISTORY_BASE_PATH, did), body, headers, exp_result=exp_result, exp_status=falcon.HTTP_400)
def testPutSignValidation(client): url = "{0}/{1}".format(HISTORY_BASE_PATH, DID) headers = {"Signature": ""} # Test url did matches id did body = deepcopy(putData) body['id'] = "did:dad:Qt27fThWoNZsa88VrTkep6H-4HA8tr54sHON1vWl6FE=" exp_result = { "title": "Validation Error", "description": "Url did must match id field did." } verifyRequest(client.simulate_put, url, body, exp_result=exp_result, exp_status=falcon.HTTP_400) # Test missing Signature Header body = deepcopy(putData) exp_result = { "title": "Authorization Error", "description": "Empty Signature header." } verifyRequest(client.simulate_put, url, body, headers, exp_result, falcon.HTTP_401) exp_result = { "title": "Missing header value", "description": "The Signature header is required." } response = client.simulate_put( url, body=json.dumps(body, ensure_ascii=False).encode('utf-8')) assert response.status == falcon.HTTP_400 assert json.loads(response.content) == exp_result # Test partial signature header headers = { "Signature": 'signer="' + h.signResource( json.dumps(body, ensure_ascii=False).encode('utf-8'), SK) + '"' } exp_result = { "title": "Authorization Error", "description": "Signature header missing signature for \"rotation\"." } verifyRequest(client.simulate_put, url, body, headers, exp_result, falcon.HTTP_401) headers = { "Signature": 'rotation="' + h.signResource( json.dumps(body, ensure_ascii=False).encode('utf-8'), SK) + '"' } exp_result = { "title": "Authorization Error", "description": "Signature header missing signature for \"signer\"." } verifyRequest(client.simulate_put, url, body, headers, exp_result, falcon.HTTP_401) # Test invalid signer signature body = deepcopy(putData) body['signers'][1] = "Xq5YqaL6L48pf0fu7IUhL0JRaU2_RxFP0AL43wYn148=" exp_result = { "title": "Authorization Error", "description": "Could not validate the request signature for rotation field. Unverifiable signature." } verifyRequest(client.simulate_put, url, body, exp_result=exp_result, exp_status=falcon.HTTP_401) # Test invalid rotation signature body = deepcopy(putData) body['signers'][0] = "Qt27fThWoNZsa88VrTkep6H-4HA8tr54sHON1vWl6FE=" body['signers'][1] = "NOf6ZghvGNbFc_wr3CC0tKZHz1qWAR4lD5aM-i0zSjw=" exp_result = { "title": "Authorization Error", "description": "Could not validate the request signature for signer field. Unverifiable signature." } verifyRequest(client.simulate_put, url, body, exp_result=exp_result, exp_status=falcon.HTTP_401) # validate that signer and rotation signature fields are working correctly seed = libnacl.randombytes(libnacl.crypto_sign_SEEDBYTES) vk, sk = libnacl.crypto_sign_seed_keypair(seed) pvk, psk = libnacl.crypto_sign_seed_keypair(seed) ppvk, ppsk = libnacl.crypto_sign_seed_keypair(seed) did = h.makeDid(vk) vk = h.keyToKey64u(vk) pvk = h.keyToKey64u(pvk) ppvk = h.keyToKey64u(ppvk) body = { "id": did, "changed": str(arrow.utcnow()), "signer": 0, "signers": [vk, pvk] } bbody = json.dumps(body, ensure_ascii=False).encode('utf-8') headers = {"Signature": 'signer="{0}"'.format(h.signResource(bbody, sk))} verifyRequest(client.simulate_post, HISTORY_BASE_PATH, body, headers=headers, exp_status=falcon.HTTP_201) body['signer'] = 1 body['changed'] = str(arrow.utcnow()) body['signers'].append(ppvk) bbody = json.dumps(body, ensure_ascii=False).encode('utf-8') headers = { "Signature": 'signer="{0}"; rotation="{1}"'.format(h.signResource(bbody, sk), h.signResource(bbody, psk)) } url = "{0}/{1}".format(HISTORY_BASE_PATH, did) verifyRequest(client.simulate_put, url, body, headers=headers, exp_status=falcon.HTTP_200)
def testKeyRevocation(client): seed = b'\x92[\xcb\xf4\xee5+\xcf\xd4b*%/\xabw8\xd4d\xa2\xf8\xad\xa7U\x19,\xcfS\x12\xa6l\xba"' # Test Valid rotation event vk, sk, did, body = h.genDidHistory(seed, signer=0, numSigners=2) vk = h.keyToKey64u(vk) headers = { "Signature": 'signer="{0}"; rotation="{1}"'.format(h.signResource(body, sk), h.signResource(body, sk)) } client.simulate_post(HISTORY_BASE_PATH, body=body, headers=headers) # Add did to database # revoke key body = json.loads(body) body['changed'] = "2000-01-01T00:00:01+00:00" body['signer'] = 2 body['signers'].append(None) signature = h.signResource( json.dumps(body, ensure_ascii=False).encode('utf-8'), sk) headers = { "Signature": 'signer="{0}"; rotation="{1}"'.format(signature, signature) } exp_result = { "history": { "id": "did:dad:iy67FstqFl_a5e-sni6yAWoj60-1E2RtzmMGjrjHaSY=", "changed": "2000-01-01T00:00:01+00:00", "signer": 2, "signers": [ "iy67FstqFl_a5e-sni6yAWoj60-1E2RtzmMGjrjHaSY=", "iy67FstqFl_a5e-sni6yAWoj60-1E2RtzmMGjrjHaSY=", None ] }, "signatures": { "signer": signature, "rotation": signature } } verifyRequest(client.simulate_put, "{0}/{1}".format(HISTORY_BASE_PATH, did), body, headers, exp_result=exp_result, exp_status=falcon.HTTP_200) # try to rotate away from the null key body['changed'] = "2000-01-01T00:00:02+00:00" body['signer'] = 3 body['signers'].append(vk) body['signers'].append(vk) headers = { "Signature": 'signer="{0}"; rotation="{1}"'.format( h.signResource(json.dumps(body, ensure_ascii=False).encode(), sk), h.signResource(json.dumps(body, ensure_ascii=False).encode(), sk)) } exp_result = { "title": "Validation Error", "description": "signers keys cannot be null unless revoking a key." } verifyRequest(client.simulate_put, "{0}/{1}".format(HISTORY_BASE_PATH, did), body, headers, exp_result=exp_result, exp_status=falcon.HTTP_400) # try to rotate away from the null key body['changed'] = "2000-01-01T00:00:02+00:00" body['signer'] = 4 body['signers'].append(vk) body['signers'].append(vk) body['signers'].append(vk) headers = { "Signature": 'signer="{0}"; rotation="{1}"'.format( h.signResource(json.dumps(body, ensure_ascii=False).encode(), sk), h.signResource(json.dumps(body, ensure_ascii=False).encode(), sk)) } exp_result = { "title": "Validation Error", "description": "signers keys cannot be null unless revoking a key." } verifyRequest(client.simulate_put, "{0}/{1}".format(HISTORY_BASE_PATH, did), body, headers, exp_result=exp_result, exp_status=falcon.HTTP_400) # try to rotate into the null key prematurely seed = libnacl.randombytes(libnacl.crypto_sign_SEEDBYTES) vk, sk, did, body = h.genDidHistory(seed, signer=0, numSigners=2) headers = { "Signature": 'signer="{0}"; rotation="{1}"'.format(h.signResource(body, sk), h.signResource(body, sk)) } client.simulate_post(HISTORY_BASE_PATH, body=body, headers=headers) # Add did to database body = json.loads(body) body['changed'] = "2000-01-01T00:00:02+00:00" body['signer'] = 4 body['signers'].append(None) body['signers'].append(None) body['signers'].append(None) headers = { "Signature": 'signer="{0}"; rotation="{1}"'.format( h.signResource(json.dumps(body, ensure_ascii=False).encode(), sk), h.signResource(json.dumps(body, ensure_ascii=False).encode(), sk)) } exp_result = { "title": "Validation Error", "description": "signers keys cannot be null unless revoking a key." } verifyRequest(client.simulate_put, "{0}/{1}".format(HISTORY_BASE_PATH, did), body, headers, exp_result=exp_result, exp_status=falcon.HTTP_400)
def testPostSignValidation(client): headers = {"Signature": ""} # Test missing Signature Header body = deepcopy(postData) body = json.dumps(body, ensure_ascii=False).encode('utf-8') exp_result = { "title": "Authorization Error", "description": "Empty Signature header." } response = client.simulate_post(HISTORY_BASE_PATH, body=body, headers=headers) assert response.status == falcon.HTTP_401 assert json.loads(response.content) == exp_result exp_result = { "title": "Missing header value", "description": "The Signature header is required." } response = client.simulate_post(HISTORY_BASE_PATH, body=body) assert response.status == falcon.HTTP_400 assert json.loads(response.content) == exp_result # Test missing signer tag in signature header body = deepcopy(postData) headers = { "Signature": 'test="' + h.signResource( json.dumps(body, ensure_ascii=False).encode('utf-8'), SK) + '"' } exp_result = { "title": "Authorization Error", "description": "Signature header missing \"signer\" tag and signature." } verifyRequest(client.simulate_post, HISTORY_BASE_PATH, body, headers, exp_result, falcon.HTTP_401) # Test invalid signature body = deepcopy(postData) body['signers'][0] = "Qt27fThWoNZsa88VrTkep6H-4HA8tr54sHON1vWl6FE=" exp_result = { "title": "Authorization Error", "description": "Could not validate the request body and signature. Unverifiable signature." } verifyRequest(client.simulate_post, HISTORY_BASE_PATH, body, exp_result=exp_result, exp_status=falcon.HTTP_401) # Test the public key in the id field did matches the first public key in rotation history body = deepcopy(postData) body['id'] = "did:dad:Qt27fThWoNZsa88VrTkep6H-4HA8tr54sHON1vWl6FE=" exp_result = { "title": "Validation Error", "description": "The DIDs key must match the first key in the signers field." } verifyRequest(client.simulate_post, HISTORY_BASE_PATH, body, exp_result=exp_result, exp_status=falcon.HTTP_400)
def testDeleteValidation(client): seed = b'\x92[\xcb\xf4\xee5+\xcf\xd4b*%/\xabw8\xd4d\xa2\xf8\xad\xa7U\x19,\xcfS\x12\xa6l\xba"' vk, sk, did, body = h.genDidHistory(seed, signer=0, numSigners=2) # Test missing url did headers = {"Signature": 'signer="{0}"'.format(h.signResource(body, sk))} client.simulate_post(HISTORY_BASE_PATH, body=body, headers=headers) # Add did to database data = json.dumps({"id": did}, ensure_ascii=False).encode() headers = {"Signature": 'signer="{0}"'.format(h.signResource(data, sk))} response = client.simulate_delete(HISTORY_BASE_PATH, body=data, headers=headers) resp_content = json.loads(response.content) assert response.status == falcon.HTTP_400 assert resp_content["title"] == "Validation Error" assert resp_content["description"] == "DID value missing from url." # Test no Signature header url = "{0}/{1}".format(HISTORY_BASE_PATH, did) headers = {"Signature": 'signer="{0}"'.format(h.signResource(body, sk))} client.simulate_post(HISTORY_BASE_PATH, body=body, headers=headers) # Add did to database data = json.dumps({"id": did}, ensure_ascii=False).encode() response = client.simulate_delete(url, body=data) resp_content = json.loads(response.content) assert response.status == falcon.HTTP_400 assert resp_content["title"] == "Missing header value" assert resp_content["description"] == "The Signature header is required." # Test empty Signature header headers = {"Signature": 'signer="{0}"'.format(h.signResource(body, sk))} client.simulate_post(HISTORY_BASE_PATH, body=body, headers=headers) # Add did to database data = json.dumps({"id": did}, ensure_ascii=False).encode() headers = {"Signature": ""} response = client.simulate_delete(url, body=data, headers=headers) resp_content = json.loads(response.content) assert response.status == falcon.HTTP_401 assert resp_content["title"] == "Authorization Error" assert resp_content["description"] == "Empty Signature header." # Test bad Signature header tag headers = {"Signature": 'signer="{0}"'.format(h.signResource(body, sk))} client.simulate_post(HISTORY_BASE_PATH, body=body, headers=headers) # Add did to database data = json.dumps({"id": did}, ensure_ascii=False).encode() headers = {"Signature": 'rotation="{0}"'.format(h.signResource(data, sk))} response = client.simulate_delete(url, body=data, headers=headers) resp_content = json.loads(response.content) assert response.status == falcon.HTTP_401 assert resp_content["title"] == "Authorization Error" assert resp_content[ "description"] == 'Signature header missing signature for "signer".' # Test mismatched dids url = "{0}/{1}".format(HISTORY_BASE_PATH, DID) headers = {"Signature": 'signer="{0}"'.format(h.signResource(body, sk))} client.simulate_post(HISTORY_BASE_PATH, body=body, headers=headers) # Add did to database data = json.dumps({"id": did}, ensure_ascii=False).encode() headers = {"Signature": 'signer="{0}"'.format(h.signResource(data, sk))} response = client.simulate_delete(url, body=data, headers=headers) resp_content = json.loads(response.content) assert response.status == falcon.HTTP_400 assert resp_content["title"] == "Validation Error" assert resp_content["description"] == "Url did must match id field did." # Test delete non existent resource url = "{0}/{1}".format(HISTORY_BASE_PATH, did) data = json.dumps({"id": did}, ensure_ascii=False).encode() headers = {"Signature": 'signer="{0}"'.format(h.signResource(data, sk))} client.simulate_delete(url, body=data, headers=headers) response = client.simulate_delete(url, body=data, headers=headers) assert response.status == falcon.HTTP_404 # Test invalid signature url = "{0}/{1}".format(HISTORY_BASE_PATH, did) headers = {"Signature": 'signer="{0}"'.format(h.signResource(body, sk))} client.simulate_post(HISTORY_BASE_PATH, body=body, headers=headers) # Add did to database data = json.dumps({"id": did}, ensure_ascii=False).encode() headers = {"Signature": 'signer="{0}"'.format(h.signResource(data, SK))} response = client.simulate_delete(url, body=data, headers=headers) resp_content = json.loads(response.content) print(resp_content) assert response.status == falcon.HTTP_401 assert resp_content["title"] == "Authorization Error" assert resp_content[ "description"] == "Could not validate the request signature for signer field. Unverifiable signature."