mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-05 22:26:41 +00:00
More test cases
This commit is contained in:
@@ -14,8 +14,82 @@ Feature: Challenge
|
|||||||
And I create a RSA private key pair as cert_key
|
And I create a RSA private key pair as cert_key
|
||||||
And I sign the certificate signing request csr with private key cert_key and output it as csr_pem in PEM format
|
And I sign the certificate signing request csr with private key cert_key and output it as csr_pem in PEM format
|
||||||
And I submit the certificate signing request PEM csr_pem certificate order to the ACME server as order
|
And I submit the certificate signing request PEM csr_pem certificate order to the ACME server as order
|
||||||
And I select challenge with type http-01 for domain localhost from order at order as challenge
|
And I select challenge with type http-01 for domain localhost from order in order as challenge
|
||||||
And I serve challenge response for challenge at localhost
|
And I serve challenge response for challenge at localhost
|
||||||
And I tell ACME server that challenge is ready to be verified
|
And I tell ACME server that challenge is ready to be verified
|
||||||
And I poll and finalize the ACME order order as finalized_order
|
And I poll and finalize the ACME order order as finalized_order
|
||||||
And the value finalized_order.body with jq ".status" should be equal to "valid"
|
And the value finalized_order.body with jq ".status" should be equal to "valid"
|
||||||
|
|
||||||
|
Scenario: Did not finish all challenges
|
||||||
|
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
|
||||||
|
When I create certificate signing request as csr
|
||||||
|
Then I add names to certificate signing request csr
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"COMMON_NAME": "localhost"
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
And I add subject alternative name to certificate signing request csr
|
||||||
|
"""
|
||||||
|
[
|
||||||
|
"infisical.com"
|
||||||
|
]
|
||||||
|
"""
|
||||||
|
And I create a RSA private key pair as cert_key
|
||||||
|
And I sign the certificate signing request csr with private key cert_key and output it as csr_pem in PEM format
|
||||||
|
And I submit the certificate signing request PEM csr_pem certificate order to the ACME server as order
|
||||||
|
And I select challenge with type http-01 for domain localhost from order in order as challenge
|
||||||
|
And I serve challenge response for challenge at localhost
|
||||||
|
And I tell ACME server that challenge is ready to be verified
|
||||||
|
|
||||||
|
# the localhost auth should be valid
|
||||||
|
And I memorize order with jq ".authorizations | map(select(.body.identifier.value == "localhost")) | first | .uri" as localhost_auth
|
||||||
|
And I peak and memorize the next nonce as nonce
|
||||||
|
When I send a raw ACME request to "{localhost_auth}"
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"protected": {
|
||||||
|
"alg": "RS256",
|
||||||
|
"nonce": "{nonce}",
|
||||||
|
"url": "{localhost_auth}",
|
||||||
|
"kid": "{acme_account.uri}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
Then the value response.status_code should be equal to 200
|
||||||
|
And the value response with jq ".status" should be equal to "valid"
|
||||||
|
|
||||||
|
# the infisical.com auth should still be pending
|
||||||
|
And I memorize order with jq ".authorizations | map(select(.body.identifier.value == "infisical.com")) | first | .uri" as infisical_auth
|
||||||
|
And I memorize response.headers with jq ".["replay-nonce"]" as nonce
|
||||||
|
When I send a raw ACME request to "{infisical_auth}"
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"protected": {
|
||||||
|
"alg": "RS256",
|
||||||
|
"nonce": "{nonce}",
|
||||||
|
"url": "{infisical_auth}",
|
||||||
|
"kid": "{acme_account.uri}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
Then the value response.status_code should be equal to 200
|
||||||
|
And the value response with jq ".status" should be equal to "pending"
|
||||||
|
|
||||||
|
# the order should be pending as well
|
||||||
|
And I memorize response.headers with jq ".["replay-nonce"]" as nonce
|
||||||
|
When I send a raw ACME request to "{order.uri}"
|
||||||
|
"""
|
||||||
|
{
|
||||||
|
"protected": {
|
||||||
|
"alg": "RS256",
|
||||||
|
"nonce": "{nonce}",
|
||||||
|
"url": "{order.uri}",
|
||||||
|
"kid": "{acme_account.uri}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
Then the value response.status_code should be equal to 200
|
||||||
|
And the value response with jq ".status" should be equal to "pending"
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import acme.client
|
|||||||
import httpx
|
import httpx
|
||||||
import jq
|
import jq
|
||||||
import requests
|
import requests
|
||||||
|
import requests.structures
|
||||||
import glom
|
import glom
|
||||||
from faker import Faker
|
from faker import Faker
|
||||||
from acme import client
|
from acme import client
|
||||||
@@ -115,6 +116,8 @@ def eval_var(context: Context, var_path: str, as_json: bool = True):
|
|||||||
value = value.to_json()
|
value = value.to_json()
|
||||||
elif isinstance(value, requests.Response):
|
elif isinstance(value, requests.Response):
|
||||||
value = value.json()
|
value = value.json()
|
||||||
|
elif isinstance(value, requests.structures.CaseInsensitiveDict):
|
||||||
|
value = dict(value.lower_items())
|
||||||
elif isinstance(value, httpx.Response):
|
elif isinstance(value, httpx.Response):
|
||||||
value = value.json()
|
value = value.json()
|
||||||
return value
|
return value
|
||||||
@@ -569,51 +572,58 @@ def step_impl(context: Context, var_path: str):
|
|||||||
print(json.dumps(value.json(), indent=2))
|
print(json.dumps(value.json(), indent=2))
|
||||||
|
|
||||||
|
|
||||||
@then(
|
def select_challenge(
|
||||||
"I select challenge with type {challenge_type} for domain {domain} from order at {var_path} as {challenge_var}"
|
|
||||||
)
|
|
||||||
def step_impl(
|
|
||||||
context: Context,
|
context: Context,
|
||||||
challenge_type: str,
|
challenge_type: str,
|
||||||
|
order_var_path: str,
|
||||||
domain: str,
|
domain: str,
|
||||||
var_path: str,
|
|
||||||
challenge_var: str,
|
|
||||||
):
|
):
|
||||||
order = eval_var(context, var_path, as_json=False)
|
acme_client = context.acme_client
|
||||||
|
order = eval_var(context, order_var_path, as_json=False)
|
||||||
|
if isinstance(order, dict):
|
||||||
|
order_body = messages.Order.from_json(order)
|
||||||
|
order = messages.OrderResource(
|
||||||
|
body=order_body,
|
||||||
|
authorizations=[
|
||||||
|
acme_client._authzr_from_response(
|
||||||
|
acme_client._post_as_get(url), uri=url
|
||||||
|
)
|
||||||
|
for url in order_body.authorizations
|
||||||
|
],
|
||||||
|
)
|
||||||
if not isinstance(order, messages.OrderResource):
|
if not isinstance(order, messages.OrderResource):
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
f"Expected OrderResource but got {type(order)!r} at {var_path!r}"
|
f"Expected OrderResource but got {type(order)!r} at {order_var_path!r}"
|
||||||
)
|
)
|
||||||
auths = list(
|
auths = list(
|
||||||
filter(lambda o: o.body.identifier.value == domain, order.authorizations)
|
filter(lambda o: o.body.identifier.value == domain, order.authorizations)
|
||||||
)
|
)
|
||||||
if not auths:
|
if not auths:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
f"Authorization for domain {domain!r} not found in {var_path!r}"
|
f"Authorization for domain {domain!r} not found in {order_var_path!r}"
|
||||||
)
|
)
|
||||||
if len(auths) > 1:
|
if len(auths) > 1:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
f"More than one order for domain {domain!r} found in {var_path!r}"
|
f"More than one order for domain {domain!r} found in {order_var_path!r}"
|
||||||
)
|
)
|
||||||
auth = auths[0]
|
auth = auths[0]
|
||||||
|
|
||||||
challenges = list(filter(lambda a: a.typ == challenge_type, auth.body.challenges))
|
challenges = list(filter(lambda a: a.typ == challenge_type, auth.body.challenges))
|
||||||
if not challenges:
|
if not challenges:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
f"Authorization type {challenge_type!r} not found in {var_path!r}"
|
f"Authorization type {challenge_type!r} not found in {order_var_path!r}"
|
||||||
)
|
)
|
||||||
if len(challenges) > 1:
|
if len(challenges) > 1:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
f"More than one authorization for type {challenge_type!r} found in {var_path!r}"
|
f"More than one authorization for type {challenge_type!r} found in {order_var_path!r}"
|
||||||
)
|
)
|
||||||
context.vars[challenge_var] = challenges[0]
|
return challenges[0]
|
||||||
|
|
||||||
|
|
||||||
@then("I serve challenge response for {var_path} at {hostname}")
|
def serve_challenge(
|
||||||
def step_impl(context: Context, var_path: str, hostname: str):
|
context: Context,
|
||||||
if hostname != "localhost":
|
challenge: messages.ChallengeBody,
|
||||||
raise ValueError("Currently only localhost is supported")
|
):
|
||||||
challenge = eval_var(context, var_path, as_json=False)
|
|
||||||
response, validation = challenge.response_and_validation(
|
response, validation = challenge.response_and_validation(
|
||||||
context.acme_client.net.key
|
context.acme_client.net.key
|
||||||
)
|
)
|
||||||
@@ -629,14 +639,43 @@ def step_impl(context: Context, var_path: str, hostname: str):
|
|||||||
context.web_server = web_server
|
context.web_server = web_server
|
||||||
|
|
||||||
|
|
||||||
@then("I tell ACME server that {var_path} is ready to be verified")
|
def notify_challenge_ready(context: Context, challenge: messages.ChallengeBody):
|
||||||
def step_impl(context: Context, var_path: str):
|
|
||||||
challenge = eval_var(context, var_path, as_json=False)
|
|
||||||
acme_client = context.acme_client
|
acme_client = context.acme_client
|
||||||
response, validation = challenge.response_and_validation(acme_client.net.key)
|
response, validation = challenge.response_and_validation(acme_client.net.key)
|
||||||
acme_client.answer_challenge(challenge, response)
|
acme_client.answer_challenge(challenge, response)
|
||||||
|
|
||||||
|
|
||||||
|
@then(
|
||||||
|
"I select challenge with type {challenge_type} for domain {domain} from order in {var_path} as {challenge_var}"
|
||||||
|
)
|
||||||
|
def step_impl(
|
||||||
|
context: Context,
|
||||||
|
challenge_type: str,
|
||||||
|
domain: str,
|
||||||
|
var_path: str,
|
||||||
|
challenge_var: str,
|
||||||
|
):
|
||||||
|
challenge = select_challenge(
|
||||||
|
context=context,
|
||||||
|
challenge_type=challenge_type,
|
||||||
|
domain=domain,
|
||||||
|
order_var_path=var_path,
|
||||||
|
)
|
||||||
|
context.vars[challenge_var] = challenge
|
||||||
|
|
||||||
|
|
||||||
|
@then("I serve challenge response for {var_path} at {hostname}")
|
||||||
|
def step_impl(context: Context, var_path: str, hostname: str):
|
||||||
|
challenge = eval_var(context, var_path, as_json=False)
|
||||||
|
serve_challenge(context=context, challenge=challenge)
|
||||||
|
|
||||||
|
|
||||||
|
@then("I tell ACME server that {var_path} is ready to be verified")
|
||||||
|
def step_impl(context: Context, var_path: str):
|
||||||
|
challenge = eval_var(context, var_path, as_json=False)
|
||||||
|
notify_challenge_ready(context=context, challenge=challenge)
|
||||||
|
|
||||||
|
|
||||||
@then("I poll and finalize the ACME order {var_path} as {finalized_var}")
|
@then("I poll and finalize the ACME order {var_path} as {finalized_var}")
|
||||||
def step_impl(context: Context, var_path: str, finalized_var: str):
|
def step_impl(context: Context, var_path: str, finalized_var: str):
|
||||||
order = eval_var(context, var_path, as_json=False)
|
order = eval_var(context, var_path, as_json=False)
|
||||||
|
|||||||
Reference in New Issue
Block a user