Browse files

Implemented Twitter's "Creating a signature".

  • Loading branch information...
1 parent aa47182 commit 44467ef600fda250740d6583cc34ade6b3375edb @r0man committed Jan 11, 2012
Showing with 77 additions and 38 deletions.
  1. +1 −0 .gitignore
  2. +22 −0 src/oauth/util.clj
  3. +20 −26 src/oauth/v1.clj
  4. +12 −0 test/oauth/test/util.clj
  5. +22 −12 test/oauth/test/v1.clj
View
1 .gitignore
@@ -1,3 +1,4 @@
lib
/.lein-deps-sum
/.lein-failures
+/logs/debug.log
View
22 src/oauth/util.clj
@@ -0,0 +1,22 @@
+(ns oauth.util
+ (:refer-clojure :exclude (replace))
+ (:import javax.crypto.Mac javax.crypto.spec.SecretKeySpec)
+ (:use [clj-http.util :only (url-encode url-decode)]
+ [clojure.string :only (replace)]))
+
+(defn hmac
+ ([^String algorithm ^String msg ^String key]
+ (hmac algorithm msg key "UTF8"))
+ ([^String algorithm ^String msg ^String key ^String encoding]
+ (let [key (SecretKeySpec. (.getBytes key "UTF8") algorithm)
+ mac (doto (Mac/getInstance algorithm)
+ (.init key))]
+ (.doFinal mac (.getBytes msg encoding)))))
+
+(defn percent-encode
+ "Percent encode `unencoded` according to RFC 3986, Section 2.1."
+ [unencoded]
+ (-> (url-encode unencoded)
+ (replace "%7E" "~")
+ (replace "*" "%2A")
+ (replace "+" "%20")))
View
46 src/oauth/v1.clj
@@ -1,9 +1,10 @@
(ns oauth.v1
(:refer-clojure :exclude (replace))
(:require [clj-http.client :as http])
- (:use [clj-http.util :only (url-encode url-decode)]
+ (:use [clj-http.util :only (base64-encode url-encode url-decode)]
[clojure.string :only (join replace split upper-case)]
- [inflections.core :only (underscore)]))
+ [inflections.core :only (underscore)]
+ oauth.util))
(def ^:dynamic *oauth-consumer-key* nil)
@@ -17,14 +18,6 @@
(defn format-header [options]
(str "OAuth " (join ", " (format-options options))))
-(defn percent-encode
- "Percent encode `unencoded` according to RFC 3986, Section 2.1."
- [unencoded]
- (-> (url-encode unencoded)
- (replace "%7E" "~")
- (replace "*" "%2A")
- (replace "+" "%20")))
-
(defn root-url [{:keys [scheme server-name server-port]}]
(str scheme "://" server-name (when server-port (str ":" server-port))))
@@ -34,15 +27,6 @@
(defn format-base-url [request]
(str (root-url request) (:uri request)))
-(defn oauth-signature-base-string [request]
- (->> [(format-http-method request)
- (url-encode (root-url request))
- (url-encode (http/generate-query-string (:query-params request)))]
- (join "&")))
-
-(defn oauth-request-signature [request]
- (oauth-signature-base-string request))
-
(defn oauth-parameters [request]
(let [body (split (:body request) #"=")
params (reduce #(concat %1 [(name (first %2)) (str (last %2))]) nil (:query-params request))]
@@ -59,10 +43,20 @@
(map #(str (percent-encode (first %1)) "=" (percent-encode (last %1))))
(join "&")))
-;; (prn (oauth-parameters
-;; {:method :post
-;; :scheme "https"
-;; :server-name "api.twitter.com"
-;; :uri "/1/statuses/update.json"
-;; :query-params {:include_entities true}
-;; :body "status=Hello%20Ladies%20%2b%20Gentlemen%2c%20a%20signed%20OAuth%20request%21"}))
+(defn oauth-signature-base-string [request]
+ (->> [(format-http-method request)
+ (percent-encode (format-base-url request))
+ (percent-encode (oauth-parameter-string request))]
+ (join "&")))
+
+(defn oauth-request-signature [request]
+ (oauth-signature-base-string request))
+
+(defn oauth-signing-key [request]
+ (str (:oauth-consumer-secret request) "&" (:oauth-token-secret request)))
+
+(defn oauth-signature [request]
+ (-> (hmac "HmacSHA1"
+ (oauth-signature-base-string request)
+ (oauth-signing-key request))
+ (base64-encode)))
View
12 test/oauth/test/util.clj
@@ -0,0 +1,12 @@
+(ns oauth.test.util
+ (:use clojure.test
+ oauth.util))
+
+(deftest test-percent-encode
+ (are [unencoded expected]
+ (is (= expected (percent-encode unencoded)))
+ "" ""
+ "Ladies + Gentlemen" "Ladies%20%2B%20Gentlemen"
+ "An encoded string!" "An%20encoded%20string%21"
+ "Dogs, Cats & Mice" "Dogs%2C%20Cats%20%26%20Mice"
+ "" "%E2%98%83")) ; https://dev.twitter.com/docs/auth/percent-encoding-parameters
View
34 test/oauth/test/v1.clj
@@ -5,11 +5,13 @@
(def example-options
{:oauth-consumer-key "xvz1evFS4wEEPTGEFPHBog"
+ :oauth-consumer-secret "kAcSOqF21Fu85e7zjz7ZN2U4ZRhfV3WpwPAoE3Z7kBw"
:oauth-nonce "kYjzVBB8Y0ZFabxSWbWovY3uYSQ2pTgmZeNu2VS4cg"
:oauth-signature "tnnArxj06cWHq44gCs1OSKk/jLY="
:oauth-signature-method "HMAC-SHA1"
:oauth-timestamp "1318622958"
:oauth-token "370773112-GmHxMAgYyLbNEtIKZeRNFsMKPR9EyMZeS9weJAEb"
+ :oauth-token-secret "LswwdoUaIvS8ltyTt5jkRh4J50vUPVVHtR2YPi5kE"
:oauth-version "1.0"})
(def example-request
@@ -47,15 +49,6 @@
"oauth_consumer_key=\"xvz1evFS4wEEPTGEFPHBog\"")
(format-options example-options)))
-(deftest test-percent-encode
- (are [unencoded expected]
- (is (= expected (percent-encode unencoded)))
- "" ""
- "Ladies + Gentlemen" "Ladies%20%2B%20Gentlemen"
- "An encoded string!" "An%20encoded%20string%21"
- "Dogs, Cats & Mice" "Dogs%2C%20Cats%20%26%20Mice"
- "" "%E2%98%83")) ; https://dev.twitter.com/docs/auth/percent-encoding-parameters
-
(deftest test-root-url
(is (= "https://api.twitter.com" (root-url example-request))))
@@ -84,9 +77,26 @@
(is (= ["status" "Hello Ladies + Gentlemen, a signed OAuth request!"] (nth params 7)))))
(deftest test-oauth-request-signature
- (let [request (oauth-request-signature example-request)]
+ (let [request (oauth-request-signature example-oauth-request)]
(is request)))
+(deftest test-oauth-signature
+ (is (= "tnnArxj06cWHq44gCs1OSKk/jLY="
+ (oauth-signature example-oauth-request))))
+
(deftest test-oauth-signature-base-string
- (is (= "POST&https%3A%2F%2Fapi.twitter.com&include_entities%3Dtrue"
- (oauth-signature-base-string example-request))))
+ (is (= (str "POST&"
+ "https%3A%2F%2Fapi.twitter.com%2F1%2Fstatuses%2Fupdate.json&"
+ "include_entities%3Dtrue%26"
+ "oauth_consumer_key%3Dxvz1evFS4wEEPTGEFPHBog%26"
+ "oauth_nonce%3DkYjzVBB8Y0ZFabxSWbWovY3uYSQ2pTgmZeNu2VS4cg%26"
+ "oauth_signature_method%3DHMAC-SHA1%26"
+ "oauth_timestamp%3D1318622958%26"
+ "oauth_token%3D370773112-GmHxMAgYyLbNEtIKZeRNFsMKPR9EyMZeS9weJAEb%26"
+ "oauth_version%3D1.0%26"
+ "status%3DHello%2520Ladies%2520%252B%2520Gentlemen%252C%2520a%2520signed%2520OAuth%2520request%2521")
+ (oauth-signature-base-string example-oauth-request))))
+
+(deftest test-oauth-signing-key
+ (is (= "kAcSOqF21Fu85e7zjz7ZN2U4ZRhfV3WpwPAoE3Z7kBw&LswwdoUaIvS8ltyTt5jkRh4J50vUPVVHtR2YPi5kE"
+ (oauth-signing-key example-oauth-request))))

0 comments on commit 44467ef

Please sign in to comment.