More for new order

This commit is contained in:
Fang-Pen Lin
2025-10-29 17:42:34 -07:00
parent 53555892d4
commit 9ee9aa3261
3 changed files with 61 additions and 39 deletions

View File

@@ -1,10 +1,10 @@
Feature: New Order
Scenario: Create a new order
# Given I have an ACME cert profile as "acme_profile"
# When I have an ACME client connecting to {BASE_URL}/api/v1/pki/acme/profiles/{acme_profile.id}/directory
Given I have an ACME cert profile as "acme_profile"
When I have an ACME client connecting to {BASE_URL}/api/v1/pki/acme/profiles/{acme_profile.id}/directory
# # TODO: make it I have an account already instead?
# Then I register a new ACME account with email fangpen@infisical.com and EAB key id {acme_profile.eab_kid} with secret {acme_profile.eab_secret} as acme_account
Then I register a new ACME account with email fangpen@infisical.com and EAB key id {acme_profile.eab_kid} with secret {acme_profile.eab_secret} as acme_account
When I create certificate signing request as csr
Then I add names to certificate signing request csr
"""
@@ -15,3 +15,4 @@ Feature: New Order
"""
Then I create a RSA private key pair as cert_key
Then I sign the certificate signing request csr with private key cert_key and output it as csr_pem in PEM format
Then I submit the certificate signing request PEM csr_pem certificate order to the ACME server

View File

@@ -98,6 +98,13 @@ def step_impl(context: Context, email: str, kid: str, secret: str, account_var:
context.vars[account_var] = context.acme_client.new_account(registration)
@then(
"I submit the certificate signing request PEM {pem_var} certificate order to the ACME server"
)
def step_impl(context: Context, pem_var: str):
context.acme_order = context.acme_client.new_order(context.vars[pem_var])
@when("I create certificate signing request as {csr_var}")
def step_impl(context: Context, csr_var: str):
context.vars[csr_var] = x509.CertificateSigningRequestBuilder()
@@ -144,5 +151,4 @@ def step_impl(context: Context, csr_var: str, pk_var: str, pem_var: str):
context.vars[csr_var]
.sign(context.vars[pk_var], hashes.SHA256())
.public_bytes(serialization.Encoding.PEM)
.decode("utf-8")
)

View File

@@ -54,7 +54,7 @@ import {
type TPkiAcmeServiceFactoryDep = {
certificateProfileDAL: Pick<TCertificateProfileDALFactory, "findById">;
acmeAccountDAL: Pick<TPkiAcmeAccountDALFactory, "findById" | "findByPublicKey" | "create">;
acmeOrderDAL: Pick<TPkiAcmeOrderDALFactory, "create">;
acmeOrderDAL: Pick<TPkiAcmeOrderDALFactory, "create" | "transaction">;
acmeAuthDAL: Pick<TPkiAcmeAuthDALFactory, "create">;
acmeOrderAuthDAL: Pick<TPkiAcmeOrderAuthDALFactory, "insertMany">;
};
@@ -256,52 +256,67 @@ export const pkiAcmeServiceFactory = ({
accountId: string;
payload: TCreateAcmeOrderPayload;
}): Promise<TAcmeResponse<TCreateAcmeOrderResponse>> => {
const account = await acmeAccountDAL.findById(profileId, accountId)!;
// TODO: check and see if we have existing orders for this account that meet the criteria
// if we do, return the existing order
const order = await acmeOrderDAL.create({
accountId: account.id,
status: AcmeOrderStatus.Pending
const order = await acmeOrderDAL.transaction(async (tx) => {
const account = await acmeAccountDAL.findById(profileId, accountId)!;
const createdOrder = await acmeOrderDAL.create(
{
accountId: account.id,
status: AcmeOrderStatus.Pending
},
tx
);
const authorizations: TPkiAcmeAuths[] = await Promise.all(
payload.identifiers.map(async (identifier) => {
if (identifier.type === AcmeIdentifierType.DNS) {
// TODO: reuse existing authorizations for this identifier if they exist
return await acmeAuthDAL.create({
accountId: account.id,
status: AcmeAuthStatus.Pending,
identifierType: identifier.type,
identifierValue: identifier.value,
// TODO: read config from the profile to get the expiration time instead
expiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000)
});
} else {
throw new AcmeMalformedError({ detail: "Only DNS identifiers are supported" });
}
})
);
await acmeOrderAuthDAL.insertMany(
authorizations.map((auth) => ({
orderId: order.id,
authId: auth.id
}))
);
return { ...createdOrder, authorizations, account };
});
const authorizations: TPkiAcmeAuths[] = await Promise.all(
payload.identifiers.map(async (identifier) => {
if (identifier.type === AcmeIdentifierType.DNS) {
// TODO: reuse existing authorizations for this identifier if they exist
return await acmeAuthDAL.create({
accountId: account.id,
status: AcmeAuthStatus.Pending,
identifierType: identifier.type,
identifierValue: identifier.value,
// TODO: read config from the profile to get the expiration time instead
expiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000)
});
} else {
throw new AcmeMalformedError({ detail: "Only DNS identifiers are supported" });
}
})
);
await acmeOrderAuthDAL.insertMany(
authorizations.map((auth) => ({
orderId: order.id,
authId: auth.id
}))
);
// FIXME: Implement ACME new order creation
const orderId = "FIXME-order-id";
return {
status: 201,
body: {
status: "pending",
// TODO: read config from the profile to get the expiration time instead
expires: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString(),
identifiers: [],
authorizations: [],
finalize: buildUrl(`/api/v1/pki/acme/profiles/${account.profileId}/orders/${orderId}/finalize`)
identifiers: order.authorizations.map((auth) => ({
type: auth.identifierType,
value: auth.identifierValue
})),
authorizations: order.authorizations.map((auth) => ({
id: auth.id,
status: auth.status,
identifier: {
type: auth.identifierType,
value: auth.identifierValue
}
})),
finalize: buildUrl(`/api/v1/pki/acme/profiles/${order.account.profileId}/orders/${order.id}/finalize`)
},
headers: {
Location: buildUrl(`/api/v1/pki/acme/profiles/${account.profileId}/orders/${orderId}`)
Location: buildUrl(`/api/v1/pki/acme/profiles/${order.account.profileId}/orders/${order.id}`)
}
};
};