better error handling for oauth
restructure route handlers
This commit is contained in:
parent
af90e8639a
commit
fd54e61a49
5 changed files with 100 additions and 91 deletions
18
project.clj
18
project.clj
|
@ -1,17 +1,19 @@
|
||||||
(defproject cat "0.1.0-SNAPSHOT"
|
(defproject cat "0.1.0-SNAPSHOT"
|
||||||
|
|
||||||
:description "A cuddle graph for zeus people"
|
:description "A cuddle graph for zeus people"
|
||||||
;:url "http://example.com/FIXME"
|
;:url "http://example.com/FIXME"
|
||||||
|
|
||||||
:dependencies [[buddy "2.0.0"]
|
:dependencies [[buddy "2.0.0"]
|
||||||
[com.cemerick/friend "0.2.3"]
|
|
||||||
[cheshire "5.8.1"]
|
[cheshire "5.8.1"]
|
||||||
[clj-oauth "1.5.5"]
|
[clj-oauth "1.5.5"]
|
||||||
[clojure.java-time "0.3.2"]
|
[clojure.java-time "0.3.2"]
|
||||||
|
[com.cemerick/friend "0.2.3"]
|
||||||
[com.cognitect/transit-clj "0.8.313"]
|
[com.cognitect/transit-clj "0.8.313"]
|
||||||
|
[com.google.protobuf/protobuf-java "3.6.1"]
|
||||||
[compojure "1.6.1"]
|
[compojure "1.6.1"]
|
||||||
[conman "0.8.3"]
|
[conman "0.8.3"]
|
||||||
[cprop "0.1.13"]
|
[cprop "0.1.13"]
|
||||||
|
[funcool/promesa "1.9.0"]
|
||||||
[funcool/struct "1.3.0"]
|
[funcool/struct "1.3.0"]
|
||||||
[luminus-immutant "0.2.4"]
|
[luminus-immutant "0.2.4"]
|
||||||
[luminus-migrations "0.6.3"]
|
[luminus-migrations "0.6.3"]
|
||||||
|
@ -20,17 +22,16 @@
|
||||||
[markdown-clj "1.0.5"]
|
[markdown-clj "1.0.5"]
|
||||||
[metosin/muuntaja "0.6.3"]
|
[metosin/muuntaja "0.6.3"]
|
||||||
[metosin/ring-http-response "0.9.1"]
|
[metosin/ring-http-response "0.9.1"]
|
||||||
[slingshot "0.12.1"]
|
[metosin/vega-tools "0.2.0"]
|
||||||
[mount "0.1.15"]
|
[mount "0.1.15"]
|
||||||
|
[mysql/mysql-connector-java "8.0.12"]
|
||||||
[nrepl "0.5.3"]
|
[nrepl "0.5.3"]
|
||||||
[org.clojure/clojure "1.10.0"]
|
[org.clojure/clojure "1.10.0"]
|
||||||
[org.clojure/clojurescript "1.10.439" :scope "provided"]
|
[org.clojure/clojurescript "1.10.439" :scope "provided"]
|
||||||
[org.clojure/tools.cli "0.4.1"]
|
[org.clojure/tools.cli "0.4.1"]
|
||||||
[org.clojure/tools.logging "0.4.1"]
|
[org.clojure/tools.logging "0.4.1"]
|
||||||
;[org.postgresql/postgresql "42.2.5"]
|
;[org.postgresql/postgresql "42.2.5"]
|
||||||
[mysql/mysql-connector-java "8.0.12"]
|
;https://www.webjars.org/
|
||||||
[com.google.protobuf/protobuf-java "3.6.1"]
|
|
||||||
;https://www.webjars.org/
|
|
||||||
[org.webjars.npm/bulma "0.7.2"]
|
[org.webjars.npm/bulma "0.7.2"]
|
||||||
[org.webjars/font-awesome "5.6.1"]
|
[org.webjars/font-awesome "5.6.1"]
|
||||||
[org.webjars/webjars-locator "0.34"]
|
[org.webjars/webjars-locator "0.34"]
|
||||||
|
@ -38,8 +39,7 @@
|
||||||
[ring/ring-core "1.7.1"]
|
[ring/ring-core "1.7.1"]
|
||||||
[ring/ring-defaults "0.3.2"]
|
[ring/ring-defaults "0.3.2"]
|
||||||
[selmer "1.12.5"]
|
[selmer "1.12.5"]
|
||||||
[metosin/vega-tools "0.2.0"]
|
[slingshot "0.12.1"]]
|
||||||
[funcool/promesa "1.9.0"]]
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -2,30 +2,42 @@
|
||||||
(:require [cat.middleware :as middleware]
|
(:require [cat.middleware :as middleware]
|
||||||
[cat.layout :refer [error-page]]
|
[cat.layout :refer [error-page]]
|
||||||
[cat.routes.home :refer [home-routes]]
|
[cat.routes.home :refer [home-routes]]
|
||||||
[cat.routes.oauth :refer [oauth-routes]]
|
[cat.routes.oauth :refer [oauth-init oauth-callback clear-session!]]
|
||||||
[cat.routes.admin :refer [admin-routes]]
|
[cat.routes.admin :refer [set-admin! create-new-relation! create-user!]]
|
||||||
[compojure.core :refer [routes wrap-routes]]
|
[compojure.core :refer [routes defroutes GET POST wrap-routes]]
|
||||||
[ring.util.http-response :as response]
|
[ring.util.http-response :as response]
|
||||||
[compojure.route :as route]
|
[compojure.route :as route]
|
||||||
[cat.env :refer [defaults]]
|
[cat.env :refer [defaults]]
|
||||||
|
[clojure.tools.logging :as log]
|
||||||
[mount.core :as mount]))
|
[mount.core :as mount]))
|
||||||
|
|
||||||
(mount/defstate init-app
|
(mount/defstate init-app
|
||||||
:start ((or (:init defaults) identity))
|
:start ((or (:init defaults) identity))
|
||||||
:stop ((or (:stop 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
|
(mount/defstate app
|
||||||
:start
|
:start
|
||||||
(middleware/wrap-base
|
(middleware/wrap-base
|
||||||
(routes
|
(routes
|
||||||
(-> #'home-routes
|
(-> #'home-routes
|
||||||
(wrap-routes middleware/wrap-csrf)
|
(wrap-routes middleware/wrap-csrf)
|
||||||
(wrap-routes middleware/wrap-formats))
|
(wrap-routes middleware/wrap-formats))
|
||||||
#'oauth-routes
|
#'oauth-routes
|
||||||
(-> #'admin-routes
|
(-> #'admin-routes
|
||||||
(wrap-routes middleware/wrap-restricted))
|
(wrap-routes middleware/wrap-restricted))
|
||||||
(route/not-found
|
(route/not-found
|
||||||
(:body
|
(:body
|
||||||
(error-page {:status 404
|
(error-page {:status 404
|
||||||
:title "page not found"}))))))
|
:title "page not found"}))))))
|
||||||
|
|
||||||
|
|
|
@ -12,19 +12,19 @@
|
||||||
:client-secret (env :oauth-consumer-secret)
|
:client-secret (env :oauth-consumer-secret)
|
||||||
:authorize-uri (env :authorize-uri)
|
:authorize-uri (env :authorize-uri)
|
||||||
:redirect-uri (str (env :app-host) "/oauth/oauth-callback")
|
: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
|
; To authorize, redirect the user to the sign in / grant page
|
||||||
|
|
||||||
|
|
||||||
(defn- authorize-uri
|
(defn- authorize-uri
|
||||||
[client-params #_csrf-token]
|
[client-params #_csrf-token]
|
||||||
(str
|
(str
|
||||||
(:authorize-uri client-params)
|
(:authorize-uri client-params)
|
||||||
"?"
|
"?"
|
||||||
(httpclient/generate-query-string {:response_type "code"
|
(httpclient/generate-query-string {:response_type "code"
|
||||||
:client_id (:client-id client-params)
|
:client_id (:client-id client-params)
|
||||||
:redirect_uri (:redirect-uri client-params)})
|
:redirect_uri (:redirect-uri client-params)})
|
||||||
;"response_type=code"
|
;"response_type=code"
|
||||||
;"&client_id="
|
;"&client_id="
|
||||||
;(url-encode (:client-id client-params))
|
;(url-encode (:client-id client-params))
|
||||||
|
@ -34,7 +34,7 @@
|
||||||
;(url-encode (:scope client-params))
|
;(url-encode (:scope client-params))
|
||||||
;"&state="
|
;"&state="
|
||||||
;(url-encode csrf-token)
|
;(url-encode csrf-token)
|
||||||
))
|
))
|
||||||
|
|
||||||
(defn authorize-api-uri
|
(defn authorize-api-uri
|
||||||
"let the user authorize access by redirecting to the signin / grant page
|
"let the user authorize access by redirecting to the signin / grant page
|
||||||
|
@ -51,20 +51,21 @@
|
||||||
(do
|
(do
|
||||||
(log/debug "Requesting access token with code " code)
|
(log/debug "Requesting access token with code " code)
|
||||||
(let [oauth2-params (oauth2-params)
|
(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
|
{:form-params {:code code
|
||||||
:grant_type "authorization_code"
|
:grant_type "authorization_code"
|
||||||
:client_id (:client-id oauth2-params)
|
:client_id (:client-id oauth2-params)
|
||||||
:client_secret (:client-secret oauth2-params)
|
:client_secret (:client-secret oauth2-params)
|
||||||
:redirect_uri (:redirect-uri oauth2-params)}
|
:redirect_uri (:redirect-uri oauth2-params)}
|
||||||
;:basic-auth [(:client-id oauth2-params) (:client-secret oauth2-params)]
|
|
||||||
:as :json
|
:as :json
|
||||||
:insecure? true
|
:throw-exceptions false
|
||||||
})]
|
:insecure? true})]
|
||||||
(log/debug "Access token response:" access-token)
|
(condp = (:status resp)
|
||||||
(:body access-token)))
|
200 (:body resp)
|
||||||
(catch Exception e (log/error "Something terrible happened..." e)))
|
401 (-> {:status 401 :body "Invalid authentication credentials"})
|
||||||
nil))
|
{:status 500 :body "Something went pear-shape when trying to authenticate"})))
|
||||||
|
)
|
||||||
|
(log/info "Invalid csrf token whilst authenticating")))
|
||||||
|
|
||||||
(defn get-user-info
|
(defn get-user-info
|
||||||
"User info API call"
|
"User info API call"
|
||||||
|
@ -73,30 +74,31 @@
|
||||||
(-> (httpclient/get url {:oauth-token access-token
|
(-> (httpclient/get url {:oauth-token access-token
|
||||||
:as :json
|
:as :json
|
||||||
:insecure? true})
|
:insecure? true})
|
||||||
:body)
|
:body)))
|
||||||
))
|
|
||||||
|
|
||||||
; Refresh token when it expires
|
; Refresh token when it expires
|
||||||
|
|
||||||
|
|
||||||
(defn- refresh-tokens
|
(defn- refresh-tokens
|
||||||
"Request a new token pair"
|
"Request a new token pair"
|
||||||
[refresh-token]
|
[refresh-token]
|
||||||
(try+
|
(try+
|
||||||
(let [oauth2-params (oauth2-params)
|
(let [oauth2-params (oauth2-params)
|
||||||
{{access-token :access_token refresh-token :refresh_token} :body}
|
{{access-token :access_token refresh-token :refresh_token} :body}
|
||||||
(httpclient/post (:access-token-uri oauth2-params)
|
(httpclient/post (:access-token-uri oauth2-params)
|
||||||
{:form-params {:grant_type "refresh_token"
|
{:form-params {:grant_type "refresh_token"
|
||||||
:refresh_token refresh-token}
|
:refresh_token refresh-token}
|
||||||
:basic-auth [(:client-id oauth2-params) (:client-secret oauth2-params)]
|
:basic-auth [(:client-id oauth2-params) (:client-secret oauth2-params)]
|
||||||
:as :json
|
:as :json
|
||||||
:insecure? true})]
|
:insecure? true})]
|
||||||
[access-token refresh-token])
|
[access-token refresh-token])
|
||||||
(catch [:status 401] _ nil)))
|
(catch [:status 401] _ nil)))
|
||||||
|
|
||||||
(defn get-fresh-tokens
|
(defn get-fresh-tokens
|
||||||
"Returns current token pair if they have not expired, or a refreshed token pair otherwise"
|
"Returns current token pair if they have not expired, or a refreshed token pair otherwise"
|
||||||
[access-token refresh-token]
|
[access-token refresh-token]
|
||||||
(try+
|
(try+
|
||||||
(and (get-user-info access-token)
|
(and (get-user-info access-token)
|
||||||
[access-token refresh-token])
|
[access-token refresh-token])
|
||||||
(catch [:status 401] _ (refresh-tokens refresh-token))))
|
(catch [:status 401] _ (refresh-tokens refresh-token))))
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
(ns cat.routes.admin
|
(ns cat.routes.admin
|
||||||
(:require [cat.db.core :refer [*db*] :as db]
|
(:require [cat.db.core :refer [*db*] :as db]
|
||||||
[compojure.core :refer [defroutes GET POST]]
|
|
||||||
[struct.core :as st]
|
[struct.core :as st]
|
||||||
[clojure.tools.logging :as log]
|
[clojure.tools.logging :as log]
|
||||||
[ring.util.http-response :as response]))
|
[ring.util.http-response :as response]))
|
||||||
|
@ -13,29 +12,28 @@
|
||||||
[[:from_id st/required st/integer-str]
|
[[:from_id st/required st/integer-str]
|
||||||
[:to_id st/required st/integer-str]])
|
[:to_id st/required st/integer-str]])
|
||||||
|
|
||||||
(defroutes admin-routes
|
(defn set-admin! [req enabled?]
|
||||||
(GET "/admin/enable" req (-> (response/found "/")
|
(-> (response/found "/")
|
||||||
(assoc :session (assoc-in (:session req) [:user :admin :enabled] true))))
|
(assoc :session (assoc-in (:session req) [:user :admin :enabled] enabled?))))
|
||||||
(GET "/admin/disable" req (-> (response/found "/")
|
|
||||||
(assoc :session (assoc-in (:session req) [:user :admin :enabled] false))))
|
|
||||||
|
|
||||||
(POST "/relations" req
|
(defn create-new-relation! [req]
|
||||||
(let [data (:params req) [err result] (st/validate data relation-schema)]
|
(let [data (:params req)
|
||||||
(log/info "Post to " (:uri req))
|
[err result] (st/validate data relation-schema)]
|
||||||
(if (nil? err)
|
(if (nil? err)
|
||||||
(do
|
(do
|
||||||
(db/create-relation! result)
|
(log/info "Admin creates relation from " (:from_id data) "to" (:to_id data))
|
||||||
(response/found "/"))
|
(db/create-relation! result)
|
||||||
(do
|
(response/found "/"))
|
||||||
(response/bad-request "Incorrect input")))))
|
(do
|
||||||
(POST "/users" req
|
(response/bad-request "Incorrect input")))))
|
||||||
(let [data (:params req)]
|
|
||||||
(log/info "Post to " (:uri req))
|
(defn create-user! [req]
|
||||||
(println data)
|
(let [data (:params req)]
|
||||||
(if (st/valid? data user-schema)
|
(println data)
|
||||||
(do
|
(if (st/valid? data user-schema)
|
||||||
(db/create-user! (assoc data :zeusid nil))
|
(do
|
||||||
(response/found "/"))
|
(log/info "Admin creates user: " (:name data))
|
||||||
(do
|
(db/create-user! (assoc data :zeusid nil))
|
||||||
(response/bad-request "Incorrect input")))))
|
(response/found "/"))
|
||||||
)
|
(do
|
||||||
|
(response/bad-request "Incorrect input")))))
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
(assoc :session nil)))
|
(assoc :session nil)))
|
||||||
|
|
||||||
(defn oauth-init
|
(defn oauth-init
|
||||||
"Initiates the Twitter OAuth"
|
"Initiates the OAuth"
|
||||||
[request]
|
[request]
|
||||||
(let [reee (mo/authorize-api-uri)]
|
(let [reee (mo/authorize-api-uri)]
|
||||||
(log/debug "authorize uri: " reee)
|
(log/debug "authorize uri: " reee)
|
||||||
|
@ -40,13 +40,14 @@
|
||||||
"Handles the callback from adams with the access_token
|
"Handles the callback from adams with the access_token
|
||||||
Fetches the user from the database, creating a new one if not found
|
Fetches the user from the database, creating a new one if not found
|
||||||
Sets the user in the session and redirects back to origin \"/\" "
|
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
|
; oauth request was denied by user
|
||||||
(if (:denied params)
|
(if (:denied params)
|
||||||
(-> (found "/")
|
(-> (found "/")
|
||||||
(assoc :flash {:denied true}))
|
(assoc :flash {:denied true}))
|
||||||
; fetch the request token and do anything else you wanna do if not denied.
|
; 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)
|
fetched-user (mo/get-user-info access_token)
|
||||||
local-user (db/get-zeus-user {:zeusid (:id fetched-user)})]
|
local-user (db/get-zeus-user {:zeusid (:id fetched-user)})]
|
||||||
(if local-user
|
(if local-user
|
||||||
|
@ -78,7 +79,3 @@
|
||||||
; 401 (println error))))
|
; 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! "/")))
|
|
||||||
|
|
Loading…
Reference in a new issue