Add pass rule

This commit is contained in:
Owen
2025-08-24 22:20:09 -07:00
parent 72f19274cd
commit 78d3861382
7 changed files with 19 additions and 9 deletions

View File

@@ -205,6 +205,7 @@
"resourceSetting": "{resourceName} Settings", "resourceSetting": "{resourceName} Settings",
"alwaysAllow": "Always Allow", "alwaysAllow": "Always Allow",
"alwaysDeny": "Always Deny", "alwaysDeny": "Always Deny",
"passToAuth": "Pass to Auth",
"orgSettingsDescription": "Configure your organization's general settings", "orgSettingsDescription": "Configure your organization's general settings",
"orgGeneralSettings": "Organization Settings", "orgGeneralSettings": "Organization Settings",
"orgGeneralSettingsDescription": "Manage your organization details and configuration", "orgGeneralSettingsDescription": "Manage your organization details and configuration",
@@ -545,6 +546,7 @@
"rulesActions": "Actions", "rulesActions": "Actions",
"rulesActionAlwaysAllow": "Always Allow: Bypass all authentication methods", "rulesActionAlwaysAllow": "Always Allow: Bypass all authentication methods",
"rulesActionAlwaysDeny": "Always Deny: Block all requests; no authentication can be attempted", "rulesActionAlwaysDeny": "Always Deny: Block all requests; no authentication can be attempted",
"rulesActionPassToAuth": "Pass to Auth: Allow authentication methods to be attempted",
"rulesMatchCriteria": "Matching Criteria", "rulesMatchCriteria": "Matching Criteria",
"rulesMatchCriteriaIpAddress": "Match a specific IP address", "rulesMatchCriteriaIpAddress": "Match a specific IP address",
"rulesMatchCriteriaIpAddressRange": "Match a range of IP addresses in CIDR notation", "rulesMatchCriteriaIpAddressRange": "Match a range of IP addresses in CIDR notation",

View File

@@ -430,7 +430,7 @@ export const resourceRules = pgTable("resourceRules", {
.references(() => resources.resourceId, { onDelete: "cascade" }), .references(() => resources.resourceId, { onDelete: "cascade" }),
enabled: boolean("enabled").notNull().default(true), enabled: boolean("enabled").notNull().default(true),
priority: integer("priority").notNull(), priority: integer("priority").notNull(),
action: varchar("action").notNull(), // ACCEPT, DROP action: varchar("action").notNull(), // ACCEPT, DROP, PASS
match: varchar("match").notNull(), // CIDR, PATH, IP match: varchar("match").notNull(), // CIDR, PATH, IP
value: varchar("value").notNull() value: varchar("value").notNull()
}); });

View File

@@ -570,7 +570,7 @@ export const resourceRules = sqliteTable("resourceRules", {
.references(() => resources.resourceId, { onDelete: "cascade" }), .references(() => resources.resourceId, { onDelete: "cascade" }),
enabled: integer("enabled", { mode: "boolean" }).notNull().default(true), enabled: integer("enabled", { mode: "boolean" }).notNull().default(true),
priority: integer("priority").notNull(), priority: integer("priority").notNull(),
action: text("action").notNull(), // ACCEPT, DROP action: text("action").notNull(), // ACCEPT, DROP, PASS
match: text("match").notNull(), // CIDR, PATH, IP match: text("match").notNull(), // CIDR, PATH, IP
value: text("value").notNull() value: text("value").notNull()
}); });

View File

@@ -178,6 +178,9 @@ export async function verifyResourceSession(
} else if (action == "DROP") { } else if (action == "DROP") {
logger.debug("Resource denied by rule"); logger.debug("Resource denied by rule");
return notAllowed(res); return notAllowed(res);
} else if (action == "PASS") {
logger.debug("Resource passed by rule, continuing to auth checks");
// Continue to authentication checks below
} }
// otherwise its undefined and we pass // otherwise its undefined and we pass
@@ -581,7 +584,7 @@ async function checkRules(
resourceId: number, resourceId: number,
clientIp: string | undefined, clientIp: string | undefined,
path: string | undefined path: string | undefined
): Promise<"ACCEPT" | "DROP" | undefined> { ): Promise<"ACCEPT" | "DROP" | "PASS" | undefined> {
const ruleCacheKey = `rules:${resourceId}`; const ruleCacheKey = `rules:${resourceId}`;
let rules: ResourceRule[] | undefined = cache.get(ruleCacheKey); let rules: ResourceRule[] | undefined = cache.get(ruleCacheKey);

View File

@@ -17,7 +17,7 @@ import { OpenAPITags, registry } from "@server/openApi";
const createResourceRuleSchema = z const createResourceRuleSchema = z
.object({ .object({
action: z.enum(["ACCEPT", "DROP"]), action: z.enum(["ACCEPT", "DROP", "PASS"]),
match: z.enum(["CIDR", "IP", "PATH"]), match: z.enum(["CIDR", "IP", "PATH"]),
value: z.string().min(1), value: z.string().min(1),
priority: z.number().int(), priority: z.number().int(),

View File

@@ -29,7 +29,7 @@ const updateResourceRuleParamsSchema = z
// Define Zod schema for request body validation // Define Zod schema for request body validation
const updateResourceRuleSchema = z const updateResourceRuleSchema = z
.object({ .object({
action: z.enum(["ACCEPT", "DROP"]).optional(), action: z.enum(["ACCEPT", "DROP", "PASS"]).optional(),
match: z.enum(["CIDR", "IP", "PATH"]).optional(), match: z.enum(["CIDR", "IP", "PATH"]).optional(),
value: z.string().min(1).optional(), value: z.string().min(1).optional(),
priority: z.number().int(), priority: z.number().int(),

View File

@@ -76,7 +76,7 @@ import { useTranslations } from "next-intl";
// Schema for rule validation // Schema for rule validation
const addRuleSchema = z.object({ const addRuleSchema = z.object({
action: z.string(), action: z.enum(["ACCEPT", "DROP", "PASS"]),
match: z.string(), match: z.string(),
value: z.string(), value: z.string(),
priority: z.coerce.number().int().optional() priority: z.coerce.number().int().optional()
@@ -104,7 +104,8 @@ export default function ResourceRules(props: {
const RuleAction = { const RuleAction = {
ACCEPT: t('alwaysAllow'), ACCEPT: t('alwaysAllow'),
DROP: t('alwaysDeny') DROP: t('alwaysDeny'),
PASS: t('passToAuth')
} as const; } as const;
const RuleMatch = { const RuleMatch = {
@@ -113,7 +114,7 @@ export default function ResourceRules(props: {
CIDR: t('ipAddressRange') CIDR: t('ipAddressRange')
} as const; } as const;
const addRuleForm = useForm({ const addRuleForm = useForm<z.infer<typeof addRuleSchema>>({
resolver: zodResolver(addRuleSchema), resolver: zodResolver(addRuleSchema),
defaultValues: { defaultValues: {
action: "ACCEPT", action: "ACCEPT",
@@ -437,7 +438,7 @@ export default function ResourceRules(props: {
cell: ({ row }) => ( cell: ({ row }) => (
<Select <Select
defaultValue={row.original.action} defaultValue={row.original.action}
onValueChange={(value: "ACCEPT" | "DROP") => onValueChange={(value: "ACCEPT" | "DROP" | "PASS") =>
updateRule(row.original.ruleId, { action: value }) updateRule(row.original.ruleId, { action: value })
} }
> >
@@ -449,6 +450,7 @@ export default function ResourceRules(props: {
{RuleAction.ACCEPT} {RuleAction.ACCEPT}
</SelectItem> </SelectItem>
<SelectItem value="DROP">{RuleAction.DROP}</SelectItem> <SelectItem value="DROP">{RuleAction.DROP}</SelectItem>
<SelectItem value="PASS">{RuleAction.PASS}</SelectItem>
</SelectContent> </SelectContent>
</Select> </Select>
) )
@@ -629,6 +631,9 @@ export default function ResourceRules(props: {
<SelectItem value="DROP"> <SelectItem value="DROP">
{RuleAction.DROP} {RuleAction.DROP}
</SelectItem> </SelectItem>
<SelectItem value="PASS">
{RuleAction.PASS}
</SelectItem>
</SelectContent> </SelectContent>
</Select> </Select>
</FormControl> </FormControl>