Skip to content

Commit 3438b05

Browse files
authored
Replace Python test_recheck_caa with Go TestCAARechecking (#8085)
Replace a python integration test which relies on our "setup_twenty_days_ago" scaffolding with a Go test that uses direct database statements to avoid any need to do clock manipulation. The resulting test is much more verbose, but also (in my opinion) much clearer and significantly faster.
1 parent c0e31f9 commit 3438b05

File tree

3 files changed

+112
-43
lines changed

3 files changed

+112
-43
lines changed

test/integration/common_test.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,23 @@ func delHTTP01Response(token string) error {
9090
return nil
9191
}
9292

93+
func addCAAIssueRecord(host string, issue string) error {
94+
resp, err := http.Post("http://boulder.service.consul:8055/add-caa", "",
95+
bytes.NewBufferString(fmt.Sprintf(`{
96+
"host": "%s",
97+
"policies": [{"tag": "issue", "value": "%s"}]
98+
}`, host, issue)))
99+
if err != nil {
100+
return fmt.Errorf("adding CAA record: %s", err)
101+
}
102+
defer resp.Body.Close()
103+
104+
if resp.StatusCode != http.StatusOK {
105+
return fmt.Errorf("adding CAA record: status %d", resp.StatusCode)
106+
}
107+
return nil
108+
}
109+
93110
func makeClientAndOrder(c *client, csrKey *ecdsa.PrivateKey, idents []acme.Identifier, cn bool, profile string, certToReplace *x509.Certificate) (*client, *acme.Order, error) {
94111
var err error
95112
if c == nil {
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
//go:build integration
2+
3+
package integration
4+
5+
import (
6+
"crypto/ecdsa"
7+
"crypto/elliptic"
8+
"crypto/rand"
9+
"database/sql"
10+
"strings"
11+
"testing"
12+
"time"
13+
14+
"github.com/eggsampler/acme/v3"
15+
"github.com/letsencrypt/boulder/test/vars"
16+
)
17+
18+
func TestCAARechecking(t *testing.T) {
19+
t.Parallel()
20+
21+
domain := randomDomain(t)
22+
idents := []acme.Identifier{{Type: "dns", Value: domain}}
23+
24+
// Create an order and authorization, and fulfill the associated challenge.
25+
// This should put the authz into the "valid" state, since CAA checks passed.
26+
client, err := makeClient()
27+
if err != nil {
28+
t.Fatalf("creating acme client: %s", err)
29+
}
30+
31+
order, err := client.Client.NewOrder(client.Account, idents)
32+
if err != nil {
33+
t.Fatalf("creating order: %s", err)
34+
}
35+
36+
authz, err := client.Client.FetchAuthorization(client.Account, order.Authorizations[0])
37+
if err != nil {
38+
t.Fatalf("fetching authorization: %s", err)
39+
}
40+
41+
chal, ok := authz.ChallengeMap[acme.ChallengeTypeHTTP01]
42+
if !ok {
43+
t.Fatalf("no HTTP challenge found in %#v", authz)
44+
}
45+
46+
err = addHTTP01Response(chal.Token, chal.KeyAuthorization)
47+
if err != nil {
48+
t.Fatalf("setting HTTP-01 challenge token: %s", err)
49+
}
50+
defer delHTTP01Response(chal.Token)
51+
52+
chal, err = client.Client.UpdateChallenge(client.Account, chal)
53+
if err != nil {
54+
t.Fatalf("completing HTTP-01 validation: %s", err)
55+
}
56+
57+
// Manipulate the database so that it looks like the authz was validated
58+
// more than 8 hours ago.
59+
db, err := sql.Open("mysql", vars.DBConnSAIntegrationFullPerms)
60+
if err != nil {
61+
t.Fatalf("sql.Open: %s", err)
62+
}
63+
64+
_, err = db.Exec(`UPDATE authz2 SET attemptedAt = ? WHERE identifierValue = ?`, time.Now().Add(-24*time.Hour).Format(time.DateTime), domain)
65+
if err != nil {
66+
t.Fatalf("updating authz attemptedAt timestamp: %s", err)
67+
}
68+
69+
// Change the CAA record to now forbid issuance.
70+
err = addCAAIssueRecord(domain, ";")
71+
if err != nil {
72+
t.Fatalf("updating CAA record: %s", err)
73+
}
74+
75+
// Try to finalize the order created above. Due to our db manipulation, this
76+
// should trigger a CAA recheck. And due to our challtestsrv manipulation,
77+
// that CAA recheck should fail. Therefore the whole finalize should fail.
78+
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
79+
if err != nil {
80+
t.Fatalf("generating cert key: %s", err)
81+
}
82+
83+
csr, err := makeCSR(key, idents, false)
84+
if err != nil {
85+
t.Fatalf("generating finalize csr: %s", err)
86+
}
87+
88+
_, err = client.Client.FinalizeOrder(client.Account, order, csr)
89+
if err == nil {
90+
t.Errorf("expected finalize to fail, but got success")
91+
}
92+
if !strings.Contains(err.Error(), "CAA") {
93+
t.Errorf("expected finalize to fail due to CAA, but got: %s", err)
94+
}
95+
}

test/v2_integration.py

Lines changed: 0 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1170,49 +1170,6 @@ def test_expiration_mailer():
11701170
if mailcount != 2:
11711171
raise(Exception("\nExpiry mailer failed: expected 2 emails, got %d" % mailcount))
11721172

1173-
caa_recheck_setup_data = {}
1174-
@register_twenty_days_ago
1175-
def caa_recheck_setup():
1176-
client = chisel2.make_client()
1177-
# Issue a certificate with the clock set back, and save the authzs to check
1178-
# later that they are valid (200). They should however require rechecking for
1179-
# CAA purposes.
1180-
numNames = 10
1181-
# Generate numNames subdomains of a random domain
1182-
base_domain = random_domain()
1183-
domains = [ "{0}.{1}".format(str(n),base_domain) for n in range(numNames) ]
1184-
order = chisel2.auth_and_issue(domains, client=client)
1185-
1186-
global caa_recheck_setup_data
1187-
caa_recheck_setup_data = {
1188-
'client': client,
1189-
'authzs': order.authorizations,
1190-
}
1191-
1192-
def test_recheck_caa():
1193-
"""Request issuance for a domain where we have a old cached authz from when CAA
1194-
was good. We'll set a new CAA record forbidding issuance; the CAA should
1195-
recheck CAA and reject the request.
1196-
"""
1197-
if 'authzs' not in caa_recheck_setup_data:
1198-
raise(Exception("CAA authzs not prepared for test_caa"))
1199-
domains = []
1200-
for a in caa_recheck_setup_data['authzs']:
1201-
response = caa_recheck_setup_data['client']._post(a.uri, None)
1202-
if response.status_code != 200:
1203-
raise(Exception("Unexpected response for CAA authz: ",
1204-
response.status_code))
1205-
domain = a.body.identifier.value
1206-
domains.append(domain)
1207-
1208-
# Set a forbidding CAA record on just one domain
1209-
challSrv.add_caa_issue(domains[3], ";")
1210-
1211-
# Request issuance for the previously-issued domain name, which should
1212-
# now be denied due to CAA.
1213-
chisel2.expect_problem("urn:ietf:params:acme:error:caa",
1214-
lambda: chisel2.auth_and_issue(domains, client=caa_recheck_setup_data['client']))
1215-
12161173
def test_caa_good():
12171174
domain = random_domain()
12181175
challSrv.add_caa_issue(domain, "happy-hacker-ca.invalid")

0 commit comments

Comments
 (0)