From 21c772492263086acf4681d9f27eedf377232028 Mon Sep 17 00:00:00 2001 From: pavel-paulau Date: Thu, 29 Oct 2015 08:32:14 -0700 Subject: [PATCH 1/2] Remove Let's Encrypt clients from Dockerfile Resolves #1056. --- Dockerfile | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/Dockerfile b/Dockerfile index 4d2a17516..1e87d3b10 100644 --- a/Dockerfile +++ b/Dockerfile @@ -24,19 +24,6 @@ RUN go get -v github.com/golang/lint/golint ENV BOULDER_CONFIG /go/src/github.com/letsencrypt/boulder/test/boulder-config.json ENV GOPATH /go/src/github.com/letsencrypt/boulder/Godeps/_workspace:$GOPATH -# Get the Let's Encrypt client -RUN git clone --depth 1 https://www.github.com/letsencrypt/letsencrypt.git /letsencrypt \ - && cd /letsencrypt \ - && ./bootstrap/debian.sh \ - && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* \ - && virtualenv --no-site-packages -p python2 venv \ - && ./venv/bin/pip install \ - -r requirements.txt \ - -e acme \ - -e .[dev,docs,testing] \ - -e letsencrypt-apache \ - -e letsencrypt-nginx - WORKDIR /go/src/github.com/letsencrypt/boulder # Copy in the Boulder sources From 9ea4ac8b14220f2196c8b9dda1a07f79dc5efe8c Mon Sep 17 00:00:00 2001 From: Jeff Hodges Date: Wed, 18 Nov 2015 14:53:03 -0800 Subject: [PATCH 2/2] return ProblemDetails when validating emails in ra Fixes #1153 --- probs/probs.go | 1 + ra/registration-authority.go | 38 ++++++++++++++++++++----------- ra/registration-authority_test.go | 19 ++++++++++------ test/test-tools.go | 2 +- 4 files changed, 39 insertions(+), 21 deletions(-) diff --git a/probs/probs.go b/probs/probs.go index 1809fee85..30ae12c46 100644 --- a/probs/probs.go +++ b/probs/probs.go @@ -15,6 +15,7 @@ const ( UnknownHostProblem = ProblemType("urn:acme:error:unknownHost") RateLimitedProblem = ProblemType("urn:acme:error:rateLimited") BadNonceProblem = ProblemType("urn:acme:error:badNonce") + InvalidEmailProblem = ProblemType("urn:acme:error:invalidEmail") ) // ProblemType defines the error types in the ACME protocol diff --git a/ra/registration-authority.go b/ra/registration-authority.go index f9a25e667..44b3e07ae 100644 --- a/ra/registration-authority.go +++ b/ra/registration-authority.go @@ -20,6 +20,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/golang.org/x/net/publicsuffix" + "github.com/letsencrypt/boulder/probs" "github.com/letsencrypt/boulder/bdns" "github.com/letsencrypt/boulder/cmd" @@ -78,13 +79,18 @@ func NewRegistrationAuthorityImpl(clk clock.Clock, logger *blog.AuditLogger, sta return ra } -var errUnparseableEmail = errors.New("not a valid e-mail address") -var errEmptyDNSResponse = errors.New("empty DNS response") +const ( + unparseableEmailDetail = "not a valid e-mail address" + emptyDNSResponseDetail = "empty DNS response" +) -func validateEmail(address string, resolver bdns.DNSResolver) (rtt time.Duration, count int64, err error) { - _, err = mail.ParseAddress(address) +func validateEmail(address string, resolver bdns.DNSResolver) (rtt time.Duration, count int64, prob *probs.ProblemDetails) { + _, err := mail.ParseAddress(address) if err != nil { - return time.Duration(0), 0, errUnparseableEmail + return 0, 0, &probs.ProblemDetails{ + Type: probs.InvalidEmailProblem, + Detail: unparseableEmailDetail, + } } splitEmail := strings.SplitN(address, "@", -1) domain := strings.ToLower(splitEmail[len(splitEmail)-1]) @@ -93,20 +99,27 @@ func validateEmail(address string, resolver bdns.DNSResolver) (rtt time.Duration var resultA []net.IP resultMX, rtt1, err = resolver.LookupMX(domain) count++ + if err == nil && len(resultMX) == 0 { resultA, rtt2, err = resolver.LookupHost(domain) count++ if err == nil && len(resultA) == 0 { - err = errEmptyDNSResponse + return rtt1 + rtt2, count, &probs.ProblemDetails{ + Type: probs.InvalidEmailProblem, + Detail: emptyDNSResponseDetail, + } } } if err != nil { - problem := bdns.ProblemDetailsFromDNSError(err) - err = core.MalformedRequestError(problem.Detail) + dnsProblem := bdns.ProblemDetailsFromDNSError(err) + return rtt, count, &probs.ProblemDetails{ + Type: probs.InvalidEmailProblem, + Detail: dnsProblem.Detail, + } } rtt = rtt1 + rtt2 - return + return rtt, count, nil } type certificateRequestEvent struct { @@ -235,14 +248,13 @@ func (ra *RegistrationAuthorityImpl) validateContacts(contacts []*core.AcmeURL) // Note: the stats handling here is a bit of a lie, // since validateEmail() mainly does MX lookups and // only does A lookups when the MX is missing. - rtt, count, err := validateEmail(contact.Opaque, ra.DNSResolver) + rtt, count, problem := validateEmail(contact.Opaque, ra.DNSResolver) if count > 0 { ra.stats.TimingDuration("RA.DNS.RTT.A", time.Duration(int64(rtt)/count), 1.0) ra.stats.Inc("RA.DNS.Rate", count, 1.0) } - if err != nil { - return core.MalformedRequestError(fmt.Sprintf( - "Validation of contact %s failed: %s", contact, err)) + if problem != nil { + return problem } default: err = core.MalformedRequestError(fmt.Sprintf("Contact method %s is not supported", contact.Scheme)) diff --git a/ra/registration-authority_test.go b/ra/registration-authority_test.go index 840a63e02..bb2853ac8 100644 --- a/ra/registration-authority_test.go +++ b/ra/registration-authority_test.go @@ -28,6 +28,7 @@ import ( blog "github.com/letsencrypt/boulder/log" "github.com/letsencrypt/boulder/mocks" "github.com/letsencrypt/boulder/policy" + "github.com/letsencrypt/boulder/probs" "github.com/letsencrypt/boulder/sa" "github.com/letsencrypt/boulder/test" "github.com/letsencrypt/boulder/test/vars" @@ -314,8 +315,8 @@ func TestValidateEmail(t *testing.T) { input string expected string }{ - {"an email`", errUnparseableEmail.Error()}, - {"a@always.invalid", "Server failure at resolver"}, + {"an email`", unparseableEmailDetail}, + {"a@always.invalid", emptyDNSResponseDetail}, {"a@always.timeout", "DNS query timed out"}, {"a@always.error", "DNS networking error"}, } @@ -324,16 +325,20 @@ func TestValidateEmail(t *testing.T) { "b@email.only", } for _, tc := range testFailures { - _, _, err := validateEmail(tc.input, &mocks.DNSResolver{}) - if err.Error() != tc.expected { + _, _, problem := validateEmail(tc.input, &mocks.DNSResolver{}) + if problem.Type != probs.InvalidEmailProblem { + t.Errorf("validateEmail(%q): got problem type %#v, expected %#v", tc.input, problem.Type, probs.InvalidEmailProblem) + } + if problem.Detail != tc.expected { t.Errorf("validateEmail(%q): got %#v, expected %#v", - tc.input, err, tc.expected) + tc.input, problem.Detail, tc.expected) } } + for _, addr := range testSuccesses { - if _, _, err := validateEmail(addr, &mocks.DNSResolver{}); err != nil { + if _, _, prob := validateEmail(addr, &mocks.DNSResolver{}); prob != nil { t.Errorf("validateEmail(%q): expected success, but it failed: %s", - addr, err) + addr, prob) } } } diff --git a/test/test-tools.go b/test/test-tools.go index 82e0358dc..68f1798ef 100644 --- a/test/test-tools.go +++ b/test/test-tools.go @@ -50,7 +50,7 @@ func AssertNotError(t *testing.T, err error, message string) { // AssertError checks that err is non-nil func AssertError(t *testing.T, err error, message string) { if err == nil { - t.Fatalf("%s %s", caller(), message) + t.Fatalf("%s %s: expected error but received none", caller(), message) } }