mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-09-22 13:39:35 +00:00
Add challenge
This commit is contained in:
@@ -18,6 +18,7 @@ Feature: Order
|
||||
Then I submit the certificate signing request PEM csr_pem certificate order to the ACME server as order
|
||||
Then the value order.authorizations[0].uri with jq . should match pattern {BASE_URL}/api/v1/pki/acme/profiles/{acme_profile.id}/authorizations/(.+)
|
||||
Then the value order.authorizations[0].body with jq .status should be equal to "pending"
|
||||
Then the value order.authorizations[0].body with jq .challenge should be equal to "pending"
|
||||
Then the value order.authorizations[0].body with jq .identifier should be equal to json
|
||||
"""
|
||||
{
|
||||
|
||||
@@ -186,8 +186,6 @@ export const registerPkiAcmeRouter = async (server: FastifyZodProvider) => {
|
||||
200: DeactivateAcmeAccountResponseSchema
|
||||
}
|
||||
},
|
||||
// TODO: replace with verify ACME signature here instead
|
||||
// onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||
handler: async (req, res) => {
|
||||
const { payload, profileId, accountId } = await validateExistingAccount({
|
||||
req,
|
||||
@@ -223,8 +221,6 @@ export const registerPkiAcmeRouter = async (server: FastifyZodProvider) => {
|
||||
201: AcmeOrderResourceSchema
|
||||
}
|
||||
},
|
||||
// TODO: replace with verify ACME signature here instead
|
||||
// onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||
handler: async (req, res) => {
|
||||
const { profileId, accountId, payload } = await validateExistingAccount({
|
||||
req,
|
||||
@@ -262,8 +258,6 @@ export const registerPkiAcmeRouter = async (server: FastifyZodProvider) => {
|
||||
200: AcmeOrderResourceSchema
|
||||
}
|
||||
},
|
||||
// TODO: replace with verify ACME signature here instead
|
||||
// onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||
handler: async (req, res) => {
|
||||
const { profileId, accountId } = await validateExistingAccount({
|
||||
req,
|
||||
@@ -301,8 +295,6 @@ export const registerPkiAcmeRouter = async (server: FastifyZodProvider) => {
|
||||
200: AcmeOrderResourceSchema
|
||||
}
|
||||
},
|
||||
// TODO: replace with verify ACME signature here instead
|
||||
// onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||
handler: async (req, res) => {
|
||||
const { profileId, accountId, payload } = await validateExistingAccount({
|
||||
req,
|
||||
@@ -378,8 +370,6 @@ export const registerPkiAcmeRouter = async (server: FastifyZodProvider) => {
|
||||
200: z.string()
|
||||
}
|
||||
},
|
||||
// TODO: replace with verify ACME signature here instead
|
||||
// onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||
handler: async (req, res) => {
|
||||
const { profileId, accountId } = await validateExistingAccount({
|
||||
req,
|
||||
@@ -413,8 +403,6 @@ export const registerPkiAcmeRouter = async (server: FastifyZodProvider) => {
|
||||
200: GetAcmeAuthorizationResponseSchema
|
||||
}
|
||||
},
|
||||
// TODO: replace with verify ACME signature here instead
|
||||
// onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||
handler: async (req, res) => {
|
||||
const { profileId, accountId, payload } = await validateExistingAccount({ req });
|
||||
if (payload !== "") {
|
||||
@@ -451,10 +439,16 @@ export const registerPkiAcmeRouter = async (server: FastifyZodProvider) => {
|
||||
200: RespondToAcmeChallengeResponseSchema
|
||||
}
|
||||
},
|
||||
// TODO: replace with verify ACME signature here instead
|
||||
// onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
|
||||
handler: async (req) => {
|
||||
const challenge = await server.services.pkiAcme.respondToAcmeChallenge(req.params.profileId, req.params.authzId);
|
||||
handler: async (req, res) => {
|
||||
const { profileId, accountId, payload } = await validateExistingAccount({ req });
|
||||
if (payload !== "") {
|
||||
throw new AcmeMalformedError({ detail: "Payload should be empty" });
|
||||
}
|
||||
return sendAcmeResponse(
|
||||
res,
|
||||
profileId,
|
||||
await server.services.pkiAcme.respondToAcmeChallenge({ profileId, authzId: req.params.authzId })
|
||||
);
|
||||
return challenge;
|
||||
}
|
||||
});
|
||||
|
||||
13
backend/src/ee/services/pki-acme/pki-acme-challenge-dal.ts
Normal file
13
backend/src/ee/services/pki-acme/pki-acme-challenge-dal.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { TDbClient } from "@app/db";
|
||||
import { TableName } from "@app/db/schemas";
|
||||
import { ormify } from "@app/lib/knex";
|
||||
|
||||
export type TPkiAcmeChallengeDALFactory = ReturnType<typeof pkiAcmeChallengeDALFactory>;
|
||||
|
||||
export const pkiAcmeChallengeDALFactory = (db: TDbClient) => {
|
||||
const pkiAcmeChallengeOrm = ormify(db, TableName.PkiAcmeChallenge);
|
||||
|
||||
return {
|
||||
...pkiAcmeChallengeOrm
|
||||
};
|
||||
};
|
||||
@@ -21,6 +21,12 @@ export enum AcmeAuthStatus {
|
||||
Revoked = "revoked"
|
||||
}
|
||||
|
||||
export enum AcmeChallengeType {
|
||||
HTTP_01 = "http-01",
|
||||
DNS_01 = "dns-01",
|
||||
TLS_ALPN_01 = "tls-alpn-01"
|
||||
}
|
||||
|
||||
export const ProtectedHeaderSchema = z
|
||||
.object({
|
||||
alg: z.string(),
|
||||
@@ -136,7 +142,7 @@ export const GetAcmeAuthorizationResponseSchema = z.object({
|
||||
}),
|
||||
challenges: z.array(
|
||||
z.object({
|
||||
type: z.string(),
|
||||
type: z.enum(Object.values(AcmeChallengeType) as [string, ...string[]]),
|
||||
url: z.string(),
|
||||
status: z.string(),
|
||||
token: z.string(),
|
||||
@@ -146,7 +152,7 @@ export const GetAcmeAuthorizationResponseSchema = z.object({
|
||||
});
|
||||
|
||||
export const RespondToAcmeChallengeResponseSchema = z.object({
|
||||
type: z.string(),
|
||||
type: z.enum(Object.values(AcmeChallengeType) as [string, ...string[]]),
|
||||
url: z.string(),
|
||||
status: z.string(),
|
||||
token: z.string(),
|
||||
|
||||
@@ -15,6 +15,7 @@ import { errors, flattenedVerify, FlattenedVerifyResult, importJWK, JWSHeaderPar
|
||||
import { z, ZodError } from "zod";
|
||||
import { TPkiAcmeAccountDALFactory } from "./pki-acme-account-dal";
|
||||
import { TPkiAcmeAuthDALFactory } from "./pki-acme-auth-dal";
|
||||
import { TPkiAcmeChallengeDALFactory } from "./pki-acme-challenge-dal";
|
||||
import {
|
||||
AcmeAccountDoesNotExistError,
|
||||
AcmeBadPublicKeyError,
|
||||
@@ -28,6 +29,7 @@ import { TPkiAcmeOrderAuthDALFactory } from "./pki-acme-order-auth-dal";
|
||||
import { TPkiAcmeOrderDALFactory } from "./pki-acme-order-dal";
|
||||
import {
|
||||
AcmeAuthStatus,
|
||||
AcmeChallengeType,
|
||||
AcmeIdentifierType,
|
||||
AcmeOrderStatus,
|
||||
CreateAcmeAccountBodySchema,
|
||||
@@ -58,6 +60,7 @@ type TPkiAcmeServiceFactoryDep = {
|
||||
acmeOrderDAL: Pick<TPkiAcmeOrderDALFactory, "create" | "transaction" | "findByAccountAndOrderIdWithAuthorizations">;
|
||||
acmeAuthDAL: Pick<TPkiAcmeAuthDALFactory, "create" | "findByAccountIdAndAuthIdWithChallenges">;
|
||||
acmeOrderAuthDAL: Pick<TPkiAcmeOrderAuthDALFactory, "insertMany">;
|
||||
acmeChallengeDAL: Pick<TPkiAcmeChallengeDALFactory, "create">;
|
||||
};
|
||||
|
||||
export const pkiAcmeServiceFactory = ({
|
||||
@@ -65,7 +68,8 @@ export const pkiAcmeServiceFactory = ({
|
||||
acmeAccountDAL,
|
||||
acmeOrderDAL,
|
||||
acmeAuthDAL,
|
||||
acmeOrderAuthDAL
|
||||
acmeOrderAuthDAL,
|
||||
acmeChallengeDAL
|
||||
}: TPkiAcmeServiceFactoryDep): TPkiAcmeServiceFactory => {
|
||||
const validateAcmeProfile = async (profileId: string): Promise<TCertificateProfileWithConfigs> => {
|
||||
const profile = await certificateProfileDAL.findById(profileId);
|
||||
@@ -376,7 +380,7 @@ export const pkiAcmeServiceFactory = ({
|
||||
payload.identifiers.map(async (identifier) => {
|
||||
if (identifier.type === AcmeIdentifierType.DNS) {
|
||||
// TODO: reuse existing authorizations for this identifier if they exist
|
||||
return await acmeAuthDAL.create(
|
||||
const auth = await acmeAuthDAL.create(
|
||||
{
|
||||
accountId: account.id,
|
||||
status: AcmeAuthStatus.Pending,
|
||||
@@ -391,6 +395,15 @@ export const pkiAcmeServiceFactory = ({
|
||||
},
|
||||
tx
|
||||
);
|
||||
// TODO: support other challenge types here. Currently only HTTP-01 is supported.
|
||||
await acmeChallengeDAL.create(
|
||||
{
|
||||
authId: auth.id,
|
||||
type: AcmeChallengeType.HTTP_01
|
||||
},
|
||||
tx
|
||||
);
|
||||
return auth;
|
||||
} else {
|
||||
throw new AcmeUnsupportedIdentifierError({ detail: "Only DNS identifiers are supported" });
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user