diff options
author | Damien F. Katz <damien@apache.org> | 2009-08-04 19:50:46 +0000 |
---|---|---|
committer | Damien F. Katz <damien@apache.org> | 2009-08-04 19:50:46 +0000 |
commit | 8e2215ee6306b0f4c13553796d401e9f5f93bcb6 (patch) | |
tree | 948b9179887e73379bc445b9ad058de3a0bbe870 /share/www/script/test | |
parent | fd72a9bc48ebab76976f538c28459a0e26aa1750 (diff) |
Initial check-in of OAuth and cookie authentication.
git-svn-id: https://svn.apache.org/repos/asf/couchdb/trunk@800938 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'share/www/script/test')
-rw-r--r-- | share/www/script/test/changes.js | 4 | ||||
-rw-r--r-- | share/www/script/test/cookie_auth.js | 162 | ||||
-rw-r--r-- | share/www/script/test/oauth.js | 166 | ||||
-rw-r--r-- | share/www/script/test/security_validation.js | 12 | ||||
-rw-r--r-- | share/www/script/test/show_documents.js | 2 |
5 files changed, 337 insertions, 9 deletions
diff --git a/share/www/script/test/changes.js b/share/www/script/test/changes.js index 1800ca82..d8abcc71 100644 --- a/share/www/script/test/changes.js +++ b/share/www/script/test/changes.js @@ -195,8 +195,8 @@ couchTests.changes = function(debug) { // test for userCtx run_on_modified_server( [{section: "httpd", - key: "authentication_handler", - value: "{couch_httpd, special_test_authentication_handler}"}, + key: "authentication_handlers", + value: "{couch_httpd_auth, special_test_authentication_handler}"}, {section:"httpd", key: "WWW-Authenticate", value: "X-Couch-Test-Auth"}], diff --git a/share/www/script/test/cookie_auth.js b/share/www/script/test/cookie_auth.js new file mode 100644 index 00000000..63ab21b9 --- /dev/null +++ b/share/www/script/test/cookie_auth.js @@ -0,0 +1,162 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. + +couchTests.cookie_auth = function(debug) { + // This tests cookie-based authentication. + + var db = new CouchDB("test_suite_db"); + db.deleteDb(); + db.createDb(); + if (debug) debugger; + + // Simple secret key generator + function generateSecret(length) { + var secret = ''; + for (var i=0; i<length; i++) { + secret += String.fromCharCode(Math.floor(Math.random() * 256)); + } + return secret; + } + // this function will be called on the modified server + var testFun = function () { + try { + // try using an invalid cookie + var usersDb = new CouchDB("test_suite_users"); + usersDb.deleteDb(); + usersDb.createDb(); + + var password = "3.141592653589"; + + // Create a user + T(usersDb.save({ + _id: "a1", + salt: "123", + password_sha: "8da1CtkFvb58LWrnup5chgdZVUs=", + username: "Jason Davies", + author: "Jason Davies", + type: "user", + roles: ["_admin"] + }).ok); + + var validationDoc = { + _id : "_design/validate", + validate_doc_update: "(" + (function (newDoc, oldDoc, userCtx) { + // docs should have an author field. + if (!newDoc._deleted && !newDoc.author) { + throw {forbidden: + "Documents must have an author field"}; + } + if (oldDoc && oldDoc.author != userCtx.name) { + throw {unauthorized: + "You are not the author of this document. You jerk."+userCtx.name}; + } + }).toString() + ")" + }; + + T(db.save(validationDoc).ok); + + + + T(CouchDB.login('Jason Davies', password).ok); + // update the credentials document + var doc = usersDb.open("a1"); + doc.foo=2; + T(usersDb.save(doc).ok); + + // Save a document that's missing an author field. + try { + // db has a validation function + db.save({foo:1}); + T(false && "Can't get here. Should have thrown an error 2"); + } catch (e) { + T(e.error == "forbidden"); + T(db.last_req.status == 403); + } + + // TODO should login() throw an exception here? + T(!CouchDB.login('Jason Davies', "2.71828").ok); + T(!CouchDB.login('Robert Allen Zimmerman', 'd00d').ok); + + // test redirect + xhr = CouchDB.request("POST", "/_session?next=/", { + headers: {"Content-Type": "application/x-www-form-urlencoded"}, + body: "username=Jason%20Davies&password="+encodeURIComponent(password) + }); + // should this be a redirect code instead of 200? + T(xhr.status == 200); + + usersDb.deleteDb(); + // test user creation + T(CouchDB.createUser("test", "testpassword", "test@somemail.com", ['read', 'write']).ok); + + // make sure we create a unique user + T(!CouchDB.createUser("test", "testpassword2", "test2@somemail.com", ['read', 'write']).ok); + + // test login + T(CouchDB.login("test", "testpassword").ok); + T(!CouchDB.login('test', "testpassword2").ok); + + // test update user without changing password + T(CouchDB.updateUser("test", "test2@somemail.com").ok); + result = usersDb.view("_auth/users", {key: "test"}); + T(result.rows[0].value['email'] == "test2@somemail.com"); + + + // test changing password + result = usersDb.view("_auth/users", {key: "test"}); + T(CouchDB.updateUser("test", "test2@somemail.com", [], "testpassword2", "testpassword").ok); + result1 = usersDb.view("_auth/users", {key: "test"}); + T(result.rows[0].value['password_sha'] != result1.rows[0].value['password_sha']); + + + // test changing password with passing old password + T(!CouchDB.updateUser("test", "test2@somemail.com", [], "testpassword2").ok); + + // test changing password whith bad old password + T(!CouchDB.updateUser("test", "test2@somemail.com", [], "testpassword2", "badpasswword").ok); + + // Only admins can change roles + T(!CouchDB.updateUser("test", "test2@somemail.com", ['read', 'write']).ok); + + T(CouchDB.logout().ok); + + T(CouchDB.updateUser("test", "test2@somemail.com").ok); + result = usersDb.view("_auth/users", {key: "test"}); + T(result.rows[0].value['email'] == "test2@somemail.com"); + + // test changing password, we don't need to set old password when we are admin + result = usersDb.view("_auth/users", {key: "test"}); + T(CouchDB.updateUser("test", "test2@somemail.com", [], "testpassword3").ok); + result1 = usersDb.view("_auth/users", {key: "test"}); + T(result.rows[0].value['password_sha'] != result1.rows[0].value['password_sha']); + + // Only admins can change roles + T(CouchDB.updateUser("test", "test2@somemail.com", ['read']).ok); + + } finally { + // Make sure we erase any auth cookies so we don't affect other tests + T(CouchDB.logout().ok); + } + }; + + run_on_modified_server( + [{section: "httpd", + key: "authentication_handlers", + value: "{couch_httpd_auth, cookie_authentication_handler}"}, + {section: "couch_httpd_auth", + key: "secret", value: generateSecret(64)}, + {section: "couch_httpd_auth", + key: "authentication_db", value: "test_suite_users"}], + testFun + ); + +}; diff --git a/share/www/script/test/oauth.js b/share/www/script/test/oauth.js new file mode 100644 index 00000000..fb4ab818 --- /dev/null +++ b/share/www/script/test/oauth.js @@ -0,0 +1,166 @@ +// Licensed under the Apache License, Version 2.0 (the "License"); you may not +// use this file except in compliance with the License. You may obtain a copy +// of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations under +// the License. + +couchTests.oauth = function(debug) { + // This tests OAuth authentication. + + var authorization_url = "/_oauth/authorize"; + + var db = new CouchDB("test_suite_db"); + db.deleteDb(); + db.createDb(); + if (debug) debugger; + + var dbA = new CouchDB("test_suite_db_a"); + var dbB = new CouchDB("test_suite_db_b"); + dbA.deleteDb(); + dbA.createDb(); + dbB.deleteDb(); + dbB.createDb(); + + // Simple secret key generator + function generateSecret(length) { + var secret = ''; + for (var i=0; i<length; i++) { + secret += String.fromCharCode(Math.floor(Math.random() * 256)); + } + return secret; + } + + function oauthRequest(path, message, accessor, method) { + message.action = path; + message.method = method || 'GET'; + OAuth.SignatureMethod.sign(message, accessor); + var parameters = message.parameters; + if (method == "POST" || method == "GET") { + if (method == "GET") { + return CouchDB.request("GET", OAuth.addToURL(path, parameters)); + } else { + return CouchDB.request("POST", path, { + headers: {"Content-Type": "application/x-www-form-urlencoded"}, + body: OAuth.formEncode(parameters) + }); + } + } else { + return CouchDB.request("GET", path, { + headers: {Authorization: OAuth.getAuthorizationHeader('', parameters)} + }); + } + } + + var consumerSecret = generateSecret(64); + var tokenSecret = generateSecret(64); + + var host = CouchDB.host; + var dbPair = { + source: { + url: "http://" + host + "/test_suite_db_a", + auth: { + oauth: { + consumer_key: "key", + consumer_secret: consumerSecret, + token_secret: tokenSecret, + token: "foo" + } + } + }, + target: "http://" + host + "/test_suite_db_b" + }; + + // this function will be called on the modified server + var testFun = function () { + try { + var usersDb = new CouchDB("test_suite_users"); + usersDb.deleteDb(); + usersDb.createDb(); + + // Create a user + T(CouchDB.createUser("jason", "testpassword", "test@somemail.com", ['test'], true).ok); + + var accessor = { + consumerSecret: consumerSecret, + tokenSecret: tokenSecret + }; + + var signatureMethods = ["PLAINTEXT", "HMAC-SHA1"]; + var consumerKeys = {key: 200, nonexistent_key: 400}; + + for (var i=0; i<signatureMethods.length; i++) { + for (var consumerKey in consumerKeys) { + var expectedCode = consumerKeys[consumerKey]; + var message = { + parameters: { + oauth_signature_method: signatureMethods[i], + oauth_consumer_key: consumerKey, + oauth_token: "foo", + oauth_token_secret: tokenSecret, + oauth_version: "1.0" + } + }; + + // Get request token via Authorization header + xhr = oauthRequest("http://" + host + "/_oauth/request_token", message, accessor); + T(xhr.status == expectedCode); + + // GET request token via query parameters + xhr = oauthRequest("http://" + host + "/_oauth/request_token", message, accessor, "GET"); + T(xhr.status == expectedCode); + + responseMessage = OAuth.decodeForm(xhr.responseText); + + // Obtaining User Authorization + //Only needed for 3-legged OAuth + //xhr = CouchDB.request("GET", authorization_url + '?oauth_token=' + responseMessage.oauth_token); + //T(xhr.status == expectedCode); + + xhr = oauthRequest("http://" + host + "/_session", message, accessor); + T(xhr.status == expectedCode); + if (xhr.status == expectedCode == 200) { + data = JSON.parse(xhr.responseText); + T(data.name == "jason"); + T(data.roles[0] == "test"); + } + + xhr = oauthRequest("http://" + host + "/_session?foo=bar", message, accessor); + T(xhr.status == expectedCode); + + // Replication + var result = CouchDB.replicate(dbPair.source, dbPair.target); + T(result.ok); + } + } + + } finally { + } + }; + + run_on_modified_server( + [{section: "httpd", + key: "WWW-Authenticate", value: 'Basic realm="administrator",OAuth'}, + {section: "couch_httpd_auth", + key: "secret", value: generateSecret(64)}, + {section: "couch_httpd_auth", + key: "authentication_db", value: "test_suite_users"}, + {section: "oauth_consumer_secrets", + key: "key", value: consumerSecret}, + {section: "oauth_token_users", + key: "foo", value: "jason"}, + {section: "oauth_token_secrets", + key: "foo", value: tokenSecret}, + {section: "couch_httpd_oauth", + key: "authorization_url", value: authorization_url}, + {section: "httpd", + key: "authentication_handlers", + value: "{couch_httpd_oauth, oauth_authentication_handler}, {couch_httpd_auth, default_authentication_handler}"}], + testFun + ); +}; diff --git a/share/www/script/test/security_validation.js b/share/www/script/test/security_validation.js index 10553e5e..52f895bd 100644 --- a/share/www/script/test/security_validation.js +++ b/share/www/script/test/security_validation.js @@ -39,14 +39,14 @@ couchTests.security_validation = function(debug) { run_on_modified_server( [{section: "httpd", - key: "authentication_handler", - value: "{couch_httpd, special_test_authentication_handler}"}, + key: "authentication_handlers", + value: "{couch_httpd_auth, special_test_authentication_handler}"}, {section:"httpd", key: "WWW-Authenticate", value: "X-Couch-Test-Auth"}], function () { - // try saving document usin the wrong credentials + // try saving document using the wrong credentials var wrongPasswordDb = new CouchDB("test_suite_db", {"WWW-Authenticate": "X-Couch-Test-Auth Damien Katz:foo"} ); @@ -59,8 +59,8 @@ couchTests.security_validation = function(debug) { T(wrongPasswordDb.last_req.status == 401); } - // test force_login=true. - var resp = wrongPasswordDb.request("GET", "/_whoami?force_login=true"); + // test force basic login + var resp = wrongPasswordDb.request("GET", "/_session?basic=true"); var err = JSON.parse(resp.responseText); T(err.error == "unauthorized"); T(resp.status == 401); @@ -104,7 +104,7 @@ couchTests.security_validation = function(debug) { T(userDb.save(designDoc).ok); // test the _whoami endpoint - var resp = userDb.request("GET", "/_whoami"); + var resp = userDb.request("GET", "/_session"); var user = JSON.parse(resp.responseText) T(user.name == "Damien Katz"); // test that the roles are listed properly diff --git a/share/www/script/test/show_documents.js b/share/www/script/test/show_documents.js index a1138596..c87cfb0b 100644 --- a/share/www/script/test/show_documents.js +++ b/share/www/script/test/show_documents.js @@ -335,7 +335,7 @@ couchTests.show_documents = function(debug) { var doc2 = {_id:"foo", a:2}; db.save(doc1); - //create the conflict with a all_or_nothing bulk docs request + // create the conflict with an all_or_nothing bulk docs request var docs = [doc2]; db.bulkSave(docs, {all_or_nothing:true}); |