move ProblemDetails into its own package

Part of #1161
This commit is contained in:
Jeff Hodges 2015-11-20 20:29:56 -08:00
parent fab8bec525
commit 2114f5d5cc
12 changed files with 149 additions and 132 deletions

View File

@ -19,6 +19,7 @@ import (
"time"
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/letsencrypt/go-jose"
"github.com/letsencrypt/boulder/probs"
)
// AcmeStatus defines the state of a given authorization
@ -36,16 +37,6 @@ type IdentifierType string
// OCSPStatus defines the state of OCSP for a domain
type OCSPStatus string
// ProblemType defines the error types in the ACME protocol
type ProblemType string
// ProblemDetails objects represent problem documents
// https://tools.ietf.org/html/draft-ietf-appsawg-http-problem-00
type ProblemDetails struct {
Type ProblemType `json:"type,omitempty"`
Detail string `json:"detail,omitempty"`
}
// These statuses are the states of authorizations
const (
StatusUnknown = AcmeStatus("unknown") // Unknown status; the default
@ -77,18 +68,6 @@ const (
OCSPStatusRevoked = OCSPStatus("revoked")
)
// Error types that can be used in ACME payloads
const (
ConnectionProblem = ProblemType("urn:acme:error:connection")
MalformedProblem = ProblemType("urn:acme:error:malformed")
ServerInternalProblem = ProblemType("urn:acme:error:serverInternal")
TLSProblem = ProblemType("urn:acme:error:tls")
UnauthorizedProblem = ProblemType("urn:acme:error:unauthorized")
UnknownHostProblem = ProblemType("urn:acme:error:unknownHost")
RateLimitedProblem = ProblemType("urn:acme:error:rateLimited")
BadNonceProblem = ProblemType("urn:acme:error:badNonce")
)
// These types are the available challenges
const (
ChallengeTypeSimpleHTTP = "simpleHttp"
@ -125,10 +104,6 @@ const TLSSNISuffix = "acme.invalid"
// DNSPrefix is attached to DNS names in DNS challenges
const DNSPrefix = "_acme-challenge"
func (pd *ProblemDetails) Error() string {
return fmt.Sprintf("%s :: %s", pd.Type, pd.Detail)
}
// An AcmeIdentifier encodes an identifier that can
// be validated by ACME. The protocol allows for different
// types of identifier to be supported (DNS names, IP
@ -329,7 +304,7 @@ type Challenge struct {
Status AcmeStatus `json:"status,omitempty"`
// Contains the error that occured during challenge validation, if any
Error *ProblemDetails `json:"error,omitempty"`
Error *probs.ProblemDetails `json:"error,omitempty"`
// If successful, the time at which this challenge
// was completed by the server.

View File

@ -17,13 +17,6 @@ import (
"github.com/letsencrypt/boulder/test"
)
func TestProblemDetails(t *testing.T) {
pd := &ProblemDetails{
Type: MalformedProblem,
Detail: "Wat? o.O"}
test.AssertEquals(t, pd.Error(), "urn:acme:error:malformed :: Wat? o.O")
}
func TestRegistrationUpdate(t *testing.T) {
oldURL, _ := ParseAcmeURL("http://old.invalid")
newURL, _ := ParseAcmeURL("http://new.invalid")

View File

@ -3,7 +3,7 @@ package dns
import (
"net"
"github.com/letsencrypt/boulder/core"
"github.com/letsencrypt/boulder/probs"
)
const detailDNSTimeout = "DNS query timed out"
@ -14,8 +14,8 @@ const detailServerFailure = "Server failure at resolver"
// methods and tests if the error was an underlying net.OpError or an error
// caused by resolver returning SERVFAIL or other invalid Rcodes and returns
// the relevant core.ProblemDetails.
func ProblemDetailsFromDNSError(err error) *core.ProblemDetails {
problem := &core.ProblemDetails{Type: core.ConnectionProblem}
func ProblemDetailsFromDNSError(err error) *probs.ProblemDetails {
problem := &probs.ProblemDetails{Type: probs.ConnectionProblem}
if netErr, ok := err.(*net.OpError); ok {
if netErr.Timeout() {
problem.Detail = detailDNSTimeout

View File

@ -5,8 +5,8 @@ import (
"net"
"testing"
"github.com/letsencrypt/boulder/core"
"github.com/letsencrypt/boulder/mocks"
"github.com/letsencrypt/boulder/probs"
)
func TestProblemDetailsFromDNSError(t *testing.T) {
@ -27,8 +27,8 @@ func TestProblemDetailsFromDNSError(t *testing.T) {
}
for _, tc := range testCases {
err := ProblemDetailsFromDNSError(tc.err)
if err.Type != core.ConnectionProblem {
t.Errorf("ProblemDetailsFromDNSError(%q).Type = %q, expected %q", tc.err, err.Type, core.ConnectionProblem)
if err.Type != probs.ConnectionProblem {
t.Errorf("ProblemDetailsFromDNSError(%q).Type = %q, expected %q", tc.err, err.Type, probs.ConnectionProblem)
}
if err.Detail != tc.expected {
t.Errorf("ProblemDetailsFromDNSError(%q).Detail = %q, expected %q", tc.err, err.Detail, tc.expected)

29
probs/probs.go Normal file
View File

@ -0,0 +1,29 @@
package probs
import "fmt"
// Error types that can be used in ACME payloads
const (
ConnectionProblem = ProblemType("urn:acme:error:connection")
MalformedProblem = ProblemType("urn:acme:error:malformed")
ServerInternalProblem = ProblemType("urn:acme:error:serverInternal")
TLSProblem = ProblemType("urn:acme:error:tls")
UnauthorizedProblem = ProblemType("urn:acme:error:unauthorized")
UnknownHostProblem = ProblemType("urn:acme:error:unknownHost")
RateLimitedProblem = ProblemType("urn:acme:error:rateLimited")
BadNonceProblem = ProblemType("urn:acme:error:badNonce")
)
// ProblemType defines the error types in the ACME protocol
type ProblemType string
// ProblemDetails objects represent problem documents
// https://tools.ietf.org/html/draft-ietf-appsawg-http-problem-00
type ProblemDetails struct {
Type ProblemType `json:"type,omitempty"`
Detail string `json:"detail,omitempty"`
}
func (pd *ProblemDetails) Error() string {
return fmt.Sprintf("%s :: %s", pd.Type, pd.Detail)
}

14
probs/probs_test.go Normal file
View File

@ -0,0 +1,14 @@
package probs
import (
"testing"
"github.com/letsencrypt/boulder/test"
)
func TestProblemDetails(t *testing.T) {
pd := &ProblemDetails{
Type: MalformedProblem,
Detail: "Wat? o.O"}
test.AssertEquals(t, pd.Error(), "urn:acme:error:malformed :: Wat? o.O")
}

View File

@ -25,6 +25,7 @@ import (
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cactus/go-statsd-client/statsd"
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/jmhodges/clock"
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/streadway/amqp"
"github.com/letsencrypt/boulder/probs"
"github.com/letsencrypt/boulder/cmd"
"github.com/letsencrypt/boulder/core"
@ -245,7 +246,7 @@ func wrapError(err error) *rpcError {
wrapped.Type = "RateLimitedError"
case core.ServiceUnavailableError:
wrapped.Type = "ServiceUnavailableError"
case *core.ProblemDetails:
case *probs.ProblemDetails:
wrapped.Type = string(terr.Type)
wrapped.Value = terr.Detail
@ -285,8 +286,8 @@ func unwrapError(rpcError *rpcError) error {
return core.ServiceUnavailableError(rpcError.Value)
default:
if strings.HasPrefix(rpcError.Type, "urn:") {
return &core.ProblemDetails{
Type: core.ProblemType(rpcError.Type),
return &probs.ProblemDetails{
Type: probs.ProblemType(rpcError.Type),
Detail: rpcError.Value,
}
}

View File

@ -11,6 +11,7 @@ import (
"testing"
"github.com/letsencrypt/boulder/core"
"github.com/letsencrypt/boulder/probs"
"github.com/letsencrypt/boulder/test"
)
@ -43,17 +44,17 @@ func TestWrapError(t *testing.T) {
expected error
}{
{
&core.ProblemDetails{
Type: core.ConnectionProblem,
&probs.ProblemDetails{
Type: probs.ConnectionProblem,
Detail: "whoops",
},
&core.ProblemDetails{
Type: core.ConnectionProblem,
&probs.ProblemDetails{
Type: probs.ConnectionProblem,
Detail: "whoops",
},
},
{
&core.ProblemDetails{Type: "invalid", Detail: "hm"},
&probs.ProblemDetails{Type: "invalid", Detail: "hm"},
errors.New("hm"),
},
{

View File

@ -14,6 +14,7 @@ import (
jose "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/letsencrypt/go-jose"
"github.com/letsencrypt/boulder/core"
"github.com/letsencrypt/boulder/probs"
)
var mediumBlobSize = int(math.Pow(2, 24))
@ -170,7 +171,7 @@ func modelToChallenge(cm *challModel) (core.Challenge, error) {
c.KeyAuthorization = &ka
}
if len(cm.Error) > 0 {
var problem core.ProblemDetails
var problem probs.ProblemDetails
err := json.Unmarshal(cm.Error, &problem)
if err != nil {
return core.Challenge{}, err

View File

@ -25,6 +25,7 @@ import (
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/letsencrypt/go-jose"
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/letsencrypt/net/publicsuffix"
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/miekg/dns"
"github.com/letsencrypt/boulder/probs"
"github.com/letsencrypt/boulder/core"
bdns "github.com/letsencrypt/boulder/dns"
@ -125,7 +126,7 @@ func verifyValidationJWS(validation *jose.JsonWebSignature, accountKey *jose.Jso
// This is the same choice made by the Go internal resolution library used by
// net/http, except we only send A queries and accept IPv4 addresses.
// TODO(#593): Add IPv6 support
func (va ValidationAuthorityImpl) getAddr(hostname string) (addr net.IP, addrs []net.IP, problem *core.ProblemDetails) {
func (va ValidationAuthorityImpl) getAddr(hostname string) (addr net.IP, addrs []net.IP, problem *probs.ProblemDetails) {
addrs, rtt, err := va.DNSResolver.LookupHost(hostname)
if err != nil {
problem = bdns.ProblemDetailsFromDNSError(err)
@ -136,8 +137,8 @@ func (va ValidationAuthorityImpl) getAddr(hostname string) (addr net.IP, addrs [
va.stats.Inc("VA.DNS.Rate", 1, 1.0)
if len(addrs) == 0 {
problem = &core.ProblemDetails{
Type: core.UnknownHostProblem,
problem = &probs.ProblemDetails{
Type: probs.UnknownHostProblem,
Detail: fmt.Sprintf("No IPv4 addresses found for %s", hostname),
}
return
@ -158,7 +159,7 @@ func (d *dialer) Dial(_, _ string) (net.Conn, error) {
// resolveAndConstructDialer gets the prefered address using va.getAddr and returns
// the chosen address and dialer for that address and correct port.
func (va *ValidationAuthorityImpl) resolveAndConstructDialer(name string, port int) (dialer, *core.ProblemDetails) {
func (va *ValidationAuthorityImpl) resolveAndConstructDialer(name string, port int) (dialer, *probs.ProblemDetails) {
d := dialer{
record: core.ValidationRecord{
Hostname: name,
@ -205,8 +206,8 @@ func (va *ValidationAuthorityImpl) fetchHTTP(identifier core.AcmeIdentifier, pat
va.log.Audit(fmt.Sprintf("Attempting to validate %s for %s", challenge.Type, url))
httpRequest, err := http.NewRequest("GET", url.String(), nil)
if err != nil {
challenge.Error = &core.ProblemDetails{
Type: core.MalformedProblem,
challenge.Error = &probs.ProblemDetails{
Type: probs.MalformedProblem,
Detail: "URL provided for HTTP was invalid",
}
va.log.Debug(fmt.Sprintf("%s [%s] HTTP failure: %s", challenge.Type, identifier, err))
@ -297,7 +298,7 @@ func (va *ValidationAuthorityImpl) fetchHTTP(identifier core.AcmeIdentifier, pat
httpResponse, err := client.Do(httpRequest)
if err != nil {
challenge.Status = core.StatusInvalid
challenge.Error = &core.ProblemDetails{
challenge.Error = &probs.ProblemDetails{
Type: parseHTTPConnError(err),
Detail: fmt.Sprintf("Could not connect to %s", url),
}
@ -307,8 +308,8 @@ func (va *ValidationAuthorityImpl) fetchHTTP(identifier core.AcmeIdentifier, pat
if httpResponse.StatusCode != 200 {
challenge.Status = core.StatusInvalid
challenge.Error = &core.ProblemDetails{
Type: core.UnauthorizedProblem,
challenge.Error = &probs.ProblemDetails{
Type: probs.UnauthorizedProblem,
Detail: fmt.Sprintf("Invalid response from %s [%s]: %d",
url.String(), dialer.record.AddressUsed, httpResponse.StatusCode),
}
@ -320,8 +321,8 @@ func (va *ValidationAuthorityImpl) fetchHTTP(identifier core.AcmeIdentifier, pat
body, err := ioutil.ReadAll(httpResponse.Body)
if err != nil {
challenge.Status = core.StatusInvalid
challenge.Error = &core.ProblemDetails{
Type: core.UnauthorizedProblem,
challenge.Error = &probs.ProblemDetails{
Type: probs.UnauthorizedProblem,
Detail: fmt.Sprintf("Error reading HTTP response body: %v", err),
}
return emptyBody, challenge, err
@ -359,7 +360,7 @@ func (va *ValidationAuthorityImpl) validateTLSWithZName(identifier core.AcmeIden
if err != nil {
challenge.Status = core.StatusInvalid
challenge.Error = &core.ProblemDetails{
challenge.Error = &probs.ProblemDetails{
Type: parseHTTPConnError(err),
Detail: "Failed to connect to host for DVSNI challenge",
}
@ -371,8 +372,8 @@ func (va *ValidationAuthorityImpl) validateTLSWithZName(identifier core.AcmeIden
// Check that zName is a dNSName SAN in the server's certificate
certs := conn.ConnectionState().PeerCertificates
if len(certs) == 0 {
challenge.Error = &core.ProblemDetails{
Type: core.UnauthorizedProblem,
challenge.Error = &probs.ProblemDetails{
Type: probs.UnauthorizedProblem,
Detail: "No certs presented for TLS SNI challenge",
}
challenge.Status = core.StatusInvalid
@ -385,8 +386,8 @@ func (va *ValidationAuthorityImpl) validateTLSWithZName(identifier core.AcmeIden
}
}
challenge.Error = &core.ProblemDetails{
Type: core.UnauthorizedProblem,
challenge.Error = &probs.ProblemDetails{
Type: probs.UnauthorizedProblem,
Detail: "Correct zName not found for TLS SNI challenge",
}
challenge.Status = core.StatusInvalid
@ -399,8 +400,8 @@ func (va *ValidationAuthorityImpl) validateSimpleHTTP(identifier core.AcmeIdenti
if identifier.Type != core.IdentifierDNS {
challenge.Status = core.StatusInvalid
challenge.Error = &core.ProblemDetails{
Type: core.MalformedProblem,
challenge.Error = &probs.ProblemDetails{
Type: probs.MalformedProblem,
Detail: "Identifier type for SimpleHTTP was not DNS",
}
@ -424,8 +425,8 @@ func (va *ValidationAuthorityImpl) validateSimpleHTTP(identifier core.AcmeIdenti
err = fmt.Errorf("Validation response failed to parse as JWS: %s", err.Error())
va.log.Debug(err.Error())
challenge.Status = core.StatusInvalid
challenge.Error = &core.ProblemDetails{
Type: core.UnauthorizedProblem,
challenge.Error = &probs.ProblemDetails{
Type: probs.UnauthorizedProblem,
Detail: err.Error(),
}
return challenge, err
@ -444,8 +445,8 @@ func (va *ValidationAuthorityImpl) validateSimpleHTTP(identifier core.AcmeIdenti
if err != nil {
va.log.Debug(err.Error())
challenge.Status = core.StatusInvalid
challenge.Error = &core.ProblemDetails{
Type: core.UnauthorizedProblem,
challenge.Error = &probs.ProblemDetails{
Type: probs.UnauthorizedProblem,
Detail: err.Error(),
}
return challenge, err
@ -460,8 +461,8 @@ func (va *ValidationAuthorityImpl) validateDvsni(identifier core.AcmeIdentifier,
challenge := input
if identifier.Type != "dns" {
challenge.Error = &core.ProblemDetails{
Type: core.MalformedProblem,
challenge.Error = &probs.ProblemDetails{
Type: probs.MalformedProblem,
Detail: "Identifier type for DVSNI was not DNS",
}
challenge.Status = core.StatusInvalid
@ -480,8 +481,8 @@ func (va *ValidationAuthorityImpl) validateDvsni(identifier core.AcmeIdentifier,
if err != nil {
va.log.Debug(err.Error())
challenge.Status = core.StatusInvalid
challenge.Error = &core.ProblemDetails{
Type: core.UnauthorizedProblem,
challenge.Error = &probs.ProblemDetails{
Type: probs.UnauthorizedProblem,
Detail: err.Error(),
}
return challenge, err
@ -502,8 +503,8 @@ func (va *ValidationAuthorityImpl) validateHTTP01(identifier core.AcmeIdentifier
if identifier.Type != core.IdentifierDNS {
challenge.Status = core.StatusInvalid
challenge.Error = &core.ProblemDetails{
Type: core.MalformedProblem,
challenge.Error = &probs.ProblemDetails{
Type: probs.MalformedProblem,
Detail: "Identifier type for HTTP validation was not DNS",
}
@ -526,8 +527,8 @@ func (va *ValidationAuthorityImpl) validateHTTP01(identifier core.AcmeIdentifier
err = fmt.Errorf("Error parsing key authorization file: %s", err.Error())
va.log.Debug(err.Error())
challenge.Status = core.StatusInvalid
challenge.Error = &core.ProblemDetails{
Type: core.UnauthorizedProblem,
challenge.Error = &probs.ProblemDetails{
Type: probs.UnauthorizedProblem,
Detail: err.Error(),
}
return challenge, err
@ -539,8 +540,8 @@ func (va *ValidationAuthorityImpl) validateHTTP01(identifier core.AcmeIdentifier
challenge.KeyAuthorization.String(), string(body))
va.log.Debug(err.Error())
challenge.Status = core.StatusInvalid
challenge.Error = &core.ProblemDetails{
Type: core.UnauthorizedProblem,
challenge.Error = &probs.ProblemDetails{
Type: probs.UnauthorizedProblem,
Detail: err.Error(),
}
return challenge, err
@ -554,8 +555,8 @@ func (va *ValidationAuthorityImpl) validateTLSSNI01(identifier core.AcmeIdentifi
challenge := input
if identifier.Type != "dns" {
challenge.Error = &core.ProblemDetails{
Type: core.MalformedProblem,
challenge.Error = &probs.ProblemDetails{
Type: probs.MalformedProblem,
Detail: "Identifier type for TLS-SNI was not DNS",
}
challenge.Status = core.StatusInvalid
@ -574,7 +575,7 @@ func (va *ValidationAuthorityImpl) validateTLSSNI01(identifier core.AcmeIdentifi
// parseHTTPConnError returns the ACME ProblemType corresponding to an error
// that occurred during domain validation.
func parseHTTPConnError(err error) core.ProblemType {
func parseHTTPConnError(err error) probs.ProblemType {
if urlErr, ok := err.(*url.Error); ok {
err = urlErr.Err
}
@ -585,21 +586,21 @@ func parseHTTPConnError(err error) core.ProblemType {
if netErr, ok := err.(*net.OpError); ok {
dnsErr, ok := netErr.Err.(*net.DNSError)
if ok && !dnsErr.Timeout() && !dnsErr.Temporary() {
return core.UnknownHostProblem
return probs.UnknownHostProblem
} else if fmt.Sprintf("%T", netErr.Err) == "tls.alert" {
return core.TLSProblem
return probs.TLSProblem
}
}
return core.ConnectionProblem
return probs.ConnectionProblem
}
func (va *ValidationAuthorityImpl) validateDNS01(identifier core.AcmeIdentifier, input core.Challenge) (core.Challenge, error) {
challenge := input
if identifier.Type != core.IdentifierDNS {
challenge.Error = &core.ProblemDetails{
Type: core.MalformedProblem,
challenge.Error = &probs.ProblemDetails{
Type: probs.MalformedProblem,
Detail: "Identifier type for DNS was not itself DNS",
}
va.log.Debug(fmt.Sprintf("DNS [%s] Identifier failure", identifier))
@ -632,15 +633,15 @@ func (va *ValidationAuthorityImpl) validateDNS01(identifier core.AcmeIdentifier,
}
}
challenge.Error = &core.ProblemDetails{
Type: core.UnauthorizedProblem,
challenge.Error = &probs.ProblemDetails{
Type: probs.UnauthorizedProblem,
Detail: "Correct value not found for DNS challenge",
}
challenge.Status = core.StatusInvalid
return challenge, challenge.Error
}
func (va *ValidationAuthorityImpl) checkCAA(identifier core.AcmeIdentifier, regID int64) *core.ProblemDetails {
func (va *ValidationAuthorityImpl) checkCAA(identifier core.AcmeIdentifier, regID int64) *probs.ProblemDetails {
// Check CAA records for the requested identifier
present, valid, err := va.CheckCAARecords(identifier)
if err != nil {
@ -650,8 +651,8 @@ func (va *ValidationAuthorityImpl) checkCAA(identifier core.AcmeIdentifier, regI
// AUDIT[ Certificate Requests ] 11917fa4-10ef-4e0d-9105-bacbe7836a3c
va.log.Audit(fmt.Sprintf("Checked CAA records for %s, registration ID %d [Present: %t, Valid for issuance: %t]", identifier.Value, regID, present, valid))
if !valid {
return &core.ProblemDetails{
Type: core.ConnectionProblem,
return &probs.ProblemDetails{
Type: probs.ConnectionProblem,
Detail: "CAA check for identifier failed",
}
}
@ -669,7 +670,7 @@ func (va *ValidationAuthorityImpl) validate(authz core.Authorization, challengeI
if !authz.Challenges[challengeIndex].IsSane(true) {
chall := &authz.Challenges[challengeIndex]
chall.Status = core.StatusInvalid
chall.Error = &core.ProblemDetails{Type: core.MalformedProblem,
chall.Error = &probs.ProblemDetails{Type: probs.MalformedProblem,
Detail: fmt.Sprintf("Challenge failed sanity check.")}
logEvent.Challenge = *chall
logEvent.Error = chall.Error.Detail
@ -685,7 +686,7 @@ func (va *ValidationAuthorityImpl) validate(authz core.Authorization, challengeI
} else if !authz.Challenges[challengeIndex].RecordsSane() {
chall := &authz.Challenges[challengeIndex]
chall.Status = core.StatusInvalid
chall.Error = &core.ProblemDetails{Type: core.ServerInternalProblem,
chall.Error = &probs.ProblemDetails{Type: probs.ServerInternalProblem,
Detail: "Records for validation failed sanity check"}
logEvent.Error = chall.Error.Detail
}

View File

@ -30,6 +30,7 @@ import (
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cactus/go-statsd-client/statsd"
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/jmhodges/clock"
"github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/letsencrypt/go-jose"
"github.com/letsencrypt/boulder/probs"
"github.com/letsencrypt/boulder/core"
"github.com/letsencrypt/boulder/mocks"
@ -303,7 +304,7 @@ func TestSimpleHttp(t *testing.T) {
invalidChall, err := va.validateSimpleHTTP(ident, chall)
test.AssertEquals(t, invalidChall.Status, core.StatusInvalid)
test.AssertError(t, err, "Server's down; expected refusal. Where did we connect?")
test.AssertEquals(t, invalidChall.Error.Type, core.ConnectionProblem)
test.AssertEquals(t, invalidChall.Error.Type, probs.ConnectionProblem)
va = NewValidationAuthorityImpl(&PortConfig{HTTPPort: goodPort}, nil, stats, clock.Default())
va.DNSResolver = &mocks.DNSResolver{}
@ -319,7 +320,7 @@ func TestSimpleHttp(t *testing.T) {
invalidChall, err = va.validateSimpleHTTP(ident, chall)
test.AssertEquals(t, invalidChall.Status, core.StatusInvalid)
test.AssertError(t, err, "Should have found a 404 for the challenge.")
test.AssertEquals(t, invalidChall.Error.Type, core.UnauthorizedProblem)
test.AssertEquals(t, invalidChall.Error.Type, probs.UnauthorizedProblem)
test.AssertEquals(t, len(log.GetAllMatching(`^\[AUDIT\] `)), 1)
log.Clear()
@ -329,7 +330,7 @@ func TestSimpleHttp(t *testing.T) {
invalidChall, err = va.validateSimpleHTTP(ident, chall)
test.AssertEquals(t, invalidChall.Status, core.StatusInvalid)
test.AssertError(t, err, "Should have found the wrong token value.")
test.AssertEquals(t, invalidChall.Error.Type, core.UnauthorizedProblem)
test.AssertEquals(t, invalidChall.Error.Type, probs.UnauthorizedProblem)
test.AssertEquals(t, len(log.GetAllMatching(`^\[AUDIT\] `)), 1)
log.Clear()
@ -351,12 +352,12 @@ func TestSimpleHttp(t *testing.T) {
invalidChall, err = va.validateSimpleHTTP(ipIdentifier, chall)
test.AssertEquals(t, invalidChall.Status, core.StatusInvalid)
test.AssertError(t, err, "IdentifierType IP shouldn't have worked.")
test.AssertEquals(t, invalidChall.Error.Type, core.MalformedProblem)
test.AssertEquals(t, invalidChall.Error.Type, probs.MalformedProblem)
invalidChall, err = va.validateSimpleHTTP(core.AcmeIdentifier{Type: core.IdentifierDNS, Value: "always.invalid"}, chall)
test.AssertEquals(t, invalidChall.Status, core.StatusInvalid)
test.AssertError(t, err, "Domain name is invalid.")
test.AssertEquals(t, invalidChall.Error.Type, core.UnknownHostProblem)
test.AssertEquals(t, invalidChall.Error.Type, probs.UnknownHostProblem)
chall.Token = "wait-long"
started := time.Now()
@ -367,7 +368,7 @@ func TestSimpleHttp(t *testing.T) {
test.Assert(t, (took < (time.Second * 10)), "HTTP connection didn't timeout after 5 seconds")
test.AssertEquals(t, invalidChall.Status, core.StatusInvalid)
test.AssertError(t, err, "Connection should've timed out")
test.AssertEquals(t, invalidChall.Error.Type, core.ConnectionProblem)
test.AssertEquals(t, invalidChall.Error.Type, probs.ConnectionProblem)
}
// TODO(https://github.com/letsencrypt/boulder/issues/894): Remove this method
@ -483,13 +484,13 @@ func TestDvsni(t *testing.T) {
}, chall)
test.AssertEquals(t, invalidChall.Status, core.StatusInvalid)
test.AssertError(t, err, "IdentifierType IP shouldn't have worked.")
test.AssertEquals(t, invalidChall.Error.Type, core.MalformedProblem)
test.AssertEquals(t, invalidChall.Error.Type, probs.MalformedProblem)
log.Clear()
invalidChall, err = va.validateDvsni(core.AcmeIdentifier{Type: core.IdentifierDNS, Value: "always.invalid"}, chall)
test.AssertEquals(t, invalidChall.Status, core.StatusInvalid)
test.AssertError(t, err, "Domain name was supposed to be invalid.")
test.AssertEquals(t, invalidChall.Error.Type, core.UnknownHostProblem)
test.AssertEquals(t, invalidChall.Error.Type, probs.UnknownHostProblem)
// Need to re-sign to get an unknown SNI (from the signature value)
chall.Token = core.NewToken()
@ -509,7 +510,7 @@ func TestDvsni(t *testing.T) {
test.Assert(t, (took < (time.Second * 10)), "HTTP connection didn't timeout after 5 seconds")
test.AssertEquals(t, invalidChall.Status, core.StatusInvalid)
test.AssertError(t, err, "Connection should've timed out")
test.AssertEquals(t, invalidChall.Error.Type, core.ConnectionProblem)
test.AssertEquals(t, invalidChall.Error.Type, probs.ConnectionProblem)
test.AssertEquals(t, len(log.GetAllMatching(`Resolved addresses for localhost \[using 127.0.0.1\]: \[127.0.0.1\]`)), 1)
// Take down DVSNI validation server and check that validation fails.
@ -517,7 +518,7 @@ func TestDvsni(t *testing.T) {
invalidChall, err = va.validateDvsni(ident, chall)
test.AssertEquals(t, invalidChall.Status, core.StatusInvalid)
test.AssertError(t, err, "Server's down; expected refusal. Where did we connect?")
test.AssertEquals(t, invalidChall.Error.Type, core.ConnectionProblem)
test.AssertEquals(t, invalidChall.Error.Type, probs.ConnectionProblem)
}
func TestDVSNIWithTLSError(t *testing.T) {
@ -533,7 +534,7 @@ func TestDVSNIWithTLSError(t *testing.T) {
invalidChall, err := va.validateDvsni(ident, chall)
test.AssertEquals(t, invalidChall.Status, core.StatusInvalid)
test.AssertError(t, err, "What cert was used?")
test.AssertEquals(t, invalidChall.Error.Type, core.TLSProblem)
test.AssertEquals(t, invalidChall.Error.Type, probs.TLSProblem)
}
func httpSrv(t *testing.T, token string) *httptest.Server {
@ -681,7 +682,7 @@ func TestHttp(t *testing.T) {
invalidChall, err := va.validateHTTP01(ident, chall)
test.AssertEquals(t, invalidChall.Status, core.StatusInvalid)
test.AssertError(t, err, "Server's down; expected refusal. Where did we connect?")
test.AssertEquals(t, invalidChall.Error.Type, core.ConnectionProblem)
test.AssertEquals(t, invalidChall.Error.Type, probs.ConnectionProblem)
va = NewValidationAuthorityImpl(&PortConfig{HTTPPort: goodPort}, nil, stats, clock.Default())
va.DNSResolver = &mocks.DNSResolver{}
@ -698,7 +699,7 @@ func TestHttp(t *testing.T) {
invalidChall, err = va.validateHTTP01(ident, chall)
test.AssertEquals(t, invalidChall.Status, core.StatusInvalid)
test.AssertError(t, err, "Should have found a 404 for the challenge.")
test.AssertEquals(t, invalidChall.Error.Type, core.UnauthorizedProblem)
test.AssertEquals(t, invalidChall.Error.Type, probs.UnauthorizedProblem)
test.AssertEquals(t, len(log.GetAllMatching(`^\[AUDIT\] `)), 1)
log.Clear()
@ -708,7 +709,7 @@ func TestHttp(t *testing.T) {
invalidChall, err = va.validateHTTP01(ident, chall)
test.AssertEquals(t, invalidChall.Status, core.StatusInvalid)
test.AssertError(t, err, "Should have found the wrong token value.")
test.AssertEquals(t, invalidChall.Error.Type, core.UnauthorizedProblem)
test.AssertEquals(t, invalidChall.Error.Type, probs.UnauthorizedProblem)
test.AssertEquals(t, len(log.GetAllMatching(`^\[AUDIT\] `)), 1)
log.Clear()
@ -730,12 +731,12 @@ func TestHttp(t *testing.T) {
invalidChall, err = va.validateHTTP01(ipIdentifier, chall)
test.AssertEquals(t, invalidChall.Status, core.StatusInvalid)
test.AssertError(t, err, "IdentifierType IP shouldn't have worked.")
test.AssertEquals(t, invalidChall.Error.Type, core.MalformedProblem)
test.AssertEquals(t, invalidChall.Error.Type, probs.MalformedProblem)
invalidChall, err = va.validateHTTP01(core.AcmeIdentifier{Type: core.IdentifierDNS, Value: "always.invalid"}, chall)
test.AssertEquals(t, invalidChall.Status, core.StatusInvalid)
test.AssertError(t, err, "Domain name is invalid.")
test.AssertEquals(t, invalidChall.Error.Type, core.UnknownHostProblem)
test.AssertEquals(t, invalidChall.Error.Type, probs.UnknownHostProblem)
setChallengeToken(&chall, pathWaitLong)
started := time.Now()
@ -746,7 +747,7 @@ func TestHttp(t *testing.T) {
test.Assert(t, (took < (time.Second * 10)), "HTTP connection didn't timeout after 5 seconds")
test.AssertEquals(t, invalidChall.Status, core.StatusInvalid)
test.AssertError(t, err, "Connection should've timed out")
test.AssertEquals(t, invalidChall.Error.Type, core.ConnectionProblem)
test.AssertEquals(t, invalidChall.Error.Type, probs.ConnectionProblem)
}
func TestHTTPRedirectLookup(t *testing.T) {
@ -891,13 +892,13 @@ func TestTLSSNI(t *testing.T) {
}, chall)
test.AssertEquals(t, invalidChall.Status, core.StatusInvalid)
test.AssertError(t, err, "IdentifierType IP shouldn't have worked.")
test.AssertEquals(t, invalidChall.Error.Type, core.MalformedProblem)
test.AssertEquals(t, invalidChall.Error.Type, probs.MalformedProblem)
log.Clear()
invalidChall, err = va.validateTLSSNI01(core.AcmeIdentifier{Type: core.IdentifierDNS, Value: "always.invalid"}, chall)
test.AssertEquals(t, invalidChall.Status, core.StatusInvalid)
test.AssertError(t, err, "Domain name was supposed to be invalid.")
test.AssertEquals(t, invalidChall.Error.Type, core.UnknownHostProblem)
test.AssertEquals(t, invalidChall.Error.Type, probs.UnknownHostProblem)
// Need to create a new authorized keys object to get an unknown SNI (from the signature value)
chall.Token = core.NewToken()
@ -913,7 +914,7 @@ func TestTLSSNI(t *testing.T) {
test.Assert(t, (took < (time.Second * 10)), "HTTP connection didn't timeout after 5 seconds")
test.AssertEquals(t, invalidChall.Status, core.StatusInvalid)
test.AssertError(t, err, "Connection should've timed out")
test.AssertEquals(t, invalidChall.Error.Type, core.ConnectionProblem)
test.AssertEquals(t, invalidChall.Error.Type, probs.ConnectionProblem)
test.AssertEquals(t, len(log.GetAllMatching(`Resolved addresses for localhost \[using 127.0.0.1\]: \[127.0.0.1\]`)), 1)
// Take down validation server and check that validation fails.
@ -921,7 +922,7 @@ func TestTLSSNI(t *testing.T) {
invalidChall, err = va.validateTLSSNI01(ident, chall)
test.AssertEquals(t, invalidChall.Status, core.StatusInvalid)
test.AssertError(t, err, "Server's down; expected refusal. Where did we connect?")
test.AssertEquals(t, invalidChall.Error.Type, core.ConnectionProblem)
test.AssertEquals(t, invalidChall.Error.Type, probs.ConnectionProblem)
}
func brokenTLSSrv() *httptest.Server {
@ -948,7 +949,7 @@ func TestTLSError(t *testing.T) {
invalidChall, err := va.validateTLSSNI01(ident, chall)
test.AssertEquals(t, invalidChall.Status, core.StatusInvalid)
test.AssertError(t, err, "What cert was used?")
test.AssertEquals(t, invalidChall.Error.Type, core.TLSProblem)
test.AssertEquals(t, invalidChall.Error.Type, probs.TLSProblem)
}
func TestValidateHTTP(t *testing.T) {
@ -1096,8 +1097,8 @@ func TestCAATimeout(t *testing.T) {
va.DNSResolver = &mocks.DNSResolver{}
va.IssuerDomain = "letsencrypt.org"
err := va.checkCAA(core.AcmeIdentifier{Type: core.IdentifierDNS, Value: "caa-timeout.com"}, 101)
if err.Type != core.ConnectionProblem {
t.Errorf("Expected timeout error type %s, got %s", core.ConnectionProblem, err.Type)
if err.Type != probs.ConnectionProblem {
t.Errorf("Expected timeout error type %s, got %s", probs.ConnectionProblem, err.Type)
}
expected := "DNS query timed out"
if err.Detail != expected {
@ -1173,7 +1174,7 @@ func TestDNSValidationFailure(t *testing.T) {
t.Logf("Resulting Authz: %+v", authz)
test.AssertNotNil(t, mockRA.lastAuthz, "Should have gotten an authorization")
test.Assert(t, authz.Challenges[0].Status == core.StatusInvalid, "Should be invalid.")
test.AssertEquals(t, authz.Challenges[0].Error.Type, core.UnauthorizedProblem)
test.AssertEquals(t, authz.Challenges[0].Error.Type, probs.UnauthorizedProblem)
}
func TestDNSValidationInvalid(t *testing.T) {
@ -1201,7 +1202,7 @@ func TestDNSValidationInvalid(t *testing.T) {
test.AssertNotNil(t, mockRA.lastAuthz, "Should have gotten an authorization")
test.Assert(t, authz.Challenges[0].Status == core.StatusInvalid, "Should be invalid.")
test.AssertEquals(t, authz.Challenges[0].Error.Type, core.MalformedProblem)
test.AssertEquals(t, authz.Challenges[0].Error.Type, probs.MalformedProblem)
}
func TestDNSValidationNotSane(t *testing.T) {
@ -1231,7 +1232,7 @@ func TestDNSValidationNotSane(t *testing.T) {
for i := 0; i < len(authz.Challenges); i++ {
va.validate(authz, i)
test.AssertEquals(t, authz.Challenges[i].Status, core.StatusInvalid)
test.AssertEquals(t, authz.Challenges[i].Error.Type, core.MalformedProblem)
test.AssertEquals(t, authz.Challenges[i].Error.Type, probs.MalformedProblem)
}
}
@ -1258,7 +1259,7 @@ func TestDNSValidationServFail(t *testing.T) {
test.AssertNotNil(t, mockRA.lastAuthz, "Should have gotten an authorization")
test.Assert(t, authz.Challenges[0].Status == core.StatusInvalid, "Should be invalid.")
test.AssertEquals(t, authz.Challenges[0].Error.Type, core.ConnectionProblem)
test.AssertEquals(t, authz.Challenges[0].Error.Type, probs.ConnectionProblem)
}
func TestDNSValidationNoServer(t *testing.T) {
@ -1280,7 +1281,7 @@ func TestDNSValidationNoServer(t *testing.T) {
test.AssertNotNil(t, mockRA.lastAuthz, "Should have gotten an authorization")
test.Assert(t, authz.Challenges[0].Status == core.StatusInvalid, "Should be invalid.")
test.AssertEquals(t, authz.Challenges[0].Error.Type, core.ConnectionProblem)
test.AssertEquals(t, authz.Challenges[0].Error.Type, probs.ConnectionProblem)
}
// TestDNSValidationLive is an integration test, depending on

View File

@ -23,6 +23,7 @@ import (
jose "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/letsencrypt/go-jose"
"github.com/letsencrypt/boulder/core"
blog "github.com/letsencrypt/boulder/log"
"github.com/letsencrypt/boulder/probs"
)
// Paths are the ACME-spec identified URL path-segments for various methods
@ -486,12 +487,12 @@ func (wfe *WebFrontEndImpl) verifyPOST(logEvent *requestEvent, request *http.Req
// Notify the client of an error condition and log it for audit purposes.
func (wfe *WebFrontEndImpl) sendError(response http.ResponseWriter, logEvent *requestEvent, msg string, detail error, code int) {
problem := core.ProblemDetails{Detail: msg}
problem := probs.ProblemDetails{Detail: msg}
switch code {
case http.StatusPreconditionFailed:
fallthrough
case http.StatusForbidden:
problem.Type = core.UnauthorizedProblem
problem.Type = probs.UnauthorizedProblem
case http.StatusConflict:
fallthrough
case http.StatusMethodNotAllowed:
@ -501,14 +502,14 @@ func (wfe *WebFrontEndImpl) sendError(response http.ResponseWriter, logEvent *re
case http.StatusBadRequest:
fallthrough
case http.StatusLengthRequired:
problem.Type = core.MalformedProblem
problem.Type = probs.MalformedProblem
case StatusRateLimited:
problem.Type = core.RateLimitedProblem
problem.Type = probs.RateLimitedProblem
case statusBadNonce:
problem.Type = core.BadNonceProblem
problem.Type = probs.BadNonceProblem
code = http.StatusBadRequest
default: // Either http.StatusInternalServerError or an unexpected code
problem.Type = core.ServerInternalProblem
problem.Type = probs.ServerInternalProblem
}
// Record details to the log event
@ -516,7 +517,7 @@ func (wfe *WebFrontEndImpl) sendError(response http.ResponseWriter, logEvent *re
// Only audit log internal errors so users cannot purposefully cause
// auditable events.
if problem.Type == core.ServerInternalProblem {
if problem.Type == probs.ServerInternalProblem {
// AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3
wfe.log.Audit(fmt.Sprintf("Internal error - %s - %s", msg, detail))
} else if statusCodeFromError(detail) != http.StatusInternalServerError {