finally fix oauth login
This commit is contained in:
parent
3ea91cd11f
commit
661435beb4
8 changed files with 191 additions and 48 deletions
23
cat.iml
23
cat.iml
|
@ -21,6 +21,7 @@
|
|||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="vega" level="application" />
|
||||
<orderEntry type="library" name="Leiningen: aopalliance:1.0" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: args4j:2.0.26" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: binaryage/devtools:0.9.10" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: binaryage/env-config:0.2.2" level="project" />
|
||||
|
@ -50,6 +51,7 @@
|
|||
<orderEntry type="library" name="Leiningen: co.deps/ring-etag-middleware:0.2.0" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: com.andrewmcveigh/cljs-time:0.5.2" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: com.carouselapps/to-jdbc-uri:0.5.0" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: com.cemerick/friend:0.2.3" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: com.cognitect/transit-clj:0.8.313" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: com.cognitect/transit-cljs:0.8.256" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: com.cognitect/transit-java:0.8.337" level="project" />
|
||||
|
@ -64,6 +66,7 @@
|
|||
<orderEntry type="library" name="Leiningen: com.google.code.gson/gson:2.7" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: com.google.errorprone/error_prone_annotations:2.0.18" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: com.google.guava/guava:25.1-jre" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: com.google.inject/guice:2.0" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: com.google.j2objc/j2objc-annotations:1.1" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: com.google.javascript/closure-compiler-externs:v20180805" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: com.google.javascript/closure-compiler-unshaded:v20180805" level="project" />
|
||||
|
@ -78,10 +81,10 @@
|
|||
<orderEntry type="library" name="Leiningen: com.stuartsierra/component:0.3.2" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: com.stuartsierra/dependency:0.2.0" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: com.zaxxer/HikariCP:3.2.0" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: commons-codec:1.8" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: commons-codec:1.6" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: commons-fileupload:1.3.3" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: commons-io:2.6" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: commons-logging:1.2" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: commons-logging:1.1.1" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: compojure:1.6.1" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: conman:0.8.3" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: cprop:0.1.13" level="project" />
|
||||
|
@ -129,14 +132,16 @@
|
|||
<orderEntry type="library" name="Leiningen: net.cgrand/sjacket:0.1.1" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: net.incongru.watchservice/barbary-watchservice:1.0" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: net.java.dev.jna/jna:3.2.2" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: net.jcip/jcip-annotations:1.0" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: net.jodah/expiringmap:0.5.8" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: net.sourceforge.nekohtml/nekohtml:1.9.10" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: nrepl/bencode:1.0.0" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: nrepl:0.5.3" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: ns-tracker:0.3.1" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: org.apache.commons/commons-compress:1.9" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: org.apache.commons/commons-lang3:3.1" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: org.apache.httpcomponents/httpclient:4.5" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: org.apache.httpcomponents/httpcore:4.4.1" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: org.apache.httpcomponents/httpclient:4.3.5" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: org.apache.httpcomponents/httpcore:4.3.2" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: org.apache.httpcomponents/httpmime:4.5" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: org.bouncycastle/bcpkix-jdk15on:1.54" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: org.bouncycastle/bcprov-jdk15on:1.54" level="project" />
|
||||
|
@ -145,12 +150,12 @@
|
|||
<orderEntry type="library" name="Leiningen: org.clojure/clojure:1.10.0" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: org.clojure/clojurescript:1.10.439" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: org.clojure/core.async:0.4.474" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: org.clojure/core.cache:0.6.5" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: org.clojure/core.cache:0.6.3" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: org.clojure/core.memoize:0.5.9" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: org.clojure/core.rrb-vector:0.0.11" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: org.clojure/core.specs.alpha:0.2.44" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: org.clojure/data.json:0.2.6" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: org.clojure/data.priority-map:0.0.7" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: org.clojure/data.priority-map:0.0.2" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: org.clojure/google-closure-library-third-party:0.0-20170809-b9c14c6b" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: org.clojure/google-closure-library:0.0-20170809-b9c14c6b" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: org.clojure/java.classpath:0.2.3" level="project" />
|
||||
|
@ -174,8 +179,10 @@
|
|||
<orderEntry type="library" name="Leiningen: org.jboss.spec.javax.websocket/jboss-websocket-api_1.1_spec:1.1.0.Final" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: org.jboss.xnio/xnio-api:3.3.6.Final" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: org.jboss.xnio/xnio-nio:3.3.6.Final" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: org.mindrot/jbcrypt:0.3m" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: org.mozilla/rhino:1.7R5" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: org.msgpack/msgpack:0.6.12" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: org.openid4java/openid4java-nodeps:0.9.6" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: org.ow2.asm/asm-all:4.2" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: org.ow2.asm/asm:5.1" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: org.postgresql/postgresql:42.2.5" level="project" />
|
||||
|
@ -208,10 +215,12 @@
|
|||
<orderEntry type="library" name="Leiningen: ring/ring-ssl:0.3.0" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: selmer:1.12.5" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: simple-lein-profile-merge:0.1.4" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: slingshot:0.12.2" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: slingshot:0.12.1" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: strictly-specking-standalone:0.1.1" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: suspendable:0.1.1" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: tigris:0.1.1" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: virgil:0.1.6" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: xerces/xercesImpl:2.8.1" level="project" />
|
||||
<orderEntry type="library" name="Leiningen: xml-apis:1.3.03" level="project" />
|
||||
</component>
|
||||
</module>
|
|
@ -4,6 +4,7 @@
|
|||
;: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"]
|
||||
|
@ -19,6 +20,7 @@
|
|||
[markdown-clj "1.0.5"]
|
||||
[metosin/muuntaja "0.6.3"]
|
||||
[metosin/ring-http-response "0.9.1"]
|
||||
[slingshot "0.12.1"]
|
||||
[mount "0.1.15"]
|
||||
[nrepl "0.5.3"]
|
||||
[org.clojure/clojure "1.10.0"]
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<title>Something bad happened</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
{% style "/assets/bootstrap/css/bootstrap.min.css" %}
|
||||
{% style "/assets/bulma/css/bulma.css" %}
|
||||
<style type="text/css">
|
||||
html {
|
||||
height: 100%;
|
||||
|
@ -13,19 +13,22 @@
|
|||
overflow: hidden;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
html body {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
}
|
||||
html .container-fluid {
|
||||
|
||||
html .section {
|
||||
display: table;
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
}
|
||||
html .row-fluid {
|
||||
|
||||
html .container {
|
||||
display: table-cell;
|
||||
height: 100%;
|
||||
vertical-align: middle;
|
||||
|
@ -33,21 +36,18 @@
|
|||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container-fluid">
|
||||
<div class="row-fluid">
|
||||
<div class="col-lg-12">
|
||||
<div class="centering text-center">
|
||||
<div class="text-center">
|
||||
<h1><span class="text-danger">Error: {{status}}</span></h1>
|
||||
<hr>
|
||||
{% if title %}
|
||||
<h2 class="without-margin">{{title}}</h2>
|
||||
{% endif %}
|
||||
{% if message %}
|
||||
<h4 class="text-danger">{{message}}</h4>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="section">
|
||||
<div class="container">
|
||||
<div class="has-text-centered">
|
||||
<h1 class="title is-3"><span class="has-text-danger">Error: {{status}}</span></h1>
|
||||
<hr>
|
||||
{% if title %}
|
||||
<h2 class="subtitle is-3">{{title}}</h2>
|
||||
{% endif %}
|
||||
{% if message %}
|
||||
<h4 class="subtitle is-5 has-text-danger">{{message}}</h4>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
<div class="navbar-start">
|
||||
<div class="navbar-item">
|
||||
{% if user %}
|
||||
Hello User!
|
||||
Hello {{ user.username }}
|
||||
{% else %}
|
||||
Please login to use the graph
|
||||
{% endif %}
|
||||
|
@ -63,12 +63,18 @@
|
|||
<div class="navbar-end">
|
||||
<div class="navbar-item">
|
||||
<div class="buttons">
|
||||
{% if user %}
|
||||
<a class="button is-light" href="/logout">
|
||||
<strong>Logout</strong>
|
||||
</a>
|
||||
{% else %}
|
||||
<a class="button is-info">
|
||||
<strong>Sign up</strong>
|
||||
</a>
|
||||
<a class="button is-light">
|
||||
<a class="button is-light" href="/oauth/oauth-init">
|
||||
Log in
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
100
src/clj/cat/moauth.clj
Normal file
100
src/clj/cat/moauth.clj
Normal file
|
@ -0,0 +1,100 @@
|
|||
(ns cat.moauth
|
||||
(:require [cat.config :refer [env]]
|
||||
[clj-http.client :as httpclient]
|
||||
[slingshot.slingshot :refer [try+]]
|
||||
[clojure.tools.logging :as log]
|
||||
[cat.layout :refer [error-page]]))
|
||||
|
||||
; Inspired by https://leonid.shevtsov.me/post/oauth2-is-easy/
|
||||
|
||||
(defn- oauth2-params []
|
||||
{:client-id (env :oauth-consumer-key)
|
||||
: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)
|
||||
;:scope "activity profile"
|
||||
})
|
||||
|
||||
; 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)})
|
||||
;"response_type=code"
|
||||
;"&client_id="
|
||||
;(url-encode (:client-id client-params))
|
||||
;"&redirect_uri="
|
||||
;(url-encode (:redirect-uri client-params))
|
||||
;"&scope="
|
||||
;(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
|
||||
of the used oauth api"
|
||||
[]
|
||||
(authorize-uri (oauth2-params)))
|
||||
|
||||
(defn get-authentication-response
|
||||
"Request an access token with the obtained unique code from the grant page"
|
||||
[csrf-token {:keys [state code]}]
|
||||
(if (or true (= csrf-token state))
|
||||
(try
|
||||
(do
|
||||
(log/info "Requesting access token with code " code)
|
||||
(let [oauth2-params (oauth2-params)
|
||||
access-token (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
|
||||
})]
|
||||
(println "Access token response:" access-token)
|
||||
(:body access-token)))
|
||||
(catch Exception e (log/error "Something terrible happened..." e)))
|
||||
nil))
|
||||
|
||||
(defn get-user-info
|
||||
"User info API call"
|
||||
[access-token]
|
||||
(let [url (str (env :user-api-uri))]
|
||||
(-> (httpclient/get url {:oauth-token access-token
|
||||
:as :json})
|
||||
: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})]
|
||||
[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))))
|
||||
|
|
@ -16,14 +16,17 @@
|
|||
(defn oauth-callback-uri
|
||||
"Generates the oauth request callback URI"
|
||||
[{:keys [headers]}]
|
||||
(str (headers "x-forwarded-proto") "://" (headers "host") "/oauth/oauth-callback"))
|
||||
(let [callback-url (str "http://" (headers "host") "/oauth/oauth-callback")]
|
||||
(println "Generated callback url:" callback-url)
|
||||
callback-url))
|
||||
|
||||
(defn fetch-request-token
|
||||
"Fetches a request token."
|
||||
[request]
|
||||
(let [callback-uri (oauth-callback-uri request)]
|
||||
(log/info "Fetching request token using callback-uri" callback-uri)
|
||||
(oauth/request-token consumer (oauth-callback-uri request))))
|
||||
(log/info "Oauth consumer: " consumer)
|
||||
(oauth/request-token consumer callback-uri {:grant_type "authorization_code"})))
|
||||
|
||||
(defn fetch-access-token
|
||||
[request_token]
|
||||
|
@ -31,5 +34,9 @@
|
|||
|
||||
(defn auth-redirect-uri
|
||||
"Gets the URI the user should be redirected to when authenticating."
|
||||
[request-token]
|
||||
(str (oauth/user-approval-uri consumer request-token)))
|
||||
([request]
|
||||
(auth-redirect-uri request ""))
|
||||
([request request-token]
|
||||
(str (oauth/user-approval-uri consumer request-token {:response_type "code"
|
||||
:client_id (env :oauth-consumer-key)
|
||||
:redirect_uri (oauth-callback-uri request)}))))
|
|
@ -7,7 +7,8 @@
|
|||
[struct.core :as st]
|
||||
[clojure.edn :as edn]
|
||||
[clojure.tools.logging :as log]
|
||||
[clojure.data.json :as json]))
|
||||
[clojure.data.json :as json]
|
||||
[oauth.client :as oauth]))
|
||||
|
||||
(def user-schema
|
||||
[[:name st/required st/string]
|
||||
|
@ -29,10 +30,11 @@
|
|||
(db/get-users))
|
||||
|
||||
(defroutes home-routes
|
||||
(GET "/" []
|
||||
(GET "/" req
|
||||
(let [users (get-users)
|
||||
relations (get-relations)]
|
||||
(home-page {:relations relations :users users :user {}})))
|
||||
(log/info (str "Session: " (:session req)))
|
||||
(home-page {:relations relations :users users :user (get-in req [:session :user])})))
|
||||
;(GET "/docs" []
|
||||
; (-> (response/ok (-> "docs/docs.md" io/resource slurp))
|
||||
; (response/header "Content-Type" "text/plain; charset=utf-8")))
|
||||
|
|
|
@ -3,32 +3,49 @@
|
|||
[compojure.core :refer [defroutes GET]]
|
||||
[clojure.java.io :as io]
|
||||
[cat.oauth :as oauth]
|
||||
[clojure.tools.logging :as log]))
|
||||
[clojure.tools.logging :as log]
|
||||
[cat.moauth :as mo]))
|
||||
|
||||
(defn set-user! [user session redirect-url]
|
||||
(-> (found redirect-url)
|
||||
(assoc :session (assoc session :user user))))
|
||||
|
||||
(defn remove-user! [session redirect-url]
|
||||
(-> (found redirect-url)
|
||||
(assoc :session (dissoc session :user))))
|
||||
|
||||
(defn clear-session! [redirect-url]
|
||||
(-> (found redirect-url)
|
||||
(dissoc :session)))
|
||||
|
||||
(defn oauth-init
|
||||
"Initiates the Twitter OAuth"
|
||||
[request]
|
||||
(-> (oauth/fetch-request-token request)
|
||||
:oauth_token
|
||||
oauth/auth-redirect-uri
|
||||
(-> (mo/authorize-api-uri)
|
||||
found))
|
||||
|
||||
(defn oauth-callback
|
||||
"Handles the callback from Twitter."
|
||||
[{:keys [session params]}]
|
||||
"Handles the callback from adams."
|
||||
[req_token {: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 [user_id screen_name]} (oauth/fetch-access-token params)]
|
||||
(log/info "successfully authenticated as" user_id screen_name)
|
||||
(-> (found "/")
|
||||
(assoc :session
|
||||
(assoc session :user-id user_id :screen-name screen_name))))))
|
||||
(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")
|
||||
(let [user (mo/get-user-info access_token)]
|
||||
(log/info "User info: " user)
|
||||
(set-user! user session "/")))))
|
||||
|
||||
;(catch [:status 401] _
|
||||
; (error-page {:status 401
|
||||
; :title "Error authenticating"
|
||||
; :message "Please contact your system administrator to fix this issue"}))
|
||||
|
||||
|
||||
(defroutes oauth-routes
|
||||
(GET "/oauth/oauth-init" req (oauth-init req))
|
||||
(GET "/oauth/oauth-callback" [& req_token :as req] (oauth-callback req)))
|
||||
|
||||
(GET "/oauth/oauth-init" req (oauth-init req))
|
||||
(GET "/oauth/oauth-callback" [& req_token :as req] (oauth-callback req_token req))
|
||||
(GET "/logout" req (remove-user! (:session req) "/")))
|
Loading…
Reference in a new issue