diff --git a/src/contexts/AuthContext.tsx b/src/contexts/AuthContext.tsx index 1d1541da..b58b8bfd 100644 --- a/src/contexts/AuthContext.tsx +++ b/src/contexts/AuthContext.tsx @@ -23,6 +23,8 @@ type EGISessionInfo = { preferred_username: string; // Nombre de usuario preferido sub: string; // Identificador único del usuario voperson_verified_email: string[]; // Lista de correos electrónicos verificados + + group_membership: string[]; }; export type AuthData = { diff --git a/src/lib/utils.ts b/src/lib/utils.ts index b6da6c65..9d7fe2cd 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -1,3 +1,5 @@ +import { AuthData } from "@/contexts/AuthContext"; +import { SystemConfig } from "@/models/systemConfig"; import { type ClassValue, clsx } from "clsx" import { twMerge } from "tailwind-merge" @@ -70,6 +72,42 @@ export function isVersionLower(version: string, target: string) { return false; } +export function getUserVOs(authData: AuthData): string[] { + const vos: string[] = []; + if (authData.egiSession?.eduperson_entitlement) { + authData.egiSession.eduperson_entitlement.forEach((entitlement) => { + // "urn:mace:egi.eu:group:vo.example.eu:role=member#aai.egi.eu" + const match = entitlement.match(/^urn:mace:egi\.eu:group:(vo\..+?):role=member(?:#|$)/); + if (match && match[1]) { + vos.push(match[1]); + } + }); + } + if (authData.egiSession?.group_membership) { + authData.egiSession.group_membership.forEach((group) => { + // "/employees/vo.example.eu" + const match = group.match(/^\/.*\/(vo\..+)$/); + if (match && match[1]) { + vos.push(match[1]); + } + }); + } + return vos; +} + +export function getAllowedVOs(systemConfig: {config: SystemConfig} | null, authData: AuthData): string[] { + if (!systemConfig || !systemConfig.config || !systemConfig.config.oidc_groups || systemConfig.config.oidc_groups.length === 0) return []; + // If user is oscar, return all allowed VOs from system config + if (authData.user === "oscar") return systemConfig.config.oidc_groups; + // Get user's VOs + const userVOs = getUserVOs(authData); + // If user has no VOs, return all allowed VOs from system config + if (userVOs.length === 0) return systemConfig.config.oidc_groups; + // Filter allowed VOs based on user's VOs + const filteredVOs = systemConfig.config.oidc_groups.filter((vo) => userVOs.includes(vo)); + return filteredVOs; +} + function sleep(ms: number) { return new Promise(resolve => setTimeout(resolve, ms)); -} \ No newline at end of file +} diff --git a/src/pages/ui/flows/components/FlowsFormPopover/index.tsx b/src/pages/ui/flows/components/FlowsFormPopover/index.tsx index d3329a15..9d9c8de0 100644 --- a/src/pages/ui/flows/components/FlowsFormPopover/index.tsx +++ b/src/pages/ui/flows/components/FlowsFormPopover/index.tsx @@ -15,18 +15,18 @@ import { useMinio } from "@/contexts/Minio/MinioContext"; import { Info, Plus, RefreshCcwIcon } from "lucide-react"; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip"; import RequestButton from "@/components/RequestButton"; -import { generateReadableName, genRandomString } from "@/lib/utils"; +import { generateReadableName, genRandomString, getAllowedVOs } from "@/lib/utils"; function FlowsFormPopover() { const { buckets } = useMinio(); const [isOpen, setIsOpen] = useState(false); - const {systemConfig, clusterInfo } = useAuth(); + const {systemConfig, clusterInfo, authData } = useAuth(); const { refreshServices } = useServicesContext(); const [newBucket, setNewBucket] = useState(false); - const oidcGroups = systemConfig?.config?.oidc_groups ?? []; + const oidcGroups = getAllowedVOs(systemConfig, authData); function nameService() { return `flows-${generateReadableName(6)}-${genRandomString(8).toLowerCase()}`; diff --git a/src/pages/ui/hub/components/HubServiceConfPopover/index.tsx b/src/pages/ui/hub/components/HubServiceConfPopover/index.tsx index 9fd74a87..46627a72 100644 --- a/src/pages/ui/hub/components/HubServiceConfPopover/index.tsx +++ b/src/pages/ui/hub/components/HubServiceConfPopover/index.tsx @@ -7,7 +7,7 @@ import { Label } from "@/components/ui/label"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { useAuth } from "@/contexts/AuthContext"; import { alert } from "@/lib/alert"; -import { generateReadableName, genRandomString } from "@/lib/utils"; +import { generateReadableName, genRandomString, getAllowedVOs } from "@/lib/utils"; import useServicesContext from "@/pages/ui/services/context/ServicesContext"; import { Service } from "@/pages/ui/services/models/service"; import OscarColors from "@/styles"; @@ -26,10 +26,10 @@ interface HubServiceConfPopoverProps { } function HubServiceConfPopover({ roCrateServiceDef, service, isOpen = false, setIsOpen, className = "", variant = "default", title = "Deploy Service" }: HubServiceConfPopoverProps) { - const {systemConfig } = useAuth(); + const {systemConfig, authData } = useAuth(); const { refreshServices } = useServicesContext(); - const oidcGroups = systemConfig?.config.oidc_groups ?? []; + const oidcGroups = getAllowedVOs(systemConfig, authData); const asyncService = roCrateServiceDef.type.toLowerCase() === "asynchronous"; function nameService() { diff --git a/src/pages/ui/juno/components/JunoFormPopover/index.tsx b/src/pages/ui/juno/components/JunoFormPopover/index.tsx index be6f77b4..b8578927 100644 --- a/src/pages/ui/juno/components/JunoFormPopover/index.tsx +++ b/src/pages/ui/juno/components/JunoFormPopover/index.tsx @@ -8,7 +8,7 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@ import { useAuth } from "@/contexts/AuthContext"; import { useMinio } from "@/contexts/Minio/MinioContext"; import { alert } from "@/lib/alert"; -import { generateReadableName, genRandomString } from "@/lib/utils"; +import { generateReadableName, genRandomString, getAllowedVOs } from "@/lib/utils"; import yamlToServices from "@/pages/ui/services/components/FDL/utils/yamlToService"; import useServicesContext from "@/pages/ui/services/context/ServicesContext"; import { Service } from "@/pages/ui/services/models/service"; @@ -24,7 +24,7 @@ function JunoFormPopover() { const { refreshServices } = useServicesContext(); const [newBucket, setNewBucket] = useState(false); - const oidcGroups = systemConfig?.config.oidc_groups ?? []; + const oidcGroups = getAllowedVOs(systemConfig, authData); function nameService() { return `juno-${generateReadableName(6)}-${genRandomString(8).toLowerCase()}`; diff --git a/src/pages/ui/services/components/ServiceForm/components/GeneralTab/index.tsx b/src/pages/ui/services/components/ServiceForm/components/GeneralTab/index.tsx index 8bf38e04..f175870f 100644 --- a/src/pages/ui/services/components/ServiceForm/components/GeneralTab/index.tsx +++ b/src/pages/ui/services/components/ServiceForm/components/GeneralTab/index.tsx @@ -25,6 +25,7 @@ import EnviromentSecrets from "./components/EnviromentSecrets"; import Annotations from "./components/Annotations"; import { AllowedUsersPopover } from "./components/AllowedUsersPopover"; +import { getAllowedVOs } from "@/lib/utils"; function ServiceGeneralTab() { const { formService, setFormService, formMode, formFunctions } = @@ -32,7 +33,7 @@ function ServiceGeneralTab() { const { handleChange, onBlur, errors } = formFunctions; const { systemConfig, authData } = useAuth(); - const voGroups = systemConfig?.config.oidc_groups; + const voGroups = getAllowedVOs(systemConfig, authData); function voGroupsIsEmpthy(){ if( voGroups === undefined){ return true} else if (JSON.stringify(voGroups) === '[""]'){ return true}