diff options
author | Matthias Andreas Benkard <code@mail.matthias.benkard.de> | 2012-03-27 20:14:38 +0200 |
---|---|---|
committer | Matthias Andreas Benkard <code@mail.matthias.benkard.de> | 2012-03-27 20:15:34 +0200 |
commit | 285529a532743d52af94d3d571178a413dd944c8 (patch) | |
tree | 1d25919aba233f3cde3c98dfab0f987dafb878b0 | |
parent | 89e5ee140a4becefa4d4023102107727c5921efb (diff) |
Implement BrowserID-based login.
-rw-r--r-- | project.clj | 1 | ||||
-rw-r--r-- | schema.sql | 7 | ||||
-rw-r--r-- | src/mulk/benki/auth.clj | 57 | ||||
-rw-r--r-- | src/mulk/benki/util.clj | 6 | ||||
-rw-r--r-- | static/js/browserid.js | 51 |
5 files changed, 109 insertions, 13 deletions
diff --git a/project.clj b/project.clj index 896a190..d29e1d7 100644 --- a/project.clj +++ b/project.clj @@ -36,6 +36,7 @@ [org.openid4java/openid4java-consumer "0.9.6" :type "pom"] [org.jsoup/jsoup "1.6.1"] [org.apache.abdera/abdera-parser "1.1.1"] + [clj-apache-http "2.3.2"] ] :dev-dependencies [[swank-clojure "1.4.0-SNAPSHOT"] [clj-stacktrace "0.2.3"]] @@ -21,6 +21,13 @@ CREATE TABLE openids( FOREIGN KEY("user") REFERENCES users ); +CREATE TABLE user_email_addresses( + "user" INTEGER NOT NULL, + email VARCHAR NOT NULL, + PRIMARY KEY(email), + FOREIGN KEY("user") REFERENCES users +); + CREATE TABLE page_keys( "user" INTEGER NOT NULL, page VARCHAR NOT NULL, diff --git a/src/mulk/benki/auth.clj b/src/mulk/benki/auth.clj index 93e106e..03d9746 100644 --- a/src/mulk/benki/auth.clj +++ b/src/mulk/benki/auth.clj @@ -2,7 +2,7 @@ (:refer-clojure) (:use [clojure core repl pprint] [hiccup core page-helpers] - [mulk.benki util db] + [mulk.benki config util db] [clojure.core.match :only [match]] [noir core] @@ -10,7 +10,8 @@ (:require [noir.session :as session] [noir.response :as response] [noir.request :as request] - [clojure.java.jdbc :as sql]) + [clojure.java.jdbc :as sql] + [com.twinql.clojure.http :as http]) (:import [org.openid4java.consumer ConsumerManager] [org.openid4java.message ParameterList])) @@ -50,6 +51,31 @@ (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 418, + :headers {"Content-Type" "text/plain"}, + :body "I couldn't find you in the database."}))) + {:status 418, + :headers {"Content-Type" "text/plain"}, + :body "Your BrowserID request was crooked."}))) + + (defpage [:post "/login/return"] [] (return-from-openid-provider)) @@ -76,14 +102,21 @@ (defpage "/login" [] (session/flash-put! (or (session/flash-get) - (get-in (request/ring-request) [:headers "Referer"]))) + (get-in (request/ring-request) [:headers "referer"]))) (layout login-page-layout "Benki 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"}]]])) + [: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"}]]]])) diff --git a/src/mulk/benki/util.clj b/src/mulk/benki/util.clj index 99e739c..505c637 100644 --- a/src/mulk/benki/util.clj +++ b/src/mulk/benki/util.clj @@ -32,11 +32,15 @@ ;; defpartial is just defn + html. (defpartial layout [kind title & content] (html5 {:xml? true} - [:head + [:head {:data-logged-in (if *user* "true" "false")} [:title title] ;; jQuery [:script {:type "text/javascript" :src (resolve-uri "/3rdparty/jquery/jquery-1.7.min.js")}] + [:script {:type "text/javascript" + :src (resolve-uri "/3rdparty/browserid/include.js")}] + [:script {:type "text/javascript" + :src (resolve-uri "/js/browserid.js")}] [:link {:type "text/css" :rel "stylesheet" :href (resolve-uri "/style/benki.css")}] diff --git a/static/js/browserid.js b/static/js/browserid.js new file mode 100644 index 0000000..dce8d42 --- /dev/null +++ b/static/js/browserid.js @@ -0,0 +1,51 @@ +// -*- js-indent-level: 2 -*- + +jQuery(function($) { + var loggedIn = function(res) { + console.log(res); + if (res.returnURI) { + window.location.assign(res.returnURI); + } else { + window.location.reload(true); + } + }; + var loggedOut = function(res) { + }; + + var gotAssertion = function(assertion) { + // got an assertion, now send it up to the server for verification + if (assertion) { + $.ajax({ + type: 'POST', + url: '/login/browserid/verify', + data: { assertion: assertion }, + success: function(res, status, xhr) { + if (res === null) { + loggedOut(); + } + else { + loggedIn(res); + } + }, + error: function(res, status, xhr) { + //console.log(res); + //console.log(status); + alert("Whoops, I failed to authenticate you! " + res.responseText); + } + }); + } else { + loggedOut(); + } + } + + $('#browserid').click(function() { + navigator.id.get(gotAssertion, {allowPersistent: true}); + return false; + }); + + // Query persistent login. + var login = $('head').attr('data-logged-in'); + if (login === "false") { + navigator.id.get(gotAssertion, {silent: true}); + } +}); |