diff --git a/src/oauth/client.clj b/src/oauth/client.clj index 0175508..967457b 100644 --- a/src/oauth/client.clj +++ b/src/oauth/client.clj @@ -42,7 +42,7 @@ "Fetch request token for the consumer." [consumer] (let [unsigned-params (sig/oauth-params consumer) - params (assoc unsigned-params :oauth_signature (sig/sign consumer + params (assoc unsigned-params :oauth_signature (sig/sign (consumer :digest-method) consumer (sig/base-string "POST" (:request-uri consumer) unsigned-params)))] @@ -78,7 +78,7 @@ to approve the Consumer's access to their account." ([consumer request-token verifier] (let [unsigned-params (sig/oauth-params consumer request-token verifier) params (assoc unsigned-params - :oauth_signature (sig/sign consumer + :oauth_signature (sig/sign (consumer :digest-method) consumer (sig/base-string "POST" (:access-uri consumer) unsigned-params)))] @@ -96,7 +96,7 @@ Authorization HTTP header or added as query parameters to the request." (let [unsigned-oauth-params (sig/oauth-params consumer token) unsigned-params (merge request-params unsigned-oauth-params)] - (assoc unsigned-oauth-params :oauth_signature (sig/sign consumer + (assoc unsigned-oauth-params :oauth_signature (sig/sign (consumer :digest-method) consumer (sig/base-string (-> request-method as-str upper-case) diff --git a/src/oauth/server.clj b/src/oauth/server.clj index 1abf2d1..600a5ee 100644 --- a/src/oauth/server.clj +++ b/src/oauth/server.clj @@ -61,17 +61,23 @@ [handler store] (fn [request] (let - [op (oauth-params request)] + [op (oauth-params request) + ;; _ (println op) + ] (if (not (empty? op)) (let [oauth-consumer (store/get-consumer store (op :oauth_consumer_key)) oauth-token (store/get-access-token store (op :oauth_token))] (if (sig/verify - (op :oauth_signature) - {:secret (and oauth-consumer (oauth-consumer :secret)) :signature-method :hmac-sha1} + (sig/url-decode (op :oauth_signature)) + (keyword (.toLowerCase (op :oauth_signature_method))) + oauth-consumer (request-base-string request) (and oauth-token (oauth-token :secret))) - (handler (assoc request :oauth-consumer oauth-consumer :oauth-token oauth-token :oauth-params op)) + (if (nil? oauth-token) + (handler (assoc request :oauth-consumer oauth-consumer :oauth-params op)) + (handler (assoc request :oauth-consumer oauth-consumer :oauth-token oauth-token :oauth-params op)) + ) (handler request) ) ) @@ -127,12 +133,12 @@ /oauth/access_token /oauth/authorize " - [handler] + [handler store] (fn [request] (condp = (:uri request) "/oauth/request_token" - (request-token request) + (request-token store request) "/oauth/access_token" - (access-token request) + (access-token store request) (handler request))) ) diff --git a/src/oauth/signature.clj b/src/oauth/signature.clj index 09dd9a2..f1de32d 100644 --- a/src/oauth/signature.clj +++ b/src/oauth/signature.clj @@ -20,7 +20,8 @@ [length] (. (new BigInteger (* 5 length) secure-random) toString 32)) -(def signature-methods {:hmac-sha1 "HMAC-SHA1"}) +(def signature-methods {:hmac-sha1 "HMAC-SHA1" + :plaintext "PLAINTEXT"}) (defn url-form-encode [params] (str-join "&" (map (fn [[k v]] @@ -30,7 +31,7 @@ ([method base-url c t params] (base-string method base-url (assoc params :oauth_consumer_key (:key c) :oauth_token (:token t) - :oauth_signature_method (signature-methods (:signature-method c)) + :oauth_signature_method (or (params :oauth_signature_method) (signature-methods (:signature-method c))) :oauth_version "1.0" )) ) @@ -41,22 +42,28 @@ (defmulti sign "Sign a base string for authentication." - (fn [c & r] (:signature-method c))) + (fn [c & r] c)) (defmethod sign :hmac-sha1 - [c base-string & [token-secret]] - (let [key (str (:secret c) "&" (or token-secret ""))] + [ _ c base-string & [token-secret]] + (let [key (str (url-encode (:secret c)) "&" (url-encode (or token-secret "")))] (digest/hmac key base-string))) -(defn verify [sig c base-string & [token-secret]] - (= sig (sign c base-string token-secret)) +(defmethod sign :plaintext + [ _ c base-string & [token-secret]] + (str (url-encode (c :secret)) "&" (url-encode token-secret))) + +(defn verify [sig digest-method c base-string & [token-secret]] + (do + (println sig (sign digest-method c base-string token-secret)) + (= sig (sign digest-method c base-string token-secret))) ) (defn url-encode "The java.net.URLEncoder class encodes for application/x-www-form-urlencoded, but OAuth requires RFC 3986 encoding." [s] - (-> (java.net.URLEncoder/encode s "UTF-8") + (-> (java.net.URLEncoder/encode (str s) "UTF-8") (.replace "+" "%20") (.replace "*" "%2A") (.replace "%7E" "~"))) diff --git a/test/oauth/client_test.clj b/test/oauth/client_test.clj index dfd7e82..b1af626 100644 --- a/test/oauth/client_test.clj +++ b/test/oauth/client_test.clj @@ -12,7 +12,7 @@ nil nil :hmac-sha1)] - (is (= (sig/sign c (sig/base-string "GET" + (is (= (sig/sign :hmac-sha1 c (sig/base-string "GET" "http://photos.example.net/photos" {:oauth_consumer_key "dpf43f3p2l4k3l03" :oauth_token "nnch734d00sl2jdk" diff --git a/test/oauth/server_test.clj b/test/oauth/server_test.clj index 40989ba..32f262e 100644 --- a/test/oauth/server_test.clj +++ b/test/oauth/server_test.clj @@ -81,7 +81,7 @@ ))) (defn app [req] - (if (req :oauth-token) + (if (or (req :oauth-token)(req :oauth-consumer)) { :status 200 :request req @@ -93,15 +93,7 @@ :body "" })) -(defn token-finder [consumer token] - ["kd94hf93k423kf44" "pfkkdhi9sl3r4s00"]) -;; (if (and (= consumer "0685bd9184jfhq22") (= token "ad180jjd733klru7")) -;; ["kd94hf93k423kf44" "pfkkdhi9sl3r4s00"] nil -;; )) -(defn store-token-finder [store] - (fn [consumer token] - ) - ) + (deftest #^{:doc "wrap oauth"} wrap-oauth @@ -112,6 +104,7 @@ (is (= 401 ((oauth-app {:headers { :authorize "Basic realm=\"Secure Area\""}}) :status))) (is (= 401 ((oauth-app {:headers { :authorize "OAuth realm=\"http://sp.example.com/\", oauth_consumer_key=\"0685bd9184jfhq22\", oauth_token=\"ad180jjd733klru7\", oauth_signature_method=\"HMAC-SHA1\", oauth_signature=\"fake\", oauth_timestamp=\"137131200\", oauth_nonce=\"4572616e48616d6d65724c61686176\",oauth_version=\"1.0\""}}) :status))) + ;; 3 legged HMAC-SHA1 (is (= 200 ((oauth-app { :request-method :get :server-name "photos.example.net" @@ -119,6 +112,25 @@ :scheme :http :params {:file "vacation.jpg" :size "original"} :headers { :authorize "OAuth realm=\"http://sp.example.com/\", oauth_consumer_key=\"dpf43f3p2l4k3l03\", oauth_token=\"nnch734d00sl2jdk\", oauth_signature_method=\"HMAC-SHA1\", oauth_signature=\"tR3%2BTy81lMeYAr%2FFid0kMTYa%2FWM%3D\", oauth_timestamp=\"1191242096\", oauth_nonce=\"kllo9940pd9333jh\",oauth_version=\"1.0\""}}) :status))) + + ;; 3 legged PLAINTEXT + (is (= 200 ((oauth-app { + :request-method :get + :server-name "photos.example.net" + :uri "/photos" + :scheme :http + :params {:file "vacation.jpg" :size "original"} + :headers { :authorize "OAuth realm=\"http://sp.example.com/\", oauth_consumer_key=\"dpf43f3p2l4k3l03\", oauth_token=\"nnch734d00sl2jdk\", oauth_signature_method=\"PLAINTEXT\", oauth_signature=\"kd94hf93k423kf44%26pfkkdhi9sl3r4s00\", oauth_timestamp=\"1191242096\", oauth_nonce=\"kllo9940pd9333jh\",oauth_version=\"1.0\""}}) :status))) + + ;; 2 legged PLAINTEXT + (is (= 200 ((oauth-app { + :request-method :get + :server-name "photos.example.net" + :uri "/photos" + :scheme :http + :params {:file "vacation.jpg" :size "original"} + :headers { :authorize "OAuth realm=\"http://sp.example.com/\", oauth_consumer_key=\"dpf43f3p2l4k3l03\", oauth_signature_method=\"PLAINTEXT\", oauth_signature=\"kd94hf93k423kf44%26\", oauth_timestamp=\"1191242096\", oauth_nonce=\"kllo9940pd9333jh\",oauth_version=\"1.0\""}}) :status))) + )) (deftest @@ -147,6 +159,43 @@ ) )) ) + +;; +(deftest + #^{:doc "integrated token request in app using example from http://oauth.net/core/1.0a/#anchor43"} + integrated-token-request + (let [oauth-app (os/wrap-oauth (os/oauth-token-manager app :memory ) :memory) + _ (store/store-consumer :memory {:key "dpf43f3p2l4k3l03" :secret "kd94hf93k423kf44"})] + (is (= 401 ((oauth-app {}) :status))) + (is (= 401 ((oauth-app {:headers { :authorize "Basic realm=\"Secure Area\""}}) :status))) + (is (= 401 ((oauth-app {:headers { :authorize "OAuth realm=\"https://photos.example.net/\", oauth_consumer_key=\"dpf43f3p2l4k3l03\", oauth_signature_method=\"HMAC-SHA1\", oauth_signature=\"fake\", oauth_timestamp=\"1191242090\", oauth_nonce=\"hsu94j3884jdopsl\", oauth_version=\"1.0\", oauth_callback=\"http%3A%2F%2Fprinter.example.com%2Frequest_token_ready\""}}) :status))) + + (let [ response (oauth-app { + :request-method :post + :server-name "photos.example.net" + :uri "/oauth/request_token" + :scheme :https + :headers { :authorize "OAuth realm=\"https://photos.example.net/\", oauth_consumer_key=\"dpf43f3p2l4k3l03\", oauth_signature_method=\"PLAINTEXT\", oauth_signature=\"kd94hf93k423kf44%26\", oauth_timestamp=\"1191242090\", oauth_nonce=\"hsu94j3884jdopsl\", oauth_callback=\"http://printer.example.com/request_token_ready\" oauth_version=\"1.0\""}}) + token-body (response :body) + _ (println token-body) + token-params (os/parse-form-encoded (response :body))] + (is(= 200 (response :status))) + (is (not (nil? token-body))) + (is (not (nil? token-params))) + (is (not (nil? (token-params :oauth_token)))) + (is (not (nil? (token-params :oauth_secret)))) + (is (= (token-params :oauth_callback_confirmed) "true")) + (is (nil? (token-params :oauth_verifier))) + (let [token (store/get-request-token :memory (token-params :oauth_token))] + (is (not (nil? token))) + (is (= (token :token) (token-params :oauth_token))) + (is (= (token :secret) (token-params :oauth_secret))) + (is (= (token :consumer) (store/get-consumer :memory "dpf43f3p2l4k3l03"))) + (is (not (nil? (token :verifier)))) + )) + + )) + (deftest #^{:doc "access token request"} diff --git a/test/oauth/signature_test.clj b/test/oauth/signature_test.clj index 44455a1..0323d8c 100644 --- a/test/oauth/signature_test.clj +++ b/test/oauth/signature_test.clj @@ -43,13 +43,13 @@ )) (deftest - #^{:doc "Test signing of a request."} - signature + #^{:doc "Test hmac-sha1 signing of a request."} + hmac-sha1-signature (let [c { :key "dpf43f3p2l4k3l03" :secret "kd94hf93k423kf44" :signature-method :hmac-sha1}] - (is (= (sig/sign c (sig/base-string "GET" + (is (= (sig/sign :hmac-sha1 c (sig/base-string "GET" "http://photos.example.net/photos" {:oauth_consumer_key "dpf43f3p2l4k3l03" :oauth_token "nnch734d00sl2jdk" @@ -62,6 +62,34 @@ "pfkkdhi9sl3r4s00") "tR3+Ty81lMeYAr/Fid0kMTYa/WM=")))) +(deftest + #^{:doc "test plaintext signatures"} + plaintext-signature + (let [c { :key "dpf43f3p2l4k3l03" + :secret "kd94hf93k423kf44" + :signature-method :hmac-sha1}] ; I'm intentionally testing with this as sha1 + + (is (= "kd94hf93k423kf44&" (sig/sign :plaintext c (sig/base-string "POST" + "https://photos.example.net/request_token" + {:oauth_consumer_key "dpf43f3p2l4k3l03" + :oauth_signature_method "PLAINTEXT" + :oauth_timestamp "1191242090" + :oauth_nonce "hsu94j3884jdopsl" + :oauth_version "1.0"})) + )) + (is (= "kd94hf93k423kf44&hdhd0244k9j7ao03" (sig/sign :plaintext c (sig/base-string "POST" + "https://photos.example.net/access_token" + {:oauth_consumer_key "dpf43f3p2l4k3l03" + :oauth_signature_method "PLAINTEXT" + :oauth_timestamp "1191242090" + :oauth_token "hh5s93j4hdidpola" + :oauth_nonce "hsu94j3884jdopsl" + :oauth_verifier "hfdp7dh39dks9884" + :oauth_version "1.0"}) + "hdhd0244k9j7ao03") + )) + + )) (deftest #^{:doc "Test verification of signed request."} verify @@ -69,7 +97,7 @@ :secret "kd94hf93k423kf44" :signature-method :hmac-sha1}] - (is (sig/verify "tR3+Ty81lMeYAr/Fid0kMTYa/WM=" c (sig/base-string "GET" + (is (sig/verify "tR3+Ty81lMeYAr/Fid0kMTYa/WM=" :hmac-sha1 c (sig/base-string "GET" "http://photos.example.net/photos" {:oauth_consumer_key "dpf43f3p2l4k3l03" :oauth_token "nnch734d00sl2jdk" @@ -81,6 +109,14 @@ :size "original"}) "pfkkdhi9sl3r4s00") ) + (is (sig/verify "kd94hf93k423kf44&" :plaintext c (sig/base-string "POST" + "https://photos.example.net/request_token" + {:oauth_consumer_key "dpf43f3p2l4k3l03" + :oauth_signature_method "PLAINTEXT" + :oauth_timestamp "1191242090" + :oauth_nonce "hsu94j3884jdopsl" + :oauth_version "1.0"})) + ) ))