Skip to content

Commit dac12d6

Browse files
triluchAndrzej Voss
andauthored
Add CORS header support on metrics PUT/POST. (#60)
In the scenario where prom-aggregation-gateway is exposed to external client that writes metrics (so, browser for example) it should support adding CORS header (`Access-Control-Allow-Origin`) also on PUT/POST requests. This adds another layer of security (incorrect origins will be rejected) and allows matching origins to read the response from the gateway - browser client can confirm that metrics were indeed sent correctly. Also added few simple router tests for GET and PUT with both failed and successful CORS. Fixes #58 Signed-off-by: Andrzej Voss <git@poczta.tril.pl> Co-authored-by: Andrzej Voss <git@poczta.tril.pl>
1 parent 30831b9 commit dac12d6

File tree

2 files changed

+75
-1
lines changed

2 files changed

+75
-1
lines changed

routers/public.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ func setupAPIRouter(cfg ApiRouterConfig, agg *metrics.Aggregate, promConfig prom
3333
} else {
3434
corsConfig.AllowAllOrigins = true
3535
}
36+
corsHandler := cors.New(corsConfig)
3637
cfg.authAccounts = processAuthConfig(cfg.Accounts)
3738

3839
metricsMiddleware := middleware.New(middleware.Config{
@@ -47,13 +48,15 @@ func setupAPIRouter(cfg ApiRouterConfig, agg *metrics.Aggregate, promConfig prom
4748

4849
neededHandlers := []gin.HandlerFunc{}
4950

51+
neededHandlers = append(neededHandlers, corsHandler)
52+
5053
if len(cfg.Accounts) > 0 {
5154
neededHandlers = append(neededHandlers, gin.BasicAuth(cfg.authAccounts))
5255
}
5356

5457
r.GET("/metrics",
5558
mGin.Handler("getMetrics", metricsMiddleware),
56-
cors.New(corsConfig),
59+
corsHandler,
5760
agg.HandleRender,
5861
)
5962

routers/router_test.go

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,3 +181,74 @@ func TestAuthRouter(t *testing.T) {
181181
})
182182
}
183183
}
184+
185+
func TestCorsRouter(t *testing.T) {
186+
tests := []struct {
187+
name string
188+
path string
189+
method string
190+
corsDomain string
191+
origin string
192+
statusCode int
193+
expectedHeader string
194+
}{
195+
{
196+
"GET returning header on all allowed origins",
197+
"/metrics",
198+
"GET",
199+
"*",
200+
"https://cors-domain",
201+
200,
202+
"*",
203+
},
204+
{
205+
"PUT returning header on all allowed origins",
206+
"/metrics",
207+
"PUT",
208+
"*",
209+
"https://cors-domain",
210+
202,
211+
"*",
212+
},
213+
{
214+
"GET returning 403 and not returning header on origin not in cors config",
215+
"/metrics",
216+
"GET",
217+
"https://cors-domain",
218+
"https://invalid-domain",
219+
403,
220+
"",
221+
},
222+
{
223+
"PUT returning 403 and not returning header on origin not in cors config",
224+
"/metrics",
225+
"PUT",
226+
"https://cors-domain",
227+
"https://invalid-domain",
228+
403,
229+
"",
230+
},
231+
}
232+
233+
for idx, test := range tests {
234+
t.Run(fmt.Sprintf("test #%d: %s", idx+1, test.name), func(t *testing.T) {
235+
// setup router
236+
router := setupTestRouter(ApiRouterConfig{CorsDomain: test.corsDomain})
237+
238+
buf := bytes.NewBufferString("")
239+
req, err := http.NewRequest(test.method, test.path, buf)
240+
require.NoError(t, err)
241+
242+
req.Header.Set("origin", test.origin)
243+
244+
// make request
245+
w := httptest.NewRecorder()
246+
router.ServeHTTP(w, req)
247+
248+
assert.Equal(t, test.statusCode, w.Code)
249+
250+
responseHeaders := w.Header()
251+
assert.Equal(t, test.expectedHeader, responseHeaders.Get("access-control-allow-origin"))
252+
})
253+
}
254+
}

0 commit comments

Comments
 (0)