You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by ga...@apache.org on 2013/04/03 08:35:58 UTC

git commit: updated refs/heads/1715-admin-auth to 1f52687

Updated Branches:
  refs/heads/1715-admin-auth 628a1b5cf -> 1f5268716


white list auth module


Project: http://git-wip-us.apache.org/repos/asf/couchdb/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb/commit/1f526871
Tree: http://git-wip-us.apache.org/repos/asf/couchdb/tree/1f526871
Diff: http://git-wip-us.apache.org/repos/asf/couchdb/diff/1f526871

Branch: refs/heads/1715-admin-auth
Commit: 1f526871622d132481871e04d4f35aa0c607b088
Parents: 628a1b5
Author: Garren Smith <ga...@gmail.com>
Authored: Wed Apr 3 08:35:14 2013 +0200
Committer: Garren Smith <ga...@gmail.com>
Committed: Wed Apr 3 08:35:14 2013 +0200

----------------------------------------------------------------------
 .gitignore                                         |    1 +
 src/fauxton/app/addons/auth/base.js                |   34 ++
 src/fauxton/app/addons/auth/resources.js           |  325 +++++++++++++++
 src/fauxton/app/addons/auth/routes.js              |   22 +
 .../auth/templates/change_password_modal.html      |   35 ++
 .../addons/auth/templates/create_admin_modal.html  |   46 ++
 .../app/addons/auth/templates/login_modal.html     |   35 ++
 .../app/addons/auth/templates/nav_link.html        |   42 ++
 8 files changed, 540 insertions(+), 0 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb/blob/1f526871/.gitignore
----------------------------------------------------------------------
diff --git a/.gitignore b/.gitignore
index e3f57eb..67da1c8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -91,6 +91,7 @@ src/fauxton/app/addons/*
 !src/fauxton/app/addons/logs
 !src/fauxton/app/addons/stats
 !src/fauxton/app/addons/contribute
+!src/fauxton/app/addons/auth
 src/fauxton/settings.json*
 !src/fauxton/settings.json.default
 share/www/fauxton

http://git-wip-us.apache.org/repos/asf/couchdb/blob/1f526871/src/fauxton/app/addons/auth/base.js
----------------------------------------------------------------------
diff --git a/src/fauxton/app/addons/auth/base.js b/src/fauxton/app/addons/auth/base.js
new file mode 100644
index 0000000..4cf1b83
--- /dev/null
+++ b/src/fauxton/app/addons/auth/base.js
@@ -0,0 +1,34 @@
+// 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.
+
+define([
+       "app",
+       "api",
+       "addons/auth/routes"
+],
+
+function(app, FauxtonAPI, Auth) {
+
+  Auth.initialize = function() {
+    Auth.session = new Auth.Session();
+    Auth.navLink = new Auth.NavLink({model: Auth.session});
+
+    FauxtonAPI.addHeaderLink({
+      title: "Auth", 
+      href: "#_auth",
+      view: Auth.navLink,
+      establish: [Auth.session.fetchOnce()]
+    });
+  };
+
+  return Auth;
+});

http://git-wip-us.apache.org/repos/asf/couchdb/blob/1f526871/src/fauxton/app/addons/auth/resources.js
----------------------------------------------------------------------
diff --git a/src/fauxton/app/addons/auth/resources.js b/src/fauxton/app/addons/auth/resources.js
new file mode 100644
index 0000000..5b61d50
--- /dev/null
+++ b/src/fauxton/app/addons/auth/resources.js
@@ -0,0 +1,325 @@
+// 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.
+
+define([
+       "app",
+       "api",
+       "addons/config/resources"
+],
+
+function (app, FauxtonAPI, Config) {
+  var Auth = new FauxtonAPI.addon();
+
+  Auth.Session = Backbone.Model.extend({
+    url: '/_session',
+
+    is_admin_party: function () {
+      var userCtx = this.get('userCtx');
+
+      if (!userCtx.name && userCtx.roles.indexOf("_admin") > -1) {
+        return true;
+      }
+
+      return false;
+    },
+
+    user: function () {
+      var userCtx = this.get('userCtx');
+
+      if (!userCtx || !userCtx.name) { return null; }
+
+      return {
+        name: userCtx.name,
+        roles: userCtx.roles
+      };
+    },
+
+    fetchOnce: function (opt) {
+      var options = _.extend({}, opt);
+
+      if (!this._deferred || this._deferred.isRejected() || options.forceFetch ) {
+        this._deferred = this.fetch();
+      }
+
+      return this._deferred;
+    },
+
+    validate_user: function (username, password, msg) {
+      if (_.isEmpty(username) || _.isEmpty(password)) {
+        var deferred = $.Deferred();
+
+        deferred.rejectWith(this, [msg]);
+        return deferred;
+      }
+    },
+
+    validate_passwords: function (password, password_confirm, msg) {
+      if (_.isEmpty(password) || _.isEmpty(password_confirm) || (password !== password_confirm)) {
+        var deferred = $.Deferred();
+
+        deferred.rejectWith(this, [msg]);
+        return deferred;
+      }
+
+    },
+
+    create_admin: function (username, password, login) {
+      var self = this,
+          error_promise =  this.validate_user(username, password, 'Authname or password cannot be blank.');
+
+      if (error_promise) { return error_promise; }
+
+      var admin = new Config.OptionModel({
+        section: "admins",
+        name: username,
+        value: password
+      });
+
+      return admin.save().then(function () {
+        if (login) {
+          return self.login(username, password);
+        } else {
+         return self.fetchOnce({forceFetch: true});
+        }
+      });
+    },
+
+    login: function (username, password) {
+      var error_promise =  this.validate_user(username, password, 'Authname or password cannot be blank.');
+
+      if (error_promise) { return error_promise; }
+
+      var self = this;
+
+      return $.ajax({
+        type: "POST", 
+        url: "/_session", 
+        dataType: "json",
+        data: {name: username, password: password}
+      }).then(function () {
+         return self.fetchOnce({forceFetch: true});
+      });
+    },
+
+    logout: function () {
+      var self = this;
+
+      return $.ajax({
+        type: "DELETE", 
+        url: "/_session", 
+        dataType: "json",
+        username : "_", 
+        password : "_"
+      }).then(function () {
+       return self.fetchOnce({forceFetch: true });
+      });
+    },
+
+    change_password: function (password, password_confirm) {
+      var error_promise =  this.validate_passwords(password, password_confirm, 'Passwords do not match.');
+
+      if (error_promise) { return error_promise; }
+
+      var  self = this,
+           info = this.get('info'),
+           userCtx = this.get('userCtx');
+
+       var admin = new Config.OptionModel({
+        section: "admins",
+        name: userCtx.name,
+        value: password
+      });
+
+      return admin.save().then(function () {
+        return self.login(userCtx.name, password);
+      });
+    }
+  });
+
+  Auth.ModalView = FauxtonAPI.View.extend({
+
+    show_modal: function () {
+      this.clear_error_msg();
+      this.$('.modal').modal();
+      // hack to get modal visible 
+      $('.modal-backdrop').css('z-index',1025);
+    },
+
+    hide_modal: function () {
+      this.$('.modal').modal('hide');
+    },
+
+    set_error_msg: function (msg) {
+      var text;
+      if (typeof(msg) == 'string') {
+        text = msg;
+      } else {
+        text = JSON.parse(msg.responseText).reason;
+      }
+
+      this.$('#modal-error').text(text).removeClass('hide');
+    },
+
+    clear_error_msg: function () {
+      this.$('#modal-error').text(' ').addClass('hide');
+    }
+
+  });
+
+  Auth.CreateAdminModal = Auth.ModalView.extend({
+    template: 'addons/auth/templates/create_admin_modal',
+
+    initialize: function (options) {
+      this.login_after = options.login_after || true;
+    },
+
+    events: {
+      "click #create-admin": "create_admin"
+    },
+
+    create_admin: function (event) {
+      event.preventDefault();
+      this.clear_error_msg();
+
+      var self = this,
+      username = this.$('#username').val(),
+      password = this.$('#password').val();
+
+      var promise = this.model.create_admin(username, password, this.login_after);
+
+      promise.then(function () {
+        self.$('.modal').modal('hide');
+        self.hide_modal();
+      });
+
+      promise.fail(function (rsp) {
+        self.set_error_msg(rsp);
+      });
+    }
+
+  });
+
+  Auth.LoginModal = Auth.ModalView.extend({
+    template: 'addons/auth/templates/login_modal',
+
+    events: {
+      "click #login": "login"
+    },
+
+    login: function () {
+      event.preventDefault();
+      this.clear_error_msg();
+
+      var self = this,
+      username = this.$('#username').val(),
+      password = this.$('#password').val();
+
+      var promise = this.model.login(username, password);
+
+      promise.done(function () {
+        self.hide_modal();
+      });
+
+      promise.fail(function (rsp) {
+        self.set_error_msg(rsp);
+      });
+    }
+
+  });
+
+  Auth.ChangePasswordModal = Auth.ModalView.extend({
+    template: 'addons/auth/templates/change_password_modal',
+
+    events: {
+      "click #change-password": "change_password"
+    },
+
+    change_password: function () {
+      event.preventDefault();
+      this.clear_error_msg();
+
+      var self = this,
+          new_password = this.$('#password').val(),
+          password_confirm = this.$('#password-confirm').val();
+
+      var promise = this.model.change_password(new_password, password_confirm);
+
+      promise.done(function () {
+        self.hide_modal();
+      });
+
+      promise.fail(function (rsp) {
+        self.set_error_msg(rsp);
+      });
+    }
+  });
+
+  Auth.NavLink = FauxtonAPI.View.extend({
+    template: 'addons/auth/templates/nav_link',
+
+    tagName: "li",
+    className: "dropdown",
+
+    initialize:function (options) {
+    },
+
+    serialize: function () {
+      return {
+        admin_party: this.model.is_admin_party(),
+        user: this.model.user()
+      };
+    },
+
+    events: {
+      "click #user-create-admin": 'show_admin_modal',
+      "click #user-create-more-admin": 'show_create_more_admin_modal',
+      "click #user-login": 'show_login_modal',
+      "click #user-change-password": 'show_change_password_modal',
+      "click #user-logout": 'logout_user'
+    },
+
+    beforeRender: function () {
+      this.listenTo(this.model, 'change', this.render);
+      this.create_admin_modal = this.setView('#user-create-admin-modal', new Auth.CreateAdminModal({model: this.model}));
+      this.login_modal = this.setView('#login-modal', new Auth.LoginModal({model: this.model}));
+      this.change_password_modal = this.setView('#change-password-modal', new Auth.ChangePasswordModal({model: this.model}));
+    },
+
+    show_admin_modal: function (event) {
+      event.preventDefault();
+      this.create_admin_modal.show_modal();
+    },
+
+    show_create_more_admin_modal: function (event) {
+      event.preventDefault();
+      this.create_admin_modal.login_after = false;
+      this.create_admin_modal.show_modal();
+    },
+
+    show_login_modal: function (event) {
+      event.preventDefault();
+      this.login_modal.show_modal();
+    },
+
+    show_change_password_modal: function (event) {
+      event.preventDefault();
+      this.change_password_modal.show_modal();
+    },
+
+    logout_user: function () {
+      event.preventDefault();
+      this.model.logout();
+    }
+  });
+
+  return Auth;
+});

http://git-wip-us.apache.org/repos/asf/couchdb/blob/1f526871/src/fauxton/app/addons/auth/routes.js
----------------------------------------------------------------------
diff --git a/src/fauxton/app/addons/auth/routes.js b/src/fauxton/app/addons/auth/routes.js
new file mode 100644
index 0000000..6ff7502
--- /dev/null
+++ b/src/fauxton/app/addons/auth/routes.js
@@ -0,0 +1,22 @@
+// 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.
+
+define([
+       "app",
+       "api",
+       "addons/auth/resources"
+],
+
+function(app, FauxtonAPI, Auth) {
+  
+  return Auth;
+});

http://git-wip-us.apache.org/repos/asf/couchdb/blob/1f526871/src/fauxton/app/addons/auth/templates/change_password_modal.html
----------------------------------------------------------------------
diff --git a/src/fauxton/app/addons/auth/templates/change_password_modal.html b/src/fauxton/app/addons/auth/templates/change_password_modal.html
new file mode 100644
index 0000000..5e3db38
--- /dev/null
+++ b/src/fauxton/app/addons/auth/templates/change_password_modal.html
@@ -0,0 +1,35 @@
+<!--
+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.
+-->
+
+<div class="modal hide fade">
+  <div class="modal-header">
+    <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
+    <h3>Change Password</h3>
+  </div>
+  <div class="modal-body">
+    <div id="modal-error" class="hide alert alert-error"/>
+    <form>
+      <p class="help-block">
+      Enter your new password.
+      </p>
+      <input id="password" type="password" name="password" placeholder= "New Password:" size="24">
+      <br/>
+      <input id="password-confirm" type="password" name="password_confirm" placeholder= "Verify New Password" size="24">
+    </form>
+  </div>
+  <div class="modal-footer">
+    <a href="#" data-dismiss="modal" class="btn">Cancel</a>
+    <a href="#" id="change-password" class="btn btn-primary">Change</a>
+  </div>
+</div>

http://git-wip-us.apache.org/repos/asf/couchdb/blob/1f526871/src/fauxton/app/addons/auth/templates/create_admin_modal.html
----------------------------------------------------------------------
diff --git a/src/fauxton/app/addons/auth/templates/create_admin_modal.html b/src/fauxton/app/addons/auth/templates/create_admin_modal.html
new file mode 100644
index 0000000..0d16ca1
--- /dev/null
+++ b/src/fauxton/app/addons/auth/templates/create_admin_modal.html
@@ -0,0 +1,46 @@
+<!--
+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.
+-->
+
+<div class="modal hide fade">
+  <div class="modal-header">
+    <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
+    <h3>Create Server Admin</h3>
+  </div>
+  <div class="modal-body">
+    <div id="modal-error" class="hide alert alert-error"/>
+    <form>
+      <input id="username" type="text" name="name" placeholder= "Username:" size="24">
+      <br/>
+      <input id="password" type="password" name="password" placeholder= "Password" size="24">
+    </form>
+    <p class="help-block">
+    Before a server admin is configured, all clients have admin privileges.
+    This is fine when HTTP access is restricted 
+    to trusted users. <strong>If end-users will be accessing this CouchDB, you must
+      create an admin account to prevent accidental (or malicious) data loss.</strong>
+    </p>
+    <p class="help-block">Server admins can create and destroy databases, install 
+    and update _design documents, run the test suite, and edit all aspects of CouchDB 
+    configuration.
+    </p>
+    <p class="help-block">Non-admin users have read and write access to all databases, which
+    are controlled by validation functions. CouchDB can be configured to block all
+    access to anonymous users.
+    </p>
+  </div>
+  <div class="modal-footer">
+    <a href="#" data-dismiss="modal" class="btn">Cancel</a>
+    <a href="#" id="create-admin" class="btn btn-primary">Create Admin</a>
+  </div>
+</div>

http://git-wip-us.apache.org/repos/asf/couchdb/blob/1f526871/src/fauxton/app/addons/auth/templates/login_modal.html
----------------------------------------------------------------------
diff --git a/src/fauxton/app/addons/auth/templates/login_modal.html b/src/fauxton/app/addons/auth/templates/login_modal.html
new file mode 100644
index 0000000..e0395da
--- /dev/null
+++ b/src/fauxton/app/addons/auth/templates/login_modal.html
@@ -0,0 +1,35 @@
+<!--
+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.
+-->
+
+<div class="modal hide fade">
+  <div class="modal-header">
+    <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
+    <h3>Login</h3>
+  </div>
+  <div class="modal-body">
+    <div id="modal-error" class="hide alert alert-error"/>
+    <form>
+      <p class="help-block">
+      Login to CouchDB with your name and password.
+      </p>
+      <input id="username" type="text" name="name" placeholder= "Username:" size="24">
+      <br/>
+      <input id="password" type="password" name="password" placeholder= "Password" size="24">
+    </form>
+  </div>
+  <div class="modal-footer">
+    <a href="#" data-dismiss="modal" class="btn">Cancel</a>
+    <a href="#" id="login" class="btn btn-primary">Login</a>
+  </div>
+</div>

http://git-wip-us.apache.org/repos/asf/couchdb/blob/1f526871/src/fauxton/app/addons/auth/templates/nav_link.html
----------------------------------------------------------------------
diff --git a/src/fauxton/app/addons/auth/templates/nav_link.html b/src/fauxton/app/addons/auth/templates/nav_link.html
new file mode 100644
index 0000000..2f1462f
--- /dev/null
+++ b/src/fauxton/app/addons/auth/templates/nav_link.html
@@ -0,0 +1,42 @@
+<!--
+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.
+-->
+
+<a id="user-drop" class="dropdown-toggle" role="button" data-toggle="dropdown" href="#">
+  <% if (admin_party) { %>
+  Admin Party!
+  <% } else if (user) { %>
+  <%= user.name %>
+  <% } else { %>
+  Login
+  <% } %>
+  <b class="caret"></b>
+</a>
+<ul class="dropdown-menu" role="menu" aria-labelledby="user-drop">
+  <!-- dropdown menu links -->
+  <% if (admin_party) { %>
+  <li> <a id="user-create-admin" href="#"> Create Admin </a> </li>
+  <% } else if (user) { %>
+  <li> <a id="user-create-more-admin" href="#"> Create Admins </a> </li>
+  <li> <a id="user-change-password" href="#"> Change Password </a> </li>
+  <li> <a id="user-logout" href="#"> Logout </a> </li> 
+  <% } else { %>
+  <li> <a id="user-login" href="#"> Login </a> </li> 
+  <li> <a id="user-sign-up"> Sign up </a> </li>
+  <% } %>
+</ul>
+
+<div id="user-create-admin-modal"> </div>
+<div id="login-modal"> </div>
+<div id="change-password-modal"> </div>
+<div id="signup-modal"> </div>