Beispiel #1
0
func TestModifyRequest(t *testing.T) {
	m := NewModifier()
	m.SetRequestModifier(nil)

	req, err := http.NewRequest("CONNECT", "https://www.example.com", nil)
	if err != nil {
		t.Fatalf("http.NewRequest(): got %v, want no error", err)
	}

	ctx := session.FromContext(nil)
	martian.SetContext(req, ctx)
	defer martian.RemoveContext(req)

	if err := m.ModifyRequest(req); err != nil {
		t.Fatalf("ModifyRequest(): got %v, want no error", err)
	}

	actx := auth.FromContext(ctx)

	if got, want := actx.ID(), ""; got != want {
		t.Errorf("actx.ID(): got %q, want %q", got, want)
	}

	// IP with port and modifier with error.
	tm := martiantest.NewModifier()
	reqerr := errors.New("request error")
	tm.RequestError(reqerr)

	req.RemoteAddr = "1.1.1.1:8111"
	m.SetRequestModifier(tm)

	if err := m.ModifyRequest(req); err != reqerr {
		t.Fatalf("ModifyConnectRequest(): got %v, want %v", err, reqerr)
	}

	if got, want := actx.ID(), "1.1.1.1"; got != want {
		t.Errorf("actx.ID(): got %q, want %q", got, want)
	}

	// IP without port and modifier with auth error.
	req.RemoteAddr = "4.4.4.4"

	autherr := errors.New("auth error")
	tm.RequestError(nil)
	tm.RequestFunc(func(req *http.Request) {
		ctx := martian.Context(req)
		actx := auth.FromContext(ctx)

		actx.SetError(autherr)
	})

	if err := m.ModifyRequest(req); err != nil {
		t.Fatalf("ModifyRequest(): got %v, want no error", err)
	}

	if got, want := actx.ID(), ""; got != want {
		t.Errorf("actx.ID(): got %q, want %q", got, want)
	}
}
Beispiel #2
0
func TestModifyResponse(t *testing.T) {
	m := NewModifier()
	m.SetResponseModifier(nil)

	req, err := http.NewRequest("GET", "http://example.com", nil)
	if err != nil {
		t.Fatalf("http.NewRequest(): got %v, want no error", err)
	}

	ctx, err := session.FromContext(nil)
	if err != nil {
		t.Fatalf("session.FromContext(): got %v, want no error", err)
	}

	martian.SetContext(req, ctx)
	defer martian.RemoveContext(req)

	res := proxyutil.NewResponse(200, nil, req)
	if err := m.ModifyResponse(res); err != nil {
		t.Fatalf("ModifyResponse(): got %v, want no error", err)
	}

	// Modifier with error.
	tm := martiantest.NewModifier()
	reserr := errors.New("response error")
	tm.ResponseError(reserr)

	m.SetResponseModifier(tm)
	if err := m.ModifyResponse(res); err != reserr {
		t.Fatalf("ModifyResponse(): got %v, want %v", err, reserr)
	}

	// Modifier with auth error.
	tm.ResponseError(nil)
	autherr := errors.New("auth error")
	tm.ResponseFunc(func(res *http.Response) {
		ctx := martian.Context(res.Request)
		actx := auth.FromContext(ctx)

		actx.SetError(autherr)
	})

	actx := auth.FromContext(ctx)
	actx.SetID("bad-auth")

	if err := m.ModifyResponse(res); err != nil {
		t.Fatalf("ModifyResponse(): got %v, want no error", err)
	}
	if got, want := res.StatusCode, 403; got != want {
		t.Errorf("res.StatusCode: got %d, want %d", got, want)
	}

	if got, want := actx.Error(), autherr; got != want {
		t.Errorf("actx.Error(): got %v, want %v", got, want)
	}
}
Beispiel #3
0
// ModifyResponse sets the status code to 400 Bad Request if a loop was
// detected in the request.
func (m *viaModifier) ModifyResponse(res *http.Response) error {
	ctx := martian.Context(res.Request)

	if err, _ := ctx.Get(viaLoopKey); err != nil {
		res.StatusCode = 400
		res.Status = http.StatusText(400)

		return err.(error)
	}

	return nil
}
Beispiel #4
0
// ModifyResponse runs resmod.ModifyResponse and modifies the response to
// include the correct status code and headers if auth error is present.
//
// If an error is returned from resmod.ModifyResponse it is returned.
func (m *Modifier) ModifyResponse(res *http.Response) error {
	ctx := martian.Context(res.Request)
	actx := auth.FromContext(ctx)

	err := m.resmod.ModifyResponse(res)

	if actx.Error() != nil {
		res.StatusCode = http.StatusProxyAuthRequired
		res.Header.Set("Proxy-Authenticate", "Basic")
	}

	return err
}
Beispiel #5
0
// ModifyResponse runs resmod.ModifyResponse.
//
// If an error is returned from resmod.ModifyResponse it is returned.
func (m *Modifier) ModifyResponse(res *http.Response) error {
	ctx := martian.Context(res.Request)
	actx := auth.FromContext(ctx)

	err := m.resmod.ModifyResponse(res)

	if actx.Error() != nil {
		res.StatusCode = 403
		res.Status = http.StatusText(403)
	}

	return err
}
Beispiel #6
0
// ModifyRequest runs the RequestModifier for the associated auth ID. If no
// modifier is found for auth ID then auth error is set.
func (f *Filter) ModifyRequest(req *http.Request) error {
	ctx := martian.Context(req)
	actx := FromContext(ctx)

	if reqmod, ok := f.reqmods[actx.ID()]; ok {
		return reqmod.ModifyRequest(req)
	}

	if err := f.requireKnownAuth(actx.ID()); err != nil {
		actx.SetError(err)
	}

	return nil
}
Beispiel #7
0
// ModifyRequest sets the auth ID in the context from the request iff it has
// not already been set and runs reqmod.ModifyRequest. If the underlying
// modifier has indicated via auth error that no valid auth credentials
// have been found we set ctx.SkipRoundTrip.
func (m *Modifier) ModifyRequest(req *http.Request) error {
	ctx := martian.Context(req)
	actx := auth.FromContext(ctx)

	actx.SetID(id(req.Header))

	err := m.reqmod.ModifyRequest(req)

	if actx.Error() != nil {
		ctx.SkipRoundTrip()
	}

	return err
}
Beispiel #8
0
// ModifyRequest sets the auth ID in the context from the request iff it has
// not already been set and runs reqmod.ModifyRequest. If the underlying
// modifier has indicated via auth error that no valid auth credentials
// have been found we set ctx.SkipRoundTrip.
func (m *Modifier) ModifyRequest(req *http.Request) error {
	ctx := martian.Context(req)
	actx := auth.FromContext(ctx)

	ip, _, err := net.SplitHostPort(req.RemoteAddr)
	if err != nil {
		ip = req.RemoteAddr
	}

	actx.SetID(ip)

	err = m.reqmod.ModifyRequest(req)

	if actx.Error() != nil {
		ctx.SkipRoundTrip()
	}

	return err
}
Beispiel #9
0
// ModifyRequest sets the Via header and provides loop-detection. If Via is
// already present, it will be appended to the existing value. If a loop is
// detected an error is added to the context and the request round trip is
// skipped.
//
// http://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-14#section-9.9
func (m *viaModifier) ModifyRequest(req *http.Request) error {
	via := fmt.Sprintf("%d.%d %s", req.ProtoMajor, req.ProtoMinor, m.requestedBy)

	if v := req.Header.Get("Via"); v != "" {
		if strings.Contains(v, m.requestedBy) {
			err := fmt.Errorf("via: detected request loop, header contains %s", m.requestedBy)

			ctx := martian.Context(req)
			ctx.Set(viaLoopKey, err)
			ctx.SkipRoundTrip()

			return err
		}

		via = fmt.Sprintf("%s, %s", v, via)
	}

	req.Header.Set("Via", via)

	return nil
}
Beispiel #10
0
// ModifyResponse logs responses.
func (l *Logger) ModifyResponse(res *http.Response) error {
	ctx := martian.Context(res.Request)
	id := ctx.ID()

	return l.LogResponse(id, res)
}
Beispiel #11
0
// ModifyRequest logs requests.
func (l *Logger) ModifyRequest(req *http.Request) error {
	ctx := martian.Context(req)
	id := ctx.ID()

	return l.LogRequest(id, req)
}
Beispiel #12
0
func TestProxyAuthInvalidCredentials(t *testing.T) {
	m := NewModifier()
	autherr := errors.New("auth error")

	tm := martiantest.NewModifier()
	tm.RequestFunc(func(req *http.Request) {
		ctx := martian.Context(req)
		actx := auth.FromContext(ctx)

		actx.SetError(autherr)
	})
	tm.ResponseFunc(func(res *http.Response) {
		ctx := martian.Context(res.Request)
		actx := auth.FromContext(ctx)

		actx.SetError(autherr)
	})

	m.SetRequestModifier(tm)
	m.SetResponseModifier(tm)

	req, err := http.NewRequest("GET", "http://example.com", nil)
	if err != nil {
		t.Fatalf("http.NewRequest(): got %v, want no error", err)
	}
	req.Header.Set("Proxy-Authorization", "Basic "+encode("user:pass"))

	ctx, err := session.FromContext(nil)
	if err != nil {
		t.Fatalf("session.FromContext(): got %v, want no error", err)
	}

	martian.SetContext(req, ctx)
	defer martian.RemoveContext(req)

	if err := m.ModifyRequest(req); err != nil {
		t.Fatalf("ModifyRequest(): got %v, want no error", err)
	}

	if !tm.RequestModified() {
		t.Error("tm.RequestModified(): got false, want true")
	}

	actx := auth.FromContext(ctx)
	if actx.Error() != autherr {
		t.Fatalf("auth.Error(): got %v, want %v", actx.Error(), autherr)
	}
	actx.SetError(nil)

	res := proxyutil.NewResponse(200, nil, req)

	if err := m.ModifyResponse(res); err != nil {
		t.Fatalf("ModifyResponse(): got %v, want no error", err)
	}

	if !tm.ResponseModified() {
		t.Error("tm.ResponseModified(): got false, want true")
	}

	if actx.Error() != autherr {
		t.Fatalf("auth.Error(): got %v, want %v", actx.Error(), autherr)
	}

	if got, want := res.StatusCode, http.StatusProxyAuthRequired; got != want {
		t.Errorf("res.StatusCode: got %d, want %d", got, want)
	}
	if got, want := res.Header.Get("Proxy-Authenticate"), "Basic"; got != want {
		t.Errorf("res.Header.Get(%q): got %q, want %q", "Proxy-Authenticate", got, want)
	}
}