diff --git a/backend/src/app/loggers/audit.clj b/backend/src/app/loggers/audit.clj index 71cf7e1ae..deb58cfd4 100644 --- a/backend/src/app/loggers/audit.clj +++ b/backend/src/app/loggers/audit.clj @@ -101,12 +101,13 @@ (:name event) (:type event) (:profile-id event) + (some-> (:ip-addr event) db/inet) (db/tjson (:props event))])] (aa/with-thread executor (db/with-atomic [conn pool] (db/insert-multi! conn :audit-log - [:id :name :type :profile-id :props] + [:id :name :type :profile-id :ip-addr :props] (sequence (map event->row) events)))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -147,17 +148,22 @@ (defn archive-events [{:keys [pool uri tokens] :as cfg}] - (letfn [(decode-row [{:keys [props] :as row}] + (letfn [(decode-row [{:keys [props ip-addr] :as row}] (cond-> row (db/pgobject? props) - (assoc :props (db/decode-transit-pgobject props)))) + (assoc :props (db/decode-transit-pgobject props)) - (row->event [{:keys [name type created-at profile-id props]}] - {:type type - :name name - :timestamp created-at - :profile-id profile-id - :props props}) + (db/pgobject? ip-addr "inet") + (assoc :ip-addr (db/decode-inet ip-addr)))) + + (row->event [{:keys [name type created-at profile-id props ip-addr]}] + (cond-> {:type type + :name name + :timestamp created-at + :profile-id profile-id + :props props} + (some? ip-addr) + (update :context assoc :source-ip ip-addr))) (send [events] (let [token (tokens :generate {:iss "authentication" @@ -168,7 +174,7 @@ "origin" (cf/get :public-uri) "cookie" (u/map->query-string {:auth-token token})} params {:uri uri - :timeout 5000 + :timeout 6000 :method :post :headers headers :body body} @@ -187,7 +193,6 @@ (db/with-atomic [conn pool] (let [rows (db/exec! conn [sql:retrieve-batch-of-audit-log]) - xform (comp (map decode-row) (map row->event)) events (into [] xform rows)] diff --git a/backend/src/app/migrations.clj b/backend/src/app/migrations.clj index 022abb69b..f8decf5e3 100644 --- a/backend/src/app/migrations.clj +++ b/backend/src/app/migrations.clj @@ -184,6 +184,9 @@ {:name "0058-del-team-on-delete-trigger" :fn (mg/resource "app/migrations/sql/0058-del-team-on-delete-trigger.sql")} + + {:name "0059-mod-audit-log-table" + :fn (mg/resource "app/migrations/sql/0059-mod-audit-log-table.sql")} ]) diff --git a/backend/src/app/migrations/sql/0059-mod-audit-log-table.sql b/backend/src/app/migrations/sql/0059-mod-audit-log-table.sql new file mode 100644 index 000000000..1a2497a0a --- /dev/null +++ b/backend/src/app/migrations/sql/0059-mod-audit-log-table.sql @@ -0,0 +1,2 @@ +ALTER TABLE audit_log + ADD COLUMN ip_addr inet NULL; diff --git a/backend/src/app/rpc.clj b/backend/src/app/rpc.clj index 45598854d..947936940 100644 --- a/backend/src/app/rpc.clj +++ b/backend/src/app/rpc.clj @@ -32,9 +32,10 @@ [methods {:keys [profile-id] :as request}] (let [type (keyword (get-in request [:path-params :type])) - data (d/merge (:params request) - (:body-params request) - (:uploads request)) + data (merge (:params request) + (:body-params request) + (:uploads request) + {::request request}) data (if profile-id (assoc data :profile-id profile-id) @@ -50,12 +51,15 @@ (defn- rpc-mutation-handler [methods {:keys [profile-id] :as request}] (let [type (keyword (get-in request [:path-params :type])) - data (d/merge (:params request) - (:body-params request) - (:uploads request)) + data (merge (:params request) + (:body-params request) + (:uploads request) + {::request request}) + data (if profile-id (assoc data :profile-id profile-id) (dissoc data :profile-id)) + result ((get methods type default-handler) data) mdata (meta result)] (cond->> {:status 200 :body result} @@ -85,6 +89,11 @@ (rlm/execute rlinst (f cfg params)))) f)) +(defn- parse-client-ip + [{:keys [headers] :as request}] + (or (some-> (get headers "x-forwarded-for") (str/split ",") first) + (get headers "x-real-ip") + (get request :remote-addr))) (defn- wrap-impl [{:keys [audit] :as cfg} f mdata] @@ -95,15 +104,23 @@ (l/trace :action "register" :name (::sv/name mdata)) (fn [params] + + ;; Raise authentication error when rpc method requires auth but + ;; no profile-id is found in the request. (when (and auth? (not (uuid? (:profile-id params)))) (ex/raise :type :authentication :code :authentication-required :hint "authentication required for this endpoint")) - (let [params (us/conform spec params) - result (f cfg params) - resultm (meta result)] - (when (and (::type cfg) (fn? audit)) - (let [profile-id (or (:profile-id params) + + (let [params' (dissoc params ::request) + params' (us/conform spec params') + result (f cfg params')] + + ;; When audit log is enabled (default false). + (when (fn? audit) + (let [resultm (meta result) + request (::request params) + profile-id (or (:profile-id params') (:profile-id result) (::audit/profile-id resultm)) props (d/merge params (::audit/props resultm))] @@ -111,7 +128,9 @@ :name (or (::audit/name resultm) (::sv/name mdata)) :profile-id profile-id + :ip-addr (parse-client-ip request) :props props}))) + result)))) (defn- process-method