integrate couchdb admin authentication
Project: http://git-wip-us.apache.org/repos/asf/couchdb/repo Commit: http://git-wip-us.apache.org/repos/asf/couchdb/commit/c33e3903 Tree: http://git-wip-us.apache.org/repos/asf/couchdb/tree/c33e3903 Diff: http://git-wip-us.apache.org/repos/asf/couchdb/diff/c33e3903 Branch: refs/heads/route-events Commit: c33e3903c7bcc2d3a5c4a0ebfcbce5f6ec494ab4 Parents: 5127523 Author: Garren Smith <[email protected]> Authored: Thu May 9 16:00:21 2013 +0200 Committer: Garren Smith <[email protected]> Committed: Thu May 9 16:00:21 2013 +0200 ---------------------------------------------------------------------- src/fauxton/app/addons/auth/base.js | 28 ++++++- src/fauxton/app/addons/auth/resources.js | 64 +++++++++++---- .../app/addons/auth/templates/nav_link.html | 2 +- .../app/addons/auth/templates/noAccess.html | 19 +++++ src/fauxton/app/addons/config/routes.js | 2 + src/fauxton/app/addons/exampleAuth/base.js | 10 +- src/fauxton/app/addons/logs/routes.js | 2 + src/fauxton/app/api.js | 23 ++++-- src/fauxton/app/modules/documents/routes.js | 2 +- src/fauxton/app/router.js | 3 +- 10 files changed, 121 insertions(+), 34 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/couchdb/blob/c33e3903/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 index 4cf1b83..9f40308 100644 --- a/src/fauxton/app/addons/auth/base.js +++ b/src/fauxton/app/addons/auth/base.js @@ -19,7 +19,7 @@ define([ function(app, FauxtonAPI, Auth) { Auth.initialize = function() { - Auth.session = new Auth.Session(); + var session = Auth.session = new Auth.Session(); Auth.navLink = new Auth.NavLink({model: Auth.session}); FauxtonAPI.addHeaderLink({ @@ -28,6 +28,32 @@ function(app, FauxtonAPI, Auth) { view: Auth.navLink, establish: [Auth.session.fetchOnce()] }); + + var auth = function (roles, layout) { + var deferred = $.Deferred(); + + var sessionDeferred = session.fetchOnce().then(function () { + console.log(session); + + if (session.isAdminParty()) { + deferred.resolve(); + } else if(session.matchesRoles(roles)) { + deferred.resolve(); + } else { + deferred.reject(); + } + }); + + return [sessionDeferred, deferred]; + }; + + var authDenied = function () { + app.masterLayout.setView('#dashboard', new Auth.NoAccessView()); + app.masterLayout.renderView('#dashboard'); + }; + + FauxtonAPI.auth.registerAuth(auth); + FauxtonAPI.auth.registerAuthDenied(authDenied); }; return Auth; http://git-wip-us.apache.org/repos/asf/couchdb/blob/c33e3903/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 index 64dd254..92cff91 100644 --- a/src/fauxton/app/addons/auth/resources.js +++ b/src/fauxton/app/addons/auth/resources.js @@ -17,6 +17,8 @@ define([ function (app, FauxtonAPI) { + var Auth = new FauxtonAPI.addon(); + var Admin = Backbone.Model.extend({ url: function () { @@ -44,12 +46,10 @@ function (app, FauxtonAPI) { } }); - var Auth = new FauxtonAPI.addon(); - Auth.Session = Backbone.Model.extend({ url: '/_session', - is_admin_party: function () { + isAdminParty: function () { var userCtx = this.get('userCtx'); if (!userCtx.name && userCtx.roles.indexOf("_admin") > -1) { @@ -70,6 +70,30 @@ function (app, FauxtonAPI) { }; }, + userRoles: function () { + var user = this.user(); + + if (user && user.roles) { + return user.roles; + } + + return []; + }, + + matchesRoles: function (roles) { + if (roles.length === 0) { + return true; + } + + var numberMatchingRoles = _.intersection(this.userRoles(), roles).length; + + if (numberMatchingRoles > 0) { + return true; + } + + return false; + }, + fetchOnce: function (opt) { var options = _.extend({}, opt); @@ -80,7 +104,7 @@ function (app, FauxtonAPI) { return this._deferred; }, - validate_user: function (username, password, msg) { + validateUser: function (username, password, msg) { if (_.isEmpty(username) || _.isEmpty(password)) { var deferred = $.Deferred(); @@ -89,7 +113,7 @@ function (app, FauxtonAPI) { } }, - validate_passwords: function (password, password_confirm, msg) { + validatePasswords: function (password, password_confirm, msg) { if (_.isEmpty(password) || _.isEmpty(password_confirm) || (password !== password_confirm)) { var deferred = $.Deferred(); @@ -99,9 +123,9 @@ function (app, FauxtonAPI) { }, - create_admin: function (username, password, login) { + createAdmin: function (username, password, login) { var self = this, - error_promise = this.validate_user(username, password, 'Authname or password cannot be blank.'); + error_promise = this.validateUser(username, password, 'Authname or password cannot be blank.'); if (error_promise) { return error_promise; } @@ -120,7 +144,7 @@ function (app, FauxtonAPI) { }, login: function (username, password) { - var error_promise = this.validate_user(username, password, 'Authname or password cannot be blank.'); + var error_promise = this.validateUser(username, password, 'Authname or password cannot be blank.'); if (error_promise) { return error_promise; } @@ -150,8 +174,8 @@ function (app, FauxtonAPI) { }); }, - change_password: function (password, password_confirm) { - var error_promise = this.validate_passwords(password, password_confirm, 'Passwords do not match.'); + changePassword: function (password, password_confirm) { + var error_promise = this.validatePasswords(password, password_confirm, 'Passwords do not match.'); if (error_promise) { return error_promise; } @@ -208,10 +232,10 @@ function (app, FauxtonAPI) { }, events: { - "click #create-admin": "create_admin" + "click #create-admin": "createAdmin" }, - create_admin: function (event) { + createAdmin: function (event) { event.preventDefault(); this.clear_error_msg(); @@ -219,7 +243,7 @@ function (app, FauxtonAPI) { username = this.$('#username').val(), password = this.$('#password').val(); - var promise = this.model.create_admin(username, password, this.login_after); + var promise = this.model.createAdmin(username, password, this.login_after); promise.then(function () { self.$('.modal').modal('hide'); @@ -265,10 +289,10 @@ function (app, FauxtonAPI) { template: 'addons/auth/templates/change_password_modal', events: { - "click #change-password": "change_password" + "click #change-password": "changePassword" }, - change_password: function () { + changePassword: function () { event.preventDefault(); this.clear_error_msg(); @@ -276,7 +300,7 @@ function (app, FauxtonAPI) { new_password = this.$('#password').val(), password_confirm = this.$('#password-confirm').val(); - var promise = this.model.change_password(new_password, password_confirm); + var promise = this.model.changePassword(new_password, password_confirm); promise.done(function () { self.hide_modal(); @@ -299,7 +323,7 @@ function (app, FauxtonAPI) { serialize: function () { return { - admin_party: this.model.is_admin_party(), + admin_party: this.model.isAdminParty(), user: this.model.user() }; }, @@ -346,5 +370,11 @@ function (app, FauxtonAPI) { } }); + Auth.NoAccessView = FauxtonAPI.View.extend({ + template: "addons/auth/templates/noAccess" + + }); + + return Auth; }); http://git-wip-us.apache.org/repos/asf/couchdb/blob/c33e3903/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 index 2f1462f..ba0a6f9 100644 --- a/src/fauxton/app/addons/auth/templates/nav_link.html +++ b/src/fauxton/app/addons/auth/templates/nav_link.html @@ -32,7 +32,7 @@ the License. <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> + <!--<li> <a id="user-sign-up"> Sign up </a> </li>--> <% } %> </ul> http://git-wip-us.apache.org/repos/asf/couchdb/blob/c33e3903/src/fauxton/app/addons/auth/templates/noAccess.html ---------------------------------------------------------------------- diff --git a/src/fauxton/app/addons/auth/templates/noAccess.html b/src/fauxton/app/addons/auth/templates/noAccess.html new file mode 100644 index 0000000..f1a9506 --- /dev/null +++ b/src/fauxton/app/addons/auth/templates/noAccess.html @@ -0,0 +1,19 @@ +<!-- +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="row-fluid" > + <div class="span6 offset4"> + <h3> You do not have permission to view this page </h3> +</div> +</div> http://git-wip-us.apache.org/repos/asf/couchdb/blob/c33e3903/src/fauxton/app/addons/config/routes.js ---------------------------------------------------------------------- diff --git a/src/fauxton/app/addons/config/routes.js b/src/fauxton/app/addons/config/routes.js index 42934a8..d86715f 100644 --- a/src/fauxton/app/addons/config/routes.js +++ b/src/fauxton/app/addons/config/routes.js @@ -28,6 +28,8 @@ function(app, FauxtonAPI, Config) { this.configs = new Config.Collection(); }, + roles: ["_admin"], + crumbs: [ {"name": "Config","link": "_config"} ], http://git-wip-us.apache.org/repos/asf/couchdb/blob/c33e3903/src/fauxton/app/addons/exampleAuth/base.js ---------------------------------------------------------------------- diff --git a/src/fauxton/app/addons/exampleAuth/base.js b/src/fauxton/app/addons/exampleAuth/base.js index b58558c..aa99670 100644 --- a/src/fauxton/app/addons/exampleAuth/base.js +++ b/src/fauxton/app/addons/exampleAuth/base.js @@ -30,10 +30,10 @@ function(app, FauxtonAPI) { // The roles argument that is passed in is the required roles for the current user // to be allowed to access the current page. // The layout is the main layout for use when you want to render a view onto the page - var auth = function (roles, layout) { + var auth = function (roles) { var deferred = $.Deferred(); - if (roles.indexOf('admin') > -1) { + if (roles.indexOf('_admin') > -1) { deferred.reject(); } else { deferred.resolve(); @@ -44,9 +44,9 @@ function(app, FauxtonAPI) { // If you would like to do something with when access is denied you can register this callback. // It will be called is access has been denied on the previous page. - var authFail = function (layout) { - layout.setView('#dashboard', new noAccessView()); - layout.renderView('#dashboard'); + var authFail = function () { + app.masterLayout.setView('#dashboard', new noAccessView()); + app.masterLayout.renderView('#dashboard'); }; // Register the auth call back. This will be called before new route rendered http://git-wip-us.apache.org/repos/asf/couchdb/blob/c33e3903/src/fauxton/app/addons/logs/routes.js ---------------------------------------------------------------------- diff --git a/src/fauxton/app/addons/logs/routes.js b/src/fauxton/app/addons/logs/routes.js index 1ce260c..ae0a6b6 100644 --- a/src/fauxton/app/addons/logs/routes.js +++ b/src/fauxton/app/addons/logs/routes.js @@ -32,6 +32,8 @@ function(app, FauxtonAPI, Log) { "_log": "showLog" }, + roles: ["_admin"], + apiUrl: function() { return this.logs.url(); }, http://git-wip-us.apache.org/repos/asf/couchdb/blob/c33e3903/src/fauxton/app/api.js ---------------------------------------------------------------------- diff --git a/src/fauxton/app/api.js b/src/fauxton/app/api.js index b50bc02..9c4ecef 100644 --- a/src/fauxton/app/api.js +++ b/src/fauxton/app/api.js @@ -118,8 +118,19 @@ function(app, Fauxton) { Auth.extend = Backbone.Model.extend; _.extend(Auth.prototype, Backbone.Events, { - initialize: function() {}, - authDeniedCb: undefined, + authDeniedCb: function() {}, + + initialize: function() { + var self = this; + + $(document).ajaxError(function(event, jqxhr, settings, exception) { + console.log("UNAUTH"); + console.log(arguments); + if (exception === "Unauthorized" || exception === "Forbidden") { + self.authDeniedCb(); + } + }); + }, authHandlerCb : function (roles, layout) { var deferred = $.Deferred(); @@ -135,14 +146,12 @@ function(app, Fauxton) { this.authDeniedCb = authDeniedCb; }, - checkAccess: function (roles, layout) { + checkAccess: function (roles) { var requiredRoles = roles || [], authDeniedCb = this.authDeniedCb, - promise = $.when.apply(null, this.authHandlerCb(requiredRoles, layout)); + promise = $.when.apply(null, this.authHandlerCb(requiredRoles)); - if (authDeniedCb) { - promise.fail(function () { authDeniedCb(layout);}); - } + promise.fail(function () { authDeniedCb();}); return promise; } http://git-wip-us.apache.org/repos/asf/couchdb/blob/c33e3903/src/fauxton/app/modules/documents/routes.js ---------------------------------------------------------------------- diff --git a/src/fauxton/app/modules/documents/routes.js b/src/fauxton/app/modules/documents/routes.js index e75601a..bb8b193 100644 --- a/src/fauxton/app/modules/documents/routes.js +++ b/src/fauxton/app/modules/documents/routes.js @@ -175,7 +175,7 @@ function(app, FauxtonAPI, Documents, Databases) { "database/:database/_all_docs(:extra)": "allDocs", "database/:database/_design/:ddoc/_view/:view": { route: "viewFn", - roles: ['admin'] + roles: ['_admin'] }, "database/:database/new_view": "newViewEditor" }, http://git-wip-us.apache.org/repos/asf/couchdb/blob/c33e3903/src/fauxton/app/router.js ---------------------------------------------------------------------- diff --git a/src/fauxton/app/router.js b/src/fauxton/app/router.js index 6c417ed..4a79ff1 100644 --- a/src/fauxton/app/router.js +++ b/src/fauxton/app/router.js @@ -67,7 +67,7 @@ function(req, app, Initialize, FauxtonAPI, Fauxton, Layout, Databases, Documents routeCallback = routeObject.routeCallback(route), roles = routeObject.getRouteRoles(route); - var authPromise = app.auth.checkAccess(roles, masterLayout); + var authPromise = app.auth.checkAccess(roles); authPromise.then(function () { routeCallback.apply(routeObject, args); @@ -111,7 +111,6 @@ function(req, app, Initialize, FauxtonAPI, Fauxton, Layout, Databases, Documents }, initialize: function() { - console.log('HI ROUTS'); //TODO: It would be nice to handle this with a router this.navBar = app.navBar = new Fauxton.NavBar(); this.apiBar = app.apiBar = new Fauxton.ApiBar();
