From 3c5e625f472fc2130690e93916d36d55b0ec57a2 Mon Sep 17 00:00:00 2001 From: Scott Leggett Date: Mon, 7 Oct 2024 23:32:54 +0800 Subject: [PATCH] chore: add keycloak UserGroupIDRole tests --- internal/keycloak/helper_test.go | 6 + .../testdata/usergroups_children0.json | 32 +++ .../testdata/usergroups_children1.json | 20 ++ .../testdata/usergroups_children2.json | 84 ++++++++ .../testdata/usergroups_children3.json | 26 +++ .../testdata/usergroups_children4.json | 50 +++++ .../testdata/usergroups_children5.json | 74 +++++++ .../testdata/usergroups_children6.json | 50 +++++ .../testdata/usergroups_children7.json | 26 +++ .../testdata/usergroups_children8.json | 26 +++ .../testdata/usergroups_groups_first0.json | 72 +++++++ .../testdata/usergroups_groups_first10.json | 72 +++++++ .../testdata/usergroups_groups_first15.json | 72 +++++++ .../testdata/usergroups_groups_first20.json | 44 ++++ .../testdata/usergroups_groups_first5.json | 72 +++++++ internal/keycloak/usergroups_test.go | 199 ++++++++++++++++++ 16 files changed, 925 insertions(+) create mode 100644 internal/keycloak/testdata/usergroups_children0.json create mode 100644 internal/keycloak/testdata/usergroups_children1.json create mode 100644 internal/keycloak/testdata/usergroups_children2.json create mode 100644 internal/keycloak/testdata/usergroups_children3.json create mode 100644 internal/keycloak/testdata/usergroups_children4.json create mode 100644 internal/keycloak/testdata/usergroups_children5.json create mode 100644 internal/keycloak/testdata/usergroups_children6.json create mode 100644 internal/keycloak/testdata/usergroups_children7.json create mode 100644 internal/keycloak/testdata/usergroups_children8.json create mode 100644 internal/keycloak/testdata/usergroups_groups_first0.json create mode 100644 internal/keycloak/testdata/usergroups_groups_first10.json create mode 100644 internal/keycloak/testdata/usergroups_groups_first15.json create mode 100644 internal/keycloak/testdata/usergroups_groups_first20.json create mode 100644 internal/keycloak/testdata/usergroups_groups_first5.json create mode 100644 internal/keycloak/usergroups_test.go diff --git a/internal/keycloak/helper_test.go b/internal/keycloak/helper_test.go index 273a45d..844c23f 100644 --- a/internal/keycloak/helper_test.go +++ b/internal/keycloak/helper_test.go @@ -24,3 +24,9 @@ func (l *LagoonClaims) SetClientID(clientID string) { func (c *Client) UseDefaultHTTPClient() { c.httpClient = http.DefaultClient } + +// UsePageSize sets the page size used by the client when retrieving groups +// from Keycloak. +func (c *Client) UsePageSize(pageSize int) { + c.pageSize = pageSize +} diff --git a/internal/keycloak/testdata/usergroups_children0.json b/internal/keycloak/testdata/usergroups_children0.json new file mode 100644 index 0000000..83616dc --- /dev/null +++ b/internal/keycloak/testdata/usergroups_children0.json @@ -0,0 +1,32 @@ +[ + { + "access": { + "manage": true, + "manageMembers": true, + "manageMembership": true, + "view": true, + "viewMembers": true + }, + "id": "2e833d9b-39b7-4f25-b37f-cfb8765015ab", + "name": "scott-test-child-group2", + "parentId": "ee6d02d1-b14b-41dd-95b6-cb8c26b1a321", + "path": "/scott-test-ancestor-group2/scott-test-child-group2", + "subGroupCount": 3, + "subGroups": [] + }, + { + "access": { + "manage": true, + "manageMembers": true, + "manageMembership": true, + "view": true, + "viewMembers": true + }, + "id": "7f22ce84-c0af-4ff4-afcd-288f0473deb5", + "name": "scott-test-child-group3", + "parentId": "ee6d02d1-b14b-41dd-95b6-cb8c26b1a321", + "path": "/scott-test-ancestor-group2/scott-test-child-group3", + "subGroupCount": 1, + "subGroups": [] + } +] diff --git a/internal/keycloak/testdata/usergroups_children1.json b/internal/keycloak/testdata/usergroups_children1.json new file mode 100644 index 0000000..ffa5be1 --- /dev/null +++ b/internal/keycloak/testdata/usergroups_children1.json @@ -0,0 +1,20 @@ +[ + { + "access": { + "manage": true, + "manageMembers": true, + "manageMembership": true, + "view": true, + "viewMembers": true + }, + "attributes": {}, + "clientRoles": {}, + "id": "139ad442-1d20-4c58-b009-c0afe21bf85b", + "name": "scott-test-grandchild-group3", + "parentId": "7f22ce84-c0af-4ff4-afcd-288f0473deb5", + "path": "/scott-test-ancestor-group2/scott-test-child-group3/scott-test-grandchild-group3", + "realmRoles": [], + "subGroupCount": 1, + "subGroups": [] + } +] diff --git a/internal/keycloak/testdata/usergroups_children2.json b/internal/keycloak/testdata/usergroups_children2.json new file mode 100644 index 0000000..7559ece --- /dev/null +++ b/internal/keycloak/testdata/usergroups_children2.json @@ -0,0 +1,84 @@ +[ + { + "access": { + "manage": true, + "manageMembers": true, + "manageMembership": true, + "view": true, + "viewMembers": true + }, + "attributes": { + "type": [ + "role-subgroup" + ] + }, + "clientRoles": {}, + "id": "2c0f9a62-3e50-4e90-913d-90db6cb47cce", + "name": "scott-test-child-group2-developer", + "parentId": "2e833d9b-39b7-4f25-b37f-cfb8765015ab", + "path": "/scott-test-ancestor-group2/scott-test-child-group2/scott-test-child-group2-developer", + "realmRoles": [ + "developer" + ], + "subGroupCount": 0, + "subGroups": [] + }, + { + "access": { + "manage": true, + "manageMembers": true, + "manageMembership": true, + "view": true, + "viewMembers": true + }, + "attributes": { + "type": [ + "role-subgroup" + ] + }, + "clientRoles": {}, + "id": "43db2a06-ca7c-482e-b068-23127ae5d50a", + "name": "scott-test-child-group2-maintainer", + "parentId": "2e833d9b-39b7-4f25-b37f-cfb8765015ab", + "path": "/scott-test-ancestor-group2/scott-test-child-group2/scott-test-child-group2-maintainer", + "realmRoles": [], + "subGroupCount": 0, + "subGroups": [] + }, + { + "access": { + "manage": true, + "manageMembers": true, + "manageMembership": true, + "view": true, + "viewMembers": true + }, + "attributes": {}, + "clientRoles": {}, + "id": "879d1d38-97d8-449a-affd-8529b8e31feb", + "name": "scott-test-grandchild-group2", + "parentId": "2e833d9b-39b7-4f25-b37f-cfb8765015ab", + "path": "/scott-test-ancestor-group2/scott-test-child-group2/scott-test-grandchild-group2", + "realmRoles": [], + "subGroupCount": 1, + "subGroups": [] + }, + { + "access": { + "manage": true, + "manageMembers": true, + "manageMembership": true, + "view": true, + "viewMembers": true + }, + "attributes": {}, + "clientRoles": {}, + "id": "c7d3b738-91f2-4cf1-aeec-2ab444eb3215", + "name": "scott-test-grandchild-group2b", + "parentId": "2e833d9b-39b7-4f25-b37f-cfb8765015ab", + "path": "/scott-test-ancestor-group2/scott-test-child-group2/scott-test-grandchild-group2b", + "realmRoles": [], + "subGroupCount": 1, + "subGroups": [] + } +] diff --git a/internal/keycloak/testdata/usergroups_children3.json b/internal/keycloak/testdata/usergroups_children3.json new file mode 100644 index 0000000..b8e7797 --- /dev/null +++ b/internal/keycloak/testdata/usergroups_children3.json @@ -0,0 +1,26 @@ +[ + { + "access": { + "manage": true, + "manageMembers": true, + "manageMembership": true, + "view": true, + "viewMembers": true + }, + "attributes": { + "type": [ + "role-subgroup" + ] + }, + "clientRoles": {}, + "id": "26fc9bcf-1d04-426f-ac25-67146d2d3fd0", + "name": "scott-test-grandchild-group3-owner", + "parentId": "139ad442-1d20-4c58-b009-c0afe21bf85b", + "path": "/scott-test-ancestor-group2/scott-test-child-group3/scott-test-grandchild-group3/scott-test-grandchild-group3-owner", + "realmRoles": [ + "owner" + ], + "subGroupCount": 0, + "subGroups": [] + } +] diff --git a/internal/keycloak/testdata/usergroups_children4.json b/internal/keycloak/testdata/usergroups_children4.json new file mode 100644 index 0000000..f212d70 --- /dev/null +++ b/internal/keycloak/testdata/usergroups_children4.json @@ -0,0 +1,50 @@ +[ + { + "access": { + "manage": true, + "manageMembers": true, + "manageMembership": true, + "view": true, + "viewMembers": true + }, + "attributes": { + "type": [ + "role-subgroup" + ] + }, + "clientRoles": {}, + "id": "d56c752d-e6d5-47c1-980d-2722b5a7c589", + "name": "project-a-fishy-website-maintainer", + "parentId": "54486df8-450d-4b62-8e10-223ac3419d05", + "path": "/project-a-fishy-website/project-a-fishy-website-maintainer", + "realmRoles": [ + "maintainer" + ], + "subGroupCount": 0, + "subGroups": [] + }, + { + "access": { + "manage": true, + "manageMembers": true, + "manageMembership": true, + "view": true, + "viewMembers": true + }, + "attributes": { + "type": [ + "role-subgroup" + ] + }, + "clientRoles": {}, + "id": "59eaaf1f-f88c-4447-aea1-2b06fec92cb0", + "name": "project-a-fishy-website-owner", + "parentId": "54486df8-450d-4b62-8e10-223ac3419d05", + "path": "/project-a-fishy-website/project-a-fishy-website-owner", + "realmRoles": [ + "owner" + ], + "subGroupCount": 0, + "subGroups": [] + } +] diff --git a/internal/keycloak/testdata/usergroups_children5.json b/internal/keycloak/testdata/usergroups_children5.json new file mode 100644 index 0000000..44475f4 --- /dev/null +++ b/internal/keycloak/testdata/usergroups_children5.json @@ -0,0 +1,74 @@ +[ + { + "access": { + "manage": true, + "manageMembers": true, + "manageMembership": true, + "view": true, + "viewMembers": true + }, + "attributes": { + "type": [ + "role-subgroup" + ] + }, + "clientRoles": {}, + "id": "0c104b4a-7573-4bb8-993c-7b8c816e40f4", + "name": "corp6-senior-devs-developer", + "parentId": "eca344cd-2b81-4447-bcf9-ce07aa9d4a1b", + "path": "/corp6-senior-devs/corp6-senior-devs-developer", + "realmRoles": [ + "developer" + ], + "subGroupCount": 0, + "subGroups": [] + }, + { + "access": { + "manage": true, + "manageMembers": true, + "manageMembership": true, + "view": true, + "viewMembers": true + }, + "attributes": { + "type": [ + "role-subgroup" + ] + }, + "clientRoles": {}, + "id": "68cd6ee1-96a0-4f33-9bb9-7583b154134b", + "name": "corp6-senior-devs-maintainer", + "parentId": "eca344cd-2b81-4447-bcf9-ce07aa9d4a1b", + "path": "/corp6-senior-devs/corp6-senior-devs-maintainer", + "realmRoles": [ + "maintainer" + ], + "subGroupCount": 0, + "subGroups": [] + }, + { + "access": { + "manage": true, + "manageMembers": true, + "manageMembership": true, + "view": true, + "viewMembers": true + }, + "attributes": { + "type": [ + "role-subgroup" + ] + }, + "clientRoles": {}, + "id": "8bd42c93-3e25-4453-b4f8-c040486a009e", + "name": "corp6-senior-devs-owner", + "parentId": "eca344cd-2b81-4447-bcf9-ce07aa9d4a1b", + "path": "/corp6-senior-devs/corp6-senior-devs-owner", + "realmRoles": [ + "owner" + ], + "subGroupCount": 0, + "subGroups": [] + } +] diff --git a/internal/keycloak/testdata/usergroups_children6.json b/internal/keycloak/testdata/usergroups_children6.json new file mode 100644 index 0000000..4dc8efd --- /dev/null +++ b/internal/keycloak/testdata/usergroups_children6.json @@ -0,0 +1,50 @@ +[ + { + "access": { + "manage": true, + "manageMembers": true, + "manageMembership": true, + "view": true, + "viewMembers": true + }, + "attributes": { + "type": [ + "role-subgroup" + ] + }, + "clientRoles": {}, + "id": "60df5791-3676-42a4-9564-9dd7b09276b2", + "name": "project-a-website-for-cats-maintainer", + "parentId": "52c2e558-d939-4d76-b241-910386d59aa7", + "path": "/project-a-website-for-cats/project-a-website-for-cats-maintainer", + "realmRoles": [ + "maintainer" + ], + "subGroupCount": 0, + "subGroups": [] + }, + { + "access": { + "manage": true, + "manageMembers": true, + "manageMembership": true, + "view": true, + "viewMembers": true + }, + "attributes": { + "type": [ + "role-subgroup" + ] + }, + "clientRoles": {}, + "id": "5b5b78e1-43dd-4062-969a-159b60a0f063", + "name": "project-a-website-for-cats-owner", + "parentId": "52c2e558-d939-4d76-b241-910386d59aa7", + "path": "/project-a-website-for-cats/project-a-website-for-cats-owner", + "realmRoles": [ + "owner" + ], + "subGroupCount": 0, + "subGroups": [] + } +] diff --git a/internal/keycloak/testdata/usergroups_children7.json b/internal/keycloak/testdata/usergroups_children7.json new file mode 100644 index 0000000..19a7307 --- /dev/null +++ b/internal/keycloak/testdata/usergroups_children7.json @@ -0,0 +1,26 @@ +[ + { + "access": { + "manage": true, + "manageMembers": true, + "manageMembership": true, + "view": true, + "viewMembers": true + }, + "attributes": { + "type": [ + "role-subgroup" + ] + }, + "clientRoles": {}, + "id": "e8574654-592b-4c09-8537-bab007a21fea", + "name": "scott-test-grandchild-group2b-owner", + "parentId": "c7d3b738-91f2-4cf1-aeec-2ab444eb3215", + "path": "/scott-test-ancestor-group2/scott-test-child-group2/scott-test-grandchild-group2b/scott-test-grandchild-group2b-owner", + "realmRoles": [ + "owner" + ], + "subGroupCount": 0, + "subGroups": [] + } +] diff --git a/internal/keycloak/testdata/usergroups_children8.json b/internal/keycloak/testdata/usergroups_children8.json new file mode 100644 index 0000000..5e6205e --- /dev/null +++ b/internal/keycloak/testdata/usergroups_children8.json @@ -0,0 +1,26 @@ +[ + { + "access": { + "manage": true, + "manageMembers": true, + "manageMembership": true, + "view": true, + "viewMembers": true + }, + "attributes": { + "type": [ + "role-subgroup" + ] + }, + "clientRoles": {}, + "id": "18c64f97-99c5-4a40-a660-0d626a4ce034", + "name": "scott-test-grandchild-group2-maintainer", + "parentId": "879d1d38-97d8-449a-affd-8529b8e31feb", + "path": "/scott-test-ancestor-group2/scott-test-child-group2/scott-test-grandchild-group2/scott-test-grandchild-group2-maintainer", + "realmRoles": [ + "maintainer" + ], + "subGroupCount": 0, + "subGroups": [] + } +] diff --git a/internal/keycloak/testdata/usergroups_groups_first0.json b/internal/keycloak/testdata/usergroups_groups_first0.json new file mode 100644 index 0000000..a2f086d --- /dev/null +++ b/internal/keycloak/testdata/usergroups_groups_first0.json @@ -0,0 +1,72 @@ +[ + { + "access": { + "manage": true, + "manageMembers": true, + "manageMembership": true, + "view": true, + "viewMembers": true + }, + "id": "3c1f5f78-3dba-44b9-94d1-27a0ca504238", + "name": "a", + "path": "/a", + "subGroupCount": 1, + "subGroups": [] + }, + { + "access": { + "manage": true, + "manageMembers": true, + "manageMembership": true, + "view": true, + "viewMembers": true + }, + "id": "945d6316-aa1c-4d2f-94b9-eccb6ef3aa26", + "name": "awebsite-for-cats-devteam", + "path": "/awebsite-for-cats-devteam", + "subGroupCount": 2, + "subGroups": [] + }, + { + "access": { + "manage": true, + "manageMembers": true, + "manageMembership": true, + "view": true, + "viewMembers": true + }, + "id": "f4d765e6-4d8e-4834-b8fc-9f89a19abcbf", + "name": "bigbus-contractors", + "path": "/bigbus-contractors", + "subGroupCount": 2, + "subGroups": [] + }, + { + "access": { + "manage": true, + "manageMembers": true, + "manageMembership": true, + "view": true, + "viewMembers": true + }, + "id": "c46856da-bd2b-49f6-a943-d4d7a61f8cfb", + "name": "corp2-bigbus-contractors", + "path": "/corp2-bigbus-contractors", + "subGroupCount": 2, + "subGroups": [] + }, + { + "access": { + "manage": true, + "manageMembers": true, + "manageMembership": true, + "view": true, + "viewMembers": true + }, + "id": "9ea08d19-0565-403b-9cde-8a3ed590dda7", + "name": "corp3-bigbus-contractors", + "path": "/corp3-bigbus-contractors", + "subGroupCount": 2, + "subGroups": [] + } +] diff --git a/internal/keycloak/testdata/usergroups_groups_first10.json b/internal/keycloak/testdata/usergroups_groups_first10.json new file mode 100644 index 0000000..96cf24c --- /dev/null +++ b/internal/keycloak/testdata/usergroups_groups_first10.json @@ -0,0 +1,72 @@ +[ + { + "access": { + "manage": true, + "manageMembers": true, + "manageMembership": true, + "view": true, + "viewMembers": true + }, + "id": "eca344cd-2b81-4447-bcf9-ce07aa9d4a1b", + "name": "corp6-senior-devs", + "path": "/corp6-senior-devs", + "subGroupCount": 3, + "subGroups": [] + }, + { + "access": { + "manage": true, + "manageMembers": true, + "manageMembership": true, + "view": true, + "viewMembers": true + }, + "id": "3c7dea60-6dec-4f2d-b8ac-f28aa9e206d9", + "name": "scott-test-ancestor-group", + "path": "/scott-test-ancestor-group", + "subGroupCount": 2, + "subGroups": [] + }, + { + "access": { + "manage": true, + "manageMembers": true, + "manageMembership": true, + "view": true, + "viewMembers": true + }, + "id": "ee6d02d1-b14b-41dd-95b6-cb8c26b1a321", + "name": "scott-test-ancestor-group2", + "path": "/scott-test-ancestor-group2", + "subGroupCount": 2, + "subGroups": [] + }, + { + "access": { + "manage": true, + "manageMembers": true, + "manageMembership": true, + "view": true, + "viewMembers": true + }, + "id": "bd9d6c6c-7f46-4cb3-93ab-1023cb379d21", + "name": "scott-test-group", + "path": "/scott-test-group", + "subGroupCount": 0, + "subGroups": [] + }, + { + "access": { + "manage": true, + "manageMembers": true, + "manageMembership": true, + "view": true, + "viewMembers": true + }, + "id": "796640a1-185c-4348-90ef-f776c9e828ed", + "name": "scott-test-group-empty", + "path": "/scott-test-group-empty", + "subGroupCount": 0, + "subGroups": [] + } +] diff --git a/internal/keycloak/testdata/usergroups_groups_first15.json b/internal/keycloak/testdata/usergroups_groups_first15.json new file mode 100644 index 0000000..eae3778 --- /dev/null +++ b/internal/keycloak/testdata/usergroups_groups_first15.json @@ -0,0 +1,72 @@ +[ + { + "access": { + "manage": true, + "manageMembers": true, + "manageMembership": true, + "view": true, + "viewMembers": true + }, + "id": "c97d32cf-2459-4ce3-8529-df2a223f6682", + "name": "scott-test-group2", + "path": "/scott-test-group2", + "subGroupCount": 0, + "subGroups": [] + }, + { + "access": { + "manage": true, + "manageMembers": true, + "manageMembership": true, + "view": true, + "viewMembers": true + }, + "id": "d3fa3b78-1fe9-45c4-b735-4c07a41905eb", + "name": "test-group442", + "path": "/test-group442", + "subGroupCount": 0, + "subGroups": [] + }, + { + "access": { + "manage": true, + "manageMembers": true, + "manageMembership": true, + "view": true, + "viewMembers": true + }, + "id": "54486df8-450d-4b62-8e10-223ac3419d05", + "name": "project-a-fishy-website", + "path": "/project-a-fishy-website", + "subGroupCount": 2, + "subGroups": [] + }, + { + "access": { + "manage": true, + "manageMembers": true, + "manageMembership": true, + "view": true, + "viewMembers": true + }, + "id": "4dabd962-a772-4757-9de7-7245cc238086", + "name": "project-a-website-for-birds", + "path": "/project-a-website-for-birds", + "subGroupCount": 2, + "subGroups": [] + }, + { + "access": { + "manage": true, + "manageMembers": true, + "manageMembership": true, + "view": true, + "viewMembers": true + }, + "id": "52c2e558-d939-4d76-b241-910386d59aa7", + "name": "project-a-website-for-cats", + "path": "/project-a-website-for-cats", + "subGroupCount": 2, + "subGroups": [] + } +] diff --git a/internal/keycloak/testdata/usergroups_groups_first20.json b/internal/keycloak/testdata/usergroups_groups_first20.json new file mode 100644 index 0000000..9fd3600 --- /dev/null +++ b/internal/keycloak/testdata/usergroups_groups_first20.json @@ -0,0 +1,44 @@ +[ + { + "access": { + "manage": true, + "manageMembers": true, + "manageMembership": true, + "view": true, + "viewMembers": true + }, + "id": "5005c22e-48c3-46cd-bf4a-393f6e13e9a8", + "name": "project-a-website-for-dogs", + "path": "/project-a-website-for-dogs", + "subGroupCount": 2, + "subGroups": [] + }, + { + "access": { + "manage": true, + "manageMembers": true, + "manageMembership": true, + "view": true, + "viewMembers": true + }, + "id": "0472e029-e829-41ea-ac01-94891fd2332b", + "name": "project-a-website-for-ducks", + "path": "/project-a-website-for-ducks", + "subGroupCount": 2, + "subGroups": [] + }, + { + "access": { + "manage": true, + "manageMembers": true, + "manageMembership": true, + "view": true, + "viewMembers": true + }, + "id": "1ad2cd0c-5046-434f-9580-7b036a08222b", + "name": "project-a-website-for-fish", + "path": "/project-a-website-for-fish", + "subGroupCount": 2, + "subGroups": [] + } +] diff --git a/internal/keycloak/testdata/usergroups_groups_first5.json b/internal/keycloak/testdata/usergroups_groups_first5.json new file mode 100644 index 0000000..c018d22 --- /dev/null +++ b/internal/keycloak/testdata/usergroups_groups_first5.json @@ -0,0 +1,72 @@ +[ + { + "access": { + "manage": true, + "manageMembers": true, + "manageMembership": true, + "view": true, + "viewMembers": true + }, + "id": "fe0fd424-a0fe-4796-9d4b-0c4b5a0b0f08", + "name": "corp4-bigbus-contractors", + "path": "/corp4-bigbus-contractors", + "subGroupCount": 2, + "subGroups": [] + }, + { + "access": { + "manage": true, + "manageMembers": true, + "manageMembership": true, + "view": true, + "viewMembers": true + }, + "id": "754963d5-5154-410d-a0f4-ed5c029620a1", + "name": "corp5-bigbus-contractors", + "path": "/corp5-bigbus-contractors", + "subGroupCount": 2, + "subGroups": [] + }, + { + "access": { + "manage": true, + "manageMembers": true, + "manageMembership": true, + "view": true, + "viewMembers": true + }, + "id": "7ffd7b50-fb33-487e-8331-d60925213f3d", + "name": "corp6-bigbus-contracts", + "path": "/corp6-bigbus-contracts", + "subGroupCount": 1, + "subGroups": [] + }, + { + "access": { + "manage": true, + "manageMembers": true, + "manageMembership": true, + "view": true, + "viewMembers": true + }, + "id": "2b876213-78d8-4aff-8a92-ef3dacc8fc32", + "name": "corp6-devs-birds", + "path": "/corp6-devs-birds", + "subGroupCount": 2, + "subGroups": [] + }, + { + "access": { + "manage": true, + "manageMembers": true, + "manageMembership": true, + "view": true, + "viewMembers": true + }, + "id": "042a0523-5175-4b38-9fc9-55950afe5787", + "name": "corp6-devs-fish", + "path": "/corp6-devs-fish", + "subGroupCount": 1, + "subGroups": [] + } +] diff --git a/internal/keycloak/usergroups_test.go b/internal/keycloak/usergroups_test.go new file mode 100644 index 0000000..646541b --- /dev/null +++ b/internal/keycloak/usergroups_test.go @@ -0,0 +1,199 @@ +package keycloak_test + +import ( + "bytes" + "context" + "fmt" + "io" + "log/slog" + "net/http" + "net/http/httptest" + "os" + "testing" + + "github.com/alecthomas/assert/v2" + "github.com/google/uuid" + "github.com/uselagoon/ssh-portal/internal/keycloak" + "github.com/uselagoon/ssh-portal/internal/lagoon" +) + +// newTestUGIDRoleServer sets up a mock keycloak which responds with +// appropriate group JSON data to exercise UserGroupIDRole. +func newTestUGIDRoleServer(tt *testing.T) *httptest.Server { + // set up the map of group requests to responses + var reqRespMap map[string]string = map[string]string{ + "ee6d02d1-b14b-41dd-95b6-cb8c26b1a321/children": "testdata/usergroups_children0.json", + "7f22ce84-c0af-4ff4-afcd-288f0473deb5/children": "testdata/usergroups_children1.json", + "2e833d9b-39b7-4f25-b37f-cfb8765015ab/children": "testdata/usergroups_children2.json", + "139ad442-1d20-4c58-b009-c0afe21bf85b/children": "testdata/usergroups_children3.json", + "54486df8-450d-4b62-8e10-223ac3419d05/children": "testdata/usergroups_children4.json", + "eca344cd-2b81-4447-bcf9-ce07aa9d4a1b/children": "testdata/usergroups_children5.json", + "52c2e558-d939-4d76-b241-910386d59aa7/children": "testdata/usergroups_children6.json", + "c7d3b738-91f2-4cf1-aeec-2ab444eb3215/children": "testdata/usergroups_children7.json", + "879d1d38-97d8-449a-affd-8529b8e31feb/children": "testdata/usergroups_children8.json", + } + // load the discovery JSON first, because the mux closure needs to + // reference its buffer + discoveryBuf, err := os.ReadFile("testdata/realm.oidc.discovery.json") + if err != nil { + tt.Fatal(err) + return nil + } + // configure router with the URLs that OIDC discovery and JWKS require + mux := http.NewServeMux() + mux.HandleFunc("/auth/realms/lagoon/.well-known/openid-configuration", + func(w http.ResponseWriter, r *http.Request) { + d := bytes.NewBuffer(discoveryBuf) + _, err = io.Copy(w, d) + if err != nil { + tt.Fatal(err) + } + }) + mux.HandleFunc("/auth/realms/lagoon/protocol/openid-connect/certs", + func(w http.ResponseWriter, r *http.Request) { + f, err := os.Open("testdata/realm.oidc.certs.json") + if err != nil { + tt.Fatal(err) + return + } + _, err = io.Copy(w, f) + if err != nil { + tt.Fatal(err) + } + }) + // configure the group paths + for groupID, file := range reqRespMap { + mux.HandleFunc("/auth/admin/realms/lagoon/groups/"+groupID, + func(w http.ResponseWriter, r *http.Request) { + responseData, err := os.Open(file) + if err != nil { + tt.Fatal(err) + return + } + _, err = io.Copy(w, responseData) + if err != nil { + tt.Fatal(err) + } + }) + } + // configure the "all groups" paths + mux.HandleFunc("/auth/admin/realms/lagoon/groups", + func(w http.ResponseWriter, r *http.Request) { + paramFirst := r.URL.Query().Get("first") + paramMax := r.URL.Query().Get("max") + assert.Equal(tt, "5", paramMax) + dataPath := + fmt.Sprintf("testdata/usergroups_groups_first%s.json", paramFirst) + f, err := os.Open(dataPath) + if err != nil { + tt.Fatal(err) + return + } + _, err = io.Copy(w, f) + if err != nil { + tt.Fatal(err) + } + }) + ts := httptest.NewServer(mux) + // now replace the example URL in the discovery JSON with the actual + // httptest server URL + discoveryBuf = bytes.ReplaceAll(discoveryBuf, + []byte("https://keycloak.example.com"), []byte(ts.URL)) + return ts +} + +func TestUserGroupIDRole(t *testing.T) { + var testCases = map[string]struct { + userGroupPaths []string + expect map[uuid.UUID]lagoon.UserRole + }{ + "single project owner": { + userGroupPaths: []string{ + "/project-a-fishy-website/project-a-fishy-website-owner", + }, + expect: map[uuid.UUID]lagoon.UserRole{ + uuid.MustParse("54486df8-450d-4b62-8e10-223ac3419d05"): lagoon.Owner, + }, + }, + "multi project member": { + userGroupPaths: []string{ + "/project-a-fishy-website/project-a-fishy-website-owner", + "/project-a-website-for-cats/project-a-website-for-cats-maintainer", + }, + expect: map[uuid.UUID]lagoon.UserRole{ + uuid.MustParse("54486df8-450d-4b62-8e10-223ac3419d05"): lagoon.Owner, + uuid.MustParse("52c2e558-d939-4d76-b241-910386d59aa7"): lagoon.Maintainer, + }, + }, + "regular group maintainer": { + userGroupPaths: []string{ + "/corp6-senior-devs/corp6-senior-devs-maintainer", + }, + expect: map[uuid.UUID]lagoon.UserRole{ + uuid.MustParse("eca344cd-2b81-4447-bcf9-ce07aa9d4a1b"): lagoon.Maintainer, + }, + }, + "child subgroup developer": { + userGroupPaths: []string{ + "/scott-test-ancestor-group2/scott-test-child-group2/scott-test-child-group2-developer", + }, + expect: map[uuid.UUID]lagoon.UserRole{ + uuid.MustParse("2e833d9b-39b7-4f25-b37f-cfb8765015ab"): lagoon.Developer, + }, + }, + "grandchild subgroup owner": { + userGroupPaths: []string{ + "/scott-test-ancestor-group2/scott-test-child-group3/scott-test-grandchild-group3/scott-test-grandchild-group3-owner", + }, + expect: map[uuid.UUID]lagoon.UserRole{ + uuid.MustParse("139ad442-1d20-4c58-b009-c0afe21bf85b"): lagoon.Owner, + }, + }, + "multiple grandchild subgroups exercise cache": { + userGroupPaths: []string{ + "/scott-test-ancestor-group2/scott-test-child-group2/scott-test-grandchild-group2/scott-test-grandchild-group2-maintainer", + "/scott-test-ancestor-group2/scott-test-child-group2/scott-test-grandchild-group2b/scott-test-grandchild-group2b-owner", + }, + expect: map[uuid.UUID]lagoon.UserRole{ + uuid.MustParse("879d1d38-97d8-449a-affd-8529b8e31feb"): lagoon.Maintainer, + uuid.MustParse("c7d3b738-91f2-4cf1-aeec-2ab444eb3215"): lagoon.Owner, + }, + }, + "project, regular, and subgroups": { + userGroupPaths: []string{ + "/project-a-fishy-website/project-a-fishy-website-owner", + "/corp6-senior-devs/corp6-senior-devs-maintainer", + "/scott-test-ancestor-group2/scott-test-child-group2/scott-test-child-group2-developer", + }, + expect: map[uuid.UUID]lagoon.UserRole{ + uuid.MustParse("54486df8-450d-4b62-8e10-223ac3419d05"): lagoon.Owner, + uuid.MustParse("eca344cd-2b81-4447-bcf9-ce07aa9d4a1b"): lagoon.Maintainer, + uuid.MustParse("2e833d9b-39b7-4f25-b37f-cfb8765015ab"): lagoon.Developer, + }, + }, + } + for name, tc := range testCases { + t.Run(name, func(tt *testing.T) { + ts := newTestUGIDRoleServer(tt) + defer ts.Close() + // init keycloak client + k, err := keycloak.NewClient( + context.Background(), + slog.New(slog.NewJSONHandler(os.Stderr, nil)), + ts.URL, + "auth-server", + "", + 10) + if err != nil { + tt.Fatal(err) + } + // override internal HTTP client for testing + k.UseDefaultHTTPClient() + // override default huge pages + k.UsePageSize(5) + // perform testing + gidRoleMap := k.UserGroupIDRole(context.Background(), tc.userGroupPaths) + assert.Equal(tt, tc.expect, gidRoleMap, name) + }) + } +}