diff --git a/.circleci/config.yml b/.circleci/config.yml index 09dcf1b..e815e3b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -58,7 +58,8 @@ jobs: - run: name: Add a dummy OPA policy. command: | - curl -X PUT http://localhost:8181/v1/policies/publication_based_authorization -H 'Content-Type: text/plain' --data-raw 'package draft_annotations_api.publication_based_authorization is_authorized {true}' + curl -X PUT http://localhost:8181/v1/policies/read -H 'Content-Type: text/plain' --data-raw 'package draft_annotations_api.read is_authorized {true}' + curl -X PUT http://localhost:8181/v1/policies/write -H 'Content-Type: text/plain' --data-raw 'package draft_annotations_api.write is_authorized {true}' - run: name: Dredd API Testing command: dredd diff --git a/annotations/annotations_api.go b/annotations/annotations_api.go index 4795c9c..a1c3906 100644 --- a/annotations/annotations_api.go +++ b/annotations/annotations_api.go @@ -151,6 +151,10 @@ func (api *UPPAnnotationsAPI) getUPPAnnotationsResponse(ctx context.Context, con params.Add("lifecycle", lc) } + //by default publications are not returned from public-annotations-api, + //so we need to add this parameter to the query + params.Add("showPublication", "true") + baseURL.RawQuery = params.Encode() apiReqURI = baseURL.String() } diff --git a/annotations/annotations_api_test.go b/annotations/annotations_api_test.go index 9056e4a..6ddf488 100644 --- a/annotations/annotations_api_test.go +++ b/annotations/annotations_api_test.go @@ -66,7 +66,7 @@ func TestAnnotationsAPIGTGInvalidURL(t *testing.T) { } func TestAnnotationsAPIGTGConnectionError(t *testing.T) { - annotationsServerMock := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})) + annotationsServerMock := httptest.NewServer(http.HandlerFunc(func(_ http.ResponseWriter, _ *http.Request) {})) annotationsServerMock.Close() log := logger.NewUPPLogger("draft-annotations-api", "INFO") @@ -87,6 +87,7 @@ func TestHappyAnnotationsAPI(t *testing.T) { annotationsAPI := NewUPPAnnotationsAPI(testClient, annotationsServerMock.URL+"/content/%v/annotations", testBasicAuthUsername, testBasicAuthPassword, log) resp, err := annotationsAPI.getUPPAnnotationsResponse(ctx, uuid) assert.NoError(t, err) + defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) } @@ -95,13 +96,14 @@ func TestHappyAnnotationsAPIWithLifecycles(t *testing.T) { tid := "tid_all-good" ctx := tidUtils.TransactionAwareContext(context.TODO(), tid) - annotationsServerMock := newAnnotationsAPIServerMock(t, tid, uuid, "lifecycle=pac&lifecycle=v1&lifecycle=next-video", http.StatusOK, "I am happy!") + annotationsServerMock := newAnnotationsAPIServerMock(t, tid, uuid, "lifecycle=pac&lifecycle=v1&lifecycle=next-video&showPublication=true", http.StatusOK, "I am happy!") defer annotationsServerMock.Close() log := logger.NewUPPLogger("draft-annotations-api", "INFO") annotationsAPI := NewUPPAnnotationsAPI(testClient, annotationsServerMock.URL+"/content/%v/annotations", testBasicAuthUsername, testBasicAuthPassword, log) resp, err := annotationsAPI.getUPPAnnotationsResponse(ctx, uuid, pacAnnotationLifecycle, v1AnnotationLifecycle, nextVideoAnnotationLifecycle) assert.NoError(t, err) + defer resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) } @@ -117,6 +119,7 @@ func TestUnhappyAnnotationsAPI(t *testing.T) { annotationsAPI := NewUPPAnnotationsAPI(testClient, annotationsServerMock.URL+"/content/%v/annotations", testBasicAuthUsername, testBasicAuthPassword, log) resp, err := annotationsAPI.getUPPAnnotationsResponse(ctx, uuid) assert.NoError(t, err) + defer resp.Body.Close() assert.Equal(t, http.StatusServiceUnavailable, resp.StatusCode) } @@ -129,6 +132,7 @@ func TestNoTIDAnnotationsAPI(t *testing.T) { annotationsAPI := NewUPPAnnotationsAPI(testClient, annotationsServerMock.URL+"/content/%v/annotations", testBasicAuthUsername, testBasicAuthPassword, log) resp, err := annotationsAPI.getUPPAnnotationsResponse(context.TODO(), uuid) assert.NoError(t, err) + defer resp.Body.Close() assert.Equal(t, http.StatusServiceUnavailable, resp.StatusCode) } @@ -136,7 +140,9 @@ func TestRequestFailsAnnotationsAPI(t *testing.T) { log := logger.NewUPPLogger("draft-annotations-api", "INFO") annotationsAPI := NewUPPAnnotationsAPI(testClient, ":#", testBasicAuthUsername, testBasicAuthPassword, log) resp, err := annotationsAPI.getUPPAnnotationsResponse(context.TODO(), "") - + if err == nil { + defer resp.Body.Close() + } assert.Error(t, err) assert.Nil(t, resp) } @@ -145,7 +151,9 @@ func TestResponseFailsAnnotationsAPI(t *testing.T) { log := logger.NewUPPLogger("draft-annotations-api", "INFO") annotationsAPI := NewUPPAnnotationsAPI(testClient, "#:", testBasicAuthUsername, testBasicAuthPassword, log) resp, err := annotationsAPI.getUPPAnnotationsResponse(context.TODO(), "") - + if err == nil { + defer resp.Body.Close() + } assert.Error(t, err) assert.Nil(t, resp) } @@ -163,13 +171,15 @@ func TestAnnotationsAPITimeout(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*50) defer cancel() - _, err := annotationsAPI.getUPPAnnotationsResponse(ctx, testContentUUID) + resp, err := annotationsAPI.getUPPAnnotationsResponse(ctx, testContentUUID) + if err == nil { + defer resp.Body.Close() + } assert.Error(t, err) assert.True(t, (err.(net.Error)).Timeout()) } func TestGetAnnotationsHappy(t *testing.T) { - var testCases = []struct { name string annotationsStatus int diff --git a/handler/handler.go b/handler/handler.go index d54f45d..3497690 100644 --- a/handler/handler.go +++ b/handler/handler.go @@ -11,6 +11,7 @@ import ( "strings" "time" + "github.com/Financial-Times/draft-annotations-api/policy" "github.com/Financial-Times/go-logger/v2" "github.com/gorilla/mux" @@ -96,9 +97,11 @@ func (h *Handler) DeleteAnnotation(w http.ResponseWriter, r *http.Request) { return } + var scheduledForDelete interface{} i := 0 for _, item := range uppList { if item.(map[string]interface{})["id"] == conceptID { + scheduledForDelete = item continue } uppList[i] = item @@ -106,8 +109,24 @@ func (h *Handler) DeleteAnnotation(w http.ResponseWriter, r *http.Request) { } uppList = uppList[:i] + if !isAuthorizedForDelete(r, scheduledForDelete) { + writeLog.Infof("Not authorized to delete annotation with current policy: %s", r.Header.Get("X-Policy")) + w.WriteHeader(http.StatusForbidden) + _, _ = w.Write([]byte("Forbidden")) + return + } + annotationsBody := make(map[string]interface{}) annotationsBody["annotations"] = uppList + + //if the policy and the publication from the annotation match, set the publication in the annotations body + if scheduledForDelete != nil { + pub, ok := scheduledForDelete.(map[string]interface{})["publication"] + if ok { + annotationsBody["publication"] = pub + } + } + _, newHash, err := h.saveAndReturnAnnotations(ctx, annotationsBody, writeLog, oldHash, contentUUID) if err != nil { handleWriteErrors("Error writing draft annotations", err, writeLog, w, http.StatusInternalServerError) @@ -640,3 +659,51 @@ func switchToIsClassifiedBy(toChange []interface{}) []interface{} { } return changed } + +func isAuthorizedForDelete(r *http.Request, scheduledForDelete interface{}) bool { + if scheduledForDelete == nil { + return true + } + + publication, ok := scheduledForDelete.(map[string]interface{})["publication"].([]interface{}) + if !ok { + //if no publication is returned, we assume its FT PINK + publication = []interface{}{"88fdde6c-2aa4-4f78-af02-9f680097cfd6"} + } + + af := r.Header.Get("Access-From") + if af == "" { + //if access-from header is missing, we skip the policy check + return true + } + + policyHeaders := r.Header.Get("X-Policy") + policyHeaders = strings.ReplaceAll(policyHeaders, " ", "") + splitPolicyHeaders := strings.Split(policyHeaders, ",") + allowDelete := false + + for _, header := range splitPolicyHeaders { + //extract the publication from the policy header + incomingPublication := strings.ReplaceAll(header, policy.WritePBLC, "") + + //verify if the extracted uuid is valid + _, err := uuid.Parse(incomingPublication) + if err != nil { + continue + } + + if contains(incomingPublication, publication) { + allowDelete = true + } + } + return allowDelete +} + +func contains(needle string, haystack []interface{}) bool { + for _, v := range haystack { + if v == needle { + return true + } + } + return false +} diff --git a/handler/handler_test.go b/handler/handler_test.go index 06d0940..aed84ba 100644 --- a/handler/handler_test.go +++ b/handler/handler_test.go @@ -1,4 +1,4 @@ -package handler_test +package handler import ( "bytes" @@ -18,17 +18,15 @@ import ( "time" "github.com/Financial-Times/cm-annotations-ontology/validator" - "github.com/Financial-Times/go-logger/v2" - "github.com/gorilla/mux" - "github.com/stretchr/testify/require" - "github.com/Financial-Times/draft-annotations-api/annotations" - "github.com/Financial-Times/draft-annotations-api/handler" "github.com/Financial-Times/go-ft-http/fthttp" + "github.com/Financial-Times/go-logger/v2" tidutils "github.com/Financial-Times/transactionid-utils-go" randomdata "github.com/Pallinder/go-randomdata" + "github.com/gorilla/mux" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" ) const ( @@ -53,7 +51,7 @@ func TestHappyFetchFromAnnotationsRW(t *testing.T) { log := logger.NewUPPLogger("draft-annotations-api", "INFO") v := validator.NewSchemaValidator(log).GetJSONValidator() - h := handler.New(rw, annAPI, nil, aug, v, time.Second, log) + h := New(rw, annAPI, nil, aug, v, time.Second, log) r := mux.NewRouter() r.HandleFunc("/draft-annotations/content/{uuid}/annotations", h.ReadAnnotations).Methods(http.MethodGet) @@ -129,7 +127,7 @@ func TestReadHasBrandAnnotation(t *testing.T) { annAPI := &AnnotationsAPIMock{} log := logger.NewUPPLogger("draft-annotations-api", "INFO") v := validator.NewSchemaValidator(log).GetJSONValidator() - h := handler.New(rw, annAPI, nil, aug, v, time.Second, log) + h := New(rw, annAPI, nil, aug, v, time.Second, log) r := mux.NewRouter() r.HandleFunc("/draft-annotations/content/{uuid}/annotations", h.ReadAnnotations).Methods(http.MethodGet) @@ -176,7 +174,7 @@ func TestAddAnnotation(t *testing.T) { log := logger.NewUPPLogger("draft-annotations-api", "INFO") v := validator.NewSchemaValidator(log).GetJSONValidator() - h := handler.New(rw, annAPI, annotations.NewCanonicalizer(annotations.NewCanonicalAnnotationSorter), aug, v, time.Second, log) + h := New(rw, annAPI, annotations.NewCanonicalizer(annotations.NewCanonicalAnnotationSorter), aug, v, time.Second, log) router := mux.NewRouter() router.HandleFunc("/draft-annotations/content/{uuid}/annotations", h.AddAnnotation).Methods(http.MethodPost) @@ -298,7 +296,7 @@ func TestWriteHasBrandAnnotation(t *testing.T) { log := logger.NewUPPLogger("draft-annotations-api", "INFO") v := validator.NewSchemaValidator(log).GetJSONValidator() - h := handler.New(rw, annAPI, annotations.NewCanonicalizer(annotations.NewCanonicalAnnotationSorter), aug, v, time.Second, log) + h := New(rw, annAPI, annotations.NewCanonicalizer(annotations.NewCanonicalAnnotationSorter), aug, v, time.Second, log) router := mux.NewRouter() router.HandleFunc("/draft-annotations/content/{uuid}/annotations", h.WriteAnnotations).Methods(http.MethodPut) @@ -413,7 +411,7 @@ func TestReplaceHasBrandAnnotation(t *testing.T) { log := logger.NewUPPLogger("draft-annotations-api", "INFO") v := validator.NewSchemaValidator(log).GetJSONValidator() - h := handler.New(rw, annAPI, canonicalizer, aug, v, time.Second, log) + h := New(rw, annAPI, canonicalizer, aug, v, time.Second, log) router := mux.NewRouter() router.HandleFunc("/draft-annotations/content/{uuid}/annotations/{cuuid}", h.ReplaceAnnotation).Methods(http.MethodPatch) @@ -552,7 +550,7 @@ func TestUnHappyFetchFromAnnotationsRW(t *testing.T) { log := logger.NewUPPLogger("draft-annotations-api", "INFO") v := validator.NewSchemaValidator(log).GetJSONValidator() - h := handler.New(rw, annAPI, nil, aug, v, time.Second, log) + h := New(rw, annAPI, nil, aug, v, time.Second, log) r := mux.NewRouter() r.HandleFunc("/draft-annotations/content/{uuid}/annotations", h.ReadAnnotations).Methods(http.MethodGet) @@ -588,7 +586,7 @@ func TestUnHappyAugmenter(t *testing.T) { log := logger.NewUPPLogger("draft-annotations-api", "INFO") v := validator.NewSchemaValidator(log).GetJSONValidator() - h := handler.New(rw, annAPI, nil, aug, v, time.Second, log) + h := New(rw, annAPI, nil, aug, v, time.Second, log) r := mux.NewRouter() r.HandleFunc("/draft-annotations/content/{uuid}/annotations", h.ReadAnnotations).Methods(http.MethodGet) @@ -631,7 +629,7 @@ func TestFetchFromAnnotationsAPIIfNotFoundInRW(t *testing.T) { assert.Equal(t, annotationsAPIServerMock.URL+"/content/%v/annotations", annotationsAPI.Endpoint()) v := validator.NewSchemaValidator(log).GetJSONValidator() - h := handler.New(rw, annotationsAPI, nil, aug, v, time.Second, log) + h := New(rw, annotationsAPI, nil, aug, v, time.Second, log) r := mux.NewRouter() r.HandleFunc("/draft-annotations/content/{uuid}/annotations", h.ReadAnnotations).Methods(http.MethodGet) @@ -670,7 +668,7 @@ func TestFetchFromAnnotationsAPI404(t *testing.T) { log := logger.NewUPPLogger("draft-annotations-api", "INFO") v := validator.NewSchemaValidator(log).GetJSONValidator() annotationsAPI := annotations.NewUPPAnnotationsAPI(testClient, annotationsAPIServerMock.URL+"/content/%v/annotations", testBasicAuthUsername, testBasicAuthPassword, log) - h := handler.New(rw, annotationsAPI, nil, aug, v, time.Second, log) + h := New(rw, annotationsAPI, nil, aug, v, time.Second, log) r := mux.NewRouter() r.HandleFunc("/draft-annotations/content/{uuid}/annotations", h.ReadAnnotations).Methods(http.MethodGet) @@ -706,7 +704,7 @@ func TestFetchFromAnnotationsAPI404NoAnnoPostMapping(t *testing.T) { log := logger.NewUPPLogger("draft-annotations-api", "INFO") v := validator.NewSchemaValidator(log).GetJSONValidator() annotationsAPI := annotations.NewUPPAnnotationsAPI(testClient, annotationsAPIServerMock.URL+"/content/%v/annotations", testBasicAuthUsername, testBasicAuthPassword, log) - h := handler.New(rw, annotationsAPI, nil, aug, v, time.Second, log) + h := New(rw, annotationsAPI, nil, aug, v, time.Second, log) r := mux.NewRouter() r.HandleFunc("/draft-annotations/content/{uuid}/annotations", h.ReadAnnotations).Methods(http.MethodGet) @@ -741,7 +739,7 @@ func TestFetchFromAnnotationsAPI500(t *testing.T) { log := logger.NewUPPLogger("draft-annotations-api", "INFO") v := validator.NewSchemaValidator(log).GetJSONValidator() annotationsAPI := annotations.NewUPPAnnotationsAPI(testClient, annotationsAPIServerMock.URL+"/content/%v/annotations", testBasicAuthUsername, testBasicAuthPassword, log) - h := handler.New(rw, annotationsAPI, nil, aug, v, time.Second, log) + h := New(rw, annotationsAPI, nil, aug, v, time.Second, log) r := mux.NewRouter() r.HandleFunc("/draft-annotations/content/{uuid}/annotations", h.ReadAnnotations).Methods(http.MethodGet) @@ -774,7 +772,7 @@ func TestFetchFromAnnotationsAPIWithInvalidURL(t *testing.T) { log := logger.NewUPPLogger("draft-annotations-api", "INFO") v := validator.NewSchemaValidator(log).GetJSONValidator() annotationsAPI := annotations.NewUPPAnnotationsAPI(testClient, ":#", testBasicAuthUsername, testBasicAuthPassword, log) - h := handler.New(rw, annotationsAPI, nil, aug, v, time.Second, log) + h := New(rw, annotationsAPI, nil, aug, v, time.Second, log) r := mux.NewRouter() r.HandleFunc("/draft-annotations/content/{uuid}/annotations", h.ReadAnnotations).Methods(http.MethodGet) @@ -808,7 +806,7 @@ func TestFetchFromAnnotationsAPIWithConnectionError(t *testing.T) { log := logger.NewUPPLogger("draft-annotations-api", "INFO") v := validator.NewSchemaValidator(log).GetJSONValidator() annotationsAPI := annotations.NewUPPAnnotationsAPI(testClient, annotationsAPIServerMock.URL, testBasicAuthUsername, testBasicAuthPassword, log) - h := handler.New(rw, annotationsAPI, nil, aug, v, time.Second, log) + h := New(rw, annotationsAPI, nil, aug, v, time.Second, log) r := mux.NewRouter() r.HandleFunc("/draft-annotations/content/{uuid}/annotations", h.ReadAnnotations).Methods(http.MethodGet) @@ -1336,7 +1334,7 @@ func TestSaveAnnotations(t *testing.T) { log := logger.NewUPPLogger("draft-annotations-api", "INFO") v := validator.NewSchemaValidator(log).GetJSONValidator() - h := handler.New(rw, annotationsAPI, canonicalizer, aug, v, time.Second, log) + h := New(rw, annotationsAPI, canonicalizer, aug, v, time.Second, log) r := mux.NewRouter() r.HandleFunc("/draft-annotations/content/{uuid}/annotations", h.WriteAnnotations).Methods(http.MethodPut) @@ -1384,7 +1382,7 @@ func TestSaveAnnotationsInvalidContentUUID(t *testing.T) { log := logger.NewUPPLogger("draft-annotations-api", "INFO") v := validator.NewSchemaValidator(log).GetJSONValidator() - h := handler.New(rw, annotationsAPI, annotations.NewCanonicalizer(annotations.NewCanonicalAnnotationSorter), aug, v, time.Second, log) + h := New(rw, annotationsAPI, annotations.NewCanonicalizer(annotations.NewCanonicalAnnotationSorter), aug, v, time.Second, log) r := mux.NewRouter() r.HandleFunc("/draft-annotations/content/{uuid}/annotations", h.WriteAnnotations).Methods(http.MethodPut) @@ -1422,7 +1420,7 @@ func TestSaveAnnotationsInvalidAnnotationsBody(t *testing.T) { log := logger.NewUPPLogger("draft-annotations-api", "INFO") v := validator.NewSchemaValidator(log).GetJSONValidator() - h := handler.New(rw, annotationsAPI, annotations.NewCanonicalizer(annotations.NewCanonicalAnnotationSorter), aug, v, time.Second, log) + h := New(rw, annotationsAPI, annotations.NewCanonicalizer(annotations.NewCanonicalAnnotationSorter), aug, v, time.Second, log) r := mux.NewRouter() r.HandleFunc("/draft-annotations/content/{uuid}/annotations", h.WriteAnnotations).Methods(http.MethodPut) @@ -1469,7 +1467,7 @@ func TestSaveAnnotationsErrorFromRW(t *testing.T) { log := logger.NewUPPLogger("draft-annotations-api", "INFO") v := validator.NewSchemaValidator(log).GetJSONValidator() - h := handler.New(rw, annotationsAPI, canonicalizer, aug, v, time.Second, log) + h := New(rw, annotationsAPI, canonicalizer, aug, v, time.Second, log) r := mux.NewRouter() r.HandleFunc("/draft-annotations/content/{uuid}/annotations", h.WriteAnnotations).Methods(http.MethodPut) @@ -1514,7 +1512,7 @@ func TestAnnotationsReadTimeoutGenericRW(t *testing.T) { log := logger.NewUPPLogger("draft-annotations-api", "INFO") v := validator.NewSchemaValidator(log).GetJSONValidator() - h := handler.New(rw, annAPI, nil, aug, v, time.Second, log) + h := New(rw, annAPI, nil, aug, v, time.Second, log) r := mux.NewRouter() r.HandleFunc("/draft-annotations/content/{uuid}/annotations", h.ReadAnnotations).Methods(http.MethodGet) @@ -1547,7 +1545,7 @@ func TestAnnotationsReadTimeoutUPP(t *testing.T) { log := logger.NewUPPLogger("draft-annotations-api", "INFO") v := validator.NewSchemaValidator(log).GetJSONValidator() - h := handler.New(rw, annAPI, nil, aug, v, time.Second, log) + h := New(rw, annAPI, nil, aug, v, time.Second, log) r := mux.NewRouter() r.HandleFunc("/draft-annotations/content/{uuid}/annotations", h.ReadAnnotations).Methods(http.MethodGet) @@ -1611,7 +1609,7 @@ func TestAnnotationsWriteTimeout(t *testing.T) { log := logger.NewUPPLogger("draft-annotations-api", "INFO") v := validator.NewSchemaValidator(log).GetJSONValidator() - h := handler.New(rw, annotationsAPI, canonicalizer, aug, v, time.Second, log) + h := New(rw, annotationsAPI, canonicalizer, aug, v, time.Second, log) r := mux.NewRouter() r.HandleFunc("/draft-annotations/content/{uuid}/annotations", h.WriteAnnotations).Methods(http.MethodPut) @@ -1671,7 +1669,7 @@ func TestHappyDeleteAnnotations(t *testing.T) { log := logger.NewUPPLogger("draft-annotations-api", "INFO") v := validator.NewSchemaValidator(log).GetJSONValidator() - h := handler.New(rw, annAPI, canonicalizer, aug, v, time.Second, log) + h := New(rw, annAPI, canonicalizer, aug, v, time.Second, log) r := mux.NewRouter() r.HandleFunc("/draft-annotations/content/{uuid}/annotations/{cuuid}", h.DeleteAnnotation).Methods(http.MethodDelete) @@ -1706,7 +1704,7 @@ func TestUnHappyDeleteAnnotationsMissingContentUUID(t *testing.T) { log := logger.NewUPPLogger("draft-annotations-api", "INFO") v := validator.NewSchemaValidator(log).GetJSONValidator() - h := handler.New(rw, annAPI, nil, aug, v, time.Second, log) + h := New(rw, annAPI, nil, aug, v, time.Second, log) r := mux.NewRouter() r.HandleFunc("/draft-annotations/content/{uuid}/annotations/{cuuid}", h.DeleteAnnotation).Methods(http.MethodDelete) @@ -1734,7 +1732,7 @@ func TestUnHappyDeleteAnnotationsInvalidConceptUUID(t *testing.T) { log := logger.NewUPPLogger("draft-annotations-api", "INFO") v := validator.NewSchemaValidator(log).GetJSONValidator() - h := handler.New(rw, annAPI, nil, aug, v, time.Second, log) + h := New(rw, annAPI, nil, aug, v, time.Second, log) r := mux.NewRouter() r.HandleFunc("/draft-annotations/content/{uuid}/annotations/{cuuid}", h.DeleteAnnotation).Methods(http.MethodDelete) @@ -1764,7 +1762,7 @@ func TestUnHappyDeleteAnnotationsWhenRetrievingAnnotationsFails(t *testing.T) { log := logger.NewUPPLogger("draft-annotations-api", "INFO") v := validator.NewSchemaValidator(log).GetJSONValidator() - h := handler.New(rw, annAPI, nil, aug, v, time.Second, log) + h := New(rw, annAPI, nil, aug, v, time.Second, log) r := mux.NewRouter() r.HandleFunc("/draft-annotations/content/{uuid}/annotations/{cuuid}", h.DeleteAnnotation).Methods(http.MethodDelete) @@ -1798,7 +1796,7 @@ func TestUnHappyDeleteAnnotationsWhenNoAnnotationsFound(t *testing.T) { log := logger.NewUPPLogger("draft-annotations-api", "INFO") v := validator.NewSchemaValidator(log).GetJSONValidator() - h := handler.New(rw, annAPI, nil, aug, v, time.Second, log) + h := New(rw, annAPI, nil, aug, v, time.Second, log) r := mux.NewRouter() r.HandleFunc("/draft-annotations/content/:uuid/annotations/{cuuid}", h.DeleteAnnotation).Methods(http.MethodDelete) @@ -1838,7 +1836,7 @@ func TestUnHappyDeleteAnnotationsWhenWritingAnnotationsFails(t *testing.T) { log := logger.NewUPPLogger("draft-annotations-api", "INFO") v := validator.NewSchemaValidator(log).GetJSONValidator() - h := handler.New(rw, annAPI, canonicalizer, aug, v, time.Second, log) + h := New(rw, annAPI, canonicalizer, aug, v, time.Second, log) r := mux.NewRouter() r.HandleFunc("/draft-annotations/content/{uuid}/annotations/{cuuid}", h.DeleteAnnotation).Methods(http.MethodDelete) @@ -1880,7 +1878,7 @@ func TestHappyAddAnnotation(t *testing.T) { log := logger.NewUPPLogger("draft-annotations-api", "INFO") v := validator.NewSchemaValidator(log).GetJSONValidator() - h := handler.New(rw, annAPI, canonicalizer, aug, v, time.Second, log) + h := New(rw, annAPI, canonicalizer, aug, v, time.Second, log) r := mux.NewRouter() r.HandleFunc("/draft-annotations/content/{uuid}/annotations", h.AddAnnotation).Methods(http.MethodPost) @@ -1938,7 +1936,7 @@ func TestHappyAddExistingAnnotation(t *testing.T) { log := logger.NewUPPLogger("draft-annotations-api", "INFO") v := validator.NewSchemaValidator(log).GetJSONValidator() - h := handler.New(rw, annAPI, canonicalizer, aug, v, time.Second, log) + h := New(rw, annAPI, canonicalizer, aug, v, time.Second, log) r := mux.NewRouter() r.HandleFunc("/draft-annotations/content/{uuid}/annotations", h.AddAnnotation).Methods(http.MethodPost) @@ -1995,7 +1993,7 @@ func TestHappyAddAnnotationWithExistingConceptIdDifferentPredicate(t *testing.T) log := logger.NewUPPLogger("draft-annotations-api", "INFO") v := validator.NewSchemaValidator(log).GetJSONValidator() - h := handler.New(rw, annAPI, canonicalizer, aug, v, time.Second, log) + h := New(rw, annAPI, canonicalizer, aug, v, time.Second, log) r := mux.NewRouter() r.HandleFunc("/draft-annotations/content/{uuid}/annotations", h.AddAnnotation).Methods(http.MethodPost) @@ -2040,7 +2038,7 @@ func TestUnHappyAddAnnotationInvalidContentId(t *testing.T) { log := logger.NewUPPLogger("draft-annotations-api", "INFO") v := validator.NewSchemaValidator(log).GetJSONValidator() - h := handler.New(rw, annAPI, nil, aug, v, time.Second, log) + h := New(rw, annAPI, nil, aug, v, time.Second, log) r := mux.NewRouter() r.HandleFunc("/draft-annotations/content/{uuid}/annotations", h.AddAnnotation).Methods(http.MethodPost) @@ -2070,7 +2068,7 @@ func TestUnHappyAddAnnotationInvalidConceptIdPrefix(t *testing.T) { log := logger.NewUPPLogger("draft-annotations-api", "INFO") v := validator.NewSchemaValidator(log).GetJSONValidator() - h := handler.New(rw, annAPI, nil, aug, v, time.Second, log) + h := New(rw, annAPI, nil, aug, v, time.Second, log) r := mux.NewRouter() r.HandleFunc("/draft-annotations/content/{uuid}/annotations", h.AddAnnotation).Methods(http.MethodPost) @@ -2109,7 +2107,7 @@ func TestUnHappyAddAnnotationEmptyConceptId(t *testing.T) { log := logger.NewUPPLogger("draft-annotations-api", "INFO") v := validator.NewSchemaValidator(log).GetJSONValidator() - h := handler.New(rw, annAPI, nil, aug, v, time.Second, log) + h := New(rw, annAPI, nil, aug, v, time.Second, log) r := mux.NewRouter() r.HandleFunc("/draft-annotations/content/{uuid}/annotations", h.AddAnnotation).Methods(http.MethodPost) @@ -2147,7 +2145,7 @@ func TestUnHappyAddAnnotationInvalidConceptUuid(t *testing.T) { log := logger.NewUPPLogger("draft-annotations-api", "INFO") v := validator.NewSchemaValidator(log).GetJSONValidator() - h := handler.New(rw, annAPI, nil, aug, v, time.Second, log) + h := New(rw, annAPI, nil, aug, v, time.Second, log) r := mux.NewRouter() r.HandleFunc("/draft-annotations/content/{uuid}/annotations", h.AddAnnotation).Methods(http.MethodPost) @@ -2186,7 +2184,7 @@ func TestUnHappyAddAnnotationInvalidPredicate(t *testing.T) { log := logger.NewUPPLogger("draft-annotations-api", "INFO") v := validator.NewSchemaValidator(log).GetJSONValidator() - h := handler.New(rw, annAPI, nil, aug, v, time.Second, log) + h := New(rw, annAPI, nil, aug, v, time.Second, log) r := mux.NewRouter() r.HandleFunc("/draft-annotations/content/{uuid}/annotations", h.AddAnnotation).Methods(http.MethodPost) @@ -2235,7 +2233,7 @@ func TestUnhappyAddAnnotationWhenWritingAnnotationsFails(t *testing.T) { log := logger.NewUPPLogger("draft-annotations-api", "INFO") v := validator.NewSchemaValidator(log).GetJSONValidator() - h := handler.New(rw, annAPI, canonicalizer, aug, v, time.Second, log) + h := New(rw, annAPI, canonicalizer, aug, v, time.Second, log) r := mux.NewRouter() r.HandleFunc("/draft-annotations/content/{uuid}/annotations", h.AddAnnotation).Methods(http.MethodPost) @@ -2277,7 +2275,7 @@ func TestUnhappyAddAnnotationWhenGettingAnnotationsFails(t *testing.T) { log := logger.NewUPPLogger("draft-annotations-api", "INFO") v := validator.NewSchemaValidator(log).GetJSONValidator() - h := handler.New(rw, annAPI, annotations.NewCanonicalizer(annotations.NewCanonicalAnnotationSorter), aug, v, time.Second, log) + h := New(rw, annAPI, annotations.NewCanonicalizer(annotations.NewCanonicalAnnotationSorter), aug, v, time.Second, log) r := mux.NewRouter() r.HandleFunc("/draft-annotations/content/{uuid}/annotations", h.AddAnnotation).Methods(http.MethodPost) @@ -2321,7 +2319,7 @@ func TestUnhappyAddAnnotationWhenNoAnnotationsFound(t *testing.T) { log := logger.NewUPPLogger("draft-annotations-api", "INFO") v := validator.NewSchemaValidator(log).GetJSONValidator() - h := handler.New(rw, annAPI, annotations.NewCanonicalizer(annotations.NewCanonicalAnnotationSorter), aug, v, time.Second, log) + h := New(rw, annAPI, annotations.NewCanonicalizer(annotations.NewCanonicalAnnotationSorter), aug, v, time.Second, log) r := mux.NewRouter() r.HandleFunc("/draft-annotations/content/{uuid}/annotations", h.AddAnnotation).Methods(http.MethodPost) @@ -2374,7 +2372,7 @@ func TestHappyReplaceAnnotation(t *testing.T) { log := logger.NewUPPLogger("draft-annotations-api", "INFO") v := validator.NewSchemaValidator(log).GetJSONValidator() - h := handler.New(rw, annAPI, canonicalizer, aug, v, time.Second, log) + h := New(rw, annAPI, canonicalizer, aug, v, time.Second, log) r := mux.NewRouter() r.HandleFunc("/draft-annotations/content/{uuid}/annotations/{cuuid}", h.ReplaceAnnotation).Methods(http.MethodPatch) @@ -2472,7 +2470,7 @@ func TestHappyReplaceAnnotationWithPredicate(t *testing.T) { log := logger.NewUPPLogger("draft-annotations-api", "INFO") v := validator.NewSchemaValidator(log).GetJSONValidator() - h := handler.New(rw, annAPI, canonicalizer, aug, v, time.Second, log) + h := New(rw, annAPI, canonicalizer, aug, v, time.Second, log) r := mux.NewRouter() r.HandleFunc("/draft-annotations/content/{uuid}/annotations/{cuuid}", h.ReplaceAnnotation).Methods(http.MethodPatch) @@ -2526,7 +2524,7 @@ func TestHappyReplaceExistingAnnotation(t *testing.T) { log := logger.NewUPPLogger("draft-annotations-api", "INFO") v := validator.NewSchemaValidator(log).GetJSONValidator() - h := handler.New(rw, annAPI, canonicalizer, aug, v, time.Second, log) + h := New(rw, annAPI, canonicalizer, aug, v, time.Second, log) r := mux.NewRouter() r.HandleFunc("/draft-annotations/content/{uuid}/annotations/{cuuid}", h.ReplaceAnnotation).Methods(http.MethodPatch) @@ -2570,7 +2568,7 @@ func TestUnHappyReplaceAnnotationsInvalidContentUUID(t *testing.T) { log := logger.NewUPPLogger("draft-annotations-api", "INFO") v := validator.NewSchemaValidator(log).GetJSONValidator() - h := handler.New(rw, annAPI, nil, aug, v, time.Second, log) + h := New(rw, annAPI, nil, aug, v, time.Second, log) r := mux.NewRouter() r.HandleFunc("/draft-annotations/content/{uuid}/annotations/{cuuid}", h.ReplaceAnnotation).Methods(http.MethodPatch) @@ -2600,7 +2598,7 @@ func TestUnHappyReplaceAnnotationInvalidConceptIdInURI(t *testing.T) { log := logger.NewUPPLogger("draft-annotations-api", "INFO") v := validator.NewSchemaValidator(log).GetJSONValidator() - h := handler.New(rw, annAPI, nil, aug, v, time.Second, log) + h := New(rw, annAPI, nil, aug, v, time.Second, log) r := mux.NewRouter() r.HandleFunc("/draft-annotations/content/{uuid}/annotations/{cuuid}", h.ReplaceAnnotation).Methods(http.MethodPatch) @@ -2635,7 +2633,7 @@ func TestUnHappyReplaceAnnotationEmptyBody(t *testing.T) { log := logger.NewUPPLogger("draft-annotations-api", "INFO") v := validator.NewSchemaValidator(log).GetJSONValidator() - h := handler.New(rw, annAPI, nil, aug, v, time.Second, log) + h := New(rw, annAPI, nil, aug, v, time.Second, log) r := mux.NewRouter() r.HandleFunc("/draft-annotations/content/{uuid}/annotations/{cuuid}", h.ReplaceAnnotation).Methods(http.MethodPatch) @@ -2665,7 +2663,7 @@ func TestUnHappyReplaceAnnotationInvalidConceptIdInBody(t *testing.T) { log := logger.NewUPPLogger("draft-annotations-api", "INFO") v := validator.NewSchemaValidator(log).GetJSONValidator() - h := handler.New(rw, annAPI, nil, aug, v, time.Second, log) + h := New(rw, annAPI, nil, aug, v, time.Second, log) r := mux.NewRouter() r.HandleFunc("/draft-annotations/content/{uuid}/annotations/{cuuid}", h.ReplaceAnnotation).Methods(http.MethodPatch) @@ -2702,7 +2700,7 @@ func TestUnHappyReplaceAnnotationInvalidPredicate(t *testing.T) { log := logger.NewUPPLogger("draft-annotations-api", "INFO") v := validator.NewSchemaValidator(log).GetJSONValidator() - h := handler.New(rw, annAPI, nil, aug, v, time.Second, log) + h := New(rw, annAPI, nil, aug, v, time.Second, log) r := mux.NewRouter() r.HandleFunc("/draft-annotations/content/{uuid}/annotations/{cuuid}", h.ReplaceAnnotation).Methods(http.MethodPatch) @@ -2750,7 +2748,7 @@ func TestUnhappyReplaceAnnotationWhenWritingAnnotationsFails(t *testing.T) { log := logger.NewUPPLogger("draft-annotations-api", "INFO") v := validator.NewSchemaValidator(log).GetJSONValidator() - h := handler.New(rw, annAPI, canonicalizer, aug, v, time.Second, log) + h := New(rw, annAPI, canonicalizer, aug, v, time.Second, log) r := mux.NewRouter() r.HandleFunc("/draft-annotations/content/{uuid}/annotations/{cuuid}", h.ReplaceAnnotation).Methods(http.MethodPatch) @@ -2790,7 +2788,7 @@ func TestUnhappyReplaceAnnotationWhenGettingAnnotationsFails(t *testing.T) { log := logger.NewUPPLogger("draft-annotations-api", "INFO") v := validator.NewSchemaValidator(log).GetJSONValidator() - h := handler.New(rw, annAPI, annotations.NewCanonicalizer(annotations.NewCanonicalAnnotationSorter), aug, v, time.Second, log) + h := New(rw, annAPI, annotations.NewCanonicalizer(annotations.NewCanonicalAnnotationSorter), aug, v, time.Second, log) r := mux.NewRouter() r.HandleFunc("/draft-annotations/content/{uuid}/annotations/{cuuid}", h.ReplaceAnnotation).Methods(http.MethodPatch) @@ -2833,7 +2831,7 @@ func TestUnhappyReplaceAnnotationWhenNoAnnotationsFound(t *testing.T) { log := logger.NewUPPLogger("draft-annotations-api", "INFO") v := validator.NewSchemaValidator(log).GetJSONValidator() - h := handler.New(rw, annAPI, annotations.NewCanonicalizer(annotations.NewCanonicalAnnotationSorter), aug, v, time.Second, log) + h := New(rw, annAPI, annotations.NewCanonicalizer(annotations.NewCanonicalAnnotationSorter), aug, v, time.Second, log) r := mux.NewRouter() r.HandleFunc("/draft-annotations/content/{uuid}/annotations/{cuuid}", h.ReplaceAnnotation).Methods(http.MethodPatch) @@ -2862,6 +2860,48 @@ func TestUnhappyReplaceAnnotationWhenNoAnnotationsFound(t *testing.T) { assert.Equal(t, http.StatusNotFound, resp.StatusCode) } +func TestUnHappyDeleteAnnotationsWhenAuthorizationFails(t *testing.T) { + _ = os.Setenv("JSON_SCHEMAS_PATH", "../schemas") + _ = os.Setenv("JSON_SCHEMAS_API_CONFIG_PATH", "../config/schemas-api-config.json") + _ = os.Setenv("JSON_SCHEMA_NAME", "draft-annotations-pac-add.json;draft-annotations-pac-replace.json;draft-annotations-pac-write.json;draft-annotations-sv-add.json;draft-annotations-sv-replace.json;draft-annotations-sv-write.json") + rw := new(RWMock) + rw.On("Write", mock.Anything, "83a201c6-60cd-11e7-91a7-502f7ee26895", expectedCanonicalisedAnnotationsBodyWrite, "").Return(mock.Anything, errors.New("sorry something failed")) + annAPI := new(AnnotationsAPIMock) + annAPI.On("GetAllButV2", mock.Anything, "83a201c6-60cd-11e7-91a7-502f7ee26895"). + Return(expectedAnnotations["annotations"], nil) + canonicalizer := annotations.NewCanonicalizer(annotations.NewCanonicalAnnotationSorter) + + aug := &AugmenterMock{ + augment: func(_ context.Context, depletedAnnotations []interface{}) ([]interface{}, error) { + depletedAnnotations = canonicalizer.Canonicalize(depletedAnnotations) + assert.Equal(t, expectedCanonicalisedAnnotationsBody["annotations"], depletedAnnotations) + return expectedAnnotations["annotations"].([]interface{}), nil + }, + } + + log := logger.NewUPPLogger("draft-annotations-api", "INFO") + v := validator.NewSchemaValidator(log).GetJSONValidator() + h := New(rw, annAPI, canonicalizer, aug, v, time.Second, log) + r := mux.NewRouter() + r.HandleFunc("/draft-annotations/content/{uuid}/annotations/{cuuid}", h.DeleteAnnotation).Methods(http.MethodDelete) + + req := httptest.NewRequest( + http.MethodDelete, + "http://api.ft.com/draft-annotations/content/83a201c6-60cd-11e7-91a7-502f7ee26895/annotations/0a619d71-9af5-3755-90dd-f789b686c67a", + nil) + req.Header.Set(tidutils.TransactionIDHeader, testTID) + req.Header.Set(annotations.OriginSystemIDHeader, annotations.PACOriginSystemID) + req.Header.Set("X-Policy", "PBLC_WRITE_8e6c705e-1132-42a2-8db0-c295e29e8658") + req.Header.Set("Access-From", "API Gateway") + w := httptest.NewRecorder() + + r.ServeHTTP(w, req) + resp := w.Result() + defer resp.Body.Close() + + assert.Equal(t, http.StatusForbidden, resp.StatusCode) +} + func TestValidate(t *testing.T) { _ = os.Setenv("JSON_SCHEMAS_PATH", "../schemas") _ = os.Setenv("JSON_SCHEMAS_API_CONFIG_PATH", "../config/schemas-api-config.json") @@ -3008,7 +3048,7 @@ func TestValidate(t *testing.T) { log := logger.NewUPPLogger("draft-annotations-api", "INFO") v := validator.NewSchemaValidator(log).GetJSONValidator() - h := handler.New(rw, annAPI, annotations.NewCanonicalizer(annotations.NewCanonicalAnnotationSorter), aug, v, time.Second, log) + h := New(rw, annAPI, annotations.NewCanonicalizer(annotations.NewCanonicalAnnotationSorter), aug, v, time.Second, log) r := mux.NewRouter() r.HandleFunc("/draft-annotations/validate", h.Validate).Methods(http.MethodPost) @@ -3020,7 +3060,7 @@ func TestValidate(t *testing.T) { http.MethodPost, "/draft-annotations/validate", bytes.NewBuffer(b)) - req.Header.Set(handler.SchemaNameHeader, tt.header) + req.Header.Set(SchemaNameHeader, tt.header) w := httptest.NewRecorder() @@ -3121,6 +3161,76 @@ func TestGetSchemas(t *testing.T) { } } +func TestIsAuthorizedForDelete(t *testing.T) { + tests := []struct { + name string + requestHeaders map[string]string + scheduledForDelete interface{} + expectedResult bool + }{ + { + name: "authorized deletion", + requestHeaders: map[string]string{ + "Access-From": "test", + "X-Policy": "PBLC_WRITE_88fdde6c-2aa4-4f78-af02-9f680097cfd6", + }, + scheduledForDelete: map[string]interface{}{ + "publication": []interface{}{"88fdde6c-2aa4-4f78-af02-9f680097cfd6"}, + }, + expectedResult: true, + }, + { + name: "authorized deletion no returned publication", + requestHeaders: map[string]string{ + "Access-From": "test", + "X-Policy": "PBLC_WRITE_88fdde6c-2aa4-4f78-af02-9f680097cfd6", + }, + scheduledForDelete: map[string]interface{}{}, + expectedResult: true, + }, + { + name: "unauthorized deletion with read policy", + requestHeaders: map[string]string{ + "Access-From": "test", + "X-Policy": "PBLC_READ_88fdde6c-2aa4-4f78-af02-9f680097cfd6", + }, + scheduledForDelete: map[string]interface{}{}, + expectedResult: false, + }, + { + name: "authorized deletion no access header", + requestHeaders: map[string]string{}, + scheduledForDelete: map[string]interface{}{ + "publication": []interface{}{"88fdde6c-2aa4-4f78-af02-9f680097cfd6"}, + }, + expectedResult: true, + }, + { + name: "unauthorized deletion", + requestHeaders: map[string]string{ + "Access-From": "API Gateway", + "X-Policy": "PBLC_WRITE_11fdde6c-2aa4-4f78-af02-9f680097cfd6", + }, + scheduledForDelete: map[string]interface{}{ + "publication": []interface{}{"88fdde6c-2aa4-4f78-af02-9f680097cfd6"}, + }, + expectedResult: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + req, _ := http.NewRequest("GET", "/", nil) + for k, v := range tt.requestHeaders { + req.Header.Set(k, v) + } + + result := isAuthorizedForDelete(req, tt.scheduledForDelete) + assert.Equal(t, tt.expectedResult, result) + }) + } +} + type AugmenterMock struct { mock.Mock augment func(ctx context.Context, depletedAnnotations []interface{}) ([]interface{}, error) diff --git a/main.go b/main.go index 75d0963..748bd7c 100644 --- a/main.go +++ b/main.go @@ -132,7 +132,8 @@ func main() { healthService := health.NewHealthService(*appSystemCode, *appName, appDescription, rw, annotationsAPI, conceptRead) paths := map[string]string{ - policy.Key: policy.OpaPolicyPath, + policy.ReadKey: policy.OpaPolicyPath + policy.ReadKey, + policy.WriteKey: policy.OpaPolicyPath + policy.WriteKey, } opaClient := opa.NewOpenPolicyAgentClient(*OPAAddress, paths) @@ -150,26 +151,25 @@ func main() { func serveEndpoints(port string, apiYml string, handler *handler.Handler, healthService *health.HealthService, schemaHandler *schema.SchemasHandler, log *logger.UPPLogger, opaClient *opa.OpenPolicyAgentClient) { r := mux.NewRouter() - middlewareFunc := opa.CreateRequestMiddleware(opaClient, policy.Key, log, policy.Middleware) - responseMiddleware := opa.CreateResponseMiddleware(opaClient, policy.Key, log, policy.ResponseMiddleware) + writeMiddleware := opa.CreateRequestMiddleware(opaClient, policy.WriteKey, log, policy.Middleware) + respMiddleware := opa.CreateResponseMiddleware(opaClient, policy.ReadKey, log, policy.ResponseMiddleware) - authorizedRoutes := r.NewRoute().Subrouter() - authorizedGetRoute := r.NewRoute().Subrouter() + authorizedWriteRoutes := r.NewRoute().Subrouter() + authorizedReadRoutes := r.NewRoute().Subrouter() - authorizedRoutes.Use(middlewareFunc) - authorizedGetRoute.Use(responseMiddleware) + authorizedWriteRoutes.Use(writeMiddleware) + authorizedReadRoutes.Use(respMiddleware) - authorizedGetRoute.HandleFunc("/draft-annotations/content/{uuid}/annotations", handler.ReadAnnotations).Methods(http.MethodGet) + authorizedReadRoutes.HandleFunc("/draft-annotations/content/{uuid}/annotations", handler.ReadAnnotations).Methods(http.MethodGet) - authorizedRoutes.HandleFunc("/draft-annotations/content/{uuid}/annotations", handler.WriteAnnotations).Methods(http.MethodPut) - authorizedRoutes.HandleFunc("/draft-annotations/content/{uuid}/annotations", handler.AddAnnotation).Methods(http.MethodPost) - authorizedRoutes.HandleFunc("/draft-annotations/content/{uuid}/annotations/{cuuid}", handler.ReplaceAnnotation).Methods(http.MethodPatch) + authorizedWriteRoutes.HandleFunc("/draft-annotations/content/{uuid}/annotations", handler.WriteAnnotations).Methods(http.MethodPut) + authorizedWriteRoutes.HandleFunc("/draft-annotations/content/{uuid}/annotations", handler.AddAnnotation).Methods(http.MethodPost) + authorizedWriteRoutes.HandleFunc("/draft-annotations/content/{uuid}/annotations/{cuuid}", handler.ReplaceAnnotation).Methods(http.MethodPatch) + authorizedWriteRoutes.HandleFunc("/draft-annotations/content/{uuid}/annotations/{cuuid}", handler.DeleteAnnotation).Methods(http.MethodDelete) - authorizedRoutes.HandleFunc("/draft-annotations/validate", handler.Validate).Methods(http.MethodPost) - authorizedRoutes.HandleFunc("/draft-annotations/schemas", schemaHandler.ListSchemas).Methods(http.MethodGet) - authorizedRoutes.HandleFunc("/draft-annotations/schemas/{schemaName}", schemaHandler.GetSchema).Methods(http.MethodGet) - - r.HandleFunc("/draft-annotations/content/{uuid}/annotations/{cuuid}", handler.DeleteAnnotation).Methods(http.MethodDelete) + r.HandleFunc("/draft-annotations/validate", handler.Validate).Methods(http.MethodPost) + r.HandleFunc("/draft-annotations/schemas", schemaHandler.ListSchemas).Methods(http.MethodGet) + r.HandleFunc("/draft-annotations/schemas/{schemaName}", schemaHandler.GetSchema).Methods(http.MethodGet) if apiYml != "" { if endpoint, err := apiEndpoint.NewAPIEndpointForFile(apiYml); err == nil { diff --git a/policy/policy.go b/policy/policy.go index 8a3d23c..542b3e3 100644 --- a/policy/policy.go +++ b/policy/policy.go @@ -8,10 +8,10 @@ import ( ) const ( - Key = "publication_based_authorization" - OpaPolicyPath = "draft_annotations_api/publication_based_authorization" - Read = "READ" - Write = "WRITE" + OpaPolicyPath = "draft_annotations_api/" + ReadKey = "read" + WriteKey = "write" + WritePBLC = "PBLC_WRITE_" ) type Result struct {