summaryrefslogtreecommitdiff
path: root/src/mulk/benki/auth.clj
blob: 815fad013da88588239a001421953b4f89ff2b5c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
(ns mulk.benki.auth
  (:refer-clojure)
  (:use [clojure         core repl pprint]
        [hiccup core     page-helpers]
        [mulk.benki      config util db]
        [clojure.core.match
         :only [match]]
        [noir            core]
        [clojure.java.jdbc :only [transaction do-commands]])
  (:require [noir.session      :as session]
            [noir.response     :as response]
            [noir.request      :as request]
            [clojure.java.jdbc :as sql]
            [com.twinql.clojure.http :as http])
  (:import [org.openid4java.consumer ConsumerManager]
           [org.openid4java.message ParameterList]))


(defonce manager (ConsumerManager.))


(defn return-from-openid-provider []
  (let [parlist      (ParameterList. (:query-params (request/ring-request)))
        discovered   (session/get :discovered)
        ;; Does the following work for POST requests?
        request-uri  (str (resolve-uri "/login/return")
                          (let [query-string (:query-string (request/ring-request))]
                            (if query-string
                              (str "?" query-string)
                              "")))
        verification (.verify manager request-uri parlist discovered)
        id           (.getVerifiedId verification)]
    (if id
      (with-dbt
        (let [openid  (first (query "SELECT * FROM openids WHERE openid = ?"
                                    (.getIdentifier id)))
              user-id (if openid
                        (:user openid)
                        nil)
              user    (first (if user-id
                               (query "SELECT * FROM users WHERE id = ?" user-id)
                               nil))]
          (if user-id
            (do (session/put! :user user-id)
                (if-let [return-uri (session/flash-get)]
                  (redirect return-uri)
                  (layout {} "Authenticated!" [:p "Welcome back, " (:first_name user) "!"])))
            (layout "Authentication Failed"
                    [:p "Did not recognize OpenID."]
                    [:p "Your OpenID is: " [:strong (.getIdentifier id)]]))))
      (layout "Authentication Failed" [:p "OpenID authentication failed."]))))


(defpage [:post "/login/browserid/verify"] {assertion :assertion}
  ;; NB.  Can implement this ourselves if we want.
  (let [reply  (http/post "https://browserid.org/verify"
                          :query {:assertion assertion
                                  :audience (:base-uri @benki-config)}
                :as :json)
        result (:content reply)
        status (:status result)
        email  (:email  result)]
    (if (= (:status result) "okay")
      (with-dbt
        (let [record  (first (query "SELECT * FROM user_email_addresses WHERE email = ?" email))
              user-id (and record (:user record))]
          (if user-id
            (let [return-uri (session/flash-get)]
              (session/put! :user user-id)
              (response/json {:email email, :returnURI return-uri}))
            {:status 422,
             :headers {"Content-Type" "text/plain"},
             :body "I couldn't find you in the database."})))
      {:status 400,
       :headers {"Content-Type" "text/plain"},
       :body "Your BrowserID request was crooked."})))


(defpage [:post "/login/return"] []
  (return-from-openid-provider))

(defpage "/login/return" []
  (return-from-openid-provider))

(defpage "/login/authenticate" {openid :openid_identifier}
  (let [discoveries (.discover     manager openid)
        discovered  (.associate    manager discoveries)
        authreq     (.authenticate manager discovered (resolve-uri "/login/return"))]
    (session/put! :discovered discovered)
    (redirect (.getDestinationUrl authreq true))))

(def login-page-layout
  {:head
   (list
    [:link {:type "text/css", :rel "stylesheet", :href (resolve-uri "/3rdparty/openid-selector/css/openid.css")}])
   :bottom
   (list
    [:script {:type "text/javascript", :src (resolve-uri "/3rdparty/openid-selector/js/openid-jquery.js")}]
    [:script {:type "text/javascript", :src (resolve-uri "/3rdparty/openid-selector/js/openid-en.js")}]
    [:script {:type "text/javascript", :src (resolve-uri "/js/openid-login.js")}]
    )})

(defpage "/login" []
  (session/flash-put! (or (session/flash-get)
                          (get-in (request/ring-request) [:headers "referer"])))
  (layout login-page-layout "Benki Login"
    [:div#browserid-box
     [:h2 "BrowserID login"]
     [:a#browserid {:href "#"}
      [:img {:src (resolve-uri "/3rdparty/browserid/sign_in_orange.png")
             :alt "Sign in using BrowserID"}]]]
    [:div#openid-login-panel
     [:h2 "OpenID login"]
     [:form {:action (resolve-uri "/login/authenticate"),
             :method "GET"
             :id     "openid_form"}
      [:div {:id "openid_choice"}
       [:p "Please select your OpenID provider:"]
       [:div {:id "openid_btns"}]]
      [:div {:id "openid_input_area"}
       [:input {:type "text", :name "openid_identifier", :id "openid_identifier"}]
       [:input {:type "submit"}]]]]))