Store redirects, reconstruct transport on redirect, add redirect + lookup tests

This commit is contained in:
Roland Shoemaker 2015-07-24 12:05:27 -07:00
parent 107f171c76
commit a960fa0393
4 changed files with 46 additions and 7 deletions

View File

@ -251,8 +251,11 @@ type Challenge struct {
S string `json:"s,omitempty"`
Nonce string `json:"nonce,omitempty"`
// IP addresses resolved from authorization identifier
// IP addresses resolved from authorization identifier during SimpleHTTP validation
ResolvedAddrs []net.IP `json:"resolvedAddrs,omitempty"`
// URLs redirected to during SimpleHTTP validation
Redirects []string `json:"redirects,omitempty"`
}
// IsSane checks the sanity of a challenge object before issued to the client

View File

@ -66,7 +66,7 @@ func (mock *MockDNS) LookupTXT(hostname string) ([]string, time.Duration, error)
// LookupHost is a mock
func (mock *MockDNS) LookupHost(hostname string) ([]net.IP, time.Duration, time.Duration, error) {
if hostname == "always.invalid" {
if hostname == "always.invalid" || hostname == "invalid.super" {
return []net.IP{}, 0, 0, nil
}
ip := net.ParseIP("127.0.0.1")

View File

@ -147,17 +147,33 @@ func (va ValidationAuthorityImpl) validateSimpleHTTP(identifier core.AcmeIdentif
// selected above.
defaultDial := tr.Dial
tr.Dial = func(_, _ string) (net.Conn, error) {
// Ignore the addr selected by net/http.
port := "80"
if va.TestMode {
port = "5001"
} else if scheme == "https" {
port = "443"
}
// Ignore the addr selected by net/http.
return defaultDial("tcp", net.JoinHostPort(addrs[0].String(), port))
}
var redirects []string
logRedirect := func(req *http.Request, via []*http.Request) error {
redirects = append(redirects, req.URL.String())
va.log.Info(fmt.Sprintf("validateSimpleHTTP [%s] redirect from %q to %q", identifier, via[len(via)-1].URL.String(), req.URL.String()))
addrs, problem := va.getAddrs(req.URL.Host)
if problem != nil {
return problem
}
challenge.ResolvedAddrs = append(challenge.ResolvedAddrs, addrs...)
port := "80"
if va.TestMode {
port = "5001"
} else if strings.ToLower(req.URL.Scheme) == "https" {
port = "443"
}
tr.Dial = func(_, _ string) (net.Conn, error) {
return defaultDial("tcp", net.JoinHostPort(addrs[0].String(), port))
}
return nil
}
client := http.Client{
@ -166,7 +182,7 @@ func (va ValidationAuthorityImpl) validateSimpleHTTP(identifier core.AcmeIdentif
Timeout: 5 * time.Second,
}
httpResponse, err := client.Do(httpRequest)
challenge.Redirects = redirects
if err == nil && httpResponse.StatusCode == 200 {
// Read body & test
body, readErr := ioutil.ReadAll(httpResponse.Body)
@ -192,9 +208,14 @@ func (va ValidationAuthorityImpl) validateSimpleHTTP(identifier core.AcmeIdentif
}
} else if err != nil {
challenge.Status = core.StatusInvalid
challenge.Error = &core.ProblemDetails{
Type: parseHTTPConnError(err),
Detail: fmt.Sprintf("Could not connect to %s", url.String()),
// Catch if error came from CheckRedirect
if problem, ok := err.(*core.ProblemDetails); ok {
challenge.Error = problem
} else {
challenge.Error = &core.ProblemDetails{
Type: parseHTTPConnError(err),
Detail: fmt.Sprintf("Could not connect to %s", url.String()),
}
}
va.log.Debug(strings.Join([]string{challenge.Error.Error(), err.Error()}, ": "))
} else {

View File

@ -59,6 +59,7 @@ const pathWrongToken = "wrongtoken"
const path404 = "404"
const pathFound = "302"
const pathMoved = "301"
const pathRedirectLookup = "re-lookup"
func simpleSrv(t *testing.T, token string, stopChan, waitChan chan bool, enableTLS bool) {
m := http.NewServeMux()
@ -85,6 +86,9 @@ func simpleSrv(t *testing.T, token string, stopChan, waitChan chan bool, enableT
} else if strings.HasSuffix(r.URL.Path, "wait-long") {
t.Logf("SIMPLESRV: Got a wait-long req\n")
time.Sleep(time.Second * 10)
} else if strings.HasSuffix(r.URL.Path, "re-lookup") {
t.Logf("SIMPLESRV: Got a redirect to invalid lookup req\n")
http.Redirect(w, r, "http://invalid.super/path", 302)
} else {
t.Logf("SIMPLESRV: Got a valid req\n")
fmt.Fprintf(w, "%s", token)
@ -263,6 +267,7 @@ func TestSimpleHttp(t *testing.T) {
test.AssertEquals(t, finChall.Status, core.StatusValid)
test.AssertNotError(t, err, chall.Path)
test.AssertEquals(t, len(log.GetAllMatching(`redirect from ".*/301" to ".*/valid"`)), 1)
test.AssertEquals(t, len(log.GetAllMatching(`Resolved addresses for localhost: \[127.0.0.1\]`)), 2)
log.Clear()
chall.Path = pathFound
@ -271,6 +276,16 @@ func TestSimpleHttp(t *testing.T) {
test.AssertNotError(t, err, chall.Path)
test.AssertEquals(t, len(log.GetAllMatching(`redirect from ".*/302" to ".*/301"`)), 1)
test.AssertEquals(t, len(log.GetAllMatching(`redirect from ".*/301" to ".*/valid"`)), 1)
test.AssertEquals(t, len(log.GetAllMatching(`Resolved addresses for localhost: \[127.0.0.1\]`)), 3)
log.Clear()
chall.Path = pathRedirectLookup
finChall, err = va.validateSimpleHTTP(ident, chall)
test.AssertEquals(t, finChall.Status, core.StatusInvalid)
test.AssertError(t, err, chall.Path)
test.AssertEquals(t, len(log.GetAllMatching(`redirect from ".*/re-lookup" to ".*invalid.super/path"`)), 1)
test.AssertEquals(t, len(log.GetAllMatching(`Resolved addresses for localhost: \[127.0.0.1\]`)), 1)
test.AssertEquals(t, len(log.GetAllMatching(`Could not resolve invalid.super`)), 1)
log.Clear()
chall.Path = path404