def post(self, request): """ Registers a Relay ````````````````` Registers the relay with the sentry installation. If a relay boots it will always attempt to invoke this endpoint. """ try: json_data = json.loads(request.body) except ValueError: return Response({"detail": "No valid json body"}, status=status.HTTP_400_BAD_REQUEST) serializer = RelayRegisterResponseSerializer(data=json_data) if not serializer.is_valid(): return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) sig = get_header_relay_signature(request) if not sig: return Response({"detail": "Missing relay signature"}, status=status.HTTP_400_BAD_REQUEST) relay_id = six.text_type(get_register_response_relay_id(request.body)) if relay_id != get_header_relay_id(request): return Response( {"detail": "relay_id in payload did not match header"}, status=status.HTTP_400_BAD_REQUEST, ) params = default_cache.get("relay-auth:%s" % relay_id) if params is None: return Response({"detail": "Challenge expired"}, status=status.HTTP_401_UNAUTHORIZED) key = PublicKey.parse(params["public_key"]) try: validate_register_response(key, request.body, sig) except Exception as exc: return Response({"detail": str(exc).splitlines()[0]}, status=status.HTTP_400_BAD_REQUEST) is_internal = is_internal_relay(request, params["public_key"]) try: relay = Relay.objects.get(relay_id=relay_id) except Relay.DoesNotExist: relay = Relay.objects.create(relay_id=relay_id, public_key=params["public_key"], is_internal=is_internal) else: relay.last_seen = timezone.now() relay.is_internal = is_internal relay.save() default_cache.delete("relay-auth:%s" % relay_id) return Response(serialize({"relay_id": relay.relay_id}))
def post(self, request): """ Registers a Relay ````````````````` Registers the relay with the sentry installation. If a relay boots it will always attempt to invoke this endpoint. """ try: json_data = json.loads(request.body) except ValueError: return Response({"detail": "No valid json body"}, status=status.HTTP_400_BAD_REQUEST) serializer = RelayRegisterResponseSerializer(data=json_data) if not serializer.is_valid(): return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) sig = get_header_relay_signature(request) if not sig: return Response({"detail": "Missing relay signature"}, status=status.HTTP_400_BAD_REQUEST) secret = options.get("system.secret-key") try: validated = validate_register_response(request.body, sig, secret) except UnpackErrorSignatureExpired: return Response({"detail": "Challenge expired"}, status=status.HTTP_401_UNAUTHORIZED) except Exception as exc: return Response({"detail": str(exc).splitlines()[0]}, status=status.HTTP_400_BAD_REQUEST) relay_id = six.text_type(validated["relay_id"]) public_key = validated["public_key"] if relay_id != get_header_relay_id(request): return Response( {"detail": "relay_id in payload did not match header"}, status=status.HTTP_400_BAD_REQUEST, ) is_internal = is_internal_relay(request, public_key) try: relay = Relay.objects.get(relay_id=relay_id) except Relay.DoesNotExist: relay = Relay.objects.create(relay_id=relay_id, public_key=public_key, is_internal=is_internal) else: relay.last_seen = timezone.now() relay.is_internal = is_internal relay.save() return Response(serialize({"relay_id": relay.relay_id}))
def authenticate(self, request): relay_id = get_header_relay_id(request) relay_sig = get_header_relay_signature(request) if not relay_id: raise AuthenticationFailed('Invalid relay ID') if not relay_sig: raise AuthenticationFailed('Missing relay signature') return self.authenticate_credentials(relay_id, relay_sig, request)
def is_static_relay(request): """ Checks if the request comes from a statically configured relay Note: Only checks the relay_id (no public key validation is done). """ relay_id = get_header_relay_id(request) static_relays = options.get("relay.static_auth") relay_info = static_relays.get(relay_id) return relay_info is not None
def post(self, request): """ Requests to Register a Relay ```````````````````````````` Registers the relay with the sentry installation. If a relay boots it will always attempt to invoke this endpoint. """ try: json_data = json.loads(request.body) except ValueError: return Response({ 'detail': 'No valid json body', }, status=status.HTTP_400_BAD_REQUEST) serializer = RelayRegisterChallengeSerializer(data=json_data) if not serializer.is_valid(): return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) if not self.check_allowed_relay(request, json_data): return Response({ 'detail': 'Relay is not allowed to register', }, status=status.HTTP_401_UNAUTHORIZED) sig = get_header_relay_signature(request) if not sig: return Response({ 'detail': 'Missing relay signature', }, status=status.HTTP_400_BAD_REQUEST) try: challenge = create_register_challenge(request.body, sig) except Exception as exc: return Response({ 'detail': str(exc).splitlines()[0], }, status=status.HTTP_400_BAD_REQUEST) relay_id = six.text_type(challenge['relay_id']) if relay_id != get_header_relay_id(request): return Response({ 'detail': 'relay_id in payload did not match header', }, status=status.HTTP_400_BAD_REQUEST) try: relay = Relay.objects.get(relay_id=relay_id) except Relay.DoesNotExist: pass else: if relay.public_key != six.text_type(challenge['public_key']): # This happens if we have an ID collision or someone copies an existing id return Response({ 'detail': 'Attempted to register agent with a different public key', }, status=status.HTTP_400_BAD_REQUEST) default_cache.set('relay-auth:%s' % relay_id, { 'token': challenge['token'], 'public_key': six.text_type(challenge['public_key']), }, 60) return Response(serialize({ 'relay_id': six.text_type(challenge['relay_id']), 'token': challenge['token'], }))
def post(self, request): """ Requests to Register a Relay ```````````````````````````` Registers the relay with the sentry installation. If a relay boots it will always attempt to invoke this endpoint. """ try: json_data = json.loads(request.body) except ValueError: return Response({ 'detail': 'No valid json body', }, status=status.HTTP_400_BAD_REQUEST) serializer = RelayRegisterChallengeSerializer(data=json_data) if not serializer.is_valid(): return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) if not settings.SENTRY_RELAY_OPEN_REGISTRATION and \ not is_internal_relay(request, json_data.get('public_key')): return Response({ 'detail': 'Relay is not allowed to register', }, status=status.HTTP_401_UNAUTHORIZED) sig = get_header_relay_signature(request) if not sig: return Response({ 'detail': 'Missing relay signature', }, status=status.HTTP_400_BAD_REQUEST) try: challenge = create_register_challenge(request.body, sig) except Exception as exc: return Response({ 'detail': str(exc).splitlines()[0], }, status=status.HTTP_400_BAD_REQUEST) relay_id = six.text_type(challenge['relay_id']) if relay_id != get_header_relay_id(request): return Response({ 'detail': 'relay_id in payload did not match header', }, status=status.HTTP_400_BAD_REQUEST) try: relay = Relay.objects.get(relay_id=relay_id) except Relay.DoesNotExist: pass else: if relay.public_key != six.text_type(challenge['public_key']): # This happens if we have an ID collision or someone copies an existing id return Response({ 'detail': 'Attempted to register agent with a different public key', }, status=status.HTTP_400_BAD_REQUEST) default_cache.set('relay-auth:%s' % relay_id, { 'token': challenge['token'], 'public_key': six.text_type(challenge['public_key']), }, 60) return Response(serialize({ 'relay_id': six.text_type(challenge['relay_id']), 'token': challenge['token'], }))
def post(self, request): """ Registers a Relay ````````````````` Registers the relay with the sentry installation. If a relay boots it will always attempt to invoke this endpoint. """ try: json_data = json.loads(request.body) except ValueError: return Response({ 'detail': 'No valid json body', }, status=status.HTTP_400_BAD_REQUEST) serializer = RelayRegisterResponseSerializer(data=json_data) if not serializer.is_valid(): return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) sig = get_header_relay_signature(request) if not sig: return Response({ 'detail': 'Missing relay signature', }, status=status.HTTP_400_BAD_REQUEST) relay_id = six.text_type(get_register_response_relay_id(request.body)) if relay_id != get_header_relay_id(request): return Response({ 'detail': 'relay_id in payload did not match header', }, status=status.HTTP_400_BAD_REQUEST) params = default_cache.get('relay-auth:%s' % relay_id) if params is None: return Response({ 'detail': 'Challenge expired' }, status=status.HTTP_401_UNAUTHORIZED) key = PublicKey.parse(params['public_key']) try: validate_register_response(key, request.body, sig) except Exception as exc: return Response({ 'detail': str(exc).splitlines()[0], }, status=status.HTTP_400_BAD_REQUEST) is_internal = is_internal_relay(request, params['public_key']) try: relay = Relay.objects.get(relay_id=relay_id) except Relay.DoesNotExist: relay = Relay.objects.create( relay_id=relay_id, public_key=params['public_key'], is_internal=is_internal ) else: relay.last_seen = timezone.now() relay.is_internal = is_internal relay.save() default_cache.delete('relay-auth:%s' % relay_id) return Response(serialize({ 'relay_id': relay.relay_id, }))
def post(self, request): """ Requests to Register a Relay ```````````````````````````` Registers the relay with the sentry installation. If a relay boots it will always attempt to invoke this endpoint. """ try: json_data = json.loads(request.body) except ValueError: return Response({"detail": "No valid json body"}, status=status.HTTP_400_BAD_REQUEST) serializer = RelayRegisterChallengeSerializer(data=json_data) if not serializer.is_valid(): return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) if not settings.SENTRY_RELAY_OPEN_REGISTRATION and not is_internal_relay( request, json_data.get("public_key") ): return Response( {"detail": "Relay is not allowed to register"}, status=status.HTTP_401_UNAUTHORIZED ) sig = get_header_relay_signature(request) if not sig: return Response( {"detail": "Missing relay signature"}, status=status.HTTP_400_BAD_REQUEST ) try: challenge = create_register_challenge(request.body, sig) except Exception as exc: return Response( {"detail": str(exc).splitlines()[0]}, status=status.HTTP_400_BAD_REQUEST ) relay_id = six.text_type(challenge["relay_id"]) if relay_id != get_header_relay_id(request): return Response( {"detail": "relay_id in payload did not match header"}, status=status.HTTP_400_BAD_REQUEST, ) try: relay = Relay.objects.get(relay_id=relay_id) except Relay.DoesNotExist: pass else: if relay.public_key != six.text_type(challenge["public_key"]): # This happens if we have an ID collision or someone copies an existing id return Response( {"detail": "Attempted to register agent with a different public key"}, status=status.HTTP_400_BAD_REQUEST, ) default_cache.set( "relay-auth:%s" % relay_id, {"token": challenge["token"], "public_key": six.text_type(challenge["public_key"])}, 60, ) return Response( serialize( {"relay_id": six.text_type(challenge["relay_id"]), "token": challenge["token"]} ) )
def post(self, request): """ Requests to Register a Relay ```````````````````````````` Registers the relay with the sentry installation. If a relay boots it will always attempt to invoke this endpoint. """ try: json_data = json.loads(request.body) except ValueError: return Response({"detail": "No valid json body"}, status=status.HTTP_400_BAD_REQUEST) serializer = RelayRegisterChallengeSerializer(data=json_data) if not serializer.is_valid(): return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) if not is_version_supported(json_data.get("version")): return Response( { "detail": "Relay version no longer supported, please upgrade to a more recent version" }, status=status.HTTP_403_FORBIDDEN, ) public_key = json_data.get("public_key") if not public_key: return Response({"detail": "Missing public key"}, status=status.HTTP_400_FORBIDDEN) if not settings.SENTRY_RELAY_OPEN_REGISTRATION and not is_internal_relay( request, public_key): return Response({"detail": "Relay is not allowed to register"}, status=status.HTTP_403_FORBIDDEN) sig = get_header_relay_signature(request) if not sig: return Response({"detail": "Missing relay signature"}, status=status.HTTP_400_BAD_REQUEST) secret = options.get("system.secret-key") try: challenge = create_register_challenge(request.body, sig, secret) except Exception as exc: return Response({"detail": str(exc).splitlines()[0]}, status=status.HTTP_400_BAD_REQUEST) relay_id = six.text_type(challenge["relay_id"]) if relay_id != get_header_relay_id(request): return Response( {"detail": "relay_id in payload did not match header"}, status=status.HTTP_400_BAD_REQUEST, ) try: relay = Relay.objects.get(relay_id=relay_id) except Relay.DoesNotExist: pass else: if relay.public_key != six.text_type(public_key): # This happens if we have an ID collision or someone copies an existing id return Response( { "detail": "Attempted to register agent with a different public key" }, status=status.HTTP_400_BAD_REQUEST, ) return Response(serialize(challenge))
def post(self, request: Request) -> Response: """ Registers a Relay ````````````````` Registers the relay with the sentry installation. If a relay boots it will always attempt to invoke this endpoint. """ try: json_data = json.loads(request.body) except ValueError: return Response({"detail": "No valid json body"}, status=status.HTTP_400_BAD_REQUEST) serializer = RelayRegisterResponseSerializer(data=json_data) if not serializer.is_valid(): return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) sig = get_header_relay_signature(request) if not sig: return Response({"detail": "Missing relay signature"}, status=status.HTTP_400_BAD_REQUEST) secret = options.get("system.secret-key") try: validated = validate_register_response(request.body, sig, secret) except UnpackErrorSignatureExpired: return Response({"detail": "Challenge expired"}, status=status.HTTP_401_UNAUTHORIZED) except Exception as exc: return Response({"detail": str(exc).splitlines()[0]}, status=status.HTTP_400_BAD_REQUEST) relay_id = str(validated["relay_id"]) version = str(validated["version"]) public_key = validated["public_key"] if relay_id != get_header_relay_id(request): return Response( {"detail": "relay_id in payload did not match header"}, status=status.HTTP_400_BAD_REQUEST, ) relay, static = relay_from_id(request, relay_id) if not static: is_internal = is_internal_relay(request, public_key) if relay is None: relay = Relay.objects.create(relay_id=relay_id, public_key=public_key, is_internal=is_internal) else: # update the internal flag in case it is changed relay.is_internal = is_internal relay.save() # only update usage for non static relays (static relays should not access the db) try: relay_usage = RelayUsage.objects.get(relay_id=relay_id, version=version) except RelayUsage.DoesNotExist: RelayUsage.objects.create(relay_id=relay_id, version=version, public_key=public_key) else: relay_usage.last_seen = timezone.now() relay_usage.public_key = public_key relay_usage.save() return Response(serialize({"relay_id": relay.relay_id}))