In the last couple of weeks I have been trying to learn clojure. I startet to implement a simple web application so I have a playground where I can try things (It doesn’t really do anything at the moment, but I’ll write about it in a later post). I use the noir web framework to write this web application. In this web app I wanted to use OpenID, so I can log in with my google account.

I came across clj-openid by Steve Lindsay, but it still looks a kinda incomplete. I also found friend by Chas Emerick, but it seems to do everything which is too much for me. I decided to try openid4java, which I know from writing gclimbing.com. I know friend uses openid4java too, but I wanted to use it directly - at least for now.

I probably wrote some suboptimal - or even ugly - clojure code along the way. Please contact me if you have any suggestions what I could do better!

I first added openid4java-consumer 0.9.5 as a dependency to project.clj (0.9.6 does not have a jar on maven central, so I use 0.9.5 for now):

(defproject newsreader "0.1.0-SNAPSHOT"
            :dependencies [[org.clojure/clojure "1.4.0"]
                           [noir "1.3.0-beta3"]
                           [org.openid4java/openid4java-consumer "0.9.5"]]
            :main newsreader.server)

Then I created two helper functions, one which starts the OpenID request (redirect->openid) and one to process the response (verify):

openid.clj

(ns newsreader.openid.openid
  (:require [noir.request]
            [noir.session :as session]))

(def ^:private consumerManager (org.openid4java.consumer.ConsumerManager.))

(defn redirect->openid [oidUrl returnUrl]
    (let [discoveries (.discover consumerManager oidUrl)
          discovered (.associate consumerManager discoveries)
          authRequest (.authenticate consumerManager discovered returnUrl)]

    	(session/put! :newsreader-oid-discovered discovered)
        (.getDestinationUrl authRequest true)))

(defn verify []
    (let [request (noir.request/ring-request)
          openidRequest (into {} (for [[k v] (:params request)] [(name k) v]))
          responseParameters (org.openid4java.message.ParameterList. openidRequest)
          discovered (session/get :newsreader-oid-discovered)
          receivingUrl (str (name (:scheme request)) "://"
                            ((:headers request) "host")
                            (:uri request)
                            "?" (:query-string request))
          verification (.verify consumerManager receivingUrl responseParameters 
                                                discovered)
          verified (.getVerifiedId verification)]

        (session/remove! :newsreader-oid-discovered)
        verified))

Using the code is quite simple: Redirect to the return value of redirect->openid (this is what the /login page does). Use verfiy in the OpenID response page (/openid-return). The result of verify is an Identifier - It should be used to uniquely identify the user.

login.clj

(ns newsreader.views.login
  (:require [newsreader.views.common :as common] 
            [newsreader.openid.openid :as openid]
            [noir.request]
            [noir.session :as session])
  (:use [noir.core :only [defpage]] 
  	    [hiccup.core :only [html]]))

(defpage "/login" []
        (ring.util.response/redirect 
            (openid/redirect->openid "https://www.google.com/accounts/o8/id"
                                     "http://localhost:8080/openid-return")))

(defpage "/openid-return" {openidns "openid.ns" openidmode "openid.mode"}
    (str "now verified: " (openid/verify)))

Integrating openid4java was pretty easy. The resulting code (in openid.clj) does not look especially nice, but it’s only a single file with 2 functions so I can live with that. Maybe I’ll try friend in a later version, but for now I think I am fine with this code.