Skip to content

Commit

Permalink
Update ActiveState OIDC mixing and migration
Browse files Browse the repository at this point in the history
  • Loading branch information
th3coop committed Aug 7, 2023
1 parent e7b3ef1 commit ae4d142
Show file tree
Hide file tree
Showing 6 changed files with 153 additions and 320 deletions.
11 changes: 6 additions & 5 deletions tests/common/db/oidc.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,10 @@ class Meta:
id = factory.Faker("uuid4", cast_to=None)
sub = factory.Faker("pystr", max_chars=12)
organization_id = factory.Faker("uuid4")
organization_url_name = factory.Faker("pystr", max_chars=12)
organization = factory.Faker("pystr", max_chars=12)
project_id = factory.Faker("uuid4")
activestate_project_name = factory.Faker("pystr", max_chars=12)
project = factory.Faker("pystr", max_chars=12)
actor = factory.Faker("pystr", max_chars=12)
actor_id = factory.Faker("uuid4")
branch_id = factory.Faker("uuid4")

Expand All @@ -109,11 +110,11 @@ class Meta:
model = PendingActiveStatePublisher

id = factory.Faker("uuid4", cast_to=None)
sub = factory.Faker("pystr", max_chars=12)
project_name = factory.Faker("pystr", max_chars=12)
organization_id = factory.Faker("uuid4")
organization_url_name = factory.Faker("pystr", max_chars=12)
organization = factory.Faker("pystr", max_chars=12)
project_id = factory.Faker("uuid4")
activestate_project_name = factory.Faker("pystr", max_chars=12)
project = factory.Faker("pystr", max_chars=12)
actor = factory.Faker("pystr", max_chars=12)
actor_id = factory.Faker("uuid4")
added_by = factory.SubFactory(UserFactory)
154 changes: 60 additions & 94 deletions tests/unit/oidc/models/test_activestate.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,16 @@
PendingActiveStatePublisher,
)

ORG_ID = "00000000-0000-1000-8000-000000000000"
PROJECT_ID = "00000000-0000-1000-8000-000000000001"
ORG_URL_NAME = "fakeorg"
PROJECT_NAME = "fakeproject"
ACTOR_ID = "00000000-0000-1000-8000-000000000002"
BRANCH_ID = "00000000-0000-1000-8000-000000000003"
# This follows the format of the subject that ActiveState sends us. We don't
# validate the format when verifying the JWT. That should happen when the
# Publisher is configured. We just need to make sure that the subject matches
#
# Technically, the branch should only be present if a branch was provided in the JWT
# claims
SUBJECT = "org:fake_org_id:project:fake_project_id:branch_id:fake_branch_id"
SUBJECT = "org:fake_org_id:project:fake_project_id"


def test_lookup_strategies():
Expand All @@ -48,27 +47,29 @@ def test_lookup_strategies():

def new_signed_claims(
sub: str = SUBJECT,
organization_id: str = ORG_ID,
org_url_name: str = "fakeorg",
project_id: str = PROJECT_ID,
project_name: str = "fakeproject",
project_path: str = "fakeorg/fakeproject",
actor: str = "fakeuser",
actor_id: str = ACTOR_ID,
organization: str = ORG_URL_NAME,
org_id: str = "fakeorgid",
project: str = PROJECT_NAME,
project_id: str = "fakeprojectid",
project_path: str = "fakeorg/fakeproject",
project_visibility: str = "public",
branch_id: str | None = None,
) -> SignedClaims:
project_name = "fakeproject"
org_url_name = "fakeorg"
claims = SignedClaims(
{
"sub": sub,
"organization_id": organization_id,
"organization_url_name": org_url_name,
"project_id": project_id,
"project_name": project_name,
"project_path": project_path,
"actor": actor,
"actor_id": actor_id,
"organization_id": org_id,
"organization": organization,
"project_visibility": project_visibility,
"project_id": project_id,
"project_path": project_path,
"project_name": project,
"builder": "fakebuilder",
"ingredient": "fakeingredient",
}
)
if branch_id:
Expand All @@ -85,9 +86,7 @@ def test_publisher_name(self):
def test_publisher_url(self):
org_name = "fakeorg"
project_name = "fakeproject"
publisher = ActiveStatePublisher(
organization_url_name=org_name, activestate_project_name=project_name
)
publisher = ActiveStatePublisher(organization=org_name, project=project_name)

assert (
publisher.publisher_url()
Expand All @@ -97,9 +96,7 @@ def test_publisher_url(self):
def test_stringifies_as_project_url(self):
org_name = "fakeorg"
project_name = "fakeproject"
publisher = ActiveStatePublisher(
organization_url_name=org_name, activestate_project_name=project_name
)
publisher = ActiveStatePublisher(organization=org_name, project=project_name)

assert (
str(publisher)
Expand All @@ -109,8 +106,8 @@ def test_stringifies_as_project_url(self):
def test_activestate_publisher_all_known_claims(self):
assert ActiveStatePublisher.all_known_claims() == {
# verifiable claims
"organization_id",
"project_id",
"organization",
"project",
"actor_id",
"sub",
# optional verifiable claims
Expand All @@ -125,7 +122,7 @@ def test_activestate_publisher_all_known_claims(self):
"project_visibility",
"project_name",
"project_path",
"organization_url_name",
"organization",
}

def test_activestate_publisher_unaccounted_claims(self, monkeypatch):
Expand Down Expand Up @@ -161,11 +158,11 @@ def test_activestate_publisher_unaccounted_claims(self, monkeypatch):
@pytest.mark.parametrize(
("claim_to_drop", "valid"),
[
("organization_id", False),
("project_id", False),
("organization", False),
("project", False),
("actor_id", False),
("branch_id", True),
("organization_url_name", True),
("organization", True),
("project_visibility", True),
("project_name", True),
("project_path", True),
Expand All @@ -176,8 +173,8 @@ def test_activestate_publisher_missing_claims(
):
publisher = ActiveStatePublisher(
sub=SUBJECT,
organization_id=ORG_ID,
project_id=PROJECT_ID,
organization=ORG_URL_NAME,
project=PROJECT_NAME,
actor_id=ACTOR_ID,
)

Expand Down Expand Up @@ -211,84 +208,57 @@ def test_activestate_publisher_missing_claims(
@pytest.mark.parametrize(
("expect", "actual", "valid"),
[
(ORG_ID, ORG_ID, True),
(ORG_ID, PROJECT_ID, False),
(ORG_URL_NAME, ORG_URL_NAME, True),
(ORG_URL_NAME, PROJECT_NAME, False),
],
)
def test_activestate_publisher_org_id_verified(
self, expect: str, actual: str, valid: bool
):
publisher = ActiveStatePublisher(
sub=SUBJECT,
organization_id=actual,
project_id=PROJECT_ID,
organization=actual,
project=PROJECT_NAME,
actor_id=ACTOR_ID,
)

signed_claims = new_signed_claims(organization_id=expect)
signed_claims = new_signed_claims(organization=expect)
assert publisher.verify_claims(signed_claims=signed_claims) is valid

@pytest.mark.parametrize(
("expect", "actual", "valid"),
[
(BRANCH_ID, BRANCH_ID, True),
(BRANCH_ID, PROJECT_ID, False),
# If it's configured in the publisher, it must be present in the claim
(BRANCH_ID, None, False),
# If it's not configured in the publisher, we don't care what it is
# in the claim
(None, None, True),
(None, PROJECT_ID, True),
],
)
def test_activestate_publisher_branch_id_verified(
self, expect: str, actual: str, valid: bool
):
publisher = ActiveStatePublisher(
sub=SUBJECT,
organization_id=ORG_ID,
project_id=PROJECT_ID,
actor_id=ACTOR_ID,
branch_id=expect,
)

signed_claims = new_signed_claims(branch_id=actual)
assert publisher.verify_claims(signed_claims=signed_claims) is valid

@pytest.mark.parametrize(
("expect", "actual", "valid"),
[
(PROJECT_ID, PROJECT_ID, True),
(PROJECT_ID, ORG_ID, False),
(PROJECT_NAME, PROJECT_NAME, True),
(PROJECT_NAME, ORG_URL_NAME, False),
],
)
def test_activestate_publisher_project_id_verified(
self, expect: str, actual: str, valid: bool
):
publisher = ActiveStatePublisher(
sub=SUBJECT,
organization_id=ORG_ID,
project_id=actual,
organization=ORG_URL_NAME,
project=actual,
actor_id=ACTOR_ID,
)

signed_claims = new_signed_claims(project_id=expect)
signed_claims = new_signed_claims(project=expect)
assert publisher.verify_claims(signed_claims=signed_claims) is valid

@pytest.mark.parametrize(
("expect", "actual", "valid"),
[
(ACTOR_ID, ACTOR_ID, True),
(ACTOR_ID, ORG_ID, False),
(ACTOR_ID, ORG_URL_NAME, False),
],
)
def test_activestate_publisher_user_id_verified(
self, expect: str, actual: str, valid: bool
):
publisher = ActiveStatePublisher(
sub=SUBJECT,
organization_id=ORG_ID,
project_id=PROJECT_ID,
organization=ORG_URL_NAME,
project=PROJECT_NAME,
actor_id=actual,
)

Expand All @@ -300,32 +270,26 @@ def test_activestate_publisher_user_id_verified(
[
# Both present: must match.
(
f"org:{ORG_ID}:project:{PROJECT_ID}",
f"org:{ORG_ID}:project:{PROJECT_ID}",
True,
),
# Both present, with branch id: must match.
(
f"org:{ORG_ID}:project:{PROJECT_ID}:branch_id:{BRANCH_ID}",
f"org:{ORG_ID}:project:{PROJECT_ID}:branch_id:{BRANCH_ID}",
f"org:{ORG_URL_NAME}:project:{PROJECT_NAME}",
f"org:{ORG_URL_NAME}:project:{PROJECT_NAME}",
True,
),
# sub configured without branch id, claim has branch id: must fail.
# Wrong value, project, must fail.
(
f"org:{ORG_ID}:project:{PROJECT_ID}",
f"org:{ORG_ID}:project:{PROJECT_ID}:branch_id:{BRANCH_ID}",
f"org:{ORG_URL_NAME}:project:{PROJECT_NAME}",
f"org:{ORG_URL_NAME}:project:{ORG_URL_NAME}",
False,
),
# sub configured with branch id, claim missing branch id: must fail.
# Wrong value, org_id, must fail.
(
f"org:{ORG_ID}:project:{PROJECT_ID}:branch_id:{BRANCH_ID}",
f"org:{ORG_ID}:project:{PROJECT_ID}",
f"org:{ORG_URL_NAME}:project:{PROJECT_NAME}",
f"org:{PROJECT_NAME}:project:{PROJECT_NAME}",
False,
),
# Wrong format for sub to expect from ActiveState: must fail.
# Just nonsenes, must fail.
(
f"org:{ORG_ID}:project:{PROJECT_ID}",
f"org:{ORG_ID}:project:{ORG_ID}",
f"org:{ORG_URL_NAME}:project:{PROJECT_NAME}",
"Nonsense",
False,
),
],
Expand All @@ -343,8 +307,10 @@ def test_reify_does_not_exist_yet(self, db_request):
assert (
db_request.db.query(ActiveStatePublisher)
.filter_by(
organization_id=pending_publisher.organization_id,
sub=pending_publisher.sub,
organization=pending_publisher.organization,
project=pending_publisher.project,
actor_id=pending_publisher.actor_id,
actor=pending_publisher.actor,
)
.one_or_none()
is None
Expand All @@ -353,16 +319,16 @@ def test_reify_does_not_exist_yet(self, db_request):

assert isinstance(publisher, ActiveStatePublisher)
assert pending_publisher in db_request.db.deleted
assert publisher.organization_id == pending_publisher.organization_id
assert publisher.organization == pending_publisher.organization
assert publisher.sub == pending_publisher.sub

def test_reify_already_exists(self, db_request):
existing_publisher: ActiveStatePublisher = ActiveStatePublisherFactory.create()
pending_publisher = PendingActiveStatePublisherFactory.create(
organization_id=existing_publisher.organization_id,
project_id=existing_publisher.project_id,
branch_id=existing_publisher.branch_id,
sub=existing_publisher.sub,
organization=existing_publisher.organization,
project=existing_publisher.project,
actor_id=existing_publisher.actor_id,
actor=existing_publisher.actor,
)
publisher = pending_publisher.reify(db_request.db)

Expand Down
2 changes: 1 addition & 1 deletion tests/unit/oidc/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ def test_find_publisher_by_issuer_activestate(
signed_claims = {
"sub": sub,
"organization_id": organization_id,
"organization_url_name": "fakeOrg",
"organization": "fakeOrg",
"project_id": project_id,
"project_name": "fakername1",
"project_path": "fakeOrg/fakername1",
Expand Down
Loading

0 comments on commit ae4d142

Please sign in to comment.