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/route-events Commit: 1f526871622d132481871e04d4f35aa0c607b088 Parents: 628a1b5 Author: Garren Smith <[email protected]> Authored: Wed Apr 3 08:35:14 2013 +0200 Committer: Garren Smith <[email protected]> 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">×</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">×</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">×</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>
