From f4a72987cc35a6c1ac8cc0b15a100bf3af97414b Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Fri, 22 Apr 2022 12:06:51 +0100 Subject: [PATCH 01/17] we don't need global auth where we're going --- .gitignore | 1 + drafter/doc/drafter.yml | 1 - drafter/resources/drafter-base-config.edn | 8 +----- drafter/src/drafter/handler.clj | 3 -- drafter/test/drafter/handler_test.clj | 28 +------------------ .../resources/global-auth-test-system.edn | 1 - drafter/test/resources/web.edn | 3 -- package/manifest/shared.edn | 4 --- 8 files changed, 3 insertions(+), 46 deletions(-) delete mode 100644 drafter/test/resources/global-auth-test-system.edn diff --git a/.gitignore b/.gitignore index 948efa78f..aec10224c 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ stardog.log .envrc drafter/doc/graph_rewriting_fixup.html .omni_cache +.cpcache diff --git a/drafter/doc/drafter.yml b/drafter/doc/drafter.yml index e372e9260..6409bf9d1 100644 --- a/drafter/doc/drafter.yml +++ b/drafter/doc/drafter.yml @@ -103,7 +103,6 @@ info: | rank | role | Description | |------|-----------------|--------------------------------------------------------------------------------------| - | 0 | access | Can access the system at all (only comes in to play when `:drafter/global-auth?`) | | 1 | editor | Can access the admin panel and create and edit draftsets. | | 2 | publisher | Can do everything an editor can, but also publish to the live site. | | 3 | manager | Can do everything a publisher can, but also manage user accounts (not via this API) | diff --git a/drafter/resources/drafter-base-config.edn b/drafter/resources/drafter-base-config.edn index 59b23147d..3c03ee52b 100644 --- a/drafter/resources/drafter-base-config.edn +++ b/drafter/resources/drafter-base-config.edn @@ -182,10 +182,6 @@ [:get "/endpoints" #ig/ref :drafter.feature.endpoint.list/handler] ] } - - ;; Set to true to require all requests to be authorized - :drafter/global-auth? #boolean #or [#env DRAFTER_GLOBAL_AUTH false] - :drafter.swagger/swagger-routes {:auth-methods #ig/refset :drafter.auth/auth-method :global-auth? #ig/ref :drafter/global-auth?} @@ -196,9 +192,7 @@ :jobs-status-routes #ig/ref :drafter.routes/jobs-status :drafter/global-writes-lock #ig/ref :drafter/global-writes-lock :wrap-authenticate #ig/ref :drafter.middleware/wrap-authenticate - :global-auth? #ig/ref :drafter/global-auth? - :swagger-routes #ig/ref :drafter.swagger/swagger-routes - } + :swagger-routes #ig/ref :drafter.swagger/swagger-routes} ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Web Server diff --git a/drafter/src/drafter/handler.clj b/drafter/src/drafter/handler.clj index 09beb56ef..019cd0da0 100644 --- a/drafter/src/drafter/handler.clj +++ b/drafter/src/drafter/handler.clj @@ -40,7 +40,6 @@ jobs-status-routes :jobs-status-routes global-writes-lock :drafter/global-writes-lock wrap-authenticate :wrap-authenticate - global-auth? :global-auth? swagger-routes :swagger-routes}] (wrap-handler (app-handler ;; add your application routes here @@ -77,7 +76,5 @@ ;; :json :json-kw :yaml :yaml-kw :edn :yaml-in-html :formats [:json-kw :edn]))) -(defmethod ig/init-key :drafter/global-auth? [_ v] v) - (defmethod ig/init-key :drafter.handler/app [k opts] (build-handler opts)) diff --git a/drafter/test/drafter/handler_test.clj b/drafter/test/drafter/handler_test.clj index 3e5c738fc..4691124d5 100644 --- a/drafter/test/drafter/handler_test.clj +++ b/drafter/test/drafter/handler_test.clj @@ -7,7 +7,7 @@ [drafter.user-test :refer [test-norole test-access test-editor test-publisher]]) (:import java.util.UUID)) -(deftest global-auth-test +(deftest auth-test (let [get {:scheme :http :request-method :get} whitelisted (assoc get :uri "/swagger/swagger.json") get-public (assoc @@ -47,32 +47,6 @@ list-draftsets test-norole 403 ;; Forbidden, requires editor list-draftsets test-access 403 ;; Forbidden, requires editor list-draftsets test-editor 200 - list-draftsets test-publisher 200)) - (tc/with-system [{handler :drafter.handler/app} - "global-auth-test-system.edn"] - (are [req identity status] - (= status (:status (handler (if identity - (tc/with-identity identity req) - req)))) - whitelisted nil 200 - whitelisted test-norole 200 - whitelisted test-access 200 - whitelisted test-editor 200 - whitelisted test-publisher 200 - get-public nil 401 ;; Unauthorized, requires access - get-public test-norole 403 ;; Forbidden, requires access - get-public test-access 200 - get-public test-editor 200 - get-public test-publisher 200 - options-public nil 200 - options-public test-norole 200 - options-public test-access 200 - options-public test-editor 200 - options-public test-publisher 200 - list-draftsets nil 401 ;; Unauthorized, requires editor - list-draftsets test-norole 403 ;; Forbidden, requires editor - list-draftsets test-access 403 ;; Forbidden, requires editor - list-draftsets test-editor 200 list-draftsets test-publisher 200)))) ;; When muttnik is behind basic auth and drafter is running on the same host, diff --git a/drafter/test/resources/global-auth-test-system.edn b/drafter/test/resources/global-auth-test-system.edn deleted file mode 100644 index 88d4ee761..000000000 --- a/drafter/test/resources/global-auth-test-system.edn +++ /dev/null @@ -1 +0,0 @@ -#merge [#include "test-system.edn" {:drafter/global-auth? true}] diff --git a/drafter/test/resources/web.edn b/drafter/test/resources/web.edn index bff9c4607..1aa66935e 100644 --- a/drafter/test/resources/web.edn +++ b/drafter/test/resources/web.edn @@ -143,8 +143,6 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - :drafter/global-auth? false - :drafter.swagger/swagger-routes {:auth-methods #ig/refset :drafter.auth/auth-method :global-auth? #ig/ref :drafter/global-auth?} @@ -155,7 +153,6 @@ :jobs-status-routes #ig/ref :drafter.routes/jobs-status :drafter/global-writes-lock #ig/ref :drafter/global-writes-lock :wrap-authenticate #ig/ref :drafter.middleware/wrap-authenticate - :global-auth? #ig/ref :drafter/global-auth? :swagger-routes #ig/ref :drafter.swagger/swagger-routes} :drafter.server/http {:handler #ig/ref :drafter.handler/app diff --git a/package/manifest/shared.edn b/package/manifest/shared.edn index 24c653e9b..4c521dc6b 100644 --- a/package/manifest/shared.edn +++ b/package/manifest/shared.edn @@ -85,10 +85,6 @@ :env-var DRAFTER_LOGS_DIR :optional true} - :drafter/global-auth? {:doc "Set to true to enable global auth" - :env-var DRAFTER_GLOBAL_AUTH - :optional true} - :datadog/statsd-address {:doc "Address of the statsd service" :env-var DATADOG_STATSD_ADDRESS :default "localhost:8125" From acce7227337c3f38ec7622615f2954d36cc80d30 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Tue, 3 May 2022 12:04:56 +0100 Subject: [PATCH 02/17] check for permissions instead of roles on routes --- drafter/src/drafter/async/jobs.clj | 2 +- drafter/src/drafter/feature/draftset/changes.clj | 2 +- drafter/src/drafter/feature/draftset/claim.clj | 2 +- drafter/src/drafter/feature/draftset/create.clj | 2 +- drafter/src/drafter/feature/draftset/delete.clj | 2 +- drafter/src/drafter/feature/draftset/list.clj | 2 +- drafter/src/drafter/feature/draftset/options.clj | 2 +- drafter/src/drafter/feature/draftset/publish.clj | 2 +- drafter/src/drafter/feature/draftset/query.clj | 2 +- drafter/src/drafter/feature/draftset/set_metadata.clj | 2 +- drafter/src/drafter/feature/draftset/show.clj | 2 +- drafter/src/drafter/feature/draftset/submit.clj | 2 +- drafter/src/drafter/feature/draftset/update.clj | 2 +- drafter/src/drafter/feature/draftset_data/append.clj | 2 +- .../src/drafter/feature/draftset_data/append_by_graph.clj | 2 +- drafter/src/drafter/feature/draftset_data/delete.clj | 2 +- .../src/drafter/feature/draftset_data/delete_by_graph.clj | 2 +- drafter/src/drafter/feature/draftset_data/show.clj | 2 +- drafter/src/drafter/feature/middleware.clj | 4 ++-- drafter/src/drafter/feature/users/list.clj | 2 +- drafter/src/drafter/middleware.clj | 8 ++++---- drafter/src/drafter/user.clj | 5 +++++ 22 files changed, 30 insertions(+), 25 deletions(-) diff --git a/drafter/src/drafter/async/jobs.clj b/drafter/src/drafter/async/jobs.clj index 7b2c98e12..e57e052b0 100644 --- a/drafter/src/drafter/async/jobs.clj +++ b/drafter/src/drafter/async/jobs.clj @@ -76,7 +76,7 @@ (defmethod ig/init-key :drafter.routes/jobs-status [_ opts] (context "/v1/status" [] - (middleware/wrap-authorize (:wrap-authenticate opts) :editor + (middleware/wrap-authorize (:wrap-authenticate opts) :job:view (routes (GET "/jobs/:id" [id] (or (when-let [job (some-> id r/try-parse-uuid get-job)] diff --git a/drafter/src/drafter/feature/draftset/changes.clj b/drafter/src/drafter/feature/draftset/changes.clj index 5830f88ce..e3bd8d718 100644 --- a/drafter/src/drafter/feature/draftset/changes.clj +++ b/drafter/src/drafter/feature/draftset/changes.clj @@ -28,7 +28,7 @@ (defn delete-draftset-changes-handler [{:keys [wrap-as-draftset-owner] {:keys [backend] :as manager} :drafter/manager}] - (wrap-as-draftset-owner :editor + (wrap-as-draftset-owner :draft:edit (middleware/parse-graph-param-handler true (fn [{{:keys [draftset-id graph]} :params :as request}] diff --git a/drafter/src/drafter/feature/draftset/claim.clj b/drafter/src/drafter/feature/draftset/claim.clj index a7f3d87f5..eab7ef046 100644 --- a/drafter/src/drafter/feature/draftset/claim.clj +++ b/drafter/src/drafter/feature/draftset/claim.clj @@ -40,7 +40,7 @@ (let [inner-handler (partial handler* manager)] (->> inner-handler (feat-middleware/existing-draftset-handler backend) - (middleware/wrap-authorize wrap-authenticate :editor)))) + (middleware/wrap-authorize wrap-authenticate :draft:claim)))) (defmethod ig/pre-init-spec :drafter.feature.draftset.claim/handler [_] (s/keys :req [:drafter/manager])) diff --git a/drafter/src/drafter/feature/draftset/create.clj b/drafter/src/drafter/feature/draftset/create.clj index 3a499ca6a..836f06697 100644 --- a/drafter/src/drafter/feature/draftset/create.clj +++ b/drafter/src/drafter/feature/draftset/create.clj @@ -15,7 +15,7 @@ [{{:keys [backend global-writes-lock clock] :as manager} :drafter/manager wrap-authenticate :wrap-authenticate}] (let [version "/v1"] - (middleware/wrap-authorize wrap-authenticate :editor + (middleware/wrap-authorize wrap-authenticate :draft:create (fn [{{:keys [display-name description]} :params user :identity :as request}] (feat-common/run-sync {:backend backend :global-writes-lock global-writes-lock} diff --git a/drafter/src/drafter/feature/draftset/delete.clj b/drafter/src/drafter/feature/draftset/delete.clj index 6458a3e4d..d3bef461f 100644 --- a/drafter/src/drafter/feature/draftset/delete.clj +++ b/drafter/src/drafter/feature/draftset/delete.clj @@ -8,7 +8,7 @@ (defn handler [{wrap-as-draftset-owner :wrap-as-draftset-owner backend :drafter/backend}] - (wrap-as-draftset-owner :editor + (wrap-as-draftset-owner :draft:delete (fn [{:keys [params] :as request}] (log/info "drafter.feature.draftset.delete/handler " request) (writes/submit-async-job! diff --git a/drafter/src/drafter/feature/draftset/list.clj b/drafter/src/drafter/feature/draftset/list.clj index e4eef9f80..9b8feac97 100644 --- a/drafter/src/drafter/feature/draftset/list.clj +++ b/drafter/src/drafter/feature/draftset/list.clj @@ -75,7 +75,7 @@ (defn get-draftsets-handler ":get /draftsets" [{:keys [drafter/backend wrap-authenticate]}] - (middleware/wrap-authorize wrap-authenticate :editor + (middleware/wrap-authorize wrap-authenticate :draft:view (middleware/include-endpoints-param (parse-union-with-live-handler (fn [{user :identity {:keys [include union-with-live]} :params :as request}] diff --git a/drafter/src/drafter/feature/draftset/options.clj b/drafter/src/drafter/feature/draftset/options.clj index aab6342a3..4ccec31aa 100644 --- a/drafter/src/drafter/feature/draftset/options.clj +++ b/drafter/src/drafter/feature/draftset/options.clj @@ -8,7 +8,7 @@ (defn handler [{:keys [drafter/backend wrap-authenticate]}] - (middleware/wrap-authorize wrap-authenticate :editor + (middleware/wrap-authorize wrap-authenticate :draft:view (feat-middleware/existing-draftset-handler backend (fn [{{:keys [draftset-id]} :params user :identity}] diff --git a/drafter/src/drafter/feature/draftset/publish.clj b/drafter/src/drafter/feature/draftset/publish.clj index 62144f988..d1777ed11 100644 --- a/drafter/src/drafter/feature/draftset/publish.clj +++ b/drafter/src/drafter/feature/draftset/publish.clj @@ -9,7 +9,7 @@ (defn handler [{manager :drafter/manager :keys [wrap-as-draftset-owner]}] - (wrap-as-draftset-owner :publisher + (wrap-as-draftset-owner :draft:publish (fn [{params :params :as request}] (writes/submit-async-job! (dsjobs/publish-draftset-job manager diff --git a/drafter/src/drafter/feature/draftset/query.clj b/drafter/src/drafter/feature/draftset/query.clj index 79b6771bd..b1a283032 100644 --- a/drafter/src/drafter/feature/draftset/query.clj +++ b/drafter/src/drafter/feature/draftset/query.clj @@ -9,7 +9,7 @@ (defn handler [{backend :drafter/backend :keys [wrap-as-draftset-owner timeout-fn]}] - (wrap-as-draftset-owner :editor + (wrap-as-draftset-owner :draft:view (parse-union-with-live-handler (fn [{{:keys [draftset-id union-with-live]} :params :as request}] (let [executor (backend/endpoint-repo backend draftset-id {:union-with-live? union-with-live}) diff --git a/drafter/src/drafter/feature/draftset/set_metadata.clj b/drafter/src/drafter/feature/draftset/set_metadata.clj index 3bd265e24..ae5739aaa 100644 --- a/drafter/src/drafter/feature/draftset/set_metadata.clj +++ b/drafter/src/drafter/feature/draftset/set_metadata.clj @@ -7,7 +7,7 @@ (defn handler [{:keys [wrap-as-draftset-owner] {:keys [backend] :as manager} :drafter/manager}] - (wrap-as-draftset-owner :editor + (wrap-as-draftset-owner :draft:edit (fn [{{:keys [draftset-id] :as params} :params :as request}] (feat-common/run-sync manager diff --git a/drafter/src/drafter/feature/draftset/show.clj b/drafter/src/drafter/feature/draftset/show.clj index 1f5cf6ab9..cb2d45c67 100644 --- a/drafter/src/drafter/feature/draftset/show.clj +++ b/drafter/src/drafter/feature/draftset/show.clj @@ -23,7 +23,7 @@ (defn handler [{:keys [drafter/backend wrap-authenticate]}] - (middleware/wrap-authorize wrap-authenticate :editor + (middleware/wrap-authorize wrap-authenticate :draft:view (feat-middleware/existing-draftset-handler backend (parse-union-with-live-handler diff --git a/drafter/src/drafter/feature/draftset/submit.clj b/drafter/src/drafter/feature/draftset/submit.clj index 0d5bf0cf7..d04fd379a 100644 --- a/drafter/src/drafter/feature/draftset/submit.clj +++ b/drafter/src/drafter/feature/draftset/submit.clj @@ -33,7 +33,7 @@ (defn handler [{:keys [:drafter/manager :drafter.user/repo wrap-as-draftset-owner]}] - (wrap-as-draftset-owner :editor + (wrap-as-draftset-owner :draft:offer (fn [{{:keys [user role draftset-id]} :params owner :identity}] (cond (and (some? user) (some? role)) diff --git a/drafter/src/drafter/feature/draftset/update.clj b/drafter/src/drafter/feature/draftset/update.clj index 2f41d3218..debbf620a 100644 --- a/drafter/src/drafter/feature/draftset/update.clj +++ b/drafter/src/drafter/feature/draftset/update.clj @@ -492,7 +492,7 @@ (defn handler [{:keys [wrap-as-draftset-owner] :as opts}] - (wrap-as-draftset-owner :editor (fn [request] (handler* opts request)))) + (wrap-as-draftset-owner :draft:edit (fn [request] (handler* opts request)))) (def cors-allowed-headers #{"Accept" diff --git a/drafter/src/drafter/feature/draftset_data/append.clj b/drafter/src/drafter/feature/draftset_data/append.clj index 25d1e3e43..c5f6ebe70 100644 --- a/drafter/src/drafter/feature/draftset_data/append.clj +++ b/drafter/src/drafter/feature/draftset_data/append.clj @@ -119,7 +119,7 @@ "Ring handler to append data into a draftset." [{:keys [:drafter/manager ::time/clock wrap-as-draftset-owner]}] - (wrap-as-draftset-owner :editor + (wrap-as-draftset-owner :draft:edit (require-rdf-content-type (dset-middleware/parse-graph-for-triples (temp-file-body diff --git a/drafter/src/drafter/feature/draftset_data/append_by_graph.clj b/drafter/src/drafter/feature/draftset_data/append_by_graph.clj index 6ea8bad32..773ae9d5a 100644 --- a/drafter/src/drafter/feature/draftset_data/append_by_graph.clj +++ b/drafter/src/drafter/feature/draftset_data/append_by_graph.clj @@ -52,7 +52,7 @@ (middleware/parse-graph-param-handler true (required-live-graph-param-handler backend handler)))] - (wrap-as-draftset-owner :editor + (wrap-as-draftset-owner :draft:edit (required-live-graph-param (fn [{:keys [params] :as request}] (let [{:keys [draftset-id graph metadata]} params diff --git a/drafter/src/drafter/feature/draftset_data/delete.clj b/drafter/src/drafter/feature/draftset_data/delete.clj index f4c1254db..a936e7385 100644 --- a/drafter/src/drafter/feature/draftset_data/delete.clj +++ b/drafter/src/drafter/feature/draftset_data/delete.clj @@ -131,7 +131,7 @@ temp-file-body deset-middleware/parse-graph-for-triples require-rdf-content-type - (wrap-as-draftset-owner :editor))) + (wrap-as-draftset-owner :draft:edit))) (defmethod ig/pre-init-spec :drafter.feature.draftset-data.delete/delete-data-handler [_] (s/keys :req [:drafter/manager] diff --git a/drafter/src/drafter/feature/draftset_data/delete_by_graph.clj b/drafter/src/drafter/feature/draftset_data/delete_by_graph.clj index 2e1962208..43a848d6c 100644 --- a/drafter/src/drafter/feature/draftset_data/delete_by_graph.clj +++ b/drafter/src/drafter/feature/draftset_data/delete_by_graph.clj @@ -90,7 +90,7 @@ (defn remove-graph-from-draftset-handler "Remove a supplied graph from the draftset." [{:keys [wrap-as-draftset-owner] :as resources}] - (wrap-as-draftset-owner :editor + (wrap-as-draftset-owner :draft:edit (parse-query-param-flag-handler :silent (feat-middleware/parse-graph-param-handler true (request-handler resources))))) diff --git a/drafter/src/drafter/feature/draftset_data/show.clj b/drafter/src/drafter/feature/draftset_data/show.clj index c3a2b9039..240e305b2 100644 --- a/drafter/src/drafter/feature/draftset_data/show.clj +++ b/drafter/src/drafter/feature/draftset_data/show.clj @@ -11,7 +11,7 @@ [{wrap-as-draftset-owner :wrap-as-draftset-owner backend :drafter/backend draftset-query-timeout-fn :timeout-fn}] - (wrap-as-draftset-owner :editor + (wrap-as-draftset-owner :draft:view (parse-union-with-live-handler (fn [{{:keys [draftset-id graph union-with-live] :as params} :params :as request}] (let [executor (ep/build-draftset-endpoint backend draftset-id union-with-live) diff --git a/drafter/src/drafter/feature/middleware.clj b/drafter/src/drafter/feature/middleware.clj index 2880ade30..2387e6853 100644 --- a/drafter/src/drafter/feature/middleware.clj +++ b/drafter/src/drafter/feature/middleware.clj @@ -54,8 +54,8 @@ (defn wrap-as-draftset-owner [{:keys [:drafter/backend wrap-authenticate]}] - (fn [required-role handler] - (middleware/wrap-authorize wrap-authenticate required-role + (fn [permission handler] + (middleware/wrap-authorize wrap-authenticate permission (existing-draftset-handler backend (restrict-to-draftset-owner backend handler))))) diff --git a/drafter/src/drafter/feature/users/list.clj b/drafter/src/drafter/feature/users/list.clj index e3a96c2fa..0618f7b2d 100644 --- a/drafter/src/drafter/feature/users/list.clj +++ b/drafter/src/drafter/feature/users/list.clj @@ -9,7 +9,7 @@ "Ring handler that returns a list of user objects representing users within the system." [{user-repo ::user/repo wrap-authenticate :wrap-authenticate}] - (middleware/wrap-authorize wrap-authenticate :editor + (middleware/wrap-authorize wrap-authenticate :user:view (fn [r] (let [users (user/get-all-users user-repo) summaries (map user/get-summary users)] diff --git a/drafter/src/drafter/middleware.clj b/drafter/src/drafter/middleware.clj index 409317653..ff787c452 100644 --- a/drafter/src/drafter/middleware.clj +++ b/drafter/src/drafter/middleware.clj @@ -82,18 +82,18 @@ (wrapped request) (handler request))))) -(defn wrap-authorize [wrap-authenticate required-role handler] +(defn wrap-authorize [wrap-authenticate permission handler] (wrap-authenticate (fn [request] (if (whitelisted? request) (handler request) (let [user (:identity request)] - (if (user/has-role? (:identity request) required-role) + (if (user/has-permission? (:identity request) permission) (handler request) (response/forbidden-response (str "You require the " - (name required-role) - " role to perform this action")))))))) + (name permission) + " permission to perform this action")))))))) (defn require-params [required-keys inner-handler] (fn [{:keys [params] :as request}] diff --git a/drafter/src/drafter/user.clj b/drafter/src/drafter/user.clj index 9fe48effd..31176a9e7 100644 --- a/drafter/src/drafter/user.clj +++ b/drafter/src/drafter/user.clj @@ -119,6 +119,11 @@ (and (is-known-role? role) (<= (role->permission-level requested) (role->permission-level role)))) +(defn has-permission? + "Check if a user has a given permission." + [user permission] + (contains? (:permissions user) permission)) + (defn- user-token-invalid [token invalid-key info] (let [msg (str "User token invalid: " info " (" invalid-key " = '" (invalid-key token) "')")] (throw (ex-info msg {:token token})))) From fbb0f5cc29974b6ae2b60bc72e7c631d5f0c4997 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Wed, 4 May 2022 13:55:07 +0100 Subject: [PATCH 03/17] set permissions on identity --- drafter/src/drafter/auth/auth0.clj | 36 +++++------ drafter/src/drafter/swagger.clj | 60 +++++++++---------- drafter/src/drafter/user.clj | 31 +++++++--- drafter/src/drafter/user/spec.clj | 13 ++-- drafter/test/drafter/handler_test.clj | 24 +------- .../drafter/middleware/auth0_auth_test.clj | 5 +- drafter/test/drafter/test_common.clj | 14 +++-- drafter/test/drafter/user_test.clj | 31 +++++++--- 8 files changed, 113 insertions(+), 101 deletions(-) diff --git a/drafter/src/drafter/auth/auth0.clj b/drafter/src/drafter/auth/auth0.clj index a8df61aeb..4074eb7d6 100644 --- a/drafter/src/drafter/auth/auth0.clj +++ b/drafter/src/drafter/auth/auth0.clj @@ -12,16 +12,6 @@ (or (get payload (keyword "https://pmd/user/email")) (get payload :sub))) -(defn read-role - "Tries to convert an auth0 scope into a drafter role. Returns nil if the scope could not be - converted." - [s] - (let [[ns role-str] (some-> s (string/split #":"))] - (when (and (= ns "drafter")) - (let [role (keyword role-str)] - (when (user/is-known-role? role) - role))))) - (defn- role->scope "Converts a drafter role into the corresponding auth0 scope" [role] @@ -31,7 +21,6 @@ "Parses a bearer token from an incoming request if one exists." [auth0-client jwk request] (let [token-handler (-> identity - (auth0-middleware/wrap-normalize-roles {:role-reader read-role}) (auth0-middleware/wrap-bearer-token {:auth0 auth0-client :jwk jwk})) token-request (token-handler request)] ;; NOTE: :swirrl.auth0/authenticated key is only added if a token was found on the request @@ -39,19 +28,22 @@ (select-keys token-request [:swirrl.auth0/authenticated :swirrl.auth0/access-token])))) (defn authenticate-token - "Validates the token parsed on an incoming request by parse-request-token. Checks the incoming token - is valid and contains a username and role used to construct the drafter user." + "Validates the token parsed on an incoming request by parse-request-token. + Checks the incoming token is valid and constructs a drafter user." [{:keys [:swirrl.auth0/authenticated] :as state}] (case authenticated - ::jwt/token-verified (let [access-token (:swirrl.auth0/access-token state)] - (if-let [{:keys [roles]} access-token] - (let [email' (email access-token) - role (first roles)] - (if (and email' role) - (user/create-authenticated-user email' role) - (auth/authentication-failed (response/forbidden-response "Not authorized.")))) - (auth/authentication-failed))) - ::jwt/token-expired (auth/authentication-failed (response/unauthorized-response "Token expired.")) + ::jwt/token-verified + (let [access-token (:swirrl.auth0/access-token state)] + (if-let [email (email access-token)] + {:email email + :permissions (->> access-token :payload :permissions + (keep #(re-matches #"drafter:(.*)" %)) + (map (comp keyword second)) set)} + (auth/authentication-failed))) + + ::jwt/token-expired + (auth/authentication-failed (response/unauthorized-response "Token expired.")) + ::jwt/claim-invalid (auth/authentication-failed) ::jwt/token-invalid (auth/authentication-failed) (auth/authentication-failed))) diff --git a/drafter/src/drafter/swagger.clj b/drafter/src/drafter/swagger.clj index 48be4da0e..8072e3ae0 100644 --- a/drafter/src/drafter/swagger.clj +++ b/drafter/src/drafter/swagger.clj @@ -40,120 +40,120 @@ (recur resolved)))))) (defn get-api-route-specs [global-auth?] - (let [read-role (when global-auth? :access)] + (let [access-permission (when global-auth? :public:view)] [{:id 'get-endpoints :path "/endpoints" :method :get - :role read-role} + :permission access-permission} {:id 'get-public-endpoint :path "/endpoint/public" :method :get - :role read-role} + :permission access-permission} {:id 'create-draftset :path "/draftsets" :method :post - :role :editor} + :permission :draft:create} {:id 'get-draftsets :path "/draftsets" :method :get - :role :access} + :permission :draft:view} {:id 'get-draftset :path "/draftset/{id}" :method :get - :role :access} + :permission :draft:view} {:id 'put-draftset :path "/draftset/{id}" :method :put - :role :editor} + :permission :draft:edit} {:id 'delete-draftset :path "/draftset/{id}" :method :delete - :role :editor} + :permission :draft:delete} {:id 'put-draftset-graph :path "/draftset/{id}/graph" :method :put - :role :editor} + :permission :draft:edit} {:id 'delete-draftset-graph :path "/draftset/{id}/graph" :method :delete - :role :editor} + :permission :draft:edit} {:id 'delete-draftset-changes :path "/draftset/{id}/changes" :method :delete - :role :editor} + :permission :draft:edit} {:id 'put-draftset-data :path "/draftset/{id}/data" :method :put - :role :editor} + :permission :draft:edit} {:id 'delete-draftset-data :path "/draftset/{id}/data" :method :delete - :role :editor} + :permission :draft:edit} {:id 'get-draftset-data :path "/draftset/{id}/data" :method :get - :role :editor} + :permission :draft:view} {:id 'submit-draftset-to :path "/draftset/{id}/submit-to" :method :post - :role :editor} + :permission :draft:submit} {:id 'claim-draftset :path "/draftset/{id}/claim" :method :put - :role :editor} + :permission :draft:claim} {:id 'publish-draftset :path "/draftset/{id}/publish" :method :post - :role :publisher} + :permission :draft:publish} {:id 'get-query-draftset :path "/draftset/{id}/query" :method :get - :role :editor} + :permission :draft:view} {:id 'post-query-draftset :path "/draftset/{id}/query" :method :post - :role :editor} + :permission :draft:view} {:id 'post-update-draftset :path "/draftset/{id}/update" :method :post - :role :editor} + :permission :draft:edit} {:id 'get-query-live :path "/sparql/live" :method :get - :role read-role} + :permission access-permission} {:id 'post-query-live :path "/sparql/live" :method :post - :role read-role} + :permission access-permission} {:id 'get-users :path "/users" :method :get - :role :access} + :permission :user:view} {:id 'get-job :path "/status/jobs/{jobid}" :method :get - :role :editor} + :permission :job:view} {:id 'get-jobs :path "/status/jobs" :method :get - :role :editor} + :permission :job:view} {:id 'status-job-finished :path "/status/finished-jobs/{jobid}" :method :get - :role read-role} + :permission access-permission} {:id 'status-writes-locked :path "/status/writes-locked" :method :get - :role read-role}])) + :permission access-permission}])) (defn- route-spec-path "Returns the path of an operation within the swagger spec JSON" @@ -166,7 +166,7 @@ {swagger-key (auth/get-swagger-security-definition auth-method)}}] (letfn [(authenticated? [route-spec] - (some? (:role route-spec))) + (some? (:permission route-spec))) (add-route [spec route-spec] (if (authenticated? route-spec) (let [operation-requirements (auth/get-operation-swagger-security-requirement auth-method route-spec)] @@ -276,7 +276,7 @@ (defn swagger-json-handler "Returns a ring handler which serves the swagger JSON at the given path. auth-methods should be a collection of all the configured authentication methods in the system. These are required to configure the available securityDefinitions. - The global-auth? parameter indicates whether global authentication is enabled. This affects the roles required to + The global-auth? parameter indicates whether global authentication is enabled. This affects the permissions required to access certain API routes." [path auth-methods global-auth?] (let [swagger-json (load-spec-and-resolve-refs auth-methods global-auth?)] @@ -303,4 +303,4 @@ (swagger-ui-handler json-path auth-methods)))) (defmethod ig/init-key ::swagger-routes [_ {:keys [auth-methods global-auth?] :as opts}] - (swagger-routes auth-methods global-auth? opts)) \ No newline at end of file + (swagger-routes auth-methods global-auth? opts)) diff --git a/drafter/src/drafter/user.clj b/drafter/src/drafter/user.clj index 31176a9e7..bdb6dade4 100644 --- a/drafter/src/drafter/user.clj +++ b/drafter/src/drafter/user.clj @@ -12,7 +12,7 @@ (get-all-users [this] "Returns all users in this repository")) -(defrecord User [email role password-digest]) +(defrecord User [email role permissions password-digest]) (defmethod ig/init-key :drafter.user/repo [k opts] (throw (ex-info "Config error. Please use a concrete implementation of the user repo instead." {}))) @@ -76,12 +76,25 @@ valid (throw (IllegalArgumentException. (str "Not a valid email address: " email))))) +(defn role->permissions + "This function is only intended to be used for compatibility with mongo user + storage, or for convenience in tests." + [role] + (case role + :access #{} + :editor #{:draft:claim :draft:create :draft:delete :draft:edit :draft:offer + :draft:share :draft:view :job:view :user:view} + :publisher (conj (role->permissions :editor) :draft:publish) + :manager (recur :publisher) + :system (recur :manager))) + (defn create-user - "Creates a user with a username, role and password digest which can - be used to authenticate the user." + "Creates a user with a username, role and password digest which can be used + to authenticate the user. Grants the user permissions corresponding to the + given role." [email role password-digest] (let [email (get-valid-email email)] - (->User email role password-digest))) + (->User email role (role->permissions role) password-digest))) (defn create-authenticated-user "Create a user without any authentication information which is @@ -89,15 +102,15 @@ authenticated for a request, their authentication parameters should no longer be needed, so users are normalised into a model without these parameters." - [email role] + [email role permissions] (let [email (get-valid-email email)] - {:email email :role role})) + {:email email :role role :permissions permissions})) (defn authenticated! "Asserts that the given user has been authenticated and returns a representation of the user without authentication information." - [{:keys [email role] :as user}] - (create-authenticated-user email role)) + [{:keys [email role permissions] :as user}] + (create-authenticated-user email role permissions)) (defn try-authenticate "Tries to authenticate a user with the given candidate @@ -135,7 +148,7 @@ (if-let [email (util/validate-email-address (:email token))] (let [role (keyword (:role token))] (if (is-known-role? role) - (create-authenticated-user email role) + (create-authenticated-user email role (role->permissions role)) (user-token-invalid token :role "Unknown role"))) (user-token-invalid token :email "Invalid address"))) diff --git a/drafter/src/drafter/user/spec.clj b/drafter/src/drafter/user/spec.clj index b713c9cd3..43ccfca9e 100644 --- a/drafter/src/drafter/user/spec.clj +++ b/drafter/src/drafter/user/spec.clj @@ -9,6 +9,7 @@ (:import [drafter.user User])) (s/def ::user/role (s/with-gen user/is-known-role? (fn [] (gen/elements user/roles)))) +(s/def ::user/permissions (s/coll-of keyword? :kind set?)) (s/def ::user/email :drafter/EmailAddress) (s/def ::user/password-digest string?) (s/def ::user/username :drafter/EmailAddress) @@ -17,8 +18,10 @@ (s/def :token/role string?) (s/def ::user/DbUser #(instance? User %)) -(s/def ::user/User (s/keys :req-un [::user/role ::user/email])) -(s/def ::user/UserSummary (s/keys :req-un [::user/username ::user/role])) +(s/def ::user/User + (s/keys :req-un [::user/role ::user/email ::user/permissions])) +(s/def ::user/UserSummary + (s/keys :req-un [::user/username ::user/role ::user/permissions])) (s/def ::user/UserToken (s/keys :req-un [:token/email :token/role])) (s/def ::user/repo #(satisfies? user/UserRepository %)) @@ -36,11 +39,13 @@ :ret :drafter/URI) (s/fdef user/create-user - :args (s/cat :email string? :role ::user/role :password-digest ::user/password-digest) + :args (s/cat :email string? + :role ::user/role + :password-digest ::user/password-digest) :ret ::user/DbUser) (s/fdef user/create-authenticated-user - :args (s/cat :email string? :role ::user/role) + :args (s/cat :email string? :role ::user/role :permissions ::user/permissions) :ret ::user/User) (s/fdef user/authenticated! diff --git a/drafter/test/drafter/handler_test.clj b/drafter/test/drafter/handler_test.clj index 4691124d5..2793e0cb2 100644 --- a/drafter/test/drafter/handler_test.clj +++ b/drafter/test/drafter/handler_test.clj @@ -4,23 +4,17 @@ [drafter.feature.endpoint.public :as public] [drafter.routes.sparql-test :refer [live-query]] [drafter.test-common :as tc] - [drafter.user-test :refer [test-norole test-access test-editor test-publisher]]) + [drafter.user-test :refer [test-access test-editor test-publisher]]) (:import java.util.UUID)) (deftest auth-test (let [get {:scheme :http :request-method :get} - whitelisted (assoc get :uri "/swagger/swagger.json") get-public (assoc get :uri "/v1/sparql/live" :headers {"accept" "text/plain"} :query-string "query=select%20%2A%20where%20%7B%3Fs%20%3Fp%20%3Fo%7D") - options-public (assoc get-public - :request-method :options - :headers {"origin" "http://swirrl.com" - "access-control-request-method" "post" - "access-control-request-headers" "accept"}) list-draftsets (assoc get :uri "/v1/draftsets")] (tc/with-system [{handler :drafter.handler/app} "test-system.edn"] @@ -28,24 +22,12 @@ (= status (:status (handler (if identity (tc/with-identity identity req) req)))) - whitelisted nil 200 - whitelisted test-norole 200 - whitelisted test-access 200 - whitelisted test-editor 200 - whitelisted test-publisher 200 get-public nil 200 - get-public test-norole 200 get-public test-access 200 get-public test-editor 200 get-public test-publisher 200 - options-public nil 200 - options-public test-norole 200 - options-public test-access 200 - options-public test-editor 200 - options-public test-publisher 200 - list-draftsets nil 401 ;; Unauthorized, requires editor - list-draftsets test-norole 403 ;; Forbidden, requires editor - list-draftsets test-access 403 ;; Forbidden, requires editor + list-draftsets nil 401 ;; Unauthorized, requires :draft:view + list-draftsets test-access 403 ;; Forbidden, requires :draft:view list-draftsets test-editor 200 list-draftsets test-publisher 200)))) diff --git a/drafter/test/drafter/middleware/auth0_auth_test.clj b/drafter/test/drafter/middleware/auth0_auth_test.clj index 09c315d13..cf2793262 100644 --- a/drafter/test/drafter/middleware/auth0_auth_test.clj +++ b/drafter/test/drafter/middleware/auth0_auth_test.clj @@ -43,8 +43,9 @@ [:drafter.middleware/wrap-authenticate] [{:keys [:drafter.middleware/wrap-authenticate]} system] (let [username "test@example.com" - user {:email username :role :publisher} - token (tc/user-access-token username "drafter:publisher") + permissions #{:cat:pet :missiles:launch} + user {:email username :role :publisher :permissions permissions} + token (tc/user-access-token username "drafter:publisher" permissions) request (create-authorised-request token) handler (wrap-authenticate identity) {:keys [identity] :as response} (handler request)] diff --git a/drafter/test/drafter/test_common.clj b/drafter/test/drafter/test_common.clj index 446d72614..dd5cc4837 100644 --- a/drafter/test/drafter/test_common.clj +++ b/drafter/test/drafter/test_common.clj @@ -109,13 +109,16 @@ (def alg (Algorithm/RSA256 pubkey privkey)) -(defn token [iss aud sub role] +(defn token [iss aud sub role permissions] (-> (JWT/create) (.withIssuer (str iss \/)) (.withSubject sub) (.withAudience (into-array String [aud])) (.withExpiresAt (to-date (clj-time/plus (clj-time/now) (clj-time/minutes 10)))) (.withClaim "scope" role) + (.withArrayClaim "permissions" + (into-array String + (map #(str "drafter" %) permissions))) (.sign alg))) (defn mock-jwk [] @@ -127,22 +130,23 @@ (defmethod ig/init-key :drafter.auth.auth0/mock-jwk [_ _opts] (mock-jwk)) -(defn user-access-token [user-id scope] - (token (env :auth0-domain) (env :auth0-aud) user-id scope)) +(defn user-access-token [user-id scope permissions] + (token (env :auth0-domain) (env :auth0-aud) user-id scope permissions)) (defn set-auth-header [request access-token] (assoc-in request [:headers "Authorization"] (str "Bearer " access-token))) (defn with-identity "Sets the given test user as the user on a request" - [{:keys [email role] :as user} request] + [{:keys [email role permissions] :as user} request] ;; TODO: this is a bit gross but, we need to switch implementation of this ;; mocky thing based on the type of auth provider we're currently testing. (case *auth-env* :auth0 (-> request (assoc :identity user) - (set-auth-header (user-access-token email (str "drafter" role)))) + (set-auth-header + (user-access-token email (str "drafter" role) permissions))) (let [unencoded-auth (str (user/username user) ":" "password") encoded-auth (util/str->base64 unencoded-auth)] (-> request diff --git a/drafter/test/drafter/user_test.clj b/drafter/test/drafter/user_test.clj index afa624c65..76c8df373 100644 --- a/drafter/test/drafter/user_test.clj +++ b/drafter/test/drafter/user_test.clj @@ -9,7 +9,6 @@ (use-fixtures :each tc/with-spec-instrumentation) (def test-password "password") -(def test-norole (create-user "norole@swirrl.com" :norole (get-digest test-password))) (def test-access (create-user "access@swirrl.com" :access (get-digest test-password))) (def test-editor (create-user "editor@swirrl.com" :editor (get-digest test-password))) (def test-publisher (create-user "publisher@swirrl.com" :publisher (get-digest test-password))) @@ -58,16 +57,32 @@ (is (thrown? ExceptionInfo (validate-token! {:email "foo@bar.com" :role "invalid"})))) (testing "Valid token" - (is (= {:email "foo@bar.com" :role :editor} (validate-token! {:email "foo@bar.com" :role "editor"}))))) + (is (= {:email "foo@bar.com" + :role :editor + :permissions (role->permissions :editor)} + (validate-token! {:email "foo@bar.com" :role "editor"}))))) (deftest authenticated!-test (are [user expected] (= expected (authenticated! user)) - (create-user "test@example.com" :publisher "digest") (create-authenticated-user "test@example.com" :publisher) - (create-authenticated-user "test@example.com" :editor) (create-authenticated-user "test@example.com" :editor) - (-> - (create-authenticated-user "test@example.com" :editor) - (assoc :x "x") - (assoc :y "y")) (create-authenticated-user "test@example.com" :editor))) + (create-user "test@example.com" :publisher "digest") + (create-authenticated-user "test@example.com" + :publisher + (role->permissions :publisher)) + + (create-authenticated-user "test@example.com" + :editor + (role->permissions :editor)) + (create-authenticated-user "test@example.com" + :editor + (role->permissions :editor)) + + (assoc (create-authenticated-user "test@example.com" + :editor + (role->permissions :editor)) + :x "x" :y "y") + (create-authenticated-user "test@example.com" + :editor + (role->permissions :editor)))) (deftest is-owner?-test (are [user draftset expected] (= expected (is-owner? user draftset)) From b6397ada4c211055e293161ee92cf0a0f645bacc Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Wed, 4 May 2022 15:00:32 +0100 Subject: [PATCH 04/17] permissions in client tests --- drafter-client/deps.edn | 2 +- .../test/drafter_client/client_test.clj | 13 +++---- .../test/drafter_client/test_util/auth.clj | 21 ++++++----- .../test/drafter_client/test_util/jwt.clj | 37 ------------------- 4 files changed, 19 insertions(+), 54 deletions(-) delete mode 100644 drafter-client/test/drafter_client/test_util/jwt.clj diff --git a/drafter-client/deps.edn b/drafter-client/deps.edn index 21fd11960..d3e40fdc8 100644 --- a/drafter-client/deps.edn +++ b/drafter-client/deps.edn @@ -37,7 +37,7 @@ }} - :test {:extra-paths ["test" "test/resources"] + :test {:extra-paths ["test" "test/resources" "../drafter/test"] :extra-deps {drafter/drafter {:local/root "../drafter"} org.clojure/test.check {:mvn/version "1.1.1"} lambdaisland/kaocha {:mvn/version "1.60.972"} diff --git a/drafter-client/test/drafter_client/client_test.clj b/drafter-client/test/drafter_client/client_test.clj index 027e8b6b0..3bac336ac 100644 --- a/drafter-client/test/drafter_client/client_test.clj +++ b/drafter-client/test/drafter_client/client_test.clj @@ -9,15 +9,14 @@ [drafter-client.client.endpoint :as endpoint] [drafter-client.test-helpers :as h] [drafter-client.test-util.auth :as auth-util] - [drafter-client.test-util.jwt :as jwt] [drafter.main :as drafter] + [drafter.test-common :refer [mock-jwk]] [drafter.util :as util] [environ.core :refer [env]] [grafter-2.rdf.protocols :as pr] [grafter-2.rdf4j.io :as rio] [grafter-2.rdf4j.repository :as gr-repo] - [integrant.core :as ig] - [grafter-2.rdf4j.io :as gio]) + [integrant.core :as ig]) (:import clojure.lang.ExceptionInfo java.net.URI [java.util UUID] @@ -32,11 +31,11 @@ ;; Override the :drafter.auth.auth0/jwk init-key otherwise it'll be trying to ;; contact auth0 (defmethod ig/init-key :drafter.auth.auth0/jwk [_ {:keys [endpoint] :as opts}] - (jwt/mock-jwk)) + (mock-jwk)) ;; But this is the one that everything should use anyway (defmethod ig/init-key :drafter.auth.auth0/mock-jwk [_ {:keys [endpoint] :as opts}] - (jwt/mock-jwk)) + (mock-jwk)) (defn start-auth0-drafter-server [] (drafter/-main (h/res-file "auth0-test-config.edn") @@ -385,12 +384,12 @@ draftset (sut/new-draftset client token name description) _ (sut/add-data-sync client token draftset f {:gzip gzip?}) quads* (h/get-user-quads client token draftset) - expected-quads (set (gio/statements f))] + expected-quads (set (rio/statements f))] (t/is (= expected-quads (set quads*))))))) (t/testing "Add quads from a gzipped file" (let [source (io/file "test/resources/test_data.trig") - expected-quads (set (gio/statements source))] + expected-quads (set (rio/statements source))] (t/testing "with format and gzip extension" (let [f (File/createTempFile "drafter-client" ".trig.gz")] (try diff --git a/drafter-client/test/drafter_client/test_util/auth.clj b/drafter-client/test/drafter_client/test_util/auth.clj index 7629e8bd3..d8b526222 100644 --- a/drafter-client/test/drafter_client/test_util/auth.clj +++ b/drafter-client/test/drafter_client/test_util/auth.clj @@ -1,19 +1,22 @@ (ns drafter-client.test-util.auth - (:require [drafter-client.test-util.jwt :as jwt] + (:require [drafter.test-common :refer [token]] + [drafter.user :refer [role->permissions]] [environ.core :refer [env]])) (def system-user {:email "system@swirrl.com" :role "system"}) (defn system-token [] - (jwt/token (env :auth0-domain) - (env :auth0-aud) - "system@swirrl.com" - "drafter:system")) + (token (env :auth0-domain) + (env :auth0-aud) + "system@swirrl.com" + "drafter:system" + (role->permissions :system))) (def test-publisher {:email "publisher@swirrl.com" :role "publisher"}) (defn publisher-token [] - (jwt/token (env :auth0-domain) - (env :auth0-aud) - "publisher@swirrl.com" - "drafter:publisher")) + (token (env :auth0-domain) + (env :auth0-aud) + "publisher@swirrl.com" + "drafter:publisher" + (role->permissions :publisher))) diff --git a/drafter-client/test/drafter_client/test_util/jwt.clj b/drafter-client/test/drafter_client/test_util/jwt.clj deleted file mode 100644 index 42a0ee493..000000000 --- a/drafter-client/test/drafter_client/test_util/jwt.clj +++ /dev/null @@ -1,37 +0,0 @@ -(ns drafter-client.test-util.jwt - (:require [cheshire.core :as json] - [clj-time.coerce :refer [to-date]] - [clj-time.core :as time] - [integrant.core :as ig]) - (:import com.auth0.jwt.algorithms.Algorithm - [com.auth0.jwt.exceptions InvalidClaimException - JWTVerificationException TokenExpiredException] - [com.auth0.jwk Jwk JwkProvider] - com.auth0.jwt.JWT - java.security.KeyPairGenerator - java.util.Base64)) - -(defonce keypair - (-> (KeyPairGenerator/getInstance "RSA") - (doto (.initialize 4096)) - (.genKeyPair))) - -(def pubkey (.getPublic keypair)) -(def privkey (.getPrivate keypair)) - -(def alg (Algorithm/RSA256 pubkey privkey)) - -(defn token [iss aud sub role] - (-> (JWT/create) - (.withIssuer (str iss \/)) - (.withSubject sub) - (.withAudience (into-array String [aud])) - (.withExpiresAt (to-date (time/plus (time/now) (time/minutes 30)))) - (.withClaim "scope" role) - (.sign alg))) - -(defn mock-jwk [] - (reify JwkProvider - (get [_ _] - (proxy [Jwk] ["" "" "RSA" "" '() "" '() "" {}] - (getPublicKey [] (.getPublic keypair)))))) From 67a68e59e6a9d9069941b1135c804a881c82f127 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Wed, 11 May 2022 14:31:12 +0100 Subject: [PATCH 05/17] remove reference to roles everywhere internally, in particular submit and claim drafts with "claim permission" rather than "claim role" --- .../env/dev/resources/auth0-test-config.edn | 3 +- .../resources/drafter-mock-middleware.edn | 1 - drafter-client/src/drafter_client/client.clj | 15 ++- .../test/drafter_client/client_test.clj | 2 +- drafter/doc/drafter.yml | 88 ++++++--------- .../env/dev/resources/drafter-dev-auth0.edn | 3 +- .../env/dev/resources/drafter-dev-config.edn | 3 +- drafter/src/drafter/auth/auth0.clj | 4 +- .../drafter/backend/draftset/operations.clj | 101 ++++++------------ drafter/src/drafter/draftset.clj | 14 +-- drafter/src/drafter/draftset/spec.clj | 8 +- .../src/drafter/feature/draftset/claim.clj | 24 ++--- drafter/src/drafter/feature/draftset/list.clj | 30 +++--- .../src/drafter/feature/draftset/submit.clj | 38 +++---- drafter/src/drafter/rdf/drafter_ontology.clj | 2 +- drafter/src/drafter/user.clj | 86 +++++++-------- drafter/src/drafter/user/mongo.clj | 8 +- drafter/src/drafter/user/spec.clj | 18 +--- .../backend/draftset/operations_test.clj | 78 +++++++++----- .../drafter/feature/draftset/claim_test.clj | 32 +++--- .../drafter/feature/draftset/options_test.clj | 2 +- .../drafter/feature/draftset/show_test.clj | 12 +-- .../drafter/feature/draftset/submit_test.clj | 31 +++--- .../drafter/feature/draftset/test_helper.clj | 11 +- drafter/test/drafter/model.clj | 36 ++++--- .../drafter/user/auth0_repository_test.clj | 2 +- drafter/test/drafter/user/mongo_test.clj | 15 +-- drafter/test/drafter/user_test.clj | 84 ++++++++------- .../claimable-draftset-changes-2.trig | 4 +- .../draftset/claimable-draftset-changes.trig | 4 +- .../list_test-1-draftset-with-submission.trig | 2 +- .../drafter/feature/draftset/list_test-2.trig | 4 +- .../draftset/list_test-unclaimable.trig | 4 +- .../draftset/list_test-union-with-live.trig | 2 +- .../endpoint/list_test-with-login.trig | 4 +- drafter/test/resources/web.edn | 7 +- 36 files changed, 376 insertions(+), 406 deletions(-) diff --git a/drafter-client/env/dev/resources/auth0-test-config.edn b/drafter-client/env/dev/resources/auth0-test-config.edn index 98d485ccf..f4c3f8385 100644 --- a/drafter-client/env/dev/resources/auth0-test-config.edn +++ b/drafter-client/env/dev/resources/auth0-test-config.edn @@ -22,5 +22,4 @@ ;; auth0 authentication method :drafter.auth.auth0/auth0-auth-method {:auth0-client #ig/ref :swirrl.auth0/client - :jwk #ig/ref :drafter.auth.auth0/mock-jwk} - } + :jwk #ig/ref :drafter.auth.auth0/mock-jwk}} diff --git a/drafter-client/resources/drafter-mock-middleware.edn b/drafter-client/resources/drafter-mock-middleware.edn index fe2fd253c..63ba67407 100644 --- a/drafter-client/resources/drafter-mock-middleware.edn +++ b/drafter-client/resources/drafter-mock-middleware.edn @@ -16,7 +16,6 @@ :drafter.middleware/wrap-authenticate {:middleware [#ig/ref :swirrl.auth0.middleware/bearer-token - #ig/ref :swirrl.auth0.middleware/normalize-roles #ig/ref :drafter.middleware.auth0-auth/identify #ig/ref :drafter.middleware.auth0-auth/token-authentication]} diff --git a/drafter-client/src/drafter_client/client.clj b/drafter-client/src/drafter_client/client.clj index a6b4313ae..291f15031 100644 --- a/drafter-client/src/drafter_client/client.clj +++ b/drafter-client/src/drafter_client/client.clj @@ -1,5 +1,5 @@ (ns drafter-client.client - (:refer-clojure :exclude [name type get]) + (:refer-clojure :exclude [get]) (:require [cheshire.core :as json] [clj-time.format :refer [formatters parse]] [clojure.spec.alpha :as s] @@ -18,8 +18,6 @@ [martian.core :as martian]) (:import clojure.lang.ExceptionInfo)) -(alias 'c 'clojure.core) - (def live draftset/live) (defn exception? [v] @@ -75,8 +73,9 @@ same as for draftsets." [client access-token & [include]] (let [get-endpoints (partial i/request client i/get-endpoints access-token) - include (if (keyword? include) (c/name include) include) - endpoints (if include (get-endpoints :include include) (get-endpoints))] + endpoints (if include + (get-endpoints :include (name include)) + (get-endpoints))] (map endpoint/from-json endpoints))) (defn get-public-endpoint @@ -147,9 +146,9 @@ (defn submit-to-user [client access-token id user] (i/request client i/submit-draftset-to access-token id :user user)) -(defn submit-to-role [client access-token id role] - (let [role (if (keyword? role) (c/name role) role)] - (i/request client i/submit-draftset-to access-token id :role role))) +(defn submit-to-permission [client access-token id permission] + (i/request client i/submit-draftset-to access-token id + :permission (name permission))) (defn claim [client access-token id] (i/request client i/claim-draftset access-token id)) diff --git a/drafter-client/test/drafter_client/client_test.clj b/drafter-client/test/drafter_client/client_test.clj index 3bac336ac..7cfc400fd 100644 --- a/drafter-client/test/drafter_client/client_test.clj +++ b/drafter-client/test/drafter_client/client_test.clj @@ -220,7 +220,7 @@ token (auth-util/publisher-token) ds-1 (sut/new-draftset client token "first" "description") ds-2 (sut/new-draftset client token "second" "description")] - (sut/submit-to-role client token (draftset/id ds-2) :publisher) + (sut/submit-to-permission client token (draftset/id ds-2) :draft:claim) (t/testing "default" (let [draftsets (sut/draftsets client token)] (t/is (= #{(draftset/id ds-1) (draftset/id ds-2)} diff --git a/drafter/doc/drafter.yml b/drafter/doc/drafter.yml index 6409bf9d1..3ad3002df 100644 --- a/drafter/doc/drafter.yml +++ b/drafter/doc/drafter.yml @@ -50,15 +50,14 @@ info: - `/data` which can be used to `POST` (append), `DELETE` or `GET` quads from the draftset. - - `/submit-to` to relinquish ownership of the drafset and either - assign ownership to another user, or make it available to - users in a given role. The user which takes ownership of the - draftset may depending on their role then choose to make - further ammendments, `/publish` or submit the draftset to a - new owner. + - `/submit-to` to relinquish ownership of the drafset and either assign + ownership to another user, or make it available to users with a given + permission. The user which takes ownership of the draftset may + depending on their permissions then choose to make further ammendments, + `/publish` or submit the draftset to a new owner. - - `/publish` which can be used by clients with the `publisher` - role to publish a reviewed draftset to the live site. + - `/publish` which can be used by clients with the `draft:publish` + permission to publish a reviewed draftset to the live site. - `/claim` which a user must call on Draftset's submitted to them before they can perform any actions upon them. Claiming @@ -97,27 +96,24 @@ info: ## Roles - Users in Drafter and PMD are assigned to a role which authorises - them to perform various actions associated with the role and all - of the roles ranked beneath it. The roles are currently: + Users in Drafter and PMD are assigned roles, which in turn grant sets of + permissions. A user with multiple roles is granted the union of the + permissions associated with each role. - | rank | role | Description | - |------|-----------------|--------------------------------------------------------------------------------------| - | 1 | editor | Can access the admin panel and create and edit draftsets. | - | 2 | publisher | Can do everything an editor can, but also publish to the live site. | - | 3 | manager | Can do everything a publisher can, but also manage user accounts (not via this API) | + ## Permissions + Currently available permissions are: - Roles are also what users use to exchange Draftsets. Users submit - a Draftset to a role, which puts it in that roles pool of - claimable Draftsets. Draftsets are then only claimable out of the - role's pool by users with a role of an equal or higher rank. In - addition to this the user who submitted the draftset to the role - can also withdraw it from submission by claiming it back - - regarldess of their role's rank. - - Draftsets *must* be claimed before they can be reviewed, published - or edited. + - draft:claim + - draft:create + - draft:delete + - draft:edit + - draft:publish + - draft:share + - draft:submit + - draft:view + - job:view + - user:view ## Authentication & Security @@ -492,17 +488,14 @@ paths: /draftset/{id}/submit-to: post: operationId: submit-draftset-to - summary: Submit a Draftset to a user or role + summary: Submit a Draftset to a user or permission holder description: | - Submits this draftset for review and potential publication. + Submits this draftset to be claimed by another user. Draftsets are submitted directly to a user, or into a pool for - users of a given role. - - Users with a role greater than or equal to the role the - draftset was submitted to can then lay claim to it. + users with a given permission. parameters: - $ref: '#/parameters/id' - - $ref: '#/parameters/role' + - $ref: '#/parameters/permission' - $ref: '#/parameters/submit-user' # - $ref: '#/parameters/message' # - $ref: '#/parameters/note' @@ -524,11 +517,6 @@ paths: performing this operation. This is necessary to prevent other's from making changes to the data contained within the Draftset. - - Each role in the system has a pool of 0 or more claimable - draftsets associated with it. Claimable draftsets are - draftsets in a pool where the rank of the pools role is less - than or equal to the user's role's rank. parameters: - $ref: '#/parameters/id' #- $ref: '#/parameters/messagenonote' @@ -856,16 +844,12 @@ parameters: in: query required: false type: string - role: - name: role - description: The role to submit the draftset to + permission: + name: permission + description: A permission in: query required: false type: string - enum: - - editor - - publisher - - manager submit-user: name: user description: The username of the user to submit the draftset to. @@ -1095,17 +1079,13 @@ definitions: User: type: object - required: [username, role] + required: [username] properties: username: type: string description: Username of the user - role: - type: string - description: role of the user example: username: user@example.com - role: publisher Endpoint: type: object @@ -1159,13 +1139,9 @@ definitions: submitted-by: type: string description: The owner who submitted this Draftset for review - claim-role: + claim-permission: type: string - enum: - - editor - - publisher - - manager - description: The required role for users who can claim this Draftset + description: Only users with this permission can claim this Draftset claim-user: type: string description: The user who can claim this Draftset diff --git a/drafter/env/dev/resources/drafter-dev-auth0.edn b/drafter/env/dev/resources/drafter-dev-auth0.edn index 89f4b1c33..dc1c64e3f 100644 --- a/drafter/env/dev/resources/drafter-dev-auth0.edn +++ b/drafter/env/dev/resources/drafter-dev-auth0.edn @@ -17,5 +17,4 @@ ;; auth methods ;; auth0 :drafter.auth.auth0/auth0-auth-method {:auth0-client #ig/ref :swirrl.auth0/client - :jwk #ig/ref :swirrl.auth0/jwk} - } + :jwk #ig/ref :swirrl.auth0/jwk}} diff --git a/drafter/env/dev/resources/drafter-dev-config.edn b/drafter/env/dev/resources/drafter-dev-config.edn index e78b2d1db..22c4a6802 100644 --- a/drafter/env/dev/resources/drafter-dev-config.edn +++ b/drafter/env/dev/resources/drafter-dev-config.edn @@ -15,5 +15,4 @@ ;; auth method ;; JWT signed by mock JWK :drafter.auth.mock-auth0/mock-auth0-auth-method {:auth0-client #ig/ref :swirrl.auth0/client - :jwk #ig/ref :drafter.auth.auth0/mock-jwk} - } + :jwk #ig/ref :drafter.auth.auth0/mock-jwk}} diff --git a/drafter/src/drafter/auth/auth0.clj b/drafter/src/drafter/auth/auth0.clj index 4074eb7d6..ba2b02dc0 100644 --- a/drafter/src/drafter/auth/auth0.clj +++ b/drafter/src/drafter/auth/auth0.clj @@ -52,7 +52,7 @@ "Returns an implementation of the AuthenticationMethod protocol which uses auth0. Tokens should be specified on incoming requests within an 'Authorization: Bearer ' header. The validity of the token is checked with the given jwk parameter. The decoded token should contain the user's - email and at least one drafter role or it will be rejected." + email or it will be rejected." [auth0-client jwk] (reify auth/AuthenticationMethod (parse-request [_this request] @@ -71,7 +71,7 @@ :flow "application" :description "OAuth authentication via Auth0" :tokenUrl (str (:endpoint auth0-client) "/oauth/token") - :scopes (into {} (map (fn [role] [(role->scope role) (user/get-role-summary role)]) user/roles))}) + :scopes (into {} (map (fn [permission] [(str "drafter:" permission) (user/get-role-summary role)]) user/roles))}) (get-operation-swagger-security-requirement [_this {:keys [role] :as operation}] (let [satisfying-roles (user/roles-including role)] diff --git a/drafter/src/drafter/backend/draftset/operations.clj b/drafter/src/drafter/backend/draftset/operations.clj index 77eaba3c0..b5910a3e4 100644 --- a/drafter/src/drafter/backend/draftset/operations.clj +++ b/drafter/src/drafter/backend/draftset/operations.clj @@ -85,10 +85,6 @@ (let [delete-query (delete-draftset-statements-query draftset-ref)] (sparql/update! db delete-query))) -(defn- role-scores-values-clause [scored-roles] - (let [score-pairs (map (fn [[r v]] (format "(\"%s\" %d)" (name r) v)) scored-roles)] - (clojure.string/join " " score-pairs))) - (defn- graph-mapping-draft-graphs [graph-mapping] (vals graph-mapping)) @@ -171,7 +167,7 @@ "}" "OPTIONAL {" " ?ds <" drafter:hasSubmission "> ?submission ." - " ?submission <" drafter:claimRole "> ?role ." + " ?submission <" drafter:claimPermission "> ?permission ." "}" "{" " SELECT DISTINCT ?ds WHERE {" @@ -203,17 +199,6 @@ (defn- user-is-owner-clause [user] (str "{ ?ds <" drafter:hasOwner "> <" (user/user->uri user) "> . }")) -(defn- user-is-in-claim-role-clause [user] - (let [role (user/role user) - user-role-score (role user/role->permission-level)] - (str - "{" - " VALUES (?role ?rv) { " (role-scores-values-clause user/role->permission-level) " }" - " ?ds <" drafter:hasSubmission "> ?submission ." - " ?submission <" drafter:claimRole "> ?role ." - " FILTER (" user-role-score " >= ?rv)" - "}"))) - (defn- draftset-properties-result->properties [draftset-ref {:keys [created @@ -221,7 +206,7 @@ description creator owner - role + permission claimuser submitter modified @@ -235,7 +220,7 @@ optional-fields {:display-name title :description description :current-owner (some-> owner (user/uri->username)) - :claim-role (some-> role (keyword)) + :claim-permission (keyword permission) :claim-user (some-> claimuser (user/uri->username)) :submitted-by (some-> submitter (user/uri->username))}] (merge required-fields (remove (comp nil? second) optional-fields)))) @@ -315,7 +300,8 @@ (let [q (set-draftset-metadata-query (ds/->draftset-uri draftset-ref) update-pairs)] (sparql/update! backend q)))) -(defn- submit-draftset-to-role-query [draftset-ref submission-id owner role] +(defn- submit-draftset-to-permission-query + [draftset-ref submission-id owner permission] (let [draftset-uri (ds/->draftset-uri draftset-ref) submit-uri (submission-id->uri submission-id) user-uri (user/user->uri owner)] @@ -327,7 +313,7 @@ "} INSERT {" (with-state-graph "<" submit-uri "> <" rdf:a "> <" drafter:Submission "> ." - "<" submit-uri "> <" drafter:claimRole "> \"" (name role) "\" ." + "<" submit-uri "> <" drafter:claimPermission "> \"" (name permission) "\" ." "<" draftset-uri "> <" drafter:hasSubmission "> <" submit-uri "> ." "<" draftset-uri "> <" drafter:submittedBy "> <" user-uri "> ." ) @@ -341,15 +327,16 @@ ) "}"))) -(defn submit-draftset-to-role! - "Submits a draftset to users of the specified role. +(defn submit-draftset-to-permission! + "Submits a draftset to users with the specified permission. - Removes the current owner of a draftset and makes it available to be - claimed by another user in a particular role. If the given user is - not the current owner of the draftset, no changes are made." - [backend draftset-ref owner role] - (let [q (submit-draftset-to-role-query draftset-ref (util/create-uuid) owner role)] - (sparql/update! backend q))) + Removes the current owner of a draftset and makes it available to be claimed + by another user with a particular permission. If the given user is not the + current owner of the draftset, no changes are made." + [backend draftset-ref owner permission] + (sparql/update! backend + (submit-draftset-to-permission-query + draftset-ref (util/create-uuid) owner permission))) (defn- submit-to-user-query [draftset-ref submission-id submitter target] (let [submitter-uri (user/user->uri submitter) @@ -384,10 +371,7 @@ (defn- try-claim-draftset-query [draftset-ref claimant] (let [draftset-uri (ds/->draftset-uri draftset-ref) - user-uri (user/user->uri claimant) - role (user/role claimant) - user-score (user/role->permission-level role) - scores-values (role-scores-values-clause user/role->permission-level)] + user-uri (user/user->uri claimant)] (str "DELETE {" (with-state-graph @@ -400,41 +384,20 @@ (with-state-graph "<" draftset-uri "> <" rdf:a "> <" drafter:DraftSet "> ." "<" draftset-uri "> <" drafter:hasSubmission "> ?submission ." - "?submission ?sp ?so ." - "{" - " SELECT DISTINCT ?submission WHERE {" - " {" - " VALUES (?role ?rv) { " scores-values " }" - " ?submission <" drafter:claimRole "> ?role ." - " FILTER (" user-score " >= ?rv)" - " } UNION {" - " ?submission <" drafter:claimUser "> <" user-uri "> ." - " } UNION {" - " <" draftset-uri "> <" drafter:submittedBy "> <" user-uri "> ." - " <" draftset-uri "> <" drafter:hasSubmission "> ?submission ." - " }" - " }" - "}") + "?submission ?sp ?so .") "}"))) (defn- try-claim-draftset! - "Sets the claiming user to the owner of the given draftset if: - - the draftset is available (has no current owner) - - the claiming user is in the appropriate role" + "Sets the claiming user to the owner of the given draftset if the draftset is + available (has no current owner). We should have already checked the + claimant has permission to claim the draftset." [backend draftset-ref claimant] (let [q (try-claim-draftset-query draftset-ref claimant)] (sparql/update! backend q))) -(defn- infer-claim-outcome [{:keys [current-owner claim-role claim-user] :as ds-info} claimant] - (cond - (nil? ds-info) :not-found - (= (user/username claimant) current-owner) :ok - (some? current-owner) :owned - (and (some? claim-role) - (not (user/has-role? claimant claim-role))) :role - (and (some? claim-user) - (not= claim-user (user/username claimant))) :user - :else :unknown)) +(defn- infer-claim-outcome + [{:keys [current-owner] :as ds-info} claimant] + (if (= (user/username claimant) current-owner) :ok :unknown)) (defn claim-draftset! "Attempts to claim a draftset for a user. If the draftset is @@ -443,17 +406,19 @@ operation and the current info for the draftset. The possible outcomes are: - :ok The draftset was claimed by the user - - :owned Claim failed as the draftset is not available - - :role Claim failed because the user is not in the claim role - - :user Claim failed because the user is not the assigned user - :not-found Claim failed because the draftset does not exist + - :forbidden Claim failed because the user does not have permission - :unknown Claim failed for an unknown reason" [backend draftset-ref claimant] - - (try-claim-draftset! backend draftset-ref claimant) - (let [ds-info (get-draftset-info backend draftset-ref) - outcome (infer-claim-outcome ds-info claimant)] - [outcome ds-info])) + (if-let [ds-info (get-draftset-info backend draftset-ref)] + (if (user/can-claim? claimant ds-info) + (do + (try-claim-draftset! backend draftset-ref claimant) + (let [ds-info (get-draftset-info backend draftset-ref) + outcome (infer-claim-outcome ds-info claimant)] + [outcome ds-info])) + [:forbidden nil]) + [:not-found nil])) (defn find-permitted-draftset-operations [backend draftset-ref user] (if-let [ds-info (get-draftset-info backend draftset-ref)] diff --git a/drafter/src/drafter/draftset.clj b/drafter/src/drafter/draftset.clj index b97f1b580..cd03f3202 100644 --- a/drafter/src/drafter/draftset.clj +++ b/drafter/src/drafter/draftset.clj @@ -76,15 +76,15 @@ ([creator display-name description] (assoc (create-draftset creator display-name) :description description))) -(defn- submit [draftset submitter role-or-user-key role-or-user-value] +(defn- submit [draftset submitter permission-or-user-key permission-or-user-value] (-> draftset - (dissoc :current-owner :claim-role :claim-user) - (assoc role-or-user-key role-or-user-value) + (dissoc :current-owner :claim-permission :claim-user) + (assoc permission-or-user-key permission-or-user-value) (assoc :submitted-by submitter))) ;; Not used outside of tests -(defn submit-to-role [draftset submitter role] - (submit draftset submitter :claim-role role)) +(defn submit-to-permission [draftset submitter permission] + (submit draftset submitter :claim-permission permission)) ;; Not used outside of tests (defn submit-to-user [draftset submitter username] @@ -92,5 +92,5 @@ (defn claim [draftset claimant] (-> draftset - (dissoc :submission) - (assoc :current-owner claimant))) + (dissoc :claim-permission :claim-user) + (assoc :current-owner (:email claimant)))) diff --git a/drafter/src/drafter/draftset/spec.clj b/drafter/src/drafter/draftset/spec.clj index a9866be84..d3de8e38c 100644 --- a/drafter/src/drafter/draftset/spec.clj +++ b/drafter/src/drafter/draftset/spec.clj @@ -16,7 +16,7 @@ (s/def ::ds/submitted-by :drafter/EmailAddress) (s/def ::ds/current-owner :drafter/EmailAddress) (s/def ::ds/claim-user string?) -(s/def ::ds/claim-role keyword?) +(s/def ::ds/claim-permission keyword?) (s/def ::ds/HasDescription (s/keys :req-un [::ds/description])) (s/def ::ds/HasDisplayName (s/keys :req-un [::ds/display-name])) @@ -24,9 +24,11 @@ (s/keys :req-un [::ds/changes ::ds/created-by] :opt-un [::ds/display-name ::ds/description ::ds/submitted-by]))) (s/def ::ds/OwnedDraftset (s/merge ::ds/DraftsetCommon (s/keys :req-un [::ds/current-owner]))) -(s/def ::ds/SubmittedToRole (s/keys :req-un [::ds/claim-role])) +(s/def ::ds/SubmittedToPermission (s/keys :req-un [::ds/claim-permission])) (s/def ::ds/SubmittedToUser (s/keys :req-un [::ds/claim-user])) -(s/def ::ds/SubmittedDraftset (s/and ::ds/DraftsetCommon (s/or :role ::ds/SubmittedToRole :user ::ds/SubmittedToUser))) +(s/def ::ds/SubmittedDraftset + (s/and ::ds/DraftsetCommon (s/or :permission ::ds/SubmittedToPermission + :user ::ds/SubmittedToUser))) (s/def ::ds/Draftset (s/or :owned ::ds/OwnedDraftset :submitted ::ds/SubmittedDraftset)) (def operations #{:delete :edit :submit :publish :claim}) diff --git a/drafter/src/drafter/feature/draftset/claim.clj b/drafter/src/drafter/feature/draftset/claim.clj index eab7ef046..c144ceecd 100644 --- a/drafter/src/drafter/feature/draftset/claim.clj +++ b/drafter/src/drafter/feature/draftset/claim.clj @@ -17,23 +17,21 @@ (if (jobutil/failed-job-result? result) (response/api-response 500 result) (let [[claim-outcome ds-info] (:details result)] - (if (= :ok claim-outcome) - (ring/response ds-info) - (conflict-detected-response "Failed to claim draftset"))))) + (case claim-outcome + :ok (ring/response ds-info) + :forbidden (forbidden-response "User does not have permission to claim draftset") + :not-found (ring/not-found "Draftset not found") + :unknown (conflict-detected-response "Failed to claim draftset"))))) (defn- handler* [{:keys [backend] :as manager} {{:keys [draftset-id]} :params user :identity :as request}] - (if-let [ds-info (dsops/get-draftset-info backend draftset-id)] - (if (user/can-claim? user ds-info) - (feat-common/run-sync manager - (req/user-id request) - 'claim-draftset - draftset-id - #(dsops/claim-draftset! backend draftset-id user) - respond) - (forbidden-response "User not in role for draftset claim")) - (ring/not-found "Draftset not found"))) + (feat-common/run-sync manager + (req/user-id request) + 'claim-draftset + draftset-id + #(dsops/claim-draftset! backend draftset-id user) + respond)) (defn handler [{{:keys [backend] :as manager} :drafter/manager wrap-authenticate :wrap-authenticate}] diff --git a/drafter/src/drafter/feature/draftset/list.clj b/drafter/src/drafter/feature/draftset/list.clj index 9b8feac97..cf2fe78d1 100644 --- a/drafter/src/drafter/feature/draftset/list.clj +++ b/drafter/src/drafter/feature/draftset/list.clj @@ -10,20 +10,14 @@ [drafter.feature.endpoint.public :as pub] [drafter.endpoint :as ep])) -(defn- role-scores-values-clause [scored-roles] - (let [score-pairs (map (fn [[r v]] (format "(\"%s\" %d)" (name r) v)) scored-roles)] - (clojure.string/join " " score-pairs))) - -(defn- user-is-in-claim-role-clause [user] - (let [role (user/role user) - user-role-score (role user/role->permission-level)] - (str - "{" - " VALUES (?role ?rv) { " (role-scores-values-clause user/role->permission-level) " }" - " ?ds <" drafter:hasSubmission "> ?submission ." - " ?submission <" drafter:claimRole "> ?role ." - " FILTER (" user-role-score " >= ?rv)" - "}"))) +;; Fetches all drafts with any claim permission set, we still need to check +;; that the user actually has the set permission. +(def claim-permission-clause + (str + "{" + " ?ds <" drafter:hasSubmission "> ?submission ." + " ?submission <" drafter:claimPermission "> ?permission ." + "}")) (defn- user-is-claim-user-clause [user] (str @@ -44,7 +38,7 @@ (str "{ ?ds <" drafter:hasOwner "> <" (user/user->uri user) "> . }")) (defn user-claimable-clauses [user] - [(user-is-in-claim-role-clause user) + [claim-permission-clause (user-is-claim-user-clause user) (user-is-submitter-clause user)]) @@ -53,10 +47,12 @@ (user-is-owner-clause user))) (defn get-all-draftsets-info [repo user] - (dsops/get-all-draftsets-by repo (user-all-visible-clauses user))) + (filter #(user/can-view? user %) + (dsops/get-all-draftsets-by repo (user-all-visible-clauses user)))) (defn get-draftsets-claimable-by [repo user] - (dsops/get-all-draftsets-by repo (user-claimable-clauses user))) + (filter #(user/can-claim? user %) + (dsops/get-all-draftsets-by repo (user-claimable-clauses user)))) (defn get-draftsets-owned-by [repo user] (dsops/get-all-draftsets-by repo [(user-is-owner-clause user)])) diff --git a/drafter/src/drafter/feature/draftset/submit.clj b/drafter/src/drafter/feature/draftset/submit.clj index d04fd379a..adbea7ed9 100644 --- a/drafter/src/drafter/feature/draftset/submit.clj +++ b/drafter/src/drafter/feature/draftset/submit.clj @@ -18,36 +18,36 @@ #(feat-common/draftset-sync-write-response % backend draftset-id)) (unprocessable-entity-response (str "User: " user " not found")))) -(defn handle-role - [{:keys [backend] :as manager} role draftset-id owner] - (let [role-kw (keyword role)] - (if (user/is-known-role? role-kw) - (feat-common/run-sync - manager - (:email owner) - 'submit-draftset-to-role - draftset-id - #(dsops/submit-draftset-to-role! backend draftset-id owner role-kw) - #(feat-common/draftset-sync-write-response % backend draftset-id)) - (unprocessable-entity-response (str "Invalid role: " role))))) +(defn handle-permission + [{:keys [backend] :as manager} permission draftset-id owner] + (feat-common/run-sync + manager + (:email owner) + 'submit-draftset-to-permission + draftset-id + #(dsops/submit-draftset-to-permission! backend + draftset-id + owner + (keyword permission)) + #(feat-common/draftset-sync-write-response % backend draftset-id))) (defn handler [{:keys [:drafter/manager :drafter.user/repo wrap-as-draftset-owner]}] - (wrap-as-draftset-owner :draft:offer - (fn [{{:keys [user role draftset-id]} :params owner :identity}] + (wrap-as-draftset-owner :draft:submit + (fn [{{:keys [user permission draftset-id]} :params owner :identity}] (cond - (and (some? user) (some? role)) + (and (some? user) (some? permission)) (unprocessable-entity-response - "Only one of user and role parameters permitted") + "Only one of user and permission parameters permitted") (some? user) (handle-user manager repo user draftset-id owner) - (some? role) - (handle-role manager role draftset-id owner) + (some? permission) + (handle-permission manager permission draftset-id owner) :else - (unprocessable-entity-response "user or role parameter required"))))) + (unprocessable-entity-response "user or permission parameter required"))))) (defmethod ig/pre-init-spec :drafter.feature.draftset.submit/handler [_] (s/keys :req [:drafter/manager ::user/repo] diff --git a/drafter/src/drafter/rdf/drafter_ontology.clj b/drafter/src/drafter/rdf/drafter_ontology.clj index 506f0f946..b13c92b63 100644 --- a/drafter/src/drafter/rdf/drafter_ontology.clj +++ b/drafter/src/drafter/rdf/drafter_ontology.clj @@ -45,7 +45,7 @@ (def drafter:modifiedAt dcterms:modified) -(def drafter:claimRole (url/append-path-segments drafter "claimRole")) +(def drafter:claimPermission (url/append-path-segments drafter "claimPermission")) (def drafter:claimUser (url/append-path-segments drafter "claimUser")) diff --git a/drafter/src/drafter/user.clj b/drafter/src/drafter/user.clj index bdb6dade4..360302502 100644 --- a/drafter/src/drafter/user.clj +++ b/drafter/src/drafter/user.clj @@ -12,13 +12,29 @@ (get-all-users [this] "Returns all users in this repository")) -(defrecord User [email role permissions password-digest]) +(defrecord User [email permissions password-digest]) (defmethod ig/init-key :drafter.user/repo [k opts] (throw (ex-info "Config error. Please use a concrete implementation of the user repo instead." {}))) -(def role->permission-level - {:access 0 :editor 1 :publisher 2 :manager 3 :system 4}) +(def role->permissions + "This map is only intended to be used for compatibility with mongo user + storage, or for convenience in tests." + {:access #{} + :editor #{:draft:claim :draft:create :draft:delete :draft:edit + :draft:submit :draft:share :draft:view :job:view :user:view} + :publisher #{:draft:claim :draft:create :draft:delete :draft:edit + :draft:submit :draft:share :draft:view :job:view :user:view + :draft:publish} + :manager #{:draft:claim :draft:create :draft:delete :draft:edit + :draft:submit :draft:share :draft:view :job:view :user:view + :draft:publish + ;; :draft:claim:manager is used in tests to demonstrate scoped + ;; claim permissions. + :draft:claim:manager} + :system #{:draft:claim :draft:create :draft:delete :draft:edit + :draft:submit :draft:share :draft:view :job:view :user:view + :draft:publish}}) (defn roles-including "Returns the set of roles which include the given role" @@ -39,13 +55,9 @@ :manager "Full access to drafts" :system "Full access to the entire system"} role)) -(def ^{:doc - "Ordered list of roles from least permissions to greatest permissions."} - roles - (sort-by role->permission-level (keys role->permission-level))) +(def roles (keys role->permissions)) (def username :email) -(def role :role) (defn get-digest "Generate the hashed password from the given plaintext password." @@ -69,32 +81,20 @@ (.getSchemeSpecificPart user-uri)) (defn is-known-role? [r] - (contains? role->permission-level r)) + (contains? role->permissions r)) (defn- get-valid-email [email] (if-let [valid (util/validate-email-address email)] valid (throw (IllegalArgumentException. (str "Not a valid email address: " email))))) -(defn role->permissions - "This function is only intended to be used for compatibility with mongo user - storage, or for convenience in tests." - [role] - (case role - :access #{} - :editor #{:draft:claim :draft:create :draft:delete :draft:edit :draft:offer - :draft:share :draft:view :job:view :user:view} - :publisher (conj (role->permissions :editor) :draft:publish) - :manager (recur :publisher) - :system (recur :manager))) - (defn create-user "Creates a user with a username, role and password digest which can be used to authenticate the user. Grants the user permissions corresponding to the given role." [email role password-digest] (let [email (get-valid-email email)] - (->User email role (role->permissions role) password-digest))) + (->User email (role->permissions role) password-digest))) (defn create-authenticated-user "Create a user without any authentication information which is @@ -102,15 +102,14 @@ authenticated for a request, their authentication parameters should no longer be needed, so users are normalised into a model without these parameters." - [email role permissions] - (let [email (get-valid-email email)] - {:email email :role role :permissions permissions})) + [email permissions] + {:email (get-valid-email email) :permissions permissions}) (defn authenticated! "Asserts that the given user has been authenticated and returns a representation of the user without authentication information." - [{:keys [email role permissions] :as user}] - (create-authenticated-user email role permissions)) + [{:keys [email permissions] :as user}] + (create-authenticated-user email permissions)) (defn try-authenticate "Tries to authenticate a user with the given candidate @@ -122,15 +121,8 @@ (defn get-summary "Returns a map containing summary information about a user." - [{:keys [email role] :as user}] - {:username email :role role}) - -(defn has-role? - "Takes a user and a role keyword and tests whether the user is - authorised to operate in that role." - [{:keys [role] :as user} requested] - (and (is-known-role? role) - (<= (role->permission-level requested) (role->permission-level role)))) + [{:keys [email] :as user}] + {:username email}) (defn has-permission? "Check if a user has a given permission." @@ -148,7 +140,7 @@ (if-let [email (util/validate-email-address (:email token))] (let [role (keyword (:role token))] (if (is-known-role? role) - (create-authenticated-user email role (role->permissions role)) + (create-authenticated-user email (role->permissions role)) (user-token-invalid token :role "Unknown role"))) (user-token-invalid token :email "Invalid address"))) @@ -161,25 +153,25 @@ (defn is-submitted-by? [user {:keys [submitted-by] :as draftset}] (= (username user) submitted-by)) -(defn can-claim? [user {:keys [claim-role claim-user] :as draftset}] +(defn can-claim? [user {:keys [claim-permission claim-user] :as draftset}] (or (is-owner? user draftset) (and (not (has-owner? draftset)) (is-submitted-by? user draftset)) - (and (some? claim-role) - (has-role? user claim-role)) + (and (some? claim-permission) + (has-permission? user claim-permission)) (= claim-user (username user)))) -(defn can-view? [user draftset] - (or (can-claim? user draftset) - (is-owner? user draftset))) +;; Currently the conditions for viewing a draft (in a list of all drafts, etc) +;; happen to be the same as the conditions for claiming a draft. This needn't +;; be the case in the future. +(def can-view? can-claim?) (defn permitted-draftset-operations [draftset user] (cond (is-owner? user draftset) - (let [ops #{:delete :edit :submit :claim}] - (if (has-role? user :publisher) - (conj ops :publish) - ops)) + (set (keep #(when-let [[_ op] (re-matches #"draft:(.*)" (name %))] + (keyword op)) + (:permissions user))) (can-claim? user draftset) #{:claim} diff --git a/drafter/src/drafter/user/mongo.clj b/drafter/src/drafter/user/mongo.clj index 26c765905..138874e60 100644 --- a/drafter/src/drafter/user/mongo.clj +++ b/drafter/src/drafter/user/mongo.clj @@ -80,8 +80,8 @@ db (mg/get-db conn db-name)] (->MongoUserRepository conn db collection-name))) -(defn- user->mongo-user [user] - (let [[email role digest] ((juxt user/username user/role user/password-digest) user) +(defn- user->mongo-user [user role] + (let [[email digest] ((juxt user/username user/password-digest) user) role-number (get (set/map-invert role-mappings) role)] {:_id (ObjectId.) :email email @@ -96,8 +96,8 @@ (defn insert-user "Inserts a user into a mongo db user repository." - [repo user] - (let [mongo-user (user->mongo-user user)] + [repo user role] + (let [mongo-user (user->mongo-user user role)] (insert-document repo mongo-user))) (derive :drafter.user/mongo :drafter.user/repo) diff --git a/drafter/src/drafter/user/spec.clj b/drafter/src/drafter/user/spec.clj index 43ccfca9e..99aa3cbb9 100644 --- a/drafter/src/drafter/user/spec.clj +++ b/drafter/src/drafter/user/spec.clj @@ -8,7 +8,7 @@ [clojure.spec.test.alpha :as st]) (:import [drafter.user User])) -(s/def ::user/role (s/with-gen user/is-known-role? (fn [] (gen/elements user/roles)))) +(s/def ::user/role (set (keys user/role->permissions))) (s/def ::user/permissions (s/coll-of keyword? :kind set?)) (s/def ::user/email :drafter/EmailAddress) (s/def ::user/password-digest string?) @@ -19,9 +19,9 @@ (s/def ::user/DbUser #(instance? User %)) (s/def ::user/User - (s/keys :req-un [::user/role ::user/email ::user/permissions])) + (s/keys :req-un [::user/email ::user/permissions])) (s/def ::user/UserSummary - (s/keys :req-un [::user/username ::user/role ::user/permissions])) + (s/keys :req-un [::user/username])) (s/def ::user/UserToken (s/keys :req-un [:token/email :token/role])) (s/def ::user/repo #(satisfies? user/UserRepository %)) @@ -45,7 +45,7 @@ :ret ::user/DbUser) (s/fdef user/create-authenticated-user - :args (s/cat :email string? :role ::user/role :permissions ::user/permissions) + :args (s/cat :email string? :permissions ::user/permissions) :ret ::user/User) (s/fdef user/authenticated! @@ -56,10 +56,6 @@ :args (s/cat :user ::user/User) :ret ::user/UserSummary) -(s/fdef user/has-role? - :args (s/cat :user ::user/User :requested ::user/role) - :ret boolean?) - (s/fdef user/validate-token! :args (s/cat :token ::user/UserToken) :ret ::user/User) @@ -76,10 +72,6 @@ :args (s/cat :user ::user/User :draftset ::ds/Draftset) :ret boolean?) -(s/fdef user/can-view? - :args (s/cat :user ::user/User :draftset ::ds/Draftset) - :ret boolean?) - (s/fdef user/permitted-draftset-operations :args (s/cat :draftset ::ds/Draftset :user ::user/User) :ret (s/coll-of ::ds/Operation :kind set?)) @@ -92,12 +84,10 @@ `user/create-authenticated-user `user/authenticated! `user/get-summary - `user/has-role? `user/validate-token! `user/has-owner? `user/is-owner? `user/can-claim? - `user/can-view? `user/permitted-draftset-operations]) (defn instrument [] diff --git a/drafter/test/drafter/backend/draftset/operations_test.clj b/drafter/test/drafter/backend/draftset/operations_test.clj index 00e313170..66271ba3d 100644 --- a/drafter/test/drafter/backend/draftset/operations_test.clj +++ b/drafter/test/drafter/backend/draftset/operations_test.clj @@ -91,7 +91,10 @@ (testing "With no owner" (let [draftset-id (sut/create-draftset! *test-backend* test-editor)] - (sut/submit-draftset-to-role! *test-backend* draftset-id test-editor :publisher) + (sut/submit-draftset-to-permission! *test-backend* + draftset-id + test-editor + :draft:claim) (let [owner (sut/get-draftset-owner *test-backend* draftset-id)] (is (nil? owner)))))) @@ -102,7 +105,10 @@ (testing "Has no owner" (let [draftset-id (sut/create-draftset! *test-backend* test-editor)] - (sut/submit-draftset-to-role! *test-backend* draftset-id test-editor :publisher) + (sut/submit-draftset-to-permission! *test-backend* + draftset-id + test-editor + :draft:claim) (is (= false (sut/is-draftset-owner? *test-backend* draftset-id test-editor))))) (testing "Has different owner" @@ -133,28 +139,34 @@ (doseq [dg draft-graphs] (is (= false (mgmth/draft-exists? *test-backend* dg)))))) -(defn- draftset-has-claim-role? [draftset-id role] +(defn- draftset-has-claim-permission? [draftset-id permission] (let [q (str "ASK WHERE {" (with-state-graph "<" (->draftset-uri draftset-id) "> <" drafter:hasSubmission "> ?submission ." - "?submission <" drafter:claimRole "> \"" (name role) "\" .") + "?submission <" drafter:claimPermission "> \"" (name permission) "\" .") "}")] (sparql/eager-query *test-backend* q))) -(deftest submit-draftset-to-role-test! +(deftest submit-draftset-to-permission-test! (testing "Existing owner" (let [draftset-id (sut/create-draftset! *test-backend* test-editor "Test draftset") draftset-uri (->draftset-uri draftset-id)] - (sut/submit-draftset-to-role! *test-backend* draftset-id test-editor :publisher) + (sut/submit-draftset-to-permission! *test-backend* + draftset-id + test-editor + :draft:claim) - (is (draftset-has-claim-role? draftset-id :publisher)) + (is (draftset-has-claim-permission? draftset-id :draft:claim)) (is (= false (has-any-object? draftset-uri drafter:hasOwner))))) (testing "Submitted by other user" (let [draftset-id (sut/create-draftset! *test-backend* test-editor "Test draftset") draftset-uri (->draftset-uri draftset-id)] - (sut/submit-draftset-to-role! *test-backend* draftset-id test-publisher :manager) + (sut/submit-draftset-to-permission! *test-backend* + draftset-id + test-publisher + :draft:claim) (is (sut/is-draftset-owner? *test-backend* draftset-id test-editor)) (is (= false (has-any-object? draftset-uri drafter:hasSubmission)))))) @@ -202,11 +214,14 @@ (testing "When submitted" (let [draftset-id (sut/create-draftset! *test-backend* test-editor)] - (sut/submit-draftset-to-role! *test-backend* draftset-id test-editor :publisher) + (sut/submit-draftset-to-permission! *test-backend* + draftset-id + test-editor + :draft:claim) (sut/submit-draftset-to-user! *test-backend* draftset-id test-editor test-manager) (is (= nil (sut/get-draftset-owner *test-backend* draftset-id))) - (is (draftset-has-claim-role? draftset-id :publisher)) + (is (draftset-has-claim-permission? draftset-id :draft:claim)) (is (= false (draftset-has-claim-user? draftset-id test-manager)))))) (defn- draftset-has-submission? [draftset-ref] @@ -219,10 +234,13 @@ (sparql/eager-query *test-backend* q))) (deftest claim-draftset-test! - (testing "No owner when user in role" + (testing "No owner when user has claim permission" (let [draftset-id (sut/create-draftset! *test-backend* test-editor "Test draftset") draftset-uri (->draftset-uri draftset-id)] - (sut/submit-draftset-to-role! *test-backend* draftset-id test-editor :publisher) + (sut/submit-draftset-to-permission! *test-backend* + draftset-id + test-editor + :draft:claim) (let [[result _] (sut/claim-draftset! *test-backend* draftset-id test-publisher) ds-info (sut/get-draftset-info *test-backend* draftset-id)] @@ -244,13 +262,16 @@ (sut/submit-draftset-to-user! *test-backend* draftset-id test-editor test-publisher) (let [[result _] (sut/claim-draftset! *test-backend* draftset-id test-manager)] - (is (= :user result)) + (is (= :forbidden result)) (is (nil? (sut/get-draftset-owner *test-backend* draftset-id))) (is (draftset-has-submission? draftset-id))))) - (testing "Reclaimed by submitter after submit to role" + (testing "Reclaimed by submitter after submit to permission" (let [draftset-id (sut/create-draftset! *test-backend* test-editor "Test draftset")] - (sut/submit-draftset-to-role! *test-backend* draftset-id test-editor :publisher) + (sut/submit-draftset-to-permission! *test-backend* + draftset-id + test-editor + :draft:claim) (let [[result _] (sut/claim-draftset! *test-backend* draftset-id test-editor)] (is (= :ok result)) (is (sut/is-draftset-owner? *test-backend* draftset-id test-editor)) @@ -264,9 +285,12 @@ (is (sut/is-draftset-owner? *test-backend* draftset-id test-editor)) (is (= false (draftset-has-submission? draftset-id)))))) - (testing "No owner when user is submitter not in role" + (testing "No owner when user doesn't have permission but is submitter" (let [draftset-id (sut/create-draftset! *test-backend* test-editor "Test draftset")] - (sut/submit-draftset-to-role! *test-backend* draftset-id test-editor :publisher) + (sut/submit-draftset-to-permission! *test-backend* + draftset-id + test-editor + :draft:publish) (let [[result _] (sut/claim-draftset! *test-backend* draftset-id test-editor)] (is (= :ok result)) (is (sut/is-draftset-owner? *test-backend* draftset-id test-editor)) @@ -274,10 +298,13 @@ (testing "Owned by other user after submitted by user" (let [draftset-id (sut/create-draftset! *test-backend* test-editor "Test draftset")] - (sut/submit-draftset-to-role! *test-backend* draftset-id test-editor :publisher) + (sut/submit-draftset-to-permission! *test-backend* + draftset-id + test-editor + :draft:publish) (sut/claim-draftset! *test-backend* draftset-id test-publisher) (let [[result _] (sut/claim-draftset! *test-backend* draftset-id test-editor)] - (is (= :owned result))))) + (is (= :forbidden result))))) (testing "Claimed by current owner" (let [draftset-id (sut/create-draftset! *test-backend* test-editor) @@ -285,17 +312,20 @@ (is (= :ok result)) (is (sut/is-draftset-owner? *test-backend* draftset-id test-editor)))) - (testing "User not in claim role" + (testing "User doesn't have claim permission" (let [draftset-id (sut/create-draftset! *test-backend* test-editor)] - (sut/submit-draftset-to-role! *test-backend* draftset-id test-editor :manager) + (sut/submit-draftset-to-permission! *test-backend* + draftset-id + test-editor + :draft:claim:manager) (let [[result _] (sut/claim-draftset! *test-backend* draftset-id test-publisher)] - (is (= :role result)) + (is (= :forbidden result)) (is (nil? (sut/get-draftset-owner *test-backend* draftset-id)))))) (testing "Draftset owned by other user" (let [draftset-id (sut/create-draftset! *test-backend* test-editor)] (let [[result _] (sut/claim-draftset! *test-backend* draftset-id test-publisher)] - (is (= :owned result)) + (is (= :forbidden result)) (is (sut/is-draftset-owner? *test-backend* draftset-id test-editor))))) (testing "Draftset does not exist" @@ -345,4 +375,4 @@ (t/testing "push query" (let [[events handler] (stasher-test/recording-rdf-handler)] (.evaluate pquery handler) - (t/is (= graph-triples (set (:data @events))) "Unexpected results from push query"))))))) \ No newline at end of file + (t/is (= graph-triples (set (:data @events))) "Unexpected results from push query"))))))) diff --git a/drafter/test/drafter/feature/draftset/claim_test.clj b/drafter/test/drafter/feature/draftset/claim_test.clj index 7c6bfe643..4d4e05cc3 100644 --- a/drafter/test/drafter/feature/draftset/claim_test.clj +++ b/drafter/test/drafter/feature/draftset/claim_test.clj @@ -3,6 +3,7 @@ [drafter.draftset :as ds] [drafter.draftset.spec :as dss] [drafter.feature.draftset.create-test :as ct] + [drafter.feature.draftset.test-helper :as help] [drafter.test-common :as tc] [drafter.user :as user] [drafter.user-test @@ -21,13 +22,6 @@ (tc/assert-spec ::ds/Draftset body) body)) -(defn- create-submit-to-role-request [user draftset-location role] - (tc/with-identity user {:uri (str draftset-location "/submit-to") :request-method :post :params {:role (name role)}})) - -(defn- submit-draftset-to-role-through-api [handler user draftset-location role] - (let [response (handler (create-submit-to-role-request user draftset-location role))] - (tc/assert-is-ok-response response))) - (defn- submit-draftset-to-username-request [draftset-location target-username user] (tc/with-identity user {:uri (str draftset-location "/submit-to") :request-method :post :params {:user target-username}})) @@ -42,13 +36,16 @@ (def keys-for-test [:drafter.fixture-data/loader [:drafter/routes :draftset/api]]) -(tc/deftest-system-with-keys claim-draftset-submitted-to-role +(tc/deftest-system-with-keys claim-draftset-submitted-to-permission keys-for-test [system "test-system.edn"] (let [handler (get system [:drafter/routes :draftset/api]) {{draftset-location "Location"} :headers} (handler (ct/create-draftset-request test-editor))] - (submit-draftset-to-role-through-api handler test-editor draftset-location :publisher) + (help/submit-draftset-to-permission-through-api handler + test-editor + draftset-location + :draft:claim) (let [{:keys [current-owner] :as ds-info} (claim-draftset-through-api handler draftset-location test-publisher)] (is (= (user/username test-publisher) current-owner))))) @@ -93,7 +90,10 @@ (let [handler (get system [:drafter/routes :draftset/api]) {{draftset-location "Location"} :headers} (handler (ct/create-draftset-request test-editor))] - (submit-draftset-to-role-through-api handler test-editor draftset-location :publisher) + (help/submit-draftset-to-permission-through-api handler + test-editor + draftset-location + :draft:claim) (claim-draftset-through-api handler draftset-location test-editor))) (tc/deftest-system-with-keys claim-owned-by-other-user-draftset-submitted-by-self @@ -102,7 +102,10 @@ (let [handler (get system [:drafter/routes :draftset/api]) {{draftset-location "Location"} :headers} (handler (ct/create-draftset-request test-editor))] - (submit-draftset-to-role-through-api handler test-editor draftset-location :publisher) + (help/submit-draftset-to-permission-through-api handler + test-editor + draftset-location + :draft:claim) (claim-draftset-through-api handler draftset-location test-publisher) (let [response (handler (create-claim-request draftset-location test-editor))] (tc/assert-is-forbidden-response response)))) @@ -117,7 +120,7 @@ claim-response (handler claim-request)] (tc/assert-is-forbidden-response claim-response))) -(tc/deftest-system-with-keys ^:basic-auth claim-draftset-by-user-not-in-role +(tc/deftest-system-with-keys ^:basic-auth claim-draftset-by-user-without-permission [:drafter.fixture-data/loader [:drafter/routes :draftset/api] :drafter.user/memory-repository] [{handler [:drafter/routes :draftset/api] users :drafter.user/memory-repository :as system} "test-system.edn"] @@ -126,7 +129,10 @@ {{draftset-location "Location"} :headers} (handler (ct/create-draftset-request test-editor))] (memrepo/add-user users other-editor) - (submit-draftset-to-role-through-api handler test-editor draftset-location :publisher) + (help/submit-draftset-to-permission-through-api handler + test-editor + draftset-location + :draft:publish) (let [claim-response (handler (create-claim-request draftset-location other-editor))] (tc/assert-is-forbidden-response claim-response)))) diff --git a/drafter/test/drafter/feature/draftset/options_test.clj b/drafter/test/drafter/feature/draftset/options_test.clj index 74a60366f..a0c4c83b5 100644 --- a/drafter/test/drafter/feature/draftset/options_test.clj +++ b/drafter/test/drafter/feature/draftset/options_test.clj @@ -15,7 +15,7 @@ options-request (tc/with-identity test-editor {:uri draftset-location :request-method :options}) {:keys [body] :as options-response} (handler options-request)] (tc/assert-is-ok-response options-response) - (is (= #{:edit :delete :submit :claim} (set body))))) + (is (= #{:edit :delete :submit :claim :create :share :view} (set body))))) (tc/deftest-system-with-keys get-options-for-non-existent-draftset [:drafter.fixture-data/loader [:drafter/routes :draftset/api]] diff --git a/drafter/test/drafter/feature/draftset/show_test.clj b/drafter/test/drafter/feature/draftset/show_test.clj index dc23ee9e1..5292634fc 100644 --- a/drafter/test/drafter/feature/draftset/show_test.clj +++ b/drafter/test/drafter/feature/draftset/show_test.clj @@ -19,13 +19,6 @@ (def system-config "drafter/feature/empty-db-system.edn") -(defn- create-submit-to-role-request [user draftset-location role] - (tc/with-identity user {:uri (str draftset-location "/submit-to") :request-method :post :params {:role (name role)}})) - -(defn- submit-draftset-to-role-through-api [handler user draftset-location role] - (let [response (handler (create-submit-to-role-request user draftset-location role))] - (tc/assert-is-ok-response response))) - (tc/deftest-system-with-keys get-all-draftsets-changes-test keys-for-test [system system-config] @@ -166,7 +159,10 @@ [system system-config] (let [handler (get system [:drafter/routes :draftset/api]) draftset-location (help/create-draftset-through-api handler test-editor)] - (submit-draftset-to-role-through-api handler test-editor draftset-location :publisher) + (help/submit-draftset-to-permission-through-api handler + test-editor + draftset-location + :draft:claim) (let [ds-info (help/get-user-draftset-info-view-through-api handler draftset-location test-publisher)]))) (tc/deftest-system-with-keys get-draftset-for-other-user-test diff --git a/drafter/test/drafter/feature/draftset/submit_test.clj b/drafter/test/drafter/feature/draftset/submit_test.clj index e1e192297..40e60130e 100644 --- a/drafter/test/drafter/feature/draftset/submit_test.clj +++ b/drafter/test/drafter/feature/draftset/submit_test.clj @@ -11,26 +11,25 @@ (def keys-for-test [:drafter.fixture-data/loader [:drafter/routes :draftset/api]]) -(tc/deftest-system-with-keys submit-non-existent-draftset-to-role +(tc/deftest-system-with-keys submit-non-existent-draftset-to-permission keys-for-test [{handler [:drafter/routes :draftset/api]} "test-system.edn"] - (let [submit-response (handler (help/create-submit-to-role-request test-editor "/v1/draftset/missing" :publisher))] + (let [submit-response (handler (help/create-submit-to-permission-request + test-editor + "/v1/draftset/missing" + :draft:claim))] (tc/assert-is-not-found-response submit-response))) -(tc/deftest-system-with-keys submit-draftset-to-role-by-non-owner +(tc/deftest-system-with-keys submit-draftset-to-permission-by-non-owner keys-for-test [{handler [:drafter/routes :draftset/api]} "test-system.edn"] (let [draftset-location (help/create-draftset-through-api handler test-editor) - submit-response (handler (help/create-submit-to-role-request test-publisher draftset-location :manager))] + submit-response (handler (help/create-submit-to-permission-request + test-publisher + draftset-location + :draft:claim))] (tc/assert-is-forbidden-response submit-response))) -(tc/deftest-system-with-keys submit-draftset-to-invalid-role - keys-for-test - [{handler [:drafter/routes :draftset/api]} "test-system.edn"] - (let [draftset-location (help/create-draftset-through-api handler test-editor) - submit-response (handler (help/create-submit-to-role-request test-editor draftset-location :invalid))] - (tc/assert-is-unprocessable-response submit-response))) - (tc/deftest-system-with-keys submit-draftset-to-user keys-for-test [{handler [:drafter/routes :draftset/api]} "test-system.edn"] @@ -79,20 +78,22 @@ response (handler submit-request)] (tc/assert-is-unprocessable-response response))) -(tc/deftest-system-with-keys submit-to-with-both-user-and-role-params +(tc/deftest-system-with-keys submit-to-with-both-user-and-permission-params keys-for-test [{handler [:drafter/routes :draftset/api]} "test-system.edn"] (let [draftset-location (help/create-draftset-through-api handler test-editor) request (help/submit-draftset-to-user-request draftset-location test-publisher test-editor) - request (assoc-in request [:params :role] "editor") + request (assoc-in request [:params :permission] "draft:claim") response (handler request)] (tc/assert-is-unprocessable-response response))) -(tc/deftest-system-with-keys submit-draftset-to-role +(tc/deftest-system-with-keys submit-draftset-to-permission keys-for-test [{handler [:drafter/routes :draftset/api]} "test-system.edn"] (let [draftset-location (help/create-draftset-through-api handler test-editor) - submit-request (help/create-submit-to-role-request test-editor draftset-location :publisher) + submit-request (help/create-submit-to-permission-request test-editor + draftset-location + :draft:claim) {ds-info :body :as submit-response} (handler submit-request)] (tc/assert-is-ok-response submit-response) (tc/assert-spec ::ds/Draftset ds-info) diff --git a/drafter/test/drafter/feature/draftset/test_helper.clj b/drafter/test/drafter/feature/draftset/test_helper.clj index 94abf86e6..c2a71a697 100644 --- a/drafter/test/drafter/feature/draftset/test_helper.clj +++ b/drafter/test/drafter/feature/draftset/test_helper.clj @@ -31,10 +31,10 @@ (and (>= status 400) (< status 500))) -(defn create-submit-to-role-request [user draftset-location role] +(defn create-submit-to-permission-request [user draftset-location permission] (tc/with-identity user {:uri (str draftset-location "/submit-to") :request-method :post - :params {:role (name role)}})) + :params {:permission (name permission)}})) (defn create-draftset-through-api ([handler] (create-draftset-through-api handler test-editor)) @@ -59,8 +59,11 @@ response (handler request)] (tc/assert-is-ok-response response))) -(defn submit-draftset-to-role-through-api [handler user draftset-location role] - (let [response (handler (create-submit-to-role-request user draftset-location role))] +(defn submit-draftset-to-permission-through-api + [handler user draftset-location permission] + (let [response (handler (create-submit-to-permission-request user + draftset-location + permission))] (tc/assert-is-ok-response response))) (defn delete-draftset-graph-request [user draftset-location graph-to-delete] diff --git a/drafter/test/drafter/model.clj b/drafter/test/drafter/model.clj index acdd802ad..9634279b2 100644 --- a/drafter/test/drafter/model.clj +++ b/drafter/test/drafter/model.clj @@ -76,14 +76,14 @@ (dsops/find-permitted-draftset-operations backend draftset-ref user)) (defn- publish-draftset-op [drafter user draftset-ref {:keys [metadata] :as opts}] - (if (user/has-role? user :publisher) + (if (user/has-permission? user :draft:publish) (let [params (cond-> {:draftset-id draftset-ref} (some? metadata) (assoc :metadata (format-metadata metadata))) job (dsjobs/publish-draftset-job drafter user params)] (write-scheduler/enqueue-async-job! job)) - (throw (ex-info "You require the publisher role to perform this action" {})))) + (throw (ex-info "You require the publish permission to perform this action" {})))) (defn- draftset-query-endpoint-op [{:keys [backend]} _user draftset-ref {:keys [union-with-live?] :as opts}] (backend/endpoint-repo backend draftset-ref {:union-with-live? union-with-live?})) @@ -95,12 +95,21 @@ (defn- show-draftset-op [{:keys [backend] :as drafter} user draftset-ref {:keys [union-with-live?] :as opts}] (ds-show/get-draftset backend user draftset-ref (or union-with-live? false))) -(defn- submit-draftset-op [{:keys [backend]} user draftset-ref {target-user :user target-role :role :as opts}] +(defn- submit-draftset-op + [{:keys [backend]} user draftset-ref {target-user :user + target-permission :permission}] (cond - (and (some? target-user) (some? target-role)) (throw (ex-info "Specify only one of target user or role" {})) - (some? target-user) (dsops/submit-draftset-to-user! backend draftset-ref user target-user) - (some? target-role) (dsops/submit-draftset-to-role! backend draftset-ref user target-role) - :else (throw (ex-info "Target user or role required" {}))) + (and (some? target-user) (some? target-permission)) + (throw (ex-info "Specify only one of target user or permission" {})) + + (some? target-user) + (dsops/submit-draftset-to-user! backend draftset-ref user target-user) + + (some? target-permission) + (dsops/submit-draftset-to-permission! backend draftset-ref user target-permission) + + :else + (throw (ex-info "Target user or permission required" {}))) (dsops/get-draftset-info backend draftset-ref)) (defn- append-draftset-data-op [drafter user draftset-ref source {:keys [metadata] :as opts}] @@ -279,10 +288,10 @@ [drafter user draftset-ref target-user] (submit-draftset drafter user draftset-ref {:user target-user})) -(defn submit-draftset-to-role - "Submits a draftset owned by user to a role" - [drafter user draftset-ref target-role] - (submit-draftset drafter user draftset-ref {:role target-role})) +(defn submit-draftset-to-permission + "Submits a draftset owned by user to a permission" + [drafter user draftset-ref target-permission] + (submit-draftset drafter user draftset-ref {:permission target-permission})) (defn append-data "Appends data from an RDF source to a draftset" @@ -334,7 +343,10 @@ _ds-list (list-draftsets drafter test-publisher {})] ;;lifecycle - (submit-draftset-to-role drafter test-publisher ds-id :editor) + (submit-draftset-to-permission drafter + test-publisher + ds-id + :draft:claim) (claim-draftset drafter test-editor ds-id) (submit-draftset-to-user drafter test-editor ds-id test-publisher) (claim-draftset drafter test-publisher ds-id) diff --git a/drafter/test/drafter/user/auth0_repository_test.clj b/drafter/test/drafter/user/auth0_repository_test.clj index 8fb26bfc6..7148a4d23 100644 --- a/drafter/test/drafter/user/auth0_repository_test.clj +++ b/drafter/test/drafter/user/auth0_repository_test.clj @@ -1,7 +1,7 @@ (ns drafter.user.auth0-repository-test (:require [clojure.test :refer :all] [drafter.test-common :as tc] - [drafter.user :as user :refer [create-user get-digest roles username]] + [drafter.user :as user :refer [create-user get-digest username]] [drafter.user-test :refer [test-editor]] [drafter.user.auth0-repository :as repo])) diff --git a/drafter/test/drafter/user/mongo_test.clj b/drafter/test/drafter/user/mongo_test.clj index d712dc9ba..68bf678ee 100644 --- a/drafter/test/drafter/user/mongo_test.clj +++ b/drafter/test/drafter/user/mongo_test.clj @@ -25,19 +25,20 @@ (deftest find-existing-user-test (let [email "test@example.com" test-user (user/create-user email :publisher "dsklfsjde")] - (um/insert-user *user-repo* test-user) + (um/insert-user *user-repo* test-user :publisher) (let [found-user (user/find-user-by-username *user-repo* email)] (is (= test-user found-user))))) (deftest get-all-users-test (let [email-f #(str "user" % "@example.com") - expected-users (map #(user/create-user (email-f %1) %2 (str %1)) - (range 1 10) - (cycle user/roles))] - - (doseq [u expected-users] - (um/insert-user *user-repo* u)) + expected-users (reduce + (fn [users [i role]] + (let [u (user/create-user (email-f i) role (str i))] + (um/insert-user *user-repo* u role) + (conj users u))) + [] + (map vector (range 1 10) (cycle user/roles)))] (let [actual-users (user/get-all-users *user-repo*)] (is (= (set expected-users) (set actual-users)))))) diff --git a/drafter/test/drafter/user_test.clj b/drafter/test/drafter/user_test.clj index 76c8df373..22c1d2f0b 100644 --- a/drafter/test/drafter/user_test.clj +++ b/drafter/test/drafter/user_test.clj @@ -19,19 +19,19 @@ (testing "Invalid email address" (is (thrown? IllegalArgumentException (create-user "invalidemail" :publisher (get-digest "password")))))) -(deftest has-role?-test - (are [user role has?] (= has? (has-role? user role)) - test-editor :editor true - test-editor :publisher false - test-editor :manager false +(deftest has-permission?-test + (are [user permission has?] (= has? (has-permission? user permission)) + test-editor :draft:edit true + test-editor :draft:publish false + test-editor :draft:publish false - test-publisher :editor true - test-publisher :publisher true - test-publisher :manager false + test-publisher :draft:edit true + test-publisher :draft:publish true + test-publisher :draft:publish true - test-manager :editor true - test-manager :publisher true - test-manager :manager true)) + test-manager :draft:edit true + test-manager :draft:publish true + test-manager :draft:publish true)) (t/deftest roles-including-test (t/are [role expected] (= expected (roles-including role)) @@ -58,7 +58,6 @@ (testing "Valid token" (is (= {:email "foo@bar.com" - :role :editor :permissions (role->permissions :editor)} (validate-token! {:email "foo@bar.com" :role "editor"}))))) @@ -66,22 +65,15 @@ (are [user expected] (= expected (authenticated! user)) (create-user "test@example.com" :publisher "digest") (create-authenticated-user "test@example.com" - :publisher (role->permissions :publisher)) - (create-authenticated-user "test@example.com" - :editor - (role->permissions :editor)) - (create-authenticated-user "test@example.com" - :editor - (role->permissions :editor)) + (create-authenticated-user "test@example.com" (role->permissions :editor)) + (create-authenticated-user "test@example.com" (role->permissions :editor)) (assoc (create-authenticated-user "test@example.com" - :editor (role->permissions :editor)) :x "x" :y "y") (create-authenticated-user "test@example.com" - :editor (role->permissions :editor)))) (deftest is-owner?-test @@ -89,9 +81,9 @@ test-editor (ds/create-draftset (username test-editor)) true test-editor (ds/create-draftset (username test-publisher)) false)) -(defn- submitted-to-role [creator role] +(defn- submitted-to-permission [creator permission] (-> (ds/create-draftset (username creator)) - (ds/submit-to-role (username creator) role))) + (ds/submit-to-permission (username creator) permission))) (defn- submitted-to-user [creator target] (-> (ds/create-draftset (username creator)) @@ -99,8 +91,8 @@ (deftest is-submitted-by?-test (are [user draftset expected] (= expected (is-submitted-by? user draftset)) - test-editor (submitted-to-role test-editor :publisher) true - test-publisher (submitted-to-role test-editor :manager) false + test-editor (submitted-to-permission test-editor :draft:claim) true + test-publisher (submitted-to-permission test-editor :draft:claim) false test-editor (ds/create-draftset (username test-editor)) false)) (deftest can-claim?-test @@ -109,11 +101,11 @@ test-editor (ds/create-draftset (username test-editor)) true ;;submitter can re-claim draftset if it has not yet been claimed - test-editor (submitted-to-role test-editor :publisher) true + test-editor (submitted-to-permission test-editor :draft:claim) true test-editor (submitted-to-user test-editor test-manager) true - ;;user can claim draftset submitted to their role - test-publisher (submitted-to-role test-editor :publisher) true + ;;user can claim draftset submitted to a permission they have + test-publisher (submitted-to-permission test-editor :draft:claim) true ;;user can claim draftset submitted to them test-manager (submitted-to-user test-editor test-manager) true @@ -121,8 +113,8 @@ ;;user cannot claim draftset owned by another user test-publisher (ds/create-draftset (username test-editor)) false - ;;user cannot claim draftset submitted to role they are not in - test-publisher (submitted-to-role test-editor :manager) false + ;;user cannot claim draftset submitted to a permission they don't have + test-publisher (submitted-to-permission test-editor :draft:claim:manager) false ;;user cannot claim draftset submitted to other user test-manager (submitted-to-user test-editor test-publisher) false)) @@ -130,22 +122,36 @@ (deftest permitted-draftset-operations-test (are [user draftset expected-operations] (= expected-operations (permitted-draftset-operations draftset user)) ;;non-publishing owner - test-editor (ds/create-draftset (username test-editor)) #{:delete :edit :submit :claim} + test-editor + (ds/create-draftset (username test-editor)) + #{:share :claim :delete :edit :view :create :submit} ;;publishing owner - test-publisher (ds/create-draftset (username test-publisher)) #{:delete :edit :submit :claim :publish} + test-publisher + (ds/create-draftset (username test-publisher)) + #{:share :claim :delete :edit :view :create :submit :publish} ;;submitter on unclaimed - test-editor (submitted-to-role test-editor :publisher) #{:claim} + test-editor (submitted-to-permission test-editor :draft:claim) #{:claim} ;;submitted on claimed - test-editor (ds/claim (submitted-to-role test-editor :publisher) test-publisher) #{} + test-editor + (ds/claim (submitted-to-permission test-editor :draft:claim) test-publisher) + #{} ;;non-owner test-publisher (ds/create-draftset (username test-editor)) #{} - ;;user in claim role - test-publisher (ds/submit-to-role (ds/create-draftset "tmp@example.com") "tmp@example.com" :publisher) #{:claim} - - ;;user not in claim role - test-editor (ds/submit-to-role (ds/create-draftset "tmp@example.com") "tmp@example.com" :manager) #{})) + ;;user has claim permission + test-publisher + (ds/submit-to-permission (ds/create-draftset "tmp@example.com") + "tmp@example.com" + :draft:claim) + #{:claim} + + ;;user doesn't have claim permission + test-editor + (ds/submit-to-permission (ds/create-draftset "tmp@example.com") + "tmp@example.com" + :draft:publish) + #{})) diff --git a/drafter/test/resources/drafter/feature/draftset/claimable-draftset-changes-2.trig b/drafter/test/resources/drafter/feature/draftset/claimable-draftset-changes-2.trig index ef44c3d81..ea8b1d84b 100644 --- a/drafter/test/resources/drafter/feature/draftset/claimable-draftset-changes-2.trig +++ b/drafter/test/resources/drafter/feature/draftset/claimable-draftset-changes-2.trig @@ -95,9 +95,9 @@ draft:append-on-g2 { drafter:inDraftSet draftset:ds-2 . a drafter:Submission ; - drafter:claimRole "publisher" . + drafter:claimPermission "draft:claim" . a drafter:Submission ; - drafter:claimRole "publisher" . + drafter:claimPermission "draft:claim" . } diff --git a/drafter/test/resources/drafter/feature/draftset/claimable-draftset-changes.trig b/drafter/test/resources/drafter/feature/draftset/claimable-draftset-changes.trig index 881e4353f..10dc57773 100644 --- a/drafter/test/resources/drafter/feature/draftset/claimable-draftset-changes.trig +++ b/drafter/test/resources/drafter/feature/draftset/claimable-draftset-changes.trig @@ -50,10 +50,10 @@ drafter:inDraftSet draftset:ds-2 . a drafter:Submission ; - drafter:claimRole "publisher" . + drafter:claimPermission "draft:claim" . a drafter:Submission ; - drafter:claimRole "publisher" . + drafter:claimPermission "draft:claim" . } { diff --git a/drafter/test/resources/drafter/feature/draftset/list_test-1-draftset-with-submission.trig b/drafter/test/resources/drafter/feature/draftset/list_test-1-draftset-with-submission.trig index 1626b8b9f..3524cbd60 100644 --- a/drafter/test/resources/drafter/feature/draftset/list_test-1-draftset-with-submission.trig +++ b/drafter/test/resources/drafter/feature/draftset/list_test-1-draftset-with-submission.trig @@ -21,6 +21,6 @@ draftset:4e7f444f-3e34-420e-9126-f9691aeb986b a drafter:DraftSet ; drafter:submittedBy . a drafter:Submission ; - drafter:claimRole "editor" . + drafter:claimPermission "draft:claim" . } diff --git a/drafter/test/resources/drafter/feature/draftset/list_test-2.trig b/drafter/test/resources/drafter/feature/draftset/list_test-2.trig index 8164a8dfd..a322ce62d 100644 --- a/drafter/test/resources/drafter/feature/draftset/list_test-2.trig +++ b/drafter/test/resources/drafter/feature/draftset/list_test-2.trig @@ -47,9 +47,9 @@ draftset:55660038-da9e-42d0-a40f-00d5fa4ef44d a drafter:DraftSet ; drafter:submittedBy . a drafter:Submission ; - drafter:claimRole "publisher" . + drafter:claimPermission "draft:claim" . a drafter:Submission ; - drafter:claimRole "manager" . + drafter:claimPermission "draft:claim:manager" . } diff --git a/drafter/test/resources/drafter/feature/draftset/list_test-unclaimable.trig b/drafter/test/resources/drafter/feature/draftset/list_test-unclaimable.trig index f20c88ba7..75d22d43c 100644 --- a/drafter/test/resources/drafter/feature/draftset/list_test-unclaimable.trig +++ b/drafter/test/resources/drafter/feature/draftset/list_test-unclaimable.trig @@ -19,7 +19,7 @@ drafter:hasOwner ; rdfs:label "owned" . - # This draftset should be claimable by publisher@swirrl.com (or anyone in publisher role) + # This draftset should be claimable by publisher@swirrl.com (or anyone with draft:publish) draftset:claimable a drafter:DraftSet ; dcterms:modified "2017-11-30T14:15:18.348Z"^^xsd:dateTime ; drafter:version version:16bd5568-df31-4d15-931a-681e86c391e2 ; @@ -38,5 +38,5 @@ drafter:hasOwner . a drafter:Submission ; - drafter:claimRole "publisher" . + drafter:claimPermission "draft:publish" . } diff --git a/drafter/test/resources/drafter/feature/draftset/list_test-union-with-live.trig b/drafter/test/resources/drafter/feature/draftset/list_test-union-with-live.trig index f17c2f12d..802f8dc55 100644 --- a/drafter/test/resources/drafter/feature/draftset/list_test-union-with-live.trig +++ b/drafter/test/resources/drafter/feature/draftset/list_test-union-with-live.trig @@ -37,5 +37,5 @@ draftset:7f94456f-8a92-4d40-8691-2c32f89e9741 a drafter:DraftSet ; drafter:submittedBy . a drafter:Submission ; - drafter:claimRole "publisher" . + drafter:claimPermission "draft:claim" . } diff --git a/drafter/test/resources/drafter/feature/endpoint/list_test-with-login.trig b/drafter/test/resources/drafter/feature/endpoint/list_test-with-login.trig index afeffa4e4..130f8dad7 100644 --- a/drafter/test/resources/drafter/feature/endpoint/list_test-with-login.trig +++ b/drafter/test/resources/drafter/feature/endpoint/list_test-with-login.trig @@ -54,9 +54,9 @@ draftset:55660038-da9e-42d0-a40f-00d5fa4ef44d a drafter:DraftSet ; drafter:submittedBy . a drafter:Submission ; - drafter:claimRole "publisher" . + drafter:claimPermission "draft:claim" . a drafter:Submission ; - drafter:claimRole "manager" . + drafter:claimPermission "draft:publish" . } diff --git a/drafter/test/resources/web.edn b/drafter/test/resources/web.edn index 1aa66935e..da3985bed 100644 --- a/drafter/test/resources/web.edn +++ b/drafter/test/resources/web.edn @@ -7,9 +7,10 @@ :drafter.auth.auth0/auth0-auth-method {:auth0-client #ig/ref :swirrl.auth0/client :jwk #ig/ref :drafter.auth.auth0/mock-jwk} - :drafter.middleware/wrap-authenticate {:auth-methods [#ig/ref :drafter.auth.basic/basic-auth-method - #ig/ref :drafter.auth.jws/jws-auth-method - #ig/ref :drafter.auth.auth0/auth0-auth-method]} + :drafter.middleware/wrap-authenticate + {:auth-methods [#ig/ref :drafter.auth.basic/basic-auth-method + #ig/ref :drafter.auth.jws/jws-auth-method + #ig/ref :drafter.auth.auth0/auth0-auth-method]} ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; From 0a6d3b95468552e0cb98b775358497b51663b153 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Mon, 16 May 2022 11:38:37 +0100 Subject: [PATCH 06/17] Revert "we don't need global auth where we're going" This reverts commit ad603516c410cfe5874ba4ceee8fcf270d237a32. --- drafter/doc/drafter.yml | 1 + drafter/resources/drafter-base-config.edn | 6 +++- drafter/src/drafter/handler.clj | 5 +++- drafter/test/drafter/handler_test.clj | 28 ++++++++++++++++++- .../resources/global-auth-test-system.edn | 1 + drafter/test/resources/web.edn | 5 +++- package/manifest/shared.edn | 4 +++ 7 files changed, 46 insertions(+), 4 deletions(-) create mode 100644 drafter/test/resources/global-auth-test-system.edn diff --git a/drafter/doc/drafter.yml b/drafter/doc/drafter.yml index 3ad3002df..0ac134d4c 100644 --- a/drafter/doc/drafter.yml +++ b/drafter/doc/drafter.yml @@ -104,6 +104,7 @@ info: Currently available permissions are: + - public:view - draft:claim - draft:create - draft:delete diff --git a/drafter/resources/drafter-base-config.edn b/drafter/resources/drafter-base-config.edn index 3c03ee52b..733ce5e76 100644 --- a/drafter/resources/drafter-base-config.edn +++ b/drafter/resources/drafter-base-config.edn @@ -185,6 +185,9 @@ :drafter.swagger/swagger-routes {:auth-methods #ig/refset :drafter.auth/auth-method :global-auth? #ig/ref :drafter/global-auth?} + ;; Set to true to require all requests to be authorized + :drafter/global-auth? #boolean #or [#env DRAFTER_GLOBAL_AUTH false] + :drafter.handler/app {:repo #ig/ref :drafter.stasher/repo :live-sparql-query-route #ig/ref :drafter.routes.sparql/live-sparql-query-route @@ -192,7 +195,8 @@ :jobs-status-routes #ig/ref :drafter.routes/jobs-status :drafter/global-writes-lock #ig/ref :drafter/global-writes-lock :wrap-authenticate #ig/ref :drafter.middleware/wrap-authenticate - :swagger-routes #ig/ref :drafter.swagger/swagger-routes} + :swagger-routes #ig/ref :drafter.swagger/swagger-routes + :global-auth? #ig/ref :drafter/global-auth?} ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Web Server diff --git a/drafter/src/drafter/handler.clj b/drafter/src/drafter/handler.clj index 019cd0da0..fc80e00fd 100644 --- a/drafter/src/drafter/handler.clj +++ b/drafter/src/drafter/handler.clj @@ -40,7 +40,8 @@ jobs-status-routes :jobs-status-routes global-writes-lock :drafter/global-writes-lock wrap-authenticate :wrap-authenticate - swagger-routes :swagger-routes}] + swagger-routes :swagger-routes + global-auth? :global-auth?}] (wrap-handler (app-handler ;; add your application routes here (-> [] @@ -76,5 +77,7 @@ ;; :json :json-kw :yaml :yaml-kw :edn :yaml-in-html :formats [:json-kw :edn]))) +(defmethod ig/init-key :drafter/global-auth? [_ v] v) + (defmethod ig/init-key :drafter.handler/app [k opts] (build-handler opts)) diff --git a/drafter/test/drafter/handler_test.clj b/drafter/test/drafter/handler_test.clj index 2793e0cb2..864c4ce8f 100644 --- a/drafter/test/drafter/handler_test.clj +++ b/drafter/test/drafter/handler_test.clj @@ -7,7 +7,7 @@ [drafter.user-test :refer [test-access test-editor test-publisher]]) (:import java.util.UUID)) -(deftest auth-test +(deftest global-auth-test (let [get {:scheme :http :request-method :get} get-public (assoc get @@ -29,6 +29,32 @@ list-draftsets nil 401 ;; Unauthorized, requires :draft:view list-draftsets test-access 403 ;; Forbidden, requires :draft:view list-draftsets test-editor 200 + list-draftsets test-publisher 200)) + (tc/with-system [{handler :drafter.handler/app} + "global-auth-test-system.edn"] + (are [req identity status] + (= status (:status (handler (if identity + (tc/with-identity identity req) + req)))) + whitelisted nil 200 + whitelisted test-norole 200 + whitelisted test-access 200 + whitelisted test-editor 200 + whitelisted test-publisher 200 + get-public nil 401 ;; Unauthorized, requires access + get-public test-norole 403 ;; Forbidden, requires access + get-public test-access 200 + get-public test-editor 200 + get-public test-publisher 200 + options-public nil 200 + options-public test-norole 200 + options-public test-access 200 + options-public test-editor 200 + options-public test-publisher 200 + list-draftsets nil 401 ;; Unauthorized, requires editor + list-draftsets test-norole 403 ;; Forbidden, requires editor + list-draftsets test-access 403 ;; Forbidden, requires editor + list-draftsets test-editor 200 list-draftsets test-publisher 200)))) ;; When muttnik is behind basic auth and drafter is running on the same host, diff --git a/drafter/test/resources/global-auth-test-system.edn b/drafter/test/resources/global-auth-test-system.edn new file mode 100644 index 000000000..88d4ee761 --- /dev/null +++ b/drafter/test/resources/global-auth-test-system.edn @@ -0,0 +1 @@ +#merge [#include "test-system.edn" {:drafter/global-auth? true}] diff --git a/drafter/test/resources/web.edn b/drafter/test/resources/web.edn index da3985bed..5251cb831 100644 --- a/drafter/test/resources/web.edn +++ b/drafter/test/resources/web.edn @@ -147,6 +147,8 @@ :drafter.swagger/swagger-routes {:auth-methods #ig/refset :drafter.auth/auth-method :global-auth? #ig/ref :drafter/global-auth?} + :drafter/global-auth? false + :drafter.handler/app {:repo #ig/ref :drafter.stasher/repo :live-sparql-query-route #ig/ref :drafter.routes.sparql/live-sparql-query-route @@ -154,7 +156,8 @@ :jobs-status-routes #ig/ref :drafter.routes/jobs-status :drafter/global-writes-lock #ig/ref :drafter/global-writes-lock :wrap-authenticate #ig/ref :drafter.middleware/wrap-authenticate - :swagger-routes #ig/ref :drafter.swagger/swagger-routes} + :swagger-routes #ig/ref :drafter.swagger/swagger-routes + :global-auth? #ig/ref :drafter/global-auth?} :drafter.server/http {:handler #ig/ref :drafter.handler/app :open-browser? false diff --git a/package/manifest/shared.edn b/package/manifest/shared.edn index 4c521dc6b..24c653e9b 100644 --- a/package/manifest/shared.edn +++ b/package/manifest/shared.edn @@ -85,6 +85,10 @@ :env-var DRAFTER_LOGS_DIR :optional true} + :drafter/global-auth? {:doc "Set to true to enable global auth" + :env-var DRAFTER_GLOBAL_AUTH + :optional true} + :datadog/statsd-address {:doc "Address of the statsd service" :env-var DATADOG_STATSD_ADDRESS :default "localhost:8125" From 387c3dab15e55be70cd4f7448e74eb2a11df6986 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Mon, 16 May 2022 12:10:57 +0100 Subject: [PATCH 07/17] :public:view permission for global auth --- drafter/src/drafter/handler.clj | 65 ++++++++++++++------------- drafter/src/drafter/user.clj | 34 +++++++------- drafter/src/drafter/user/spec.clj | 2 +- drafter/test/drafter/handler_test.clj | 18 +++++--- drafter/test/drafter/user_test.clj | 1 + 5 files changed, 62 insertions(+), 58 deletions(-) diff --git a/drafter/src/drafter/handler.clj b/drafter/src/drafter/handler.clj index fc80e00fd..d3fe0bac6 100644 --- a/drafter/src/drafter/handler.clj +++ b/drafter/src/drafter/handler.clj @@ -42,40 +42,41 @@ wrap-authenticate :wrap-authenticate swagger-routes :swagger-routes global-auth? :global-auth?}] - (wrap-handler (app-handler - ;; add your application routes here - (-> [] - (add-route swagger-routes) - (add-route draftset-api-routes) - (add-route live-sparql-route) - (add-route (context "/v1/status" [] (status-routes global-writes-lock))) - (add-route jobs-status-routes) - (add-routes (denv/env-specific-routes backend)) - (add-route app-routes)) + (wrap-handler + (app-handler + ;; add your application routes here + (-> [] + (add-route swagger-routes) + (add-route draftset-api-routes) + (add-route live-sparql-route) + (add-route (context "/v1/status" [] (status-routes global-writes-lock))) + (add-route jobs-status-routes) + (add-routes (denv/env-specific-routes backend)) + (add-route app-routes)) - :ring-defaults (-> (assoc-in api-defaults [:params :multipart] true) - ;; Enables wrap-forwarded-scheme middleware. Essential in prod - ;; env when scheme needs to be passed through from load balancer - (assoc :proxy true)) - ;; add custom middleware here - :middleware - (let [middleware [wrap-verbs - wrap-encode-errors - middleware/wrap-total-requests-counter - middleware/wrap-request-timer - #(log-request % {:query ""})]] - (if global-auth? - (cons #(middleware/wrap-authorize - wrap-authenticate :access %) - middleware) - middleware)) + :ring-defaults (-> (assoc-in api-defaults [:params :multipart] true) + ;; Enables wrap-forwarded-scheme middleware. Essential in prod + ;; env when scheme needs to be passed through from load balancer + (assoc :proxy true)) + ;; add custom middleware here + :middleware + (let [middleware [wrap-verbs + wrap-encode-errors + middleware/wrap-total-requests-counter + middleware/wrap-request-timer + #(log-request % {:query ""})]] + (if global-auth? + (cons #(middleware/wrap-authorize + wrap-authenticate :public:view %) + middleware) + middleware)) - ;; add access rules here - :access-rules [] - ;; serialize/deserialize the following data formats - ;; available formats: - ;; :json :json-kw :yaml :yaml-kw :edn :yaml-in-html - :formats [:json-kw :edn]))) + ;; add access rules here + :access-rules [] + ;; serialize/deserialize the following data formats + ;; available formats: + ;; :json :json-kw :yaml :yaml-kw :edn :yaml-in-html + :formats [:json-kw :edn]))) (defmethod ig/init-key :drafter/global-auth? [_ v] v) diff --git a/drafter/src/drafter/user.clj b/drafter/src/drafter/user.clj index 360302502..216a6aad1 100644 --- a/drafter/src/drafter/user.clj +++ b/drafter/src/drafter/user.clj @@ -17,24 +17,20 @@ (defmethod ig/init-key :drafter.user/repo [k opts] (throw (ex-info "Config error. Please use a concrete implementation of the user repo instead." {}))) -(def role->permissions - "This map is only intended to be used for compatibility with mongo user +(defn role->permissions + "This function is only intended to be used for compatibility with mongo user storage, or for convenience in tests." - {:access #{} - :editor #{:draft:claim :draft:create :draft:delete :draft:edit - :draft:submit :draft:share :draft:view :job:view :user:view} - :publisher #{:draft:claim :draft:create :draft:delete :draft:edit - :draft:submit :draft:share :draft:view :job:view :user:view - :draft:publish} - :manager #{:draft:claim :draft:create :draft:delete :draft:edit - :draft:submit :draft:share :draft:view :job:view :user:view - :draft:publish - ;; :draft:claim:manager is used in tests to demonstrate scoped - ;; claim permissions. - :draft:claim:manager} - :system #{:draft:claim :draft:create :draft:delete :draft:edit - :draft:submit :draft:share :draft:view :job:view :user:view - :draft:publish}}) + [role] + (case role + :norole #{} + :access #{:public:view} + :editor (conj (role->permissions :access) + :draft:claim :draft:create :draft:delete :draft:edit + :draft:submit :draft:share :draft:view :job:view :user:view) + :publisher (conj (role->permissions :editor) :draft:publish) + ;; :manager is used in tests to demonstrate scoped claim permissions. + :manager (conj (role->permissions :publisher) :draft:claim:manager) + :system (recur :manager))) (defn roles-including "Returns the set of roles which include the given role" @@ -55,7 +51,7 @@ :manager "Full access to drafts" :system "Full access to the entire system"} role)) -(def roles (keys role->permissions)) +(def roles #{:access :editor :publisher :manager :system}) (def username :email) @@ -81,7 +77,7 @@ (.getSchemeSpecificPart user-uri)) (defn is-known-role? [r] - (contains? role->permissions r)) + (contains? roles r)) (defn- get-valid-email [email] (if-let [valid (util/validate-email-address email)] diff --git a/drafter/src/drafter/user/spec.clj b/drafter/src/drafter/user/spec.clj index 99aa3cbb9..e99c76897 100644 --- a/drafter/src/drafter/user/spec.clj +++ b/drafter/src/drafter/user/spec.clj @@ -8,7 +8,7 @@ [clojure.spec.test.alpha :as st]) (:import [drafter.user User])) -(s/def ::user/role (set (keys user/role->permissions))) +(s/def ::user/role user/roles) (s/def ::user/permissions (s/coll-of keyword? :kind set?)) (s/def ::user/email :drafter/EmailAddress) (s/def ::user/password-digest string?) diff --git a/drafter/test/drafter/handler_test.clj b/drafter/test/drafter/handler_test.clj index 864c4ce8f..378a66e6b 100644 --- a/drafter/test/drafter/handler_test.clj +++ b/drafter/test/drafter/handler_test.clj @@ -4,17 +4,23 @@ [drafter.feature.endpoint.public :as public] [drafter.routes.sparql-test :refer [live-query]] [drafter.test-common :as tc] - [drafter.user-test :refer [test-access test-editor test-publisher]]) + [drafter.user-test :refer [test-norole test-access test-editor test-publisher]]) (:import java.util.UUID)) (deftest global-auth-test (let [get {:scheme :http :request-method :get} + whitelisted (assoc get :uri "/swagger/swagger.json") get-public (assoc get :uri "/v1/sparql/live" :headers {"accept" "text/plain"} :query-string "query=select%20%2A%20where%20%7B%3Fs%20%3Fp%20%3Fo%7D") + options-public (assoc get-public + :request-method :options + :headers {"origin" "http://swirrl.com" + "access-control-request-method" "post" + "access-control-request-headers" "accept"}) list-draftsets (assoc get :uri "/v1/draftsets")] (tc/with-system [{handler :drafter.handler/app} "test-system.edn"] @@ -41,8 +47,8 @@ whitelisted test-access 200 whitelisted test-editor 200 whitelisted test-publisher 200 - get-public nil 401 ;; Unauthorized, requires access - get-public test-norole 403 ;; Forbidden, requires access + get-public nil 401 ;; Unauthorized, requires :public:view + get-public test-norole 403 ;; Forbidden, requires :public:view get-public test-access 200 get-public test-editor 200 get-public test-publisher 200 @@ -51,9 +57,9 @@ options-public test-access 200 options-public test-editor 200 options-public test-publisher 200 - list-draftsets nil 401 ;; Unauthorized, requires editor - list-draftsets test-norole 403 ;; Forbidden, requires editor - list-draftsets test-access 403 ;; Forbidden, requires editor + list-draftsets nil 401 ;; Unauthorized, requires :draft:view + list-draftsets test-norole 403 ;; Forbidden, requires :draft:view + list-draftsets test-access 403 ;; Forbidden, requires :draft:view list-draftsets test-editor 200 list-draftsets test-publisher 200)))) diff --git a/drafter/test/drafter/user_test.clj b/drafter/test/drafter/user_test.clj index 22c1d2f0b..d50ebc955 100644 --- a/drafter/test/drafter/user_test.clj +++ b/drafter/test/drafter/user_test.clj @@ -9,6 +9,7 @@ (use-fixtures :each tc/with-spec-instrumentation) (def test-password "password") +(def test-norole (create-user "norole@swirrl.com" :norole (get-digest test-password))) (def test-access (create-user "access@swirrl.com" :access (get-digest test-password))) (def test-editor (create-user "editor@swirrl.com" :editor (get-digest test-password))) (def test-publisher (create-user "publisher@swirrl.com" :publisher (get-digest test-password))) From 44e73f696145f19a2864e744d465fabf814c3e2f Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Thu, 26 May 2022 10:27:42 +0100 Subject: [PATCH 08/17] reinstate role parameter for draft submission (deprecated) --- .../src/drafter/feature/draftset/submit.clj | 29 ++++++++++++------- .../drafter/feature/draftset/claim_test.clj | 15 ++++++++++ .../drafter/feature/draftset/submit_test.clj | 14 +++++++++ .../drafter/feature/draftset/test_helper.clj | 14 +++++++++ 4 files changed, 61 insertions(+), 11 deletions(-) diff --git a/drafter/src/drafter/feature/draftset/submit.clj b/drafter/src/drafter/feature/draftset/submit.clj index adbea7ed9..3e580802b 100644 --- a/drafter/src/drafter/feature/draftset/submit.clj +++ b/drafter/src/drafter/feature/draftset/submit.clj @@ -31,23 +31,30 @@ (keyword permission)) #(feat-common/draftset-sync-write-response % backend draftset-id))) +;; Maps a role to a permission that that role has, but less privileged roles +;; don't have. +(def role->canonical-permission + {"editor" "draft:edit" "publisher" "draft:publish"}) + (defn handler [{:keys [:drafter/manager :drafter.user/repo wrap-as-draftset-owner]}] (wrap-as-draftset-owner :draft:submit - (fn [{{:keys [user permission draftset-id]} :params owner :identity}] - (cond - (and (some? user) (some? permission)) - (unprocessable-entity-response - "Only one of user and permission parameters permitted") + (fn [{{:keys [user permission role draftset-id]} :params owner :identity}] + ;; The role parameter is deprecated + (let [permission (or permission (role->canonical-permission role))] + (cond + (and (some? user) (some? permission)) + (unprocessable-entity-response + "Only one of user and permission parameters permitted") - (some? user) - (handle-user manager repo user draftset-id owner) + (some? user) + (handle-user manager repo user draftset-id owner) - (some? permission) - (handle-permission manager permission draftset-id owner) + (some? permission) + (handle-permission manager permission draftset-id owner) - :else - (unprocessable-entity-response "user or permission parameter required"))))) + :else + (unprocessable-entity-response "user or permission parameter required")))))) (defmethod ig/pre-init-spec :drafter.feature.draftset.submit/handler [_] (s/keys :req [:drafter/manager ::user/repo] diff --git a/drafter/test/drafter/feature/draftset/claim_test.clj b/drafter/test/drafter/feature/draftset/claim_test.clj index 4d4e05cc3..8ad6c5cfe 100644 --- a/drafter/test/drafter/feature/draftset/claim_test.clj +++ b/drafter/test/drafter/feature/draftset/claim_test.clj @@ -50,6 +50,21 @@ (claim-draftset-through-api handler draftset-location test-publisher)] (is (= (user/username test-publisher) current-owner))))) +;; The role parameter is deprecated +(tc/deftest-system-with-keys claim-draftset-submitted-to-role + keys-for-test + [system "test-system.edn"] + (let [handler (get system [:drafter/routes :draftset/api]) + {{draftset-location "Location"} :headers} + (handler (ct/create-draftset-request test-editor))] + (help/submit-draftset-to-role-through-api handler + test-editor + draftset-location + :editor) + (let [{:keys [current-owner] :as ds-info} + (claim-draftset-through-api handler draftset-location test-publisher)] + (is (= (user/username test-publisher) current-owner))))) + (tc/deftest-system-with-keys claim-draftset-submitted-to-user keys-for-test [system "test-system.edn"] diff --git a/drafter/test/drafter/feature/draftset/submit_test.clj b/drafter/test/drafter/feature/draftset/submit_test.clj index 40e60130e..10e8f5352 100644 --- a/drafter/test/drafter/feature/draftset/submit_test.clj +++ b/drafter/test/drafter/feature/draftset/submit_test.clj @@ -99,3 +99,17 @@ (tc/assert-spec ::ds/Draftset ds-info) (is (= false (contains? ds-info :current-owner))))) + +;; The role parameter is deprecated +(tc/deftest-system-with-keys submit-draftset-to-role + keys-for-test + [{handler [:drafter/routes :draftset/api]} "test-system.edn"] + (let [draftset-location (help/create-draftset-through-api handler test-editor) + submit-request (help/create-submit-to-role-request test-editor + draftset-location + :publisher) + {ds-info :body :as submit-response} (handler submit-request)] + (tc/assert-is-ok-response submit-response) + (tc/assert-spec ::ds/Draftset ds-info) + + (is (= false (contains? ds-info :current-owner))))) diff --git a/drafter/test/drafter/feature/draftset/test_helper.clj b/drafter/test/drafter/feature/draftset/test_helper.clj index c2a71a697..6a6bf0233 100644 --- a/drafter/test/drafter/feature/draftset/test_helper.clj +++ b/drafter/test/drafter/feature/draftset/test_helper.clj @@ -36,6 +36,12 @@ :request-method :post :params {:permission (name permission)}})) +;; The role parameter is deprecated +(defn create-submit-to-role-request [user draftset-location role] + (tc/with-identity user {:uri (str draftset-location "/submit-to") + :request-method :post + :params {:role (name role)}})) + (defn create-draftset-through-api ([handler] (create-draftset-through-api handler test-editor)) ([handler user] (create-draftset-through-api handler user nil)) @@ -66,6 +72,14 @@ permission))] (tc/assert-is-ok-response response))) +;; The role parameter is deprecated +(defn submit-draftset-to-role-through-api + [handler user draftset-location role] + (let [response (handler (create-submit-to-role-request user + draftset-location + role))] + (tc/assert-is-ok-response response))) + (defn delete-draftset-graph-request [user draftset-location graph-to-delete] (tc/with-identity user {:uri (str draftset-location "/graph") :request-method :delete :params {:graph (str graph-to-delete)}})) From 2724863ea791d4a995a94c1e4997bb678591b98f Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Thu, 26 May 2022 10:37:10 +0100 Subject: [PATCH 09/17] submit-to-role client method (deprecated) --- drafter-client/src/drafter_client/client.clj | 5 +++++ drafter-client/src/drafter_client/client/impl.clj | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/drafter-client/src/drafter_client/client.clj b/drafter-client/src/drafter_client/client.clj index 291f15031..aabcbc36f 100644 --- a/drafter-client/src/drafter_client/client.clj +++ b/drafter-client/src/drafter_client/client.clj @@ -150,6 +150,11 @@ (i/request client i/submit-draftset-to access-token id :permission (name permission))) +;; The role parameter is deprecated +(defn submit-to-role [client access-token id role] + (i/request client i/submit-draftset-to access-token id + :role (name role))) + (defn claim [client access-token id] (i/request client i/claim-draftset access-token id)) diff --git a/drafter-client/src/drafter_client/client/impl.clj b/drafter-client/src/drafter_client/client/impl.clj index 04cda3d70..7fc97a5a2 100644 --- a/drafter-client/src/drafter_client/client/impl.clj +++ b/drafter-client/src/drafter_client/client/impl.clj @@ -359,9 +359,9 @@ (martian/response-for client :status-writes-locked {})) (defn submit-draftset-to - "Submit a Draftset to a user or role" + "Submit a Draftset to a user or permission" #:drafter-client.client.impl{:generated true} - [client id & {:keys [role user] :as opts}] + [client id & {:keys [user permission] :as opts}] (martian/response-for client :submit-draftset-to From e6b09266db754f9b29d5e42b60c48eb47081b27a Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Mon, 30 May 2022 12:11:07 +0100 Subject: [PATCH 10/17] RBAC section in readme --- drafter/README.md | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/drafter/README.md b/drafter/README.md index e04c9713e..daddd4a2c 100644 --- a/drafter/README.md +++ b/drafter/README.md @@ -73,3 +73,49 @@ tagged with git tag, branch name, and commit sha. Consumers may want to mount volumes at `/app/config` to provide custom configuration, and at `/app/stasher-cache` to persist the cache. + +## RBAC + +When deploying drafter with auth0 auth, users are expected to have been +configured with some subset of the following permissions, (depending on what +they should be allowed to do), and for those permissions to be passed in the +`permissions` claim of the auth token. + +``` +drafter:draft:claim +drafter:draft:create +drafter:draft:delete +drafter:draft:edit +drafter:draft:publish +drafter:draft:share +drafter:draft:submit +drafter:draft:view +drafter:job:view +drafter:public:view +drafter:user:view +``` + +How exactly this is done isn't important, and these permissions can be split +between roles in a way that makes sense for the specific deployment, but for +example you might: + +1. create a new API called PMD-RBAC, with audience `https://publishmydata.com` +2. in RBAC Settings, "Enable RBAC" and "Add Permissions in the Access Token" +3. add all of the above permissions under "Permissions" +4. authorize the drafter and muttnik "Machine to Machine Applications" +5. under "User Management" > "Roles" create roles (see below) +6. assign roles to the relevant users + +### Example role mapping: + +- PMD-RBAC:User has drafter:public:view +- PMD-RBAC:Reviewer has drafter:draft:view drafter:job:view drafter:public:view + drafter:user:view +- PMD-RBAC:Editor has drafter:draft:claim drafter:draft:create + drafter:draft:delete drafter:draft:edit drafter:draft:share + drafter:draft:submit drafter:draft:view drafter:job:view drafter:public:view + drafter:user:view +- PMD-RBAC:Publisher has drafter:draft:claim drafter:draft:create + drafter:draft:delete drafter:draft:edit drafter:draft:publish + drafter:draft:share drafter:draft:submit drafter:draft:view drafter:job:view + drafter:public:view drafter:user:view From b60cc48d25cf9b9f2fad9977feed0b79c79b2ef8 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Tue, 14 Jun 2022 15:15:26 +0100 Subject: [PATCH 11/17] keep role in swagger spec but mark as deprecated --- drafter/doc/drafter.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drafter/doc/drafter.yml b/drafter/doc/drafter.yml index 0ac134d4c..34e4403ff 100644 --- a/drafter/doc/drafter.yml +++ b/drafter/doc/drafter.yml @@ -497,6 +497,7 @@ paths: parameters: - $ref: '#/parameters/id' - $ref: '#/parameters/permission' + - $ref: '#/parameters/role' - $ref: '#/parameters/submit-user' # - $ref: '#/parameters/message' # - $ref: '#/parameters/note' @@ -851,6 +852,13 @@ parameters: in: query required: false type: string + role: + name: role + deprecated: true + description: Deprecated, use permission instead + in: query + required: false + type: string submit-user: name: user description: The username of the user to submit the draftset to. From e1f77315d72efc326423cfcca4de242937f19ea3 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Wed, 15 Jun 2022 11:22:44 +0100 Subject: [PATCH 12/17] keep our existing audience --- drafter/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drafter/README.md b/drafter/README.md index daddd4a2c..1a7844bad 100644 --- a/drafter/README.md +++ b/drafter/README.md @@ -99,7 +99,7 @@ How exactly this is done isn't important, and these permissions can be split between roles in a way that makes sense for the specific deployment, but for example you might: -1. create a new API called PMD-RBAC, with audience `https://publishmydata.com` +1. create a new API called PMD, with audience `https://pmd` 2. in RBAC Settings, "Enable RBAC" and "Add Permissions in the Access Token" 3. add all of the above permissions under "Permissions" 4. authorize the drafter and muttnik "Machine to Machine Applications" From b3628b7a09573dd69aeffa61b2f0aea2fddffe74 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Mon, 18 Jul 2022 17:38:53 +0100 Subject: [PATCH 13/17] post rebase tweaks --- drafter/src/drafter/auth/auth0.clj | 15 ++++------ .../drafter/auth/auth0_swagger_description.md | 4 +-- drafter/src/drafter/user.clj | 30 ++++++++----------- drafter/test/drafter/auth/auth0_test.clj | 18 ++--------- drafter/test/drafter/auth/jws_test.clj | 3 +- drafter/test/drafter/middleware_test.clj | 12 ++++---- drafter/test/drafter/user_test.clj | 8 ----- 7 files changed, 31 insertions(+), 59 deletions(-) diff --git a/drafter/src/drafter/auth/auth0.clj b/drafter/src/drafter/auth/auth0.clj index ba2b02dc0..255cb3407 100644 --- a/drafter/src/drafter/auth/auth0.clj +++ b/drafter/src/drafter/auth/auth0.clj @@ -12,11 +12,6 @@ (or (get payload (keyword "https://pmd/user/email")) (get payload :sub))) -(defn- role->scope - "Converts a drafter role into the corresponding auth0 scope" - [role] - (str "drafter:" (name role))) - (defn parse-request-token "Parses a bearer token from an incoming request if one exists." [auth0-client jwk request] @@ -48,6 +43,9 @@ ::jwt/token-invalid (auth/authentication-failed) (auth/authentication-failed))) +(defn- update-keys [m f] + (into {} (map (fn [[k v]] [(f k) v]) m))) + (defn auth0-auth-method "Returns an implementation of the AuthenticationMethod protocol which uses auth0. Tokens should be specified on incoming requests within an 'Authorization: Bearer ' header. The validity of @@ -71,11 +69,10 @@ :flow "application" :description "OAuth authentication via Auth0" :tokenUrl (str (:endpoint auth0-client) "/oauth/token") - :scopes (into {} (map (fn [permission] [(str "drafter:" permission) (user/get-role-summary role)]) user/roles))}) + :scopes (update-keys user/permission-summary #(str "drafter" %))}) - (get-operation-swagger-security-requirement [_this {:keys [role] :as operation}] - (let [satisfying-roles (user/roles-including role)] - (mapv role->scope satisfying-roles))) + (get-operation-swagger-security-requirement [_this {:keys [permission] :as operation}] + [(str "drafter:" permission)]) (get-swagger-ui-config [_this] {:auth0Audience (:aud auth0-client)}))) diff --git a/drafter/src/drafter/auth/auth0_swagger_description.md b/drafter/src/drafter/auth/auth0_swagger_description.md index 3e86b39c7..4d17b7239 100644 --- a/drafter/src/drafter/auth/auth0_swagger_description.md +++ b/drafter/src/drafter/auth/auth0_swagger_description.md @@ -1,6 +1,6 @@ OAuth2 bearer token authentication via Auth0. API users can be configured in the Auth0 management console -with a drafter username and collection of scopes mapped to drafter roles. After obtaining a bearer token from +with a drafter username and collection of scopes mapped to drafter permissions. After obtaining a bearer token from the Auth0 tenant token endpoint, these can be provided on a request as an `Authorization` header with the format `Bearer `. When authenticating via the UI, the application `client_id` and `client_secret` should be specified along with the -collection of scopes to request for the token. \ No newline at end of file +collection of scopes to request for the token. diff --git a/drafter/src/drafter/user.clj b/drafter/src/drafter/user.clj index 216a6aad1..2d93b3192 100644 --- a/drafter/src/drafter/user.clj +++ b/drafter/src/drafter/user.clj @@ -32,24 +32,18 @@ :manager (conj (role->permissions :publisher) :draft:claim:manager) :system (recur :manager))) -(defn roles-including - "Returns the set of roles which include the given role" - [role] - (let [required-level (role->permission-level role)] - (->> role->permission-level - (keep (fn [[candidate level]] - (if (>= level required-level) - candidate))) - (set)))) - -(defn get-role-summary - "Returns a brief summary of the given role" - [role] - ({:access "Read-only access" - :editor "Create and edit access to drafts" - :publisher "Create, edit and publish access to drafts" - :manager "Full access to drafts" - :system "Full access to the entire system"} role)) +(def permission-summary + {:draft:claim "Claim submitted drafts" + :draft:create "Create drafts" + :draft:delete "Delete drafts" + :draft:edit "Edit drafts" + :draft:publish "Publish drafts" + :draft:share "Share drafts to be viewed" + :draft:submit "Submit drafts to be claimed" + :draft:view "View shared drafts" + :job:view "View the status of jobs" + :public:view "View the public endpoint (if global auth is on)" + :user:view "View users"}) (def roles #{:access :editor :publisher :manager :system}) diff --git a/drafter/test/drafter/auth/auth0_test.clj b/drafter/test/drafter/auth/auth0_test.clj index 29f95f7d5..4ff097338 100644 --- a/drafter/test/drafter/auth/auth0_test.clj +++ b/drafter/test/drafter/auth/auth0_test.clj @@ -7,19 +7,6 @@ [drafter.user :as user]) (:import clojure.lang.ExceptionInfo)) -(t/deftest read-role-test - (t/testing "Valid role" - (t/is (= :publisher (sut/read-role "drafter:publisher")))) - - (t/testing "Non-drafter role" - (t/is (nil? (sut/read-role "muttnik:editor")))) - - (t/testing "Invalid drafter role" - (t/is (nil? (sut/read-role "drafter:invalid")))) - - (t/testing "No prefix" - (t/is (nil? (sut/read-role "manager"))))) - (defn- get-auth-method [system] (let [jwk (:drafter.auth.auth0/mock-jwk system) auth0-client (:swirrl.auth0/client system)] @@ -50,10 +37,11 @@ [system "test-system.edn"] (let [auth-method (get-auth-method system) username "test@example.com" - token (tc/user-access-token username "drafter:editor") + permissions #{:cat:pet :missiles:launch} + token (tc/user-access-token username "drafter:editor" permissions) request (add-auth-header {:uri "/test" :request-method :get} token) user (auth-common/expect-authentication auth-method request) - expected-user (user/create-authenticated-user username :editor)] + expected-user (user/create-authenticated-user username permissions)] (t/is (= expected-user user))))) (t/deftest should-reject-invalid-token diff --git a/drafter/test/drafter/auth/jws_test.clj b/drafter/test/drafter/auth/jws_test.clj index 7932a0eb5..fa554a17c 100644 --- a/drafter/test/drafter/auth/jws_test.clj +++ b/drafter/test/drafter/auth/jws_test.clj @@ -34,7 +34,8 @@ auth-method (sut/jws-auth-method signing-key) request (add-user {:uri "/test" :request-method :get} user signing-key) identity (auth-common/expect-authentication auth-method request)] - (t/is (= user identity)))) + (t/is (= (:email user) (:email identity))) + (t/is (contains? (:permissions identity) :draft:publish)))) (t/deftest should-reject-token-with-invalid-issuer (let [doc {:user "test@example.com" diff --git a/drafter/test/drafter/middleware_test.clj b/drafter/test/drafter/middleware_test.clj index 489f6dc18..886b5a340 100644 --- a/drafter/test/drafter/middleware_test.clj +++ b/drafter/test/drafter/middleware_test.clj @@ -209,14 +209,14 @@ (t/is (nil? (sut/authenticate-request auth-methods request))))) (t/testing "Authentication succeeds" - (let [user (user/create-authenticated-user "test@example.com" :editor) + (let [user (user/create-authenticated-user "test@example.com" #{:draft:view}) auth-methods [(succeeds-with-auth-method user)] request {:uri "/test" :request-method :get}] (t/is (= user (sut/authenticate-request auth-methods request))))) (t/testing "Authenticates with first matching handler" - (let [user1 (user/create-authenticated-user "test1@example.com" :editor) - user2 (user/create-authenticated-user "test2@example.com" :publisher) + (let [user1 (user/create-authenticated-user "test1@example.com" #{:draft:view}) + user2 (user/create-authenticated-user "test2@example.com" #{:draft:view}) auth-methods [(succeeds-with-auth-method user1) (succeeds-with-auth-method user2)] request {:uri "/test" :request-method :get}] @@ -245,13 +245,13 @@ (t/testing "Allows requests with existing identity" (let [auth-methods [always-fails-auth-method] handler (sut/wrap-authenticate identity auth-methods) - user (user/create-authenticated-user "test@example.com" :publisher) + user (user/create-authenticated-user "test@example.com" #{:draft:view}) request {:uri "/test" :request-method :get :identity user} response (handler request)] (t/is (= request response)))) (t/testing "Authenticates user" - (let [user (user/create-authenticated-user "test@example.com" :editor) + (let [user (user/create-authenticated-user "test@example.com" #{:draft:view}) auth-methods [(succeeds-with-auth-method user)] handler (sut/wrap-authenticate identity auth-methods) request {:uri "/test" :request-method :get} @@ -278,4 +278,4 @@ handler (sut/wrap-authenticate identity auth-methods) request {:uri "/test" :request-method :get} response (handler request)] - (tc/assert-is-forbidden-response response)))) \ No newline at end of file + (tc/assert-is-forbidden-response response)))) diff --git a/drafter/test/drafter/user_test.clj b/drafter/test/drafter/user_test.clj index d50ebc955..f58ef8b53 100644 --- a/drafter/test/drafter/user_test.clj +++ b/drafter/test/drafter/user_test.clj @@ -34,14 +34,6 @@ test-manager :draft:publish true test-manager :draft:publish true)) -(t/deftest roles-including-test - (t/are [role expected] (= expected (roles-including role)) - :access #{:access :editor :publisher :manager :system} - :editor #{:editor :publisher :manager :system} - :publisher #{:publisher :manager :system} - :manager #{:manager :system} - :system #{:system})) - (deftest password-valid?-test (let [password (str (UUID/randomUUID)) password-digest (get-digest password) From d4707514fcc173405bcd6c4db6e649c91b96c1e8 Mon Sep 17 00:00:00 2001 From: Rick Moynihan Date: Wed, 27 Jul 2022 16:31:18 +0100 Subject: [PATCH 14/17] Fix small typo in swagger docs --- drafter/doc/drafter.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drafter/doc/drafter.yml b/drafter/doc/drafter.yml index 34e4403ff..34f6f7779 100644 --- a/drafter/doc/drafter.yml +++ b/drafter/doc/drafter.yml @@ -50,7 +50,7 @@ info: - `/data` which can be used to `POST` (append), `DELETE` or `GET` quads from the draftset. - - `/submit-to` to relinquish ownership of the drafset and either assign + - `/submit-to` to relinquish ownership of the draftset and either assign ownership to another user, or make it available to users with a given permission. The user which takes ownership of the draftset may depending on their permissions then choose to make further ammendments, From d37656657aed5448b527d12016152838f9b96898 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Fri, 29 Jul 2022 15:53:26 +0100 Subject: [PATCH 15/17] migrations --- .../rbac-0-check-claim-roles.sparql | 14 +++++++++++++ .../rbac-1-backfill-claim-permissions.sparql | 21 +++++++++++++++++++ .../rbac-2-delete-claim-roles.sparql | 14 +++++++++++++ 3 files changed, 49 insertions(+) create mode 100644 drafter/migrations/rbac-0-check-claim-roles.sparql create mode 100644 drafter/migrations/rbac-1-backfill-claim-permissions.sparql create mode 100644 drafter/migrations/rbac-2-delete-claim-roles.sparql diff --git a/drafter/migrations/rbac-0-check-claim-roles.sparql b/drafter/migrations/rbac-0-check-claim-roles.sparql new file mode 100644 index 000000000..18b01574c --- /dev/null +++ b/drafter/migrations/rbac-0-check-claim-roles.sparql @@ -0,0 +1,14 @@ +# Query to check claim roles to ensure all cases are covered in +# rbac-1-backfill-claim-permissions.sparql +# +# Run me with +# +# stardog query rbac-0-check-claim-roles.sparql + +PREFIX drafter: + +SELECT DISTINCT ?role WHERE { + GRAPH { + ?submission drafter:claimRole ?role . + } +} diff --git a/drafter/migrations/rbac-1-backfill-claim-permissions.sparql b/drafter/migrations/rbac-1-backfill-claim-permissions.sparql new file mode 100644 index 000000000..bba5c7462 --- /dev/null +++ b/drafter/migrations/rbac-1-backfill-claim-permissions.sparql @@ -0,0 +1,21 @@ +# Migration to backfill claim permissions +# +# Run me with +# +# stardog query rbac-1-backfill-claim-permissions.sparql +# +# Assumes that drafter:claimRole is always one of "editor" or "publisher", +# check that this is the case with rbac-0-check-claim-roles.sparql first. + +PREFIX drafter: + +INSERT { + GRAPH { + ?submission drafter:claimPermission ?permission . + } +} WHERE { + GRAPH { + ?submission drafter:claimRole ?role . + BIND(IF(?role = "editor", "draft:edit", "draft:publish") as ?permission) + } +} diff --git a/drafter/migrations/rbac-2-delete-claim-roles.sparql b/drafter/migrations/rbac-2-delete-claim-roles.sparql new file mode 100644 index 000000000..09e025cad --- /dev/null +++ b/drafter/migrations/rbac-2-delete-claim-roles.sparql @@ -0,0 +1,14 @@ +# Migration to delete claim roles after migrating to claim permissions +# +# Run me with +# +# stardog query rbac-2-delete-claim-roles.sparql + +PREFIX drafter: + +DELETE WHERE { + GRAPH { + ?submission drafter:claimRole ?role . + } +} + From 724a2ac7d6a5125ff99f98193a9d874a695f9e7a Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Mon, 1 Aug 2022 11:17:18 +0100 Subject: [PATCH 16/17] rm duplicates from user_test --- drafter/test/drafter/user_test.clj | 3 --- 1 file changed, 3 deletions(-) diff --git a/drafter/test/drafter/user_test.clj b/drafter/test/drafter/user_test.clj index f58ef8b53..c514fa53c 100644 --- a/drafter/test/drafter/user_test.clj +++ b/drafter/test/drafter/user_test.clj @@ -24,14 +24,11 @@ (are [user permission has?] (= has? (has-permission? user permission)) test-editor :draft:edit true test-editor :draft:publish false - test-editor :draft:publish false test-publisher :draft:edit true test-publisher :draft:publish true - test-publisher :draft:publish true test-manager :draft:edit true - test-manager :draft:publish true test-manager :draft:publish true)) (deftest password-valid?-test From 1302e9fe03225ae60da735e826759f4b0543ac74 Mon Sep 17 00:00:00 2001 From: Callum Oakley Date: Tue, 2 Aug 2022 14:01:47 +0100 Subject: [PATCH 17/17] keep drafter: prefix on permissions to avoid confusion --- .../test/drafter_client/client_test.clj | 2 +- drafter/doc/drafter.yml | 22 +++++----- .../rbac-1-backfill-claim-permissions.sparql | 2 +- drafter/src/drafter/async/jobs.clj | 2 +- drafter/src/drafter/auth/auth0.clj | 6 +-- .../src/drafter/feature/draftset/changes.clj | 2 +- .../src/drafter/feature/draftset/claim.clj | 2 +- .../src/drafter/feature/draftset/create.clj | 2 +- .../src/drafter/feature/draftset/delete.clj | 2 +- drafter/src/drafter/feature/draftset/list.clj | 2 +- .../src/drafter/feature/draftset/options.clj | 2 +- .../src/drafter/feature/draftset/publish.clj | 2 +- .../src/drafter/feature/draftset/query.clj | 2 +- .../drafter/feature/draftset/set_metadata.clj | 2 +- drafter/src/drafter/feature/draftset/show.clj | 2 +- .../src/drafter/feature/draftset/submit.clj | 4 +- .../src/drafter/feature/draftset/update.clj | 2 +- .../drafter/feature/draftset_data/append.clj | 2 +- .../feature/draftset_data/append_by_graph.clj | 2 +- .../drafter/feature/draftset_data/delete.clj | 2 +- .../feature/draftset_data/delete_by_graph.clj | 2 +- .../drafter/feature/draftset_data/show.clj | 2 +- drafter/src/drafter/feature/users/list.clj | 2 +- drafter/src/drafter/handler.clj | 2 +- drafter/src/drafter/swagger.clj | 42 +++++++++---------- drafter/src/drafter/user.clj | 36 ++++++++-------- drafter/test/drafter/auth/auth0_test.clj | 2 +- drafter/test/drafter/auth/jws_test.clj | 2 +- .../backend/draftset/operations_test.clj | 24 +++++------ .../drafter/feature/draftset/claim_test.clj | 8 ++-- .../drafter/feature/draftset/show_test.clj | 2 +- .../drafter/feature/draftset/submit_test.clj | 8 ++-- drafter/test/drafter/handler_test.clj | 14 +++---- .../drafter/middleware/auth0_auth_test.clj | 2 +- drafter/test/drafter/model.clj | 4 +- drafter/test/drafter/test_common.clj | 4 +- drafter/test/drafter/user_test.clj | 30 ++++++------- .../claimable-draftset-changes-2.trig | 4 +- .../draftset/claimable-draftset-changes.trig | 4 +- .../list_test-1-draftset-with-submission.trig | 2 +- .../drafter/feature/draftset/list_test-2.trig | 4 +- .../draftset/list_test-unclaimable.trig | 2 +- .../draftset/list_test-union-with-live.trig | 2 +- .../endpoint/list_test-with-login.trig | 4 +- 44 files changed, 137 insertions(+), 137 deletions(-) diff --git a/drafter-client/test/drafter_client/client_test.clj b/drafter-client/test/drafter_client/client_test.clj index 7cfc400fd..193e85dce 100644 --- a/drafter-client/test/drafter_client/client_test.clj +++ b/drafter-client/test/drafter_client/client_test.clj @@ -220,7 +220,7 @@ token (auth-util/publisher-token) ds-1 (sut/new-draftset client token "first" "description") ds-2 (sut/new-draftset client token "second" "description")] - (sut/submit-to-permission client token (draftset/id ds-2) :draft:claim) + (sut/submit-to-permission client token (draftset/id ds-2) :drafter:draft:claim) (t/testing "default" (let [draftsets (sut/draftsets client token)] (t/is (= #{(draftset/id ds-1) (draftset/id ds-2)} diff --git a/drafter/doc/drafter.yml b/drafter/doc/drafter.yml index 34f6f7779..b39eb7087 100644 --- a/drafter/doc/drafter.yml +++ b/drafter/doc/drafter.yml @@ -104,17 +104,17 @@ info: Currently available permissions are: - - public:view - - draft:claim - - draft:create - - draft:delete - - draft:edit - - draft:publish - - draft:share - - draft:submit - - draft:view - - job:view - - user:view + - drafter:public:view + - drafter:draft:claim + - drafter:draft:create + - drafter:draft:delete + - drafter:draft:edit + - drafter:draft:publish + - drafter:draft:share + - drafter:draft:submit + - drafter:draft:view + - drafter:job:view + - drafter:user:view ## Authentication & Security diff --git a/drafter/migrations/rbac-1-backfill-claim-permissions.sparql b/drafter/migrations/rbac-1-backfill-claim-permissions.sparql index bba5c7462..75e98ce8b 100644 --- a/drafter/migrations/rbac-1-backfill-claim-permissions.sparql +++ b/drafter/migrations/rbac-1-backfill-claim-permissions.sparql @@ -16,6 +16,6 @@ INSERT { } WHERE { GRAPH { ?submission drafter:claimRole ?role . - BIND(IF(?role = "editor", "draft:edit", "draft:publish") as ?permission) + BIND(IF(?role = "editor", "drafter:draft:edit", "drafter:draft:publish") as ?permission) } } diff --git a/drafter/src/drafter/async/jobs.clj b/drafter/src/drafter/async/jobs.clj index e57e052b0..8f19d7a82 100644 --- a/drafter/src/drafter/async/jobs.clj +++ b/drafter/src/drafter/async/jobs.clj @@ -76,7 +76,7 @@ (defmethod ig/init-key :drafter.routes/jobs-status [_ opts] (context "/v1/status" [] - (middleware/wrap-authorize (:wrap-authenticate opts) :job:view + (middleware/wrap-authorize (:wrap-authenticate opts) :drafter:job:view (routes (GET "/jobs/:id" [id] (or (when-let [job (some-> id r/try-parse-uuid get-job)] diff --git a/drafter/src/drafter/auth/auth0.clj b/drafter/src/drafter/auth/auth0.clj index 255cb3407..cf2ded94d 100644 --- a/drafter/src/drafter/auth/auth0.clj +++ b/drafter/src/drafter/auth/auth0.clj @@ -32,8 +32,8 @@ (if-let [email (email access-token)] {:email email :permissions (->> access-token :payload :permissions - (keep #(re-matches #"drafter:(.*)" %)) - (map (comp keyword second)) set)} + (keep #(re-matches #"drafter:.*" %)) + (map keyword) set)} (auth/authentication-failed))) ::jwt/token-expired @@ -69,7 +69,7 @@ :flow "application" :description "OAuth authentication via Auth0" :tokenUrl (str (:endpoint auth0-client) "/oauth/token") - :scopes (update-keys user/permission-summary #(str "drafter" %))}) + :scopes (update-keys user/permission-summary name)}) (get-operation-swagger-security-requirement [_this {:keys [permission] :as operation}] [(str "drafter:" permission)]) diff --git a/drafter/src/drafter/feature/draftset/changes.clj b/drafter/src/drafter/feature/draftset/changes.clj index e3bd8d718..59f776593 100644 --- a/drafter/src/drafter/feature/draftset/changes.clj +++ b/drafter/src/drafter/feature/draftset/changes.clj @@ -28,7 +28,7 @@ (defn delete-draftset-changes-handler [{:keys [wrap-as-draftset-owner] {:keys [backend] :as manager} :drafter/manager}] - (wrap-as-draftset-owner :draft:edit + (wrap-as-draftset-owner :drafter:draft:edit (middleware/parse-graph-param-handler true (fn [{{:keys [draftset-id graph]} :params :as request}] diff --git a/drafter/src/drafter/feature/draftset/claim.clj b/drafter/src/drafter/feature/draftset/claim.clj index c144ceecd..92157d2af 100644 --- a/drafter/src/drafter/feature/draftset/claim.clj +++ b/drafter/src/drafter/feature/draftset/claim.clj @@ -38,7 +38,7 @@ (let [inner-handler (partial handler* manager)] (->> inner-handler (feat-middleware/existing-draftset-handler backend) - (middleware/wrap-authorize wrap-authenticate :draft:claim)))) + (middleware/wrap-authorize wrap-authenticate :drafter:draft:claim)))) (defmethod ig/pre-init-spec :drafter.feature.draftset.claim/handler [_] (s/keys :req [:drafter/manager])) diff --git a/drafter/src/drafter/feature/draftset/create.clj b/drafter/src/drafter/feature/draftset/create.clj index 836f06697..37dc349a4 100644 --- a/drafter/src/drafter/feature/draftset/create.clj +++ b/drafter/src/drafter/feature/draftset/create.clj @@ -15,7 +15,7 @@ [{{:keys [backend global-writes-lock clock] :as manager} :drafter/manager wrap-authenticate :wrap-authenticate}] (let [version "/v1"] - (middleware/wrap-authorize wrap-authenticate :draft:create + (middleware/wrap-authorize wrap-authenticate :drafter:draft:create (fn [{{:keys [display-name description]} :params user :identity :as request}] (feat-common/run-sync {:backend backend :global-writes-lock global-writes-lock} diff --git a/drafter/src/drafter/feature/draftset/delete.clj b/drafter/src/drafter/feature/draftset/delete.clj index d3bef461f..b6d316faa 100644 --- a/drafter/src/drafter/feature/draftset/delete.clj +++ b/drafter/src/drafter/feature/draftset/delete.clj @@ -8,7 +8,7 @@ (defn handler [{wrap-as-draftset-owner :wrap-as-draftset-owner backend :drafter/backend}] - (wrap-as-draftset-owner :draft:delete + (wrap-as-draftset-owner :drafter:draft:delete (fn [{:keys [params] :as request}] (log/info "drafter.feature.draftset.delete/handler " request) (writes/submit-async-job! diff --git a/drafter/src/drafter/feature/draftset/list.clj b/drafter/src/drafter/feature/draftset/list.clj index cf2fe78d1..dceb11ea2 100644 --- a/drafter/src/drafter/feature/draftset/list.clj +++ b/drafter/src/drafter/feature/draftset/list.clj @@ -71,7 +71,7 @@ (defn get-draftsets-handler ":get /draftsets" [{:keys [drafter/backend wrap-authenticate]}] - (middleware/wrap-authorize wrap-authenticate :draft:view + (middleware/wrap-authorize wrap-authenticate :drafter:draft:view (middleware/include-endpoints-param (parse-union-with-live-handler (fn [{user :identity {:keys [include union-with-live]} :params :as request}] diff --git a/drafter/src/drafter/feature/draftset/options.clj b/drafter/src/drafter/feature/draftset/options.clj index 4ccec31aa..16804f0a4 100644 --- a/drafter/src/drafter/feature/draftset/options.clj +++ b/drafter/src/drafter/feature/draftset/options.clj @@ -8,7 +8,7 @@ (defn handler [{:keys [drafter/backend wrap-authenticate]}] - (middleware/wrap-authorize wrap-authenticate :draft:view + (middleware/wrap-authorize wrap-authenticate :drafter:draft:view (feat-middleware/existing-draftset-handler backend (fn [{{:keys [draftset-id]} :params user :identity}] diff --git a/drafter/src/drafter/feature/draftset/publish.clj b/drafter/src/drafter/feature/draftset/publish.clj index d1777ed11..571bd8ba9 100644 --- a/drafter/src/drafter/feature/draftset/publish.clj +++ b/drafter/src/drafter/feature/draftset/publish.clj @@ -9,7 +9,7 @@ (defn handler [{manager :drafter/manager :keys [wrap-as-draftset-owner]}] - (wrap-as-draftset-owner :draft:publish + (wrap-as-draftset-owner :drafter:draft:publish (fn [{params :params :as request}] (writes/submit-async-job! (dsjobs/publish-draftset-job manager diff --git a/drafter/src/drafter/feature/draftset/query.clj b/drafter/src/drafter/feature/draftset/query.clj index b1a283032..9ea514724 100644 --- a/drafter/src/drafter/feature/draftset/query.clj +++ b/drafter/src/drafter/feature/draftset/query.clj @@ -9,7 +9,7 @@ (defn handler [{backend :drafter/backend :keys [wrap-as-draftset-owner timeout-fn]}] - (wrap-as-draftset-owner :draft:view + (wrap-as-draftset-owner :drafter:draft:view (parse-union-with-live-handler (fn [{{:keys [draftset-id union-with-live]} :params :as request}] (let [executor (backend/endpoint-repo backend draftset-id {:union-with-live? union-with-live}) diff --git a/drafter/src/drafter/feature/draftset/set_metadata.clj b/drafter/src/drafter/feature/draftset/set_metadata.clj index ae5739aaa..423766747 100644 --- a/drafter/src/drafter/feature/draftset/set_metadata.clj +++ b/drafter/src/drafter/feature/draftset/set_metadata.clj @@ -7,7 +7,7 @@ (defn handler [{:keys [wrap-as-draftset-owner] {:keys [backend] :as manager} :drafter/manager}] - (wrap-as-draftset-owner :draft:edit + (wrap-as-draftset-owner :drafter:draft:edit (fn [{{:keys [draftset-id] :as params} :params :as request}] (feat-common/run-sync manager diff --git a/drafter/src/drafter/feature/draftset/show.clj b/drafter/src/drafter/feature/draftset/show.clj index cb2d45c67..e9cc3d5cf 100644 --- a/drafter/src/drafter/feature/draftset/show.clj +++ b/drafter/src/drafter/feature/draftset/show.clj @@ -23,7 +23,7 @@ (defn handler [{:keys [drafter/backend wrap-authenticate]}] - (middleware/wrap-authorize wrap-authenticate :draft:view + (middleware/wrap-authorize wrap-authenticate :drafter:draft:view (feat-middleware/existing-draftset-handler backend (parse-union-with-live-handler diff --git a/drafter/src/drafter/feature/draftset/submit.clj b/drafter/src/drafter/feature/draftset/submit.clj index 3e580802b..d8e665e0e 100644 --- a/drafter/src/drafter/feature/draftset/submit.clj +++ b/drafter/src/drafter/feature/draftset/submit.clj @@ -34,11 +34,11 @@ ;; Maps a role to a permission that that role has, but less privileged roles ;; don't have. (def role->canonical-permission - {"editor" "draft:edit" "publisher" "draft:publish"}) + {"editor" "drafter:draft:edit" "publisher" "drafter:draft:publish"}) (defn handler [{:keys [:drafter/manager :drafter.user/repo wrap-as-draftset-owner]}] - (wrap-as-draftset-owner :draft:submit + (wrap-as-draftset-owner :drafter:draft:submit (fn [{{:keys [user permission role draftset-id]} :params owner :identity}] ;; The role parameter is deprecated (let [permission (or permission (role->canonical-permission role))] diff --git a/drafter/src/drafter/feature/draftset/update.clj b/drafter/src/drafter/feature/draftset/update.clj index debbf620a..96d7a93c9 100644 --- a/drafter/src/drafter/feature/draftset/update.clj +++ b/drafter/src/drafter/feature/draftset/update.clj @@ -492,7 +492,7 @@ (defn handler [{:keys [wrap-as-draftset-owner] :as opts}] - (wrap-as-draftset-owner :draft:edit (fn [request] (handler* opts request)))) + (wrap-as-draftset-owner :drafter:draft:edit (fn [request] (handler* opts request)))) (def cors-allowed-headers #{"Accept" diff --git a/drafter/src/drafter/feature/draftset_data/append.clj b/drafter/src/drafter/feature/draftset_data/append.clj index c5f6ebe70..09cb49ec7 100644 --- a/drafter/src/drafter/feature/draftset_data/append.clj +++ b/drafter/src/drafter/feature/draftset_data/append.clj @@ -119,7 +119,7 @@ "Ring handler to append data into a draftset." [{:keys [:drafter/manager ::time/clock wrap-as-draftset-owner]}] - (wrap-as-draftset-owner :draft:edit + (wrap-as-draftset-owner :drafter:draft:edit (require-rdf-content-type (dset-middleware/parse-graph-for-triples (temp-file-body diff --git a/drafter/src/drafter/feature/draftset_data/append_by_graph.clj b/drafter/src/drafter/feature/draftset_data/append_by_graph.clj index 773ae9d5a..ca960e562 100644 --- a/drafter/src/drafter/feature/draftset_data/append_by_graph.clj +++ b/drafter/src/drafter/feature/draftset_data/append_by_graph.clj @@ -52,7 +52,7 @@ (middleware/parse-graph-param-handler true (required-live-graph-param-handler backend handler)))] - (wrap-as-draftset-owner :draft:edit + (wrap-as-draftset-owner :drafter:draft:edit (required-live-graph-param (fn [{:keys [params] :as request}] (let [{:keys [draftset-id graph metadata]} params diff --git a/drafter/src/drafter/feature/draftset_data/delete.clj b/drafter/src/drafter/feature/draftset_data/delete.clj index a936e7385..9d02648f0 100644 --- a/drafter/src/drafter/feature/draftset_data/delete.clj +++ b/drafter/src/drafter/feature/draftset_data/delete.clj @@ -131,7 +131,7 @@ temp-file-body deset-middleware/parse-graph-for-triples require-rdf-content-type - (wrap-as-draftset-owner :draft:edit))) + (wrap-as-draftset-owner :drafter:draft:edit))) (defmethod ig/pre-init-spec :drafter.feature.draftset-data.delete/delete-data-handler [_] (s/keys :req [:drafter/manager] diff --git a/drafter/src/drafter/feature/draftset_data/delete_by_graph.clj b/drafter/src/drafter/feature/draftset_data/delete_by_graph.clj index 43a848d6c..f26dabf25 100644 --- a/drafter/src/drafter/feature/draftset_data/delete_by_graph.clj +++ b/drafter/src/drafter/feature/draftset_data/delete_by_graph.clj @@ -90,7 +90,7 @@ (defn remove-graph-from-draftset-handler "Remove a supplied graph from the draftset." [{:keys [wrap-as-draftset-owner] :as resources}] - (wrap-as-draftset-owner :draft:edit + (wrap-as-draftset-owner :drafter:draft:edit (parse-query-param-flag-handler :silent (feat-middleware/parse-graph-param-handler true (request-handler resources))))) diff --git a/drafter/src/drafter/feature/draftset_data/show.clj b/drafter/src/drafter/feature/draftset_data/show.clj index 240e305b2..3b2704f51 100644 --- a/drafter/src/drafter/feature/draftset_data/show.clj +++ b/drafter/src/drafter/feature/draftset_data/show.clj @@ -11,7 +11,7 @@ [{wrap-as-draftset-owner :wrap-as-draftset-owner backend :drafter/backend draftset-query-timeout-fn :timeout-fn}] - (wrap-as-draftset-owner :draft:view + (wrap-as-draftset-owner :drafter:draft:view (parse-union-with-live-handler (fn [{{:keys [draftset-id graph union-with-live] :as params} :params :as request}] (let [executor (ep/build-draftset-endpoint backend draftset-id union-with-live) diff --git a/drafter/src/drafter/feature/users/list.clj b/drafter/src/drafter/feature/users/list.clj index 0618f7b2d..d7c770352 100644 --- a/drafter/src/drafter/feature/users/list.clj +++ b/drafter/src/drafter/feature/users/list.clj @@ -9,7 +9,7 @@ "Ring handler that returns a list of user objects representing users within the system." [{user-repo ::user/repo wrap-authenticate :wrap-authenticate}] - (middleware/wrap-authorize wrap-authenticate :user:view + (middleware/wrap-authorize wrap-authenticate :drafter:user:view (fn [r] (let [users (user/get-all-users user-repo) summaries (map user/get-summary users)] diff --git a/drafter/src/drafter/handler.clj b/drafter/src/drafter/handler.clj index d3fe0bac6..e4d15d5f7 100644 --- a/drafter/src/drafter/handler.clj +++ b/drafter/src/drafter/handler.clj @@ -67,7 +67,7 @@ #(log-request % {:query ""})]] (if global-auth? (cons #(middleware/wrap-authorize - wrap-authenticate :public:view %) + wrap-authenticate :drafter:public:view %) middleware) middleware)) diff --git a/drafter/src/drafter/swagger.clj b/drafter/src/drafter/swagger.clj index 8072e3ae0..125ca04b8 100644 --- a/drafter/src/drafter/swagger.clj +++ b/drafter/src/drafter/swagger.clj @@ -40,7 +40,7 @@ (recur resolved)))))) (defn get-api-route-specs [global-auth?] - (let [access-permission (when global-auth? :public:view)] + (let [access-permission (when global-auth? :drafter:public:view)] [{:id 'get-endpoints :path "/endpoints" :method :get @@ -53,76 +53,76 @@ {:id 'create-draftset :path "/draftsets" :method :post - :permission :draft:create} + :permission :drafter:draft:create} {:id 'get-draftsets :path "/draftsets" :method :get - :permission :draft:view} + :permission :drafter:draft:view} {:id 'get-draftset :path "/draftset/{id}" :method :get - :permission :draft:view} + :permission :drafter:draft:view} {:id 'put-draftset :path "/draftset/{id}" :method :put - :permission :draft:edit} + :permission :drafter:draft:edit} {:id 'delete-draftset :path "/draftset/{id}" :method :delete - :permission :draft:delete} + :permission :drafter:draft:delete} {:id 'put-draftset-graph :path "/draftset/{id}/graph" :method :put - :permission :draft:edit} + :permission :drafter:draft:edit} {:id 'delete-draftset-graph :path "/draftset/{id}/graph" :method :delete - :permission :draft:edit} + :permission :drafter:draft:edit} {:id 'delete-draftset-changes :path "/draftset/{id}/changes" :method :delete - :permission :draft:edit} + :permission :drafter:draft:edit} {:id 'put-draftset-data :path "/draftset/{id}/data" :method :put - :permission :draft:edit} + :permission :drafter:draft:edit} {:id 'delete-draftset-data :path "/draftset/{id}/data" :method :delete - :permission :draft:edit} + :permission :drafter:draft:edit} {:id 'get-draftset-data :path "/draftset/{id}/data" :method :get - :permission :draft:view} + :permission :drafter:draft:view} {:id 'submit-draftset-to :path "/draftset/{id}/submit-to" :method :post - :permission :draft:submit} + :permission :drafter:draft:submit} {:id 'claim-draftset :path "/draftset/{id}/claim" :method :put - :permission :draft:claim} + :permission :drafter:draft:claim} {:id 'publish-draftset :path "/draftset/{id}/publish" :method :post - :permission :draft:publish} + :permission :drafter:draft:publish} {:id 'get-query-draftset :path "/draftset/{id}/query" :method :get - :permission :draft:view} + :permission :drafter:draft:view} {:id 'post-query-draftset :path "/draftset/{id}/query" :method :post - :permission :draft:view} + :permission :drafter:draft:view} {:id 'post-update-draftset :path "/draftset/{id}/update" :method :post - :permission :draft:edit} + :permission :drafter:draft:edit} {:id 'get-query-live :path "/sparql/live" :method :get @@ -135,16 +135,16 @@ {:id 'get-users :path "/users" :method :get - :permission :user:view} + :permission :drafter:user:view} {:id 'get-job :path "/status/jobs/{jobid}" :method :get - :permission :job:view} + :permission :drafter:job:view} {:id 'get-jobs :path "/status/jobs" :method :get - :permission :job:view} + :permission :drafter:job:view} {:id 'status-job-finished :path "/status/finished-jobs/{jobid}" :method :get diff --git a/drafter/src/drafter/user.clj b/drafter/src/drafter/user.clj index 2d93b3192..0e33955ed 100644 --- a/drafter/src/drafter/user.clj +++ b/drafter/src/drafter/user.clj @@ -23,27 +23,29 @@ [role] (case role :norole #{} - :access #{:public:view} + :access #{:drafter:public:view} :editor (conj (role->permissions :access) - :draft:claim :draft:create :draft:delete :draft:edit - :draft:submit :draft:share :draft:view :job:view :user:view) - :publisher (conj (role->permissions :editor) :draft:publish) + :drafter:draft:claim :drafter:draft:create + :drafter:draft:delete :drafter:draft:edit + :drafter:draft:submit :drafter:draft:share + :drafter:draft:view :drafter:job:view :drafter:user:view) + :publisher (conj (role->permissions :editor) :drafter:draft:publish) ;; :manager is used in tests to demonstrate scoped claim permissions. - :manager (conj (role->permissions :publisher) :draft:claim:manager) + :manager (conj (role->permissions :publisher) :drafter:draft:claim:manager) :system (recur :manager))) (def permission-summary - {:draft:claim "Claim submitted drafts" - :draft:create "Create drafts" - :draft:delete "Delete drafts" - :draft:edit "Edit drafts" - :draft:publish "Publish drafts" - :draft:share "Share drafts to be viewed" - :draft:submit "Submit drafts to be claimed" - :draft:view "View shared drafts" - :job:view "View the status of jobs" - :public:view "View the public endpoint (if global auth is on)" - :user:view "View users"}) + {:drafter:draft:claim "Claim submitted drafts" + :drafter:draft:create "Create drafts" + :drafter:draft:delete "Delete drafts" + :drafter:draft:edit "Edit drafts" + :drafter:draft:publish "Publish drafts" + :drafter:draft:share "Share drafts to be viewed" + :drafter:draft:submit "Submit drafts to be claimed" + :drafter:draft:view "View shared drafts" + :drafter:job:view "View the status of jobs" + :drafter:public:view "View the public endpoint (if global auth is on)" + :drafter:user:view "View users"}) (def roles #{:access :editor :publisher :manager :system}) @@ -159,7 +161,7 @@ (defn permitted-draftset-operations [draftset user] (cond (is-owner? user draftset) - (set (keep #(when-let [[_ op] (re-matches #"draft:(.*)" (name %))] + (set (keep #(when-let [[_ op] (re-matches #"drafter:draft:(.*)" (name %))] (keyword op)) (:permissions user))) diff --git a/drafter/test/drafter/auth/auth0_test.clj b/drafter/test/drafter/auth/auth0_test.clj index 4ff097338..66ba47772 100644 --- a/drafter/test/drafter/auth/auth0_test.clj +++ b/drafter/test/drafter/auth/auth0_test.clj @@ -37,7 +37,7 @@ [system "test-system.edn"] (let [auth-method (get-auth-method system) username "test@example.com" - permissions #{:cat:pet :missiles:launch} + permissions #{:drafter:cat:pet :drafter:missiles:launch} token (tc/user-access-token username "drafter:editor" permissions) request (add-auth-header {:uri "/test" :request-method :get} token) user (auth-common/expect-authentication auth-method request) diff --git a/drafter/test/drafter/auth/jws_test.clj b/drafter/test/drafter/auth/jws_test.clj index fa554a17c..eb408f1d0 100644 --- a/drafter/test/drafter/auth/jws_test.clj +++ b/drafter/test/drafter/auth/jws_test.clj @@ -35,7 +35,7 @@ request (add-user {:uri "/test" :request-method :get} user signing-key) identity (auth-common/expect-authentication auth-method request)] (t/is (= (:email user) (:email identity))) - (t/is (contains? (:permissions identity) :draft:publish)))) + (t/is (contains? (:permissions identity) :drafter:draft:publish)))) (t/deftest should-reject-token-with-invalid-issuer (let [doc {:user "test@example.com" diff --git a/drafter/test/drafter/backend/draftset/operations_test.clj b/drafter/test/drafter/backend/draftset/operations_test.clj index 66271ba3d..f40f08d81 100644 --- a/drafter/test/drafter/backend/draftset/operations_test.clj +++ b/drafter/test/drafter/backend/draftset/operations_test.clj @@ -94,7 +94,7 @@ (sut/submit-draftset-to-permission! *test-backend* draftset-id test-editor - :draft:claim) + :drafter:draft:claim) (let [owner (sut/get-draftset-owner *test-backend* draftset-id)] (is (nil? owner)))))) @@ -108,7 +108,7 @@ (sut/submit-draftset-to-permission! *test-backend* draftset-id test-editor - :draft:claim) + :drafter:draft:claim) (is (= false (sut/is-draftset-owner? *test-backend* draftset-id test-editor))))) (testing "Has different owner" @@ -155,9 +155,9 @@ (sut/submit-draftset-to-permission! *test-backend* draftset-id test-editor - :draft:claim) + :drafter:draft:claim) - (is (draftset-has-claim-permission? draftset-id :draft:claim)) + (is (draftset-has-claim-permission? draftset-id :drafter:draft:claim)) (is (= false (has-any-object? draftset-uri drafter:hasOwner))))) (testing "Submitted by other user" @@ -166,7 +166,7 @@ (sut/submit-draftset-to-permission! *test-backend* draftset-id test-publisher - :draft:claim) + :drafter:draft:claim) (is (sut/is-draftset-owner? *test-backend* draftset-id test-editor)) (is (= false (has-any-object? draftset-uri drafter:hasSubmission)))))) @@ -217,11 +217,11 @@ (sut/submit-draftset-to-permission! *test-backend* draftset-id test-editor - :draft:claim) + :drafter:draft:claim) (sut/submit-draftset-to-user! *test-backend* draftset-id test-editor test-manager) (is (= nil (sut/get-draftset-owner *test-backend* draftset-id))) - (is (draftset-has-claim-permission? draftset-id :draft:claim)) + (is (draftset-has-claim-permission? draftset-id :drafter:draft:claim)) (is (= false (draftset-has-claim-user? draftset-id test-manager)))))) (defn- draftset-has-submission? [draftset-ref] @@ -240,7 +240,7 @@ (sut/submit-draftset-to-permission! *test-backend* draftset-id test-editor - :draft:claim) + :drafter:draft:claim) (let [[result _] (sut/claim-draftset! *test-backend* draftset-id test-publisher) ds-info (sut/get-draftset-info *test-backend* draftset-id)] @@ -271,7 +271,7 @@ (sut/submit-draftset-to-permission! *test-backend* draftset-id test-editor - :draft:claim) + :drafter:draft:claim) (let [[result _] (sut/claim-draftset! *test-backend* draftset-id test-editor)] (is (= :ok result)) (is (sut/is-draftset-owner? *test-backend* draftset-id test-editor)) @@ -290,7 +290,7 @@ (sut/submit-draftset-to-permission! *test-backend* draftset-id test-editor - :draft:publish) + :drafter:draft:publish) (let [[result _] (sut/claim-draftset! *test-backend* draftset-id test-editor)] (is (= :ok result)) (is (sut/is-draftset-owner? *test-backend* draftset-id test-editor)) @@ -301,7 +301,7 @@ (sut/submit-draftset-to-permission! *test-backend* draftset-id test-editor - :draft:publish) + :drafter:draft:publish) (sut/claim-draftset! *test-backend* draftset-id test-publisher) (let [[result _] (sut/claim-draftset! *test-backend* draftset-id test-editor)] (is (= :forbidden result))))) @@ -317,7 +317,7 @@ (sut/submit-draftset-to-permission! *test-backend* draftset-id test-editor - :draft:claim:manager) + :drafter:draft:claim:manager) (let [[result _] (sut/claim-draftset! *test-backend* draftset-id test-publisher)] (is (= :forbidden result)) (is (nil? (sut/get-draftset-owner *test-backend* draftset-id)))))) diff --git a/drafter/test/drafter/feature/draftset/claim_test.clj b/drafter/test/drafter/feature/draftset/claim_test.clj index 8ad6c5cfe..74cfc6bc1 100644 --- a/drafter/test/drafter/feature/draftset/claim_test.clj +++ b/drafter/test/drafter/feature/draftset/claim_test.clj @@ -45,7 +45,7 @@ (help/submit-draftset-to-permission-through-api handler test-editor draftset-location - :draft:claim) + :drafter:draft:claim) (let [{:keys [current-owner] :as ds-info} (claim-draftset-through-api handler draftset-location test-publisher)] (is (= (user/username test-publisher) current-owner))))) @@ -108,7 +108,7 @@ (help/submit-draftset-to-permission-through-api handler test-editor draftset-location - :draft:claim) + :drafter:draft:claim) (claim-draftset-through-api handler draftset-location test-editor))) (tc/deftest-system-with-keys claim-owned-by-other-user-draftset-submitted-by-self @@ -120,7 +120,7 @@ (help/submit-draftset-to-permission-through-api handler test-editor draftset-location - :draft:claim) + :drafter:draft:claim) (claim-draftset-through-api handler draftset-location test-publisher) (let [response (handler (create-claim-request draftset-location test-editor))] (tc/assert-is-forbidden-response response)))) @@ -147,7 +147,7 @@ (help/submit-draftset-to-permission-through-api handler test-editor draftset-location - :draft:publish) + :drafter:draft:publish) (let [claim-response (handler (create-claim-request draftset-location other-editor))] (tc/assert-is-forbidden-response claim-response)))) diff --git a/drafter/test/drafter/feature/draftset/show_test.clj b/drafter/test/drafter/feature/draftset/show_test.clj index 5292634fc..a462a9778 100644 --- a/drafter/test/drafter/feature/draftset/show_test.clj +++ b/drafter/test/drafter/feature/draftset/show_test.clj @@ -162,7 +162,7 @@ (help/submit-draftset-to-permission-through-api handler test-editor draftset-location - :draft:claim) + :drafter:draft:claim) (let [ds-info (help/get-user-draftset-info-view-through-api handler draftset-location test-publisher)]))) (tc/deftest-system-with-keys get-draftset-for-other-user-test diff --git a/drafter/test/drafter/feature/draftset/submit_test.clj b/drafter/test/drafter/feature/draftset/submit_test.clj index 10e8f5352..32fce9f07 100644 --- a/drafter/test/drafter/feature/draftset/submit_test.clj +++ b/drafter/test/drafter/feature/draftset/submit_test.clj @@ -17,7 +17,7 @@ (let [submit-response (handler (help/create-submit-to-permission-request test-editor "/v1/draftset/missing" - :draft:claim))] + :drafter:draft:claim))] (tc/assert-is-not-found-response submit-response))) (tc/deftest-system-with-keys submit-draftset-to-permission-by-non-owner @@ -27,7 +27,7 @@ submit-response (handler (help/create-submit-to-permission-request test-publisher draftset-location - :draft:claim))] + :drafter:draft:claim))] (tc/assert-is-forbidden-response submit-response))) (tc/deftest-system-with-keys submit-draftset-to-user @@ -83,7 +83,7 @@ [{handler [:drafter/routes :draftset/api]} "test-system.edn"] (let [draftset-location (help/create-draftset-through-api handler test-editor) request (help/submit-draftset-to-user-request draftset-location test-publisher test-editor) - request (assoc-in request [:params :permission] "draft:claim") + request (assoc-in request [:params :permission] "drafter:draft:claim") response (handler request)] (tc/assert-is-unprocessable-response response))) @@ -93,7 +93,7 @@ (let [draftset-location (help/create-draftset-through-api handler test-editor) submit-request (help/create-submit-to-permission-request test-editor draftset-location - :draft:claim) + :drafter:draft:claim) {ds-info :body :as submit-response} (handler submit-request)] (tc/assert-is-ok-response submit-response) (tc/assert-spec ::ds/Draftset ds-info) diff --git a/drafter/test/drafter/handler_test.clj b/drafter/test/drafter/handler_test.clj index 378a66e6b..3be63b0e7 100644 --- a/drafter/test/drafter/handler_test.clj +++ b/drafter/test/drafter/handler_test.clj @@ -32,8 +32,8 @@ get-public test-access 200 get-public test-editor 200 get-public test-publisher 200 - list-draftsets nil 401 ;; Unauthorized, requires :draft:view - list-draftsets test-access 403 ;; Forbidden, requires :draft:view + list-draftsets nil 401 ;; Unauthorized, requires :drafter:draft:view + list-draftsets test-access 403 ;; Forbidden, requires :drafter:draft:view list-draftsets test-editor 200 list-draftsets test-publisher 200)) (tc/with-system [{handler :drafter.handler/app} @@ -47,8 +47,8 @@ whitelisted test-access 200 whitelisted test-editor 200 whitelisted test-publisher 200 - get-public nil 401 ;; Unauthorized, requires :public:view - get-public test-norole 403 ;; Forbidden, requires :public:view + get-public nil 401 ;; Unauthorized, requires :drafter:public:view + get-public test-norole 403 ;; Forbidden, requires :drafter:public:view get-public test-access 200 get-public test-editor 200 get-public test-publisher 200 @@ -57,9 +57,9 @@ options-public test-access 200 options-public test-editor 200 options-public test-publisher 200 - list-draftsets nil 401 ;; Unauthorized, requires :draft:view - list-draftsets test-norole 403 ;; Forbidden, requires :draft:view - list-draftsets test-access 403 ;; Forbidden, requires :draft:view + list-draftsets nil 401 ;; Unauthorized, requires :drafter:draft:view + list-draftsets test-norole 403 ;; Forbidden, requires :drafter:draft:view + list-draftsets test-access 403 ;; Forbidden, requires :drafter:draft:view list-draftsets test-editor 200 list-draftsets test-publisher 200)))) diff --git a/drafter/test/drafter/middleware/auth0_auth_test.clj b/drafter/test/drafter/middleware/auth0_auth_test.clj index cf2793262..cb84e9730 100644 --- a/drafter/test/drafter/middleware/auth0_auth_test.clj +++ b/drafter/test/drafter/middleware/auth0_auth_test.clj @@ -43,7 +43,7 @@ [:drafter.middleware/wrap-authenticate] [{:keys [:drafter.middleware/wrap-authenticate]} system] (let [username "test@example.com" - permissions #{:cat:pet :missiles:launch} + permissions #{:drafter:cat:pet :drafter:missiles:launch} user {:email username :role :publisher :permissions permissions} token (tc/user-access-token username "drafter:publisher" permissions) request (create-authorised-request token) diff --git a/drafter/test/drafter/model.clj b/drafter/test/drafter/model.clj index 9634279b2..4e214964f 100644 --- a/drafter/test/drafter/model.clj +++ b/drafter/test/drafter/model.clj @@ -76,7 +76,7 @@ (dsops/find-permitted-draftset-operations backend draftset-ref user)) (defn- publish-draftset-op [drafter user draftset-ref {:keys [metadata] :as opts}] - (if (user/has-permission? user :draft:publish) + (if (user/has-permission? user :drafter:draft:publish) (let [params (cond-> {:draftset-id draftset-ref} (some? metadata) (assoc :metadata (format-metadata metadata))) job (dsjobs/publish-draftset-job drafter @@ -346,7 +346,7 @@ (submit-draftset-to-permission drafter test-publisher ds-id - :draft:claim) + :drafter:draft:claim) (claim-draftset drafter test-editor ds-id) (submit-draftset-to-user drafter test-editor ds-id test-publisher) (claim-draftset drafter test-publisher ds-id) diff --git a/drafter/test/drafter/test_common.clj b/drafter/test/drafter/test_common.clj index dd5cc4837..4f183300d 100644 --- a/drafter/test/drafter/test_common.clj +++ b/drafter/test/drafter/test_common.clj @@ -116,9 +116,7 @@ (.withAudience (into-array String [aud])) (.withExpiresAt (to-date (clj-time/plus (clj-time/now) (clj-time/minutes 10)))) (.withClaim "scope" role) - (.withArrayClaim "permissions" - (into-array String - (map #(str "drafter" %) permissions))) + (.withArrayClaim "permissions" (into-array String (map name permissions))) (.sign alg))) (defn mock-jwk [] diff --git a/drafter/test/drafter/user_test.clj b/drafter/test/drafter/user_test.clj index c514fa53c..7d89503c6 100644 --- a/drafter/test/drafter/user_test.clj +++ b/drafter/test/drafter/user_test.clj @@ -22,14 +22,14 @@ (deftest has-permission?-test (are [user permission has?] (= has? (has-permission? user permission)) - test-editor :draft:edit true - test-editor :draft:publish false + test-editor :drafter:draft:edit true + test-editor :drafter:draft:publish false - test-publisher :draft:edit true - test-publisher :draft:publish true + test-publisher :drafter:draft:edit true + test-publisher :drafter:draft:publish true - test-manager :draft:edit true - test-manager :draft:publish true)) + test-manager :drafter:draft:edit true + test-manager :drafter:draft:publish true)) (deftest password-valid?-test (let [password (str (UUID/randomUUID)) @@ -81,8 +81,8 @@ (deftest is-submitted-by?-test (are [user draftset expected] (= expected (is-submitted-by? user draftset)) - test-editor (submitted-to-permission test-editor :draft:claim) true - test-publisher (submitted-to-permission test-editor :draft:claim) false + test-editor (submitted-to-permission test-editor :drafter:draft:claim) true + test-publisher (submitted-to-permission test-editor :drafter:draft:claim) false test-editor (ds/create-draftset (username test-editor)) false)) (deftest can-claim?-test @@ -91,11 +91,11 @@ test-editor (ds/create-draftset (username test-editor)) true ;;submitter can re-claim draftset if it has not yet been claimed - test-editor (submitted-to-permission test-editor :draft:claim) true + test-editor (submitted-to-permission test-editor :drafter:draft:claim) true test-editor (submitted-to-user test-editor test-manager) true ;;user can claim draftset submitted to a permission they have - test-publisher (submitted-to-permission test-editor :draft:claim) true + test-publisher (submitted-to-permission test-editor :drafter:draft:claim) true ;;user can claim draftset submitted to them test-manager (submitted-to-user test-editor test-manager) true @@ -104,7 +104,7 @@ test-publisher (ds/create-draftset (username test-editor)) false ;;user cannot claim draftset submitted to a permission they don't have - test-publisher (submitted-to-permission test-editor :draft:claim:manager) false + test-publisher (submitted-to-permission test-editor :drafter:draft:claim:manager) false ;;user cannot claim draftset submitted to other user test-manager (submitted-to-user test-editor test-publisher) false)) @@ -122,11 +122,11 @@ #{:share :claim :delete :edit :view :create :submit :publish} ;;submitter on unclaimed - test-editor (submitted-to-permission test-editor :draft:claim) #{:claim} + test-editor (submitted-to-permission test-editor :drafter:draft:claim) #{:claim} ;;submitted on claimed test-editor - (ds/claim (submitted-to-permission test-editor :draft:claim) test-publisher) + (ds/claim (submitted-to-permission test-editor :drafter:draft:claim) test-publisher) #{} ;;non-owner @@ -136,12 +136,12 @@ test-publisher (ds/submit-to-permission (ds/create-draftset "tmp@example.com") "tmp@example.com" - :draft:claim) + :drafter:draft:claim) #{:claim} ;;user doesn't have claim permission test-editor (ds/submit-to-permission (ds/create-draftset "tmp@example.com") "tmp@example.com" - :draft:publish) + :drafter:draft:publish) #{})) diff --git a/drafter/test/resources/drafter/feature/draftset/claimable-draftset-changes-2.trig b/drafter/test/resources/drafter/feature/draftset/claimable-draftset-changes-2.trig index ea8b1d84b..dc36635d5 100644 --- a/drafter/test/resources/drafter/feature/draftset/claimable-draftset-changes-2.trig +++ b/drafter/test/resources/drafter/feature/draftset/claimable-draftset-changes-2.trig @@ -95,9 +95,9 @@ draft:append-on-g2 { drafter:inDraftSet draftset:ds-2 . a drafter:Submission ; - drafter:claimPermission "draft:claim" . + drafter:claimPermission "drafter:draft:claim" . a drafter:Submission ; - drafter:claimPermission "draft:claim" . + drafter:claimPermission "drafter:draft:claim" . } diff --git a/drafter/test/resources/drafter/feature/draftset/claimable-draftset-changes.trig b/drafter/test/resources/drafter/feature/draftset/claimable-draftset-changes.trig index 10dc57773..0514cd55f 100644 --- a/drafter/test/resources/drafter/feature/draftset/claimable-draftset-changes.trig +++ b/drafter/test/resources/drafter/feature/draftset/claimable-draftset-changes.trig @@ -50,10 +50,10 @@ drafter:inDraftSet draftset:ds-2 . a drafter:Submission ; - drafter:claimPermission "draft:claim" . + drafter:claimPermission "drafter:draft:claim" . a drafter:Submission ; - drafter:claimPermission "draft:claim" . + drafter:claimPermission "drafter:draft:claim" . } { diff --git a/drafter/test/resources/drafter/feature/draftset/list_test-1-draftset-with-submission.trig b/drafter/test/resources/drafter/feature/draftset/list_test-1-draftset-with-submission.trig index 3524cbd60..c9e944018 100644 --- a/drafter/test/resources/drafter/feature/draftset/list_test-1-draftset-with-submission.trig +++ b/drafter/test/resources/drafter/feature/draftset/list_test-1-draftset-with-submission.trig @@ -21,6 +21,6 @@ draftset:4e7f444f-3e34-420e-9126-f9691aeb986b a drafter:DraftSet ; drafter:submittedBy . a drafter:Submission ; - drafter:claimPermission "draft:claim" . + drafter:claimPermission "drafter:draft:claim" . } diff --git a/drafter/test/resources/drafter/feature/draftset/list_test-2.trig b/drafter/test/resources/drafter/feature/draftset/list_test-2.trig index a322ce62d..31138f5cf 100644 --- a/drafter/test/resources/drafter/feature/draftset/list_test-2.trig +++ b/drafter/test/resources/drafter/feature/draftset/list_test-2.trig @@ -47,9 +47,9 @@ draftset:55660038-da9e-42d0-a40f-00d5fa4ef44d a drafter:DraftSet ; drafter:submittedBy . a drafter:Submission ; - drafter:claimPermission "draft:claim" . + drafter:claimPermission "drafter:draft:claim" . a drafter:Submission ; - drafter:claimPermission "draft:claim:manager" . + drafter:claimPermission "drafter:draft:claim:manager" . } diff --git a/drafter/test/resources/drafter/feature/draftset/list_test-unclaimable.trig b/drafter/test/resources/drafter/feature/draftset/list_test-unclaimable.trig index 75d22d43c..cb4424f07 100644 --- a/drafter/test/resources/drafter/feature/draftset/list_test-unclaimable.trig +++ b/drafter/test/resources/drafter/feature/draftset/list_test-unclaimable.trig @@ -38,5 +38,5 @@ drafter:hasOwner . a drafter:Submission ; - drafter:claimPermission "draft:publish" . + drafter:claimPermission "drafter:draft:publish" . } diff --git a/drafter/test/resources/drafter/feature/draftset/list_test-union-with-live.trig b/drafter/test/resources/drafter/feature/draftset/list_test-union-with-live.trig index 802f8dc55..ed4dc63f6 100644 --- a/drafter/test/resources/drafter/feature/draftset/list_test-union-with-live.trig +++ b/drafter/test/resources/drafter/feature/draftset/list_test-union-with-live.trig @@ -37,5 +37,5 @@ draftset:7f94456f-8a92-4d40-8691-2c32f89e9741 a drafter:DraftSet ; drafter:submittedBy . a drafter:Submission ; - drafter:claimPermission "draft:claim" . + drafter:claimPermission "drafter:draft:claim" . } diff --git a/drafter/test/resources/drafter/feature/endpoint/list_test-with-login.trig b/drafter/test/resources/drafter/feature/endpoint/list_test-with-login.trig index 130f8dad7..4acce4315 100644 --- a/drafter/test/resources/drafter/feature/endpoint/list_test-with-login.trig +++ b/drafter/test/resources/drafter/feature/endpoint/list_test-with-login.trig @@ -54,9 +54,9 @@ draftset:55660038-da9e-42d0-a40f-00d5fa4ef44d a drafter:DraftSet ; drafter:submittedBy . a drafter:Submission ; - drafter:claimPermission "draft:claim" . + drafter:claimPermission "drafter:draft:claim" . a drafter:Submission ; - drafter:claimPermission "draft:publish" . + drafter:claimPermission "drafter:draft:publish" . }