RA: Use suberrors when rechecking CAA. (#4240)

When Boulder's RA rechecks CAA for a set of authorization identifiers it
should use suberrors to make it easy to identify which of a possible 100
identifiers had a CAA issue at order finalization time.

Updates #4193
Resolves #4235
This commit is contained in:
Daniel McCarney 2019-05-31 18:36:48 -04:00 committed by Jacob Hoffman-Andrews
parent 7dd176e9a4
commit caf655353e
2 changed files with 58 additions and 15 deletions

View File

@ -894,16 +894,37 @@ func (ra *RegistrationAuthorityImpl) recheckCAA(ctx context.Context, authzs []*c
ch <- err
}(authz)
}
var caaFailures []string
for _ = range authzs {
if err := <-ch; berrors.Is(err, berrors.CAA) {
caaFailures = append(caaFailures, err.Error())
} else if err != nil {
return err
var subErrors []berrors.SubBoulderError
for _, authz := range authzs {
err := <-ch
if err != nil {
if bErr, _ := err.(*berrors.BoulderError); berrors.Is(err, berrors.CAA) {
subErrors = append(subErrors, berrors.SubBoulderError{
Identifier: authz.Identifier,
BoulderError: bErr})
} else {
return err
}
}
}
if len(caaFailures) > 0 {
return berrors.CAAError("Rechecking CAA: %v", strings.Join(caaFailures, ", "))
if len(subErrors) > 0 {
var detail string
if len(subErrors) == 1 {
detail = fmt.Sprintf(
"Rechecking CAA for %q: %s",
subErrors[0].Identifier.Value,
subErrors[0].BoulderError.Detail)
} else {
detail = fmt.Sprintf(
"Rechecking CAA for %q and %d more identifiers failed. "+
"Refer to sub-problems for more information",
subErrors[0].Identifier.Value,
len(subErrors)-1)
}
return (&berrors.BoulderError{
Type: berrors.CAA,
Detail: detail,
}).WithSubErrors(subErrors)
}
return nil
}

View File

@ -2063,15 +2063,37 @@ func TestRecheckCAAFail(t *testing.T) {
makeHTTP01Authorization("b.com"),
makeHTTP01Authorization("c.com"),
}
if err := ra.recheckCAA(context.Background(), authzs); err == nil {
t.Errorf("expected err, got nil")
err := ra.recheckCAA(context.Background(), authzs)
if err == nil {
t.Fatalf("expected err, got nil")
} else if !berrors.Is(err, berrors.CAA) {
t.Errorf("expected CAA error, got %T", err)
} else if !strings.Contains(err.Error(), "CAA invalid for a.com") {
t.Errorf("expected error to contain error for a.com, got %q", err)
} else if !strings.Contains(err.Error(), "CAA invalid for c.com") {
t.Errorf("expected error to contain error for c.com, got %q", err)
t.Fatalf("expected CAA error, got %T", err)
}
// NOTE(@cpu): Safe to skip the cast check here because we already checked err
// with `berrors.Is(err, berrors.CAA)`
berr, _ := err.(*berrors.BoulderError)
// There should be two sub errors
test.AssertEquals(t, len(berr.SubErrors), 2)
// The top level error should reference the first failing identifier
if !strings.Contains(berr.Detail, `Rechecking CAA for "a.com" and 1 more identifiers`) {
t.Errorf("expected error to ref first failed identiifer, got %q", err)
}
// There should be a sub error for both a.com and c.com with the correct type
subErrMap := make(map[string]berrors.SubBoulderError, len(berr.SubErrors))
for _, subErr := range berr.SubErrors {
subErrMap[subErr.Identifier.Value] = subErr
}
subErrA, foundA := subErrMap["a.com"]
subErrB, foundB := subErrMap["c.com"]
test.AssertEquals(t, foundA, true)
test.AssertEquals(t, foundB, true)
test.AssertEquals(t, subErrA.Type, berrors.CAA)
test.AssertEquals(t, subErrB.Type, berrors.CAA)
}
func TestRecheckCAAInternalServerError(t *testing.T) {