From f8d26675dfe0077628ee984aee2af733d9337189 Mon Sep 17 00:00:00 2001 From: flynn Date: Sat, 8 Jun 2019 17:43:48 +0200 Subject: [PATCH 1/9] convert info logs to debug to remove logging bloat --- project.clj | 8 +++---- resources/html/error.html | 1 - src/clj/cat/core.clj | 12 +++++------ src/clj/cat/handler.clj | 3 ++- src/clj/cat/moauth.clj | 7 +++--- src/clj/cat/routes/admin.clj | 41 ++++++++++++++++++++++++++++++++++++ src/clj/cat/routes/home.clj | 35 +++--------------------------- src/clj/cat/routes/oauth.clj | 37 +++++++++++++------------------- 8 files changed, 72 insertions(+), 72 deletions(-) create mode 100644 src/clj/cat/routes/admin.clj diff --git a/project.clj b/project.clj index e9393fb..5723c9b 100644 --- a/project.clj +++ b/project.clj @@ -44,7 +44,7 @@ :min-lein-version "2.0.0" - + :source-paths ["src/clj" "src/cljs" "src/cljc"] :test-paths ["test/clj"] :resource-paths ["resources" "target/cljsbuild"] @@ -63,7 +63,7 @@ :css-dirs ["resources/public/css"] :nrepl-middleware [cider/wrap-cljs-repl cider.piggieback/wrap-cljs-repl]} - + :profiles {:uberjar {:omit-source true @@ -81,8 +81,6 @@ :infer-externs true :closure-warnings {:externs-validation :off :non-standard-jsdoc :off}}}}} - - :aot :all :uberjar-name "cat.jar" :source-paths ["env/prod/clj"] @@ -134,7 +132,7 @@ :main "cat.doo-runner" :optimizations :whitespace :pretty-print true}}}}} - + :profiles/dev {} :profiles/test {}} diff --git a/resources/html/error.html b/resources/html/error.html index ac877c5..450c4e4 100644 --- a/resources/html/error.html +++ b/resources/html/error.html @@ -47,7 +47,6 @@ {% if message %}

{{message}}

{% endif %} - diff --git a/src/clj/cat/core.clj b/src/clj/cat/core.clj index 7b75d5f..b0bca9f 100644 --- a/src/clj/cat/core.clj +++ b/src/clj/cat/core.clj @@ -16,10 +16,10 @@ (mount/defstate ^{:on-reload :noop} http-server :start (http/start - (-> env - (assoc :handler #'handler/app) - (update :io-threads #(or % (* 2 (.availableProcessors (Runtime/getRuntime))))) - (update :port #(or (-> env :options :port) %)))) + (-> env + (assoc :handler #'handler/app) + (update :io-threads #(or % (* 2 (.availableProcessors (Runtime/getRuntime))))) + (update :port #(or (-> env :options :port) %)))) :stop (http/stop http-server)) @@ -32,10 +32,9 @@ (when repl-server (nrepl/stop repl-server))) - (defn stop-app [] (doseq [component (:stopped (mount/stop))] - (log/info component "stopped")) + (log/debug component "stopped")) (shutdown-agents)) (defn start-app [args] @@ -63,4 +62,3 @@ (System/exit 0)) :else (start-app args))) - diff --git a/src/clj/cat/handler.clj b/src/clj/cat/handler.clj index e42c95b..3a5918f 100644 --- a/src/clj/cat/handler.clj +++ b/src/clj/cat/handler.clj @@ -2,7 +2,8 @@ (:require [cat.middleware :as middleware] [cat.layout :refer [error-page]] [cat.routes.home :refer [home-routes]] - [cat.routes.oauth :refer [oauth-routes admin-routes]] + [cat.routes.oauth :refer [oauth-routes]] + [cat.routes.admin :refer [admin-routes]] [compojure.core :refer [routes wrap-routes]] [ring.util.http-response :as response] [compojure.route :as route] diff --git a/src/clj/cat/moauth.clj b/src/clj/cat/moauth.clj index 47b2ecd..2525800 100644 --- a/src/clj/cat/moauth.clj +++ b/src/clj/cat/moauth.clj @@ -18,8 +18,7 @@ ; To authorize, redirect the user to the sign in / grant page (defn- authorize-uri - [client-params ;csrf-token - ] + [client-params #_csrf-token] (str (:authorize-uri client-params) "?" @@ -41,7 +40,7 @@ "let the user authorize access by redirecting to the signin / grant page of the used oauth api" [] - (log/info "Oauth params: " (oauth2-params)) +; (log/info "Oauth params: " (oauth2-params)) (authorize-uri (oauth2-params))) (defn get-authentication-response @@ -50,7 +49,7 @@ (if (or true (= csrf-token state)) (try (do - (log/info "Requesting access token with code " code) + (log/debug "Requesting access token with code " code) (let [oauth2-params (oauth2-params) access-token (httpclient/post (:access-token-uri oauth2-params) {:form-params {:code code diff --git a/src/clj/cat/routes/admin.clj b/src/clj/cat/routes/admin.clj new file mode 100644 index 0000000..862ece4 --- /dev/null +++ b/src/clj/cat/routes/admin.clj @@ -0,0 +1,41 @@ +(ns cat.routes.admin + (:require [cat.db.core :refer [*db*] :as db] + [compojure.core :refer [defroutes GET POST]] + [struct.core :as st] + [clojure.tools.logging :as log] + [ring.util.http-response :as response])) + +(def user-schema + [[:name st/required st/string] + [:gender st/string]]) + +(def relation-schema + [[:from_id st/required st/integer-str] + [:to_id st/required st/integer-str]]) + +(defroutes admin-routes + (GET "/admin/enable" req (-> (response/found "/") + (assoc :session (assoc-in (:session req) [:user :admin :enabled] true)))) + (GET "/admin/disable" req (-> (response/found "/") + (assoc :session (assoc-in (:session req) [:user :admin :enabled] false)))) + + (POST "/relations" req + (let [data (:params req) [err result] (st/validate data relation-schema)] + (log/info "Post to " (:uri req)) + (if (nil? err) + (do + (db/create-relation! result) + (response/found "/")) + (do + (response/bad-request "Incorrect input"))))) + (POST "/users" req + (let [data (:params req)] + (log/info "Post to " (:uri req)) + (println data) + (if (st/valid? data user-schema) + (do + (db/create-user! (assoc data :zeusid nil)) + (response/found "/")) + (do + (response/bad-request "Incorrect input"))))) + ) \ No newline at end of file diff --git a/src/clj/cat/routes/home.clj b/src/clj/cat/routes/home.clj index 54456d1..a4f267a 100644 --- a/src/clj/cat/routes/home.clj +++ b/src/clj/cat/routes/home.clj @@ -9,14 +9,6 @@ [cat.layout :refer [error-page]] [clojure.string :as s])) -(def user-schema - [[:name st/required st/string] - [:gender st/string]]) - -(def relation-schema - [[:from_id st/required st/integer-str] - [:to_id st/required st/integer-str]]) - (def request_relation-schema [[:to_id st/required st/integer-str]]) @@ -53,7 +45,7 @@ rel-requests-out (seq (db/get-relation-requests-from-user {:from_id (:id user)})) rel-requests-in (seq (db/get-relation-requests-to-user {:to_id (:id user)})) non_requested_users (seq (filter (fn [other-user] (not (some (partial = (:id other-user)) (map :to_id rel-requests-out)))) other_users))] - (log/info (str "Session: " (:session req))) + (log/debug (str "Session: " (:session req))) ;(log/info (str "Relation requests: \n OUTGOING: " rel-requests-out "\n INCOMING: " rel-requests-in)) ;(log/info (str "User relations: " user-relations)) ;(log/info (str "Other Users: " other_users)) @@ -118,7 +110,7 @@ (if (nil? from-id) (response/found (error-page {:status 400 :title "No user id found in session"}))) - (log/info "Post to " (:uri req) "\n with data " result) + (log/debug "Post to " (:uri req) "\n with data " result) (if (nil? err) (do (log/debug "Create relation request") @@ -129,28 +121,7 @@ (do (log/debug "Relation request failed") (log/debug err) - (response/unprocessable-entity "Incorrect input"))))) - - ; TODO make bottom 2 admin protected - (POST "/relations" req - (let [data (:params req) [err result] (st/validate data relation-schema)] - (log/info "Post to " (:uri req)) - (if (nil? err) - (do - (db/create-relation! result) - (response/found "/")) - (do - (response/bad-request "Incorrect input"))))) - (POST "/users" req - (let [data (:params req)] - (log/info "Post to " (:uri req)) - (println data) - (if (st/valid? data user-schema) - (do - (db/create-user! (assoc data :zeusid nil)) - (response/found "/")) - (do - (response/bad-request "Incorrect input")))))) + (response/unprocessable-entity "Incorrect input")))))) diff --git a/src/clj/cat/routes/oauth.clj b/src/clj/cat/routes/oauth.clj index 671c62a..67570f7 100644 --- a/src/clj/cat/routes/oauth.clj +++ b/src/clj/cat/routes/oauth.clj @@ -10,13 +10,13 @@ (def admins [{:name "flynn" :zeusid 117}]) (defn set-user! [user session redirect-url] - (log/info "Set user in session: " user) + (log/debug "Set user in session: " user) (let [new-session (-> session (assoc :user user) (cond-> (some (partial = (select-keys user [:zeusid :name])) admins) - (-> - (assoc-in [:user :admin] {:enabled false}) - (assoc :identity "foo"))))] + (-> + (assoc-in [:user :admin] {:enabled false}) + (assoc :identity "foo"))))] (-> (found redirect-url) (assoc :session new-session)))) @@ -32,7 +32,7 @@ "Initiates the Twitter OAuth" [request] (let [reee (mo/authorize-api-uri)] - (log/info "authorize uri: " reee) + (log/debug "authorize uri: " reee) (-> reee found))) @@ -47,12 +47,12 @@ (assoc :flash {:denied true})) ; fetch the request token and do anything else you wanna do if not denied. (let [{:keys [access_token refresh_token]} (mo/get-authentication-response nil req_token)] - (log/info "Successfully fetched access-id: " access_token) - (log/info "Fetching user info") + (log/debug "Successfully fetched access-id: " access_token) + (log/debug "Fetching user info") (let [fetched-user (mo/get-user-info access_token)] - (log/info "Fetched user info: " fetched-user) + (log/debug "Fetched user info: " fetched-user) (let [local-user (db/get-zeus-user {:zeusid (:id fetched-user)})] - (log/info "Zeus user from db: " local-user) + (log/debug "Zeus user from db: " local-user) (if local-user (set-user! local-user session "/") (try @@ -60,16 +60,15 @@ :gender nil :zeusid (:id fetched-user)} generated-key (-> user-template - (db/create-user!,,,))] - (log/info "Created user: " generated-key) + (db/create-user!))] + (log/debug "Created user: " generated-key) (set-user! (assoc user-template :id (:generated_key generated-key)) session "/")) (catch Exception e (do (log/warn "fetched user" fetched-user "already exists, but was not found") (log/warn (:cause (Throwable->map e))) (-> (found "/") - (assoc :flash {:error "An error occurred, please try again."}))) - )))))))) + (assoc :flash {:error "An error occurred, please try again."}))))))))))) ;(catch [:status 401] _ ; (error-page {:status 401 @@ -78,12 +77,6 @@ (defroutes oauth-routes - (GET "/oauth/oauth-init" req (oauth-init req)) - (GET "/oauth/oauth-callback" [& req_token :as req] (oauth-callback req_token req)) - (GET "/logout" req (clear-session! "/"))) - -(defroutes admin-routes - (GET "/admin/enable" req (-> (found "/") - (assoc :session (assoc-in (:session req) [:user :admin :enabled] true)))) - (GET "/admin/disable" req (-> (found "/") - (assoc :session (assoc-in (:session req) [:user :admin :enabled] false))))) \ No newline at end of file + (GET "/oauth/oauth-init" req (oauth-init req)) + (GET "/oauth/oauth-callback" [& req_token :as req] (oauth-callback req_token req)) + (GET "/logout" req (clear-session! "/"))) From 9d7ebbd23ed7989f8c8e9a612a35499555c5e84b Mon Sep 17 00:00:00 2001 From: flynn Date: Sat, 8 Jun 2019 18:32:20 +0200 Subject: [PATCH 2/9] another log fix --- run_jar_with_dev.sh => run_jar_with_config.sh | 2 +- src/clj/cat/moauth.clj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename run_jar_with_dev.sh => run_jar_with_config.sh (94%) diff --git a/run_jar_with_dev.sh b/run_jar_with_config.sh similarity index 94% rename from run_jar_with_dev.sh rename to run_jar_with_config.sh index 2bdcb6e..e801d7b 100755 --- a/run_jar_with_dev.sh +++ b/run_jar_with_config.sh @@ -12,4 +12,4 @@ export OAUTH_CONSUMER_SECRET="blargh" java \ -Dlogback.configurationFile=env/dev/resources/logback.xml \ - -jar target/uberjar/cat.jar \ No newline at end of file + -jar target/uberjar/cat.jar diff --git a/src/clj/cat/moauth.clj b/src/clj/cat/moauth.clj index 2525800..27655b9 100644 --- a/src/clj/cat/moauth.clj +++ b/src/clj/cat/moauth.clj @@ -61,7 +61,7 @@ :as :json :insecure? true })] - (println "Access token response:" access-token) + (log/debug "Access token response:" access-token) (:body access-token))) (catch Exception e (log/error "Something terrible happened..." e))) nil)) From af90e8639a79071f6a6c0339cd7cab48cbc6cf27 Mon Sep 17 00:00:00 2001 From: flynn Date: Sat, 8 Jun 2019 19:45:39 +0200 Subject: [PATCH 3/9] remove unneeded logs --- resources/html/home.html | 2 +- src/clj/cat/routes/oauth.clj | 48 +++++++++++++++++++----------------- 2 files changed, 26 insertions(+), 24 deletions(-) diff --git a/resources/html/home.html b/resources/html/home.html index 642e728..a63c614 100644 --- a/resources/html/home.html +++ b/resources/html/home.html @@ -71,7 +71,7 @@ Enable admin - {%endif%} + {% endif %} {% endif %} {% if user %} diff --git a/src/clj/cat/routes/oauth.clj b/src/clj/cat/routes/oauth.clj index 67570f7..82b6ea8 100644 --- a/src/clj/cat/routes/oauth.clj +++ b/src/clj/cat/routes/oauth.clj @@ -46,35 +46,37 @@ (-> (found "/") (assoc :flash {:denied true})) ; fetch the request token and do anything else you wanna do if not denied. - (let [{:keys [access_token refresh_token]} (mo/get-authentication-response nil req_token)] - (log/debug "Successfully fetched access-id: " access_token) - (log/debug "Fetching user info") - (let [fetched-user (mo/get-user-info access_token)] - (log/debug "Fetched user info: " fetched-user) - (let [local-user (db/get-zeus-user {:zeusid (:id fetched-user)})] - (log/debug "Zeus user from db: " local-user) - (if local-user - (set-user! local-user session "/") - (try - (let [user-template {:name (:username fetched-user) - :gender nil - :zeusid (:id fetched-user)} - generated-key (-> user-template - (db/create-user!))] - (log/debug "Created user: " generated-key) - (set-user! (assoc user-template :id (:generated_key generated-key)) session "/")) - (catch Exception e - (do - (log/warn "fetched user" fetched-user "already exists, but was not found") - (log/warn (:cause (Throwable->map e))) - (-> (found "/") - (assoc :flash {:error "An error occurred, please try again."}))))))))))) + (let [{:keys [access_token refresh_token]} (mo/get-authentication-response nil req_token) + fetched-user (mo/get-user-info access_token) + local-user (db/get-zeus-user {:zeusid (:id fetched-user)})] + (if local-user + (set-user! local-user session "/") + (try + (let [user-template {:name (:username fetched-user) + :gender nil + :zeusid (:id fetched-user)} + generated-key (-> user-template + (db/create-user!))] + (set-user! (assoc user-template :id (:generated_key generated-key)) session "/")) + (catch Exception e + (do + (log/warn "fetched user" fetched-user "already exists, but was not found") + (log/warn (:cause (Throwable->map e))) + (-> (found "/") + (assoc :flash {:error "An error occurred, please try again."}))))))))) ;(catch [:status 401] _ ; (error-page {:status 401 ; :title "Error authenticating" ; :message "Please contact your system administrator to fix this issue"})) +; TODO catch using +;(defn multiple-status-endpoint [req] +; (let [resp (do-external-request req)] +; (condp = (:status resp) +; 201 (println ok) +; 401 (println error)))) + (defroutes oauth-routes (GET "/oauth/oauth-init" req (oauth-init req)) From fd54e61a49d534187f3b6bc1522c4d0dad32c8f1 Mon Sep 17 00:00:00 2001 From: flynn Date: Sat, 8 Jun 2019 23:51:04 +0200 Subject: [PATCH 4/9] better error handling for oauth restructure route handlers --- project.clj | 18 +++++----- src/clj/cat/handler.clj | 48 +++++++++++++++++---------- src/clj/cat/moauth.clj | 64 +++++++++++++++++++----------------- src/clj/cat/routes/admin.clj | 50 ++++++++++++++-------------- src/clj/cat/routes/oauth.clj | 11 +++---- 5 files changed, 100 insertions(+), 91 deletions(-) diff --git a/project.clj b/project.clj index 5723c9b..77f2515 100644 --- a/project.clj +++ b/project.clj @@ -1,17 +1,19 @@ (defproject cat "0.1.0-SNAPSHOT" :description "A cuddle graph for zeus people" - ;:url "http://example.com/FIXME" + ;:url "http://example.com/FIXME" :dependencies [[buddy "2.0.0"] - [com.cemerick/friend "0.2.3"] [cheshire "5.8.1"] [clj-oauth "1.5.5"] [clojure.java-time "0.3.2"] + [com.cemerick/friend "0.2.3"] [com.cognitect/transit-clj "0.8.313"] + [com.google.protobuf/protobuf-java "3.6.1"] [compojure "1.6.1"] [conman "0.8.3"] [cprop "0.1.13"] + [funcool/promesa "1.9.0"] [funcool/struct "1.3.0"] [luminus-immutant "0.2.4"] [luminus-migrations "0.6.3"] @@ -20,17 +22,16 @@ [markdown-clj "1.0.5"] [metosin/muuntaja "0.6.3"] [metosin/ring-http-response "0.9.1"] - [slingshot "0.12.1"] + [metosin/vega-tools "0.2.0"] [mount "0.1.15"] + [mysql/mysql-connector-java "8.0.12"] [nrepl "0.5.3"] [org.clojure/clojure "1.10.0"] [org.clojure/clojurescript "1.10.439" :scope "provided"] [org.clojure/tools.cli "0.4.1"] [org.clojure/tools.logging "0.4.1"] - ;[org.postgresql/postgresql "42.2.5"] - [mysql/mysql-connector-java "8.0.12"] - [com.google.protobuf/protobuf-java "3.6.1"] - ;https://www.webjars.org/ + ;[org.postgresql/postgresql "42.2.5"] + ;https://www.webjars.org/ [org.webjars.npm/bulma "0.7.2"] [org.webjars/font-awesome "5.6.1"] [org.webjars/webjars-locator "0.34"] @@ -38,8 +39,7 @@ [ring/ring-core "1.7.1"] [ring/ring-defaults "0.3.2"] [selmer "1.12.5"] - [metosin/vega-tools "0.2.0"] - [funcool/promesa "1.9.0"]] + [slingshot "0.12.1"]] diff --git a/src/clj/cat/handler.clj b/src/clj/cat/handler.clj index 3a5918f..c03c964 100644 --- a/src/clj/cat/handler.clj +++ b/src/clj/cat/handler.clj @@ -2,30 +2,42 @@ (:require [cat.middleware :as middleware] [cat.layout :refer [error-page]] [cat.routes.home :refer [home-routes]] - [cat.routes.oauth :refer [oauth-routes]] - [cat.routes.admin :refer [admin-routes]] - [compojure.core :refer [routes wrap-routes]] + [cat.routes.oauth :refer [oauth-init oauth-callback clear-session!]] + [cat.routes.admin :refer [set-admin! create-new-relation! create-user!]] + [compojure.core :refer [routes defroutes GET POST wrap-routes]] [ring.util.http-response :as response] [compojure.route :as route] [cat.env :refer [defaults]] + [clojure.tools.logging :as log] [mount.core :as mount])) (mount/defstate init-app - :start ((or (:init defaults) identity)) - :stop ((or (:stop defaults) identity))) + :start ((or (:init defaults) identity)) + :stop ((or (:stop defaults) identity))) + +(defroutes oauth-routes + (GET "/oauth/oauth-init" req (oauth-init req)) + (GET "/oauth/oauth-callback" req (oauth-callback req)) + (GET "/logout" req (clear-session! "/"))) + +(defroutes admin-routes + (GET "/admin/enable" req (set-admin! req true)) + (GET "/admin/disable" req (set-admin! req false)) + (POST "/relations" req (create-new-relation! req)) + (POST "/users" req (create-user! req))) (mount/defstate app - :start - (middleware/wrap-base - (routes - (-> #'home-routes - (wrap-routes middleware/wrap-csrf) - (wrap-routes middleware/wrap-formats)) - #'oauth-routes - (-> #'admin-routes - (wrap-routes middleware/wrap-restricted)) - (route/not-found - (:body - (error-page {:status 404 - :title "page not found"})))))) + :start + (middleware/wrap-base + (routes + (-> #'home-routes + (wrap-routes middleware/wrap-csrf) + (wrap-routes middleware/wrap-formats)) + #'oauth-routes + (-> #'admin-routes + (wrap-routes middleware/wrap-restricted)) + (route/not-found + (:body + (error-page {:status 404 + :title "page not found"})))))) diff --git a/src/clj/cat/moauth.clj b/src/clj/cat/moauth.clj index 27655b9..191d020 100644 --- a/src/clj/cat/moauth.clj +++ b/src/clj/cat/moauth.clj @@ -12,19 +12,19 @@ :client-secret (env :oauth-consumer-secret) :authorize-uri (env :authorize-uri) :redirect-uri (str (env :app-host) "/oauth/oauth-callback") - :access-token-uri (env :access-token-uri) - }) + :access-token-uri (env :access-token-uri)}) ; To authorize, redirect the user to the sign in / grant page + (defn- authorize-uri [client-params #_csrf-token] (str - (:authorize-uri client-params) - "?" - (httpclient/generate-query-string {:response_type "code" - :client_id (:client-id client-params) - :redirect_uri (:redirect-uri client-params)}) + (:authorize-uri client-params) + "?" + (httpclient/generate-query-string {:response_type "code" + :client_id (:client-id client-params) + :redirect_uri (:redirect-uri client-params)}) ;"response_type=code" ;"&client_id=" ;(url-encode (:client-id client-params)) @@ -34,7 +34,7 @@ ;(url-encode (:scope client-params)) ;"&state=" ;(url-encode csrf-token) - )) + )) (defn authorize-api-uri "let the user authorize access by redirecting to the signin / grant page @@ -51,20 +51,21 @@ (do (log/debug "Requesting access token with code " code) (let [oauth2-params (oauth2-params) - access-token (httpclient/post (:access-token-uri oauth2-params) + resp (httpclient/post (:access-token-uri oauth2-params) {:form-params {:code code :grant_type "authorization_code" :client_id (:client-id oauth2-params) :client_secret (:client-secret oauth2-params) :redirect_uri (:redirect-uri oauth2-params)} - ;:basic-auth [(:client-id oauth2-params) (:client-secret oauth2-params)] :as :json - :insecure? true - })] - (log/debug "Access token response:" access-token) - (:body access-token))) - (catch Exception e (log/error "Something terrible happened..." e))) - nil)) + :throw-exceptions false + :insecure? true})] + (condp = (:status resp) + 200 (:body resp) + 401 (-> {:status 401 :body "Invalid authentication credentials"}) + {:status 500 :body "Something went pear-shape when trying to authenticate"}))) + ) + (log/info "Invalid csrf token whilst authenticating"))) (defn get-user-info "User info API call" @@ -73,30 +74,31 @@ (-> (httpclient/get url {:oauth-token access-token :as :json :insecure? true}) - :body) - )) + :body))) ; Refresh token when it expires + + (defn- refresh-tokens "Request a new token pair" [refresh-token] (try+ - (let [oauth2-params (oauth2-params) - {{access-token :access_token refresh-token :refresh_token} :body} - (httpclient/post (:access-token-uri oauth2-params) - {:form-params {:grant_type "refresh_token" - :refresh_token refresh-token} - :basic-auth [(:client-id oauth2-params) (:client-secret oauth2-params)] - :as :json - :insecure? true})] - [access-token refresh-token]) - (catch [:status 401] _ nil))) + (let [oauth2-params (oauth2-params) + {{access-token :access_token refresh-token :refresh_token} :body} + (httpclient/post (:access-token-uri oauth2-params) + {:form-params {:grant_type "refresh_token" + :refresh_token refresh-token} + :basic-auth [(:client-id oauth2-params) (:client-secret oauth2-params)] + :as :json + :insecure? true})] + [access-token refresh-token]) + (catch [:status 401] _ nil))) (defn get-fresh-tokens "Returns current token pair if they have not expired, or a refreshed token pair otherwise" [access-token refresh-token] (try+ - (and (get-user-info access-token) - [access-token refresh-token]) - (catch [:status 401] _ (refresh-tokens refresh-token)))) + (and (get-user-info access-token) + [access-token refresh-token]) + (catch [:status 401] _ (refresh-tokens refresh-token)))) diff --git a/src/clj/cat/routes/admin.clj b/src/clj/cat/routes/admin.clj index 862ece4..d60dfd0 100644 --- a/src/clj/cat/routes/admin.clj +++ b/src/clj/cat/routes/admin.clj @@ -1,6 +1,5 @@ (ns cat.routes.admin (:require [cat.db.core :refer [*db*] :as db] - [compojure.core :refer [defroutes GET POST]] [struct.core :as st] [clojure.tools.logging :as log] [ring.util.http-response :as response])) @@ -13,29 +12,28 @@ [[:from_id st/required st/integer-str] [:to_id st/required st/integer-str]]) -(defroutes admin-routes - (GET "/admin/enable" req (-> (response/found "/") - (assoc :session (assoc-in (:session req) [:user :admin :enabled] true)))) - (GET "/admin/disable" req (-> (response/found "/") - (assoc :session (assoc-in (:session req) [:user :admin :enabled] false)))) +(defn set-admin! [req enabled?] + (-> (response/found "/") + (assoc :session (assoc-in (:session req) [:user :admin :enabled] enabled?)))) - (POST "/relations" req - (let [data (:params req) [err result] (st/validate data relation-schema)] - (log/info "Post to " (:uri req)) - (if (nil? err) - (do - (db/create-relation! result) - (response/found "/")) - (do - (response/bad-request "Incorrect input"))))) - (POST "/users" req - (let [data (:params req)] - (log/info "Post to " (:uri req)) - (println data) - (if (st/valid? data user-schema) - (do - (db/create-user! (assoc data :zeusid nil)) - (response/found "/")) - (do - (response/bad-request "Incorrect input"))))) - ) \ No newline at end of file +(defn create-new-relation! [req] + (let [data (:params req) + [err result] (st/validate data relation-schema)] + (if (nil? err) + (do + (log/info "Admin creates relation from " (:from_id data) "to" (:to_id data)) + (db/create-relation! result) + (response/found "/")) + (do + (response/bad-request "Incorrect input"))))) + +(defn create-user! [req] + (let [data (:params req)] + (println data) + (if (st/valid? data user-schema) + (do + (log/info "Admin creates user: " (:name data)) + (db/create-user! (assoc data :zeusid nil)) + (response/found "/")) + (do + (response/bad-request "Incorrect input"))))) diff --git a/src/clj/cat/routes/oauth.clj b/src/clj/cat/routes/oauth.clj index 82b6ea8..b76247b 100644 --- a/src/clj/cat/routes/oauth.clj +++ b/src/clj/cat/routes/oauth.clj @@ -29,7 +29,7 @@ (assoc :session nil))) (defn oauth-init - "Initiates the Twitter OAuth" + "Initiates the OAuth" [request] (let [reee (mo/authorize-api-uri)] (log/debug "authorize uri: " reee) @@ -40,13 +40,14 @@ "Handles the callback from adams with the access_token Fetches the user from the database, creating a new one if not found Sets the user in the session and redirects back to origin \"/\" " - [req_token {:keys [params session]}] + + [{:keys [params session]}] ; oauth request was denied by user (if (:denied params) (-> (found "/") (assoc :flash {:denied true})) ; fetch the request token and do anything else you wanna do if not denied. - (let [{:keys [access_token refresh_token]} (mo/get-authentication-response nil req_token) + (let [{:keys [access_token refresh_token]} (mo/get-authentication-response nil params) fetched-user (mo/get-user-info access_token) local-user (db/get-zeus-user {:zeusid (:id fetched-user)})] (if local-user @@ -78,7 +79,3 @@ ; 401 (println error)))) -(defroutes oauth-routes - (GET "/oauth/oauth-init" req (oauth-init req)) - (GET "/oauth/oauth-callback" [& req_token :as req] (oauth-callback req_token req)) - (GET "/logout" req (clear-session! "/"))) From 8ac33ad8299ae9cbafbdd3353796cde71bd57342 Mon Sep 17 00:00:00 2001 From: flynn Date: Sun, 9 Jun 2019 00:01:51 +0200 Subject: [PATCH 5/9] cleanup middleware wrapping --- src/clj/cat/handler.clj | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/clj/cat/handler.clj b/src/clj/cat/handler.clj index c03c964..60677a0 100644 --- a/src/clj/cat/handler.clj +++ b/src/clj/cat/handler.clj @@ -26,18 +26,20 @@ (POST "/relations" req (create-new-relation! req)) (POST "/users" req (create-user! req))) +(defroutes app-routes + (-> home-routes + middleware/wrap-csrf + middleware/wrap-formats) + (-> oauth-routes) + (-> admin-routes + middleware/wrap-restricted) + (route/not-found + (:body + (error-page {:status 404 + :title "page not found"})))) + (mount/defstate app :start - (middleware/wrap-base - (routes - (-> #'home-routes - (wrap-routes middleware/wrap-csrf) - (wrap-routes middleware/wrap-formats)) - #'oauth-routes - (-> #'admin-routes - (wrap-routes middleware/wrap-restricted)) - (route/not-found - (:body - (error-page {:status 404 - :title "page not found"})))))) + (-> app-routes + middleware/wrap-base)) From 048266f0aa2aa742209c6ed3c17ef7094d67cc96 Mon Sep 17 00:00:00 2001 From: flynn Date: Sun, 9 Jun 2019 00:52:31 +0200 Subject: [PATCH 6/9] add role list to session --- src/clj/cat/routes/oauth.clj | 1 + 1 file changed, 1 insertion(+) diff --git a/src/clj/cat/routes/oauth.clj b/src/clj/cat/routes/oauth.clj index b76247b..16408a9 100644 --- a/src/clj/cat/routes/oauth.clj +++ b/src/clj/cat/routes/oauth.clj @@ -16,6 +16,7 @@ (cond-> (some (partial = (select-keys user [:zeusid :name])) admins) (-> (assoc-in [:user :admin] {:enabled false}) + (assoc-in [:user :roles] #{:admin}) (assoc :identity "foo"))))] (-> (found redirect-url) (assoc :session new-session)))) From 8a471893f5716cf6c7f53cb552bfeab06deb496e Mon Sep 17 00:00:00 2001 From: flynn Date: Sun, 9 Jun 2019 00:53:13 +0200 Subject: [PATCH 7/9] restructure home routes --- src/clj/cat/handler.clj | 18 +++- src/clj/cat/routes/home.clj | 187 +++++++++++++++++------------------- 2 files changed, 103 insertions(+), 102 deletions(-) diff --git a/src/clj/cat/handler.clj b/src/clj/cat/handler.clj index 60677a0..398a4ca 100644 --- a/src/clj/cat/handler.clj +++ b/src/clj/cat/handler.clj @@ -1,7 +1,7 @@ (ns cat.handler (:require [cat.middleware :as middleware] [cat.layout :refer [error-page]] - [cat.routes.home :refer [home-routes]] + [cat.routes.home :refer [show-home show-relations update-relationrequest-status create-relation-request]] [cat.routes.oauth :refer [oauth-init oauth-callback clear-session!]] [cat.routes.admin :refer [set-admin! create-new-relation! create-user!]] [compojure.core :refer [routes defroutes GET POST wrap-routes]] @@ -15,6 +15,14 @@ :start ((or (:init defaults) identity)) :stop ((or (:stop defaults) identity))) +(defroutes public-routes + (GET "/" req (show-home req)) + (GET "/relations_zeroed" [] (show-relations))) + +(defroutes user-routes + (POST "/relation_request/:id/status" [id & body] (update-relationrequest-status id body)) ; STATUS ENUM: (open, accepted, rejected) + (POST "/request_relation" req (create-relation-request req))) + (defroutes oauth-routes (GET "/oauth/oauth-init" req (oauth-init req)) (GET "/oauth/oauth-callback" req (oauth-callback req)) @@ -27,12 +35,12 @@ (POST "/users" req (create-user! req))) (defroutes app-routes - (-> home-routes + (-> public-routes middleware/wrap-csrf middleware/wrap-formats) - (-> oauth-routes) - (-> admin-routes - middleware/wrap-restricted) + user-routes + oauth-routes + admin-routes (route/not-found (:body (error-page {:status 404 diff --git a/src/clj/cat/routes/home.clj b/src/clj/cat/routes/home.clj index a4f267a..ed82c75 100644 --- a/src/clj/cat/routes/home.clj +++ b/src/clj/cat/routes/home.clj @@ -12,118 +12,111 @@ (def request_relation-schema [[:to_id st/required st/integer-str]]) -(defn home-page [params] +(defn- home-page [params] (layout/render "home.html" params)) -(defn get-relations [] +(defn- get-relations [] (map - (fn [relation] (select-keys relation [:name :name_2])) - (db/get-relations))) + (fn [relation] (select-keys relation [:name :name_2])) + (db/get-relations))) -(defn get-users [] +(defn- get-users [] (db/get-users)) -(defn response-wrong-parameters [] +(defn- response-wrong-parameters [] (error-page {:status 400 :title "Wrong request parameters" :message "Please contact your system administrator to fix this issue"})) -(defroutes home-routes - (GET "/" req - (let [users (get-users) - relations (get-relations) - user (-> (get-in req [:session :user])) - user-relations (when user - (seq (filter (fn [rel] - (or - (= (:name rel) (:name user)) - (= (:name_2 rel) (:name user)))) - relations))) - other_users (when user - (seq (filter (fn [usr] (not (= (:id usr) (:id user)))) - users))) - rel-requests-out (seq (db/get-relation-requests-from-user {:from_id (:id user)})) - rel-requests-in (seq (db/get-relation-requests-to-user {:to_id (:id user)})) - non_requested_users (seq (filter (fn [other-user] (not (some (partial = (:id other-user)) (map :to_id rel-requests-out)))) other_users))] - (log/debug (str "Session: " (:session req))) +(defn show-home [req] + (let [users (get-users) + relations (get-relations) + user (-> (get-in req [:session :user])) + user-relations (when user + (seq (filter (fn [rel] + (or + (= (:name rel) (:name user)) + (= (:name_2 rel) (:name user)))) + relations))) + other_users (when user + (seq (filter (fn [usr] (not (= (:id usr) (:id user)))) + users))) + rel-requests-out (seq (db/get-relation-requests-from-user {:from_id (:id user)})) + rel-requests-in (seq (db/get-relation-requests-to-user {:to_id (:id user)})) + non_requested_users (seq (filter (fn [other-user] (not (some (partial = (:id other-user)) (map :to_id rel-requests-out)))) other_users))] + (log/debug (str "Session: " (:session req))) ;(log/info (str "Relation requests: \n OUTGOING: " rel-requests-out "\n INCOMING: " rel-requests-in)) ;(log/info (str "User relations: " user-relations)) ;(log/info (str "Other Users: " other_users)) ;(log/info (str "rel reqs out: " rel-requests-out)) ;(log/info (str "rel reqs out id: " (seq (map :to_id rel-requests-out)))) - (home-page {:relations relations - :users users - :user user - :user-relations user-relations - :rel-requests-out rel-requests-out - :rel-requests-in rel-requests-in - :non_requested_users non_requested_users - :flash (:flash req)}))) - ;(GET "/docs" [] - ; (-> (response/ok (-> "docs/docs.md" io/resource slurp)) - ; (response/header "Content-Type" "text/plain; charset=utf-8"))) - (GET "/relations" [] - (let [] - (response/ok {}))) - (GET "/relations_zeroed" [] - (let [users (db/get-users) - relations (db/get-relations) - used-node-ids (set (flatten (map (fn [ln] [(:from_id ln) (:to_id ln)]) relations))) - filtered-users (filter (fn [{id :id}] (contains? used-node-ids id)) users) - id-index-map (:map (reduce (fn [{map :map idx :index} usr] - {:map (assoc map (:id usr) idx) - :index (inc idx)}) - {:map {} :index 0} - filtered-users)) - rels-indexed (map (fn [{src :from_id target :to_id}] - {:source (get id-index-map src) - :target (get id-index-map target) - :value (+ 20 (rand-int 30))}) - relations) - nodes-indexed (->> filtered-users - (map (fn [usr] - (-> usr - (dissoc :gender :id) - (assoc :index (get id-index-map (:id usr))) - (assoc :group (rand-int 5))))))] - (response/ok {:nodes nodes-indexed - :links rels-indexed}))) - - ; TODO make next 2 user protected - (POST "/relation_request/:id/status" [id & body] - (let [rr_id_map {:id id} - success (cond - (contains? body :accept) (do - (let [rr (db/get-relation-request rr_id_map)] - (db/create-relation! {:from_id (:from_id rr) :to_id (:to_id rr)})) - (db/update-relation-request-status! (assoc rr_id_map :status "accepted"))) - (contains? body :decline) (db/update-relation-request-status! (assoc rr_id_map :status "declined")) - :else false)] - (if success - (response/found "/") - (response-wrong-parameters)))) - ; STATUS ENUM: (open, accepted, rejected) - (POST "/request_relation" req - (let [data (:params req) - [err result] (st/validate data request_relation-schema) - from-id (get-in req [:session :user :id])] - (if (nil? from-id) (response/found (error-page - {:status 400 - :title "No user id found in session"}))) - (log/debug "Post to " (:uri req) "\n with data " result) - (if (nil? err) - (do - (log/debug "Create relation request") - (db/create-relation-request! {:from_id from-id - :to_id (:to_id result) - :status "open"}) - (response/found "/")) - (do - (log/debug "Relation request failed") - (log/debug err) - (response/unprocessable-entity "Incorrect input")))))) - - + (home-page {:relations relations + :users users + :user user + :user-relations user-relations + :rel-requests-out rel-requests-out + :rel-requests-in rel-requests-in + :non_requested_users non_requested_users + :flash (:flash req)}))) +(defn show-relations + [] + (let [users (db/get-users) + relations (db/get-relations) + used-node-ids (set (flatten (map (fn [ln] [(:from_id ln) (:to_id ln)]) relations))) + filtered-users (filter (fn [{id :id}] (contains? used-node-ids id)) users) + id-index-map (:map (reduce (fn [{map :map idx :index} usr] + {:map (assoc map (:id usr) idx) + :index (inc idx)}) + {:map {} :index 0} + filtered-users)) + rels-indexed (map (fn [{src :from_id target :to_id}] + {:source (get id-index-map src) + :target (get id-index-map target) + :value (+ 20 (rand-int 30))}) + relations) + nodes-indexed (->> filtered-users + (map (fn [usr] + (-> usr + (dissoc :gender :id) + (assoc :index (get id-index-map (:id usr))) + (assoc :group (rand-int 5))))))] + (response/ok {:nodes nodes-indexed + :links rels-indexed}))) +(defn update-relationrequest-status + [id body] + (let [rr_id_map {:id id} + success (cond + (contains? body :accept) + (do + (let [rr (db/get-relation-request rr_id_map)] + (db/create-relation! {:from_id (:from_id rr) :to_id (:to_id rr)})) + (db/update-relation-request-status! (assoc rr_id_map :status "accepted"))) + (contains? body :decline) + (db/update-relation-request-status! (assoc rr_id_map :status "declined")) + :else false)] + (if success + (response/found "/") + (response-wrong-parameters)))) +(defn create-relation-request + [req] + (let [data (:params req) + [err result] (st/validate data request_relation-schema) + from-id (get-in req [:session :user :id])] + (if (nil? from-id) (response/found (error-page + {:status 400 + :title "No user id found in session"}))) + (log/debug "Post to " (:uri req) "\n with data " result) + (if (nil? err) + (do + (log/debug "Create relation request") + (db/create-relation-request! {:from_id from-id + :to_id (:to_id result) + :status "open"}) + (response/found "/")) + (do + (log/debug "Relation request failed") + (log/debug err) + (response/unprocessable-entity "Incorrect input"))))) From f220856e39d994a268f53ad204eba57a00305f3c Mon Sep 17 00:00:00 2001 From: flynn Date: Sun, 9 Jun 2019 00:53:42 +0200 Subject: [PATCH 8/9] add auth rules, only basic admin for now --- src/clj/cat/middleware.clj | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/src/clj/cat/middleware.clj b/src/clj/cat/middleware.clj index 92e8c72..2f7abb9 100644 --- a/src/clj/cat/middleware.clj +++ b/src/clj/cat/middleware.clj @@ -18,7 +18,6 @@ [buddy.auth.backends.session :refer [session-backend]]) (:import)) - (defn wrap-internal-error [handler] (fn [req] (try @@ -31,12 +30,11 @@ (defn wrap-csrf [handler] (wrap-anti-forgery - handler - {:error-response - (error-page - {:status 403 - :title "Invalid anti-forgery token"})})) - + handler + {:error-response + (error-page + {:status 403 + :title "Invalid anti-forgery token"})})) (defn wrap-formats [handler] (let [wrapped (-> handler wrap-params (wrap-format formats/instance))] @@ -45,10 +43,24 @@ ;; since they're not compatible with this middleware ((if (:websocket? request) handler wrapped) request)))) +;; Authentication + +(defn admin-access [req] + (contains? (get-in req [:session :user :roles]) :admin)) + +(def rules [{:pattern #"^/admin/.*" + :handler admin-access} + ; TODO add other auth schemes + ;{:pattern [#"^/$" #"^/oauth/.*"] + ; :handler any-access} + ;{:pattern #"^/.*" + ; :handler user-access} + ]) + (defn on-error [request response] (error-page - {:status 403 - :title (str "Access to " (:uri request) " is not authorized")})) + {:status 403 + :title (str "Access to " (:uri request) " is not authorised")})) (defn wrap-restricted [handler] (restrict handler {:handler authenticated? @@ -63,11 +75,13 @@ (defn wrap-base [handler] (-> ((:middleware defaults) handler) wrap-auth + (wrap-access-rules {:rules rules + :on-error on-error}) wrap-webjars wrap-flash (wrap-session {:cookie-attrs {:http-only true}}) (wrap-defaults - (-> site-defaults - (assoc-in [:security :anti-forgery] false) - (dissoc :session))) + (-> site-defaults + (assoc-in [:security :anti-forgery] false) + (dissoc :session))) wrap-internal-error)) From 1fc8b9ee5df6ad5764ccf2590cc2a6b7cd74208d Mon Sep 17 00:00:00 2001 From: flynn Date: Sun, 9 Jun 2019 01:00:26 +0200 Subject: [PATCH 9/9] cleanup and add some comments --- src/clj/cat/middleware.clj | 23 ++++++++++++++++------- src/clj/cat/routes/oauth.clj | 14 -------------- 2 files changed, 16 insertions(+), 21 deletions(-) diff --git a/src/clj/cat/middleware.clj b/src/clj/cat/middleware.clj index 2f7abb9..ff67da3 100644 --- a/src/clj/cat/middleware.clj +++ b/src/clj/cat/middleware.clj @@ -48,7 +48,9 @@ (defn admin-access [req] (contains? (get-in req [:session :user :roles]) :admin)) -(def rules [{:pattern #"^/admin/.*" +(def rules + "The authentication rules" + [{:pattern #"^/admin/.*" :handler admin-access} ; TODO add other auth schemes ;{:pattern [#"^/$" #"^/oauth/.*"] @@ -57,26 +59,33 @@ ; :handler user-access} ]) -(defn on-error [request response] +(defn on-auth-error + [request response] (error-page {:status 403 :title (str "Access to " (:uri request) " is not authorised")})) -(defn wrap-restricted [handler] +(defn wrap-restricted + "Example of how to wrap a route or handling in an authentication scheme" + [handler] (restrict handler {:handler authenticated? - :on-error on-error})) + :on-error on-auth-error})) -(defn wrap-auth [handler] +(defn wrap-auth + "Installs the session backend on ring" + [handler] (let [backend (session-backend)] (-> handler (wrap-authentication backend) (wrap-authorization backend)))) -(defn wrap-base [handler] +(defn wrap-base + "The all default middleware functions. These get applied to every route." + [handler] (-> ((:middleware defaults) handler) wrap-auth (wrap-access-rules {:rules rules - :on-error on-error}) + :on-error on-auth-error}) wrap-webjars wrap-flash (wrap-session {:cookie-attrs {:http-only true}}) diff --git a/src/clj/cat/routes/oauth.clj b/src/clj/cat/routes/oauth.clj index 16408a9..e76031b 100644 --- a/src/clj/cat/routes/oauth.clj +++ b/src/clj/cat/routes/oauth.clj @@ -66,17 +66,3 @@ (log/warn (:cause (Throwable->map e))) (-> (found "/") (assoc :flash {:error "An error occurred, please try again."}))))))))) - -;(catch [:status 401] _ -; (error-page {:status 401 -; :title "Error authenticating" -; :message "Please contact your system administrator to fix this issue"})) - -; TODO catch using -;(defn multiple-status-endpoint [req] -; (let [resp (do-external-request req)] -; (condp = (:status resp) -; 201 (println ok) -; 401 (println error)))) - -