You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by ja...@apache.org on 2012/01/03 20:33:21 UTC
[2/11] git commit: Fix whitespace
Fix whitespace
Project: http://git-wip-us.apache.org/repos/asf/couchdb/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb/commit/225b39b5
Tree: http://git-wip-us.apache.org/repos/asf/couchdb/tree/225b39b5
Diff: http://git-wip-us.apache.org/repos/asf/couchdb/diff/225b39b5
Branch: refs/heads/1.2.x
Commit: 225b39b5a42962a552eddeb904bbc68c1ea14a2b
Parents: 5ef0f3c
Author: Jan Lehnardt <ja...@apache.org>
Authored: Thu Nov 17 12:26:31 2011 +0100
Committer: Jan Lehnardt <ja...@apache.org>
Committed: Tue Jan 3 19:23:59 2012 +0100
----------------------------------------------------------------------
share/www/script/couch_test_runner.js | 8 +-
share/www/script/test/cookie_auth.js | 45 +++---
share/www/script/test/users_db_security.js | 221 +++++++++++++++++++++++
src/couchdb/couch_httpd_db.erl | 20 +-
src/couchdb/couch_view_group.erl | 4 +-
src/couchdb/couch_view_updater.erl | 2 +-
6 files changed, 261 insertions(+), 39 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/couchdb/blob/225b39b5/share/www/script/couch_test_runner.js
----------------------------------------------------------------------
diff --git a/share/www/script/couch_test_runner.js b/share/www/script/couch_test_runner.js
index 6316e20..61823c0 100644
--- a/share/www/script/couch_test_runner.js
+++ b/share/www/script/couch_test_runner.js
@@ -141,7 +141,7 @@ function setupAdminParty(fun) {
success : function() {
removeAdmins(confs, doneFun);
}
- }, "admins", remove[0], null);
+ }, "admins", remove[0], null);
} else {
doneFun();
}
@@ -238,13 +238,13 @@ function saveTestReport(report) {
report.db = db_info;
$.couch.info({success : function(node_info) {
report.node = node_info;
- db.saveDoc(report);
+ db.saveDoc(report);
}});
};
var createDb = function() {
db.create({success: function() {
- db.info({success:saveReport});
- }});
+ db.info({success:saveReport});
+ }});
};
db.info({error: createDb, success:saveReport});
}
http://git-wip-us.apache.org/repos/asf/couchdb/blob/225b39b5/share/www/script/test/cookie_auth.js
----------------------------------------------------------------------
diff --git a/share/www/script/test/cookie_auth.js b/share/www/script/test/cookie_auth.js
index 09bfd69..180d42e 100644
--- a/share/www/script/test/cookie_auth.js
+++ b/share/www/script/test/cookie_auth.js
@@ -12,7 +12,7 @@
couchTests.cookie_auth = function(debug) {
// This tests cookie-based authentication.
-
+
var db = new CouchDB("test_suite_db", {"X-Couch-Full-Commit":"false"});
db.deleteDb();
db.createDb();
@@ -34,13 +34,14 @@ couchTests.cookie_auth = function(debug) {
// try using an invalid cookie
var usersDb = new CouchDB("test_suite_users", {"X-Couch-Full-Commit":"false"});
usersDb.deleteDb();
-
+ usersDb.createDb();
+
// test that the users db is born with the auth ddoc
var ddoc = usersDb.open("_design/_auth");
T(ddoc.validate_doc_update);
-
+
// TODO test that changing the config so an existing db becomes the users db installs the ddoc also
-
+
var password = "3.141592653589";
// Create a user
@@ -48,11 +49,11 @@ couchTests.cookie_auth = function(debug) {
name: "Jason Davies",
roles: ["dev"]
}, password);
- T(usersDb.save(jasonUserDoc).ok);
-
+ T(usersDb.save(jasonUserDoc).ok);
+
var checkDoc = usersDb.open(jasonUserDoc._id);
T(checkDoc.name == "Jason Davies");
-
+
var jchrisUserDoc = CouchDB.prepareUserDoc({
name: "jchris@apache.org"
}, "funnybone");
@@ -70,7 +71,7 @@ couchTests.cookie_auth = function(debug) {
T(e.error == "conflict");
T(usersDb.last_req.status == 409);
}
-
+
// we can't create _names
var underscoreUserDoc = CouchDB.prepareUserDoc({
name: "_why"
@@ -83,12 +84,12 @@ couchTests.cookie_auth = function(debug) {
T(e.error == "forbidden");
T(usersDb.last_req.status == 403);
}
-
+
// we can't create docs with malformed ids
var badIdDoc = CouchDB.prepareUserDoc({
name: "foo"
}, "bar");
-
+
badIdDoc._id = "org.apache.couchdb:w00x";
try {
@@ -98,11 +99,11 @@ couchTests.cookie_auth = function(debug) {
T(e.error == "forbidden");
T(usersDb.last_req.status == 403);
}
-
+
// login works
T(CouchDB.login('Jason Davies', password).ok);
T(CouchDB.session().userCtx.name == 'Jason Davies');
-
+
// JSON login works
var xhr = CouchDB.request("POST", "/_session", {
headers: {"Content-Type": "application/json"},
@@ -153,12 +154,12 @@ couchTests.cookie_auth = function(debug) {
}
// test users db validations
- //
+ //
// test that you can't update docs unless you are logged in as the user (or are admin)
T(CouchDB.login("jchris@apache.org", "funnybone").ok);
T(CouchDB.session().userCtx.name == "jchris@apache.org");
T(CouchDB.session().userCtx.roles.length == 0);
-
+
jasonUserDoc.foo=3;
try {
@@ -171,7 +172,7 @@ couchTests.cookie_auth = function(debug) {
// test that you can't edit roles unless you are admin
jchrisUserDoc.roles = ["foo"];
-
+
try {
usersDb.save(jchrisUserDoc);
T(false && "Can't set roles unless you are admin. Should have thrown an error.");
@@ -179,16 +180,16 @@ couchTests.cookie_auth = function(debug) {
T(e.error == "forbidden");
T(usersDb.last_req.status == 403);
}
-
+
T(CouchDB.logout().ok);
- T(CouchDB.session().userCtx.roles[0] == "_admin");
+ T(CouchDB.session().userCtx.roles[0] == "_admin");
jchrisUserDoc.foo = ["foo"];
T(usersDb.save(jchrisUserDoc).ok);
// test that you can't save system (underscore) roles even if you are admin
jchrisUserDoc.roles = ["_bar"];
-
+
try {
usersDb.save(jchrisUserDoc);
T(false && "Can't add system roles to user's db. Should have thrown an error.");
@@ -196,18 +197,18 @@ couchTests.cookie_auth = function(debug) {
T(e.error == "forbidden");
T(usersDb.last_req.status == 403);
}
-
+
// make sure the foo role has been applied
T(CouchDB.login("jchris@apache.org", "funnybone").ok);
T(CouchDB.session().userCtx.name == "jchris@apache.org");
T(CouchDB.session().userCtx.roles.indexOf("_admin") == -1);
T(CouchDB.session().userCtx.roles.indexOf("foo") != -1);
-
+
// now let's make jchris a server admin
T(CouchDB.logout().ok);
T(CouchDB.session().userCtx.roles[0] == "_admin");
T(CouchDB.session().userCtx.name == null);
-
+
// set the -hashed- password so the salt matches
// todo ask on the ML about this
run_on_modified_server([{section: "admins",
@@ -233,7 +234,7 @@ couchTests.cookie_auth = function(debug) {
T(s.info.authentication_db == "test_suite_users");
// test that jchris still has the foo role
T(CouchDB.session().userCtx.roles.indexOf("foo") != -1);
- });
+ });
} finally {
// Make sure we erase any auth cookies so we don't affect other tests
http://git-wip-us.apache.org/repos/asf/couchdb/blob/225b39b5/share/www/script/test/users_db_security.js
----------------------------------------------------------------------
diff --git a/share/www/script/test/users_db_security.js b/share/www/script/test/users_db_security.js
new file mode 100644
index 0000000..8ea93db
--- /dev/null
+++ b/share/www/script/test/users_db_security.js
@@ -0,0 +1,221 @@
+// 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.users_db_security = function(debug) {
+ var usersDb = new CouchDB("test_suite_users", {"X-Couch-Full-Commit":"false"});
+ if (debug) debugger;
+
+ var loginUser = function(username) {
+ var pws = {
+ jan: "apple",
+ jchris: "mp3",
+ jchris1: "couch",
+ fdmanana: "foobar",
+ benoitc: "test"
+ };
+ var username1 = username.replace(/[0-9]$/, "");
+ var password = pws[username];
+ //console.log("Logging in '" + username1 + "' with password '" + password + "'");
+ T(CouchDB.login(username1, pws[username]).ok);
+ };
+
+ var open_as = function(db, docId, username) {
+ loginUser(username);
+ try {
+ return db.open(docId, {"anti-cache": Math.round(Math.random() * 100000)});
+ } finally {
+ CouchDB.logout();
+ }
+ };
+
+ var view_as = function(db, viewname, username) {
+ loginUser(username);
+ try {
+ return db.view(viewname);
+ } finally {
+ CouchDB.logout();
+ }
+ };
+
+ var save_as = function(db, doc, username)
+ {
+ loginUser(username);
+ try {
+ return db.save(doc);
+ } catch (ex) {
+ return ex;
+ } finally {
+ CouchDB.logout();
+ }
+ };
+
+ var testFun = function()
+ {
+ usersDb.deleteDb();
+ usersDb.createDb();
+
+ // _users db
+ // a doc with a field 'password' should be hashed to 'password_sha'
+ // with salt and salt stored in 'salt', 'password' is set to null.
+ // Exising 'password_sha' and 'salt' fields are overwritten with new values
+ // when a non-null 'password' field exists.
+ // anonymous should be able to create a user document
+ var userDoc = {
+ _id: "org.couchdb.user:jchris",
+ type: "user",
+ name: "jchris",
+ password: "mp3",
+ roles: []
+ };
+
+ // jan's gonna be admin as he's the first user
+ TEquals(true, usersDb.save(userDoc).ok, "should save document");
+ userDoc = usersDb.open("org.couchdb.user:jchris");
+ TEquals(undefined, userDoc.password, "password field should be null 1");
+ TEquals(40, userDoc.password_sha.length, "password_sha should exist");
+ TEquals(32, userDoc.salt.length, "salt should exist");
+
+ // create server admin
+ run_on_modified_server([
+ {
+ section: "admins",
+ key: "jan",
+ value: "apple"
+ }
+ ], function() {
+
+ // anonymous should not be able to read an existing user's user document
+ var res = usersDb.open("org.couchdb.user:jchris");
+ TEquals(null, res, "anonymous user doc read should be not found");
+
+ // user should be able to read their own document
+
+ var jchrisDoc = open_as(usersDb, "org.couchdb.user:jchris", "jchris");
+ TEquals("org.couchdb.user:jchris", jchrisDoc._id);
+
+ // user should bt able to update their own document
+ // new 'password' fields should trigger new hashing routine
+ jchrisDoc.password = "couch";
+
+ TEquals(true, save_as(usersDb, jchrisDoc, "jchris").ok);
+ var jchrisDoc = open_as(usersDb, "org.couchdb.user:jchris", "jchris1");
+
+ TEquals(undefined, jchrisDoc.password, "password field should be null 2");
+ TEquals(40, jchrisDoc.password_sha.length, "password_sha should exist");
+ TEquals(32, jchrisDoc.salt.length, "salt should exist");
+
+ TEquals(true, userDoc.salt != jchrisDoc.salt, "should have new salt");
+ TEquals(true, userDoc.password_sha != jchrisDoc.password_sha,
+ "should have new password_sha");
+
+ // user should not be able to read another user's user document
+ var fdmananaDoc = {
+ _id: "org.couchdb.user:fdmanana",
+ type: "user",
+ name: "fdmanana",
+ password: "foobar",
+ roles: []
+ };
+
+ usersDb.save(fdmananaDoc);
+
+ var fdmananaDocAsReadByjchris =
+ open_as(usersDb, "org.couchdb.user:fdmanana", "jchris1");
+ TEquals(null, fdmananaDocAsReadByjchris,
+ "should not_found opening another user's user doc");
+
+
+ // save a db admin
+ var benoitcDoc = {
+ _id: "org.couchdb.user:benoitc",
+ type: "user",
+ name: "benoitc",
+ password: "test",
+ roles: []
+ };
+ usersDb.save(benoitcDoc);
+
+ TEquals(true, CouchDB.login("jan", "apple").ok);
+
+ T(usersDb.setSecObj({
+ "admins" : {
+ roles : [],
+ names : ["benoitc"]
+ }
+ }).ok);
+ CouchDB.logout();
+
+ // user should not be able to read from any view
+ var ddoc = {
+ _id: "_design/user_db_auth",
+ views: {
+ test: {
+ map: "function(doc) { emit(doc._id, null); }"
+ }
+ }
+ };
+
+ save_as(usersDb, ddoc, "jan");
+
+ try {
+ usersDb.view("user_db_auth/test");
+ T(false, "user had access to view in admin db");
+ } catch(e) {
+ TEquals("forbidden", e.error,
+ "non-admins should not be able to read a view");
+ }
+
+ // admin should be able to read from any view
+ var result = view_as(usersDb, "user_db_auth/test", "jan");
+ TEquals(3, result.total_rows, "should allow access and list two users to admin");
+
+ // db admin should be able to read from any view
+ var result = view_as(usersDb, "user_db_auth/test", "benoitc");
+ TEquals(3, result.total_rows, "should allow access and list two users to db admin");
+
+ // non-admins can't read design docs
+ try {
+ open_as(usersDb, "_design/user_db_auth", "jchris1");
+ T(false, "non-admin read design doc, should not happen");
+ } catch(e) {
+ TEquals("forbidden", e.error, "non-admins can't read design docs");
+ }
+
+ // admin should be able to read and edit any user doc
+ fdmananaDoc.password = "mobile";
+ var result = save_as(usersDb, fdmananaDoc, "jan");
+ TEquals(true, result.ok, "admin should be able to update any user doc");
+
+ // db admin should be able to read and edit any user doc
+ fdmananaDoc.password = "mobile1";
+ var result = save_as(usersDb, fdmananaDoc, "benoitc");
+ TEquals(true, result.ok, "db admin should be able to update any user doc");
+
+ // ensure creation of old-style docs still works
+ var robertDoc = CouchDB.prepareUserDoc({ name: "robert" }, "anchovy");
+ var result = usersDb.save(robertDoc);
+ TEquals(true, result.ok, "old-style user docs should still be accepted");
+
+ // log in one last time so run_on_modified_server can clean up the admin account
+ TEquals(true, CouchDB.login("jan", "apple").ok);
+ });
+ };
+
+ usersDb.deleteDb();
+ run_on_modified_server(
+ [{section: "couch_httpd_auth",
+ key: "authentication_db", value: usersDb.name}],
+ testFun
+ );
+ usersDb.deleteDb(); // cleanup
+
+};
http://git-wip-us.apache.org/repos/asf/couchdb/blob/225b39b5/src/couchdb/couch_httpd_db.erl
----------------------------------------------------------------------
diff --git a/src/couchdb/couch_httpd_db.erl b/src/couchdb/couch_httpd_db.erl
index ff4d3ec..f2fab56 100644
--- a/src/couchdb/couch_httpd_db.erl
+++ b/src/couchdb/couch_httpd_db.erl
@@ -237,7 +237,7 @@ db_req(#httpd{method='POST',path_parts=[DbName]}=Req, Db) ->
?LOG_INFO("Batch doc error (~s): ~p",[DocId, Error])
end
end),
-
+
send_json(Req, 202, [], {[
{ok, true},
{id, DocId}
@@ -699,7 +699,7 @@ db_doc_req(#httpd{method='PUT'}=Req, Db, DocId) ->
update_type = UpdateType
} = parse_doc_query(Req),
couch_doc:validate_docid(DocId),
-
+
Loc = absolute_uri(Req, "/" ++ ?b2l(Db#db.name) ++ "/" ++ ?b2l(DocId)),
RespHeaders = [{"Location", Loc}],
case couch_util:to_list(couch_httpd:header_value(Req, "Content-Type")) of
@@ -721,7 +721,7 @@ db_doc_req(#httpd{method='PUT'}=Req, Db, DocId) ->
"ok" ->
% batch
Doc = couch_doc_from_req(Req, DocId, couch_httpd:json_body(Req)),
-
+
spawn(fun() ->
case catch(couch_db:update_doc(Db, Doc, [])) of
{ok, _} -> ok;
@@ -786,7 +786,7 @@ send_doc_efficiently(#httpd{mochi_req = MochiReq} = Req,
send_json(Req, 200, Headers, couch_doc:to_json_obj(Doc, Options));
true ->
Boundary = couch_uuids:random(),
- JsonBytes = ?JSON_ENCODE(couch_doc:to_json_obj(Doc,
+ JsonBytes = ?JSON_ENCODE(couch_doc:to_json_obj(Doc,
[attachments, follows, att_encoding_info | Options])),
{ContentType, Len} = couch_doc:len_doc_to_multi_part_stream(
Boundary,JsonBytes, Atts, true),
@@ -803,7 +803,7 @@ send_docs_multipart(Req, Results, Options1) ->
OuterBoundary = couch_uuids:random(),
InnerBoundary = couch_uuids:random(),
Options = [attachments, follows, att_encoding_info | Options1],
- CType = {"Content-Type",
+ CType = {"Content-Type",
"multipart/mixed; boundary=\"" ++ ?b2l(OuterBoundary) ++ "\""},
{ok, Resp} = start_chunked_response(Req, 200, [CType]),
couch_httpd:send_chunk(Resp, <<"--", OuterBoundary/binary>>),
@@ -821,8 +821,8 @@ send_docs_multipart(Req, Results, Options1) ->
({{not_found, missing}, RevId}) ->
RevStr = couch_doc:rev_to_str(RevId),
Json = ?JSON_ENCODE({[{"missing", RevStr}]}),
- couch_httpd:send_chunk(Resp,
- [<<"\r\nContent-Type: application/json; error=\"true\"\r\n\r\n">>,
+ couch_httpd:send_chunk(Resp,
+ [<<"\r\nContent-Type: application/json; error=\"true\"\r\n\r\n">>,
Json,
<<"\r\n--", OuterBoundary/binary>>])
end, Results),
@@ -858,7 +858,7 @@ receive_request_data(Req, LenLeft) when LenLeft > 0 ->
{Data, fun() -> receive_request_data(Req, LenLeft - iolist_size(Data)) end};
receive_request_data(_Req, _) ->
throw(<<"expected more data">>).
-
+
make_content_range(From, To, Len) ->
?l2b(io_lib:format("bytes ~B-~B/~B", [From, To, Len])).
@@ -1102,8 +1102,8 @@ db_attachment_req(#httpd{method=Method,mochi_req=MochiReq}=Req, Db, DocId, FileN
_Else ->
ok
end,
-
-
+
+
fun(Size) -> couch_httpd:recv(Req, Size) end
end,
att_len = case couch_httpd:header_value(Req,"Content-Length") of
http://git-wip-us.apache.org/repos/asf/couchdb/blob/225b39b5/src/couchdb/couch_view_group.erl
----------------------------------------------------------------------
diff --git a/src/couchdb/couch_view_group.erl b/src/couchdb/couch_view_group.erl
index 62bc5af..10a16fd 100644
--- a/src/couchdb/couch_view_group.erl
+++ b/src/couchdb/couch_view_group.erl
@@ -357,7 +357,7 @@ handle_info({'EXIT', UpPid, reset},
handle_info({'EXIT', _, reset}, State) ->
%% message from an old (probably pre-compaction) updater; ignore
{noreply, State};
-
+
handle_info({'EXIT', _FromPid, normal}, State) ->
{noreply, State};
@@ -669,7 +669,7 @@ init_group(Db, Fd, #group{def_lang=Lang,views=Views}=
UserReds),
{Count, Reduced}
end,
-
+
case couch_util:get_value(<<"collation">>, Options, <<"default">>) of
<<"default">> ->
Less = fun couch_view:less_json_ids/2;
http://git-wip-us.apache.org/repos/asf/couchdb/blob/225b39b5/src/couchdb/couch_view_updater.erl
----------------------------------------------------------------------
diff --git a/src/couchdb/couch_view_updater.erl b/src/couchdb/couch_view_updater.erl
index c4483fa..084ce77 100644
--- a/src/couchdb/couch_view_updater.erl
+++ b/src/couchdb/couch_view_updater.erl
@@ -156,7 +156,7 @@ load_doc(Db, DocInfo, MapQueue, DocOpts, IncludeDesign) ->
couch_work_queue:queue(MapQueue, {Seq, Doc})
end
end.
-
+
do_maps(#group{query_server = Qs} = Group, MapQueue, WriteQueue) ->
case couch_work_queue:dequeue(MapQueue) of
closed ->