Skip to content

Commit

Permalink
Ensure users can not add cross-domain content through modify endpoint
Browse files Browse the repository at this point in the history
fixes: #5934
  • Loading branch information
gerrod3 committed Oct 24, 2024
1 parent 17770ed commit eb48cf2
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 3 deletions.
1 change: 1 addition & 0 deletions CHANGES/5934.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fixed repository modify allowing content from separate domains.
72 changes: 72 additions & 0 deletions pulp_file/tests/functional/api/test_domains.py
Original file line number Diff line number Diff line change
Expand Up @@ -289,3 +289,75 @@ def test_domain_rbac(pulpcore_bindings, file_bindings, gen_user, gen_object_with
{"name": str(uuid.uuid4())}, pulp_domain=domain.name
)
assert e.value.status == 403


@pytest.mark.parallel
def test_no_cross_pollination(
pulpcore_bindings,
file_bindings,
basic_manifest_path,
file_repository_factory,
file_remote_factory,
file_publication_factory,
file_distribution_factory,
gen_object_with_cleanup,
monitor_task,
):
"""Tests that you can't use objects across domains."""
d_remote = file_remote_factory(manifest_path=basic_manifest_path, policy="immediate")
d_repo = file_repository_factory(remote=d_remote.pulp_href)
monitor_task(file_bindings.RepositoriesFileApi.sync(d_repo.pulp_href, {}).task)
d_repo = file_bindings.RepositoriesFileApi.read(d_repo.pulp_href)
assert d_repo.latest_version_href[-2] == "1"

body = {
"name": str(uuid.uuid4()),
"storage_class": "pulpcore.app.models.storage.FileSystem",
"storage_settings": {"MEDIA_ROOT": "/var/lib/pulp/media/"},
}
domain = gen_object_with_cleanup(pulpcore_bindings.DomainsApi, body)
# Fail repository create
with pytest.raises(file_bindings.ApiException) as e:
file_repository_factory(remote=d_remote.pulp_href, pulp_domain=domain.name)
assert e.value.status == 400
assert json.loads(e.value.body) == {
"non_field_errors": [f"Objects must all be a part of the {domain.name} domain."]
}

# Fail repository sync
repo = file_repository_factory(pulp_domain=domain.name)
with pytest.raises(file_bindings.ApiException) as e:
file_bindings.RepositoriesFileApi.sync(repo.pulp_href, {"remote": d_remote.pulp_href})
assert e.value.status == 400
assert json.loads(e.value.body) == {
"non_field_errors": [f"Objects must all be a part of the {domain.name} domain."]
}

# Fail publication
with pytest.raises(file_bindings.ApiException) as e:
file_publication_factory(repository=d_repo.pulp_href, pulp_domain=domain.name)
assert e.value.status == 400
assert json.loads(e.value.body) == {
"non_field_errors": [f"Objects must all be a part of the {domain.name} domain."]
}

# Fail distribute
with pytest.raises(file_bindings.ApiException) as e:
file_distribution_factory(repository=d_repo.pulp_href, pulp_domain=domain.name)
assert e.value.status == 400
assert json.loads(e.value.body) == {
"non_field_errors": [f"Objects must all be a part of the {domain.name} domain."]
}

# Fail repo modify
content = file_bindings.ContentFilesApi.list(repository_version=d_repo.latest_version_href)
content_hrefs = [c.pulp_href for c in content.results]
body = {"add_content_units": content_hrefs}
with pytest.raises(file_bindings.ApiException) as e:
file_bindings.RepositoriesFileApi.modify(repo.pulp_href, body)
assert e.value.status == 400
error = json.loads(e.value.body)
assert "add_content_units" in error
assert error["add_content_units"][0].startswith(
f"Content units are not a part of the current domain {domain.name}: ["
)
2 changes: 2 additions & 0 deletions pulpcore/app/models/repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -984,6 +984,7 @@ def add_content(self, content):
if self.complete:
raise ResourceImmutableError(self)

assert not content.exclude(pulp_domain_id=get_domain_pk()).exists()
repo_content = []
to_add = set(content.values_list("pk", flat=True)) - set(
self.content.values_list("pk", flat=True)
Expand Down Expand Up @@ -1025,6 +1026,7 @@ def remove_content(self, content):

if not content or not content.count():
return
assert not content.exclude(pulp_domain_id=get_domain_pk()).exists()

# Normalize representation if content has already been added in this version.
# Undo addition by deleting the RepositoryContent.
Expand Down
2 changes: 1 addition & 1 deletion pulpcore/app/serializers/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ def check_cross_domains(self, data):
):
if current_domain.pulp_id != domain_id:
raise serializers.ValidationError(
_("Objects must all be apart of the {} domain.").format(
_("Objects must all be a part of the {} domain.").format(
current_domain.name
)
)
Expand Down
21 changes: 19 additions & 2 deletions pulpcore/app/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,17 +201,34 @@ def extract_pk(uri, only_prn=False):
raise ValidationError("URI does not contain an unqualified resource PK")


def raise_for_unknown_content_units(existing_content_units, content_units_pks_hrefs):
def raise_for_unknown_content_units(
existing_content_units,
content_units_pks_hrefs,
domain=None,
):
"""Verify if all the specified content units were found in the database.
Args:
existing_content_units (pulpcore.plugin.models.Content): Content filtered by
specified_content_units.
content_units_pks_hrefs (dict): An original dictionary of pk-href pairs that
are used for the verification.
domain (pulpcore.plugin.models.Domain): A domain to use for verifying that all the
content units are within the same domain. defaults to current domain.
Raises:
ValidationError: If some of the referenced content units are not present in the database
ValidationError: If some of the referenced content units are not present in the database or
content units are from multiple domains
"""
domain = domain or get_domain()
bad_domain_pks = existing_content_units.exclude(pulp_domain=domain).values_list("pk", flat=True)
if bad_domain_pks:
bad_hrefs = [content_units_pks_hrefs[str(pk)] for pk in bad_domain_pks]
raise ValidationError(
_("Content units are not a part of the current domain {}: {}").format(
domain.name, bad_hrefs
)
)

existing_content_units_pks = existing_content_units.values_list("pk", flat=True)
existing_content_units_pks = set(map(str, existing_content_units_pks))

Expand Down

0 comments on commit eb48cf2

Please sign in to comment.