From fd1ced5a8beed1b5913efe47741d42afc25cc752 Mon Sep 17 00:00:00 2001 From: xdrm-brackets Date: Sun, 20 Jun 2021 10:24:12 +0200 Subject: [PATCH] fix: restore request denied on invalid auth after contextual middlwares --- handler.go | 12 +++++++ handler_test.go | 92 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+) diff --git a/handler.go b/handler.go index 6a269bd..4dea77a 100644 --- a/handler.go +++ b/handler.go @@ -63,6 +63,18 @@ func (s Handler) resolve(w http.ResponseWriter, r *http.Request) { // create http handler var h http.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + auth := api.GetAuth(r.Context()) + if auth == nil { + handleError(api.ErrPermission, w, r) + return + } + + // reject non granted requests + if !auth.Granted() { + handleError(api.ErrPermission, w, r) + return + } + // use context defined in the request s.handle(r.Context(), input, handler, service, w, r) }) diff --git a/handler_test.go b/handler_test.go index eba1f0d..c5883c5 100644 --- a/handler_test.go +++ b/handler_test.go @@ -3,6 +3,7 @@ package aicra_test import ( "bytes" "context" + "encoding/json" "fmt" "net/http" "net/http/httptest" @@ -275,6 +276,97 @@ func TestWithAuth(t *testing.T) { } +func TestPermissionError(t *testing.T) { + + tt := []struct { + name string + manifest string + permissions []string + granted bool + }{ + { + name: "permission fulfilled", + manifest: `[ { "method": "GET", "path": "/path", "scope": [["A"]], "info": "info", "in": {}, "out": {} } ]`, + permissions: []string{"A"}, + granted: true, + }, + { + name: "missing permission", + manifest: `[ { "method": "GET", "path": "/path", "scope": [["A"]], "info": "info", "in": {}, "out": {} } ]`, + permissions: []string{}, + granted: false, + }, + } + + for _, tc := range tt { + t.Run(tc.name, func(t *testing.T) { + builder := &aicra.Builder{} + if err := addBuiltinTypes(builder); err != nil { + t.Fatalf("unexpected error <%v>", err) + } + + // add active permissions + builder.WithContext(func(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + a := api.GetAuth(r.Context()) + if a == nil { + t.Fatalf("cannot access api.Auth form request context") + } + + a.Active = tc.permissions + next.ServeHTTP(w, r) + }) + }) + + err := builder.Setup(strings.NewReader(tc.manifest)) + if err != nil { + t.Fatalf("setup: unexpected error <%v>", err) + } + + pathHandler := func(ctx context.Context) (*struct{}, api.Err) { + return nil, api.ErrNotImplemented + } + + if err := builder.Bind(http.MethodGet, "/path", pathHandler); err != nil { + t.Fatalf("bind: unexpected error <%v>", err) + } + + handler, err := builder.Build() + if err != nil { + t.Fatalf("build: unexpected error <%v>", err) + } + + response := httptest.NewRecorder() + request := httptest.NewRequest(http.MethodGet, "/path", &bytes.Buffer{}) + + // test request + handler.ServeHTTP(response, request) + if response.Body == nil { + t.Fatalf("response has no body") + } + type jsonResponse struct { + Err api.Err `json:"error"` + } + var res jsonResponse + err = json.Unmarshal(response.Body.Bytes(), &res) + if err != nil { + t.Fatalf("cannot unmarshal response: %s", err) + } + + expectedError := api.ErrNotImplemented + if !tc.granted { + expectedError = api.ErrPermission + } + + if res.Err.Code != expectedError.Code { + t.Fatalf("expected error code %d got %d", expectedError.Code, res.Err.Code) + } + + }) + } + +} + func TestDynamicScope(t *testing.T) { tt := []struct { name string