def setUp(self): super(RelayPublicKeysConfigTest, self).setUp() self.key_pair = generate_key_pair() self.public_key = self.key_pair[1] self.private_key = self.key_pair[0] self.non_existing_key = six.text_type(uuid4()) self.internal_relay = Relay.objects.create( relay_id=six.text_type(uuid4()), public_key=six.binary_type(self.public_key), is_internal=True, ) self.external_relay = Relay.objects.create( relay_id=six.text_type(uuid4()), public_key=six.binary_type(self.public_key), is_internal=False, ) self.relay_a = Relay.objects.create( relay_id=six.text_type(uuid4()), public_key=six.binary_type(self.public_key), is_internal=False, ) self.relay_b = Relay.objects.create( relay_id=six.text_type(uuid4()), public_key=six.binary_type(self.public_key), is_internal=True, ) self.project = self.create_project() self.path = reverse("sentry-api-0-relay-publickeys")
def test_multiple_relay_versions_tracked(self): """ Test that updating the relay version would properly be reflected in the relay analytics. Also that tests that multiple relays """ key_pair = generate_key_pair() relay_id = str(uuid4()) before_registration = timezone.now() self.register_relay(key_pair, "1.1.1", relay_id) after_first_relay = timezone.now() self.register_relay(key_pair, "2.2.2", relay_id) after_second_relay = timezone.now() v1 = Relay.objects.get(relay_id=relay_id) assert v1 is not None rv1 = RelayUsage.objects.get(relay_id=relay_id, version="1.1.1") assert rv1 is not None rv2 = RelayUsage.objects.get(relay_id=relay_id, version="2.2.2") assert rv2 is not None assert rv1.first_seen > before_registration assert rv1.last_seen > before_registration assert rv1.first_seen < after_first_relay assert rv1.last_seen < after_first_relay assert rv2.first_seen > after_first_relay assert rv2.last_seen > after_first_relay assert rv2.first_seen < after_second_relay assert rv2.last_seen < after_second_relay
def test_registered_relay(internal): sk, pk = generate_key_pair() relay_id = str(uuid.uuid4()) data = {"some_data": "hello"} packed, signature = sk.pack(data) request = RequestFactory().post("/", data=packed, content_type="application/json") request.META["HTTP_X_SENTRY_RELAY_SIGNATURE"] = signature request.META["HTTP_X_SENTRY_RELAY_ID"] = relay_id request.META["REMOTE_ADDR"] = "200.200.200.200" # something that is NOT local network Relay.objects.create(relay_id=relay_id, public_key=str(pk)) if internal: white_listed_pk = [str(pk)] # mark the relay as internal else: white_listed_pk = [] authenticator = RelayAuthentication() with override_settings(SENTRY_RELAY_WHITELIST_PK=white_listed_pk): authenticator.authenticate(request) # now the request should contain a relay relay = request.relay assert relay.is_internal == internal assert relay.public_key == str(pk) # data should be deserialized in request.relay_request_data assert request.relay_request_data == data
def test_basic_key_functions(): sk, pk = sentry_relay.generate_key_pair() signature = sk.sign(b"some secret data") assert pk.verify(b"some secret data", signature) assert not pk.verify(b"some other data", signature) packed, signature = sk.pack({"foo": "bar"}) pk.unpack(packed, signature) with pytest.raises(sentry_relay.UnpackErrorBadSignature): pk.unpack(b"haha", signature)
def setUp(self): super().setUp() self.key_pair = generate_key_pair() self.public_key = self.key_pair[1] settings.SENTRY_RELAY_WHITELIST_PK.append(str(self.public_key)) self.private_key = self.key_pair[0] self.relay_id = str(uuid4()) self.path = reverse("sentry-api-0-relay-register-challenge")
def setUp(self): super(RelayRegisterTest, self).setUp() self.key_pair = generate_key_pair() self.public_key = self.key_pair[1] settings.SENTRY_RELAY_WHITELIST_PK.append( six.binary_type(self.public_key)) self.private_key = self.key_pair[0] self.relay_id = six.binary_type(six.text_type(uuid4()).encode("ascii")) self.path = reverse("sentry-api-0-relay-register-challenge")
def test_no_db_for_static_relays(self): """ Tests that statically authenticated relays do not access the database during registration """ key_pair = generate_key_pair() relay_id = str(uuid4()) public_key = key_pair[1] static_auth = {relay_id: {"internal": True, "public_key": str(public_key)}} with self.assertNumQueries(0): with self.settings(SENTRY_OPTIONS={"relay.static_auth": static_auth}): self.register_relay(key_pair, "1.1.1", relay_id)
def test_forge_public_key(self): data = { "public_key": six.binary_type(self.public_key), "relay_id": self.relay_id } raw_json, signature = self.private_key.pack(data) resp = self.client.post( self.path, data=raw_json, content_type="application/json", HTTP_X_SENTRY_RELAY_ID=self.relay_id, HTTP_X_SENTRY_RELAY_SIGNATURE=signature, ) assert resp.status_code == 200, resp.content result = json.loads(resp.content) raw_json, signature = self.private_key.pack(result) self.client.post( reverse("sentry-api-0-relay-register-response"), data=raw_json, content_type="application/json", HTTP_X_SENTRY_RELAY_ID=self.relay_id, HTTP_X_SENTRY_RELAY_SIGNATURE=signature, ) keys = generate_key_pair() settings.SENTRY_RELAY_WHITELIST_PK.append(six.binary_type(keys[1])) data = { "public_key": six.binary_type(keys[1]), "relay_id": self.relay_id } raw_json, signature = keys[0].pack(data) resp = self.client.post( self.path, data=raw_json, content_type="application/json", HTTP_X_SENTRY_RELAY_ID=self.relay_id, HTTP_X_SENTRY_RELAY_SIGNATURE=signature, ) assert resp.status_code == 400, resp.content
def test_expired_challenge(self): data = { "public_key": six.binary_type(self.public_key), "relay_id": self.relay_id } raw_json, signature = self.private_key.pack(data) resp = self.client.post( self.path, data=raw_json, content_type="application/json", HTTP_X_SENTRY_RELAY_ID=self.relay_id, HTTP_X_SENTRY_RELAY_SIGNATURE=signature, ) assert resp.status_code == 200, resp.content result = json.loads(resp.content) raw_json, signature = self.private_key.pack(result) self.client.post( reverse("sentry-api-0-relay-register-response"), data=raw_json, content_type="application/json", HTTP_X_SENTRY_RELAY_ID=self.relay_id, HTTP_X_SENTRY_RELAY_SIGNATURE=signature, ) keys = generate_key_pair() data = { "token": six.binary_type(result.get("token")), "relay_id": self.relay_id } raw_json, signature = keys[0].pack(data) resp = self.client.post( reverse("sentry-api-0-relay-register-response"), data=raw_json, content_type="application/json", HTTP_X_SENTRY_RELAY_ID=self.relay_id, HTTP_X_SENTRY_RELAY_SIGNATURE=signature, ) assert resp.status_code == 401, resp.content
def test_statically_configured_relay(settings, internal): sk, pk = generate_key_pair() relay_id = str(uuid.uuid4()) data = {"some_data": "hello"} packed, signature = sk.pack(data) request = RequestFactory().post("/", data=packed, content_type="application/json") request.META["HTTP_X_SENTRY_RELAY_SIGNATURE"] = signature request.META["HTTP_X_SENTRY_RELAY_ID"] = relay_id request.META["REMOTE_ADDR"] = "200.200.200.200" # something that is NOT local network relay_options = {relay_id: {"internal": internal, "public_key": str(pk)}} settings.SENTRY_OPTIONS["relay.static_auth"] = relay_options authenticator = RelayAuthentication() authenticator.authenticate(request) # now the request should contain a relay relay = request.relay assert relay.is_internal == internal assert relay.public_key == str(pk) # data should be deserialized in request.relay_request_data assert request.relay_request_data == data
def test_relay_usage_is_updated_at_registration(self): """ Tests that during registration the proper relay usage information is updated """ key_pair = generate_key_pair() relay_id = str(uuid4()) before_registration = timezone.now() # register one relay self.register_relay(key_pair, "1.1.1", relay_id) after_first_relay = timezone.now() # register another one that should not be updated after this self.register_relay(key_pair, "2.2.2", relay_id) after_second_relay = timezone.now() # re register the first one in order to update the last used time self.register_relay(key_pair, "1.1.1", relay_id) after_re_register = timezone.now() rv1 = RelayUsage.objects.get(relay_id=relay_id, version="1.1.1") assert rv1 is not None rv2 = RelayUsage.objects.get(relay_id=relay_id, version="2.2.2") assert rv2 is not None # check first seen is not modified by re register assert rv1.first_seen > before_registration assert rv1.first_seen < after_first_relay # check last seen shows the time at re-registration assert rv1.last_seen > after_second_relay assert rv1.last_seen < after_re_register # check version 2.2.2 is not affected by version 1.1.1 assert rv2.first_seen > after_first_relay assert rv2.last_seen > after_first_relay assert rv2.first_seen < after_second_relay assert rv2.last_seen < after_second_relay
def test_basic_key_functions(): sk, pk = sentry_relay.generate_key_pair() signature = sk.sign(b"some secret data") assert pk.verify(b"some secret data", signature) assert not pk.verify(b"some other data", signature)
def test_public_keys(mini_sentry, relay, caller, relays_to_fetch): """ Tests the public key endpoint with dynamic and statically configured relays Create 2 normal relays r1 & r2 ( that will register normally to upstream) Create the configuration for 2 static relays sr1,sr2 (and add this config to r1) Send to r1 various requests for r2,sr1,sr2 from various relays (r2,sr1,sr2) """ # create info for 2 statically configured relay sk1, pk1 = generate_key_pair() id1 = str(uuid.uuid4()) sk2, pk2 = generate_key_pair() id2 = str(uuid.uuid4()) # create configuration containing the static relays relays_conf = { id1: { "public_key": str(pk1), "internal": True }, id2: { "public_key": str(pk2), "internal": False }, } # create 2 normal relays relay1 = relay(mini_sentry, wait_healthcheck=True, static_relays=relays_conf) relay2 = relay(mini_sentry, wait_healthcheck=True, static_relays=relays_conf) # create info for our test parameters r1 = RelayInfo( id=relay1.relay_id, public_key=PublicKey.parse(relay1.public_key), secret_key=SecretKey.parse(relay1.secret_key), internal=True, ) r2 = RelayInfo( id=relay2.relay_id, public_key=PublicKey.parse(relay2.public_key), secret_key=SecretKey.parse(relay2.secret_key), internal=True, ) sr1 = RelayInfo(id=id1, public_key=pk1, secret_key=sk1, internal=True) sr2 = RelayInfo(id=id2, public_key=pk2, secret_key=sk2, internal=False) test_info = {"r1": r1, "r2": r2, "sr1": sr1, "sr2": sr2} caller = test_info[caller] relays_to_fetch = [test_info[r] for r in relays_to_fetch] request = {"relay_ids": [relay_info.id for relay_info in relays_to_fetch]} packed, signature = caller.secret_key.pack(request) resp = relay1.post( "/api/0/relays/publickeys/", data=packed, headers={ "X-Sentry-Relay-Id": caller.id, "X-Sentry-Relay-Signature": signature }, ) assert resp.ok expected = { "relays": { ri.id: { "publicKey": str(ri.public_key), "internal": ri.internal } for ri in relays_to_fetch } } assert resp.json() == expected
def test_dynamic_relays(mini_sentry, relay, caller, projects): sk1, pk1 = generate_key_pair() id1 = str(uuid.uuid4()) sk2, pk2 = generate_key_pair() id2 = str(uuid.uuid4()) # create configuration containing the static relays relays_conf = { id1: {"public_key": str(pk1), "internal": True}, id2: {"public_key": str(pk2), "internal": False}, } relay1 = relay(mini_sentry, wait_healthcheck=True, static_relays=relays_conf) relay2 = relay( mini_sentry, wait_healthcheck=True, external=True, static_relays=relays_conf, ) # create info for our test parameters r1 = RelayInfo( id=relay1.relay_id, public_key=PublicKey.parse(relay1.public_key), secret_key=SecretKey.parse(relay1.secret_key), internal=True, ) r2 = RelayInfo( id=relay2.relay_id, public_key=PublicKey.parse(relay2.public_key), secret_key=SecretKey.parse(relay2.secret_key), internal=True, ) sr1 = RelayInfo(id=id1, public_key=pk1, secret_key=sk1, internal=True) sr2 = RelayInfo(id=id2, public_key=pk2, secret_key=sk2, internal=False) # add a project config for each relay key p1 = mini_sentry.add_basic_project_config(1) p2 = mini_sentry.add_basic_project_config(2) # add r2 to p2 since it is external p2["config"]["trustedRelays"].append(str(r2.public_key)) p3 = mini_sentry.add_basic_project_config(3) p4 = mini_sentry.add_basic_project_config(4) # add sr2 to p4 (since it is external) p4["config"]["trustedRelays"].append(str(sr2.public_key)) test_info = {"r1": r1, "r2": r2, "sr1": sr1, "sr2": sr2} proj_info = { "p1": p1, "p2": p2, "p3": p3, "p4": p4, } caller = test_info[caller] projects = [proj_info[proj] for proj in projects] public_keys = [str(p["publicKeys"][0]["publicKey"]) for p in projects] request = {"publicKeys": public_keys, "fullConfig": True} packed, signature = caller.secret_key.pack(request) resp = relay1.post( "/api/0/relays/projectconfigs/?version=2", data=packed, headers={"X-Sentry-Relay-Id": caller.id, "X-Sentry-Relay-Signature": signature}, ) assert resp.ok # test that it returns valid data data = resp.json() for p in public_keys: assert data["configs"][p] is not None