You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by jc...@apache.org on 2010/01/18 04:45:55 UTC

svn commit: r900275 - in /couchdb/trunk: share/www/ share/www/dialog/ share/www/script/ share/www/script/test/ src/couchdb/

Author: jchris
Date: Mon Jan 18 03:45:54 2010
New Revision: 900275

URL: http://svn.apache.org/viewvc?rev=900275&view=rev
Log:
normalize userCtx name and roles, also, no log in via a conflict doc

Modified:
    couchdb/trunk/share/www/_sidebar.html
    couchdb/trunk/share/www/dialog/_create_admin.html
    couchdb/trunk/share/www/dialog/_login.html
    couchdb/trunk/share/www/dialog/_signup.html
    couchdb/trunk/share/www/script/couch.js
    couchdb/trunk/share/www/script/couch_test_runner.js
    couchdb/trunk/share/www/script/futon.js
    couchdb/trunk/share/www/script/jquery.couch.js
    couchdb/trunk/share/www/script/test/cookie_auth.js
    couchdb/trunk/share/www/script/test/oauth.js
    couchdb/trunk/share/www/script/test/security_validation.js
    couchdb/trunk/share/www/script/test/users_db.js
    couchdb/trunk/src/couchdb/couch_db.hrl
    couchdb/trunk/src/couchdb/couch_httpd.erl
    couchdb/trunk/src/couchdb/couch_httpd_auth.erl
    couchdb/trunk/src/couchdb/couch_httpd_db.erl

Modified: couchdb/trunk/share/www/_sidebar.html
URL: http://svn.apache.org/viewvc/couchdb/trunk/share/www/_sidebar.html?rev=900275&r1=900274&r2=900275&view=diff
==============================================================================
--- couchdb/trunk/share/www/_sidebar.html (original)
+++ couchdb/trunk/share/www/_sidebar.html Mon Jan 18 03:45:54 2010
@@ -35,12 +35,12 @@
         <a href="#" class="signup">Signup</a> or <a href="#" class="login">Login</a>
       </span>
       <span class="loggedin">
-        Welcome <a class="username">?</a>! 
+        Welcome <a class="name">?</a>! 
         <br/>
         <a href="#" class="logout">Logout</a>
       </span>
       <span class="loggedinadmin">
-        Welcome <a class="username">?</a>! 
+        Welcome <a class="name">?</a>! 
         <br/>
         <a href="#" class="createadmin">Setup more admins</a> or
         <a href="#" class="logout">Logout</a> 

Modified: couchdb/trunk/share/www/dialog/_create_admin.html
URL: http://svn.apache.org/viewvc/couchdb/trunk/share/www/dialog/_create_admin.html?rev=900275&r1=900274&r2=900275&view=diff
==============================================================================
--- couchdb/trunk/share/www/dialog/_create_admin.html (original)
+++ couchdb/trunk/share/www/dialog/_create_admin.html Mon Jan 18 03:45:54 2010
@@ -27,7 +27,7 @@
     </p>
     <table summary=""><tbody><tr>
       <th><label>Username:</label></th>
-      <td><input type="text" name="username" size="24"></td>
+      <td><input type="text" name="name" size="24"></td>
     </tr><tr>
       <th><label>Password:</label></th>
       <td><input type="password" name="password" size="24"></td>

Modified: couchdb/trunk/share/www/dialog/_login.html
URL: http://svn.apache.org/viewvc/couchdb/trunk/share/www/dialog/_login.html?rev=900275&r1=900274&r2=900275&view=diff
==============================================================================
--- couchdb/trunk/share/www/dialog/_login.html (original)
+++ couchdb/trunk/share/www/dialog/_login.html Mon Jan 18 03:45:54 2010
@@ -16,11 +16,11 @@
   <h2>Login</h2>
   <fieldset>
     <p class="help">
-      Login to CouchDB with your username and password.
+      Login to CouchDB with your name and password.
     </p>
     <table summary=""><tbody><tr>
       <th><label>Username:</label></th>
-      <td><input type="text" name="username" size="24"></td>
+      <td><input type="text" name="name" size="24"></td>
     </tr><tr>
       <th><label>Password:</label></th>
       <td><input type="password" name="password" size="24"></td>

Modified: couchdb/trunk/share/www/dialog/_signup.html
URL: http://svn.apache.org/viewvc/couchdb/trunk/share/www/dialog/_signup.html?rev=900275&r1=900274&r2=900275&view=diff
==============================================================================
--- couchdb/trunk/share/www/dialog/_signup.html (original)
+++ couchdb/trunk/share/www/dialog/_signup.html Mon Jan 18 03:45:54 2010
@@ -21,7 +21,7 @@
     </p>
     <table summary=""><tbody><tr>
       <th><label>Username:</label></th>
-      <td><input type="text" name="username" size="24"></td>
+      <td><input type="text" name="name" size="24"></td>
     </tr><tr>
       <th><label>Password:</label></th>
       <td><input type="password" name="password" size="24"></td>

Modified: couchdb/trunk/share/www/script/couch.js
URL: http://svn.apache.org/viewvc/couchdb/trunk/share/www/script/couch.js?rev=900275&r1=900274&r2=900275&view=diff
==============================================================================
--- couchdb/trunk/share/www/script/couch.js [utf-8] (original)
+++ couchdb/trunk/share/www/script/couch.js [utf-8] Mon Jan 18 03:45:54 2010
@@ -121,7 +121,7 @@
       CouchDB.maybeThrowError(this.last_req);
       var results = JSON.parse(this.last_req.responseText);
       for (var i = 0; i < docs.length; i++) {
-        if(results[i].rev) {
+        if(results[i] && results[i].rev) {
           docs[i]._rev = results[i].rev;
         }
       }
@@ -322,11 +322,11 @@
 // Use this from callers to check HTTP status or header values of requests.
 CouchDB.last_req = null;
 
-CouchDB.login = function(username, password) {
+CouchDB.login = function(name, password) {
   CouchDB.last_req = CouchDB.request("POST", "/_session", {
     headers: {"Content-Type": "application/x-www-form-urlencoded",
       "X-CouchDB-WWW-Authenticate": "Cookie"},
-    body: "username=" + encodeURIComponent(username) + "&password="
+    body: "name=" + encodeURIComponent(name) + "&password="
       + encodeURIComponent(password)
   });
   return JSON.parse(CouchDB.last_req.responseText);
@@ -350,7 +350,7 @@
 CouchDB.user_prefix = "org.couchdb.user:";
 
 CouchDB.prepareUserDoc = function(user_doc, new_password) {
-  user_doc._id = user_doc._id || CouchDB.user_prefix + user_doc.username;
+  user_doc._id = user_doc._id || CouchDB.user_prefix + user_doc.name;
   if (new_password) {
     // handle the password crypto
     user_doc.salt = CouchDB.newUuids(1)[0];

Modified: couchdb/trunk/share/www/script/couch_test_runner.js
URL: http://svn.apache.org/viewvc/couchdb/trunk/share/www/script/couch_test_runner.js?rev=900275&r1=900274&r2=900275&view=diff
==============================================================================
--- couchdb/trunk/share/www/script/couch_test_runner.js (original)
+++ couchdb/trunk/share/www/script/couch_test_runner.js Mon Jan 18 03:45:54 2010
@@ -138,7 +138,8 @@
       }
     };
     $.couch.session({
-      success : function(userCtx) {
+      success : function(resp) {
+        var userCtx = resp.userCtx;
         if (userCtx.name && userCtx.roles.indexOf("_admin") != -1) {
           // admin but not admin party. dialog offering to make admin party
           $.showDialog("dialog/_admin_party.html", {

Modified: couchdb/trunk/share/www/script/futon.js
URL: http://svn.apache.org/viewvc/couchdb/trunk/share/www/script/futon.js?rev=900275&r1=900274&r2=900275&view=diff
==============================================================================
--- couchdb/trunk/share/www/script/futon.js (original)
+++ couchdb/trunk/share/www/script/futon.js Mon Jan 18 03:45:54 2010
@@ -14,9 +14,9 @@
 
   function Session() {
     
-    function doLogin(username, password, callback) {
+    function doLogin(name, password, callback) {
       $.couch.login({
-        username : username,
+        name : name,
         password : password,
         success : function() {
           $.futon.session.sidebar();
@@ -24,36 +24,36 @@
         },
         error : function(code, error, reason) {
           $.futon.session.sidebar();
-          callback({username : "Error logging in: "+reason});
+          callback({name : "Error logging in: "+reason});
         }
       });
     };
     
-    function doSignup(username, password, callback, runLogin) {
+    function doSignup(name, password, callback, runLogin) {
       $.couch.signup({
-        username : username
+        name : name
       }, password, {
         success : function() {
           if (runLogin) {
-            doLogin(username, password, callback);            
+            doLogin(name, password, callback);            
           } else {
             callback();
           }
         },
         error : function(status, error, reason) {
           $.futon.session.sidebar();
-          if (error = "conflict") {
-            callback({username : "Name '"+username+"' is taken"});
+          if (error == "conflict") {
+            callback({name : "Name '"+name+"' is taken"});
           } else {
-            callback({username : "Signup error:  "+reason});
+            callback({name : "Signup error:  "+reason});
           }
         }
       });
     };
     
     function validateUsernameAndPassword(data, callback) {
-      if (!data.username || data.username.length == 0) {
-        callback({username: "Please enter a username."});
+      if (!data.name || data.name.length == 0) {
+        callback({name: "Please enter a name."});
         return false;
       };
       if (!data.password || data.password.length == 0) {
@@ -70,10 +70,10 @@
           $.couch.config({
             success : function() {
               callback();
-              doLogin(data.username, data.password, callback);            
-              doSignup(data.username, null, callback, false);
+              doLogin(data.name, data.password, callback);            
+              doSignup(data.name, null, callback, false);
             }
-          }, "admins", data.username, data.password);
+          }, "admins", data.name, data.password);
         }
       });
       return false;
@@ -83,7 +83,7 @@
       $.showDialog("dialog/_login.html", {
         submit: function(data, callback) {
           if (!validateUsernameAndPassword(data, callback)) return;
-          doLogin(data.username, data.password, callback);
+          doLogin(data.name, data.password, callback);
         }
       });
       return false;
@@ -101,7 +101,7 @@
       $.showDialog("dialog/_signup.html", {
         submit: function(data, callback) {
           if (!validateUsernameAndPassword(data, callback)) return;
-          doSignup(data.username, data.password, callback, true);
+          doSignup(data.name, data.password, callback, true);
         }
       });
       return false;
@@ -118,9 +118,10 @@
       // get users db info?
       $("#userCtx span").hide();
       $.couch.session({
-        success : function(userCtx) {
+        success : function(r) {
+          var userCtx = r.userCtx;
           if (userCtx.name) {
-            $("#userCtx .username").text(userCtx.name).attr({href : "/_utils/document.html?"+encodeURIComponent(userCtx.info.user_db)+"/org.couchdb.user%3A"+userCtx.name});
+            $("#userCtx .name").text(userCtx.name).attr({href : "/_utils/document.html?"+encodeURIComponent(r.info.authentication_db)+"/org.couchdb.user%3A"+userCtx.name});
             if (userCtx.roles.indexOf("_admin") != -1) {
               $("#userCtx .loggedinadmin").show();
             } else {

Modified: couchdb/trunk/share/www/script/jquery.couch.js
URL: http://svn.apache.org/viewvc/couchdb/trunk/share/www/script/jquery.couch.js?rev=900275&r1=900274&r2=900275&view=diff
==============================================================================
--- couchdb/trunk/share/www/script/jquery.couch.js [utf-8] (original)
+++ couchdb/trunk/share/www/script/jquery.couch.js [utf-8] Mon Jan 18 03:45:54 2010
@@ -28,7 +28,7 @@
       return;
     }
     var user_prefix = "org.couchdb.user:";
-    user_doc._id = user_doc._id || user_prefix + user_doc.username;
+    user_doc._id = user_doc._id || user_prefix + user_doc.name;
     if (new_password) {
       // handle the password crypto
       user_doc.salt = $.couch.newUUID();
@@ -102,7 +102,7 @@
     userDb : function(callback) {
       $.couch.session({
         success : function(resp) {
-          var userDb = $.couch.db(resp.info.user_db);
+          var userDb = $.couch.db(resp.info.authentication_db);
           callback(userDb);
         }
       });
@@ -121,7 +121,7 @@
       options = options || {};
       $.ajax({
         type: "POST", url: "/_session", dataType: "json",
-        data: {username: options.username, password: options.password},
+        data: {name: options.name, password: options.password},
         complete: function(req) {
           var resp = $.httpData(req, "json");
           if (req.status == 200) {

Modified: couchdb/trunk/share/www/script/test/cookie_auth.js
URL: http://svn.apache.org/viewvc/couchdb/trunk/share/www/script/test/cookie_auth.js?rev=900275&r1=900274&r2=900275&view=diff
==============================================================================
--- couchdb/trunk/share/www/script/test/cookie_auth.js (original)
+++ couchdb/trunk/share/www/script/test/cookie_auth.js Mon Jan 18 03:45:54 2010
@@ -46,22 +46,22 @@
 
       // Create a user
       var jasonUserDoc = CouchDB.prepareUserDoc({
-        username: "Jason Davies",
+        name: "Jason Davies",
         roles: ["dev"]
       }, password);
       T(usersDb.save(jasonUserDoc).ok);      
       
       var checkDoc = usersDb.open(jasonUserDoc._id);
-      T(checkDoc.username == "Jason Davies");
+      T(checkDoc.name == "Jason Davies");
       
       var jchrisUserDoc = CouchDB.prepareUserDoc({
-        username: "jchris@apache.org"
+        name: "jchris@apache.org"
       }, "funnybone");
       T(usersDb.save(jchrisUserDoc).ok);
 
       // make sure we cant create duplicate users
       var duplicateJchrisDoc = CouchDB.prepareUserDoc({
-        username: "jchris@apache.org"
+        name: "jchris@apache.org"
       }, "eh, Boo-Boo?");
 
       try {
@@ -72,9 +72,9 @@
         T(usersDb.last_req.status == 409);
       }
       
-      // we can't create _usernames
+      // we can't create _names
       var underscoreUserDoc = CouchDB.prepareUserDoc({
-        username: "_why"
+        name: "_why"
       }, "copperfield");
 
       try {
@@ -87,7 +87,7 @@
       
       // we can't create docs with malformed ids
       var badIdDoc = CouchDB.prepareUserDoc({
-        username: "foo"
+        name: "foo"
       }, "bar");
       
       badIdDoc._id = "org.apache.couchdb:w00x";
@@ -102,12 +102,12 @@
       
       // login works
       T(CouchDB.login('Jason Davies', password).ok);
-      T(CouchDB.session().name == 'Jason Davies');
+      T(CouchDB.session().userCtx.name == 'Jason Davies');
       
       // update one's own credentials document
       jasonUserDoc.foo=2;
       T(usersDb.save(jasonUserDoc).ok);
-      T(CouchDB.session().roles.indexOf("_admin") == -1);
+      T(CouchDB.session().userCtx.roles.indexOf("_admin") == -1);
       // can't delete another users doc unless you are admin
       try {
         usersDb.deleteDoc(jchrisUserDoc);
@@ -122,12 +122,12 @@
        T(!CouchDB.login('Robert Allen Zimmerman', 'd00d').ok);
 
        // a failed login attempt should log you out
-       T(CouchDB.session().name != 'Jason Davies');
+       T(CouchDB.session().userCtx.name != 'Jason Davies');
 
        // test redirect
        xhr = CouchDB.request("POST", "/_session?next=/", {
          headers: {"Content-Type": "application/x-www-form-urlencoded"},
-         body: "username=Jason%20Davies&password="+encodeURIComponent(password)
+         body: "name=Jason%20Davies&password="+encodeURIComponent(password)
        });
        // should this be a redirect code instead of 200?
        // The cURL adapter is returning the expected 302 here.
@@ -145,8 +145,8 @@
       // 
       // 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().name == "jchris@apache.org");
-      T(CouchDB.session().roles.length == 0);
+      T(CouchDB.session().userCtx.name == "jchris@apache.org");
+      T(CouchDB.session().userCtx.roles.length == 0);
       
       jasonUserDoc.foo=3;
 
@@ -170,7 +170,7 @@
       }
       
       T(CouchDB.logout().ok);
-      T(CouchDB.session().roles[0] == "_admin");      
+      T(CouchDB.session().userCtx.roles[0] == "_admin");      
 
       jchrisUserDoc.foo = ["foo"];
       T(usersDb.save(jchrisUserDoc).ok);
@@ -188,24 +188,24 @@
       
       // make sure the foo role has been applied
       T(CouchDB.login("jchris@apache.org", "funnybone").ok);
-      T(CouchDB.session().name == "jchris@apache.org");
-      T(CouchDB.session().roles.indexOf("_admin") == -1);
-      T(CouchDB.session().roles.indexOf("foo") != -1);
+      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().roles[0] == "_admin");
-      T(CouchDB.session().name == null);
+      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",
         key: "jchris@apache.org", value: "funnybone"}], function() {
           T(CouchDB.login("jchris@apache.org", "funnybone").ok);
-          T(CouchDB.session().name == "jchris@apache.org");
-          T(CouchDB.session().roles.indexOf("_admin") != -1);
+          T(CouchDB.session().userCtx.name == "jchris@apache.org");
+          T(CouchDB.session().userCtx.roles.indexOf("_admin") != -1);
           // test that jchris still has the foo role
-          T(CouchDB.session().roles.indexOf("foo") != -1);
+          T(CouchDB.session().userCtx.roles.indexOf("foo") != -1);
 
           // should work even when user doc has no password
           jchrisUserDoc = usersDb.open(jchrisUserDoc._id);
@@ -215,13 +215,13 @@
           T(CouchDB.logout().ok);
           T(CouchDB.login("jchris@apache.org", "funnybone").ok);
           var s = CouchDB.session();
-          T(s.name == "jchris@apache.org");
-          T(s.roles.indexOf("_admin") != -1);
+          T(s.userCtx.name == "jchris@apache.org");
+          T(s.userCtx.roles.indexOf("_admin") != -1);
           // test session info
-          T(s.info.authenticated == "{couch_httpd_auth, cookie_authentication_handler}");
-          T(s.info.user_db == "test_suite_users");
+          T(s.info.authenticated == "cookie");
+          T(s.info.authentication_db == "test_suite_users");
           // test that jchris still has the foo role
-          T(CouchDB.session().roles.indexOf("foo") != -1);
+          T(CouchDB.session().userCtx.roles.indexOf("foo") != -1);
         });      
 
     } finally {

Modified: couchdb/trunk/share/www/script/test/oauth.js
URL: http://svn.apache.org/viewvc/couchdb/trunk/share/www/script/test/oauth.js?rev=900275&r1=900274&r2=900275&view=diff
==============================================================================
--- couchdb/trunk/share/www/script/test/oauth.js (original)
+++ couchdb/trunk/share/www/script/test/oauth.js Mon Jan 18 03:45:54 2010
@@ -116,7 +116,7 @@
         
       // Create a user
       var jasonUserDoc = CouchDB.prepareUserDoc({
-        username: "jason",
+        name: "jason",
         roles: ["test"]
       }, "testpassword");
       T(usersDb.save(jasonUserDoc).ok);

Modified: couchdb/trunk/share/www/script/test/security_validation.js
URL: http://svn.apache.org/viewvc/couchdb/trunk/share/www/script/test/security_validation.js?rev=900275&r1=900274&r2=900275&view=diff
==============================================================================
--- couchdb/trunk/share/www/script/test/security_validation.js (original)
+++ couchdb/trunk/share/www/script/test/security_validation.js Mon Jan 18 03:45:54 2010
@@ -105,7 +105,7 @@
 
       // test the _whoami endpoint
       var resp = userDb.request("GET", "/_session");
-      var user = JSON.parse(resp.responseText)
+      var user = JSON.parse(resp.responseText).userCtx;
       T(user.name == "Damien Katz");
       // test that the roles are listed properly
       TEquals(user.roles, []);

Modified: couchdb/trunk/share/www/script/test/users_db.js
URL: http://svn.apache.org/viewvc/couchdb/trunk/share/www/script/test/users_db.js?rev=900275&r1=900274&r2=900275&view=diff
==============================================================================
--- couchdb/trunk/share/www/script/test/users_db.js (original)
+++ couchdb/trunk/share/www/script/test/users_db.js Mon Jan 18 03:45:54 2010
@@ -32,11 +32,11 @@
     
     // test that you can login as a user using basic auth
     var jchrisUserDoc = CouchDB.prepareUserDoc({
-      username: "jchris@apache.org"
+      name: "jchris@apache.org"
     }, "funnybone");
     T(usersDb.save(jchrisUserDoc).ok);
     
-    T(CouchDB.session().name == null);
+    T(CouchDB.session().userCtx.name == null);
 
     // test that you can use basic auth aginst the users db
     var s = CouchDB.session({
@@ -44,20 +44,48 @@
         "Authorization" : "Basic amNocmlzQGFwYWNoZS5vcmc6ZnVubnlib25l"
       }
     });
-    T(s.name == "jchris@apache.org");
-    T(s.user_doc._id == "org.couchdb.user:jchris@apache.org");
-    T(s.info.authenticated == "{couch_httpd_auth, default_authentication_handler}");
-    T(s.info.user_db == "test_suite_users");
-    TEquals(["{couch_httpd_oauth, oauth_authentication_handler}", 
-      "{couch_httpd_auth, cookie_authentication_handler}", 
-      "{couch_httpd_auth, default_authentication_handler}"], s.info.handlers);
+    T(s.userCtx.name == "jchris@apache.org");
+    T(s.info.authenticated == "default");
+    T(s.info.authentication_db == "test_suite_users");
+    TEquals(["oauth", "cookie", "default"], s.info.authentication_handlers);
     var s = CouchDB.session({
       headers : {
-        "Authorization" : "Basic Xzpf" // username and pass of _:_
+        "Authorization" : "Basic Xzpf" // name and pass of _:_
       }
     });
     T(s.name == null);
-    T(s.info.authenticated == "{couch_httpd_auth, default_authentication_handler}");
+    T(s.info.authenticated == "default");
+    
+    
+    // ok, now create a conflicting edit on the jchris doc, and make sure there's no login.
+    var jchrisUser2 = JSON.parse(JSON.stringify(jchrisUserDoc));
+    jchrisUser2.foo = "bar";
+    T(usersDb.save(jchrisUser2).ok);
+    try {
+      usersDb.save(jchrisUserDoc);
+      T(false && "should be an update conflict")
+    } catch(e) {
+      T(true);
+    }
+    // save as bulk with new_edits=false to force conflict save
+    var resp = usersDb.bulkSave([jchrisUserDoc],{all_or_nothing : true});
+    
+    var jchrisWithConflict = usersDb.open(jchrisUserDoc._id, {conflicts : true});
+    T(jchrisWithConflict._conflicts.length == 1)
+    
+    // no login with conflicted user doc
+    try {
+      var s = CouchDB.session({
+        headers : {
+          "Authorization" : "Basic amNocmlzQGFwYWNoZS5vcmc6ZnVubnlib25l"
+        }
+      });
+      T(false && "this will throw")
+    } catch(e) {
+      T(e.error == "unauthorized")
+      T(/conflict/.test(e.reason))
+    }
+
   };
   
   run_on_modified_server(

Modified: couchdb/trunk/src/couchdb/couch_db.hrl
URL: http://svn.apache.org/viewvc/couchdb/trunk/src/couchdb/couch_db.hrl?rev=900275&r1=900274&r2=900275&view=diff
==============================================================================
--- couchdb/trunk/src/couchdb/couch_db.hrl (original)
+++ couchdb/trunk/src/couchdb/couch_db.hrl Mon Jan 18 03:45:54 2010
@@ -110,8 +110,7 @@
     {
     name=null,
     roles=[],
-    handler,
-    user_doc
+    handler
     }).
 
 % This should be updated anytime a header change happens that requires more

Modified: couchdb/trunk/src/couchdb/couch_httpd.erl
URL: http://svn.apache.org/viewvc/couchdb/trunk/src/couchdb/couch_httpd.erl?rev=900275&r1=900274&r2=900275&view=diff
==============================================================================
--- couchdb/trunk/src/couchdb/couch_httpd.erl (original)
+++ couchdb/trunk/src/couchdb/couch_httpd.erl Mon Jan 18 03:45:54 2010
@@ -121,7 +121,7 @@
 
 % SpecStr is "{my_module, my_fun}, {my_module2, my_fun2}"
 make_fun_spec_strs(SpecStr) ->
-    [FunSpecStr || FunSpecStr <- re:split(SpecStr, "(?<=})\\s*,\\s*(?={)", [{return, list}])].
+    re:split(SpecStr, "(?<=})\\s*,\\s*(?={)", [{return, list}]).
 
 stop() ->
     mochiweb_http:stop(?MODULE).

Modified: couchdb/trunk/src/couchdb/couch_httpd_auth.erl
URL: http://svn.apache.org/viewvc/couchdb/trunk/src/couchdb/couch_httpd_auth.erl?rev=900275&r1=900274&r2=900275&view=diff
==============================================================================
--- couchdb/trunk/src/couchdb/couch_httpd_auth.erl (original)
+++ couchdb/trunk/src/couchdb/couch_httpd_auth.erl Mon Jan 18 03:45:54 2010
@@ -43,7 +43,7 @@
         Req#httpd{user_ctx=#user_ctx{roles=[<<"_admin">>]}}
     end.
 
-basic_username_pw(Req) ->
+basic_name_pw(Req) ->
     AuthorizationHeader = header_value(Req, "Authorization"),
     case AuthorizationHeader of
     "Basic " ++ Base64Value ->
@@ -63,7 +63,7 @@
     end.
 
 default_authentication_handler(Req) ->
-    case basic_username_pw(Req) of
+    case basic_name_pw(Req) of
     {User, Pass} ->
         case get_user(?l2b(User)) of
             nil ->
@@ -76,8 +76,7 @@
                     true ->
                         Req#httpd{user_ctx=#user_ctx{
                             name=?l2b(User),
-                            roles=proplists:get_value(<<"roles">>, UserProps, []),
-                            user_doc={UserProps}
+                            roles=proplists:get_value(<<"roles">>, UserProps, [])
                         }};
                     _Else ->
                         throw({unauthorized, <<"Name or password is incorrect.">>})
@@ -105,8 +104,8 @@
 get_user(UserName) ->
     case couch_config:get("admins", ?b2l(UserName)) of
     "-hashed-" ++ HashedPwdAndSalt ->
-        % the username is an admin, now check to see if there is a user doc
-        % which has a matching username, salt, and password_sha
+        % the name is an admin, now check to see if there is a user doc
+        % which has a matching name, salt, and password_sha
         [HashedPwd, Salt] = string:tokens(HashedPwdAndSalt, ","),
         case get_user_props_from_db(UserName) of
             nil ->        
@@ -117,8 +116,7 @@
                 DocRoles = proplists:get_value(<<"roles">>, UserProps),
                 [{<<"roles">>, [<<"_admin">> | DocRoles]},
                   {<<"salt">>, ?l2b(Salt)},
-                  {<<"password_sha">>, ?l2b(HashedPwd)},
-                  {<<"user_doc">>, {UserProps}}]
+                  {<<"password_sha">>, ?l2b(HashedPwd)}]
         end;
     Else ->
         get_user_props_from_db(UserName)
@@ -128,15 +126,21 @@
     DbName = couch_config:get("couch_httpd_auth", "authentication_db"),
     {ok, Db} = ensure_users_db_exists(?l2b(DbName)),
     DocId = <<"org.couchdb.user:", UserName/binary>>,
-    try couch_httpd_db:couch_doc_open(Db, DocId, nil, []) of
-        #doc{}=Doc ->
-            {DocProps} = couch_query_servers:json_doc(Doc),
-            case proplists:get_value(<<"type">>, DocProps) of
-                <<"user">> -> 
-                    DocProps;
-                _Else -> 
-                    ?LOG_ERROR("Invalid user doc. Id: ~p",[DocId]),
-                    nil
+    try couch_httpd_db:couch_doc_open(Db, DocId, nil, [conflicts]) of
+        #doc{meta=Meta}=Doc ->
+            %  check here for conflict state and throw error if conflicted
+            case proplists:get_value(conflicts,Meta,[]) of
+                [] -> 
+                    {DocProps} = couch_query_servers:json_doc(Doc),
+                    case proplists:get_value(<<"type">>, DocProps) of
+                        <<"user">> ->
+                            DocProps;
+                        _Else -> 
+                            ?LOG_ERROR("Invalid user doc. Id: ~p",[DocId]),
+                            nil
+                    end;
+                Else ->
+                    throw({unauthorized, <<"User document conflict must be resolved before login.">>})
             end
     catch
         throw:Throw ->
@@ -180,23 +184,23 @@
                 if (newDoc._deleted === true) {
                     // allow deletes by admins and matching users 
                     // without checking the other fields
-                    if ((userCtx.roles.indexOf('_admin') != -1) || (userCtx.name == oldDoc.username)) {
+                    if ((userCtx.roles.indexOf('_admin') != -1) || (userCtx.name == oldDoc.name)) {
                         return;
                     } else {
                         throw({forbidden : 'Only admins may delete other user docs.'});
                     }
                 }
-                if (!newDoc.username) {
-                    throw({forbidden : 'doc.username is required'});
+                if (!newDoc.name) {
+                    throw({forbidden : 'doc.name is required'});
                 }
                 if (!(newDoc.roles && (typeof newDoc.roles.length != 'undefined') )) {
                     throw({forbidden : 'doc.roles must be an array'});
                 }
-                if (newDoc._id != 'org.couchdb.user:'+newDoc.username) {
-                    throw({forbidden : 'Docid must be of the form org.couchdb.user:username'});
+                if (newDoc._id != 'org.couchdb.user:'+newDoc.name) {
+                    throw({forbidden : 'Docid must be of the form org.couchdb.user:name'});
                 }
                 if (oldDoc) { // validate all updates
-                    if (oldDoc.username != newDoc.username) {
+                    if (oldDoc.name != newDoc.name) {
                       throw({forbidden : 'Usernames may not be changed.'});
                     }
                 }
@@ -205,7 +209,7 @@
                 }
                 if (userCtx.roles.indexOf('_admin') == -1) { // not an admin
                     if (oldDoc) { // validate non-admin updates
-                        if (userCtx.name != newDoc.username) {
+                        if (userCtx.name != newDoc.name) {
                           throw({forbidden : 'You may only update your own user document.'});
                         }
                         // validate role updates
@@ -229,8 +233,8 @@
                         throw({forbidden : 'No system roles (starting with underscore) in users db.'});
                     }
                 };
-                // no system names as usernames
-                if (newDoc.username[0] == '_') {
+                // no system names as names
+                if (newDoc.name[0] == '_') {
                     throw({forbidden : 'Username may not start with underscore.'});
                 }
             }">>
@@ -276,8 +280,7 @@
                                 ?LOG_DEBUG("Successful cookie auth as: ~p", [User]),
                                 Req#httpd{user_ctx=#user_ctx{
                                     name=?l2b(User),
-                                    roles=proplists:get_value(<<"roles">>, UserProps, []),
-                                    user_doc=proplists:get_value(<<"user_doc">>, UserProps, null)
+                                    roles=proplists:get_value(<<"roles">>, UserProps, [])
                                 }, auth={FullSecret, TimeLeft < Timeout*0.9}};
                             _Else ->
                                 Req
@@ -340,7 +343,7 @@
         _ ->
             []
     end,
-    UserName = ?l2b(proplists:get_value("username", Form, "")),
+    UserName = ?l2b(proplists:get_value("name", Form, "")),
     Password = ?l2b(proplists:get_value("password", Form, "")),
     ?LOG_DEBUG("Attempt Login: ~s",[UserName]),
     User = case get_user(UserName) of
@@ -367,9 +370,8 @@
             send_json(Req#httpd{req_body=ReqBody}, Code, Headers,
                 {[
                     {ok, true},
-                    {name, proplists:get_value(<<"username">>, User, null)},
-                    {roles, proplists:get_value(<<"roles">>, User, [])},
-                    {user_doc, proplists:get_value(<<"user_doc">>, User, null)}
+                    {name, proplists:get_value(<<"name">>, User, null)},
+                    {roles, proplists:get_value(<<"roles">>, User, [])}
                 ]});
         _Else ->
             % clear the session
@@ -377,6 +379,7 @@
             send_json(Req, 401, [Cookie], {[{error, <<"unauthorized">>},{reason, <<"Name or password is incorrect.">>}]})
     end;
 % get user info
+% GET /_session
 handle_session_req(#httpd{method='GET', user_ctx=UserCtx}=Req) ->
     Name = UserCtx#user_ctx.name,
     ForceLogin = couch_httpd:qs_value(Req, "basic", "false"),
@@ -385,15 +388,20 @@
             throw({unauthorized, <<"Please login.">>});
         {Name, _} ->
             send_json(Req, {[
+                % remove this ok
                 {ok, true},
-                {name, Name},
-                {roles, UserCtx#user_ctx.roles},
+                {<<"userCtx">>, {[
+                    {name, Name},
+                    {roles, UserCtx#user_ctx.roles}
+                ]}},
                 {info, {[
-                    {user_db, ?l2b(couch_config:get("couch_httpd_auth", "authentication_db"))},
-                    {handlers, [?l2b(H) || H <- couch_httpd:make_fun_spec_strs(
+                    {authentication_db, ?l2b(couch_config:get("couch_httpd_auth", "authentication_db"))},
+                    {authentication_handlers, [auth_name(H) || H <- couch_httpd:make_fun_spec_strs(
                             couch_config:get("httpd", "authentication_handlers"))]}
-                ] ++ maybe_value(authenticated, UserCtx#user_ctx.handler)}}
-            ] ++ maybe_value(user_doc, UserCtx#user_ctx.user_doc)})
+                ] ++ maybe_value(authenticated, UserCtx#user_ctx.handler, fun(Handler) -> 
+                        auth_name(?b2l(Handler))
+                    end)}}
+            ]})
     end;
 % logout by deleting the session
 handle_session_req(#httpd{method='DELETE'}=Req) ->
@@ -408,9 +416,16 @@
 handle_session_req(Req) ->
     send_method_not_allowed(Req, "GET,HEAD,POST,DELETE").
 
+maybe_value(Key, undefined, Fun) -> [];
+maybe_value(Key, Else, Fun) -> 
+    [{Key, Fun(Else)}].
 maybe_value(Key, undefined) -> [];
 maybe_value(Key, Else) -> [{Key, Else}].
 
+auth_name(String) when is_list(String) ->
+    [_,_,_,_,_,Name|_] = re:split(String, "[\\W_]", [{return, list}]),
+    ?l2b(Name).
+
 to_int(Value) when is_binary(Value) ->
     to_int(?b2l(Value)); 
 to_int(Value) when is_list(Value) ->

Modified: couchdb/trunk/src/couchdb/couch_httpd_db.erl
URL: http://svn.apache.org/viewvc/couchdb/trunk/src/couchdb/couch_httpd_db.erl?rev=900275&r1=900274&r2=900275&view=diff
==============================================================================
--- couchdb/trunk/src/couchdb/couch_httpd_db.erl (original)
+++ couchdb/trunk/src/couchdb/couch_httpd_db.erl Mon Jan 18 03:45:54 2010
@@ -467,7 +467,11 @@
             send_json(Req, 417, ErrorsJson)
         end;
     false ->
-        Docs = [couch_doc:from_json_obj(JsonObj) || JsonObj <- DocsArray],
+        Docs = lists:map(fun(JsonObj) -> 
+                Doc = couch_doc:from_json_obj(JsonObj),
+                validate_attachment_names(Doc),
+                Doc
+            end, DocsArray),
         {ok, Errors} = couch_db:update_docs(Db, Docs, Options, replicated_changes),
         ErrorsJson =
             lists:map(fun update_doc_result_to_json/1, Errors),