mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-07 23:27:35 +00:00
Add Azure Client Secrets App Connection
This commit is contained in:
@@ -8,6 +8,10 @@ import {
|
|||||||
AzureAppConfigurationConnectionListItemSchema,
|
AzureAppConfigurationConnectionListItemSchema,
|
||||||
SanitizedAzureAppConfigurationConnectionSchema
|
SanitizedAzureAppConfigurationConnectionSchema
|
||||||
} from "@app/services/app-connection/azure-app-configuration";
|
} from "@app/services/app-connection/azure-app-configuration";
|
||||||
|
import {
|
||||||
|
AzureClientSecretsConnectionListItemSchema,
|
||||||
|
SanitizedAzureClientSecretsConnectionSchema
|
||||||
|
} from "@app/services/app-connection/azure-client-secrets";
|
||||||
import {
|
import {
|
||||||
AzureKeyVaultConnectionListItemSchema,
|
AzureKeyVaultConnectionListItemSchema,
|
||||||
SanitizedAzureKeyVaultConnectionSchema
|
SanitizedAzureKeyVaultConnectionSchema
|
||||||
@@ -51,7 +55,8 @@ const SanitizedAppConnectionSchema = z.union([
|
|||||||
...SanitizedVercelConnectionSchema.options,
|
...SanitizedVercelConnectionSchema.options,
|
||||||
...SanitizedPostgresConnectionSchema.options,
|
...SanitizedPostgresConnectionSchema.options,
|
||||||
...SanitizedMsSqlConnectionSchema.options,
|
...SanitizedMsSqlConnectionSchema.options,
|
||||||
...SanitizedCamundaConnectionSchema.options
|
...SanitizedCamundaConnectionSchema.options,
|
||||||
|
...SanitizedAzureClientSecretsConnectionSchema.options
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const AppConnectionOptionsSchema = z.discriminatedUnion("app", [
|
const AppConnectionOptionsSchema = z.discriminatedUnion("app", [
|
||||||
@@ -66,7 +71,8 @@ const AppConnectionOptionsSchema = z.discriminatedUnion("app", [
|
|||||||
VercelConnectionListItemSchema,
|
VercelConnectionListItemSchema,
|
||||||
PostgresConnectionListItemSchema,
|
PostgresConnectionListItemSchema,
|
||||||
MsSqlConnectionListItemSchema,
|
MsSqlConnectionListItemSchema,
|
||||||
CamundaConnectionListItemSchema
|
CamundaConnectionListItemSchema,
|
||||||
|
AzureClientSecretsConnectionListItemSchema
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export const registerAppConnectionRouter = async (server: FastifyZodProvider) => {
|
export const registerAppConnectionRouter = async (server: FastifyZodProvider) => {
|
||||||
|
|||||||
+18
@@ -0,0 +1,18 @@
|
|||||||
|
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
|
||||||
|
import {
|
||||||
|
CreateAzureClientSecretsConnectionSchema,
|
||||||
|
SanitizedAzureClientSecretsConnectionSchema,
|
||||||
|
UpdateAzureClientSecretsConnectionSchema
|
||||||
|
} from "@app/services/app-connection/azure-client-secrets";
|
||||||
|
|
||||||
|
import { registerAppConnectionEndpoints } from "./app-connection-endpoints";
|
||||||
|
|
||||||
|
export const registerAzureClientSecretsConnectionRouter = async (server: FastifyZodProvider) => {
|
||||||
|
registerAppConnectionEndpoints({
|
||||||
|
app: AppConnection.AzureClientSecrets,
|
||||||
|
server,
|
||||||
|
sanitizedResponseSchema: SanitizedAzureClientSecretsConnectionSchema,
|
||||||
|
createSchema: CreateAzureClientSecretsConnectionSchema,
|
||||||
|
updateSchema: UpdateAzureClientSecretsConnectionSchema
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -2,6 +2,7 @@ import { AppConnection } from "@app/services/app-connection/app-connection-enums
|
|||||||
|
|
||||||
import { registerAwsConnectionRouter } from "./aws-connection-router";
|
import { registerAwsConnectionRouter } from "./aws-connection-router";
|
||||||
import { registerAzureAppConfigurationConnectionRouter } from "./azure-app-configuration-connection-router";
|
import { registerAzureAppConfigurationConnectionRouter } from "./azure-app-configuration-connection-router";
|
||||||
|
import { registerAzureClientSecretsConnectionRouter } from "./azure-client-secrets-connection-router";
|
||||||
import { registerAzureKeyVaultConnectionRouter } from "./azure-key-vault-connection-router";
|
import { registerAzureKeyVaultConnectionRouter } from "./azure-key-vault-connection-router";
|
||||||
import { registerCamundaConnectionRouter } from "./camunda-connection-router";
|
import { registerCamundaConnectionRouter } from "./camunda-connection-router";
|
||||||
import { registerDatabricksConnectionRouter } from "./databricks-connection-router";
|
import { registerDatabricksConnectionRouter } from "./databricks-connection-router";
|
||||||
@@ -28,5 +29,6 @@ export const APP_CONNECTION_REGISTER_ROUTER_MAP: Record<AppConnection, (server:
|
|||||||
[AppConnection.Vercel]: registerVercelConnectionRouter,
|
[AppConnection.Vercel]: registerVercelConnectionRouter,
|
||||||
[AppConnection.Postgres]: registerPostgresConnectionRouter,
|
[AppConnection.Postgres]: registerPostgresConnectionRouter,
|
||||||
[AppConnection.MsSql]: registerMsSqlConnectionRouter,
|
[AppConnection.MsSql]: registerMsSqlConnectionRouter,
|
||||||
[AppConnection.Camunda]: registerCamundaConnectionRouter
|
[AppConnection.Camunda]: registerCamundaConnectionRouter,
|
||||||
|
[AppConnection.AzureClientSecrets]: registerAzureClientSecretsConnectionRouter
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ export enum AppConnection {
|
|||||||
GCP = "gcp",
|
GCP = "gcp",
|
||||||
AzureKeyVault = "azure-key-vault",
|
AzureKeyVault = "azure-key-vault",
|
||||||
AzureAppConfiguration = "azure-app-configuration",
|
AzureAppConfiguration = "azure-app-configuration",
|
||||||
|
AzureClientSecrets = "azure-client-secrets",
|
||||||
Humanitec = "humanitec",
|
Humanitec = "humanitec",
|
||||||
TerraformCloud = "terraform-cloud",
|
TerraformCloud = "terraform-cloud",
|
||||||
Vercel = "vercel",
|
Vercel = "vercel",
|
||||||
|
|||||||
@@ -22,6 +22,11 @@ import {
|
|||||||
getAzureAppConfigurationConnectionListItem,
|
getAzureAppConfigurationConnectionListItem,
|
||||||
validateAzureAppConfigurationConnectionCredentials
|
validateAzureAppConfigurationConnectionCredentials
|
||||||
} from "./azure-app-configuration";
|
} from "./azure-app-configuration";
|
||||||
|
import {
|
||||||
|
AzureClientSecretsConnectionMethod,
|
||||||
|
getAzureClientSecretsConnectionListItem,
|
||||||
|
validateAzureClientSecretsConnectionCredentials
|
||||||
|
} from "./azure-client-secrets";
|
||||||
import {
|
import {
|
||||||
AzureKeyVaultConnectionMethod,
|
AzureKeyVaultConnectionMethod,
|
||||||
getAzureKeyVaultConnectionListItem,
|
getAzureKeyVaultConnectionListItem,
|
||||||
@@ -63,7 +68,8 @@ export const listAppConnectionOptions = () => {
|
|||||||
getVercelConnectionListItem(),
|
getVercelConnectionListItem(),
|
||||||
getPostgresConnectionListItem(),
|
getPostgresConnectionListItem(),
|
||||||
getMsSqlConnectionListItem(),
|
getMsSqlConnectionListItem(),
|
||||||
getCamundaConnectionListItem()
|
getCamundaConnectionListItem(),
|
||||||
|
getAzureClientSecretsConnectionListItem()
|
||||||
].sort((a, b) => a.name.localeCompare(b.name));
|
].sort((a, b) => a.name.localeCompare(b.name));
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -122,7 +128,9 @@ const VALIDATE_APP_CONNECTION_CREDENTIALS_MAP: Record<AppConnection, TAppConnect
|
|||||||
[AppConnection.MsSql]: validateSqlConnectionCredentials as TAppConnectionCredentialsValidator,
|
[AppConnection.MsSql]: validateSqlConnectionCredentials as TAppConnectionCredentialsValidator,
|
||||||
[AppConnection.TerraformCloud]: validateTerraformCloudConnectionCredentials as TAppConnectionCredentialsValidator,
|
[AppConnection.TerraformCloud]: validateTerraformCloudConnectionCredentials as TAppConnectionCredentialsValidator,
|
||||||
[AppConnection.Camunda]: validateCamundaConnectionCredentials as TAppConnectionCredentialsValidator,
|
[AppConnection.Camunda]: validateCamundaConnectionCredentials as TAppConnectionCredentialsValidator,
|
||||||
[AppConnection.Vercel]: validateVercelConnectionCredentials as TAppConnectionCredentialsValidator
|
[AppConnection.Vercel]: validateVercelConnectionCredentials as TAppConnectionCredentialsValidator,
|
||||||
|
[AppConnection.AzureClientSecrets]:
|
||||||
|
validateAzureClientSecretsConnectionCredentials as TAppConnectionCredentialsValidator
|
||||||
};
|
};
|
||||||
|
|
||||||
export const validateAppConnectionCredentials = async (
|
export const validateAppConnectionCredentials = async (
|
||||||
@@ -135,6 +143,7 @@ export const getAppConnectionMethodName = (method: TAppConnection["method"]) =>
|
|||||||
return "GitHub App";
|
return "GitHub App";
|
||||||
case AzureKeyVaultConnectionMethod.OAuth:
|
case AzureKeyVaultConnectionMethod.OAuth:
|
||||||
case AzureAppConfigurationConnectionMethod.OAuth:
|
case AzureAppConfigurationConnectionMethod.OAuth:
|
||||||
|
case AzureClientSecretsConnectionMethod.OAuth:
|
||||||
case GitHubConnectionMethod.OAuth:
|
case GitHubConnectionMethod.OAuth:
|
||||||
return "OAuth";
|
return "OAuth";
|
||||||
case AwsConnectionMethod.AccessKey:
|
case AwsConnectionMethod.AccessKey:
|
||||||
@@ -196,5 +205,6 @@ export const TRANSITION_CONNECTION_CREDENTIALS_TO_PLATFORM: Record<
|
|||||||
[AppConnection.MsSql]: transferSqlConnectionCredentialsToPlatform as TAppConnectionTransitionCredentialsToPlatform,
|
[AppConnection.MsSql]: transferSqlConnectionCredentialsToPlatform as TAppConnectionTransitionCredentialsToPlatform,
|
||||||
[AppConnection.TerraformCloud]: platformManagedCredentialsNotSupported,
|
[AppConnection.TerraformCloud]: platformManagedCredentialsNotSupported,
|
||||||
[AppConnection.Camunda]: platformManagedCredentialsNotSupported,
|
[AppConnection.Camunda]: platformManagedCredentialsNotSupported,
|
||||||
[AppConnection.Vercel]: platformManagedCredentialsNotSupported
|
[AppConnection.Vercel]: platformManagedCredentialsNotSupported,
|
||||||
|
[AppConnection.AzureClientSecrets]: platformManagedCredentialsNotSupported
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ export const APP_CONNECTION_NAME_MAP: Record<AppConnection, string> = {
|
|||||||
[AppConnection.GCP]: "GCP",
|
[AppConnection.GCP]: "GCP",
|
||||||
[AppConnection.AzureKeyVault]: "Azure Key Vault",
|
[AppConnection.AzureKeyVault]: "Azure Key Vault",
|
||||||
[AppConnection.AzureAppConfiguration]: "Azure App Configuration",
|
[AppConnection.AzureAppConfiguration]: "Azure App Configuration",
|
||||||
|
[AppConnection.AzureClientSecrets]: "Azure Client Secrets",
|
||||||
[AppConnection.Databricks]: "Databricks",
|
[AppConnection.Databricks]: "Databricks",
|
||||||
[AppConnection.Humanitec]: "Humanitec",
|
[AppConnection.Humanitec]: "Humanitec",
|
||||||
[AppConnection.TerraformCloud]: "Terraform Cloud",
|
[AppConnection.TerraformCloud]: "Terraform Cloud",
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import {
|
|||||||
import { ValidateAwsConnectionCredentialsSchema } from "./aws";
|
import { ValidateAwsConnectionCredentialsSchema } from "./aws";
|
||||||
import { awsConnectionService } from "./aws/aws-connection-service";
|
import { awsConnectionService } from "./aws/aws-connection-service";
|
||||||
import { ValidateAzureAppConfigurationConnectionCredentialsSchema } from "./azure-app-configuration";
|
import { ValidateAzureAppConfigurationConnectionCredentialsSchema } from "./azure-app-configuration";
|
||||||
|
import { ValidateAzureClientSecretsConnectionCredentialsSchema } from "./azure-client-secrets";
|
||||||
import { ValidateAzureKeyVaultConnectionCredentialsSchema } from "./azure-key-vault";
|
import { ValidateAzureKeyVaultConnectionCredentialsSchema } from "./azure-key-vault";
|
||||||
import { ValidateCamundaConnectionCredentialsSchema } from "./camunda";
|
import { ValidateCamundaConnectionCredentialsSchema } from "./camunda";
|
||||||
import { camundaConnectionService } from "./camunda/camunda-connection-service";
|
import { camundaConnectionService } from "./camunda/camunda-connection-service";
|
||||||
@@ -68,7 +69,8 @@ const VALIDATE_APP_CONNECTION_CREDENTIALS_MAP: Record<AppConnection, TValidateAp
|
|||||||
[AppConnection.Vercel]: ValidateVercelConnectionCredentialsSchema,
|
[AppConnection.Vercel]: ValidateVercelConnectionCredentialsSchema,
|
||||||
[AppConnection.Postgres]: ValidatePostgresConnectionCredentialsSchema,
|
[AppConnection.Postgres]: ValidatePostgresConnectionCredentialsSchema,
|
||||||
[AppConnection.MsSql]: ValidateMsSqlConnectionCredentialsSchema,
|
[AppConnection.MsSql]: ValidateMsSqlConnectionCredentialsSchema,
|
||||||
[AppConnection.Camunda]: ValidateCamundaConnectionCredentialsSchema
|
[AppConnection.Camunda]: ValidateCamundaConnectionCredentialsSchema,
|
||||||
|
[AppConnection.AzureClientSecrets]: ValidateAzureClientSecretsConnectionCredentialsSchema
|
||||||
};
|
};
|
||||||
|
|
||||||
export const appConnectionServiceFactory = ({
|
export const appConnectionServiceFactory = ({
|
||||||
|
|||||||
@@ -15,6 +15,12 @@ import {
|
|||||||
TAzureAppConfigurationConnectionInput,
|
TAzureAppConfigurationConnectionInput,
|
||||||
TValidateAzureAppConfigurationConnectionCredentialsSchema
|
TValidateAzureAppConfigurationConnectionCredentialsSchema
|
||||||
} from "./azure-app-configuration";
|
} from "./azure-app-configuration";
|
||||||
|
import {
|
||||||
|
TAzureClientSecretsConnection,
|
||||||
|
TAzureClientSecretsConnectionConfig,
|
||||||
|
TAzureClientSecretsConnectionInput,
|
||||||
|
TValidateAzureClientSecretsConnectionCredentialsSchema
|
||||||
|
} from "./azure-client-secrets";
|
||||||
import {
|
import {
|
||||||
TAzureKeyVaultConnection,
|
TAzureKeyVaultConnection,
|
||||||
TAzureKeyVaultConnectionConfig,
|
TAzureKeyVaultConnectionConfig,
|
||||||
@@ -83,6 +89,7 @@ export type TAppConnection = { id: string } & (
|
|||||||
| TPostgresConnection
|
| TPostgresConnection
|
||||||
| TMsSqlConnection
|
| TMsSqlConnection
|
||||||
| TCamundaConnection
|
| TCamundaConnection
|
||||||
|
| TAzureClientSecretsConnection
|
||||||
);
|
);
|
||||||
|
|
||||||
export type TAppConnectionRaw = NonNullable<Awaited<ReturnType<TAppConnectionDALFactory["findById"]>>>;
|
export type TAppConnectionRaw = NonNullable<Awaited<ReturnType<TAppConnectionDALFactory["findById"]>>>;
|
||||||
@@ -102,6 +109,7 @@ export type TAppConnectionInput = { id: string } & (
|
|||||||
| TPostgresConnectionInput
|
| TPostgresConnectionInput
|
||||||
| TMsSqlConnectionInput
|
| TMsSqlConnectionInput
|
||||||
| TCamundaConnectionInput
|
| TCamundaConnectionInput
|
||||||
|
| TAzureClientSecretsConnectionInput
|
||||||
);
|
);
|
||||||
|
|
||||||
export type TSqlConnectionInput = TPostgresConnectionInput | TMsSqlConnectionInput;
|
export type TSqlConnectionInput = TPostgresConnectionInput | TMsSqlConnectionInput;
|
||||||
@@ -126,7 +134,8 @@ export type TAppConnectionConfig =
|
|||||||
| TTerraformCloudConnectionConfig
|
| TTerraformCloudConnectionConfig
|
||||||
| TVercelConnectionConfig
|
| TVercelConnectionConfig
|
||||||
| TSqlConnectionConfig
|
| TSqlConnectionConfig
|
||||||
| TCamundaConnectionConfig;
|
| TCamundaConnectionConfig
|
||||||
|
| TAzureClientSecretsConnectionConfig;
|
||||||
|
|
||||||
export type TValidateAppConnectionCredentialsSchema =
|
export type TValidateAppConnectionCredentialsSchema =
|
||||||
| TValidateAwsConnectionCredentialsSchema
|
| TValidateAwsConnectionCredentialsSchema
|
||||||
@@ -140,7 +149,8 @@ export type TValidateAppConnectionCredentialsSchema =
|
|||||||
| TValidateMsSqlConnectionCredentialsSchema
|
| TValidateMsSqlConnectionCredentialsSchema
|
||||||
| TValidateCamundaConnectionCredentialsSchema
|
| TValidateCamundaConnectionCredentialsSchema
|
||||||
| TValidateTerraformCloudConnectionCredentialsSchema
|
| TValidateTerraformCloudConnectionCredentialsSchema
|
||||||
| TValidateVercelConnectionCredentialsSchema;
|
| TValidateVercelConnectionCredentialsSchema
|
||||||
|
| TValidateAzureClientSecretsConnectionCredentialsSchema;
|
||||||
|
|
||||||
export type TListAwsConnectionKmsKeys = {
|
export type TListAwsConnectionKmsKeys = {
|
||||||
connectionId: string;
|
connectionId: string;
|
||||||
|
|||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
export enum AzureClientSecretsConnectionMethod {
|
||||||
|
OAuth = "oauth"
|
||||||
|
}
|
||||||
+96
@@ -0,0 +1,96 @@
|
|||||||
|
import { AxiosError, AxiosResponse } from "axios";
|
||||||
|
|
||||||
|
import { getConfig } from "@app/lib/config/env";
|
||||||
|
import { request } from "@app/lib/config/request";
|
||||||
|
import { BadRequestError, InternalServerError } from "@app/lib/errors";
|
||||||
|
import { getAppConnectionMethodName } from "@app/services/app-connection/app-connection-fns";
|
||||||
|
import { IntegrationUrls } from "@app/services/integration-auth/integration-list";
|
||||||
|
|
||||||
|
import { AppConnection } from "../app-connection-enums";
|
||||||
|
import { AzureClientSecretsConnectionMethod } from "./azure-client-secrets-connection-enums";
|
||||||
|
import {
|
||||||
|
ExchangeCodeAzureResponse,
|
||||||
|
TAzureClientSecretsConnectionConfig
|
||||||
|
} from "./azure-client-secrets-connection-types";
|
||||||
|
|
||||||
|
export const getAzureClientSecretsConnectionListItem = () => {
|
||||||
|
const { INF_APP_CONNECTION_AZURE_CLIENT_ID } = getConfig();
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: "Azure Client Secrets" as const,
|
||||||
|
app: AppConnection.AzureClientSecrets as const,
|
||||||
|
methods: Object.values(AzureClientSecretsConnectionMethod) as [AzureClientSecretsConnectionMethod.OAuth],
|
||||||
|
oauthClientId: INF_APP_CONNECTION_AZURE_CLIENT_ID
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const validateAzureClientSecretsConnectionCredentials = async (config: TAzureClientSecretsConnectionConfig) => {
|
||||||
|
const { credentials: inputCredentials, method } = config;
|
||||||
|
|
||||||
|
const { INF_APP_CONNECTION_AZURE_CLIENT_ID, INF_APP_CONNECTION_AZURE_CLIENT_SECRET, SITE_URL } = getConfig();
|
||||||
|
|
||||||
|
if (!INF_APP_CONNECTION_AZURE_CLIENT_ID || !INF_APP_CONNECTION_AZURE_CLIENT_SECRET) {
|
||||||
|
throw new InternalServerError({
|
||||||
|
message: `Azure ${getAppConnectionMethodName(method)} environment variables have not been configured`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let tokenResp: AxiosResponse<ExchangeCodeAzureResponse> | null = null;
|
||||||
|
let tokenError: AxiosError | null = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
tokenResp = await request.post<ExchangeCodeAzureResponse>(
|
||||||
|
IntegrationUrls.AZURE_TOKEN_URL.replace("common", inputCredentials.tenantId || "common"),
|
||||||
|
new URLSearchParams({
|
||||||
|
grant_type: "authorization_code",
|
||||||
|
code: inputCredentials.code,
|
||||||
|
scope: `openid offline_access https://azconfig.io/.default`,
|
||||||
|
client_id: INF_APP_CONNECTION_AZURE_CLIENT_ID,
|
||||||
|
client_secret: INF_APP_CONNECTION_AZURE_CLIENT_SECRET,
|
||||||
|
redirect_uri: `${SITE_URL}/organization/app-connections/azure/oauth/callback`
|
||||||
|
})
|
||||||
|
);
|
||||||
|
} catch (e: unknown) {
|
||||||
|
if (e instanceof AxiosError) {
|
||||||
|
tokenError = e;
|
||||||
|
} else {
|
||||||
|
throw new BadRequestError({
|
||||||
|
message: `Unable to validate connection: verify credentials`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tokenError) {
|
||||||
|
if (tokenError instanceof AxiosError) {
|
||||||
|
throw new BadRequestError({
|
||||||
|
message: `Failed to get access token: ${
|
||||||
|
(tokenError?.response?.data as { error_description?: string })?.error_description || "Unknown error"
|
||||||
|
}`
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
throw new InternalServerError({
|
||||||
|
message: "Failed to get access token"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!tokenResp) {
|
||||||
|
throw new InternalServerError({
|
||||||
|
message: `Failed to get access token: Token was empty with no error`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (method) {
|
||||||
|
case AzureClientSecretsConnectionMethod.OAuth:
|
||||||
|
return {
|
||||||
|
tenantId: inputCredentials.tenantId,
|
||||||
|
accessToken: tokenResp.data.access_token,
|
||||||
|
refreshToken: tokenResp.data.refresh_token,
|
||||||
|
expiresAt: Date.now() + tokenResp.data.expires_in * 1000
|
||||||
|
};
|
||||||
|
default:
|
||||||
|
throw new InternalServerError({
|
||||||
|
message: `Unhandled Azure connection method: ${method as AzureClientSecretsConnectionMethod}`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
+76
@@ -0,0 +1,76 @@
|
|||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { AppConnections } from "@app/lib/api-docs";
|
||||||
|
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
|
||||||
|
import {
|
||||||
|
BaseAppConnectionSchema,
|
||||||
|
GenericCreateAppConnectionFieldsSchema,
|
||||||
|
GenericUpdateAppConnectionFieldsSchema
|
||||||
|
} from "@app/services/app-connection/app-connection-schemas";
|
||||||
|
|
||||||
|
import { AzureClientSecretsConnectionMethod } from "./azure-client-secrets-connection-enums";
|
||||||
|
|
||||||
|
export const AzureClientSecretsConnectionOAuthInputCredentialsSchema = z.object({
|
||||||
|
code: z.string().trim().min(1, "OAuth code required"),
|
||||||
|
tenantId: z.string().trim().optional()
|
||||||
|
});
|
||||||
|
|
||||||
|
export const AzureClientSecretsConnectionOAuthOutputCredentialsSchema = z.object({
|
||||||
|
tenantId: z.string().optional(),
|
||||||
|
accessToken: z.string(),
|
||||||
|
refreshToken: z.string(),
|
||||||
|
expiresAt: z.number()
|
||||||
|
});
|
||||||
|
|
||||||
|
export const ValidateAzureClientSecretsConnectionCredentialsSchema = z.discriminatedUnion("method", [
|
||||||
|
z.object({
|
||||||
|
method: z
|
||||||
|
.literal(AzureClientSecretsConnectionMethod.OAuth)
|
||||||
|
.describe(AppConnections.CREATE(AppConnection.AzureClientSecrets).method),
|
||||||
|
credentials: AzureClientSecretsConnectionOAuthInputCredentialsSchema.describe(
|
||||||
|
AppConnections.CREATE(AppConnection.AzureClientSecrets).credentials
|
||||||
|
)
|
||||||
|
})
|
||||||
|
]);
|
||||||
|
|
||||||
|
export const CreateAzureClientSecretsConnectionSchema = ValidateAzureClientSecretsConnectionCredentialsSchema.and(
|
||||||
|
GenericCreateAppConnectionFieldsSchema(AppConnection.AzureClientSecrets)
|
||||||
|
);
|
||||||
|
|
||||||
|
export const UpdateAzureClientSecretsConnectionSchema = z
|
||||||
|
.object({
|
||||||
|
credentials: AzureClientSecretsConnectionOAuthInputCredentialsSchema.optional().describe(
|
||||||
|
AppConnections.UPDATE(AppConnection.AzureClientSecrets).credentials
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.and(GenericUpdateAppConnectionFieldsSchema(AppConnection.AzureClientSecrets));
|
||||||
|
|
||||||
|
const BaseAzureClientSecretsConnectionSchema = BaseAppConnectionSchema.extend({
|
||||||
|
app: z.literal(AppConnection.AzureClientSecrets)
|
||||||
|
});
|
||||||
|
|
||||||
|
export const AzureClientSecretsConnectionSchema = z.intersection(
|
||||||
|
BaseAzureClientSecretsConnectionSchema,
|
||||||
|
z.discriminatedUnion("method", [
|
||||||
|
z.object({
|
||||||
|
method: z.literal(AzureClientSecretsConnectionMethod.OAuth),
|
||||||
|
credentials: AzureClientSecretsConnectionOAuthOutputCredentialsSchema
|
||||||
|
})
|
||||||
|
])
|
||||||
|
);
|
||||||
|
|
||||||
|
export const SanitizedAzureClientSecretsConnectionSchema = z.discriminatedUnion("method", [
|
||||||
|
BaseAzureClientSecretsConnectionSchema.extend({
|
||||||
|
method: z.literal(AzureClientSecretsConnectionMethod.OAuth),
|
||||||
|
credentials: AzureClientSecretsConnectionOAuthOutputCredentialsSchema.pick({
|
||||||
|
tenantId: true
|
||||||
|
})
|
||||||
|
})
|
||||||
|
]);
|
||||||
|
|
||||||
|
export const AzureClientSecretsConnectionListItemSchema = z.object({
|
||||||
|
name: z.literal("Azure Client Secrets"),
|
||||||
|
app: z.literal(AppConnection.AzureClientSecrets),
|
||||||
|
methods: z.nativeEnum(AzureClientSecretsConnectionMethod).array(),
|
||||||
|
oauthClientId: z.string().optional()
|
||||||
|
});
|
||||||
+41
@@ -0,0 +1,41 @@
|
|||||||
|
import z from "zod";
|
||||||
|
|
||||||
|
import { DiscriminativePick } from "@app/lib/types";
|
||||||
|
|
||||||
|
import { AppConnection } from "../app-connection-enums";
|
||||||
|
import {
|
||||||
|
AzureClientSecretsConnectionOAuthOutputCredentialsSchema,
|
||||||
|
AzureClientSecretsConnectionSchema,
|
||||||
|
CreateAzureClientSecretsConnectionSchema,
|
||||||
|
ValidateAzureClientSecretsConnectionCredentialsSchema
|
||||||
|
} from "./azure-client-secrets-connection-schemas";
|
||||||
|
|
||||||
|
export type TAzureClientSecretsConnection = z.infer<typeof AzureClientSecretsConnectionSchema>;
|
||||||
|
|
||||||
|
export type TAzureClientSecretsConnectionInput = z.infer<typeof CreateAzureClientSecretsConnectionSchema> & {
|
||||||
|
app: AppConnection.AzureClientSecrets;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TValidateAzureClientSecretsConnectionCredentialsSchema =
|
||||||
|
typeof ValidateAzureClientSecretsConnectionCredentialsSchema;
|
||||||
|
|
||||||
|
export type TAzureClientSecretsConnectionConfig = DiscriminativePick<
|
||||||
|
TAzureClientSecretsConnectionInput,
|
||||||
|
"method" | "app" | "credentials"
|
||||||
|
> & {
|
||||||
|
orgId: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ExchangeCodeAzureResponse = {
|
||||||
|
token_type: string;
|
||||||
|
scope: string;
|
||||||
|
expires_in: number;
|
||||||
|
ext_expires_in: number;
|
||||||
|
access_token: string;
|
||||||
|
refresh_token: string;
|
||||||
|
id_token: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TAzureClientSecretsConnectionCredentials = z.infer<
|
||||||
|
typeof AzureClientSecretsConnectionOAuthOutputCredentialsSchema
|
||||||
|
>;
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
export * from "./azure-client-secrets-connection-enums";
|
||||||
|
export * from "./azure-client-secrets-connection-fns";
|
||||||
|
export * from "./azure-client-secrets-connection-schemas";
|
||||||
|
export * from "./azure-client-secrets-connection-types";
|
||||||
@@ -5,6 +5,7 @@ import { AppConnection } from "@app/hooks/api/appConnections/enums";
|
|||||||
import {
|
import {
|
||||||
AwsConnectionMethod,
|
AwsConnectionMethod,
|
||||||
AzureAppConfigurationConnectionMethod,
|
AzureAppConfigurationConnectionMethod,
|
||||||
|
AzureClientSecretsConnectionMethod,
|
||||||
AzureKeyVaultConnectionMethod,
|
AzureKeyVaultConnectionMethod,
|
||||||
CamundaConnectionMethod,
|
CamundaConnectionMethod,
|
||||||
DatabricksConnectionMethod,
|
DatabricksConnectionMethod,
|
||||||
@@ -30,6 +31,10 @@ export const APP_CONNECTION_MAP: Record<AppConnection, { name: string; image: st
|
|||||||
name: "Azure App Configuration",
|
name: "Azure App Configuration",
|
||||||
image: "Microsoft Azure.png"
|
image: "Microsoft Azure.png"
|
||||||
},
|
},
|
||||||
|
[AppConnection.AzureClientSecrets]: {
|
||||||
|
name: "Azure Client Secrets",
|
||||||
|
image: "Microsoft Azure.png"
|
||||||
|
},
|
||||||
[AppConnection.Databricks]: { name: "Databricks", image: "Databricks.png" },
|
[AppConnection.Databricks]: { name: "Databricks", image: "Databricks.png" },
|
||||||
[AppConnection.Humanitec]: { name: "Humanitec", image: "Humanitec.png" },
|
[AppConnection.Humanitec]: { name: "Humanitec", image: "Humanitec.png" },
|
||||||
[AppConnection.TerraformCloud]: { name: "Terraform Cloud", image: "Terraform Cloud.png" },
|
[AppConnection.TerraformCloud]: { name: "Terraform Cloud", image: "Terraform Cloud.png" },
|
||||||
@@ -45,6 +50,7 @@ export const getAppConnectionMethodDetails = (method: TAppConnection["method"])
|
|||||||
return { name: "GitHub App", icon: faGithub };
|
return { name: "GitHub App", icon: faGithub };
|
||||||
case AzureKeyVaultConnectionMethod.OAuth:
|
case AzureKeyVaultConnectionMethod.OAuth:
|
||||||
case AzureAppConfigurationConnectionMethod.OAuth:
|
case AzureAppConfigurationConnectionMethod.OAuth:
|
||||||
|
case AzureClientSecretsConnectionMethod.OAuth:
|
||||||
case GitHubConnectionMethod.OAuth:
|
case GitHubConnectionMethod.OAuth:
|
||||||
return { name: "OAuth", icon: faPassport };
|
return { name: "OAuth", icon: faPassport };
|
||||||
case AwsConnectionMethod.AccessKey:
|
case AwsConnectionMethod.AccessKey:
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ export enum AppConnection {
|
|||||||
GCP = "gcp",
|
GCP = "gcp",
|
||||||
AzureKeyVault = "azure-key-vault",
|
AzureKeyVault = "azure-key-vault",
|
||||||
AzureAppConfiguration = "azure-app-configuration",
|
AzureAppConfiguration = "azure-app-configuration",
|
||||||
|
AzureClientSecrets = "azure-client-secrets",
|
||||||
Databricks = "databricks",
|
Databricks = "databricks",
|
||||||
Humanitec = "humanitec",
|
Humanitec = "humanitec",
|
||||||
TerraformCloud = "terraform-cloud",
|
TerraformCloud = "terraform-cloud",
|
||||||
|
|||||||
@@ -31,6 +31,11 @@ export type TAzureAppConfigurationConnectionOption = TAppConnectionOptionBase &
|
|||||||
oauthClientId?: string;
|
oauthClientId?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type TAzureClientSecretsConnectionOption = TAppConnectionOptionBase & {
|
||||||
|
app: AppConnection.AzureClientSecrets;
|
||||||
|
oauthClientId?: string;
|
||||||
|
};
|
||||||
|
|
||||||
export type TDatabricksConnectionOption = TAppConnectionOptionBase & {
|
export type TDatabricksConnectionOption = TAppConnectionOptionBase & {
|
||||||
app: AppConnection.Databricks;
|
app: AppConnection.Databricks;
|
||||||
};
|
};
|
||||||
@@ -65,6 +70,7 @@ export type TAppConnectionOption =
|
|||||||
| TGcpConnectionOption
|
| TGcpConnectionOption
|
||||||
| TAzureAppConfigurationConnectionOption
|
| TAzureAppConfigurationConnectionOption
|
||||||
| TAzureKeyVaultConnectionOption
|
| TAzureKeyVaultConnectionOption
|
||||||
|
| TAzureClientSecretsConnectionOption
|
||||||
| TDatabricksConnectionOption
|
| TDatabricksConnectionOption
|
||||||
| THumanitecConnectionOption
|
| THumanitecConnectionOption
|
||||||
| TTerraformCloudConnectionOption
|
| TTerraformCloudConnectionOption
|
||||||
@@ -79,6 +85,7 @@ export type TAppConnectionOptionMap = {
|
|||||||
[AppConnection.GCP]: TGcpConnectionOption;
|
[AppConnection.GCP]: TGcpConnectionOption;
|
||||||
[AppConnection.AzureKeyVault]: TAzureKeyVaultConnectionOption;
|
[AppConnection.AzureKeyVault]: TAzureKeyVaultConnectionOption;
|
||||||
[AppConnection.AzureAppConfiguration]: TAzureAppConfigurationConnectionOption;
|
[AppConnection.AzureAppConfiguration]: TAzureAppConfigurationConnectionOption;
|
||||||
|
[AppConnection.AzureClientSecrets]: TAzureClientSecretsConnectionOption;
|
||||||
[AppConnection.Databricks]: TDatabricksConnectionOption;
|
[AppConnection.Databricks]: TDatabricksConnectionOption;
|
||||||
[AppConnection.Humanitec]: THumanitecConnectionOption;
|
[AppConnection.Humanitec]: THumanitecConnectionOption;
|
||||||
[AppConnection.TerraformCloud]: TTerraformCloudConnectionOption;
|
[AppConnection.TerraformCloud]: TTerraformCloudConnectionOption;
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { AppConnection } from "@app/hooks/api/appConnections/enums";
|
||||||
|
import { TRootAppConnection } from "@app/hooks/api/appConnections/types/root-connection";
|
||||||
|
|
||||||
|
export enum AzureClientSecretsConnectionMethod {
|
||||||
|
OAuth = "oauth"
|
||||||
|
}
|
||||||
|
|
||||||
|
export type TAzureClientSecretsConnection = TRootAppConnection & {
|
||||||
|
app: AppConnection.AzureClientSecrets;
|
||||||
|
} & {
|
||||||
|
method: AzureClientSecretsConnectionMethod.OAuth;
|
||||||
|
credentials: {
|
||||||
|
code: string;
|
||||||
|
tenantId?: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -2,6 +2,7 @@ import { AppConnection } from "../enums";
|
|||||||
import { TAppConnectionOption } from "./app-options";
|
import { TAppConnectionOption } from "./app-options";
|
||||||
import { TAwsConnection } from "./aws-connection";
|
import { TAwsConnection } from "./aws-connection";
|
||||||
import { TAzureAppConfigurationConnection } from "./azure-app-configuration-connection";
|
import { TAzureAppConfigurationConnection } from "./azure-app-configuration-connection";
|
||||||
|
import { TAzureClientSecretsConnection } from "./azure-client-secrets-connection";
|
||||||
import { TAzureKeyVaultConnection } from "./azure-key-vault-connection";
|
import { TAzureKeyVaultConnection } from "./azure-key-vault-connection";
|
||||||
import { TCamundaConnection } from "./camunda-connection";
|
import { TCamundaConnection } from "./camunda-connection";
|
||||||
import { TDatabricksConnection } from "./databricks-connection";
|
import { TDatabricksConnection } from "./databricks-connection";
|
||||||
@@ -15,6 +16,7 @@ import { TVercelConnection } from "./vercel-connection";
|
|||||||
|
|
||||||
export * from "./aws-connection";
|
export * from "./aws-connection";
|
||||||
export * from "./azure-app-configuration-connection";
|
export * from "./azure-app-configuration-connection";
|
||||||
|
export * from "./azure-client-secrets-connection";
|
||||||
export * from "./azure-key-vault-connection";
|
export * from "./azure-key-vault-connection";
|
||||||
export * from "./camunda-connection";
|
export * from "./camunda-connection";
|
||||||
export * from "./databricks-connection";
|
export * from "./databricks-connection";
|
||||||
@@ -32,6 +34,7 @@ export type TAppConnection =
|
|||||||
| TGcpConnection
|
| TGcpConnection
|
||||||
| TAzureKeyVaultConnection
|
| TAzureKeyVaultConnection
|
||||||
| TAzureAppConfigurationConnection
|
| TAzureAppConfigurationConnection
|
||||||
|
| TAzureClientSecretsConnection
|
||||||
| TDatabricksConnection
|
| TDatabricksConnection
|
||||||
| THumanitecConnection
|
| THumanitecConnection
|
||||||
| TTerraformCloudConnection
|
| TTerraformCloudConnection
|
||||||
@@ -78,4 +81,5 @@ export type TAppConnectionMap = {
|
|||||||
[AppConnection.Postgres]: TPostgresConnection;
|
[AppConnection.Postgres]: TPostgresConnection;
|
||||||
[AppConnection.MsSql]: TMsSqlConnection;
|
[AppConnection.MsSql]: TMsSqlConnection;
|
||||||
[AppConnection.Camunda]: TCamundaConnection;
|
[AppConnection.Camunda]: TCamundaConnection;
|
||||||
|
[AppConnection.AzureClientSecrets]: TAzureClientSecretsConnection;
|
||||||
};
|
};
|
||||||
|
|||||||
+5
@@ -11,6 +11,7 @@ import { DiscriminativePick } from "@app/types";
|
|||||||
import { AppConnectionHeader } from "../AppConnectionHeader";
|
import { AppConnectionHeader } from "../AppConnectionHeader";
|
||||||
import { AwsConnectionForm } from "./AwsConnectionForm";
|
import { AwsConnectionForm } from "./AwsConnectionForm";
|
||||||
import { AzureAppConfigurationConnectionForm } from "./AzureAppConfigurationConnectionForm";
|
import { AzureAppConfigurationConnectionForm } from "./AzureAppConfigurationConnectionForm";
|
||||||
|
import { AzureClientSecretsConnectionForm } from "./AzureClientSecretsConnectionForm";
|
||||||
import { AzureKeyVaultConnectionForm } from "./AzureKeyVaultConnectionForm";
|
import { AzureKeyVaultConnectionForm } from "./AzureKeyVaultConnectionForm";
|
||||||
import { CamundaConnectionForm } from "./CamundaConnectionForm";
|
import { CamundaConnectionForm } from "./CamundaConnectionForm";
|
||||||
import { DatabricksConnectionForm } from "./DatabricksConnectionForm";
|
import { DatabricksConnectionForm } from "./DatabricksConnectionForm";
|
||||||
@@ -83,6 +84,8 @@ const CreateForm = ({ app, onComplete }: CreateFormProps) => {
|
|||||||
return <MsSqlConnectionForm onSubmit={onSubmit} />;
|
return <MsSqlConnectionForm onSubmit={onSubmit} />;
|
||||||
case AppConnection.Camunda:
|
case AppConnection.Camunda:
|
||||||
return <CamundaConnectionForm onSubmit={onSubmit} />;
|
return <CamundaConnectionForm onSubmit={onSubmit} />;
|
||||||
|
case AppConnection.AzureClientSecrets:
|
||||||
|
return <AzureClientSecretsConnectionForm />;
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unhandled App ${app}`);
|
throw new Error(`Unhandled App ${app}`);
|
||||||
}
|
}
|
||||||
@@ -143,6 +146,8 @@ const UpdateForm = ({ appConnection, onComplete }: UpdateFormProps) => {
|
|||||||
return <MsSqlConnectionForm onSubmit={onSubmit} appConnection={appConnection} />;
|
return <MsSqlConnectionForm onSubmit={onSubmit} appConnection={appConnection} />;
|
||||||
case AppConnection.Camunda:
|
case AppConnection.Camunda:
|
||||||
return <CamundaConnectionForm onSubmit={onSubmit} appConnection={appConnection} />;
|
return <CamundaConnectionForm onSubmit={onSubmit} appConnection={appConnection} />;
|
||||||
|
case AppConnection.AzureClientSecrets:
|
||||||
|
return <AzureClientSecretsConnectionForm appConnection={appConnection} />;
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unhandled App ${(appConnection as TAppConnection).app}`);
|
throw new Error(`Unhandled App ${(appConnection as TAppConnection).app}`);
|
||||||
}
|
}
|
||||||
|
|||||||
+178
@@ -0,0 +1,178 @@
|
|||||||
|
import crypto from "crypto";
|
||||||
|
|
||||||
|
import { useState } from "react";
|
||||||
|
import { Controller, FormProvider, useForm } from "react-hook-form";
|
||||||
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { Button, FormControl, Input, ModalClose, Select, SelectItem } from "@app/components/v2";
|
||||||
|
import { APP_CONNECTION_MAP, getAppConnectionMethodDetails } from "@app/helpers/appConnections";
|
||||||
|
import { isInfisicalCloud } from "@app/helpers/platform";
|
||||||
|
import {
|
||||||
|
AzureClientSecretsConnectionMethod,
|
||||||
|
TAzureClientSecretsConnection,
|
||||||
|
useGetAppConnectionOption
|
||||||
|
} from "@app/hooks/api/appConnections";
|
||||||
|
import { AppConnection } from "@app/hooks/api/appConnections/enums";
|
||||||
|
|
||||||
|
import {
|
||||||
|
genericAppConnectionFieldsSchema,
|
||||||
|
GenericAppConnectionsFields
|
||||||
|
} from "./GenericAppConnectionFields";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
appConnection?: TAzureClientSecretsConnection;
|
||||||
|
};
|
||||||
|
|
||||||
|
const formSchema = genericAppConnectionFieldsSchema.extend({
|
||||||
|
app: z.literal(AppConnection.AzureClientSecrets),
|
||||||
|
method: z.nativeEnum(AzureClientSecretsConnectionMethod),
|
||||||
|
tenantId: z.string().trim().optional()
|
||||||
|
});
|
||||||
|
|
||||||
|
type FormData = z.infer<typeof formSchema>;
|
||||||
|
|
||||||
|
export const AzureClientSecretsConnectionForm = ({ appConnection }: Props) => {
|
||||||
|
const isUpdate = Boolean(appConnection);
|
||||||
|
const [isRedirecting, setIsRedirecting] = useState(false);
|
||||||
|
|
||||||
|
const {
|
||||||
|
option: { oauthClientId },
|
||||||
|
isLoading
|
||||||
|
} = useGetAppConnectionOption(AppConnection.AzureClientSecrets);
|
||||||
|
|
||||||
|
const form = useForm<FormData>({
|
||||||
|
resolver: zodResolver(formSchema),
|
||||||
|
defaultValues: appConnection
|
||||||
|
? {
|
||||||
|
...appConnection,
|
||||||
|
tenantId: appConnection.credentials.tenantId
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
app: AppConnection.AzureClientSecrets,
|
||||||
|
method: AzureClientSecretsConnectionMethod.OAuth
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const {
|
||||||
|
handleSubmit,
|
||||||
|
control,
|
||||||
|
watch,
|
||||||
|
formState: { isSubmitting, isDirty }
|
||||||
|
} = form;
|
||||||
|
|
||||||
|
const selectedMethod = watch("method");
|
||||||
|
|
||||||
|
const onSubmit = (formData: FormData) => {
|
||||||
|
setIsRedirecting(true);
|
||||||
|
const state = crypto.randomBytes(16).toString("hex");
|
||||||
|
localStorage.setItem("latestCSRFToken", state);
|
||||||
|
localStorage.setItem(
|
||||||
|
"azureClientSecretsConnectionFormData",
|
||||||
|
JSON.stringify({ ...formData, connectionId: appConnection?.id })
|
||||||
|
);
|
||||||
|
|
||||||
|
switch (formData.method) {
|
||||||
|
case AzureClientSecretsConnectionMethod.OAuth:
|
||||||
|
window.location.assign(
|
||||||
|
`https://login.microsoftonline.com/${formData.tenantId || "common"}/oauth2/v2.0/authorize?client_id=${oauthClientId}&response_type=code&redirect_uri=${window.location.origin}/organization/app-connections/azure/oauth/callback&response_mode=query&scope=https://azconfig.io/.default%20openid%20offline_access&state=${state}<:>azure-client-secrets`
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error(`Unhandled Azure Connection method: ${(formData as FormData).method}`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let isMissingConfig: boolean;
|
||||||
|
|
||||||
|
switch (selectedMethod) {
|
||||||
|
case AzureClientSecretsConnectionMethod.OAuth:
|
||||||
|
isMissingConfig = !oauthClientId;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error(`Unhandled Azure Connection method: ${selectedMethod}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const methodDetails = getAppConnectionMethodDetails(selectedMethod);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FormProvider {...form}>
|
||||||
|
<form onSubmit={handleSubmit(onSubmit)}>
|
||||||
|
{!isUpdate && <GenericAppConnectionsFields />}
|
||||||
|
|
||||||
|
<Controller
|
||||||
|
name="tenantId"
|
||||||
|
control={control}
|
||||||
|
render={({ field, fieldState: { error } }) => (
|
||||||
|
<FormControl
|
||||||
|
tooltipText="The active Directory (Entra ID) Tenant ID."
|
||||||
|
isError={Boolean(error?.message)}
|
||||||
|
label="Tenant ID"
|
||||||
|
isOptional
|
||||||
|
errorText={error?.message}
|
||||||
|
>
|
||||||
|
<Input {...field} placeholder="e4f34ea5-ad23-4291-8585-66d20d603cc8" />
|
||||||
|
</FormControl>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Controller
|
||||||
|
name="method"
|
||||||
|
control={control}
|
||||||
|
render={({ field: { value, onChange }, fieldState: { error } }) => (
|
||||||
|
<FormControl
|
||||||
|
tooltipText={`The method you would like to use to connect with ${
|
||||||
|
APP_CONNECTION_MAP[AppConnection.AzureClientSecrets].name
|
||||||
|
}. This field cannot be changed after creation.`}
|
||||||
|
errorText={
|
||||||
|
!isLoading && isMissingConfig
|
||||||
|
? `Environment variables have not been configured. ${
|
||||||
|
isInfisicalCloud()
|
||||||
|
? "Please contact Infisical."
|
||||||
|
: `See documentation to configure Azure ${methodDetails.name} Connections.`
|
||||||
|
}`
|
||||||
|
: error?.message
|
||||||
|
}
|
||||||
|
isError={Boolean(error?.message) || isMissingConfig}
|
||||||
|
label="Method"
|
||||||
|
>
|
||||||
|
<Select
|
||||||
|
isDisabled={isUpdate}
|
||||||
|
value={value}
|
||||||
|
onValueChange={(val) => onChange(val)}
|
||||||
|
className="w-full border border-mineshaft-500"
|
||||||
|
position="popper"
|
||||||
|
dropdownContainerClassName="max-w-none"
|
||||||
|
>
|
||||||
|
{Object.values(AzureClientSecretsConnectionMethod).map((method) => {
|
||||||
|
return (
|
||||||
|
<SelectItem value={method} key={method}>
|
||||||
|
{getAppConnectionMethodDetails(method).name}
|
||||||
|
</SelectItem>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Select>
|
||||||
|
</FormControl>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<div className="mt-8 flex items-center">
|
||||||
|
<Button
|
||||||
|
className="mr-4"
|
||||||
|
size="sm"
|
||||||
|
type="submit"
|
||||||
|
colorSchema="secondary"
|
||||||
|
isLoading={isSubmitting || isRedirecting}
|
||||||
|
isDisabled={isSubmitting || (!isUpdate && !isDirty) || isMissingConfig || isRedirecting}
|
||||||
|
>
|
||||||
|
{isUpdate ? "Reconnect to Azure" : "Connect to Azure"}
|
||||||
|
</Button>
|
||||||
|
<ModalClose asChild>
|
||||||
|
<Button colorSchema="secondary" variant="plain">
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
</ModalClose>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</FormProvider>
|
||||||
|
);
|
||||||
|
};
|
||||||
+61
-1
@@ -7,9 +7,11 @@ import { ROUTE_PATHS } from "@app/const/routes";
|
|||||||
import { APP_CONNECTION_MAP } from "@app/helpers/appConnections";
|
import { APP_CONNECTION_MAP } from "@app/helpers/appConnections";
|
||||||
import {
|
import {
|
||||||
AzureAppConfigurationConnectionMethod,
|
AzureAppConfigurationConnectionMethod,
|
||||||
|
AzureClientSecretsConnectionMethod,
|
||||||
AzureKeyVaultConnectionMethod,
|
AzureKeyVaultConnectionMethod,
|
||||||
GitHubConnectionMethod,
|
GitHubConnectionMethod,
|
||||||
TAzureAppConfigurationConnection,
|
TAzureAppConfigurationConnection,
|
||||||
|
TAzureClientSecretsConnection,
|
||||||
TAzureKeyVaultConnection,
|
TAzureKeyVaultConnection,
|
||||||
TGitHubConnection,
|
TGitHubConnection,
|
||||||
useCreateAppConnection,
|
useCreateAppConnection,
|
||||||
@@ -32,18 +34,26 @@ type AzureAppConfigurationFormData = BaseFormData &
|
|||||||
Pick<TAzureAppConfigurationConnection, "name" | "method" | "description"> &
|
Pick<TAzureAppConfigurationConnection, "name" | "method" | "description"> &
|
||||||
Pick<TAzureAppConfigurationConnection["credentials"], "tenantId">;
|
Pick<TAzureAppConfigurationConnection["credentials"], "tenantId">;
|
||||||
|
|
||||||
|
type AzureClientSecretsFormData = BaseFormData &
|
||||||
|
Pick<TAzureClientSecretsConnection, "name" | "method" | "description"> &
|
||||||
|
Pick<TAzureClientSecretsConnection["credentials"], "tenantId">;
|
||||||
|
|
||||||
type FormDataMap = {
|
type FormDataMap = {
|
||||||
[AppConnection.GitHub]: GithubFormData & { app: AppConnection.GitHub };
|
[AppConnection.GitHub]: GithubFormData & { app: AppConnection.GitHub };
|
||||||
[AppConnection.AzureKeyVault]: AzureKeyVaultFormData & { app: AppConnection.AzureKeyVault };
|
[AppConnection.AzureKeyVault]: AzureKeyVaultFormData & { app: AppConnection.AzureKeyVault };
|
||||||
[AppConnection.AzureAppConfiguration]: AzureAppConfigurationFormData & {
|
[AppConnection.AzureAppConfiguration]: AzureAppConfigurationFormData & {
|
||||||
app: AppConnection.AzureAppConfiguration;
|
app: AppConnection.AzureAppConfiguration;
|
||||||
};
|
};
|
||||||
|
[AppConnection.AzureClientSecrets]: AzureClientSecretsFormData & {
|
||||||
|
app: AppConnection.AzureClientSecrets;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const formDataStorageFieldMap: Partial<Record<AppConnection, string>> = {
|
const formDataStorageFieldMap: Partial<Record<AppConnection, string>> = {
|
||||||
[AppConnection.GitHub]: "githubConnectionFormData",
|
[AppConnection.GitHub]: "githubConnectionFormData",
|
||||||
[AppConnection.AzureKeyVault]: "azureKeyVaultConnectionFormData",
|
[AppConnection.AzureKeyVault]: "azureKeyVaultConnectionFormData",
|
||||||
[AppConnection.AzureAppConfiguration]: "azureAppConfigurationConnectionFormData"
|
[AppConnection.AzureAppConfiguration]: "azureAppConfigurationConnectionFormData",
|
||||||
|
[AppConnection.AzureClientSecrets]: "azureClientSecretsConnectionFormData"
|
||||||
};
|
};
|
||||||
|
|
||||||
export const OAuthCallbackPage = () => {
|
export const OAuthCallbackPage = () => {
|
||||||
@@ -194,6 +204,54 @@ export const OAuthCallbackPage = () => {
|
|||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const handleAzureClientSecrets = useCallback(async () => {
|
||||||
|
const formData = getFormData(AppConnection.AzureClientSecrets);
|
||||||
|
if (formData === null) return null;
|
||||||
|
|
||||||
|
clearState(AppConnection.AzureClientSecrets);
|
||||||
|
|
||||||
|
const { connectionId, name, description, returnUrl } = formData;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (connectionId) {
|
||||||
|
await updateAppConnection.mutateAsync({
|
||||||
|
app: AppConnection.AzureClientSecrets,
|
||||||
|
connectionId,
|
||||||
|
credentials: {
|
||||||
|
code: code as string,
|
||||||
|
tenantId: formData.tenantId
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await createAppConnection.mutateAsync({
|
||||||
|
app: AppConnection.AzureClientSecrets,
|
||||||
|
name,
|
||||||
|
description,
|
||||||
|
method: AzureClientSecretsConnectionMethod.OAuth,
|
||||||
|
credentials: {
|
||||||
|
code: code as string,
|
||||||
|
tenantId: formData.tenantId
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (err: any) {
|
||||||
|
createNotification({
|
||||||
|
title: `Failed to ${connectionId ? "update" : "add"} Azure Client Secrets Connection`,
|
||||||
|
text: err?.message,
|
||||||
|
type: "error"
|
||||||
|
});
|
||||||
|
navigate({
|
||||||
|
to: returnUrl ?? "/organization/app-connections"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
connectionId,
|
||||||
|
returnUrl,
|
||||||
|
appConnectionName: formData.app
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
const handleGithub = useCallback(async () => {
|
const handleGithub = useCallback(async () => {
|
||||||
const formData = getFormData(AppConnection.GitHub);
|
const formData = getFormData(AppConnection.GitHub);
|
||||||
if (formData === null) return null;
|
if (formData === null) return null;
|
||||||
@@ -280,6 +338,8 @@ export const OAuthCallbackPage = () => {
|
|||||||
data = await handleAzureKeyVault();
|
data = await handleAzureKeyVault();
|
||||||
} else if (appConnection === AppConnection.AzureAppConfiguration) {
|
} else if (appConnection === AppConnection.AzureAppConfiguration) {
|
||||||
data = await handleAzureAppConfiguration();
|
data = await handleAzureAppConfiguration();
|
||||||
|
} else if (appConnection === AppConnection.AzureClientSecrets) {
|
||||||
|
data = await handleAzureClientSecrets();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data) {
|
if (data) {
|
||||||
|
|||||||
Reference in New Issue
Block a user