diff --git a/connector/README.md b/connector/README.md index 918a8f1..ed74b46 100644 --- a/connector/README.md +++ b/connector/README.md @@ -146,7 +146,7 @@ When it fails to connect to the downstream server, respond with Example: ```edn -[proxy "https://example.com"] +[proxy (str "https://example.com" (get request :uri))] ``` Note: this interceptor should always be the last in the list of @@ -319,6 +319,39 @@ Provide access to the last `:n-of-lines` (defaults to 100) lines of `:json-file` --- +`[org.bdinetwork.connector.interceptors/logger & [additional-props]]` + +Short name: `bdi/logger` + +Log incoming requests, response status and duration. + +Also logs BDI specific information: "client", +"delegation-evidence", "delegation-issues", "delegation-mask". + +Optional `additional-props` will be evaluated in the "leave" +phase and logged as diagnostic context, `props` should be a shallow +map with string keys. + +Example log messsage: + +``` +GET http://localhost:8081/ HTTP/1.1 / 200 OK / 370ms +``` + +Example with MDC: + +```edn +[bdi/logger {"ua" (get-in request [:headers "user-agent"])}] +``` + +Example log message: + +``` +GET http://localhost:8080/ HTTP/1.1 / 200 OK / 123ms status=200, uri="/", ua="curl/1.2.3" +``` + +--- + `[org.bdinetwork.connector.interceptors/noodlebar-delegation]` Short name: `bdi/noodlebar-delegation` @@ -329,6 +362,24 @@ not match the delegation mask. --- +`[org.bdinetwork.connector.interceptors/noodlebar-validate-policy {:keys [policy-issuer resource-type resource-identifier resource-attributes action]}]` + +Short name: `bdi/noodlebar-validate-policy` + +Retrieves and evaluates delegation evidence for request. +Responds with 403 Forbidden when the evidence is not found or does +not match the delegation mask. + +Derives some information from the request's Bearer token claims: + +The policy's target must match the bearer-token's :organizationId claim +The policy's service-provider must match the :aud claim + +Required keys: +policy-issuer, resource-type, resource-identifier, resource-attributes, action + +--- + `[(org.bdinetwork.connector.interceptors/set-bearer-token) {:keys [server-id base-url client-id private-key x5c association-id association-url path]}]` Short name: `bdi/set-bearer-token` @@ -408,7 +459,7 @@ The following example is protected by a basic authentication username / password [request update :headers assoc "authorization" #join ["Basic " #b64 #join [#env! "BACKEND_USER" ":" #env! "BACKEND_PASS"]]] [response update :headers assoc "x-bdi-connector" "passed"] - [proxy "http://backend:port/"]]} + [proxy (str "http://backend:port/" (get request :uri))]]} {:match {} :interceptors [[logger] diff --git a/connector/src/org/bdinetwork/connector/interceptors.clj b/connector/src/org/bdinetwork/connector/interceptors.clj index 0287462..d48c73a 100644 --- a/connector/src/org/bdinetwork/connector/interceptors.clj +++ b/connector/src/org/bdinetwork/connector/interceptors.clj @@ -15,6 +15,7 @@ [org.bdinetwork.ishare.client :as ishare-client] [org.bdinetwork.ishare.client.request :as ishare-request] [org.bdinetwork.ishare.client.validate-delegation :as validate-delegation] + [passage.interceptors :as passage] [passage.response :as response] [ring.middleware.json :as ring-json] [ring.middleware.params :as ring-params]) @@ -261,3 +262,82 @@ (assoc :response (-> response/forbidden (assoc-in [:headers "content-type"] "application/json") (assoc :body (json/json-str {:delegation-issues issues})))))))}) + +(def ^{:interceptor true + :expr-arglist '[{:keys [policy-issuer resource-type resource-identifier resource-attributes action]}]} + noodlebar-validate-policy + "Retrieves and evaluates delegation evidence for request. + Responds with 403 Forbidden when the evidence is not found or does + not match the delegation mask. + + Derives some information from the request's Bearer token claims: + + The policy's target must match the bearer-token's :organizationId claim + The policy's service-provider must match the :aud claim + + Required keys: + policy-issuer, resource-type, resource-identifier, resource-attributes, action" + (update noodlebar-delegation :enter + (fn noodlebar-policy-enter [enter] + (fn [ctx base-request {:keys [policy-issuer resource-type resource-identifier resource-attributes action]}] + (enter ctx + base-request + {:policyIssuer policy-issuer + :target {:accessSubject (get-in ctx [:oauth2/bearer-token-claims :organizationId])} + :policySets + [{:policies + [{:rules [{:effect "Permit"}] + :target + {:resource {:type resource-type + :identifiers [resource-identifier] + :attributes resource-attributes} + :actions [action] + :environment + {:serviceProviders [(get-in ctx [:oauth2/bearer-token-claims :aud])]}}}]}]}))))) + + + + +(def ^{:interceptor true + :expr-arglist '[& [additional-props]]} + logger + "Log incoming requests, response status and duration. + + Also logs BDI specific information: \"client\", + \"delegation-evidence\", \"delegation-issues\", \"delegation-mask\". + + Optional `additional-props` will be evaluated in the \"leave\" + phase and logged as diagnostic context, `props` should be a shallow + map with string keys. + + Example log messsage: + + ``` + GET http://localhost:8081/ HTTP/1.1 / 200 OK / 370ms + ``` + + Example with MDC: + + ```edn + [bdi/logger {\"ua\" (get-in request [:headers \"user-agent\"])}] + ``` + + Example log message: + + ``` + GET http://localhost:8080/ HTTP/1.1 / 200 OK / 123ms status=200, uri=\"/\", ua=\"curl/1.2.3\" + ```" + (-> passage/logger + (update :leave + (fn [leave] + (fn logger-leave + ([{:keys [request response] :as ctx} additional-props] + (leave ctx (merge {"uri" (get request :uri) + "status" (get response :status) + "client" (get-in ctx [:oauth2/bearer-token-claims :sub]) + "delegation-issues" (get ctx :delegation-issues) + "delegation-evidence" (get ctx :delegation-evidence) + "delegation-mask" (get ctx :delegation-mask)} + additional-props))) + ([ctx] + (logger-leave ctx nil)))))))