mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-05 04:26:33 +00:00
review fixes
This commit is contained in:
@@ -17,7 +17,7 @@ export async function up(knex: Knex): Promise<void> {
|
|||||||
t.string("type").notNullable();
|
t.string("type").notNullable();
|
||||||
|
|
||||||
t.string("tenancyOcid").notNullable();
|
t.string("tenancyOcid").notNullable();
|
||||||
t.string("allowedUsernames").notNullable();
|
t.string("allowedUsernames").nullable();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export const IdentityOciAuthsSchema = z.object({
|
|||||||
identityId: z.string().uuid(),
|
identityId: z.string().uuid(),
|
||||||
type: z.string(),
|
type: z.string(),
|
||||||
tenancyOcid: z.string(),
|
tenancyOcid: z.string(),
|
||||||
allowedUsernames: z.string()
|
allowedUsernames: z.string().nullable().optional()
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TIdentityOciAuths = z.infer<typeof IdentityOciAuthsSchema>;
|
export type TIdentityOciAuths = z.infer<typeof IdentityOciAuthsSchema>;
|
||||||
|
|||||||
@@ -1022,7 +1022,7 @@ interface AddIdentityOciAuthEvent {
|
|||||||
metadata: {
|
metadata: {
|
||||||
identityId: string;
|
identityId: string;
|
||||||
tenancyOcid: string;
|
tenancyOcid: string;
|
||||||
allowedUsernames: string;
|
allowedUsernames: string | null;
|
||||||
accessTokenTTL: number;
|
accessTokenTTL: number;
|
||||||
accessTokenMaxTTL: number;
|
accessTokenMaxTTL: number;
|
||||||
accessTokenNumUsesLimit: number;
|
accessTokenNumUsesLimit: number;
|
||||||
@@ -1042,7 +1042,7 @@ interface UpdateIdentityOciAuthEvent {
|
|||||||
metadata: {
|
metadata: {
|
||||||
identityId: string;
|
identityId: string;
|
||||||
tenancyOcid?: string;
|
tenancyOcid?: string;
|
||||||
allowedUsernames?: string;
|
allowedUsernames: string | null;
|
||||||
accessTokenTTL?: number;
|
accessTokenTTL?: number;
|
||||||
accessTokenMaxTTL?: number;
|
accessTokenMaxTTL?: number;
|
||||||
accessTokenNumUsesLimit?: number;
|
accessTokenNumUsesLimit?: number;
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ export const registerIdentityOciAuthRouter = async (server: FastifyZodProvider)
|
|||||||
metadata: {
|
metadata: {
|
||||||
identityId: identityOciAuth.identityId,
|
identityId: identityOciAuth.identityId,
|
||||||
tenancyOcid: identityOciAuth.tenancyOcid,
|
tenancyOcid: identityOciAuth.tenancyOcid,
|
||||||
allowedUsernames: identityOciAuth.allowedUsernames,
|
allowedUsernames: identityOciAuth.allowedUsernames || null,
|
||||||
accessTokenTTL: identityOciAuth.accessTokenTTL,
|
accessTokenTTL: identityOciAuth.accessTokenTTL,
|
||||||
accessTokenMaxTTL: identityOciAuth.accessTokenMaxTTL,
|
accessTokenMaxTTL: identityOciAuth.accessTokenMaxTTL,
|
||||||
accessTokenTrustedIps: identityOciAuth.accessTokenTrustedIps as TIdentityTrustedIp[],
|
accessTokenTrustedIps: identityOciAuth.accessTokenTrustedIps as TIdentityTrustedIp[],
|
||||||
@@ -214,7 +214,8 @@ export const registerIdentityOciAuthRouter = async (server: FastifyZodProvider)
|
|||||||
actorAuthMethod: req.permission.authMethod,
|
actorAuthMethod: req.permission.authMethod,
|
||||||
actorOrgId: req.permission.orgId,
|
actorOrgId: req.permission.orgId,
|
||||||
...req.body,
|
...req.body,
|
||||||
identityId: req.params.identityId
|
identityId: req.params.identityId,
|
||||||
|
allowedUsernames: req.body.allowedUsernames || null
|
||||||
});
|
});
|
||||||
|
|
||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
@@ -225,7 +226,7 @@ export const registerIdentityOciAuthRouter = async (server: FastifyZodProvider)
|
|||||||
metadata: {
|
metadata: {
|
||||||
identityId: identityOciAuth.identityId,
|
identityId: identityOciAuth.identityId,
|
||||||
tenancyOcid: identityOciAuth.tenancyOcid,
|
tenancyOcid: identityOciAuth.tenancyOcid,
|
||||||
allowedUsernames: identityOciAuth.allowedUsernames,
|
allowedUsernames: identityOciAuth.allowedUsernames || null,
|
||||||
accessTokenTTL: identityOciAuth.accessTokenTTL,
|
accessTokenTTL: identityOciAuth.accessTokenTTL,
|
||||||
accessTokenMaxTTL: identityOciAuth.accessTokenMaxTTL,
|
accessTokenMaxTTL: identityOciAuth.accessTokenMaxTTL,
|
||||||
accessTokenTrustedIps: identityOciAuth.accessTokenTrustedIps as TIdentityTrustedIp[],
|
accessTokenTrustedIps: identityOciAuth.accessTokenTrustedIps as TIdentityTrustedIp[],
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||||
import { ForbiddenError } from "@casl/ability";
|
import { ForbiddenError } from "@casl/ability";
|
||||||
|
import { AxiosError } from "axios";
|
||||||
import jwt from "jsonwebtoken";
|
import jwt from "jsonwebtoken";
|
||||||
import RE2 from "re2";
|
import RE2 from "re2";
|
||||||
|
|
||||||
@@ -15,6 +16,7 @@ import { getConfig } from "@app/lib/config/env";
|
|||||||
import { request } from "@app/lib/config/request";
|
import { request } from "@app/lib/config/request";
|
||||||
import { BadRequestError, NotFoundError, PermissionBoundaryError, UnauthorizedError } from "@app/lib/errors";
|
import { BadRequestError, NotFoundError, PermissionBoundaryError, UnauthorizedError } from "@app/lib/errors";
|
||||||
import { extractIPDetails, isValidIpOrCidr } from "@app/lib/ip";
|
import { extractIPDetails, isValidIpOrCidr } from "@app/lib/ip";
|
||||||
|
import { logger } from "@app/lib/logger";
|
||||||
import { blockLocalAndPrivateIpAddresses } from "@app/lib/validator";
|
import { blockLocalAndPrivateIpAddresses } from "@app/lib/validator";
|
||||||
|
|
||||||
import { ActorType, AuthTokenType } from "../auth/auth-type";
|
import { ActorType, AuthTokenType } from "../auth/auth-type";
|
||||||
@@ -60,15 +62,20 @@ export const identityOciAuthServiceFactory = ({
|
|||||||
await blockLocalAndPrivateIpAddresses(headers.host);
|
await blockLocalAndPrivateIpAddresses(headers.host);
|
||||||
|
|
||||||
// Validate OCI host format
|
// 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({
|
throw new BadRequestError({
|
||||||
message: "Invalid OCI host format. Expected format: identity.<region>.oraclecloud.com"
|
message: "Invalid OCI host format. Expected format: identity.<region>.oraclecloud.com"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const { data } = await request.get<TOciGetUserResponse>(`https://${headers.host}/20160918/users/${userOcid}`, {
|
const { data } = await request
|
||||||
headers
|
.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) {
|
if (data.compartmentId !== identityOciAuth.tenancyOcid) {
|
||||||
throw new UnauthorizedError({
|
throw new UnauthorizedError({
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export type TLoginOciAuthDTO = {
|
|||||||
export type TAttachOciAuthDTO = {
|
export type TAttachOciAuthDTO = {
|
||||||
identityId: string;
|
identityId: string;
|
||||||
tenancyOcid: string;
|
tenancyOcid: string;
|
||||||
allowedUsernames: string;
|
allowedUsernames: string | null;
|
||||||
accessTokenTTL: number;
|
accessTokenTTL: number;
|
||||||
accessTokenMaxTTL: number;
|
accessTokenMaxTTL: number;
|
||||||
accessTokenNumUsesLimit: number;
|
accessTokenNumUsesLimit: number;
|
||||||
@@ -23,8 +23,8 @@ export type TAttachOciAuthDTO = {
|
|||||||
|
|
||||||
export type TUpdateOciAuthDTO = {
|
export type TUpdateOciAuthDTO = {
|
||||||
identityId: string;
|
identityId: string;
|
||||||
tenancyOcid?: string;
|
tenancyOcid: string;
|
||||||
allowedUsernames?: string;
|
allowedUsernames: string | null;
|
||||||
accessTokenTTL?: number;
|
accessTokenTTL?: number;
|
||||||
accessTokenMaxTTL?: number;
|
accessTokenMaxTTL?: number;
|
||||||
accessTokenNumUsesLimit?: number;
|
accessTokenNumUsesLimit?: number;
|
||||||
|
|||||||
@@ -9,16 +9,18 @@ export const validateUsernames = z
|
|||||||
.string()
|
.string()
|
||||||
.trim()
|
.trim()
|
||||||
.max(500, "Input exceeds the maximum limit of 500 characters")
|
.max(500, "Input exceeds the maximum limit of 500 characters")
|
||||||
.transform((val) =>
|
.nullish()
|
||||||
val
|
.transform((val) => {
|
||||||
|
if (!val) return [];
|
||||||
|
return val
|
||||||
.split(",")
|
.split(",")
|
||||||
.map((s) => s.trim())
|
.map((s) => s.trim())
|
||||||
.filter(Boolean)
|
.filter(Boolean);
|
||||||
)
|
})
|
||||||
.refine((arr) => arr.every((name) => usernameSchema.safeParse(name).success), {
|
.refine((arr) => arr.every((name) => usernameSchema.safeParse(name).success), {
|
||||||
message: "One or more usernames are invalid"
|
message: "One or more usernames are invalid"
|
||||||
})
|
})
|
||||||
.transform((arr) => arr.join(", "));
|
.transform((arr) => (arr.length > 0 ? arr.join(", ") : null));
|
||||||
|
|
||||||
export const validateTenancy = z
|
export const validateTenancy = z
|
||||||
.string()
|
.string()
|
||||||
|
|||||||
@@ -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**.
|
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.
|
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">
|
||||||
|

|
||||||
|
</Step>
|
||||||
|
<Step title="Select domain">
|
||||||
|
Select the domain in which you want to create the Infisical user account.
|
||||||
|
|
||||||
|

|
||||||
|
</Step>
|
||||||
|
<Step title="Navigate to 'Users'">
|
||||||
|

|
||||||
|
</Step>
|
||||||
|
<Step title="Click 'Create user'">
|
||||||
|

|
||||||
|
</Step>
|
||||||
|
<Step title="Create user">
|
||||||
|
The name, email, and username can be anything.
|
||||||
|
|
||||||
|

|
||||||
|
</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'.
|
||||||
|
|
||||||
|

|
||||||
|
</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'.
|
||||||
|
|
||||||
|

|
||||||
|
</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.
|
||||||
|
|
||||||
|

|
||||||
|
</Step>
|
||||||
|
</Steps>
|
||||||
|
</Accordion>
|
||||||
|
|
||||||
## Guide
|
## Guide
|
||||||
|
|
||||||
In the following steps, we explore how to create and use identities for your workloads and applications on OCI to
|
In the following steps, we explore how to create and use identities for your workloads and applications on OCI to
|
||||||
|
|||||||
@@ -294,7 +294,7 @@ export type IdentityOciAuth = {
|
|||||||
identityId: string;
|
identityId: string;
|
||||||
type: "iam";
|
type: "iam";
|
||||||
tenancyOcid: string;
|
tenancyOcid: string;
|
||||||
allowedUsernames: string;
|
allowedUsernames?: string | null;
|
||||||
accessTokenTTL: number;
|
accessTokenTTL: number;
|
||||||
accessTokenMaxTTL: number;
|
accessTokenMaxTTL: number;
|
||||||
accessTokenNumUsesLimit: number;
|
accessTokenNumUsesLimit: number;
|
||||||
@@ -305,7 +305,7 @@ export type AddIdentityOciAuthDTO = {
|
|||||||
organizationId: string;
|
organizationId: string;
|
||||||
identityId: string;
|
identityId: string;
|
||||||
tenancyOcid: string;
|
tenancyOcid: string;
|
||||||
allowedUsernames: string;
|
allowedUsernames?: string | null;
|
||||||
accessTokenTTL: number;
|
accessTokenTTL: number;
|
||||||
accessTokenMaxTTL: number;
|
accessTokenMaxTTL: number;
|
||||||
accessTokenNumUsesLimit: number;
|
accessTokenNumUsesLimit: number;
|
||||||
@@ -318,7 +318,7 @@ export type UpdateIdentityOciAuthDTO = {
|
|||||||
organizationId: string;
|
organizationId: string;
|
||||||
identityId: string;
|
identityId: string;
|
||||||
tenancyOcid?: string;
|
tenancyOcid?: string;
|
||||||
allowedUsernames?: string;
|
allowedUsernames?: string | null;
|
||||||
accessTokenTTL?: number;
|
accessTokenTTL?: number;
|
||||||
accessTokenMaxTTL?: number;
|
accessTokenMaxTTL?: number;
|
||||||
accessTokenNumUsesLimit?: number;
|
accessTokenNumUsesLimit?: number;
|
||||||
|
|||||||
+12
-5
@@ -29,8 +29,15 @@ import { IdentityFormTab } from "./types";
|
|||||||
|
|
||||||
const schema = z
|
const schema = z
|
||||||
.object({
|
.object({
|
||||||
tenancyOcid: z.string().trim().min(1, "Tenancy OCID is required."),
|
tenancyOcid: z
|
||||||
allowedUsernames: z.string(),
|
.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
|
accessTokenTTL: z
|
||||||
.string()
|
.string()
|
||||||
.refine(
|
.refine(
|
||||||
@@ -110,7 +117,7 @@ export const IdentityOciAuthForm = ({
|
|||||||
if (data) {
|
if (data) {
|
||||||
reset({
|
reset({
|
||||||
tenancyOcid: data.tenancyOcid,
|
tenancyOcid: data.tenancyOcid,
|
||||||
allowedUsernames: data.allowedUsernames,
|
allowedUsernames: data.allowedUsernames || undefined,
|
||||||
accessTokenTTL: String(data.accessTokenTTL),
|
accessTokenTTL: String(data.accessTokenTTL),
|
||||||
accessTokenMaxTTL: String(data.accessTokenMaxTTL),
|
accessTokenMaxTTL: String(data.accessTokenMaxTTL),
|
||||||
accessTokenNumUsesLimit: String(data.accessTokenNumUsesLimit),
|
accessTokenNumUsesLimit: String(data.accessTokenNumUsesLimit),
|
||||||
@@ -125,7 +132,7 @@ export const IdentityOciAuthForm = ({
|
|||||||
} else {
|
} else {
|
||||||
reset({
|
reset({
|
||||||
tenancyOcid: "",
|
tenancyOcid: "",
|
||||||
allowedUsernames: "",
|
allowedUsernames: undefined,
|
||||||
accessTokenTTL: "2592000",
|
accessTokenTTL: "2592000",
|
||||||
accessTokenMaxTTL: "2592000",
|
accessTokenMaxTTL: "2592000",
|
||||||
accessTokenNumUsesLimit: "0",
|
accessTokenNumUsesLimit: "0",
|
||||||
@@ -161,7 +168,7 @@ export const IdentityOciAuthForm = ({
|
|||||||
organizationId: orgId,
|
organizationId: orgId,
|
||||||
identityId,
|
identityId,
|
||||||
tenancyOcid,
|
tenancyOcid,
|
||||||
allowedUsernames: allowedUsernames || "",
|
allowedUsernames: allowedUsernames || undefined,
|
||||||
accessTokenTTL: Number(accessTokenTTL),
|
accessTokenTTL: Number(accessTokenTTL),
|
||||||
accessTokenMaxTTL: Number(accessTokenMaxTTL),
|
accessTokenMaxTTL: Number(accessTokenMaxTTL),
|
||||||
accessTokenNumUsesLimit: Number(accessTokenNumUsesLimit),
|
accessTokenNumUsesLimit: Number(accessTokenNumUsesLimit),
|
||||||
|
|||||||
@@ -1,37 +1,33 @@
|
|||||||
import { faHome } from '@fortawesome/free-solid-svg-icons'
|
import { faHome } from "@fortawesome/free-solid-svg-icons";
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
import {
|
import { createFileRoute, linkOptions, stripSearchParams } from "@tanstack/react-router";
|
||||||
createFileRoute,
|
import { zodValidator } from "@tanstack/zod-adapter";
|
||||||
linkOptions,
|
import { z } from "zod";
|
||||||
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({
|
const SettingsPageQueryParams = z.object({
|
||||||
selectedTab: z.string().catch(''),
|
selectedTab: z.string().catch("")
|
||||||
})
|
});
|
||||||
|
|
||||||
export const Route = createFileRoute(
|
export const Route = createFileRoute(
|
||||||
'/_authenticate/_inject-org-details/_org-layout/organization/settings/',
|
"/_authenticate/_inject-org-details/_org-layout/organization/settings/"
|
||||||
)({
|
)({
|
||||||
component: SettingsPage,
|
component: SettingsPage,
|
||||||
validateSearch: zodValidator(SettingsPageQueryParams),
|
validateSearch: zodValidator(SettingsPageQueryParams),
|
||||||
search: {
|
search: {
|
||||||
middlewares: [stripSearchParams({ selectedTab: '' })],
|
middlewares: [stripSearchParams({ selectedTab: "" })]
|
||||||
},
|
},
|
||||||
context: () => ({
|
context: () => ({
|
||||||
breadcrumbs: [
|
breadcrumbs: [
|
||||||
{
|
{
|
||||||
label: 'Home',
|
label: "Home",
|
||||||
icon: () => <FontAwesomeIcon icon={faHome} />,
|
icon: () => <FontAwesomeIcon icon={faHome} />,
|
||||||
link: linkOptions({ to: '/' }),
|
link: linkOptions({ to: "/" })
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Settings',
|
label: "Settings"
|
||||||
},
|
}
|
||||||
],
|
]
|
||||||
}),
|
})
|
||||||
})
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user