mirror of
https://github.com/fosrl/pangolin.git
synced 2026-08-04 19:51:29 +02:00
check idp org ownership on save policy closes #3290
This commit is contained in:
@@ -1,7 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
db,
|
db,
|
||||||
idp,
|
|
||||||
idpOrg,
|
|
||||||
resourcePolicies,
|
resourcePolicies,
|
||||||
resourcePolicyHeaderAuth,
|
resourcePolicyHeaderAuth,
|
||||||
resourcePolicyPassword,
|
resourcePolicyPassword,
|
||||||
@@ -20,6 +18,7 @@ import { Config, ResourcePolicyData } from "./types";
|
|||||||
import logger from "@server/logger";
|
import logger from "@server/logger";
|
||||||
import { getUniqueResourcePolicyName } from "@server/db/names";
|
import { getUniqueResourcePolicyName } from "@server/db/names";
|
||||||
import { hashPassword } from "@server/auth/password";
|
import { hashPassword } from "@server/auth/password";
|
||||||
|
import { idpExistsForOrg } from "@server/lib/idp/idpExistsForOrg";
|
||||||
import { isValidCIDR, isValidIP, isValidUrlGlobPattern } from "../validators";
|
import { isValidCIDR, isValidIP, isValidUrlGlobPattern } from "../validators";
|
||||||
import { isLicensedOrSubscribed } from "#dynamic/lib/isLicencedOrSubscribed";
|
import { isLicensedOrSubscribed } from "#dynamic/lib/isLicencedOrSubscribed";
|
||||||
import { tierMatrix } from "../billing/tierMatrix";
|
import { tierMatrix } from "../billing/tierMatrix";
|
||||||
@@ -71,19 +70,13 @@ export async function updateResourcePolicies(
|
|||||||
|
|
||||||
// Validate auto-login-idp if provided
|
// Validate auto-login-idp if provided
|
||||||
if (policyData["auto-login-idp"]) {
|
if (policyData["auto-login-idp"]) {
|
||||||
const [provider] = await trx
|
const providerExists = await idpExistsForOrg(
|
||||||
.select()
|
policyData["auto-login-idp"],
|
||||||
.from(idp)
|
orgId,
|
||||||
.innerJoin(idpOrg, eq(idpOrg.idpId, idp.idpId))
|
trx
|
||||||
.where(
|
);
|
||||||
and(
|
|
||||||
eq(idp.idpId, policyData["auto-login-idp"]),
|
|
||||||
eq(idpOrg.orgId, orgId)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.limit(1);
|
|
||||||
|
|
||||||
if (!provider) {
|
if (!providerExists) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Identity provider not found for policy '${policyNiceId}' in this organization`
|
`Identity provider not found for policy '${policyNiceId}' in this organization`
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
import { db, idp, idpOrg, Transaction } from "@server/db";
|
||||||
|
import { and, eq } from "drizzle-orm";
|
||||||
|
|
||||||
|
export function isOrgIdentityProviderMode(): boolean {
|
||||||
|
return process.env.IDENTITY_PROVIDER_MODE === "org";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether an identity provider can be used for the given org.
|
||||||
|
* In org IdP mode, the provider must be linked via idpOrg.
|
||||||
|
* In global IdP mode, the provider only needs to exist.
|
||||||
|
*/
|
||||||
|
export async function idpExistsForOrg(
|
||||||
|
idpId: number,
|
||||||
|
orgId: string,
|
||||||
|
dbOrTrx: typeof db | Transaction = db
|
||||||
|
): Promise<boolean> {
|
||||||
|
if (isOrgIdentityProviderMode()) {
|
||||||
|
const [provider] = await dbOrTrx
|
||||||
|
.select({ idpId: idp.idpId })
|
||||||
|
.from(idp)
|
||||||
|
.innerJoin(idpOrg, eq(idpOrg.idpId, idp.idpId))
|
||||||
|
.where(and(eq(idp.idpId, idpId), eq(idpOrg.orgId, orgId)))
|
||||||
|
.limit(1);
|
||||||
|
|
||||||
|
return !!provider;
|
||||||
|
}
|
||||||
|
|
||||||
|
const [provider] = await dbOrTrx
|
||||||
|
.select({ idpId: idp.idpId })
|
||||||
|
.from(idp)
|
||||||
|
.where(eq(idp.idpId, idpId))
|
||||||
|
.limit(1);
|
||||||
|
|
||||||
|
return !!provider;
|
||||||
|
}
|
||||||
@@ -14,8 +14,6 @@
|
|||||||
import { hashPassword } from "@server/auth/password";
|
import { hashPassword } from "@server/auth/password";
|
||||||
import {
|
import {
|
||||||
db,
|
db,
|
||||||
idp,
|
|
||||||
idpOrg,
|
|
||||||
orgs,
|
orgs,
|
||||||
resourcePolicies,
|
resourcePolicies,
|
||||||
resourcePolicyHeaderAuth,
|
resourcePolicyHeaderAuth,
|
||||||
@@ -31,6 +29,7 @@ import {
|
|||||||
type ResourcePolicy
|
type ResourcePolicy
|
||||||
} from "@server/db";
|
} from "@server/db";
|
||||||
import { getUniqueResourcePolicyName } from "@server/db/names";
|
import { getUniqueResourcePolicyName } from "@server/db/names";
|
||||||
|
import { idpExistsForOrg } from "@server/lib/idp/idpExistsForOrg";
|
||||||
import response from "@server/lib/response";
|
import response from "@server/lib/response";
|
||||||
import {
|
import {
|
||||||
getResourceRuleValueValidationError,
|
getResourceRuleValueValidationError,
|
||||||
@@ -204,14 +203,9 @@ export async function createResourcePolicy(
|
|||||||
|
|
||||||
// Check if Identity provider in `skipToIdpId` exists
|
// Check if Identity provider in `skipToIdpId` exists
|
||||||
if (skipToIdpId) {
|
if (skipToIdpId) {
|
||||||
const [provider] = await db
|
const providerExists = await idpExistsForOrg(skipToIdpId, orgId);
|
||||||
.select()
|
|
||||||
.from(idp)
|
|
||||||
.innerJoin(idpOrg, eq(idpOrg.idpId, idp.idpId))
|
|
||||||
.where(and(eq(idp.idpId, skipToIdpId), eq(idpOrg.orgId, orgId)))
|
|
||||||
.limit(1);
|
|
||||||
|
|
||||||
if (!provider) {
|
if (!providerExists) {
|
||||||
return next(
|
return next(
|
||||||
createHttpError(
|
createHttpError(
|
||||||
HttpCode.INTERNAL_SERVER_ERROR,
|
HttpCode.INTERNAL_SERVER_ERROR,
|
||||||
|
|||||||
@@ -2,8 +2,6 @@ import { Request, Response, NextFunction } from "express";
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import {
|
import {
|
||||||
db,
|
db,
|
||||||
idp,
|
|
||||||
idpOrg,
|
|
||||||
resourcePolicies,
|
resourcePolicies,
|
||||||
rolePolicies,
|
rolePolicies,
|
||||||
roles,
|
roles,
|
||||||
@@ -18,6 +16,7 @@ import logger from "@server/logger";
|
|||||||
import { fromError } from "zod-validation-error";
|
import { fromError } from "zod-validation-error";
|
||||||
import { and, eq, inArray, ne } from "drizzle-orm";
|
import { and, eq, inArray, ne } from "drizzle-orm";
|
||||||
import { OpenAPITags, registry } from "@server/openApi";
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
|
import { idpExistsForOrg } from "@server/lib/idp/idpExistsForOrg";
|
||||||
|
|
||||||
const setResourcePolicyAcccessControlBodySchema = z.strictObject({
|
const setResourcePolicyAcccessControlBodySchema = z.strictObject({
|
||||||
sso: z.boolean(),
|
sso: z.boolean(),
|
||||||
@@ -27,7 +26,7 @@ const setResourcePolicyAcccessControlBodySchema = z.strictObject({
|
|||||||
}),
|
}),
|
||||||
skipToIdpId: z.int().positive().optional().nullable().openapi({
|
skipToIdpId: z.int().positive().optional().nullable().openapi({
|
||||||
type: "integer",
|
type: "integer",
|
||||||
description: "Page number to retrieve"
|
description: "Default identity provider ID to skip to on login"
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -36,8 +35,8 @@ const setResourcePolicyAccessControlParamsSchema = z.strictObject({
|
|||||||
});
|
});
|
||||||
|
|
||||||
registry.registerPath({
|
registry.registerPath({
|
||||||
method: "post",
|
method: "put",
|
||||||
path: "/resource-policy/{resourceId}/access-control",
|
path: "/resource-policy/{resourcePolicyId}/access-control",
|
||||||
description:
|
description:
|
||||||
"Set access control users for a resource policy, including SSO, users, roles, Identity provider.",
|
"Set access control users for a resource policy, including SSO, users, roles, Identity provider.",
|
||||||
tags: [OpenAPITags.PublicResourcePolicyLegacy],
|
tags: [OpenAPITags.PublicResourcePolicyLegacy],
|
||||||
@@ -163,16 +162,9 @@ export async function setResourcePolicyAccessControl(
|
|||||||
|
|
||||||
// Check if Identity provider in `skipToIdpId` exists
|
// Check if Identity provider in `skipToIdpId` exists
|
||||||
if (idpId) {
|
if (idpId) {
|
||||||
const [provider] = await db
|
const providerExists = await idpExistsForOrg(idpId, policy.orgId);
|
||||||
.select()
|
|
||||||
.from(idp)
|
|
||||||
.innerJoin(idpOrg, eq(idpOrg.idpId, idp.idpId))
|
|
||||||
.where(
|
|
||||||
and(eq(idp.idpId, idpId), eq(idpOrg.orgId, policy.orgId))
|
|
||||||
)
|
|
||||||
.limit(1);
|
|
||||||
|
|
||||||
if (!provider) {
|
if (!providerExists) {
|
||||||
return next(
|
return next(
|
||||||
createHttpError(
|
createHttpError(
|
||||||
HttpCode.INTERNAL_SERVER_ERROR,
|
HttpCode.INTERNAL_SERVER_ERROR,
|
||||||
|
|||||||
Reference in New Issue
Block a user