Example #1
0
// WithParseAndValidate represent a middleware handler. For POST or
// PUT requests, it also parses the request body as a form. The extracted valid
// token will be added to the context. The extracted token will be checked
// against the Blacklist. errHandler is an optional argument. Only the first
// item in the slice will be considered. Default errHandler is:
//
//		http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
//
// ProTip: Instead of passing the token as an HTML Header you can also add the token
// to a form (multipart/form-data) with an input name of access_token. If the
// token cannot be found within the Header the fallback triggers the lookup within the form.
func (s *Service) WithParseAndValidate(errHandler ...ctxhttp.Handler) ctxhttp.Middleware {
	var errH ctxhttp.Handler
	errH = ctxhttp.HandlerFunc(defaultTokenErrorHandler)
	if len(errHandler) == 1 && errHandler[0] != nil {
		errH = errHandler[0]
	}
	return func(h ctxhttp.Handler) ctxhttp.Handler {
		return ctxhttp.HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {

			token, err := jwt.ParseFromRequest(r, s.keyFunc)

			var inBL bool
			if token != nil {
				inBL = s.Blacklist.Has(token.Raw)
			}
			if token != nil && err == nil && token.Valid && !inBL {
				return h.ServeHTTPContext(NewContext(ctx, token), w, r)
			}
			if PkgLog.IsDebug() {
				PkgLog.Debug("ctxjwt.Service.Authenticate", "err", err, "token", token, "inBlacklist", inBL)
			}
			return errH.ServeHTTPContext(NewContextWithError(ctx, err), w, r)
		})
	}
}
Example #2
0
func TestWithAccessLog(t *testing.T) {
	var buf bytes.Buffer
	defer buf.Reset()

	ctx := ctxlog.NewContext(context.Background(), log.NewStdLogger(log.SetStdWriter(&buf)))

	finalH := ctxhttp.Chain(
		ctxhttp.HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
			w.WriteHeader(http.StatusTeapot)
			_, err := w.Write([]byte{'1', '2', '3'})
			time.Sleep(time.Millisecond)
			return err
		}),
		ctxhttp.WithAccessLog(),
	)

	r, _ := http.NewRequest("GET", "/gopherine", nil)
	r.RemoteAddr = "127.0.0.1"
	r.Header.Set("User-Agent", "Mozilla")
	r.Header.Set("Referer", "http://rustlang.org")

	w := httptest.NewRecorder()
	if err := finalH.ServeHTTPContext(ctx, w, r); err != nil {
		t.Fatal(err)
	}

	assert.Exactly(t, `123`, w.Body.String())
	assert.Exactly(t, http.StatusTeapot, w.Code)

	want1 := `request error: "" method: "GET" uri: "/gopherine" type: "access" status: "error" status_code: 418 duration:`
	want2 := `size: 3 remote_addr: "127.0.0.1" user_agent: "Mozilla" referer: "http://rustlang.org"`
	assert.Contains(t, buf.String(), want1)
	assert.Contains(t, buf.String(), want2)
}
Example #3
0
func TestWithParseAndValidateInBlackList(t *testing.T) {
	bl := &testRealBL{}
	jm, err := ctxjwt.NewService(
		ctxjwt.WithBlacklist(bl),
	)
	assert.NoError(t, err)

	theToken, _, err := jm.GenerateToken(nil)
	bl.token = theToken
	assert.NoError(t, err)
	assert.NotEmpty(t, theToken)

	req, err := http.NewRequest("GET", "http://auth.xyz", nil)
	assert.NoError(t, err)
	ctxjwt.SetHeaderAuthorization(req, theToken)

	finalHandler := ctxhttp.HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
		w.WriteHeader(http.StatusTeapot)
		return nil
	})
	authHandler := jm.WithParseAndValidate()(finalHandler)

	wRec := httptest.NewRecorder()
	assert.NoError(t, authHandler.ServeHTTPContext(context.Background(), wRec, req))

	assert.NotEqual(t, http.StatusTeapot, wRec.Code)
	assert.Equal(t, http.StatusUnauthorized, wRec.Code)
}
Example #4
0
func TestWithParseAndValidateSuccess(t *testing.T) {
	jm, err := ctxjwt.NewService()
	assert.NoError(t, err)

	theToken, _, err := jm.GenerateToken(map[string]interface{}{
		"xfoo": "bar",
		"zfoo": 4711,
	})
	assert.NoError(t, err)
	assert.NotEmpty(t, theToken)

	req, err := http.NewRequest("GET", "http://auth.xyz", nil)
	assert.NoError(t, err)
	ctxjwt.SetHeaderAuthorization(req, theToken)

	finalHandler := ctxhttp.HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
		w.WriteHeader(http.StatusTeapot)
		fmt.Fprintf(w, "I'm more of a coffee pot")

		ctxToken, err := ctxjwt.FromContext(ctx)
		assert.NoError(t, err)
		assert.NotNil(t, ctxToken)
		assert.Exactly(t, "bar", ctxToken.Claims["xfoo"].(string))

		return nil
	})
	authHandler := jm.WithParseAndValidate()(finalHandler)

	wRec := httptest.NewRecorder()
	assert.NoError(t, authHandler.ServeHTTPContext(context.Background(), wRec, req))
	assert.Equal(t, http.StatusTeapot, wRec.Code)
	assert.Equal(t, `I'm more of a coffee pot`, wRec.Body.String())
}
Example #5
0
// WithIsCountryAllowedByIP a more advanced function. It expects from the context
// the store.ManagerReader ...
func (s *Service) WithIsCountryAllowedByIP() ctxhttp.Middleware {
	return func(h ctxhttp.Handler) ctxhttp.Handler {
		return ctxhttp.HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {

			_, requestedStore, err := store.FromContextReader(ctx)
			if err != nil {
				if PkgLog.IsDebug() {
					PkgLog.Debug("geoip.WithCountryByIP.FromContextManagerReader", "err", err)
				}
				return errgo.Mask(err)
			}

			var ipCountry *IPCountry
			ctx, ipCountry, err = s.newContextCountryByIP(ctx, r)
			if err != nil {
				ctx = NewContextWithError(ctx, err)
				return h.ServeHTTPContext(ctx, w, r)
			}

			allowedCountries, err := directory.AllowedCountries(requestedStore.Config)
			if err != nil {
				if PkgLog.IsDebug() {
					PkgLog.Debug("geoip.WithCountryByIP.directory.AllowedCountries", "err", err, "st.Config", requestedStore.Config)
				}
				return errgo.Mask(err)
			}

			if false == s.IsAllowed(requestedStore, ipCountry, allowedCountries, r) {
				h = s.altHandlerByID(requestedStore)
			}

			return h.ServeHTTPContext(ctx, w, r)
		})
	}
}
Example #6
0
// Benchmark_WithValidateBaseUrl-4         	    3000	    489089 ns/op	  188333 B/op	     272 allocs/op => with debug enabled
// Benchmark_WithValidateBaseUrl-4         	  200000	      8925 ns/op	    2924 B/op	      49 allocs/op => no debug
func Benchmark_WithValidateBaseUrl(b *testing.B) {
	// todo: there is room for optimization with disabled debugging. too many allocs
	store.PkgLog.SetLevel(log.StdLevelInfo)
	req, err := http.NewRequest(httputils.MethodGet, "https://corestore.io/customer/comments/view?id=1916#tab=ratings", nil)
	if err != nil {
		b.Fatal(err)
	}

	finalHandler := store.WithValidateBaseURL(middlewareConfigReader)(ctxhttp.HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
		return errors.New("This handler should not be called!")
	}))
	want := "https://www.corestore.io/customer/comments/view?id=1916#tab=ratings"
	rec := httptest.NewRecorder()
	b.ReportAllocs()
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		if err := finalHandler.ServeHTTPContext(middlewareCtxStoreService, rec, req); err != nil {
			b.Error(err)
		}
		if rec.HeaderMap.Get("Location") != want {
			b.Errorf("Have: %s\nWant: %s", rec.HeaderMap.Get("Location"), want)
		}
		rec.HeaderMap = nil
	}
}
Example #7
0
func finalHandlerWithValidateBaseURL(t *testing.T) ctxhttp.Handler {
	return ctxhttp.HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
		assert.NotNil(t, ctx)
		assert.NotNil(t, w)
		assert.NotNil(t, r)
		assert.Empty(t, w.Header().Get("Location"))
		return nil
	})
}
Example #8
0
func ipErrorFinalHandler(t *testing.T) ctxhttp.Handler {
	return ctxhttp.HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
		ipc, err, ok := geoip.FromContextCountry(ctx)
		assert.Nil(t, ipc)
		assert.True(t, ok)
		assert.EqualError(t, err, geoip.ErrCannotGetRemoteAddr.Error())
		return nil
	})
}
Example #9
0
func finalInitStoreHandler(t *testing.T, wantStoreCode string) ctxhttp.Handler {
	return ctxhttp.HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
		_, haveReqStore, err := store.FromContextReader(ctx)
		if err != nil {
			return err
		}
		assert.Exactly(t, wantStoreCode, haveReqStore.StoreCode())
		return nil
	})
}
Example #10
0
func TestCustomHTTPRateLimitHandlers(t *testing.T) {
	limiter := ctxthrottled.HTTPRateLimit{
		RateLimiter: &stubLimiter{},
		VaryBy:      &pathGetter{},
		DeniedHandler: ctxhttp.HandlerFunc(func(_ context.Context, w http.ResponseWriter, _ *http.Request) error {
			http.Error(w, "custom limit exceeded", 400)
			return nil
		}),
	}

	handler := limiter.WithRateLimit(nil, ctxhttp.HandlerFunc(func(_ context.Context, w http.ResponseWriter, _ *http.Request) error {
		w.WriteHeader(200)
		return nil
	}))

	runHTTPTestCases(t, handler, []httpTestCase{
		{"limit", 400, map[string]string{}},
		{"error", 500, map[string]string{}},
	})
}
Example #11
0
func finalHandlerFinland(t *testing.T) ctxhttp.Handler {
	return ctxhttp.HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
		ipc, err, ok := geoip.FromContextCountry(ctx)
		assert.NotNil(t, ipc)
		assert.True(t, ok)
		assert.NoError(t, err)
		assert.Exactly(t, "2a02:d200::", ipc.IP.String())
		assert.Exactly(t, "FI", ipc.Country.Country.IsoCode)
		return nil
	})
}
Example #12
0
// WithValidateBaseURL is a middleware which checks if the request base URL
// is equal to the one store in the configuration, if not
// i.e. redirect from http://example.com/store/ to http://www.example.com/store/
// @see app/code/Magento/Store/App/FrontController/Plugin/RequestPreprocessor.php
func WithValidateBaseURL(cr config.ReaderPubSuber) ctxhttp.Middleware {

	// Having the GetBool command here, means you must restart the app to take
	// changes in effect. @todo refactor and use pub/sub to automatically change
	// the isRedirectToBase value.
	checkBaseURL, err := cr.GetBool(config.Path(PathRedirectToBase)) // scope default
	if config.NotKeyNotFoundError(err) && PkgLog.IsDebug() {
		PkgLog.Debug("ctxhttp.WithValidateBaseUrl.GetBool", "err", err, "path", PathRedirectToBase)
	}

	redirectCode := http.StatusMovedPermanently
	if rc, err := cr.GetInt(config.Path(PathRedirectToBase)); rc != redirectCode && false == config.NotKeyNotFoundError(err) {
		redirectCode = http.StatusFound
	}

	return func(h ctxhttp.Handler) ctxhttp.Handler {
		return ctxhttp.HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {

			if checkBaseURL && r.Method != "POST" {

				_, requestedStore, err := FromContextReader(ctx)
				if err != nil {
					if PkgLog.IsDebug() {
						PkgLog.Debug("ctxhttp.WithValidateBaseUrl.FromContextServiceReader", "err", err, "ctx", ctx)
					}
					return errgo.Mask(err)
				}

				baseURL, err := requestedStore.BaseURL(config.URLTypeWeb, requestedStore.IsCurrentlySecure(r))
				if err != nil {
					if PkgLog.IsDebug() {
						PkgLog.Debug("ctxhttp.WithValidateBaseUrl.requestedStore.BaseURL", "err", err, "ctx", ctx)
					}
					return errgo.Mask(err)
				}

				if err := httputils.IsBaseURLCorrect(r, &baseURL); err != nil {
					if PkgLog.IsDebug() {
						PkgLog.Debug("store.WithValidateBaseUrl.IsBaseUrlCorrect.error", "err", err, "baseURL", baseURL, "request", r)
					}

					baseURL.Path = r.URL.Path
					baseURL.RawPath = r.URL.RawPath
					baseURL.RawQuery = r.URL.RawQuery
					baseURL.Fragment = r.URL.Fragment
					http.Redirect(w, r, (&baseURL).String(), redirectCode)
					return nil
				}
			}
			return h.ServeHTTPContext(ctx, w, r)
		})
	}
}
Example #13
0
// WithCountryByIP is a simple middleware which detects the country via an IP
// address. With the detected country a new tree context.Context gets created.
func (s *Service) WithCountryByIP() ctxhttp.Middleware {
	return func(h ctxhttp.Handler) ctxhttp.Handler {
		return ctxhttp.HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
			var err error
			ctx, _, err = s.newContextCountryByIP(ctx, r)
			if err != nil {
				ctx = NewContextWithError(ctx, err)
			}
			return h.ServeHTTPContext(ctx, w, r)
		})
	}
}
Example #14
0
func benchValidationHandler(b *testing.B, wantStoreCode string) ctxhttp.Handler {
	return ctxhttp.HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
		_, haveReqStore, err := store.FromContextReader(ctx)
		if err != nil {
			return err
		}

		if wantStoreCode != haveReqStore.StoreCode() {
			b.Errorf("Want: %s\nHave: %s", wantStoreCode, haveReqStore.StoreCode())
		}
		return nil
	})
}
Example #15
0
func TestWithValidateBaseUrl_ActivatedAndShouldRedirectWithGETRequest(t *testing.T) {

	var newReq = func(urlStr string) *http.Request {
		req, err := http.NewRequest(httputils.MethodGet, urlStr, nil)
		if err != nil {
			t.Fatal(err)
		}
		return req
	}

	tests := []struct {
		rec             *httptest.ResponseRecorder
		req             *http.Request
		wantRedirectURL string
	}{
		{
			httptest.NewRecorder(),
			newReq("http://corestore.io/catalog/product/view/"),
			"http://www.corestore.io/catalog/product/view/",
		},
		{
			httptest.NewRecorder(),
			newReq("http://corestore.io/catalog/product/view"),
			"http://www.corestore.io/catalog/product/view",
		},
		{
			httptest.NewRecorder(),
			newReq("http://corestore.io"),
			"http://www.corestore.io",
		},
		{
			httptest.NewRecorder(),
			newReq("https://corestore.io/catalog/category/view?catid=1916"),
			"https://www.corestore.io/catalog/category/view?catid=1916",
		},
		{
			httptest.NewRecorder(),
			newReq("https://corestore.io/customer/comments/view?id=1916#tab=ratings"),
			"https://www.corestore.io/customer/comments/view?id=1916#tab=ratings",
		},
	}

	for i, test := range tests {
		mw := store.WithValidateBaseURL(middlewareConfigReader)(ctxhttp.HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
			return fmt.Errorf("This handler should not be called! Iindex %d", i)
		}))
		assert.NoError(t, mw.ServeHTTPContext(middlewareCtxStoreService, test.rec, test.req), "Index %d", i)
		assert.Exactly(t, test.wantRedirectURL, test.rec.HeaderMap.Get("Location"), "Index %d", i)
	}
}
Example #16
0
func testAuth(t *testing.T, errH ctxhttp.Handler, opts ...ctxjwt.Option) (ctxhttp.Handler, string) {
	jm, err := ctxjwt.NewService(opts...)
	assert.NoError(t, err)
	theToken, _, err := jm.GenerateToken(map[string]interface{}{
		"xfoo": "bar",
		"zfoo": 4711,
	})
	assert.NoError(t, err)

	final := ctxhttp.HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
		w.WriteHeader(http.StatusOK)
		return nil
	})
	authHandler := jm.WithParseAndValidate(errH)(final)
	return authHandler, theToken
}
Example #17
0
// WithInitStoreByToken is a middleware which initializes a request based store
// via a JSON Web Token.
// Extracts the store.Reader and jwt.Token from context.Context. If the requested
// store is different than the initialized requested store than the new requested
// store will be saved in the context.
func WithInitStoreByToken() ctxhttp.Middleware {

	return func(h ctxhttp.Handler) ctxhttp.Handler {
		return ctxhttp.HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {

			storeService, requestedStore, err := FromContextReader(ctx)
			if err != nil {
				if PkgLog.IsDebug() {
					PkgLog.Debug("store.WithInitStoreByToken.FromContextServiceReader", "err", err, "ctx", ctx)
				}
				return errgo.Mask(err)
			}

			token, err := ctxjwt.FromContext(ctx)
			if err != nil {
				if PkgLog.IsDebug() {
					PkgLog.Debug("store.WithInitStoreByToken.ctxjwt.FromContext.err", "err", err, "ctx", ctx)
				}
				return errgo.Mask(err)
			}

			scopeOption, err := CodeFromClaim(token.Claims)
			if err != nil {
				if PkgLog.IsDebug() {
					PkgLog.Debug("store.WithInitStoreByToken.StoreCodeFromClaim", "err", err, "token", token, "ctx", ctx)
				}
				return errgo.Mask(err)
			}

			newRequestedStore, err := storeService.RequestedStore(scopeOption)
			if err != nil {
				if PkgLog.IsDebug() {
					PkgLog.Debug("store.WithInitStoreByToken.RequestedStore", "err", err, "token", token, "scopeOption", scopeOption, "ctx", ctx)
				}
				return errgo.Mask(err)
			}

			if newRequestedStore.StoreID() != requestedStore.StoreID() {
				// this may lead to a bug because the previously set storeService and requestedStore
				// will still exists and have not been removed.
				ctx = NewContextReader(ctx, storeService, newRequestedStore)
			}

			return h.ServeHTTPContext(ctx, w, r)
		})
	}
}
Example #18
0
func TestHTTPRateLimit(t *testing.T) {
	limiter := ctxthrottled.HTTPRateLimit{
		RateLimiter: &stubLimiter{},
		VaryBy:      &pathGetter{},
	}

	handler := limiter.WithRateLimit(nil, ctxhttp.HandlerFunc(func(_ context.Context, w http.ResponseWriter, _ *http.Request) error {
		w.WriteHeader(200)
		return nil
	}))

	runHTTPTestCases(t, handler, []httpTestCase{
		{"ok", 200, map[string]string{"X-Ratelimit-Limit": "1", "X-Ratelimit-Remaining": "2", "X-Ratelimit-Reset": "60"}},
		{"error", 500, map[string]string{}},
		{"limit", 429, map[string]string{"Retry-After": "60"}},
	})
}
Example #19
0
func TestWithParseAndValidateHTTPErrorHandler(t *testing.T) {

	authHandler, _ := testAuth(t, ctxhttp.HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
		tok, err := ctxjwt.FromContext(ctx)
		assert.Nil(t, tok)
		w.WriteHeader(http.StatusTeapot)
		_, err = w.Write([]byte(err.Error()))
		return err
	}))

	req, err := http.NewRequest("GET", "http://auth.xyz", nil)
	assert.NoError(t, err)
	w := httptest.NewRecorder()
	assert.NoError(t, authHandler.ServeHTTPContext(context.Background(), w, req))
	assert.Equal(t, http.StatusTeapot, w.Code)
	assert.Equal(t, "no token present in request", w.Body.String())
}
Example #20
0
File: http.go Project: levcom/csfw
// WithRateLimit wraps an ctxhttp.Handler to limit incoming requests.
// Requests that are not limited will be passed to the handler
// unchanged.  Limited requests will be passed to the DeniedHandler.
// X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset and
// Retry-After headers will be written to the response based on the
// values in the RateLimitResult.
func (t *HTTPRateLimit) WithRateLimit(rlStore throttled.GCRAStore, h ctxhttp.Handler) ctxhttp.Handler {
	if t.Config == nil {
		t.Config = config.DefaultManager
	}
	if t.DeniedHandler == nil {
		t.DeniedHandler = DefaultDeniedHandler
	}

	if t.RateLimiter == nil {
		if rlStore == nil {
			var err error
			rlStore, err = memstore.New(65536)
			if err != nil {
				panic(err)
			}
		}

		var err error
		t.RateLimiter, err = throttled.NewGCRARateLimiter(rlStore, t.quota())
		if err != nil {
			panic(err)
		}
	}

	return ctxhttp.HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {

		var k string
		if t.VaryBy != nil {
			k = t.VaryBy.Key(r)
		}

		limited, context, err := t.RateLimiter.RateLimit(k, 1)

		if err != nil {
			return err
		}

		setRateLimitHeaders(w, context)

		if !limited {
			return h.ServeHTTPContext(ctx, w, r)
		}

		return t.DeniedHandler.ServeHTTPContext(ctx, w, r)
	})
}
Example #21
0
func TestWithIsCountryAllowedByIPErrorStoreManager(t *testing.T) {
	s := mustGetTestService()
	defer deferClose(t, s.GeoIP)

	finalHandler := ctxhttp.HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
		ipc, err, ok := geoip.FromContextCountry(ctx)
		assert.Nil(t, ipc)
		assert.False(t, ok)
		assert.NoError(t, err)
		return nil
	})

	countryHandler := s.WithIsCountryAllowedByIP()(finalHandler)
	rec := httptest.NewRecorder()
	req, err := http.NewRequest("GET", "http://corestore.io", nil)
	assert.NoError(t, err)
	assert.EqualError(t, countryHandler.ServeHTTPContext(context.Background(), rec, req), store.ErrContextServiceNotFound.Error())
}
Example #22
0
func TestWithInitStoreByToken_EqualPointers(t *testing.T) {
	// this Test is related to Benchmark_WithInitStoreByToken
	// The returned pointers from store.FromContextReader must be the
	// same for each request with the same request pattern.

	ctx := newStoreServiceWithTokenCtx(scope.Option{Website: scope.MockID(2)}, "nz")
	rec := httptest.NewRecorder()
	req, err := http.NewRequest(httputils.MethodGet, "https://corestore.io/store/list", nil)
	if err != nil {
		t.Fatal(err)
	}

	var equalStorePointer *store.Store
	mw := store.WithInitStoreByToken()(ctxhttp.HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
		_, haveReqStore, err := store.FromContextReader(ctx)
		if err != nil {
			return err
		}

		if equalStorePointer == nil {
			equalStorePointer = haveReqStore
		}

		if "nz" != haveReqStore.StoreCode() {
			t.Errorf("Have: %s\nWant: nz", haveReqStore.StoreCode())
		}

		wantP := reflect.ValueOf(equalStorePointer)
		haveP := reflect.ValueOf(haveReqStore)

		if wantP.Pointer() != haveP.Pointer() {
			t.Errorf("Expecting equal pointers for each request.\nWant: %p\nHave: %p", equalStorePointer, haveReqStore)
		}

		return nil
	}))

	for i := 0; i < 10; i++ {
		if err := mw.ServeHTTPContext(ctx, rec, req); err != nil {
			t.Error(err)
		}
	}
}
Example #23
0
func TestWithCountryByIPErrorGetCountryByIP(t *testing.T) {
	s := mustGetTestService()
	s.GeoIP = geoReaderMock{}
	defer deferClose(t, s.GeoIP)

	finalHandler := ctxhttp.HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
		ipc, err, ok := geoip.FromContextCountry(ctx)
		assert.Nil(t, ipc)
		assert.True(t, ok)
		assert.EqualError(t, err, "Failed to read country from MMDB")
		return nil
	})

	countryHandler := s.WithCountryByIP()(finalHandler)
	rec := httptest.NewRecorder()
	req, err := http.NewRequest("GET", "http://corestore.io", nil)
	assert.NoError(t, err)
	req.Header.Set("X-Forwarded-For", "2a02:d200::")
	assert.NoError(t, countryHandler.ServeHTTPContext(context.Background(), rec, req))
}
Example #24
0
func bmServeHTTP(b *testing.B, opts ...ctxjwt.Option) {
	service, err := ctxjwt.NewService(opts...)
	if err != nil {
		b.Error(err)
	}
	token, _, err := service.GenerateToken(map[string]interface{}{
		"xfoo": "bar",
		"zfoo": 4711,
	})
	if err != nil {
		b.Error(err)
	}

	final := ctxhttp.HandlerFunc(func(_ context.Context, w http.ResponseWriter, _ *http.Request) error {
		w.WriteHeader(http.StatusTeapot)
		return nil
	})
	jwtHandler := service.WithParseAndValidate()(final)

	req, err := http.NewRequest("GET", "http://abc.xyz", nil)
	if err != nil {
		b.Error(err)
	}
	ctxjwt.SetHeaderAuthorization(req, token)
	w := httptest.NewRecorder()
	ctx := context.Background()

	b.ReportAllocs()
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		if err := jwtHandler.ServeHTTPContext(ctx, w, req); err != nil {
			b.Error(err)
		}
		if w.Code != http.StatusTeapot {
			b.Errorf("Response Code want %d; have %d", http.StatusTeapot, w.Code)
		}
	}
}
Example #25
0
func TestHTTPRateLimitConfig(t *testing.T) {
	cr := config.NewMockReader(
		config.WithMockValues(config.MockPV{
			config.MockPathScopeDefault(ctxthrottled.PathRateLimitBurst):    0,
			config.MockPathScopeDefault(ctxthrottled.PathRateLimitRequests): 1,
			config.MockPathScopeDefault(ctxthrottled.PathRateLimitDuration): "i",
		}),
	)

	limiter := ctxthrottled.HTTPRateLimit{
		Config: cr,
		VaryBy: &pathGetter{},
	}

	handler := limiter.WithRateLimit(nil, ctxhttp.HandlerFunc(func(_ context.Context, w http.ResponseWriter, _ *http.Request) error {
		w.WriteHeader(200)
		return nil
	}))

	runHTTPTestCases(t, handler, []httpTestCase{
		{"xx", 200, map[string]string{"X-Ratelimit-Limit": "1", "X-Ratelimit-Remaining": "0", "X-Ratelimit-Reset": "60"}},
		{"xx", 429, map[string]string{"X-Ratelimit-Limit": "1", "X-Ratelimit-Remaining": "0", "X-Ratelimit-Reset": "60", "Retry-After": "60"}},
	})
}
Example #26
0
			return h.ServeHTTPContext(ctx, w, r)
		})
	}
}

// DefaultAlternativeHandler gets called when detected IPCountry cannot be found
// within the list of allowed countries. This handler can be overridden depending
// on the overall scope (Website, Group or Store). This function gets called in
// WithIsCountryAllowedByIP.
//
// Status is StatusServiceUnavailable
var DefaultAlternativeHandler ctxhttp.Handler = defaultAlternativeHandler

var defaultAlternativeHandler ctxhttp.Handler = ctxhttp.HandlerFunc(func(_ context.Context, w http.ResponseWriter, _ *http.Request) error {
	http.Error(w, http.StatusText(http.StatusServiceUnavailable), http.StatusServiceUnavailable)
	return nil
})

// altHandlerByID searches in the hierarchical order of store -> group -> website
// the next alternative handler IF a country is not allowed as defined in function
// type IsAllowedFunc.
func (s *Service) altHandlerByID(st *store.Store) ctxhttp.Handler {

	if s.storeIDs != nil && s.storeAltH != nil {
		return findHandlerByID(scope.StoreID, st.StoreID(), s.storeIDs, s.storeAltH)
	}
	if s.groupIDs != nil && s.groupAltH != nil {
		return findHandlerByID(scope.GroupID, st.Group.GroupID(), s.groupIDs, s.groupAltH)
	}
	if s.websiteIDs != nil && s.websiteAltH != nil {
		return findHandlerByID(scope.WebsiteID, st.Website.WebsiteID(), s.websiteIDs, s.websiteAltH)
func ExampleWithInitStoreByToken() {
	initStore()
	ctx := store.NewContextReader(context.Background(), testStoreService)

	jwtService, err := ctxjwt.NewService(ctxjwt.WithPassword([]byte(`GÒph3r`)))

	finalHandler := ctxhttp.Chain(
		ctxhttp.HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
			_, haveReqStore, err := store.FromContextReader(ctx)
			if err != nil {
				return err
			}
			// now we know that the current request depends on the store view DE.
			fmt.Fprintf(w, "StoreCode: %s\n", haveReqStore.StoreCode())
			return nil
		}), // 								  executed 3rd
		store.WithInitStoreByToken(),      // executed 2nd
		jwtService.WithParseAndValidate(), // executed 1st
	)

	ts := httptest.NewServer(ctxhttp.NewAdapter(ctx, finalHandler))
	defer ts.Close()

	// Setup GET request
	token, _, err := jwtService.GenerateToken(
		map[string]interface{}{
			// Despite default store for Website ID 1 is AT we are currently
			// in the store context of DE.
			store.ParamName: "de",
		},
	)
	if err != nil {
		log.Fatal("jwtService.GenerateToken", "err", err)
	}

	req, err := http.NewRequest("GET", ts.URL, nil)
	if err != nil {
		log.Fatal("http.Get", "err", err)
	}
	ctxjwt.SetHeaderAuthorization(req, token)

	res, err := http.DefaultClient.Do(req)
	if err != nil {
		log.Fatal("http.DefaultClient.Do", "err", err)
	}

	response, err := ioutil.ReadAll(res.Body)
	if errC := res.Body.Close(); errC != nil {
		log.Fatal("res.Body.Close", "err", errC)
	}

	if err != nil {
		log.Fatal("ioutil.ReadAll", "err", err)
	}

	fmt.Printf("Response: %s\n", response)
	fmt.Printf("Log: %s\n", testDebugLogBuf.String())
	// Output:
	// Response: StoreCode: de
	//
	// Log:
}
Example #28
0
// WithInitStoreByFormCookie reads from a GET parameter or cookie the store code.
// Checks if the store code is valid and allowed. If so it adjusts the context.Context
// to provide the new requestedStore.
//
// It calls Reader.RequestedStore() to determine the correct store.
// 		1. check cookie store, always a string and the store code
// 		2. check for GET ___store variable, always a string and the store code
func WithInitStoreByFormCookie() ctxhttp.Middleware {
	return func(h ctxhttp.Handler) ctxhttp.Handler {
		return ctxhttp.HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {

			storeService, requestedStore, err := FromContextReader(ctx)
			if err != nil {
				if PkgLog.IsDebug() {
					PkgLog.Debug("store.WithInitStoreByToken.FromContextServiceReader", "err", err, "ctx", ctx)
				}
				return errgo.Mask(err)
			}

			var reqSO scope.Option

			reqSO, err = CodeFromRequestGET(r)
			if err != nil {
				if PkgLog.IsDebug() {
					PkgLog.Debug("store.WithInitStoreByFormCookie.StoreCodeFromRequestGET", "err", err, "req", r, "scope", reqSO)
				}

				reqSO, err = CodeFromCookie(r)
				if err != nil {
					// ignore further processing because all codes are invalid or not found
					if PkgLog.IsDebug() {
						PkgLog.Debug("store.WithInitStoreByFormCookie.StoreCodeFromCookie", "err", err, "req", r, "scope", reqSO)
					}
					return h.ServeHTTPContext(ctx, w, r)
				}
			}

			var newRequestedStore *Store
			if newRequestedStore, err = storeService.RequestedStore(reqSO); err != nil {
				if PkgLog.IsDebug() {
					PkgLog.Debug("store.WithInitStoreByFormCookie.storeService.RequestedStore", "err", err, "req", r, "scope", reqSO)
				}
				return errgo.Mask(err)
			}

			soStoreCode := reqSO.StoreCode()

			// delete and re-set a new cookie, adjust context.Context
			if newRequestedStore != nil && newRequestedStore.Data.Code.String == soStoreCode {
				wds, err := newRequestedStore.Website.DefaultStore()
				if err != nil {
					if PkgLog.IsDebug() {
						PkgLog.Debug("store.WithInitStoreByFormCookie.Website.DefaultStore", "err", err, "soStoreCode", soStoreCode)
					}
					return errgo.Mask(err)
				}
				if wds.Data.Code.String == soStoreCode {
					newRequestedStore.DeleteCookie(w) // cookie not needed anymore
				} else {
					newRequestedStore.SetCookie(w) // make sure we force set the new store

					if newRequestedStore.StoreID() != requestedStore.StoreID() {
						// this may lead to a bug because the previously set storeService and requestedStore
						// will still exists and have not been removed.
						ctx = NewContextReader(ctx, storeService, newRequestedStore)
					}
				}
			}

			return h.ServeHTTPContext(ctx, w, r)

		})
	}
}
Example #29
0
File: http.go Project: levcom/csfw
	// greater than or equal to zero.
	// Scope Global, Type Int.
	PathRateLimitBurst = `corestore/ctxthrottled/burst`
	// PathRateLimitRequests number of requests allowed per time period
	// Scope Global, Type Int.
	PathRateLimitRequests = `corestore/ctxthrottled/requests`
	// PathRateLimitDuration per second (s), minute (i), hour (h), day (d)
	// Scope Global, Type String.
	PathRateLimitDuration = `corestore/ctxthrottled/duration`
)

// DefaultDeniedHandler is the default DeniedHandler for an
// HTTPRateLimit. It returns a 429 status code with a generic
// message.
var DefaultDeniedHandler = ctxhttp.Handler(ctxhttp.HandlerFunc(func(_ context.Context, w http.ResponseWriter, _ *http.Request) error {
	http.Error(w, "limit exceeded", 429)
	return nil
}))

// DefaultBurst defines the number of requests that
// will be allowed to exceed the rate in a single burst and must be
// greater than or equal to zero.
var DefaultBurst int = 5

// DefaultRequests number of requests allowed per time period
var DefaultRequests int = 100

// DefaultDuration per second (s), minute (i), hour (h), day (d)
var DefaultDuration string = "h"

// HTTPRateLimit faciliates using a Limiter to limit HTTP requests.
type HTTPRateLimit struct {