From 0b05b13b6bde5209c359b18e9b579bbdd43dafa6 Mon Sep 17 00:00:00 2001 From: Martin Kanis Date: Tue, 21 Jul 2026 10:57:26 +0200 Subject: [PATCH] [CVE-2026-16072] Organization managers can create managed members through stored registration links without manage-users Closes #50998 Signed-off-by: Martin Kanis (cherry picked from commit 60967c8cbe6cd5d8a852deb9dbb5ae8428adf82d) --- .../idm/OrganizationInvitationRepresentation.java | 9 +++++++++ .../upgrading/topics/changes/changes-26_7_2.adoc | 14 ++++++++++++++ .../upgrading/topics/changes/changes.adoc | 4 ++++ .../admin/messages/messages_ca.properties | 2 -- .../admin/messages/messages_cs.properties | 2 -- .../admin/messages/messages_es.properties | 2 -- .../admin/messages/messages_fr.properties | 2 -- .../admin/messages/messages_id.properties | 2 -- .../admin/messages/messages_ru.properties | 2 -- .../admin/messages/messages_sv.properties | 2 -- .../admin/messages/messages_tr.properties | 2 -- .../admin/messages/messages_uk.properties | 2 -- .../admin/messages/messages_vi.properties | 2 -- .../admin/messages/messages_zh_Hans.properties | 2 -- .../admin/messages/messages_zh_Hant.properties | 2 -- .../admin/messages/messages_en.properties | 2 -- js/apps/admin-ui/src/organizations/Invitations.tsx | 14 -------------- .../defs/organizationInvitationRepresentation.ts | 1 + .../resource/OrganizationInvitationResource.java | 2 -- .../OrganizationInvitationManagementTest.java | 13 +++++++++++++ 20 files changed, 41 insertions(+), 42 deletions(-) create mode 100644 docs/documentation/upgrading/topics/changes/changes-26_7_2.adoc diff --git a/core/src/main/java/org/keycloak/representations/idm/OrganizationInvitationRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/OrganizationInvitationRepresentation.java index 481d54185fe1..21c2fcca9c16 100644 --- a/core/src/main/java/org/keycloak/representations/idm/OrganizationInvitationRepresentation.java +++ b/core/src/main/java/org/keycloak/representations/idm/OrganizationInvitationRepresentation.java @@ -18,6 +18,7 @@ public enum Status { private int sentDate; private int expiresAt; private Status status; + @Deprecated private String inviteLink; public OrganizationInvitationRepresentation() { @@ -87,10 +88,18 @@ public void setStatus(Status status) { this.status = status; } + /** + * @deprecated The invite link is no longer exposed in API responses. + */ + @Deprecated public String getInviteLink() { return inviteLink; } + /** + * @deprecated The invite link is no longer exposed in API responses. + */ + @Deprecated public void setInviteLink(String inviteLink) { this.inviteLink = inviteLink; } diff --git a/docs/documentation/upgrading/topics/changes/changes-26_7_2.adoc b/docs/documentation/upgrading/topics/changes/changes-26_7_2.adoc new file mode 100644 index 000000000000..1e644315d19e --- /dev/null +++ b/docs/documentation/upgrading/topics/changes/changes-26_7_2.adoc @@ -0,0 +1,14 @@ +// ------------------------ Deprecated features ------------------------ // +== Deprecated features + +The following sections provide details on deprecated features. + +=== Organization invitation link no longer exposed in API responses + +The `inviteLink` field in `OrganizationInvitationRepresentation` is deprecated and is no longer returned in Admin REST API responses from the organization invitation endpoints. + +Previously, the invitation link containing the signed registration token was stored and returned in the representation. The invitation link is still sent via email to the intended recipient. + +The `getInviteLink()` and `setInviteLink()` methods on `OrganizationInvitationRepresentation` are deprecated and will be removed in a future major version. If your code reads `inviteLink` from invitation API responses, it will now receive `null`. + +The "Copy invite link" action has also been removed from the admin console invitations management UI. \ No newline at end of file diff --git a/docs/documentation/upgrading/topics/changes/changes.adoc b/docs/documentation/upgrading/topics/changes/changes.adoc index cd63f5376d9b..063356a596c8 100644 --- a/docs/documentation/upgrading/topics/changes/changes.adoc +++ b/docs/documentation/upgrading/topics/changes/changes.adoc @@ -1,6 +1,10 @@ [[migration-changes]] == Migration Changes +=== Migrating to 26.7.2 + +include::changes-26_7_2.adoc[leveloffset=2] + === Migrating to 26.7.1 include::changes-26_7_1.adoc[leveloffset=2] diff --git a/js/apps/admin-ui/maven-resources-community/theme/keycloak.v2/admin/messages/messages_ca.properties b/js/apps/admin-ui/maven-resources-community/theme/keycloak.v2/admin/messages/messages_ca.properties index b2ad56e926dd..0f9f1f9d0e62 100644 --- a/js/apps/admin-ui/maven-resources-community/theme/keycloak.v2/admin/messages/messages_ca.properties +++ b/js/apps/admin-ui/maven-resources-community/theme/keycloak.v2/admin/messages/messages_ca.properties @@ -2218,8 +2218,6 @@ filterByStatus=Filtra per estat sentDate=Data d’enviament expiresAt=Caduca el resendInvitation=Torna a enviar la invitació -copyInviteLink=Copia l’enllaç d’invitació -inviteLinkCopied=L’enllaç d’invitació s’ha copiat al porta-retalls deleteInvitation=Suprimeix la invitació deleteInvitations=Suprimeix les invitacions organizationInvitationsDeleteConfirmTitle=Suprimiu les invitacions? diff --git a/js/apps/admin-ui/maven-resources-community/theme/keycloak.v2/admin/messages/messages_cs.properties b/js/apps/admin-ui/maven-resources-community/theme/keycloak.v2/admin/messages/messages_cs.properties index 3e6a6e7f4ad6..45a339752884 100644 --- a/js/apps/admin-ui/maven-resources-community/theme/keycloak.v2/admin/messages/messages_cs.properties +++ b/js/apps/admin-ui/maven-resources-community/theme/keycloak.v2/admin/messages/messages_cs.properties @@ -2107,8 +2107,6 @@ filterByStatus=Filtrujte podle stavu sentDate=Datum odeslání expiresAt=Platnost vyprší v resendInvitation=Znovu odeslat pozvánku -copyInviteLink=Zkopírovat odkaz na pozvánku -inviteLinkCopied=Odkaz na pozvánku zkopírován do schránky deleteInvitation=Smazat pozvánku deleteInvitations=Smazat pozvánky organizationInvitationsDeleteConfirmTitle=Smazat pozvánky? diff --git a/js/apps/admin-ui/maven-resources-community/theme/keycloak.v2/admin/messages/messages_es.properties b/js/apps/admin-ui/maven-resources-community/theme/keycloak.v2/admin/messages/messages_es.properties index 36ca231a35a4..7a22fcf36242 100644 --- a/js/apps/admin-ui/maven-resources-community/theme/keycloak.v2/admin/messages/messages_es.properties +++ b/js/apps/admin-ui/maven-resources-community/theme/keycloak.v2/admin/messages/messages_es.properties @@ -3530,8 +3530,6 @@ filterByStatus=Filtro por Estatus sentDate=Enviar fecha expiresAt=Expira en resendInvitation=Reenvio de invitación -copyInviteLink=Copiar el enlace de invitado -inviteLinkCopied=Enlace de invitación copiado al portapapeles deleteInvitation=Borrar invitación deleteInvitations=Borrar invitaciones organizationInvitationsDeleteConfirmTitle=Quiere borrar las invitaciones? diff --git a/js/apps/admin-ui/maven-resources-community/theme/keycloak.v2/admin/messages/messages_fr.properties b/js/apps/admin-ui/maven-resources-community/theme/keycloak.v2/admin/messages/messages_fr.properties index 1e0b877b7e61..90a6e7c02ec6 100644 --- a/js/apps/admin-ui/maven-resources-community/theme/keycloak.v2/admin/messages/messages_fr.properties +++ b/js/apps/admin-ui/maven-resources-community/theme/keycloak.v2/admin/messages/messages_fr.properties @@ -3581,8 +3581,6 @@ filterByStatus=Filtrer par statut sentDate=Date d'envoi expiresAt=Expire le resendInvitation=Renvoyer l'invitation -copyInviteLink=Copier le lien d'invitation -inviteLinkCopied=Lien d'invitation copié dans le presse-papier deleteInvitation=Supprimer l'invitation deleteInvitations=Supprimer les invitations organizationInvitationsDeleteConfirmTitle=Supprimer les invitations ? diff --git a/js/apps/admin-ui/maven-resources-community/theme/keycloak.v2/admin/messages/messages_id.properties b/js/apps/admin-ui/maven-resources-community/theme/keycloak.v2/admin/messages/messages_id.properties index 034bc2d9f4f3..f0f1e2cce035 100644 --- a/js/apps/admin-ui/maven-resources-community/theme/keycloak.v2/admin/messages/messages_id.properties +++ b/js/apps/admin-ui/maven-resources-community/theme/keycloak.v2/admin/messages/messages_id.properties @@ -2111,8 +2111,6 @@ filterByStatus=Filter berdasarkan status sentDate=Tanggal terkirim expiresAt=Kedaluwarsa pada resendInvitation=Kirim ulang undangan -copyInviteLink=Salin tautan undangan -inviteLinkCopied=Tautan undangan disalin ke clipboard deleteInvitation=Hapus undangan deleteInvitations=Hapus undangan organizationInvitationsDeleteConfirmTitle=Hapus undangan? diff --git a/js/apps/admin-ui/maven-resources-community/theme/keycloak.v2/admin/messages/messages_ru.properties b/js/apps/admin-ui/maven-resources-community/theme/keycloak.v2/admin/messages/messages_ru.properties index 9867124ef950..fbcf032dd13f 100644 --- a/js/apps/admin-ui/maven-resources-community/theme/keycloak.v2/admin/messages/messages_ru.properties +++ b/js/apps/admin-ui/maven-resources-community/theme/keycloak.v2/admin/messages/messages_ru.properties @@ -3574,8 +3574,6 @@ filterByStatus=Фильтр по статусу sentDate=Дата отправки expiresAt=Истекает resendInvitation=Отправить приглашение повторно -copyInviteLink=Копировать ссылку приглашения -inviteLinkCopied=Ссылка приглашения скопирована в буфер обмена deleteInvitation=Удалить приглашение deleteInvitations=Удалить приглашения organizationInvitationsDeleteConfirmTitle=Удалить приглашения? diff --git a/js/apps/admin-ui/maven-resources-community/theme/keycloak.v2/admin/messages/messages_sv.properties b/js/apps/admin-ui/maven-resources-community/theme/keycloak.v2/admin/messages/messages_sv.properties index 675c91aa9485..7a2ec0f4cc2d 100644 --- a/js/apps/admin-ui/maven-resources-community/theme/keycloak.v2/admin/messages/messages_sv.properties +++ b/js/apps/admin-ui/maven-resources-community/theme/keycloak.v2/admin/messages/messages_sv.properties @@ -2120,8 +2120,6 @@ filterByStatus=Filtrera efter status sentDate=Skickat datum expiresAt=Upphör att gälla vid resendInvitation=Skicka inbjudan på nytt -copyInviteLink=Kopiera inbjudningslänken -inviteLinkCopied=Länk till inbjudan kopierad till urklipp deleteInvitation=Ta bort inbjudan deleteInvitations=Ta bort inbjudningar organizationInvitationsDeleteConfirmTitle=Ta bort inbjudningar? diff --git a/js/apps/admin-ui/maven-resources-community/theme/keycloak.v2/admin/messages/messages_tr.properties b/js/apps/admin-ui/maven-resources-community/theme/keycloak.v2/admin/messages/messages_tr.properties index e5e6c6d31b7d..fb20c44a456a 100644 --- a/js/apps/admin-ui/maven-resources-community/theme/keycloak.v2/admin/messages/messages_tr.properties +++ b/js/apps/admin-ui/maven-resources-community/theme/keycloak.v2/admin/messages/messages_tr.properties @@ -3597,8 +3597,6 @@ filterByStatus=Duruma göre filtrele sentDate=Gönderim tarihi expiresAt=Bitiş tarihi resendInvitation=Davetiye yeniden gönder -copyInviteLink=Davet bağlantısını kopyala -inviteLinkCopied=Davet bağlantısı panoya kopyalandı deleteInvitation=Davetiye sil deleteInvitations=Davetiyeleri sil organizationInvitationsDeleteConfirmTitle=Davetiyeler silinsin mi? diff --git a/js/apps/admin-ui/maven-resources-community/theme/keycloak.v2/admin/messages/messages_uk.properties b/js/apps/admin-ui/maven-resources-community/theme/keycloak.v2/admin/messages/messages_uk.properties index 4561e937fd16..eb5cc44db2b1 100644 --- a/js/apps/admin-ui/maven-resources-community/theme/keycloak.v2/admin/messages/messages_uk.properties +++ b/js/apps/admin-ui/maven-resources-community/theme/keycloak.v2/admin/messages/messages_uk.properties @@ -2108,8 +2108,6 @@ filterByStatus=Фільтрувати за статусом sentDate=Дата надсилання expiresAt=Закінчується resendInvitation=Надіслати запрошення повторно -copyInviteLink=Копіювати посилання-запрошення -inviteLinkCopied=Посилання-запрошення скопійовано до буфера обміну deleteInvitation=Видалити запрошення deleteInvitations=Видалити запрошення organizationInvitationsDeleteConfirmTitle=Видалити запрошення? diff --git a/js/apps/admin-ui/maven-resources-community/theme/keycloak.v2/admin/messages/messages_vi.properties b/js/apps/admin-ui/maven-resources-community/theme/keycloak.v2/admin/messages/messages_vi.properties index 34e09ae4ed71..ab3e13a95073 100644 --- a/js/apps/admin-ui/maven-resources-community/theme/keycloak.v2/admin/messages/messages_vi.properties +++ b/js/apps/admin-ui/maven-resources-community/theme/keycloak.v2/admin/messages/messages_vi.properties @@ -2107,8 +2107,6 @@ filterByStatus=Lọc theo trạng thái sentDate=Ngày gửi expiresAt=Hết hạn vào resendInvitation=Gửi lại lời mời -copyInviteLink=Sao chép liên kết mời -inviteLinkCopied=Đã sao chép liên kết mời vào clipboard deleteInvitation=Xóa lời mời deleteInvitations=Xóa lời mời organizationInvitationsDeleteConfirmTitle=Xóa lời mời? diff --git a/js/apps/admin-ui/maven-resources-community/theme/keycloak.v2/admin/messages/messages_zh_Hans.properties b/js/apps/admin-ui/maven-resources-community/theme/keycloak.v2/admin/messages/messages_zh_Hans.properties index bb97f5499752..899be8beffd7 100644 --- a/js/apps/admin-ui/maven-resources-community/theme/keycloak.v2/admin/messages/messages_zh_Hans.properties +++ b/js/apps/admin-ui/maven-resources-community/theme/keycloak.v2/admin/messages/messages_zh_Hans.properties @@ -3478,8 +3478,6 @@ filterByStatus=使用状态过滤 sentDate=发送日期 expiresAt=过期时间 resendInvitation=重新发送邀请 -copyInviteLink=复制邀请链接 -inviteLinkCopied=邀请链接已复制至剪贴板 deleteInvitation=删除邀请 deleteInvitations=删除邀请 organizationInvitationsDeleteConfirmTitle=删除邀请? diff --git a/js/apps/admin-ui/maven-resources-community/theme/keycloak.v2/admin/messages/messages_zh_Hant.properties b/js/apps/admin-ui/maven-resources-community/theme/keycloak.v2/admin/messages/messages_zh_Hant.properties index 89897abde790..110e0cc544b0 100644 --- a/js/apps/admin-ui/maven-resources-community/theme/keycloak.v2/admin/messages/messages_zh_Hant.properties +++ b/js/apps/admin-ui/maven-resources-community/theme/keycloak.v2/admin/messages/messages_zh_Hant.properties @@ -3596,8 +3596,6 @@ filterByStatus=使用狀態過濾 sentDate=送出日期 expiresAt=過期於 resendInvitation=重新傳送邀請 -copyInviteLink=複製邀請連結 -inviteLinkCopied=已複製邀請連結到剪貼簿 deleteInvitation=刪除邀請 deleteInvitations=刪除邀請 organizationInvitationsDeleteConfirmTitle=刪除邀請? diff --git a/js/apps/admin-ui/maven-resources/theme/keycloak.v2/admin/messages/messages_en.properties b/js/apps/admin-ui/maven-resources/theme/keycloak.v2/admin/messages/messages_en.properties index df6e879eb420..897822092b03 100644 --- a/js/apps/admin-ui/maven-resources/theme/keycloak.v2/admin/messages/messages_en.properties +++ b/js/apps/admin-ui/maven-resources/theme/keycloak.v2/admin/messages/messages_en.properties @@ -2132,8 +2132,6 @@ filterByStatus=Filter by status sentDate=Sent date expiresAt=Expires at resendInvitation=Resend invitation -copyInviteLink=Copy invite link -inviteLinkCopied=Invite link copied to clipboard deleteInvitation=Delete invitation deleteInvitations=Delete invitations organizationInvitationsDeleteConfirmTitle=Delete invitations? diff --git a/js/apps/admin-ui/src/organizations/Invitations.tsx b/js/apps/admin-ui/src/organizations/Invitations.tsx index 96f5b33c91d4..8c87b45305c9 100644 --- a/js/apps/admin-ui/src/organizations/Invitations.tsx +++ b/js/apps/admin-ui/src/organizations/Invitations.tsx @@ -307,20 +307,6 @@ export const Invitations = () => { }, ]; - if (invitation.inviteLink) { - actions.splice(1, 0, { - title: t("copyInviteLink"), - onClick: async () => { - try { - await navigator.clipboard.writeText(invitation.inviteLink!); - addAlert(t("inviteLinkCopied")); - } catch (error) { - addError("clipboardCopyError", error); - } - }, - }); - } - return actions; }} columns={[ diff --git a/js/libs/keycloak-admin-client/src/defs/organizationInvitationRepresentation.ts b/js/libs/keycloak-admin-client/src/defs/organizationInvitationRepresentation.ts index b034030f4b40..de299f4f4080 100644 --- a/js/libs/keycloak-admin-client/src/defs/organizationInvitationRepresentation.ts +++ b/js/libs/keycloak-admin-client/src/defs/organizationInvitationRepresentation.ts @@ -12,5 +12,6 @@ export default interface OrganizationInvitationRepresentation { sentDate?: number; expiresAt?: number; status?: OrganizationInvitationStatus; + /** @deprecated The invite link is no longer exposed in API responses. */ inviteLink?: string; } diff --git a/services/src/main/java/org/keycloak/organization/admin/resource/OrganizationInvitationResource.java b/services/src/main/java/org/keycloak/organization/admin/resource/OrganizationInvitationResource.java index 5766beac5bb3..062f5cb292fe 100644 --- a/services/src/main/java/org/keycloak/organization/admin/resource/OrganizationInvitationResource.java +++ b/services/src/main/java/org/keycloak/organization/admin/resource/OrganizationInvitationResource.java @@ -384,8 +384,6 @@ private OrganizationInvitationRepresentation toRepresentation(OrganizationInvita rep.setOrganizationId(model.getOrganizationId()); rep.setSentDate(model.getCreatedAt()); rep.setExpiresAt(model.getExpiresAt()); - rep.setInviteLink(model.getInviteLink()); - OrganizationInvitationRepresentation.Status dynamicStatus = model.isExpired() ? EXPIRED : PENDING; diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/organization/admin/OrganizationInvitationManagementTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/organization/admin/OrganizationInvitationManagementTest.java index 33e3d3789097..2f14bc50a7ee 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/organization/admin/OrganizationInvitationManagementTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/organization/admin/OrganizationInvitationManagementTest.java @@ -131,6 +131,19 @@ public void testGetInvitationById() { assertThat(invitation.getStatus(), equalTo(PENDING)); } + @Test + public void testInviteLinkNotExposedInApiResponse() { + sendInvitation("sectest@test-org.com", "Sec", "Test"); + + List invitations = organization.invitations().list(); + assertThat(invitations, hasSize(1)); + assertThat(invitations.get(0).getInviteLink(), is(nullValue())); + + String invitationId = invitations.get(0).getId(); + OrganizationInvitationRepresentation invitation = organization.invitations().get(invitationId); + assertThat(invitation.getInviteLink(), is(nullValue())); + } + @Test public void testGetNonExistentInvitation() { // Try to get non-existent invitation - should throw an exception or return null