func TestValidateHTTPResponseDocument(t *testing.T) { chall := core.HTTPChallenge01(accountKey) setChallengeToken(&chall, core.NewToken()) hs := httpSrv(t, `a.StartOfLine.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.PastTruncationPoint.aaaaaaaaaaaaaaaaaaaa`) port, err := getPort(hs) test.AssertNotError(t, err, "failed to get test server port") stats, _ := statsd.NewNoopClient() va := NewValidationAuthorityImpl(&cmd.PortConfig{HTTPPort: port}, nil, nil, stats, clock.Default()) va.DNSResolver = &bdns.MockDNSResolver{} mockRA := &MockRegistrationAuthority{} va.RA = mockRA defer hs.Close() var authz = core.Authorization{ ID: core.NewToken(), RegistrationID: 1, Identifier: ident, Challenges: []core.Challenge{chall}, } va.validate(ctx, authz, 0) test.AssertEquals(t, core.StatusInvalid, mockRA.lastAuthz.Challenges[0].Status) test.Assert(t, len(log.GetAllMatching("StartOfLine")) > 1, "Beginning of response body not logged") test.Assert(t, len(log.GetAllMatching("…")) > 1, "Ellipsis not logged") test.AssertEquals(t, len(log.GetAllMatching("PastTruncationPoint")), 0) // End of response body was logged }
func TestHTTPRedirectUserAgent(t *testing.T) { chall := core.HTTPChallenge01(accountKey) err := setChallengeToken(&chall, expectedToken) test.AssertNotError(t, err, "Failed to complete HTTP challenge") hs := httpSrv(t, expectedToken) defer hs.Close() port, err := getPort(hs) test.AssertNotError(t, err, "failed to get test server port") stats, _ := statsd.NewNoopClient() va := NewValidationAuthorityImpl(&PortConfig{HTTPPort: port}, nil, stats, clock.Default()) va.DNSResolver = &bdns.MockDNSResolver{} va.UserAgent = rejectUserAgent setChallengeToken(&chall, pathMoved) _, prob := va.validateHTTP01(context.Background(), ident, chall) if prob == nil { t.Fatalf("Challenge with rejectUserAgent should have failed (%s).", pathMoved) } setChallengeToken(&chall, pathFound) _, prob = va.validateHTTP01(context.Background(), ident, chall) if prob == nil { t.Fatalf("Challenge with rejectUserAgent should have failed (%s).", pathFound) } }
// ChallengesFor makes a decision of what challenges, and combinations, are // acceptable for the given identifier. // // Note: Current implementation is static, but future versions may not be. func (pa *AuthorityImpl) ChallengesFor(identifier core.AcmeIdentifier) ([]core.Challenge, [][]int) { challenges := []core.Challenge{} if pa.enabledChallenges[core.ChallengeTypeHTTP01] { challenges = append(challenges, core.HTTPChallenge01()) } if pa.enabledChallenges[core.ChallengeTypeTLSSNI01] { challenges = append(challenges, core.TLSSNIChallenge01()) } if pa.enabledChallenges[core.ChallengeTypeDNS01] { challenges = append(challenges, core.DNSChallenge01()) } // We shuffle the challenges and combinations to prevent ACME clients from // relying on the specific order that boulder returns them in. shuffled := make([]core.Challenge, len(challenges)) combinations := make([][]int, len(challenges)) for i, challIdx := range pa.pseudoRNG.Perm(len(challenges)) { shuffled[i] = challenges[challIdx] combinations[i] = []int{i} } shuffledCombos := make([][]int, len(combinations)) for i, comboIdx := range pa.pseudoRNG.Perm(len(combinations)) { shuffledCombos[i] = combinations[comboIdx] } return shuffled, shuffledCombos }
// ChallengesFor makes a decision of what challenges, and combinations, are // acceptable for the given identifier. // // Note: Current implementation is static, but future versions may not be. func (pa PolicyAuthorityImpl) ChallengesFor(identifier core.AcmeIdentifier, accountKey *jose.JsonWebKey) (challenges []core.Challenge, combinations [][]int, err error) { challenges = []core.Challenge{} combinations = [][]int{} // TODO(https://github.com/letsencrypt/boulder/issues/894): Remove this block if pa.enabledChallenges[core.ChallengeTypeSimpleHTTP] { challenges = append(challenges, core.SimpleHTTPChallenge(accountKey)) } // TODO(https://github.com/letsencrypt/boulder/issues/894): Remove this block if pa.enabledChallenges[core.ChallengeTypeDVSNI] { challenges = append(challenges, core.DvsniChallenge(accountKey)) } if pa.enabledChallenges[core.ChallengeTypeHTTP01] { challenges = append(challenges, core.HTTPChallenge01(accountKey)) } if pa.enabledChallenges[core.ChallengeTypeTLSSNI01] { challenges = append(challenges, core.TLSSNIChallenge01(accountKey)) } if pa.enabledChallenges[core.ChallengeTypeDNS01] { challenges = append(challenges, core.DNSChallenge01(accountKey)) } combinations = make([][]int, len(challenges)) for i := range combinations { combinations[i] = []int{i} } return }
func TestUpdateValidations(t *testing.T) { stats, _ := statsd.NewNoopClient() va := NewValidationAuthorityImpl(&PortConfig{}, nil, stats, clock.Default()) va.DNSResolver = &mocks.DNSResolver{} mockRA := &MockRegistrationAuthority{} va.RA = mockRA chall := core.HTTPChallenge01(accountKey) chall.ValidationRecord = []core.ValidationRecord{} err := setChallengeToken(&chall, core.NewToken()) test.AssertNotError(t, err, "Failed to complete HTTP challenge") var authz = core.Authorization{ ID: core.NewToken(), RegistrationID: 1, Identifier: ident, Challenges: []core.Challenge{chall}, } started := time.Now() va.UpdateValidations(authz, 0) took := time.Since(started) // Check that the call to va.UpdateValidations didn't block for 3 seconds test.Assert(t, (took < (time.Second * 3)), "UpdateValidations blocked") }
func TestValidateHTTP(t *testing.T) { chall := core.HTTPChallenge01(accountKey) err := setChallengeToken(&chall, core.NewToken()) test.AssertNotError(t, err, "Failed to complete HTTP challenge") hs := httpSrv(t, chall.Token) port, err := getPort(hs) test.AssertNotError(t, err, "failed to get test server port") stats, _ := statsd.NewNoopClient() va := NewValidationAuthorityImpl(&PortConfig{HTTPPort: port}, nil, stats, clock.Default()) va.DNSResolver = &mocks.DNSResolver{} mockRA := &MockRegistrationAuthority{} va.RA = mockRA defer hs.Close() var authz = core.Authorization{ ID: core.NewToken(), RegistrationID: 1, Identifier: ident, Challenges: []core.Challenge{chall}, } va.validate(authz, 0) test.AssertEquals(t, core.StatusValid, mockRA.lastAuthz.Challenges[0].Status) }
func TestHTTPRedirectLookup(t *testing.T) { chall := core.HTTPChallenge01(accountKey) err := setChallengeToken(&chall, expectedToken) test.AssertNotError(t, err, "Failed to complete HTTP challenge") hs := httpSrv(t, expectedToken) defer hs.Close() port, err := getPort(hs) test.AssertNotError(t, err, "failed to get test server port") stats, _ := statsd.NewNoopClient() va := NewValidationAuthorityImpl(&PortConfig{HTTPPort: port}, nil, stats, clock.Default()) va.DNSResolver = &bdns.MockDNSResolver{} log.Clear() setChallengeToken(&chall, pathMoved) _, prob := va.validateHTTP01(context.Background(), ident, chall) if prob != nil { t.Fatalf("Unexpected failure in redirect (%s): %s", pathMoved, prob) } test.AssertEquals(t, len(log.GetAllMatching(`redirect from ".*/`+pathMoved+`" to ".*/`+pathValid+`"`)), 1) test.AssertEquals(t, len(log.GetAllMatching(`Resolved addresses for localhost \[using 127.0.0.1\]: \[127.0.0.1\]`)), 2) log.Clear() setChallengeToken(&chall, pathFound) _, prob = va.validateHTTP01(context.Background(), ident, chall) if prob != nil { t.Fatalf("Unexpected failure in redirect (%s): %s", pathFound, prob) } test.AssertEquals(t, len(log.GetAllMatching(`redirect from ".*/`+pathFound+`" to ".*/`+pathMoved+`"`)), 1) test.AssertEquals(t, len(log.GetAllMatching(`redirect from ".*/`+pathMoved+`" to ".*/`+pathValid+`"`)), 1) test.AssertEquals(t, len(log.GetAllMatching(`Resolved addresses for localhost \[using 127.0.0.1\]: \[127.0.0.1\]`)), 3) log.Clear() setChallengeToken(&chall, pathReLookupInvalid) _, err = va.validateHTTP01(context.Background(), ident, chall) test.AssertError(t, err, chall.Token) test.AssertEquals(t, len(log.GetAllMatching(`Resolved addresses for localhost \[using 127.0.0.1\]: \[127.0.0.1\]`)), 1) test.AssertEquals(t, len(log.GetAllMatching(`No IPv4 addresses found for invalid.invalid`)), 1) log.Clear() setChallengeToken(&chall, pathReLookup) _, prob = va.validateHTTP01(context.Background(), ident, chall) if prob != nil { t.Fatalf("Unexpected error in redirect (%s): %s", pathReLookup, prob) } test.AssertEquals(t, len(log.GetAllMatching(`redirect from ".*/`+pathReLookup+`" to ".*other.valid:\d+/path"`)), 1) test.AssertEquals(t, len(log.GetAllMatching(`Resolved addresses for localhost \[using 127.0.0.1\]: \[127.0.0.1\]`)), 1) test.AssertEquals(t, len(log.GetAllMatching(`Resolved addresses for other.valid \[using 127.0.0.1\]: \[127.0.0.1\]`)), 1) log.Clear() setChallengeToken(&chall, pathRedirectPort) _, err = va.validateHTTP01(context.Background(), ident, chall) test.AssertError(t, err, chall.Token) test.AssertEquals(t, len(log.GetAllMatching(`redirect from ".*/port-redirect" to ".*other.valid:8080/path"`)), 1) test.AssertEquals(t, len(log.GetAllMatching(`Resolved addresses for localhost \[using 127.0.0.1\]: \[127.0.0.1\]`)), 1) test.AssertEquals(t, len(log.GetAllMatching(`Resolved addresses for other.valid \[using 127.0.0.1\]: \[127.0.0.1\]`)), 1) }
func TestHTTPRedirectLookup(t *testing.T) { chall := core.HTTPChallenge01(accountKey) err := setChallengeToken(&chall, expectedToken) test.AssertNotError(t, err, "Failed to complete HTTP challenge") hs := httpSrv(t, expectedToken) defer hs.Close() port, err := getPort(hs) test.AssertNotError(t, err, "failed to get test server port") stats, _ := statsd.NewNoopClient() va := NewValidationAuthorityImpl(&PortConfig{HTTPPort: port}, nil, stats, clock.Default()) va.DNSResolver = &mocks.DNSResolver{} log.Clear() setChallengeToken(&chall, pathMoved) finChall, err := va.validateHTTP01(ident, chall) test.AssertEquals(t, finChall.Status, core.StatusValid) test.AssertNotError(t, err, chall.Token) test.AssertEquals(t, len(log.GetAllMatching(`redirect from ".*/`+pathMoved+`" to ".*/`+pathValid+`"`)), 1) test.AssertEquals(t, len(log.GetAllMatching(`Resolved addresses for localhost \[using 127.0.0.1\]: \[127.0.0.1\]`)), 2) log.Clear() setChallengeToken(&chall, pathFound) finChall, err = va.validateHTTP01(ident, chall) test.AssertEquals(t, finChall.Status, core.StatusValid) test.AssertNotError(t, err, chall.Token) test.AssertEquals(t, len(log.GetAllMatching(`redirect from ".*/`+pathFound+`" to ".*/`+pathMoved+`"`)), 1) test.AssertEquals(t, len(log.GetAllMatching(`redirect from ".*/`+pathMoved+`" to ".*/`+pathValid+`"`)), 1) test.AssertEquals(t, len(log.GetAllMatching(`Resolved addresses for localhost \[using 127.0.0.1\]: \[127.0.0.1\]`)), 3) log.Clear() setChallengeToken(&chall, pathReLookupInvalid) finChall, err = va.validateHTTP01(ident, chall) test.AssertEquals(t, finChall.Status, core.StatusInvalid) test.AssertError(t, err, chall.Token) test.AssertEquals(t, len(log.GetAllMatching(`Resolved addresses for localhost \[using 127.0.0.1\]: \[127.0.0.1\]`)), 1) test.AssertEquals(t, len(log.GetAllMatching(`No IPv4 addresses found for invalid.invalid`)), 1) log.Clear() setChallengeToken(&chall, pathReLookup) finChall, err = va.validateHTTP01(ident, chall) test.AssertEquals(t, finChall.Status, core.StatusValid) test.AssertNotError(t, err, chall.Token) test.AssertEquals(t, len(log.GetAllMatching(`redirect from ".*/`+pathReLookup+`" to ".*other.valid:\d+/path"`)), 1) test.AssertEquals(t, len(log.GetAllMatching(`Resolved addresses for localhost \[using 127.0.0.1\]: \[127.0.0.1\]`)), 1) test.AssertEquals(t, len(log.GetAllMatching(`Resolved addresses for other.valid \[using 127.0.0.1\]: \[127.0.0.1\]`)), 1) log.Clear() setChallengeToken(&chall, pathRedirectPort) finChall, err = va.validateHTTP01(ident, chall) fmt.Println(finChall.ValidationRecord) test.AssertEquals(t, finChall.Status, core.StatusInvalid) test.AssertError(t, err, chall.Token) test.AssertEquals(t, len(log.GetAllMatching(`redirect from ".*/port-redirect" to ".*other.valid:8080/path"`)), 1) test.AssertEquals(t, len(log.GetAllMatching(`Resolved addresses for localhost \[using 127.0.0.1\]: \[127.0.0.1\]`)), 1) test.AssertEquals(t, len(log.GetAllMatching(`Resolved addresses for other.valid \[using 127.0.0.1\]: \[127.0.0.1\]`)), 1) }
// ChallengesFor makes a decision of what challenges, and combinations, are // acceptable for the given identifier. // // Note: Current implementation is static, but future versions may not be. func (pa PolicyAuthorityImpl) ChallengesFor(identifier core.AcmeIdentifier, accountKey *jose.JsonWebKey) (challenges []core.Challenge, combinations [][]int, err error) { // TODO(https://github.com/letsencrypt/boulder/issues/894): Update these lines challenges = []core.Challenge{ core.SimpleHTTPChallenge(accountKey), core.DvsniChallenge(accountKey), core.HTTPChallenge01(accountKey), core.TLSSNIChallenge01(accountKey), } combinations = [][]int{[]int{0}, []int{1}, []int{2}, []int{3}} return }
func TestHTTPRedirectLookup(t *testing.T) { chall := core.HTTPChallenge01(accountKey) setChallengeToken(&chall, expectedToken) hs := httpSrv(t, expectedToken) defer hs.Close() port, err := getPort(hs) test.AssertNotError(t, err, "failed to get test server port") va, _, log := setup() va.httpPort = port setChallengeToken(&chall, pathMoved) _, prob := va.validateHTTP01(ctx, ident, chall) if prob != nil { t.Fatalf("Unexpected failure in redirect (%s): %s", pathMoved, prob) } test.AssertEquals(t, len(log.GetAllMatching(`redirect from ".*/`+pathMoved+`" to ".*/`+pathValid+`"`)), 1) test.AssertEquals(t, len(log.GetAllMatching(`Resolved addresses for localhost \[using 127.0.0.1\]: \[127.0.0.1\]`)), 2) log.Clear() setChallengeToken(&chall, pathFound) _, prob = va.validateHTTP01(ctx, ident, chall) if prob != nil { t.Fatalf("Unexpected failure in redirect (%s): %s", pathFound, prob) } test.AssertEquals(t, len(log.GetAllMatching(`redirect from ".*/`+pathFound+`" to ".*/`+pathMoved+`"`)), 1) test.AssertEquals(t, len(log.GetAllMatching(`redirect from ".*/`+pathMoved+`" to ".*/`+pathValid+`"`)), 1) test.AssertEquals(t, len(log.GetAllMatching(`Resolved addresses for localhost \[using 127.0.0.1\]: \[127.0.0.1\]`)), 3) log.Clear() setChallengeToken(&chall, pathReLookupInvalid) _, err = va.validateHTTP01(ctx, ident, chall) test.AssertError(t, err, chall.Token) test.AssertEquals(t, len(log.GetAllMatching(`Resolved addresses for localhost \[using 127.0.0.1\]: \[127.0.0.1\]`)), 1) test.AssertEquals(t, len(log.GetAllMatching(`No IPv4 addresses found for invalid.invalid`)), 1) log.Clear() setChallengeToken(&chall, pathReLookup) _, prob = va.validateHTTP01(ctx, ident, chall) if prob != nil { t.Fatalf("Unexpected error in redirect (%s): %s", pathReLookup, prob) } test.AssertEquals(t, len(log.GetAllMatching(`redirect from ".*/`+pathReLookup+`" to ".*other.valid:\d+/path"`)), 1) test.AssertEquals(t, len(log.GetAllMatching(`Resolved addresses for localhost \[using 127.0.0.1\]: \[127.0.0.1\]`)), 1) test.AssertEquals(t, len(log.GetAllMatching(`Resolved addresses for other.valid \[using 127.0.0.1\]: \[127.0.0.1\]`)), 1) log.Clear() setChallengeToken(&chall, pathRedirectPort) _, err = va.validateHTTP01(ctx, ident, chall) test.AssertError(t, err, chall.Token) test.AssertEquals(t, len(log.GetAllMatching(`redirect from ".*/port-redirect" to ".*other.valid:8080/path"`)), 1) test.AssertEquals(t, len(log.GetAllMatching(`Resolved addresses for localhost \[using 127.0.0.1\]: \[127.0.0.1\]`)), 1) test.AssertEquals(t, len(log.GetAllMatching(`Resolved addresses for other.valid \[using 127.0.0.1\]: \[127.0.0.1\]`)), 1) }
func TestValidateHTTP(t *testing.T) { chall := core.HTTPChallenge01() setChallengeToken(&chall, core.NewToken()) hs := httpSrv(t, chall.Token) port, err := getPort(hs) test.AssertNotError(t, err, "failed to get test server port") va, _, _ := setup() va.httpPort = port defer hs.Close() _, prob := va.validateChallenge(ctx, ident, chall) test.Assert(t, prob == nil, "validation failed") }
func TestHTTPRedirectLoop(t *testing.T) { chall := core.HTTPChallenge01() setChallengeToken(&chall, "looper") hs := httpSrv(t, expectedToken) defer hs.Close() port, err := getPort(hs) test.AssertNotError(t, err, "failed to get test server port") va, _, _ := setup() va.httpPort = port _, prob := va.validateHTTP01(ctx, ident, chall) if prob == nil { t.Fatalf("Challenge should have failed for %s", chall.Token) } }
func TestHTTPRedirectLoop(t *testing.T) { chall := core.HTTPChallenge01(accountKey) setChallengeToken(&chall, "looper") hs := httpSrv(t, expectedToken) defer hs.Close() port, err := getPort(hs) test.AssertNotError(t, err, "failed to get test server port") stats, _ := statsd.NewNoopClient() va := NewValidationAuthorityImpl(&cmd.PortConfig{HTTPPort: port}, nil, nil, stats, clock.Default()) va.DNSResolver = &bdns.MockDNSResolver{} log.Clear() _, prob := va.validateHTTP01(ctx, ident, chall) if prob == nil { t.Fatalf("Challenge should have failed for %s", chall.Token) } }
func TestLimitedReader(t *testing.T) { chall := core.HTTPChallenge01() setChallengeToken(&chall, core.NewToken()) ident.Value = "localhost" hs := httpSrv(t, "01234567890123456789012345678901234567890123456789012345678901234567890123456789") port, err := getPort(hs) test.AssertNotError(t, err, "failed to get test server port") va, _, _ := setup() va.httpPort = port defer hs.Close() _, prob := va.validateChallenge(ctx, ident, chall) test.AssertEquals(t, prob.Type, probs.UnauthorizedProblem) test.Assert(t, strings.HasPrefix(prob.Detail, "Invalid response from "), "Expected failure due to truncation") }
func TestHTTPRedirectLoop(t *testing.T) { chall := core.HTTPChallenge01(accountKey) err := setChallengeToken(&chall, "looper") test.AssertNotError(t, err, "Failed to complete HTTP challenge") hs := httpSrv(t, expectedToken) defer hs.Close() port, err := getPort(hs) test.AssertNotError(t, err, "failed to get test server port") stats, _ := statsd.NewNoopClient() va := NewValidationAuthorityImpl(&PortConfig{HTTPPort: port}, nil, stats, clock.Default()) va.DNSResolver = &mocks.DNSResolver{} log.Clear() finChall, err := va.validateHTTP01(ident, chall) test.AssertEquals(t, finChall.Status, core.StatusInvalid) test.AssertError(t, err, chall.Token) fmt.Println(finChall) }
// ChallengesFor makes a decision of what challenges, and combinations, are // acceptable for the given identifier. // // Note: Current implementation is static, but future versions may not be. func (pa PolicyAuthorityImpl) ChallengesFor(identifier core.AcmeIdentifier, accountKey *jose.JsonWebKey) ([]core.Challenge, [][]int, error) { challenges := []core.Challenge{} // TODO(https://github.com/letsencrypt/boulder/issues/894): Remove this block if pa.enabledChallenges[core.ChallengeTypeSimpleHTTP] { challenges = append(challenges, core.SimpleHTTPChallenge(accountKey)) } // TODO(https://github.com/letsencrypt/boulder/issues/894): Remove this block if pa.enabledChallenges[core.ChallengeTypeDVSNI] { challenges = append(challenges, core.DvsniChallenge(accountKey)) } if pa.enabledChallenges[core.ChallengeTypeHTTP01] { challenges = append(challenges, core.HTTPChallenge01(accountKey)) } if pa.enabledChallenges[core.ChallengeTypeTLSSNI01] { challenges = append(challenges, core.TLSSNIChallenge01(accountKey)) } if pa.enabledChallenges[core.ChallengeTypeDNS01] { challenges = append(challenges, core.DNSChallenge01(accountKey)) } // We shuffle the challenges and combinations to prevent ACME clients from // relying on the specific order that boulder returns them in. shuffled := make([]core.Challenge, len(challenges)) combinations := make([][]int, len(challenges)) for i, challIdx := range pa.pseudoRNG.Perm(len(challenges)) { shuffled[i] = challenges[challIdx] combinations[i] = []int{i} } shuffledCombos := make([][]int, len(combinations)) for i, comboIdx := range pa.pseudoRNG.Perm(len(combinations)) { shuffledCombos[i] = combinations[comboIdx] } return shuffled, shuffledCombos, nil }
func TestHTTPRedirectUserAgent(t *testing.T) { chall := core.HTTPChallenge01() setChallengeToken(&chall, expectedToken) hs := httpSrv(t, expectedToken) defer hs.Close() port, err := getPort(hs) test.AssertNotError(t, err, "failed to get test server port") va, _, _ := setup() va.userAgent = rejectUserAgent va.httpPort = port setChallengeToken(&chall, pathMoved) _, prob := va.validateHTTP01(ctx, ident, chall) if prob == nil { t.Fatalf("Challenge with rejectUserAgent should have failed (%s).", pathMoved) } setChallengeToken(&chall, pathFound) _, prob = va.validateHTTP01(ctx, ident, chall) if prob == nil { t.Fatalf("Challenge with rejectUserAgent should have failed (%s).", pathFound) } }
func TestHTTPRedirectLookup(t *testing.T) { chall := core.HTTPChallenge01() setChallengeToken(&chall, expectedToken) hs := httpSrv(t, expectedToken) defer hs.Close() port, err := getPort(hs) test.AssertNotError(t, err, "failed to get test server port") va, _, log := setup() va.httpPort = port setChallengeToken(&chall, pathMoved) _, prob := va.validateHTTP01(ctx, ident, chall) if prob != nil { t.Fatalf("Unexpected failure in redirect (%s): %s", pathMoved, prob) } test.AssertEquals(t, len(log.GetAllMatching(`redirect from ".*/`+pathMoved+`" to ".*/`+pathValid+`"`)), 1) test.AssertEquals(t, len(log.GetAllMatching(`Resolved addresses for localhost \[using 127.0.0.1\]: \[127.0.0.1\]`)), 2) log.Clear() setChallengeToken(&chall, pathFound) _, prob = va.validateHTTP01(ctx, ident, chall) if prob != nil { t.Fatalf("Unexpected failure in redirect (%s): %s", pathFound, prob) } test.AssertEquals(t, len(log.GetAllMatching(`redirect from ".*/`+pathFound+`" to ".*/`+pathMoved+`"`)), 1) test.AssertEquals(t, len(log.GetAllMatching(`redirect from ".*/`+pathMoved+`" to ".*/`+pathValid+`"`)), 1) test.AssertEquals(t, len(log.GetAllMatching(`Resolved addresses for localhost \[using 127.0.0.1\]: \[127.0.0.1\]`)), 3) log.Clear() setChallengeToken(&chall, pathReLookupInvalid) _, err = va.validateHTTP01(ctx, ident, chall) test.AssertError(t, err, chall.Token) test.AssertEquals(t, len(log.GetAllMatching(`Resolved addresses for localhost \[using 127.0.0.1\]: \[127.0.0.1\]`)), 1) test.AssertEquals(t, len(log.GetAllMatching(`No valid IP addresses found for invalid.invalid`)), 1) log.Clear() setChallengeToken(&chall, pathReLookup) _, prob = va.validateHTTP01(ctx, ident, chall) if prob != nil { t.Fatalf("Unexpected error in redirect (%s): %s", pathReLookup, prob) } test.AssertEquals(t, len(log.GetAllMatching(`redirect from ".*/`+pathReLookup+`" to ".*other.valid:\d+/path"`)), 1) test.AssertEquals(t, len(log.GetAllMatching(`Resolved addresses for localhost \[using 127.0.0.1\]: \[127.0.0.1\]`)), 1) test.AssertEquals(t, len(log.GetAllMatching(`Resolved addresses for other.valid \[using 127.0.0.1\]: \[127.0.0.1\]`)), 1) log.Clear() setChallengeToken(&chall, pathRedirectPort) _, err = va.validateHTTP01(ctx, ident, chall) test.AssertError(t, err, chall.Token) test.AssertEquals(t, len(log.GetAllMatching(`redirect from ".*/port-redirect" to ".*other.valid:8080/path"`)), 1) test.AssertEquals(t, len(log.GetAllMatching(`Resolved addresses for localhost \[using 127.0.0.1\]: \[127.0.0.1\]`)), 1) test.AssertEquals(t, len(log.GetAllMatching(`Resolved addresses for other.valid \[using 127.0.0.1\]: \[127.0.0.1\]`)), 1) // This case will redirect from a valid host to a host that is throwing // HTTP 500 errors. The test case is ensuring that the connection error // is referencing the redirected to host, instead of the original host. log.Clear() setChallengeToken(&chall, pathRedirectToFailingURL) _, prob = va.validateHTTP01(ctx, ident, chall) test.AssertNotNil(t, prob, "Problem Details should not be nil") test.AssertEquals(t, prob.Detail, "Could not connect to other.valid") }
func TestHTTP(t *testing.T) { chall := core.HTTPChallenge01() setChallengeToken(&chall, expectedToken) // NOTE: We do not attempt to shut down the server. The problem is that the // "wait-long" handler sleeps for ten seconds, but this test finishes in less // than that. So if we try to call hs.Close() at the end of the test, we'll be // closing the test server while a request is still pending. Unfortunately, // there appears to be an issue in httptest that trips Go's race detector when // that happens, failing the test. So instead, we live with leaving the server // around till the process exits. // TODO(#1989): close hs hs := httpSrv(t, chall.Token) goodPort, err := getPort(hs) test.AssertNotError(t, err, "failed to get test server port") // Attempt to fail a challenge by telling the VA to connect to a port we are // not listening on. badPort := goodPort + 1 if badPort == 65536 { badPort = goodPort - 1 } va, _, log := setup() va.httpPort = badPort _, prob := va.validateHTTP01(ctx, ident, chall) if prob == nil { t.Fatalf("Server's down; expected refusal. Where did we connect?") } test.AssertEquals(t, prob.Type, probs.ConnectionProblem) va.httpPort = goodPort log.Clear() t.Logf("Trying to validate: %+v\n", chall) _, prob = va.validateHTTP01(ctx, ident, chall) if prob != nil { t.Errorf("Unexpected failure in HTTP validation: %s", prob) } test.AssertEquals(t, len(log.GetAllMatching(`\[AUDIT\] `)), 1) log.Clear() setChallengeToken(&chall, path404) _, prob = va.validateHTTP01(ctx, ident, chall) if prob == nil { t.Fatalf("Should have found a 404 for the challenge.") } test.AssertEquals(t, prob.Type, probs.UnauthorizedProblem) test.AssertEquals(t, len(log.GetAllMatching(`\[AUDIT\] `)), 1) log.Clear() setChallengeToken(&chall, pathWrongToken) // The "wrong token" will actually be the expectedToken. It's wrong // because it doesn't match pathWrongToken. _, prob = va.validateHTTP01(ctx, ident, chall) if prob == nil { t.Fatalf("Should have found the wrong token value.") } test.AssertEquals(t, prob.Type, probs.UnauthorizedProblem) test.AssertEquals(t, len(log.GetAllMatching(`\[AUDIT\] `)), 1) log.Clear() setChallengeToken(&chall, pathMoved) _, prob = va.validateHTTP01(ctx, ident, chall) if prob != nil { t.Fatalf("Failed to follow 301 redirect") } test.AssertEquals(t, len(log.GetAllMatching(`redirect from ".*/`+pathMoved+`" to ".*/`+pathValid+`"`)), 1) log.Clear() setChallengeToken(&chall, pathFound) _, prob = va.validateHTTP01(ctx, ident, chall) if prob != nil { t.Fatalf("Failed to follow 302 redirect") } test.AssertEquals(t, len(log.GetAllMatching(`redirect from ".*/`+pathFound+`" to ".*/`+pathMoved+`"`)), 1) test.AssertEquals(t, len(log.GetAllMatching(`redirect from ".*/`+pathMoved+`" to ".*/`+pathValid+`"`)), 1) ipIdentifier := core.AcmeIdentifier{Type: core.IdentifierType("ip"), Value: "127.0.0.1"} _, prob = va.validateHTTP01(ctx, ipIdentifier, chall) if prob == nil { t.Fatalf("IdentifierType IP shouldn't have worked.") } test.AssertEquals(t, prob.Type, probs.MalformedProblem) _, prob = va.validateHTTP01(ctx, core.AcmeIdentifier{Type: core.IdentifierDNS, Value: "always.invalid"}, chall) if prob == nil { t.Fatalf("Domain name is invalid.") } test.AssertEquals(t, prob.Type, probs.UnknownHostProblem) setChallengeToken(&chall, pathWaitLong) started := time.Now() _, prob = va.validateHTTP01(ctx, ident, chall) took := time.Since(started) // Check that the HTTP connection times out after 5 seconds and doesn't block for 10 seconds test.Assert(t, (took > (time.Second * 5)), "HTTP timed out before 5 seconds") test.Assert(t, (took < (time.Second * 10)), "HTTP connection didn't timeout after 5 seconds") if prob == nil { t.Fatalf("Connection should've timed out") } test.AssertEquals(t, prob.Type, probs.ConnectionProblem) }
func TestHttp(t *testing.T) { chall := core.HTTPChallenge01(accountKey) err := setChallengeToken(&chall, expectedToken) test.AssertNotError(t, err, "Failed to complete HTTP challenge") // NOTE: We do not attempt to shut down the server. The problem is that the // "wait-long" handler sleeps for ten seconds, but this test finishes in less // than that. So if we try to call hs.Close() at the end of the test, we'll be // closing the test server while a request is still pending. Unfortunately, // there appears to be an issue in httptest that trips Go's race detector when // that happens, failing the test. So instead, we live with leaving the server // around till the process exits. // TODO(#661): add hs.Close back, see ticket for blocker hs := httpSrv(t, chall.Token) goodPort, err := getPort(hs) test.AssertNotError(t, err, "failed to get test server port") // Attempt to fail a challenge by telling the VA to connect to a port we are // not listening on. badPort := goodPort + 1 if badPort == 65536 { badPort = goodPort - 1 } stats, _ := statsd.NewNoopClient() va := NewValidationAuthorityImpl(&PortConfig{HTTPPort: badPort}, nil, stats, clock.Default()) va.DNSResolver = &mocks.DNSResolver{} 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) va = NewValidationAuthorityImpl(&PortConfig{HTTPPort: goodPort}, nil, stats, clock.Default()) va.DNSResolver = &mocks.DNSResolver{} log.Clear() t.Logf("Trying to validate: %+v\n", chall) finChall, err := va.validateHTTP01(ident, chall) test.AssertEquals(t, finChall.Status, core.StatusValid) test.AssertNotError(t, err, "Error validating http") test.AssertEquals(t, len(log.GetAllMatching(`^\[AUDIT\] `)), 1) log.Clear() setChallengeToken(&chall, path404) 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, len(log.GetAllMatching(`^\[AUDIT\] `)), 1) log.Clear() setChallengeToken(&chall, pathWrongToken) // The "wrong token" will actually be the expectedToken. It's wrong // because it doesn't match pathWrongToken. 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, len(log.GetAllMatching(`^\[AUDIT\] `)), 1) log.Clear() setChallengeToken(&chall, pathMoved) finChall, err = va.validateHTTP01(ident, chall) test.AssertEquals(t, finChall.Status, core.StatusValid) test.AssertNotError(t, err, "Failed to follow 301 redirect") test.AssertEquals(t, len(log.GetAllMatching(`redirect from ".*/`+pathMoved+`" to ".*/`+pathValid+`"`)), 1) log.Clear() setChallengeToken(&chall, pathFound) finChall, err = va.validateHTTP01(ident, chall) test.AssertEquals(t, finChall.Status, core.StatusValid) test.AssertNotError(t, err, "Failed to follow 302 redirect") test.AssertEquals(t, len(log.GetAllMatching(`redirect from ".*/`+pathFound+`" to ".*/`+pathMoved+`"`)), 1) test.AssertEquals(t, len(log.GetAllMatching(`redirect from ".*/`+pathMoved+`" to ".*/`+pathValid+`"`)), 1) ipIdentifier := core.AcmeIdentifier{Type: core.IdentifierType("ip"), Value: "127.0.0.1"} 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) 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) setChallengeToken(&chall, pathWaitLong) started := time.Now() invalidChall, err = va.validateHTTP01(ident, chall) took := time.Since(started) // Check that the HTTP connection times out after 5 seconds and doesn't block for 10 seconds test.Assert(t, (took > (time.Second * 5)), "HTTP timed out before 5 seconds") 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) }