mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-10-09 21:14:22 +00:00
fix(ui): wire certificate errors, cap client-side, harden the self-signed cert
This commit is contained in:
+2
-2
@@ -78,13 +78,13 @@ describe("AzureCertificateCredentialsForm browser flow", () => {
|
||||
view.getByRole("link", { name: "Deploy to Azure" }).element(),
|
||||
).toHaveAttribute(
|
||||
"href",
|
||||
"https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fdocs.prowler.com%2Fassets%2Ftemplates%2Fazure%2Fprowler-scan.json",
|
||||
"https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Fprowler-cloud%2Fprowler%2Fmaster%2Fpermissions%2Ftemplates%2Fazure%2Fbicep%2Fprowler-scan.json",
|
||||
);
|
||||
expect(
|
||||
view.getByRole("link", { name: "Open template" }).element(),
|
||||
).toHaveAttribute(
|
||||
"href",
|
||||
"https://docs.prowler.com/assets/templates/azure/prowler-scan.json",
|
||||
"https://raw.githubusercontent.com/prowler-cloud/prowler/master/permissions/templates/azure/bicep/prowler-scan.json",
|
||||
);
|
||||
|
||||
await view.getByRole("button", { name: "Generate certificate" }).click();
|
||||
|
||||
+3
-3
@@ -36,7 +36,7 @@ describe("AzureCertificateCredentialsForm", () => {
|
||||
expect(link).toHaveAttribute("rel", "noopener noreferrer");
|
||||
expect(link).toHaveAttribute(
|
||||
"href",
|
||||
"https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fdocs.prowler.com%2Fassets%2Ftemplates%2Fazure%2Fprowler-scan.json",
|
||||
"https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Fprowler-cloud%2Fprowler%2Fmaster%2Fpermissions%2Ftemplates%2Fazure%2Fbicep%2Fprowler-scan.json",
|
||||
);
|
||||
});
|
||||
|
||||
@@ -48,7 +48,7 @@ describe("AzureCertificateCredentialsForm", () => {
|
||||
const link = screen.getByRole("link", { name: "Open template" });
|
||||
expect(link).toHaveAttribute(
|
||||
"href",
|
||||
"https://docs.prowler.com/assets/templates/azure/prowler-scan.json",
|
||||
"https://raw.githubusercontent.com/prowler-cloud/prowler/master/permissions/templates/azure/bicep/prowler-scan.json",
|
||||
);
|
||||
expect(link).toHaveAttribute("target", "_blank");
|
||||
expect(link).toHaveAttribute("rel", "noopener noreferrer");
|
||||
@@ -83,7 +83,7 @@ describe("AzureCertificateCredentialsForm", () => {
|
||||
},
|
||||
{
|
||||
element: screen.getByRole("link", { name: "Open template" }),
|
||||
href: "https://docs.prowler.com/assets/templates/azure/prowler-scan.json",
|
||||
href: "https://raw.githubusercontent.com/prowler-cloud/prowler/master/permissions/templates/azure/bicep/prowler-scan.json",
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
@@ -20,8 +20,10 @@
|
||||
import "reflect-metadata";
|
||||
|
||||
import {
|
||||
BasicConstraintsExtension,
|
||||
cryptoProvider,
|
||||
Extension,
|
||||
KeyUsageFlags,
|
||||
KeyUsagesExtension,
|
||||
X509CertificateGenerator,
|
||||
} from "@peculiar/x509";
|
||||
|
||||
@@ -131,7 +133,13 @@ export async function generateProwlerCertificate(
|
||||
hash: "SHA-256",
|
||||
},
|
||||
keys: keyPair,
|
||||
extensions: [] as Extension[],
|
||||
// Match `openssl x509 -req` defaults: mark the leaf as end-entity
|
||||
// (`cA=false`) and declare `digitalSignature` so audit tooling and
|
||||
// strict CA validators don't flag the certificate as unusual.
|
||||
extensions: [
|
||||
new BasicConstraintsExtension(false, undefined, true),
|
||||
new KeyUsagesExtension(KeyUsageFlags.digitalSignature, true),
|
||||
],
|
||||
});
|
||||
|
||||
const certPem = cert.toString("pem");
|
||||
|
||||
@@ -16,6 +16,8 @@ export const PROVIDER_CREDENTIALS_ERROR_MAPPING: Record<string, string> = {
|
||||
[ErrorPointers.AWS_SESSION_TOKEN]: ProviderCredentialFields.AWS_SESSION_TOKEN,
|
||||
[ErrorPointers.CLIENT_ID]: ProviderCredentialFields.CLIENT_ID,
|
||||
[ErrorPointers.CLIENT_SECRET]: ProviderCredentialFields.CLIENT_SECRET,
|
||||
[ErrorPointers.CERTIFICATE_CONTENT]:
|
||||
ProviderCredentialFields.CERTIFICATE_CONTENT,
|
||||
[ErrorPointers.USER]: ProviderCredentialFields.USER,
|
||||
[ErrorPointers.PASSWORD]: ProviderCredentialFields.PASSWORD,
|
||||
[ErrorPointers.TENANT_ID]: ProviderCredentialFields.TENANT_ID,
|
||||
|
||||
@@ -294,10 +294,10 @@ describe("getAzureDeploymentQuickLink", () => {
|
||||
|
||||
// Then
|
||||
expect(PROWLER_AZURE_ARM_TEMPLATE_URL).toBe(
|
||||
"https://docs.prowler.com/assets/templates/azure/prowler-scan.json",
|
||||
"https://raw.githubusercontent.com/prowler-cloud/prowler/master/permissions/templates/azure/bicep/prowler-scan.json",
|
||||
);
|
||||
expect(url).toBe(
|
||||
"https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fdocs.prowler.com%2Fassets%2Ftemplates%2Fazure%2Fprowler-scan.json",
|
||||
"https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Fprowler-cloud%2Fprowler%2Fmaster%2Fpermissions%2Ftemplates%2Fazure%2Fbicep%2Fprowler-scan.json",
|
||||
);
|
||||
expect(url).not.toContain("localhost");
|
||||
expect(url).not.toContain("prowler-cloud-public.s3");
|
||||
|
||||
@@ -40,8 +40,12 @@ export const getAttackPathHubUrl = (queryId: string): string =>
|
||||
export const PROWLER_CF_TEMPLATE_URL =
|
||||
"https://prowler-cloud-public.s3.eu-west-1.amazonaws.com/permissions/templates/aws/cloudformation/prowler-scan-role.yml";
|
||||
|
||||
// Stopgap: point the Azure Portal at the raw template on GitHub until the
|
||||
// docs deploy publishes the file under `docs.prowler.com/assets/...`.
|
||||
// The Portal fetches this URL over HTTPS, so `raw.githubusercontent.com`
|
||||
// works exactly the same for the Deploy-to-Azure flow.
|
||||
export const PROWLER_AZURE_ARM_TEMPLATE_URL =
|
||||
"https://docs.prowler.com/assets/templates/azure/prowler-scan.json";
|
||||
"https://raw.githubusercontent.com/prowler-cloud/prowler/master/permissions/templates/azure/bicep/prowler-scan.json";
|
||||
|
||||
// Prowler Cloud billing/subscription management page.
|
||||
export const BILLING_URL = "https://cloud.prowler.com/billing";
|
||||
|
||||
@@ -1640,7 +1640,7 @@ export class ProvidersPage extends BasePage {
|
||||
}),
|
||||
).toHaveAttribute(
|
||||
"href",
|
||||
"https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fdocs.prowler.com%2Fassets%2Ftemplates%2Fazure%2Fprowler-scan.json",
|
||||
"https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Fprowler-cloud%2Fprowler%2Fmaster%2Fpermissions%2Ftemplates%2Fazure%2Fbicep%2Fprowler-scan.json",
|
||||
);
|
||||
await expect(
|
||||
this.page.getByRole("link", {
|
||||
@@ -1649,7 +1649,7 @@ export class ProvidersPage extends BasePage {
|
||||
}),
|
||||
).toHaveAttribute(
|
||||
"href",
|
||||
"https://docs.prowler.com/assets/templates/azure/prowler-scan.json",
|
||||
"https://raw.githubusercontent.com/prowler-cloud/prowler/master/permissions/templates/azure/bicep/prowler-scan.json",
|
||||
);
|
||||
await expect(
|
||||
this.page.getByRole("button", { name: "Generate certificate" }),
|
||||
|
||||
@@ -7,6 +7,16 @@ import { MAX_SAML_ADDITIONAL_EMAIL_DOMAINS } from "@/types/saml";
|
||||
|
||||
import { PROVIDER_TYPES, ProviderType } from "./providers";
|
||||
|
||||
// Matches the API's `_MAX_CERTIFICATE_CONTENT_LENGTH` in
|
||||
// `api/src/backend/api/v1/serializers.py`, i.e. base64 of the SDK's 50 KiB
|
||||
// `_MAX_CERTIFICATE_BUNDLE_BYTES` cap. Reject oversized certificate
|
||||
// content client-side so the user sees the error inline before a
|
||||
// round-trip that the API would 400 with the same message.
|
||||
export const MAX_CERTIFICATE_CONTENT_LENGTH = 68268;
|
||||
|
||||
export const CERTIFICATE_CONTENT_MAX_SIZE_ERROR =
|
||||
"Certificate content exceeds the maximum size.";
|
||||
|
||||
export const KUBECONFIG_UNSUPPORTED_COMMAND_AUTHENTICATION_ERROR =
|
||||
"Kubernetes kubeconfig command-based authentication is not supported in Prowler Cloud for security reasons.";
|
||||
|
||||
@@ -241,6 +251,10 @@ export const addCredentialsFormSchema = (
|
||||
[ProviderCredentialFields.CLIENT_SECRET]: z.string().optional(),
|
||||
[ProviderCredentialFields.CERTIFICATE_CONTENT]: z
|
||||
.string()
|
||||
.max(
|
||||
MAX_CERTIFICATE_CONTENT_LENGTH,
|
||||
CERTIFICATE_CONTENT_MAX_SIZE_ERROR,
|
||||
)
|
||||
.optional(),
|
||||
[ProviderCredentialFields.TENANT_ID]: z.guid({
|
||||
error: "Tenant ID must be a valid GUID",
|
||||
@@ -284,6 +298,10 @@ export const addCredentialsFormSchema = (
|
||||
.optional(),
|
||||
[ProviderCredentialFields.CERTIFICATE_CONTENT]: z
|
||||
.string()
|
||||
.max(
|
||||
MAX_CERTIFICATE_CONTENT_LENGTH,
|
||||
CERTIFICATE_CONTENT_MAX_SIZE_ERROR,
|
||||
)
|
||||
.optional(),
|
||||
[ProviderCredentialFields.TENANT_ID]: z
|
||||
.string()
|
||||
|
||||
Reference in New Issue
Block a user