mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-08 13:28:27 +00:00
Finish infra for sending raw ACME req, add tests for nonce
This commit is contained in:
@@ -4,3 +4,4 @@ Feature: Account
|
|||||||
Given I have an ACME cert profile as "acme_profile"
|
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
|
When I have an ACME client connecting to {BASE_URL}/api/v1/pki/acme/profiles/{acme_profile.id}/directory
|
||||||
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
|
||||||
|
Then the value acme_account.uri with jq "." should match pattern {BASE_URL}/api/v1/pki/acme/profiles/{acme_profile.id}/accounts/(.+)
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ Feature: ACME Cert Profile
|
|||||||
Scenario: Create a cert profile
|
Scenario: Create a cert profile
|
||||||
Given I make a random slug as profile_slug
|
Given I make a random slug as profile_slug
|
||||||
Given I use AUTH_TOKEN for authentication
|
Given I use AUTH_TOKEN for authentication
|
||||||
When I send a POST request to "/api/v1/pki/certificate-profiles" with JSON payload
|
When I send a "POST" request to "/api/v1/pki/certificate-profiles" with JSON payload
|
||||||
"""
|
"""
|
||||||
{
|
{
|
||||||
"projectId": "{PROJECT_ID}",
|
"projectId": "{PROJECT_ID}",
|
||||||
@@ -25,7 +25,7 @@ Feature: ACME Cert Profile
|
|||||||
Scenario: Reveal EAB secret
|
Scenario: Reveal EAB secret
|
||||||
Given I make a random slug as profile_slug
|
Given I make a random slug as profile_slug
|
||||||
Given I use AUTH_TOKEN for authentication
|
Given I use AUTH_TOKEN for authentication
|
||||||
When I send a POST request to "/api/v1/pki/certificate-profiles" with JSON payload
|
When I send a "POST" request to "/api/v1/pki/certificate-profiles" with JSON payload
|
||||||
"""
|
"""
|
||||||
{
|
{
|
||||||
"projectId": "{PROJECT_ID}",
|
"projectId": "{PROJECT_ID}",
|
||||||
@@ -39,7 +39,7 @@ Feature: ACME Cert Profile
|
|||||||
"""
|
"""
|
||||||
Then the value response.status_code should be equal to 200
|
Then the value response.status_code should be equal to 200
|
||||||
And I memorize response with jq ".certificateProfile.id" as profile_id
|
And I memorize response with jq ".certificateProfile.id" as profile_id
|
||||||
When I send a GET request to "/api/v1/pki/certificate-profiles/{profile_id}/acme/eab-secret/reveal"
|
When I send a "GET" request to "/api/v1/pki/certificate-profiles/{profile_id}/acme/eab-secret/reveal"
|
||||||
Then the value response.status_code should be equal to 200
|
Then the value response.status_code should be equal to 200
|
||||||
Then the value response with jq ".eabKid" should be equal to "{profile_id}"
|
Then the value response with jq ".eabKid" should be equal to "{profile_id}"
|
||||||
Then the value response with jq ".eabSecret" should be present
|
Then the value response with jq ".eabSecret" should be present
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ Feature: Challenge
|
|||||||
Scenario: Validate challenge
|
Scenario: Validate challenge
|
||||||
Given I have an ACME cert profile as "acme_profile"
|
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
|
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
|
When I create certificate signing request as csr
|
||||||
Then I add names to certificate signing request csr
|
Then I add names to certificate signing request csr
|
||||||
@@ -20,4 +19,3 @@ Feature: Challenge
|
|||||||
Then I tell ACME server that challenge is ready to be verified
|
Then I tell ACME server that challenge is ready to be verified
|
||||||
Then I poll and finalize the ACME order order as finalized_order
|
Then I poll and finalize the ACME order order as finalized_order
|
||||||
Then the value finalized_order.body with jq ".status" should be equal to "valid"
|
Then the value finalized_order.body with jq ".status" should be equal to "valid"
|
||||||
# TODO: check the fullchain pem content of the order
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ Feature: Directory
|
|||||||
|
|
||||||
Scenario: Get the directory of ACME service urls
|
Scenario: Get the directory of ACME service urls
|
||||||
Given I have an ACME cert profile as "acme_profile"
|
Given I have an ACME cert profile as "acme_profile"
|
||||||
When I send a GET request to "/api/v1/pki/acme/profiles/{acme_profile.id}/directory"
|
When I send a "GET" request to "/api/v1/pki/acme/profiles/{acme_profile.id}/directory"
|
||||||
Then the response status code should be "200"
|
Then the response status code should be "200"
|
||||||
Then the response body should match JSON value
|
Then the response body should match JSON value
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -2,6 +2,28 @@ Feature: Nonce
|
|||||||
|
|
||||||
Scenario: Generate a new nonce
|
Scenario: Generate a new nonce
|
||||||
Given I have an ACME cert profile as "acme_profile"
|
Given I have an ACME cert profile as "acme_profile"
|
||||||
When I send a HEAD request to "/api/v1/pki/acme/profiles/{acme_profile.id}/new-nonce"
|
When I send a "HEAD" request to "/api/v1/pki/acme/profiles/{acme_profile.id}/new-nonce"
|
||||||
Then the response status code should be "200"
|
Then the response status code should be "200"
|
||||||
Then the response header "Replay-Nonce" should contains non-empty value
|
Then the response header "Replay-Nonce" should contains non-empty value
|
||||||
|
|
||||||
|
Scenario: Send bad nonce
|
||||||
|
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
|
||||||
|
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 memorize acme_account.uri with jq "capture("/(?<id>[^/]+)$") | .id" as account_id
|
||||||
|
When I send a raw ACME request to "/api/v1/pki/acme/profiles/{acme_profile.id}/accounts/{account_id}/orders"
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"protected": {
|
||||||
|
"alg": "RS256",
|
||||||
|
"nonce": "oFvnlFP1wIhRlYS2jTaXbA",
|
||||||
|
"url": "{BASE_URL}/api/v1/pki/acme/profiles/{acme_profile.id}/accounts/{account_id}/orders",
|
||||||
|
"kid": "{acme_account.uri}"
|
||||||
|
},
|
||||||
|
"payload": {}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
Then the value response.status_code should be equal to 400
|
||||||
|
Then the value response with jq ".type" should be equal to "urn:ietf:params:acme:error:badNonce"
|
||||||
|
Then the value response with jq ".status" should be equal to 400
|
||||||
|
Then the value response with jq ".detail" should be equal to "Invalid nonce"
|
||||||
|
|||||||
@@ -3,7 +3,9 @@ import logging
|
|||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import threading
|
import threading
|
||||||
|
import urllib.parse
|
||||||
|
|
||||||
|
import acme.client
|
||||||
import httpx
|
import httpx
|
||||||
import jq
|
import jq
|
||||||
import requests
|
import requests
|
||||||
@@ -12,12 +14,14 @@ from faker import Faker
|
|||||||
from acme import client
|
from acme import client
|
||||||
from acme import messages
|
from acme import messages
|
||||||
from acme import standalone
|
from acme import standalone
|
||||||
|
from acme.jws import Signature
|
||||||
from behave.runner import Context
|
from behave.runner import Context
|
||||||
from behave import given
|
from behave import given
|
||||||
from behave import when
|
from behave import when
|
||||||
from behave import then
|
from behave import then
|
||||||
from josepy.jwk import JWKRSA
|
from josepy.jwk import JWKRSA
|
||||||
from josepy import JSONObjectWithFields
|
from josepy import JSONObjectWithFields
|
||||||
|
from josepy import json_util
|
||||||
from cryptography.hazmat.primitives import serialization
|
from cryptography.hazmat.primitives import serialization
|
||||||
from cryptography.hazmat.primitives.asymmetric import rsa
|
from cryptography.hazmat.primitives.asymmetric import rsa
|
||||||
from cryptography import x509
|
from cryptography import x509
|
||||||
@@ -152,7 +156,7 @@ def step_impl(context: Context, token_var: str):
|
|||||||
context.auth_token = eval_var(context, token_var)
|
context.auth_token = eval_var(context, token_var)
|
||||||
|
|
||||||
|
|
||||||
@when('I send a {method} request to "{url}"')
|
@when('I send a "{method}" request to "{url}"')
|
||||||
def step_impl(context: Context, method: str, url: str):
|
def step_impl(context: Context, method: str, url: str):
|
||||||
logger.debug("Sending %s request to %s", method, url)
|
logger.debug("Sending %s request to %s", method, url)
|
||||||
response = context.http_client.request(
|
response = context.http_client.request(
|
||||||
@@ -166,7 +170,7 @@ def step_impl(context: Context, method: str, url: str):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
@when('I send a {method} request to "{url}" with JSON payload')
|
@when('I send a "{method}" request to "{url}" with JSON payload')
|
||||||
def step_impl(context: Context, method: str, url: str):
|
def step_impl(context: Context, method: str, url: str):
|
||||||
json_payload = json.loads(context.text)
|
json_payload = json.loads(context.text)
|
||||||
json_payload = replace_vars(json_payload, context.vars)
|
json_payload = replace_vars(json_payload, context.vars)
|
||||||
@@ -248,6 +252,43 @@ def step_impl(context: Context, email: str, kid: str, secret: str, account_var:
|
|||||||
context.vars[account_var] = acme_client.new_account(registration)
|
context.vars[account_var] = acme_client.new_account(registration)
|
||||||
|
|
||||||
|
|
||||||
|
def send_raw_acme_req(context: Context, url: str):
|
||||||
|
acme_client = context.acme_client
|
||||||
|
content = json.loads(context.text)
|
||||||
|
protected = replace_vars(content["protected"], context.vars)
|
||||||
|
payload = (
|
||||||
|
replace_vars(content["payload"], context.vars) if "payload" in content else None
|
||||||
|
)
|
||||||
|
alg = acme_client.net.alg
|
||||||
|
encoded_payload = json.dumps(payload).encode() if payload else b""
|
||||||
|
protected_headers = json.dumps(protected)
|
||||||
|
signature = alg.sign(
|
||||||
|
key=acme_client.net.key.key,
|
||||||
|
msg=Signature._msg(protected_headers, encoded_payload),
|
||||||
|
)
|
||||||
|
jws = json.dumps(
|
||||||
|
{
|
||||||
|
"protected": json_util.encode_b64jose(protected_headers.encode()),
|
||||||
|
"payload": json_util.encode_b64jose(encoded_payload),
|
||||||
|
"signature": json_util.encode_b64jose(signature),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
base_url = context.vars["BASE_URL"]
|
||||||
|
url = urllib.parse.urljoin(base_url, replace_vars(url, context.vars))
|
||||||
|
response = acme_client.net._send_request(
|
||||||
|
"POST",
|
||||||
|
url,
|
||||||
|
data=jws,
|
||||||
|
headers={"Content-Type": acme.client.ClientNetwork.JOSE_CONTENT_TYPE},
|
||||||
|
)
|
||||||
|
context.vars["response"] = response
|
||||||
|
|
||||||
|
|
||||||
|
@when('I send a raw ACME request to "{url}"')
|
||||||
|
def step_impl(context: Context, url: str):
|
||||||
|
send_raw_acme_req(context, url)
|
||||||
|
|
||||||
|
|
||||||
@then(
|
@then(
|
||||||
"I submit the certificate signing request PEM {pem_var} certificate order to the ACME server as {order_var}"
|
"I submit the certificate signing request PEM {pem_var} certificate order to the ACME server as {order_var}"
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user