diff --git a/messages/bg-BG.json b/messages/bg-BG.json index 0b8a3cc6a..a26cfc443 100644 --- a/messages/bg-BG.json +++ b/messages/bg-BG.json @@ -1462,6 +1462,7 @@ "actionGenerateAccessToken": "Генериране на токен за достъп", "actionDeleteAccessToken": "Изтриване на токен за достъп", "actionListAccessTokens": "Изброяване на токени за достъп", + "actionCreateResourceSessionToken": "Създаване на токен за сесия на ресурс", "actionCreateResourceRule": "Създаване на правило за ресурс", "actionDeleteResourceRule": "Изтрийте правило за ресурс", "actionListResourceRules": "Изброяване на правила за ресурс", diff --git a/messages/cs-CZ.json b/messages/cs-CZ.json index 31586b8d3..d821c0642 100644 --- a/messages/cs-CZ.json +++ b/messages/cs-CZ.json @@ -1462,6 +1462,7 @@ "actionGenerateAccessToken": "Generovat přístupový token", "actionDeleteAccessToken": "Odstranit přístupový token", "actionListAccessTokens": "Seznam přístupových tokenů", + "actionCreateResourceSessionToken": "Vytvořit token relace prostředku", "actionCreateResourceRule": "Vytvořit pravidlo pro zdroj", "actionDeleteResourceRule": "Odstranit pravidlo pro dokument", "actionListResourceRules": "Seznam pravidel zdrojů", diff --git a/messages/da-DK.json b/messages/da-DK.json index f6e0462ed..ba6ca1a88 100644 --- a/messages/da-DK.json +++ b/messages/da-DK.json @@ -1462,6 +1462,7 @@ "actionGenerateAccessToken": "Generer adgangstoken", "actionDeleteAccessToken": "Slet adgangstoken", "actionListAccessTokens": "Vis adgangstokens", + "actionCreateResourceSessionToken": "Opret ressourcesessionstoken", "actionCreateResourceRule": "Opret ressourceregel", "actionDeleteResourceRule": "Slet ressourceregel", "actionListResourceRules": "Vis ressourceregler", diff --git a/messages/de-DE.json b/messages/de-DE.json index 16edb164a..b1776525e 100644 --- a/messages/de-DE.json +++ b/messages/de-DE.json @@ -1462,6 +1462,7 @@ "actionGenerateAccessToken": "Zugriffstoken generieren", "actionDeleteAccessToken": "Zugriffstoken löschen", "actionListAccessTokens": "Zugriffstoken auflisten", + "actionCreateResourceSessionToken": "Ressourcensitzungstoken erstellen", "actionCreateResourceRule": "Ressourcenregel erstellen", "actionDeleteResourceRule": "Ressourcenregel löschen", "actionListResourceRules": "Ressourcenregeln auflisten", diff --git a/messages/en-US.json b/messages/en-US.json index 24735be61..3b07d1ab9 100644 --- a/messages/en-US.json +++ b/messages/en-US.json @@ -1462,6 +1462,7 @@ "actionGenerateAccessToken": "Generate Access Token", "actionDeleteAccessToken": "Delete Access Token", "actionListAccessTokens": "List Access Tokens", + "actionCreateResourceSessionToken": "Create Resource Session Token", "actionCreateResourceRule": "Create Resource Rule", "actionDeleteResourceRule": "Delete Resource Rule", "actionListResourceRules": "List Resource Rules", diff --git a/messages/es-ES.json b/messages/es-ES.json index 7edeb5990..6045d43e9 100644 --- a/messages/es-ES.json +++ b/messages/es-ES.json @@ -1462,6 +1462,7 @@ "actionGenerateAccessToken": "Generar token de acceso", "actionDeleteAccessToken": "Eliminar token de acceso", "actionListAccessTokens": "Lista de Tokens de Acceso", + "actionCreateResourceSessionToken": "Crear token de sesión de recurso", "actionCreateResourceRule": "Crear Regla de Recursos", "actionDeleteResourceRule": "Eliminar Regla de Recurso", "actionListResourceRules": "Lista de Reglas de Recursos", diff --git a/messages/fr-FR.json b/messages/fr-FR.json index d204a2370..cc90cc919 100644 --- a/messages/fr-FR.json +++ b/messages/fr-FR.json @@ -1462,6 +1462,7 @@ "actionGenerateAccessToken": "Générer un jeton d'accès", "actionDeleteAccessToken": "Supprimer un jeton d'accès", "actionListAccessTokens": "Lister les jetons d'accès", + "actionCreateResourceSessionToken": "Créer un jeton de session de ressource", "actionCreateResourceRule": "Créer une règle de ressource", "actionDeleteResourceRule": "Supprimer une règle de ressource", "actionListResourceRules": "Lister les règles de ressource", diff --git a/messages/it-IT.json b/messages/it-IT.json index 156ea239e..eb263b0d1 100644 --- a/messages/it-IT.json +++ b/messages/it-IT.json @@ -1462,6 +1462,7 @@ "actionGenerateAccessToken": "Genera Token di Accesso", "actionDeleteAccessToken": "Elimina Token di Accesso", "actionListAccessTokens": "Elenca Token di Accesso", + "actionCreateResourceSessionToken": "Crea token di sessione risorsa", "actionCreateResourceRule": "Crea Regola Risorsa", "actionDeleteResourceRule": "Elimina Regola Risorsa", "actionListResourceRules": "Elenca Regole Risorsa", diff --git a/messages/ko-KR.json b/messages/ko-KR.json index f357fec22..9e5f6ed5c 100644 --- a/messages/ko-KR.json +++ b/messages/ko-KR.json @@ -1462,6 +1462,7 @@ "actionGenerateAccessToken": "액세스 토큰 생성", "actionDeleteAccessToken": "액세스 토큰 삭제", "actionListAccessTokens": "액세스 토큰 목록", + "actionCreateResourceSessionToken": "리소스 세션 토큰 생성", "actionCreateResourceRule": "리소스 규칙 생성", "actionDeleteResourceRule": "리소스 규칙 삭제", "actionListResourceRules": "리소스 규칙 목록", diff --git a/messages/nb-NO.json b/messages/nb-NO.json index 37cec416f..ad815ba32 100644 --- a/messages/nb-NO.json +++ b/messages/nb-NO.json @@ -1462,6 +1462,7 @@ "actionGenerateAccessToken": "Generer tilgangstoken", "actionDeleteAccessToken": "Slett tilgangstoken", "actionListAccessTokens": "List opp tilgangstokener", + "actionCreateResourceSessionToken": "Opprett ressurssesjonstoken", "actionCreateResourceRule": "Opprett ressursregel", "actionDeleteResourceRule": "Slett ressursregel", "actionListResourceRules": "List opp ressursregler", diff --git a/messages/nl-NL.json b/messages/nl-NL.json index 860fef6fb..8a19211d6 100644 --- a/messages/nl-NL.json +++ b/messages/nl-NL.json @@ -1462,6 +1462,7 @@ "actionGenerateAccessToken": "Genereer Toegangstoken", "actionDeleteAccessToken": "Verwijder toegangstoken", "actionListAccessTokens": "Lijst toegangstokens", + "actionCreateResourceSessionToken": "Resourcesessietoken maken", "actionCreateResourceRule": "Bronregel aanmaken", "actionDeleteResourceRule": "Verwijder Resource Regel", "actionListResourceRules": "Bron regels weergeven", diff --git a/messages/pl-PL.json b/messages/pl-PL.json index 4ddaf757a..1fc95a73c 100644 --- a/messages/pl-PL.json +++ b/messages/pl-PL.json @@ -1462,6 +1462,7 @@ "actionGenerateAccessToken": "Wygeneruj token dostępu", "actionDeleteAccessToken": "Usuń token dostępu", "actionListAccessTokens": "Lista tokenów dostępu", + "actionCreateResourceSessionToken": "Utwórz token sesji zasobu", "actionCreateResourceRule": "Utwórz regułę zasobu", "actionDeleteResourceRule": "Usuń regułę zasobu", "actionListResourceRules": "Lista reguł zasobu", diff --git a/messages/pt-PT.json b/messages/pt-PT.json index 1313711e2..762a87e59 100644 --- a/messages/pt-PT.json +++ b/messages/pt-PT.json @@ -1462,6 +1462,7 @@ "actionGenerateAccessToken": "Gerar Token de Acesso", "actionDeleteAccessToken": "Eliminar Token de Acesso", "actionListAccessTokens": "Listar Tokens de Acesso", + "actionCreateResourceSessionToken": "Criar token de sessão de recurso", "actionCreateResourceRule": "Criar Regra de Recurso", "actionDeleteResourceRule": "Eliminar Regra de Recurso", "actionListResourceRules": "Listar Regras de Recurso", diff --git a/messages/ru-RU.json b/messages/ru-RU.json index 91d5bd427..07dc3b7a1 100644 --- a/messages/ru-RU.json +++ b/messages/ru-RU.json @@ -1462,6 +1462,7 @@ "actionGenerateAccessToken": "Сгенерировать токен доступа", "actionDeleteAccessToken": "Удалить токен доступа", "actionListAccessTokens": "Список токенов доступа", + "actionCreateResourceSessionToken": "Создать токен сеанса ресурса", "actionCreateResourceRule": "Создать правило ресурса", "actionDeleteResourceRule": "Удалить правило ресурса", "actionListResourceRules": "Список правил ресурса", diff --git a/messages/tr-TR.json b/messages/tr-TR.json index 9f6cecd1e..7097b48dc 100644 --- a/messages/tr-TR.json +++ b/messages/tr-TR.json @@ -1462,6 +1462,7 @@ "actionGenerateAccessToken": "Erişim Jetonu Oluştur", "actionDeleteAccessToken": "Erişim Jetonunu Sil", "actionListAccessTokens": "Erişim Jetonlarını Listele", + "actionCreateResourceSessionToken": "Kaynak Oturum Belirteci Oluştur", "actionCreateResourceRule": "Kaynak Kuralı Oluştur", "actionDeleteResourceRule": "Kaynak Kuralını Sil", "actionListResourceRules": "Kaynak Kurallarını Listele", diff --git a/messages/zh-CN.json b/messages/zh-CN.json index 58b458265..362282d15 100644 --- a/messages/zh-CN.json +++ b/messages/zh-CN.json @@ -1462,6 +1462,7 @@ "actionGenerateAccessToken": "生成访问令牌", "actionDeleteAccessToken": "删除访问令牌", "actionListAccessTokens": "访问令牌", + "actionCreateResourceSessionToken": "创建资源会话令牌", "actionCreateResourceRule": "创建资源规则", "actionDeleteResourceRule": "删除资源规则", "actionListResourceRules": "列出资源规则", diff --git a/messages/zh-TW.json b/messages/zh-TW.json index 6eb103d3a..c37430567 100644 --- a/messages/zh-TW.json +++ b/messages/zh-TW.json @@ -1099,6 +1099,7 @@ "actionGenerateAccessToken": "生成訪問令牌", "actionDeleteAccessToken": "刪除訪問令牌", "actionListAccessTokens": "訪問令牌", + "actionCreateResourceSessionToken": "建立資源工作階段權杖", "actionCreateResourceRule": "創建資源規則", "actionDeleteResourceRule": "刪除資源規則", "actionListResourceRules": "列出資源規則", diff --git a/server/auth/actions.ts b/server/auth/actions.ts index e47f94d74..50c98c528 100644 --- a/server/auth/actions.ts +++ b/server/auth/actions.ts @@ -71,6 +71,7 @@ export enum ActionsEnum { setResourceWhitelist = "setResourceWhitelist", getResourceWhitelist = "getResourceWhitelist", generateAccessToken = "generateAccessToken", + createResourceSessionToken = "createResourceSessionToken", deleteAcessToken = "deleteAcessToken", listAccessTokens = "listAccessTokens", createResourceRule = "createResourceRule", diff --git a/server/routers/integration.ts b/server/routers/integration.ts index fb3486fd7..74ea20078 100644 --- a/server/routers/integration.ts +++ b/server/routers/integration.ts @@ -808,6 +808,16 @@ authenticated.post( accessToken.generateAccessToken ); +authenticated.post( + `/resource/:resourceId/session-token`, + verifyApiKeyResourceAccess, + verifyApiKeyUserAccess, + verifyLimits, + verifyApiKeyHasAction(ActionsEnum.createResourceSessionToken), + logActionAudit(ActionsEnum.createResourceSessionToken), + resource.createResourceSessionToken +); + authenticated.delete( `/access-token/:accessTokenId`, verifyApiKeyAccessTokenAccess, diff --git a/server/routers/resource/createResourceSessionToken.ts b/server/routers/resource/createResourceSessionToken.ts new file mode 100644 index 000000000..82f0d0cbf --- /dev/null +++ b/server/routers/resource/createResourceSessionToken.ts @@ -0,0 +1,133 @@ +import { Request, Response, NextFunction } from "express"; +import { z } from "zod"; +import { db } from "@server/db"; +import { resources, users, userOrgs } from "@server/db"; +import { eq, and } from "drizzle-orm"; +import { createResourceSession } from "@server/auth/sessions/resource"; +import HttpCode from "@server/types/HttpCode"; +import createHttpError from "http-errors"; +import { fromError } from "zod-validation-error"; +import logger from "@server/logger"; +import { createSession, generateSessionToken } from "@server/auth/sessions/app"; +import { response } from "@server/lib/response"; + +const createResourceSessionTokenParams = z.strictObject({ + resourceId: z.coerce.number().int().positive() +}); + +const createResourceSessionTokenBody = z.strictObject({ + userId: z.string().nonempty(), + idpId: z.coerce.number().int().positive().optional() +}); + +export type CreateResourceSessionTokenResponse = { + requestToken: string; +}; + +export async function createResourceSessionToken( + req: Request, + res: Response, + next: NextFunction +): Promise { + try { + const parsedParams = createResourceSessionTokenParams.safeParse( + req.params + ); + if (!parsedParams.success) { + return next( + createHttpError( + HttpCode.BAD_REQUEST, + fromError(parsedParams.error).toString() + ) + ); + } + + const parsedBody = createResourceSessionTokenBody.safeParse(req.body); + if (!parsedBody.success) { + return next( + createHttpError( + HttpCode.BAD_REQUEST, + fromError(parsedBody.error).toString() + ) + ); + } + + const { resourceId } = parsedParams.data; + const { userId, idpId } = parsedBody.data; + + const [resource] = await db + .select() + .from(resources) + .where(eq(resources.resourceId, resourceId)) + .limit(1); + + if (!resource) { + return next( + createHttpError( + HttpCode.NOT_FOUND, + `Resource with ID ${resourceId} not found` + ) + ); + } + + const candidates = await db + .select({ userId: users.userId }) + .from(userOrgs) + .innerJoin(users, eq(userOrgs.userId, users.userId)) + .where( + and( + eq(users.userId, userId), + eq(userOrgs.orgId, resource.orgId) + ) + ); + + if (candidates.length === 0) { + return next( + createHttpError( + HttpCode.NOT_FOUND, + `User not found in the organization that owns this resource` + ) + ); + } + + if (candidates.length > 1) { + return next( + createHttpError( + HttpCode.BAD_REQUEST, + "Multiple users match this username (external users from different identity providers). Specify idpId to disambiguate." + ) + ); + } + + const targetUserId = candidates[0].userId; + + const appSessionToken = generateSessionToken(); + const appSession = await createSession(appSessionToken, targetUserId); + + const requestToken = generateSessionToken(); + await createResourceSession({ + resourceId, + token: requestToken, + userSessionId: appSession.sessionId, + isRequestToken: true, + expiresAt: Date.now() + 1000 * 30, // 30 seconds + sessionLength: 1000 * 30, + doNotExtend: true + }); + + logger.debug("Resource session token created successfully"); + + return response(res, { + data: { requestToken }, + success: true, + error: false, + message: "Resource session token created successfully", + status: HttpCode.OK + }); + } catch (error) { + logger.error(error); + return next( + createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred") + ); + } +} diff --git a/server/routers/resource/index.ts b/server/routers/resource/index.ts index 83dbdea2a..4bc9d20f0 100644 --- a/server/routers/resource/index.ts +++ b/server/routers/resource/index.ts @@ -17,6 +17,7 @@ export * from "./getResourceWhitelist"; export * from "./authWithWhitelist"; export * from "./authWithAccessToken"; export * from "./getExchangeToken"; +export * from "./createResourceSessionToken"; export * from "./createResourceRule"; export * from "./deleteResourceRule"; export * from "./listResourceRules"; diff --git a/src/components/PermissionsSelectBox.tsx b/src/components/PermissionsSelectBox.tsx index 8f9236b2b..06d9ff690 100644 --- a/src/components/PermissionsSelectBox.tsx +++ b/src/components/PermissionsSelectBox.tsx @@ -77,7 +77,8 @@ function getActionsCategories(root: boolean) { [t("actionDeleteSiteResource")]: "deleteSiteResource", [t("actionGetSiteResource")]: "getSiteResource", [t("actionListSiteResources")]: "listSiteResources", - [t("actionUpdateSiteResource")]: "updateSiteResource" + [t("actionUpdateSiteResource")]: "updateSiteResource", + [t("actionCreateResourceSessionToken")]: "createResourceSessionToken" }, Target: {