review fixes

This commit is contained in:
x032205
2025-05-12 14:49:45 -04:00
parent d5dbc7d7e0
commit 091e521180
11 changed files with 104 additions and 48 deletions

View File

@@ -17,7 +17,7 @@ export async function up(knex: Knex): Promise<void> {
t.string("type").notNullable();
t.string("tenancyOcid").notNullable();
t.string("allowedUsernames").notNullable();
t.string("allowedUsernames").nullable();
});
}

View File

@@ -18,7 +18,7 @@ export const IdentityOciAuthsSchema = z.object({
identityId: z.string().uuid(),
type: z.string(),
tenancyOcid: z.string(),
allowedUsernames: z.string()
allowedUsernames: z.string().nullable().optional()
});
export type TIdentityOciAuths = z.infer<typeof IdentityOciAuthsSchema>;

View File

@@ -1022,7 +1022,7 @@ interface AddIdentityOciAuthEvent {
metadata: {
identityId: string;
tenancyOcid: string;
allowedUsernames: string;
allowedUsernames: string | null;
accessTokenTTL: number;
accessTokenMaxTTL: number;
accessTokenNumUsesLimit: number;
@@ -1042,7 +1042,7 @@ interface UpdateIdentityOciAuthEvent {
metadata: {
identityId: string;
tenancyOcid?: string;
allowedUsernames?: string;
allowedUsernames: string | null;
accessTokenTTL?: number;
accessTokenMaxTTL?: number;
accessTokenNumUsesLimit?: number;

View File

@@ -143,7 +143,7 @@ export const registerIdentityOciAuthRouter = async (server: FastifyZodProvider)
metadata: {
identityId: identityOciAuth.identityId,
tenancyOcid: identityOciAuth.tenancyOcid,
allowedUsernames: identityOciAuth.allowedUsernames,
allowedUsernames: identityOciAuth.allowedUsernames || null,
accessTokenTTL: identityOciAuth.accessTokenTTL,
accessTokenMaxTTL: identityOciAuth.accessTokenMaxTTL,
accessTokenTrustedIps: identityOciAuth.accessTokenTrustedIps as TIdentityTrustedIp[],
@@ -214,7 +214,8 @@ export const registerIdentityOciAuthRouter = async (server: FastifyZodProvider)
actorAuthMethod: req.permission.authMethod,
actorOrgId: req.permission.orgId,
...req.body,
identityId: req.params.identityId
identityId: req.params.identityId,
allowedUsernames: req.body.allowedUsernames || null
});
await server.services.auditLog.createAuditLog({
@@ -225,7 +226,7 @@ export const registerIdentityOciAuthRouter = async (server: FastifyZodProvider)
metadata: {
identityId: identityOciAuth.identityId,
tenancyOcid: identityOciAuth.tenancyOcid,
allowedUsernames: identityOciAuth.allowedUsernames,
allowedUsernames: identityOciAuth.allowedUsernames || null,
accessTokenTTL: identityOciAuth.accessTokenTTL,
accessTokenMaxTTL: identityOciAuth.accessTokenMaxTTL,
accessTokenTrustedIps: identityOciAuth.accessTokenTrustedIps as TIdentityTrustedIp[],

View File

@@ -1,5 +1,6 @@
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
import { ForbiddenError } from "@casl/ability";
import { AxiosError } from "axios";
import jwt from "jsonwebtoken";
import RE2 from "re2";
@@ -15,6 +16,7 @@ import { getConfig } from "@app/lib/config/env";
import { request } from "@app/lib/config/request";
import { BadRequestError, NotFoundError, PermissionBoundaryError, UnauthorizedError } from "@app/lib/errors";
import { extractIPDetails, isValidIpOrCidr } from "@app/lib/ip";
import { logger } from "@app/lib/logger";
import { blockLocalAndPrivateIpAddresses } from "@app/lib/validator";
import { ActorType, AuthTokenType } from "../auth/auth-type";
@@ -60,15 +62,20 @@ export const identityOciAuthServiceFactory = ({
await blockLocalAndPrivateIpAddresses(headers.host);
// Validate OCI host format
if (!headers.host || !new RE2("^identity\\.[a-zA-Z0-9-]+\\.oraclecloud\\.com$").test(headers.host)) {
if (!headers.host || !new RE2("^identity\\.([a-z]{2}-[a-z]+-[1-9])\\.oraclecloud\\.com$").test(headers.host)) {
throw new BadRequestError({
message: "Invalid OCI host format. Expected format: identity.<region>.oraclecloud.com"
});
}
const { data } = await request.get<TOciGetUserResponse>(`https://${headers.host}/20160918/users/${userOcid}`, {
headers
});
const { data } = await request
.get<TOciGetUserResponse>(`https://${headers.host}/20160918/users/${userOcid}`, {
headers
})
.catch((err: AxiosError) => {
logger.error(err.response, "OciIdentityLogin: Failed to authenticate with Oracle Cloud");
throw err;
});
if (data.compartmentId !== identityOciAuth.tenancyOcid) {
throw new UnauthorizedError({

View File

@@ -13,7 +13,7 @@ export type TLoginOciAuthDTO = {
export type TAttachOciAuthDTO = {
identityId: string;
tenancyOcid: string;
allowedUsernames: string;
allowedUsernames: string | null;
accessTokenTTL: number;
accessTokenMaxTTL: number;
accessTokenNumUsesLimit: number;
@@ -23,8 +23,8 @@ export type TAttachOciAuthDTO = {
export type TUpdateOciAuthDTO = {
identityId: string;
tenancyOcid?: string;
allowedUsernames?: string;
tenancyOcid: string;
allowedUsernames: string | null;
accessTokenTTL?: number;
accessTokenMaxTTL?: number;
accessTokenNumUsesLimit?: number;

View File

@@ -9,16 +9,18 @@ export const validateUsernames = z
.string()
.trim()
.max(500, "Input exceeds the maximum limit of 500 characters")
.transform((val) =>
val
.nullish()
.transform((val) => {
if (!val) return [];
return val
.split(",")
.map((s) => s.trim())
.filter(Boolean)
)
.filter(Boolean);
})
.refine((arr) => arr.every((name) => usernameSchema.safeParse(name).success), {
message: "One or more usernames are invalid"
})
.transform((arr) => arr.join(", "));
.transform((arr) => (arr.length > 0 ? arr.join(", ") : null));
export const validateTenancy = z
.string()

View File

@@ -43,6 +43,49 @@ To be more specific:
4. Infisical checks the user's properties against set criteria such as **Allowed Usernames** and **Tenancy OCID**.
5. If all checks pass, Infisical returns a short-lived access token that the client can use to make authenticated requests to the Infisical API.
## Prerequisite
In order to sign requests, you must have an OCI user with credentials such as the private key. If you're unaware of how to create a user and obtain the needed credentials, expand the menu below.
<Accordion title="Creating an OCI user">
<Steps>
<Step title="Search for 'Domains' and click as shown">
![Search Domains](/images/app-connections/oci/search-domains.png)
</Step>
<Step title="Select domain">
Select the domain in which you want to create the Infisical user account.
![Select Domain](/images/app-connections/oci/select-domain.png)
</Step>
<Step title="Navigate to 'Users'">
![Select Users](/images/app-connections/oci/select-users.png)
</Step>
<Step title="Click 'Create user'">
![Click Create User](/images/app-connections/oci/click-create-user.png)
</Step>
<Step title="Create user">
The name, email, and username can be anything.
![Create User](/images/app-connections/oci/create-user.png)
</Step>
<Step title="Navigate to 'API keys'">
After you've created a user, you'll be redirected to the user's page. Navigate to 'API keys'.
![Select API Keys](/images/app-connections/oci/select-api-keys.png)
</Step>
<Step title="Add API key">
Click on 'Add API key' and then download or import the private key. After you've obtained the private key, click 'Add'.
![Add API Key](/images/app-connections/oci/add-api-key.png)
</Step>
<Step title="Store configuration">
After creating the API key, you'll be shown a modal with relevant information. Save the highlighted values (and the private key) for later steps.
![User Info](/images/app-connections/oci/user-info.png)
</Step>
</Steps>
</Accordion>
## Guide
In the following steps, we explore how to create and use identities for your workloads and applications on OCI to

View File

@@ -294,7 +294,7 @@ export type IdentityOciAuth = {
identityId: string;
type: "iam";
tenancyOcid: string;
allowedUsernames: string;
allowedUsernames?: string | null;
accessTokenTTL: number;
accessTokenMaxTTL: number;
accessTokenNumUsesLimit: number;
@@ -305,7 +305,7 @@ export type AddIdentityOciAuthDTO = {
organizationId: string;
identityId: string;
tenancyOcid: string;
allowedUsernames: string;
allowedUsernames?: string | null;
accessTokenTTL: number;
accessTokenMaxTTL: number;
accessTokenNumUsesLimit: number;
@@ -318,7 +318,7 @@ export type UpdateIdentityOciAuthDTO = {
organizationId: string;
identityId: string;
tenancyOcid?: string;
allowedUsernames?: string;
allowedUsernames?: string | null;
accessTokenTTL?: number;
accessTokenMaxTTL?: number;
accessTokenNumUsesLimit?: number;

View File

@@ -29,8 +29,15 @@ import { IdentityFormTab } from "./types";
const schema = z
.object({
tenancyOcid: z.string().trim().min(1, "Tenancy OCID is required."),
allowedUsernames: z.string(),
tenancyOcid: z
.string()
.trim()
.min(1, "Tenancy OCID cannot be empty.")
.refine(
(val) => /^ocid1\.tenancy\.oc1\..+$/.test(val),
"Invalid Tenancy OCID format. Must start with ocid1.tenancy.oc1."
),
allowedUsernames: z.string().optional(),
accessTokenTTL: z
.string()
.refine(
@@ -110,7 +117,7 @@ export const IdentityOciAuthForm = ({
if (data) {
reset({
tenancyOcid: data.tenancyOcid,
allowedUsernames: data.allowedUsernames,
allowedUsernames: data.allowedUsernames || undefined,
accessTokenTTL: String(data.accessTokenTTL),
accessTokenMaxTTL: String(data.accessTokenMaxTTL),
accessTokenNumUsesLimit: String(data.accessTokenNumUsesLimit),
@@ -125,7 +132,7 @@ export const IdentityOciAuthForm = ({
} else {
reset({
tenancyOcid: "",
allowedUsernames: "",
allowedUsernames: undefined,
accessTokenTTL: "2592000",
accessTokenMaxTTL: "2592000",
accessTokenNumUsesLimit: "0",
@@ -161,7 +168,7 @@ export const IdentityOciAuthForm = ({
organizationId: orgId,
identityId,
tenancyOcid,
allowedUsernames: allowedUsernames || "",
allowedUsernames: allowedUsernames || undefined,
accessTokenTTL: Number(accessTokenTTL),
accessTokenMaxTTL: Number(accessTokenMaxTTL),
accessTokenNumUsesLimit: Number(accessTokenNumUsesLimit),

View File

@@ -1,37 +1,33 @@
import { faHome } from '@fortawesome/free-solid-svg-icons'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import {
createFileRoute,
linkOptions,
stripSearchParams,
} from '@tanstack/react-router'
import { zodValidator } from '@tanstack/zod-adapter'
import { z } from 'zod'
import { faHome } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { createFileRoute, linkOptions, stripSearchParams } from "@tanstack/react-router";
import { zodValidator } from "@tanstack/zod-adapter";
import { z } from "zod";
import { SettingsPage } from './SettingsPage'
import { SettingsPage } from "./SettingsPage";
const SettingsPageQueryParams = z.object({
selectedTab: z.string().catch(''),
})
selectedTab: z.string().catch("")
});
export const Route = createFileRoute(
'/_authenticate/_inject-org-details/_org-layout/organization/settings/',
"/_authenticate/_inject-org-details/_org-layout/organization/settings/"
)({
component: SettingsPage,
validateSearch: zodValidator(SettingsPageQueryParams),
search: {
middlewares: [stripSearchParams({ selectedTab: '' })],
middlewares: [stripSearchParams({ selectedTab: "" })]
},
context: () => ({
breadcrumbs: [
{
label: 'Home',
label: "Home",
icon: () => <FontAwesomeIcon icon={faHome} />,
link: linkOptions({ to: '/' }),
link: linkOptions({ to: "/" })
},
{
label: 'Settings',
},
],
}),
})
label: "Settings"
}
]
})
});