From 78b9b6ced4b64208b314f16e86567520ff0f1cdc Mon Sep 17 00:00:00 2001 From: Justin Richer Date: Tue, 21 Mar 2017 15:04:18 -0400 Subject: [PATCH] auto format and cleanup javascript --- .../src/main/webapp/resources/js/admin.js | 762 ++--- .../src/main/webapp/resources/js/blacklist.js | 256 +- .../src/main/webapp/resources/js/client.js | 2500 +++++++++-------- .../src/main/webapp/resources/js/dynreg.js | 1369 ++++----- .../src/main/webapp/resources/js/grant.js | 311 +- .../src/main/webapp/resources/js/profile.js | 39 +- .../src/main/webapp/resources/js/rsreg.js | 935 +++--- .../src/main/webapp/resources/js/scope.js | 627 +++-- .../src/main/webapp/resources/js/token.js | 696 ++--- .../src/main/webapp/resources/js/whitelist.js | 745 ++--- 10 files changed, 4427 insertions(+), 3813 deletions(-) diff --git a/openid-connect-server-webapp/src/main/webapp/resources/js/admin.js b/openid-connect-server-webapp/src/main/webapp/resources/js/admin.js index fdbacdfbb..18c2efeec 100644 --- a/openid-connect-server-webapp/src/main/webapp/resources/js/admin.js +++ b/openid-connect-server-webapp/src/main/webapp/resources/js/admin.js @@ -53,344 +53,386 @@ Backbone.Collection.prototype.fetchIfNeeded = function(options) { } }; -var URIModel = Backbone.Model.extend({ +var URIModel = Backbone.Model + .extend({ - validate: function(attrs){ + validate: function(attrs) { - var expression = /^(?:([a-z0-9+.-]+:\/\/)((?:(?:[a-z0-9-._~!$&'()*+,;=:]|%[0-9A-F]{2})*)@)?((?:[a-z0-9-._~!$&'()*+,;=]|%[0-9A-F]{2})*)(:(?:\d*))?(\/(?:[a-z0-9-._~!$&'()*+,;=:@\/]|%[0-9A-F]{2})*)?|([a-z0-9+.-]+:)(\/?(?:[a-z0-9-._~!$&'()*+,;=:@]|%[0-9A-F]{2})+(?:[a-z0-9-._~!$&'()*+,;=:@\/]|%[0-9A-F]{2})*)?)(\?(?:[a-z0-9-._~!$&'()*+,;=:\/?@]|%[0-9A-F]{2})*)?(#(?:[a-z0-9-._~!$&'()*+,;=:\/?@]|%[0-9A-F]{2})*)?$/i; - var regex = new RegExp(expression); + var expression = /^(?:([a-z0-9+.-]+:\/\/)((?:(?:[a-z0-9-._~!$&'()*+,;=:]|%[0-9A-F]{2})*)@)?((?:[a-z0-9-._~!$&'()*+,;=]|%[0-9A-F]{2})*)(:(?:\d*))?(\/(?:[a-z0-9-._~!$&'()*+,;=:@\/]|%[0-9A-F]{2})*)?|([a-z0-9+.-]+:)(\/?(?:[a-z0-9-._~!$&'()*+,;=:@]|%[0-9A-F]{2})+(?:[a-z0-9-._~!$&'()*+,;=:@\/]|%[0-9A-F]{2})*)?)(\?(?:[a-z0-9-._~!$&'()*+,;=:\/?@]|%[0-9A-F]{2})*)?(#(?:[a-z0-9-._~!$&'()*+,;=:\/?@]|%[0-9A-F]{2})*)?$/i; + var regex = new RegExp(expression); - if (attrs.item == null || !attrs.item.match(regex)) { - return "Invalid URI"; - } - } - -}); + if (attrs.item == null || !attrs.item.match(regex)) { + return "Invalid URI"; + } + } + }); /* -* Backbone JS Reusable ListWidget -* Options -* { -* collection: Backbone JS Collection -* type: ('uri'|'default') -* autocomplete: ['item1','item2'] List of auto complete items -* } -* + * Backbone JS Reusable ListWidget Options { collection: Backbone JS Collection + * type: ('uri'|'default') autocomplete: ['item1','item2'] List of auto complete + * items } + * */ var ListWidgetChildView = Backbone.View.extend({ - tagName: 'tr', + tagName: 'tr', - events:{ - "click .btn-delete-list-item":'deleteItem', - "change .checkbox-list-item":'toggleCheckbox' - }, - - deleteItem:function (e) { - e.preventDefault(); - e.stopImmediatePropagation(); - //this.$el.tooltip('delete'); - - this.model.destroy({ - dataType: false, processData: false, - error:app.errorHandlerView.handleError() - }); - - }, - - toggleCheckbox:function(e) { - e.preventDefault(); - e.stopImmediatePropagation(); - if ($(e.target).is(':checked')) { - this.options.collection.add(this.model); - } else { - this.options.collection.remove(this.model); - } - - }, + events: { + "click .btn-delete-list-item": 'deleteItem', + "change .checkbox-list-item": 'toggleCheckbox' + }, - initialize:function (options) { - this.options = {toggle: false, checked: false}; - _.extend(this.options, options); - if (!this.template) { - this.template = _.template($('#tmpl-list-widget-child').html()); - } - }, + deleteItem: function(e) { + e.preventDefault(); + e.stopImmediatePropagation(); + // this.$el.tooltip('delete'); - render:function () { - - var data = {model: this.model.toJSON(), opt: this.options}; - - this.$el.html(this.template(data)); + this.model.destroy({ + dataType: false, + processData: false, + error: app.errorHandlerView.handleError() + }); - $('.item-full', this.el).hide(); - - if (this.model.get('item').length > 30) { - this.$el.tooltip({title:$.t('admin.list-widget.tooltip')}); - - var _self = this; - - $(this.el).click(function(event) { - event.preventDefault(); - $('.item-short', _self.el).hide(); - $('.item-full', _self.el).show(); - _self.$el.tooltip('destroy'); - }); - } - - - - $(this.el).i18n(); - return this; - } + }, + + toggleCheckbox: function(e) { + e.preventDefault(); + e.stopImmediatePropagation(); + if ($(e.target).is(':checked')) { + this.options.collection.add(this.model); + } else { + this.options.collection.remove(this.model); + } + + }, + + initialize: function(options) { + this.options = { + toggle: false, + checked: false + }; + _.extend(this.options, options); + if (!this.template) { + this.template = _.template($('#tmpl-list-widget-child').html()); + } + }, + + render: function() { + + var data = { + model: this.model.toJSON(), + opt: this.options + }; + + this.$el.html(this.template(data)); + + $('.item-full', this.el).hide(); + + if (this.model.get('item').length > 30) { + this.$el.tooltip({ + title: $.t('admin.list-widget.tooltip') + }); + + var _self = this; + + $(this.el).click(function(event) { + event.preventDefault(); + $('.item-short', _self.el).hide(); + $('.item-full', _self.el).show(); + _self.$el.tooltip('destroy'); + }); + } + + $(this.el).i18n(); + return this; + } }); var ListWidgetView = Backbone.View.extend({ - tagName: "div", + tagName: "div", - events:{ - "click .btn-add-list-item":"addItem", - "keypress":function (e) { - // trap the enter key - if (e.which == 13) { - e.preventDefault(); - this.addItem(e); - $("input", this.$el).focus(); - } - } - }, + events: { + "click .btn-add-list-item": "addItem", + "keypress": function(e) { + // trap the enter key + if (e.which == 13) { + e.preventDefault(); + this.addItem(e); + $("input", this.$el).focus(); + } + } + }, - initialize:function (options) { - this.options = options; + initialize: function(options) { + this.options = options; - if (!this.template) { - this.template = _.template($('#tmpl-list-widget').html()); - } + if (!this.template) { + this.template = _.template($('#tmpl-list-widget').html()); + } - this.collection.bind('add', this.render, this); - this.collection.bind('remove', this.render, this); - }, + this.collection.bind('add', this.render, this); + this.collection.bind('remove', this.render, this); + }, - addItem:function(e) { - e.preventDefault(); + addItem: function(e) { + e.preventDefault(); - var input_value = $("input", this.el).val().trim(); + var input_value = $("input", this.el).val().trim(); - if (input_value === ""){ - return; - } + if (input_value === "") { + return; + } - var model; + var model; - if (this.options.type == 'uri') { - model = new URIModel({item:input_value}); - } else { - model = new Backbone.Model({item:input_value}); - model.validate = function(attrs) { - if(!attrs.item) { - return "value can't be null"; - } - }; - } + if (this.options.type == 'uri') { + model = new URIModel({ + item: input_value + }); + } else { + model = new Backbone.Model({ + item: input_value + }); + model.validate = function(attrs) { + if (!attrs.item) { + return "value can't be null"; + } + }; + } - // if it's valid and doesn't already exist - if (model.get("item") != null && this.collection.where({item: input_value}).length < 1) { - this.collection.add(model); - } else { - // else add a visual error indicator - $(".control-group", this.el).addClass('error'); - } - }, + // if it's valid and doesn't already exist + if (model.get("item") != null && this.collection.where({ + item: input_value + }).length < 1) { + this.collection.add(model); + } else { + // else add a visual error indicator + $(".control-group", this.el).addClass('error'); + } + }, - render:function (eventName) { + render: function(eventName) { - this.$el.html(this.template({placeholder:this.options.placeholder, - helpBlockText:this.options.helpBlockText})); + this.$el.html(this.template({ + placeholder: this.options.placeholder, + helpBlockText: this.options.helpBlockText + })); - var _self = this; + var _self = this; - if (_.size(this.collection.models) == 0 && _.size(this.options.autocomplete) == 0) { - $("tbody", _self.el).html($('#tmpl-list-widget-child-empty').html()); - } else { - - // make a copy of our collection to work from - var values = this.collection.clone(); + if (_.size(this.collection.models) == 0 && _.size(this.options.autocomplete) == 0) { + $("tbody", _self.el).html($('#tmpl-list-widget-child-empty').html()); + } else { - // look through our autocomplete values (if we have them) and render them all as checkboxes - if (this.options.autocomplete) { - _.each(this.options.autocomplete, function(option) { - var found = _.find(values.models, function(element) { - return element.get('item') == option; - }); - - var model = null; - var checked = false; - - if (found) { - // if we found the element, check the box - model = found; - checked = true; - // and remove it from the list of items to be rendered later - values.remove(found, {silent: true}); - } else { - model = new Backbone.Model({item:option}); - checked = false; - } - - var el = new ListWidgetChildView({model:model, toggle: true, checked: checked, collection: _self.collection}).render().el; - $("tbody", _self.el).append(el); - - }, this); - } - - - // now render everything not in the autocomplete list - _.each(values.models, function (model) { - var el = new ListWidgetChildView({model:model, collection: _self.collection}).render().el; - $("tbody", _self.el).append(el); - }, this); - } + // make a copy of our collection to work from + var values = this.collection.clone(); + + // look through our autocomplete values (if we have them) and render + // them all as checkboxes + if (this.options.autocomplete) { + _.each(this.options.autocomplete, function(option) { + var found = _.find(values.models, function(element) { + return element.get('item') == option; + }); + + var model = null; + var checked = false; + + if (found) { + // if we found the element, check the box + model = found; + checked = true; + // and remove it from the list of items to be rendered + // later + values.remove(found, { + silent: true + }); + } else { + model = new Backbone.Model({ + item: option + }); + checked = false; + } + + var el = new ListWidgetChildView({ + model: model, + toggle: true, + checked: checked, + collection: _self.collection + }).render().el; + $("tbody", _self.el).append(el); + + }, this); + } + + // now render everything not in the autocomplete list + _.each(values.models, function(model) { + var el = new ListWidgetChildView({ + model: model, + collection: _self.collection + }).render().el; + $("tbody", _self.el).append(el); + }, this); + } + + $(this.el).i18n(); + return this; + } - $(this.el).i18n(); - return this; - } - }); var BreadCrumbView = Backbone.View.extend({ - tagName: 'ul', + tagName: 'ul', - initialize:function (options) { - this.options = options; + initialize: function(options) { + this.options = options; - if (!this.template) { - this.template = _.template($('#tmpl-breadcrumbs').html()); - } + if (!this.template) { + this.template = _.template($('#tmpl-breadcrumbs').html()); + } - this.$el.addClass('breadcrumb'); + this.$el.addClass('breadcrumb'); - this.collection.bind('add', this.render, this); - }, + this.collection.bind('add', this.render, this); + }, - render:function () { + render: function() { - this.$el.empty(); - var parent = this; + this.$el.empty(); + var parent = this; - // go through each of the breadcrumb models - _.each(this.collection.models, function (crumb, index) { + // go through each of the breadcrumb models + _.each(this.collection.models, function(crumb, index) { - // if it's the last index in the crumbs then render the link inactive - if (index == parent.collection.size() - 1) { - crumb.set({active:true}, {silent:true}); - } else { - crumb.set({active:false}, {silent:true}); - } + // if it's the last index in the crumbs then render the link + // inactive + if (index == parent.collection.size() - 1) { + crumb.set({ + active: true + }, { + silent: true + }); + } else { + crumb.set({ + active: false + }, { + silent: true + }); + } - this.$el.append(this.template(crumb.toJSON())); - }, this); + this.$el.append(this.template(crumb.toJSON())); + }, this); - $('#breadcrumbs').html(this.el); - $(this.el).i18n(); - } + $('#breadcrumbs').html(this.el); + $(this.el).i18n(); + } }); - // User Profile var UserProfileView = Backbone.View.extend({ tagName: 'span', - - initialize:function(options) { - this.options = options; - if (!this.template) { - this.template = _.template($('#tmpl-user-profile-element').html()); - } - }, - - render:function() { - - $(this.el).html($('#tmpl-user-profile').html()); - - var t = this.template; - _.each(this.model, function (value, key) { - if (key && value) { - - if (typeof(value) === 'object') { - - var el = this.el; - var k = key; - - _.each(value, function (value, key) { - $('dl', el).append( - t({key: key, value: value, category: k}) - ); - }); - } else if (typeof(value) === 'array') { - // TODO: handle array types - } else { - $('dl', this.el).append( - t({key: key, value: value}) - ); - } - } - }, this); - - $(this.el).i18n(); + initialize: function(options) { + this.options = options; + if (!this.template) { + this.template = _.template($('#tmpl-user-profile-element').html()); + } + }, + + render: function() { + + $(this.el).html($('#tmpl-user-profile').html()); + + var t = this.template; + + _.each(this.model, function(value, key) { + if (key && value) { + + if (typeof (value) === 'object') { + + var el = this.el; + var k = key; + + _.each(value, function(value, key) { + $('dl', el).append(t({ + key: key, + value: value, + category: k + })); + }); + } else if (typeof (value) === 'array') { + // TODO: handle array types + } else { + $('dl', this.el).append(t({ + key: key, + value: value + })); + } + } + }, this); + + $(this.el).i18n(); return this; } }); // error handler var ErrorHandlerView = Backbone.View.extend({ - - initialize:function(options) { - this.options = options; - if (!this.template) { - this.template = _.template($('#tmpl-error-box').html()); - } - if (!this.headerTemplate) { - this.headerTemplate = _.template($('#tmpl-error-header').html()); - } + + initialize: function(options) { + this.options = options; + if (!this.template) { + this.template = _.template($('#tmpl-error-box').html()); + } + if (!this.headerTemplate) { + this.headerTemplate = _.template($('#tmpl-error-header').html()); + } }, - - reloadPage:function(event) { + + reloadPage: function(event) { event.preventDefault(); window.location.reload(true); }, - handleError:function(message) { - + handleError: function(message) { + if (!message) { message = {}; } var _self = this; - + return function(model, response, options) { - + if (message.log) { console.log(message.log); } - - _self.showErrorMessage( - _self.headerTemplate({message: message, model: model, response: response, options: options}), - _self.template({message: message, model: model, response: response, options: options}) - ); - + + _self.showErrorMessage(_self.headerTemplate({ + message: message, + model: model, + response: response, + options: options + }), _self.template({ + message: message, + model: model, + response: response, + options: options + })); + $('#modalAlert .modal-body .page-reload').on('click', _self.reloadPage); } - }, - - showErrorMessage:function(header, message) { + }, + + showErrorMessage: function(header, message) { // hide the sheet if it's visible $('#loadingbox').sheet('hide'); - + $('#modalAlert').i18n(); $('#modalAlert div.modal-header').html(header); $('#modalAlert .modal-body').html(message); @@ -400,62 +442,66 @@ var ErrorHandlerView = Backbone.View.extend({ 'keyboard': true, 'show': true }); - + } }); - // Router var AppRouter = Backbone.Router.extend({ - routes:{ - - "": "root" - - }, - - root:function() { - if (isAdmin()) { - this.navigate('admin/clients', {trigger: true}); - } else { - this.navigate('user/approved', {trigger: true}); - } - }, - - initialize:function () { + routes: { - this.breadCrumbView = new BreadCrumbView({ - collection:new Backbone.Collection() - }); + "": "root" - this.breadCrumbView.render(); - - this.errorHandlerView = new ErrorHandlerView(); + }, - // call all the extra initialization functions - var app = this; - _.each(ui.init, function(fn) { - fn(app); - }); + root: function() { + if (isAdmin()) { + this.navigate('admin/clients', { + trigger: true + }); + } else { + this.navigate('user/approved', { + trigger: true + }); + } + }, - }, + initialize: function() { - notImplemented:function(){ - this.breadCrumbView.collection.reset(); - this.breadCrumbView.collection.add([ - {text:$.t('admin.home'), href:""} - ]); - - this.updateSidebar('none'); - - $('#content').html("

Not implemented yet.

"); - }, - - updateSidebar:function(item) { - $('.sidebar-nav li.active').removeClass('active'); - - $('.sidebar-nav li a[href^="manage/#' + item + '"]').parent().addClass('active'); - } + this.breadCrumbView = new BreadCrumbView({ + collection: new Backbone.Collection() + }); + + this.breadCrumbView.render(); + + this.errorHandlerView = new ErrorHandlerView(); + + // call all the extra initialization functions + var app = this; + _.each(ui.init, function(fn) { + fn(app); + }); + + }, + + notImplemented: function() { + this.breadCrumbView.collection.reset(); + this.breadCrumbView.collection.add([{ + text: $.t('admin.home'), + href: "" + }]); + + this.updateSidebar('none'); + + $('#content').html("

Not implemented yet.

"); + }, + + updateSidebar: function(item) { + $('.sidebar-nav li.active').removeClass('active'); + + $('.sidebar-nav li a[href^="manage/#' + item + '"]').parent().addClass('active'); + } }); // holds the global app. @@ -463,59 +509,67 @@ var AppRouter = Backbone.Router.extend({ var app = null; // main -$(function () { +$(function() { - var loader = function(source) { - return $.get(source, function (templates) { - console.log('Loading file: ' + source); - $('#templates').append(templates); - }); - }; - - // load templates and append them to the body - $.when.apply(null, ui.templates.map(loader) - ).done(function() { - console.log('done'); - $.ajaxSetup({cache:false}); - app = new AppRouter(); + var loader = function(source) { + return $.get(source, function(templates) { + console.log('Loading file: ' + source); + $('#templates').append(templates); + }); + }; - _.each(ui.routes.reverse(), function(route) { - console.log("Adding route: " + route.name); - app.route(route.path, route.name, route.callback); - }); - - app.on('route', function(name, args) { - // scroll to top of page on new route selection - $("html, body").animate({ scrollTop: 0 }, "slow"); - }); - - // grab all hashed URLs and send them through the app router instead - $(document).on('click', 'a[href^="manage/#"]', function(event) { - event.preventDefault(); - app.navigate(this.hash.slice(1), {trigger: true}); - }); - - var base = $('base').attr('href'); - $.getJSON(base + '.well-known/openid-configuration', function(data) { - app.serverConfiguration = data; - var baseUrl = $.url(app.serverConfiguration.issuer); - Backbone.history.start({pushState: true, root: baseUrl.attr('relative') + 'manage/'}); - }); - }); - - window.onerror = function ( message, filename, lineno, colno, error ){ - console.log(message); - //Display an alert with an error message + // load templates and append them to the body + $.when.apply(null, ui.templates.map(loader)).done(function() { + console.log('done'); + $.ajaxSetup({ + cache: false + }); + app = new AppRouter(); + + _.each(ui.routes.reverse(), function(route) { + console.log("Adding route: " + route.name); + app.route(route.path, route.name, route.callback); + }); + + app.on('route', function(name, args) { + // scroll to top of page on new route selection + $("html, body").animate({ + scrollTop: 0 + }, "slow"); + }); + + // grab all hashed URLs and send them through the app router instead + $(document).on('click', 'a[href^="manage/#"]', function(event) { + event.preventDefault(); + app.navigate(this.hash.slice(1), { + trigger: true + }); + }); + + var base = $('base').attr('href'); + $.getJSON(base + '.well-known/openid-configuration', function(data) { + app.serverConfiguration = data; + var baseUrl = $.url(app.serverConfiguration.issuer); + Backbone.history.start({ + pushState: true, + root: baseUrl.attr('relative') + 'manage/' + }); + }); + }); + + window.onerror = function(message, filename, lineno, colno, error) { + console.log(message); + // Display an alert with an error message $('#modalAlert div.modal-header').html($.t('error.title')); $('#modalAlert div.modal-body').html($.t('error.message') + message + '
' + [filename, lineno, colno, error]); - - $("#modalAlert").modal({ // wire up the actual modal functionality and show the dialog - "backdrop" : "static", - "keyboard" : true, - "show" : true // ensure the modal is shown immediately - }); - } + $("#modalAlert").modal({ // wire up the actual modal functionality + // and show the dialog + "backdrop": "static", + "keyboard": true, + "show": true + // ensure the modal is shown immediately + }); + + } }); - - diff --git a/openid-connect-server-webapp/src/main/webapp/resources/js/blacklist.js b/openid-connect-server-webapp/src/main/webapp/resources/js/blacklist.js index 719a68517..7b1404699 100644 --- a/openid-connect-server-webapp/src/main/webapp/resources/js/blacklist.js +++ b/openid-connect-server-webapp/src/main/webapp/resources/js/blacklist.js @@ -16,63 +16,64 @@ *******************************************************************************/ var BlackListModel = Backbone.Model.extend({ idAttribute: 'id', - + urlRoot: 'api/blacklist' }); var BlackListCollection = Backbone.Collection.extend({ - initialize: function() { }, + initialize: function() { + }, url: "api/blacklist" }); var BlackListListView = Backbone.View.extend({ tagName: 'span', - - initialize:function(options) { - this.options = options; + + initialize: function(options) { + this.options = options; }, - load:function(callback) { - if (this.collection.isFetched) { - callback(); - return; - } + load: function(callback) { + if (this.collection.isFetched) { + callback(); + return; + } - $('#loadingbox').sheet('show'); - $('#loading').html( - '' + $.t('admin.blacklist') + ' ' - ); + $('#loadingbox').sheet('show'); + $('#loading').html('' + $.t('admin.blacklist') + ' '); + + $.when(this.collection.fetchIfNeeded({ + success: function(e) { + $('#loading-blacklist').addClass('label-success'); + }, + error: app.errorHandlerView.handleError() + })).done(function() { + $('#loadingbox').sheet('hide'); + callback(); + }); + }, - $.when(this.collection.fetchIfNeeded({success:function(e) {$('#loading-blacklist').addClass('label-success');}, error:app.errorHandlerView.handleError()})) - .done(function() { - $('#loadingbox').sheet('hide'); - callback(); - }); - }, - events: { - "click .refresh-table":"refreshTable", - "click .btn-add":"addItem", - "submit #add-blacklist form":"addItem" + "click .refresh-table": "refreshTable", + "click .btn-add": "addItem", + "submit #add-blacklist form": "addItem" }, - refreshTable:function(e) { - e.preventDefault(); + refreshTable: function(e) { + e.preventDefault(); - var _self = this; - $('#loadingbox').sheet('show'); - $('#loading').html( - '' + $.t('admin.blacklist') + ' ' - ); + var _self = this; + $('#loadingbox').sheet('show'); + $('#loading').html('' + $.t('admin.blacklist') + ' '); - $.when(this.collection.fetch()).done(function() { - $('#loadingbox').sheet('hide'); - _self.render(); - }); - }, - - togglePlaceholder:function() { + $.when(this.collection.fetch()).done(function() { + $('#loadingbox').sheet('hide'); + _self.render(); + }); + }, + + togglePlaceholder: function() { if (this.collection.length > 0) { $('#blacklist-table', this.el).show(); $('#blacklist-table-empty', this.el).hide(); @@ -81,136 +82,143 @@ var BlackListListView = Backbone.View.extend({ $('#blacklist-table-empty', this.el).show(); } }, - - render:function (eventName) { - + + render: function(eventName) { + $(this.el).html($('#tmpl-blacklist-table').html()); - + var _self = this; _.each(this.collection.models, function(blacklist) { - var view = new BlackListWidgetView({model: blacklist}); + var view = new BlackListWidgetView({ + model: blacklist + }); view.parentView = _self; $("#blacklist-table", _self.el).append(view.render().el); }, this); - + this.togglePlaceholder(); - - $(this.el).i18n(); + + $(this.el).i18n(); return this; }, - - addItem:function(e) { - e.preventDefault(); - var input_value = $("#blacklist-uri", this.el).val().trim(); - - if (input_value === "") { - return; - } - - // TODO: URI/pattern validation, check against existing clients - - var item = new BlackListModel({ - uri: input_value - }); - - var _self = this; // closures... - - item.save({}, { - success:function() { - _self.collection.add(item); - _self.render(); - }, - error:app.errorHandlerView.handleError() - }); + addItem: function(e) { + e.preventDefault(); + + var input_value = $("#blacklist-uri", this.el).val().trim(); + + if (input_value === "") { + return; + } + + // TODO: URI/pattern validation, check against existing clients + + var item = new BlackListModel({ + uri: input_value + }); + + var _self = this; // closures... + + item.save({}, { + success: function() { + _self.collection.add(item); + _self.render(); + }, + error: app.errorHandlerView.handleError() + }); } }); var BlackListWidgetView = Backbone.View.extend({ - + tagName: 'tr', - - initialize:function(options) { + + initialize: function(options) { this.options = options; - + if (!this.template) { this.template = _.template($('#tmpl-blacklist-item').html()); } }, - - render:function() { + + render: function() { this.$el.html(this.template(this.model.toJSON())); - return this; - + return this; + }, - - events:{ - 'click .btn-delete':'deleteBlacklist' + + events: { + 'click .btn-delete': 'deleteBlacklist' }, - - deleteBlacklist:function (e) { - e.preventDefault(); - if (confirm($.t("blacklist.confirm"))) { - var _self = this; + deleteBlacklist: function(e) { + e.preventDefault(); - this.model.destroy({ - dataType: false, processData: false, - success:function () { - - _self.$el.fadeTo("fast", 0.00, function () { //fade - $(this).slideUp("fast", function () { //slide up - $(this).remove(); //then remove from the DOM - _self.parentView.togglePlaceholder(); - }); - }); - }, - error:app.errorHandlerView.handleError() - }); + if (confirm($.t("blacklist.confirm"))) { + var _self = this; - _self.parentView.delegateEvents(); - } + this.model.destroy({ + dataType: false, + processData: false, + success: function() { - return false; - } + _self.$el.fadeTo("fast", 0.00, function() { // fade + $(this).slideUp("fast", function() { // slide up + $(this).remove(); // then remove from the DOM + _self.parentView.togglePlaceholder(); + }); + }); + }, + error: app.errorHandlerView.handleError() + }); + + _self.parentView.delegateEvents(); + } + + return false; + } }); +ui.routes.push({ + path: "admin/blacklist", + name: "blackList", + callback: function() { -ui.routes.push({path: "admin/blacklist", name: "blackList", callback: - function() { - if (!isAdmin()) { this.root(); return; } - + this.breadCrumbView.collection.reset(); - this.breadCrumbView.collection.add([ - {text:$.t('admin.home'), href:""}, - {text:$.t('admin.manage-blacklist'), href:"manage/#admin/blacklist"} - ]); - - this.updateSidebar('admin/blacklist'); - - var view = new BlackListListView({collection: this.blackListList}); - - view.load( - function(collection, response, options) { - $('#content').html(view.render().el); - setPageTitle($.t('admin.manage-blacklist')); - } - ); + this.breadCrumbView.collection.add([{ + text: $.t('admin.home'), + href: "" + }, { + text: $.t('admin.manage-blacklist'), + href: "manage/#admin/blacklist" + }]); + + this.updateSidebar('admin/blacklist'); + + var view = new BlackListListView({ + collection: this.blackListList + }); + + view.load(function(collection, response, options) { + $('#content').html(view.render().el); + setPageTitle($.t('admin.manage-blacklist')); + }); } -}); +}); ui.templates.push('resources/template/blacklist.html'); ui.init.push(function(app) { - app.blackListList = new BlackListCollection(); + app.blackListList = new BlackListCollection(); }); diff --git a/openid-connect-server-webapp/src/main/webapp/resources/js/client.js b/openid-connect-server-webapp/src/main/webapp/resources/js/client.js index fceea8749..e5e42a310 100644 --- a/openid-connect-server-webapp/src/main/webapp/resources/js/client.js +++ b/openid-connect-server-webapp/src/main/webapp/resources/js/client.js @@ -16,123 +16,123 @@ *******************************************************************************/ var ClientModel = Backbone.Model.extend({ - idAttribute: "id", + idAttribute: "id", - initialize: function () { + initialize: function() { - // bind validation errors to dom elements - // this will display form elements in red if they are not valid - this.bind('error', function(model, errs) { - _.map(errs, function (val, elID) { - $('#' + elID).addClass('error'); - }); - }); + // bind validation errors to dom elements + // this will display form elements in red if they are not valid + this.bind('error', function(model, errs) { + _.map(errs, function(val, elID) { + $('#' + elID).addClass('error'); + }); + }); - }, + }, - // We can pass it default values. - defaults:{ - id:null, - - clientId:null, - clientSecret:null, - redirectUris:[], - clientName:null, - clientUri:null, - logoUri:null, - contacts:[], - tosUri:null, - tokenEndpointAuthMethod:null, - scope:[], - grantTypes:[], - responseTypes:[], - policyUri:null, - - jwksUri:null, - jwks:null, - jwksType:"URI", - - applicationType:null, - sectorIdentifierUri:null, - subjectType:null, - - requestObjectSigningAlg:null, - - userInfoSignedResponseAlg:null, - userInfoEncryptedResponseAlg:null, - userInfoEncryptedResponseEnc:null, - - idTokenSignedResponseAlg:null, - idTokenEncryptedResponseAlg:null, - idTokenEncryptedResponseEnc:null, - - tokenEndpointAuthSigningAlg:null, - - defaultMaxAge:null, - requireAuthTime:false, - defaultACRvalues:null, - - initiateLoginUri:null, - postLogoutRedirectUris:[], - - requestUris:[], - - softwareStatement:null, - softwareId:null, - softwareVersion:null, - - codeChallengeMethod:null, - - authorities:[], - accessTokenValiditySeconds: null, - refreshTokenValiditySeconds: null, - resourceIds:[], - //additionalInformation? - - claimsRedirectUris:[], - - clientDescription:null, - reuseRefreshToken:true, - clearAccessTokensOnRefresh:true, - dynamicallyRegistered:false, - allowIntrospection:false, - idTokenValiditySeconds: null, - deviceCodeValiditySeconds: null, - createdAt:null, + // We can pass it default values. + defaults: { + id: null, - allowRefresh:false, - displayClientSecret: false, - generateClientSecret: false, - }, + clientId: null, + clientSecret: null, + redirectUris: [], + clientName: null, + clientUri: null, + logoUri: null, + contacts: [], + tosUri: null, + tokenEndpointAuthMethod: null, + scope: [], + grantTypes: [], + responseTypes: [], + policyUri: null, - urlRoot:"api/clients", - - matches:function(term) { - - var matches = []; - - if (term) { - if (this.get('clientId').toLowerCase().indexOf(term.toLowerCase()) != -1) { - matches.push($.t('client.client-table.match.id')); - } - if (this.get('clientName') != null && this.get('clientName').toLowerCase().indexOf(term.toLowerCase()) != -1) { - matches.push($.t('client.client-table.match.name')); - } - if (this.get('clientDescription') != null && this.get('clientDescription').toLowerCase().indexOf(term.toLowerCase()) != -1) { - matches.push($.t('client.client-table.match.description')); - } - if (this.get('clientUri') != null && this.get('clientUri').toLowerCase().indexOf(term.toLowerCase()) != -1) { - matches.push($.t('client.client-table.match.homepage')); - } - if (this.get('policyUri') != null && this.get('policyUri').toLowerCase().indexOf(term.toLowerCase()) != -1) { - matches.push($.t('client.client-table.match.policy')); - } - if (this.get('tosUri') != null && this.get('tosUri').toLowerCase().indexOf(term.toLowerCase()) != -1) { - matches.push($.t('client.client-table.match.terms')); - } - if (this.get('logoUri') != null && this.get('logoUri').toLowerCase().indexOf(term.toLowerCase()) != -1) { - matches.push($.t('client.client-table.match.logo')); - } + jwksUri: null, + jwks: null, + jwksType: "URI", + + applicationType: null, + sectorIdentifierUri: null, + subjectType: null, + + requestObjectSigningAlg: null, + + userInfoSignedResponseAlg: null, + userInfoEncryptedResponseAlg: null, + userInfoEncryptedResponseEnc: null, + + idTokenSignedResponseAlg: null, + idTokenEncryptedResponseAlg: null, + idTokenEncryptedResponseEnc: null, + + tokenEndpointAuthSigningAlg: null, + + defaultMaxAge: null, + requireAuthTime: false, + defaultACRvalues: null, + + initiateLoginUri: null, + postLogoutRedirectUris: [], + + requestUris: [], + + softwareStatement: null, + softwareId: null, + softwareVersion: null, + + codeChallengeMethod: null, + + authorities: [], + accessTokenValiditySeconds: null, + refreshTokenValiditySeconds: null, + resourceIds: [], + // additionalInformation? + + claimsRedirectUris: [], + + clientDescription: null, + reuseRefreshToken: true, + clearAccessTokensOnRefresh: true, + dynamicallyRegistered: false, + allowIntrospection: false, + idTokenValiditySeconds: null, + deviceCodeValiditySeconds: null, + createdAt: null, + + allowRefresh: false, + displayClientSecret: false, + generateClientSecret: false, + }, + + urlRoot: "api/clients", + + matches: function(term) { + + var matches = []; + + if (term) { + if (this.get('clientId').toLowerCase().indexOf(term.toLowerCase()) != -1) { + matches.push($.t('client.client-table.match.id')); + } + if (this.get('clientName') != null && this.get('clientName').toLowerCase().indexOf(term.toLowerCase()) != -1) { + matches.push($.t('client.client-table.match.name')); + } + if (this.get('clientDescription') != null && this.get('clientDescription').toLowerCase().indexOf(term.toLowerCase()) != -1) { + matches.push($.t('client.client-table.match.description')); + } + if (this.get('clientUri') != null && this.get('clientUri').toLowerCase().indexOf(term.toLowerCase()) != -1) { + matches.push($.t('client.client-table.match.homepage')); + } + if (this.get('policyUri') != null && this.get('policyUri').toLowerCase().indexOf(term.toLowerCase()) != -1) { + matches.push($.t('client.client-table.match.policy')); + } + if (this.get('tosUri') != null && this.get('tosUri').toLowerCase().indexOf(term.toLowerCase()) != -1) { + matches.push($.t('client.client-table.match.terms')); + } + if (this.get('logoUri') != null && this.get('logoUri').toLowerCase().indexOf(term.toLowerCase()) != -1) { + matches.push($.t('client.client-table.match.logo')); + } if (this.get('contacts') != null) { var f = _.filter(this.get('contacts'), function(item) { return item.toLowerCase().indexOf(term.toLowerCase()) != -1; @@ -142,7 +142,7 @@ var ClientModel = Backbone.Model.extend({ } } if (this.get('redirectUris') != null) { - var f = _.filter(this.get('redirectUris'), function (item) { + var f = _.filter(this.get('redirectUris'), function(item) { return item.toLowerCase().indexOf(term.toLowerCase()) != -1; }); if (f.length > 0) { @@ -150,7 +150,7 @@ var ClientModel = Backbone.Model.extend({ } } if (this.get('scope') != null) { - var f = _.filter(this.get('scope'), function (item) { + var f = _.filter(this.get('scope'), function(item) { return item.toLowerCase().indexOf(term.toLowerCase()) != -1; }); if (f.length > 0) { @@ -163,29 +163,34 @@ var ClientModel = Backbone.Model.extend({ if (this.get('softwareVersion') != null && this.get('softwareVersion').toLowerCase().indexOf(term.toLowerCase()) != -1) { matches.push($.t('client.client-table.match.software-version')); } - } else { - // there's no search term, we always match - - this.unset('matches', {silent: true}); - //console.log('no term'); - return true; - } - - - var matchString = matches.join(' | '); - - if (matches.length > 0) { - this.set({ - matches: matchString - }, {silent: true}); - - return true; - } else { - this.unset('matches', {silent: true}); - - return false; - } - } + } else { + // there's no search term, we always match + + this.unset('matches', { + silent: true + }); + // console.log('no term'); + return true; + } + + var matchString = matches.join(' | '); + + if (matches.length > 0) { + this.set({ + matches: matchString + }, { + silent: true + }); + + return true; + } else { + this.unset('matches', { + silent: true + }); + + return false; + } + } }); @@ -195,64 +200,66 @@ var RegistrationTokenModel = Backbone.Model.extend({ }); var ClientStatsModel = Backbone.Model.extend({ - urlRoot: 'api/stats/byclientid' + urlRoot: 'api/stats/byclientid' }); var ClientCollection = Backbone.Collection.extend({ - initialize: function() { - //this.fetch(); - }, + initialize: function() { + // this.fetch(); + }, - model:ClientModel, - url:"api/clients", - - getByClientId: function(clientId) { - var clients = this.where({clientId: clientId}); + model: ClientModel, + url: "api/clients", + + getByClientId: function(clientId) { + var clients = this.where({ + clientId: clientId + }); if (clients.length == 1) { return clients[0]; } else { return null; } - } + } }); var ClientView = Backbone.View.extend({ - tagName: 'tr', - - isRendered: false, + tagName: 'tr', - initialize:function (options) { - this.options = options; + isRendered: false, - if (!this.template) { - this.template = _.template($('#tmpl-client-table-item').html()); - } + initialize: function(options) { + this.options = options; - if (!this.scopeTemplate) { - this.scopeTemplate = _.template($('#tmpl-scope-list').html()); - } + if (!this.template) { + this.template = _.template($('#tmpl-client-table-item').html()); + } - if (!this.moreInfoTemplate) { - this.moreInfoTemplate = _.template($('#tmpl-client-more-info-block').html()); - } - - if (!this.registrationTokenTemplate) { - this.registrationTokenTemplate = _.template($('#tmpl-client-registration-token').html()); - } - - if (!this.countTemplate) { - this.countTemplate = _.template($('#tmpl-client-count').html()); - } - - this.model.bind('change', this.render, this); - - }, + if (!this.scopeTemplate) { + this.scopeTemplate = _.template($('#tmpl-scope-list').html()); + } - render:function (eventName) { - - var creationDate = this.model.get('createdAt'); + if (!this.moreInfoTemplate) { + this.moreInfoTemplate = _.template($('#tmpl-client-more-info-block').html()); + } + + if (!this.registrationTokenTemplate) { + this.registrationTokenTemplate = _.template($('#tmpl-client-registration-token').html()); + } + + if (!this.countTemplate) { + this.countTemplate = _.template($('#tmpl-client-count').html()); + } + + this.model.bind('change', this.render, this); + + }, + + render: function(eventName) { + + var creationDate = this.model.get('createdAt'); var displayCreationDate = $.t('client.client-table.unknown'); var hoverCreationDate = ""; if (creationDate == null || !moment(creationDate).isValid()) { @@ -268,144 +275,176 @@ var ClientView = Backbone.View.extend({ hoverCreationDate = creationDate.format("LLL"); } - - var json = {client: this.model.toJSON(), whiteList: this.options.whiteList, - displayCreationDate: displayCreationDate, hoverCreationDate: hoverCreationDate}; - this.$el.html(this.template(json)); + var json = { + client: this.model.toJSON(), + whiteList: this.options.whiteList, + displayCreationDate: displayCreationDate, + hoverCreationDate: hoverCreationDate + }; + this.$el.html(this.template(json)); - $('.scope-list', this.el).html(this.scopeTemplate({scopes: this.model.get('scope'), systemScopes: this.options.systemScopeList})); - - $('.client-more-info-block', this.el).html(this.moreInfoTemplate({client: this.model.toJSON()})); - - $('.clientid-full', this.el).hide(); - - this.$('.dynamically-registered').tooltip({title: $.t('client.client-table.dynamically-registered-tooltip')}); - this.$('.allow-introspection').tooltip({title: $.t('client.client-table.allow-introspection-tooltip')}); - - this.updateMatched(); - this.updateStats(); - - $(this.el).i18n(); - - this.isRendered = true; - - return this; - }, - - updateStats:function(eventName) { - $('.count', this.el).html(this.countTemplate({count: this.options.clientStat.get('approvedSiteCount')})); - }, - - showRegistrationToken:function(e) { - e.preventDefault(); + $('.scope-list', this.el).html(this.scopeTemplate({ + scopes: this.model.get('scope'), + systemScopes: this.options.systemScopeList + })); - $('#modalAlertLabel').html($.t('client.client-form.registration-access-token')); - - var token = new RegistrationTokenModel({clientId: this.model.get('clientId')}); - - var _self = this; - token.fetch({success:function() { - var savedModel = { - clientId: _self.model.get('clientId'), - registrationToken: token.get('value') - }; - - $('#modalAlert .modal-body').html(_self.registrationTokenTemplate(savedModel)); - - $('#modalAlert .modal-body #rotate-token').click(function(e) { - if (confirm($.t('client.client-form.rotate-registration-token-confirm'))) { - token.save(null, {success: function() { - console.log('token:' + token.get('value')); - $('#modalAlert .modal-body #registrationToken').val(token.get('value')); - }, - error: app.errorHandlerView.handleError({message: $.t('client.client-form.rotate-registration-token-error')}) - }); - } - }); - - $('#modalAlert').i18n(); - $('#modalAlert').modal({ - 'backdrop': 'static', - 'keyboard': true, - 'show': true - }); - - }, - error:app.errorHandlerView.handleError({log: "An error occurred when fetching the registration token", message: $.t('client.client-form.registration-token-error')}) - }); - - }, - - updateMatched:function() { - - //console.log(this.model.get('matches')); - - if (this.model.get('matches')) { - $('.matched', this.el).show(); - $('.matched span', this.el).html(this.model.get('matches')); - } else { - $('.matched', this.el).hide(); - } - }, + $('.client-more-info-block', this.el).html(this.moreInfoTemplate({ + client: this.model.toJSON() + })); - events:{ - "click .btn-edit":"editClient", - "click .btn-delete":"deleteClient", - "click .btn-whitelist":"whiteListClient", + $('.clientid-full', this.el).hide(); + + this.$('.dynamically-registered').tooltip({ + title: $.t('client.client-table.dynamically-registered-tooltip') + }); + this.$('.allow-introspection').tooltip({ + title: $.t('client.client-table.allow-introspection-tooltip') + }); + + this.updateMatched(); + this.updateStats(); + + $(this.el).i18n(); + + this.isRendered = true; + + return this; + }, + + updateStats: function(eventName) { + $('.count', this.el).html(this.countTemplate({ + count: this.options.clientStat.get('approvedSiteCount') + })); + }, + + showRegistrationToken: function(e) { + e.preventDefault(); + + $('#modalAlertLabel').html($.t('client.client-form.registration-access-token')); + + var token = new RegistrationTokenModel({ + clientId: this.model.get('clientId') + }); + + var _self = this; + token.fetch({ + success: function() { + var savedModel = { + clientId: _self.model.get('clientId'), + registrationToken: token.get('value') + }; + + $('#modalAlert .modal-body').html(_self.registrationTokenTemplate(savedModel)); + + $('#modalAlert .modal-body #rotate-token').click(function(e) { + if (confirm($.t('client.client-form.rotate-registration-token-confirm'))) { + token.save(null, { + success: function() { + console.log('token:' + token.get('value')); + $('#modalAlert .modal-body #registrationToken').val(token.get('value')); + }, + error: app.errorHandlerView.handleError({ + message: $.t('client.client-form.rotate-registration-token-error') + }) + }); + } + }); + + $('#modalAlert').i18n(); + $('#modalAlert').modal({ + 'backdrop': 'static', + 'keyboard': true, + 'show': true + }); + + }, + error: app.errorHandlerView.handleError({ + log: "An error occurred when fetching the registration token", + message: $.t('client.client-form.registration-token-error') + }) + }); + + }, + + updateMatched: function() { + + // console.log(this.model.get('matches')); + + if (this.model.get('matches')) { + $('.matched', this.el).show(); + $('.matched span', this.el).html(this.model.get('matches')); + } else { + $('.matched', this.el).hide(); + } + }, + + events: { + "click .btn-edit": "editClient", + "click .btn-delete": "deleteClient", + "click .btn-whitelist": "whiteListClient", 'click .toggleMoreInformation': 'toggleMoreInformation', - "click .clientid-substring":"showClientId", - "click .dynamically-registered": 'showRegistrationToken' - }, + "click .clientid-substring": "showClientId", + "click .dynamically-registered": 'showRegistrationToken' + }, - editClient:function (e) { - e.preventDefault(); - app.navigate('admin/client/' + this.model.id, {trigger: true}); - }, + editClient: function(e) { + e.preventDefault(); + app.navigate('admin/client/' + this.model.id, { + trigger: true + }); + }, - whiteListClient:function(e) { - e.preventDefault(); - if (this.options.whiteList == null) { - // create a new one - app.navigate('admin/whitelist/new/' + this.model.get('id'), {trigger: true}); - } else { - // edit the existing one - app.navigate('admin/whitelist/' + this.options.whiteList.get('id'), {trigger: true}); - } - }, - - deleteClient:function (e) { - e.preventDefault(); + whiteListClient: function(e) { + e.preventDefault(); + if (this.options.whiteList == null) { + // create a new one + app.navigate('admin/whitelist/new/' + this.model.get('id'), { + trigger: true + }); + } else { + // edit the existing one + app.navigate('admin/whitelist/' + this.options.whiteList.get('id'), { + trigger: true + }); + } + }, - if (confirm($.t('client.client-table.confirm'))) { - var _self = this; + deleteClient: function(e) { + e.preventDefault(); - this.model.destroy({ - dataType: false, processData: false, - success:function () { - _self.$el.fadeTo("fast", 0.00, function () { //fade - $(this).slideUp("fast", function () { //slide up - $(this).remove(); //then remove from the DOM - _self.parentView.togglePlaceholder(); - }); - }); - }, - error:app.errorHandlerView.handleError({log: "An error occurred when deleting a client"}) - }); + if (confirm($.t('client.client-table.confirm'))) { + var _self = this; - _self.parentView.delegateEvents(); - } + this.model.destroy({ + dataType: false, + processData: false, + success: function() { + _self.$el.fadeTo("fast", 0.00, function() { // fade + $(this).slideUp("fast", function() { // slide up + $(this).remove(); // then remove from the DOM + _self.parentView.togglePlaceholder(); + }); + }); + }, + error: app.errorHandlerView.handleError({ + log: "An error occurred when deleting a client" + }) + }); - return false; - }, + _self.parentView.delegateEvents(); + } - toggleMoreInformation:function(e) { + return false; + }, + + toggleMoreInformation: function(e) { e.preventDefault(); if ($('.moreInformation', this.el).is(':visible')) { // hide it $('.moreInformationContainer', this.el).removeClass('alert').removeClass('alert-info').addClass('muted'); $('.moreInformation', this.el).hide('fast'); $('.toggleMoreInformation i', this.el).attr('class', 'icon-chevron-right'); - + } else { // show it $('.moreInformationContainer', this.el).addClass('alert').addClass('alert-info').removeClass('muted'); @@ -413,134 +452,145 @@ var ClientView = Backbone.View.extend({ $('.toggleMoreInformation i', this.el).attr('class', 'icon-chevron-down'); } }, - - showClientId:function(e) { + + showClientId: function(e) { e.preventDefault(); - + $('.clientid-full', this.el).show(); - + }, - - close:function () { - $(this.el).unbind(); - $(this.el).empty(); - } + + close: function() { + $(this.el).unbind(); + $(this.el).empty(); + } }); var ClientListView = Backbone.View.extend({ - tagName: 'span', + tagName: 'span', - stats: {}, - - initialize:function (options) { - this.options = options; - this.filteredModel = this.model; - }, - - load:function(callback) { - if (this.model.isFetched && - this.options.whiteListList.isFetched && - this.options.systemScopeList.isFetched) { - callback(); - return; - } - - $('#loadingbox').sheet('show'); - $('#loading').html( - '' + $.t("common.clients") + ' ' + - '' + $.t("whitelist.whitelist") + ' ' + - '' + $.t("common.scopes") + ' ' - ); + stats: {}, - $.when(this.model.fetchIfNeeded({success:function(e) {$('#loading-clients').addClass('label-success');}, error:app.errorHandlerView.handleError()}), - this.options.whiteListList.fetchIfNeeded({success:function(e) {$('#loading-whitelist').addClass('label-success');}, error:app.errorHandlerView.handleError()}), - this.options.systemScopeList.fetchIfNeeded({success:function(e) {$('#loading-scopes').addClass('label-success');}, error:app.errorHandlerView.handleError()})) - .done(function() { - $('#loadingbox').sheet('hide'); - callback(); - }); - - }, + initialize: function(options) { + this.options = options; + this.filteredModel = this.model; + }, - events:{ - "click .new-client":"newClient", - "click .refresh-table":"refreshTable", - 'keyup .search-query':'searchTable', - 'click .form-search button':'clearSearch', - 'page .paginator':'changePage' - }, + load: function(callback) { + if (this.model.isFetched && this.options.whiteListList.isFetched && this.options.systemScopeList.isFetched) { + callback(); + return; + } - newClient:function (e) { - e.preventDefault(); - this.remove(); - app.navigate('admin/client/new', {trigger: true}); - }, + $('#loadingbox').sheet('show'); + $('#loading').html('' + $.t("common.clients") + ' ' + '' + $.t("whitelist.whitelist") + ' ' + '' + $.t("common.scopes") + ' '); - render:function (eventName) { + $.when(this.model.fetchIfNeeded({ + success: function(e) { + $('#loading-clients').addClass('label-success'); + }, + error: app.errorHandlerView.handleError() + }), this.options.whiteListList.fetchIfNeeded({ + success: function(e) { + $('#loading-whitelist').addClass('label-success'); + }, + error: app.errorHandlerView.handleError() + }), this.options.systemScopeList.fetchIfNeeded({ + success: function(e) { + $('#loading-scopes').addClass('label-success'); + }, + error: app.errorHandlerView.handleError() + })).done(function() { + $('#loadingbox').sheet('hide'); + callback(); + }); - // append and render table structure - $(this.el).html($('#tmpl-client-table').html()); - - this.renderInner(); - $(this.el).i18n(); - return this; - }, - - renderInner:function(eventName) { + }, - // set up the rows to render - // (note that this doesn't render until visibility is determined in togglePlaceholder) - - _.each(this.filteredModel.models, function (client, index) { - var clientStat = this.getStat(client.get('clientId')); - var view = new ClientView({ - model:client, - clientStat:clientStat, + events: { + "click .new-client": "newClient", + "click .refresh-table": "refreshTable", + 'keyup .search-query': 'searchTable', + 'click .form-search button': 'clearSearch', + 'page .paginator': 'changePage' + }, + + newClient: function(e) { + e.preventDefault(); + this.remove(); + app.navigate('admin/client/new', { + trigger: true + }); + }, + + render: function(eventName) { + + // append and render table structure + $(this.el).html($('#tmpl-client-table').html()); + + this.renderInner(); + $(this.el).i18n(); + return this; + }, + + renderInner: function(eventName) { + + // set up the rows to render + // (note that this doesn't render until visibility is determined in + // togglePlaceholder) + + _.each(this.filteredModel.models, function(client, index) { + var clientStat = this.getStat(client.get('clientId')); + var view = new ClientView({ + model: client, + clientStat: clientStat, systemScopeList: this.options.systemScopeList, whiteList: this.options.whiteListList.getByClientId(client.get('clientId')) }); - view.parentView = this; - //var element = view.render().el; - var element = view.el; - $("#client-table",this.el).append(element); - this.addView(client.get('id'), view); - }, this); + view.parentView = this; + // var element = view.render().el; + var element = view.el; + $("#client-table", this.el).append(element); + this.addView(client.get('id'), view); + }, this); - this.togglePlaceholder(); - }, - - views:{}, - - addView:function(index, view) { - this.views[index] = view; - }, - - getView:function(index) { - return this.views[index]; - }, - - getStat:function(index) { + this.togglePlaceholder(); + }, + + views: {}, + + addView: function(index, view) { + this.views[index] = view; + }, + + getView: function(index) { + return this.views[index]; + }, + + getStat: function(index) { if (!this.stats[index]) { - this.stats[index] = new ClientStatsModel({id: index}); + this.stats[index] = new ClientStatsModel({ + id: index + }); } return this.stats[index]; }, - - togglePlaceholder:function() { - // set up pagination - var numPages = Math.ceil(this.filteredModel.length / 10); - if (numPages > 1) { - $('.paginator', this.el).show(); - $('.paginator', this.el).bootpag({ - total: numPages, - maxVisible: 10, - leaps: false, - page: 1 - }); - } else { - $('.paginator', this.el).hide(); - } + + togglePlaceholder: function() { + // set up pagination + var numPages = Math.ceil(this.filteredModel.length / 10); + if (numPages > 1) { + $('.paginator', this.el).show(); + $('.paginator', this.el).bootpag({ + total: numPages, + maxVisible: 10, + leaps: false, + page: 1 + }); + } else { + $('.paginator', this.el).hide(); + } if (this.filteredModel.length > 0) { this.changePage(undefined, 1); @@ -561,867 +611,947 @@ var ClientListView = Backbone.View.extend({ } } }, - - changePage:function(event, num) { + + changePage: function(event, num) { console.log('Page changed: ' + num); - - $('.paginator', this.el).bootpag({page:num}); - var _self = this; - - _.each(this.filteredModel.models, function (client, index) { - var view = _self.getView(client.get('id')); - if (!view) { - console.log('Error: no view for client ' + client.get('id')); - return; - } - // only show/render clients on the current page - - console.log(':: ' + index + ' ' + num + ' ' + Math.ceil((index + 1) / 10) != num); - - if (Math.ceil((index + 1) / 10) != num) { - $(view.el).hide(); - } else { - if (!view.isRendered) { - view.render(); - var clientStat = view.options.clientStat; - - // load and display the stats - $.when(clientStat.fetchIfNeeded({ - success:function(e) { - - }, - error:app.errorHandlerView.handleError()})) - .done(function(e) { - view.updateStats(); - }); - } - $(view.el).show(); - } - }); - - /* - $('#client-table tbody tr', this.el).each(function(index, element) { - if (Math.ceil((index + 1) / 10) != num) { - // hide the element - $(element).hide(); - } else { - // show the element - $(element).show(); - } + $('.paginator', this.el).bootpag({ + page: num }); - */ - }, - - refreshTable:function(e) { - e.preventDefault(); - $('#loadingbox').sheet('show'); - $('#loading').html( - '' + $.t("common.clients") + ' ' + - '' + $.t("whitelist.whitelist") + ' ' + - '' + $.t("common.scopes") + ' ' - ); + var _self = this; + + _.each(this.filteredModel.models, function(client, index) { + var view = _self.getView(client.get('id')); + if (!view) { + console.log('Error: no view for client ' + client.get('id')); + return; + } + + // only show/render clients on the current page + + console.log(':: ' + index + ' ' + num + ' ' + Math.ceil((index + 1) / 10) != num); + + if (Math.ceil((index + 1) / 10) != num) { + $(view.el).hide(); + } else { + if (!view.isRendered) { + view.render(); + var clientStat = view.options.clientStat; + + // load and display the stats + $.when(clientStat.fetchIfNeeded({ + success: function(e) { + + }, + error: app.errorHandlerView.handleError() + })).done(function(e) { + view.updateStats(); + }); + } + $(view.el).show(); + } + }); + + /* + * $('#client-table tbody tr', this.el).each(function(index, element) { + * if (Math.ceil((index + 1) / 10) != num) { // hide the element + * $(element).hide(); } else { // show the element $(element).show(); } + * }); + */ + }, + + refreshTable: function(e) { + e.preventDefault(); + $('#loadingbox').sheet('show'); + $('#loading').html('' + $.t("common.clients") + ' ' + '' + $.t("whitelist.whitelist") + ' ' + '' + $.t("common.scopes") + ' '); + + var _self = this; + $.when(this.model.fetch({ + success: function(e) { + $('#loading-clients').addClass('label-success'); + }, + error: app.errorHandlerView.handleError() + }), this.options.whiteListList.fetch({ + success: function(e) { + $('#loading-whitelist').addClass('label-success'); + }, + error: app.errorHandlerView.handleError() + }), this.options.systemScopeList.fetch({ + success: function(e) { + $('#loading-scopes').addClass('label-success'); + }, + error: app.errorHandlerView.handleError() + })).done(function() { + $('#loadingbox').sheet('hide'); + _self.render(); + }); + }, + + searchTable: function(e) { + var term = $('.search-query', this.el).val(); - var _self = this; - $.when(this.model.fetch({success:function(e) {$('#loading-clients').addClass('label-success');}, error:app.errorHandlerView.handleError()}), - this.options.whiteListList.fetch({success:function(e) {$('#loading-whitelist').addClass('label-success');}, error:app.errorHandlerView.handleError()}), - this.options.systemScopeList.fetch({success:function(e) {$('#loading-scopes').addClass('label-success');}, error:app.errorHandlerView.handleError()})) - .done(function() { - $('#loadingbox').sheet('hide'); - _self.render(); - }); - }, - - searchTable:function(e) { - var term = $('.search-query', this.el).val(); - this.filteredModel = new ClientCollection(this.model.filter(function(client) { return client.matches(term); })); - - // clear out the table - $('tbody', this.el).html(''); - - // re-render the table - this.renderInner(); - - }, - - clearSearch:function(e) { - $('.search-query', this.el).val(''); - this.searchTable(); - } - - + + // clear out the table + $('tbody', this.el).html(''); + + // re-render the table + this.renderInner(); + + }, + + clearSearch: function(e) { + $('.search-query', this.el).val(''); + this.searchTable(); + } + }); var ClientFormView = Backbone.View.extend({ - tagName:"span", + tagName: "span", - initialize:function (options) { - this.options = options; + initialize: function(options) { + this.options = options; - if (!this.template) { - this.template = _.template($('#tmpl-client-form').html()); - } - - if (!this.clientSavedTemplate) { - this.clientSavedTemplate = _.template($('#tmpl-client-saved').html()); - } + if (!this.template) { + this.template = _.template($('#tmpl-client-form').html()); + } - this.redirectUrisCollection = new Backbone.Collection(); - this.scopeCollection = new Backbone.Collection(); - this.contactsCollection = new Backbone.Collection(); - this.defaultACRvaluesCollection = new Backbone.Collection(); - this.requestUrisCollection = new Backbone.Collection(); - this.postLogoutRedirectUrisCollection = new Backbone.Collection(); - this.claimsRedirectUrisCollection = new Backbone.Collection(); - // TODO: add Spring authorities collection and resource IDs collection? - - // collection of sub-views that need to be sync'd on save - this.listWidgetViews = []; - }, + if (!this.clientSavedTemplate) { + this.clientSavedTemplate = _.template($('#tmpl-client-saved').html()); + } - events:{ - "click .btn-save":"saveClient", - "click #allowRefresh" : "toggleRefreshTokenTimeout", - "click #disableAccessTokenTimeout" : function() { - $("#access-token-timeout-time", this.$el).prop('disabled',!$("#access-token-timeout-time", this.$el).prop('disabled')); - $("#access-token-timeout-unit", this.$el).prop('disabled',!$("#access-token-timeout-unit", this.$el).prop('disabled')); - document.getElementById("access-token-timeout-time").value = ''; - }, - "click #disableRefreshTokenTimeout" : function() { - $("#refresh-token-timeout-time", this.$el).prop('disabled',!$("#refresh-token-timeout-time", this.$el).prop('disabled')); - $("#refresh-token-timeout-unit", this.$el).prop('disabled',!$("#refresh-token-timeout-unit", this.$el).prop('disabled')); - document.getElementById("refresh-token-timeout-time").value = ''; - }, - "click .btn-cancel":"cancel", - "change #tokenEndpointAuthMethod input:radio":"toggleClientCredentials", - "change #displayClientSecret":"toggleDisplayClientSecret", - "change #generateClientSecret":"toggleGenerateClientSecret", - "change #logoUri input":"previewLogo", - "change #jwkSelector input:radio":"toggleJWKSetType" - }, + this.redirectUrisCollection = new Backbone.Collection(); + this.scopeCollection = new Backbone.Collection(); + this.contactsCollection = new Backbone.Collection(); + this.defaultACRvaluesCollection = new Backbone.Collection(); + this.requestUrisCollection = new Backbone.Collection(); + this.postLogoutRedirectUrisCollection = new Backbone.Collection(); + this.claimsRedirectUrisCollection = new Backbone.Collection(); + // TODO: add Spring authorities collection and resource IDs collection? - cancel:function(e) { - e.preventDefault(); - app.navigate('admin/clients', {trigger: true}); - }, - - load:function(callback) { - if (this.model.isFetched && - this.options.systemScopeList.isFetched) { - callback(); - return; - } - - $('#loadingbox').sheet('show'); - $('#loading').html( - '' + $.t('common.clients') + ' ' + - '' + $.t("common.scopes") + ' ' - ); - - $.when(this.options.systemScopeList.fetchIfNeeded({success:function(e) {$('#loading-scopes').addClass('label-success');}, error:app.errorHandlerView.handleError()}), - this.model.fetchIfNeeded({success:function(e) {$('#loading-clients').addClass('label-success');}, error:app.errorHandlerView.handleError()})) - .done(function() { - $('#loadingbox').sheet('hide'); - callback(); - }); + // collection of sub-views that need to be sync'd on save + this.listWidgetViews = []; }, - - toggleRefreshTokenTimeout:function () { - $("#refreshTokenValidityTime", this.$el).toggle(); - }, - - previewLogo:function() { - if ($('#logoUri input', this.el).val()) { - $('#logoPreview', this.el).empty(); - $('#logoPreview', this.el).attr('src', $('#logoUri input', this.el).val()); - } else { - //$('#logoBlock', this.el).hide(); - $('#logoPreview', this.el).attr('src', 'resources/images/logo_placeholder.gif'); - } - }, - /** - * Set up the form based on the current state of the tokenEndpointAuthMethod parameter - * @param event - */ - toggleClientCredentials:function() { - - var tokenEndpointAuthMethod = $('#tokenEndpointAuthMethod input', this.el).filter(':checked').val(); - - if (tokenEndpointAuthMethod == 'SECRET_BASIC' - || tokenEndpointAuthMethod == 'SECRET_POST' - || tokenEndpointAuthMethod == 'SECRET_JWT') { - - // client secret is required, show all the bits - $('#clientSecretPanel', this.el).show(); - // this function sets up the display portions - this.toggleGenerateClientSecret(); - } else { - // no client secret, hide all the bits - $('#clientSecretPanel', this.el).hide(); - } - - // show or hide the signing algorithm method depending on what's selected - if (tokenEndpointAuthMethod == 'PRIVATE_KEY' - || tokenEndpointAuthMethod == 'SECRET_JWT') { - $('#tokenEndpointAuthSigningAlg', this.el).show(); - } else { - $('#tokenEndpointAuthSigningAlg', this.el).hide(); - } - }, - - /** - * Set up the form based on the JWK Set selector - */ - toggleJWKSetType:function() { - var jwkSelector = $('#jwkSelector input:radio', this.el).filter(':checked').val(); - - if (jwkSelector == 'URI') { - $('#jwksUri', this.el).show(); - $('#jwks', this.el).hide(); - } else if (jwkSelector == 'VAL') { - $('#jwksUri', this.el).hide(); - $('#jwks', this.el).show(); - } else { - $('#jwksUri', this.el).hide(); - $('#jwks', this.el).hide(); - } - - }, - - /** - * Set up the form based on the "Generate" checkbox - * @param event - */ - toggleGenerateClientSecret:function() { + events: { + "click .btn-save": "saveClient", + "click #allowRefresh": "toggleRefreshTokenTimeout", + "click #disableAccessTokenTimeout": function() { + $("#access-token-timeout-time", this.$el).prop('disabled', !$("#access-token-timeout-time", this.$el).prop('disabled')); + $("#access-token-timeout-unit", this.$el).prop('disabled', !$("#access-token-timeout-unit", this.$el).prop('disabled')); + document.getElementById("access-token-timeout-time").value = ''; + }, + "click #disableRefreshTokenTimeout": function() { + $("#refresh-token-timeout-time", this.$el).prop('disabled', !$("#refresh-token-timeout-time", this.$el).prop('disabled')); + $("#refresh-token-timeout-unit", this.$el).prop('disabled', !$("#refresh-token-timeout-unit", this.$el).prop('disabled')); + document.getElementById("refresh-token-timeout-time").value = ''; + }, + "click .btn-cancel": "cancel", + "change #tokenEndpointAuthMethod input:radio": "toggleClientCredentials", + "change #displayClientSecret": "toggleDisplayClientSecret", + "change #generateClientSecret": "toggleGenerateClientSecret", + "change #logoUri input": "previewLogo", + "change #jwkSelector input:radio": "toggleJWKSetType" + }, - if ($('#generateClientSecret input', this.el).is(':checked')) { - // show the "generated" block, hide the "display" checkbox - $('#displayClientSecret', this.el).hide(); - $('#clientSecret', this.el).hide(); - $('#clientSecretGenerated', this.el).show(); - $('#clientSecretHidden', this.el).hide(); - } else { - // show the display checkbox, fall back to the "display" logic - $('#displayClientSecret', this.el).show(); - this.toggleDisplayClientSecret(); - } - }, - - /** - * Handle whether or not to display the client secret - * @param event - */ - toggleDisplayClientSecret:function() { + cancel: function(e) { + e.preventDefault(); + app.navigate('admin/clients', { + trigger: true + }); + }, - if ($('#displayClientSecret input').is(':checked')) { - // want to display it - $('#clientSecret', this.el).show(); - $('#clientSecretHidden', this.el).hide(); - $('#clientSecretGenerated', this.el).hide(); - } else { - // want to hide it - $('#clientSecret', this.el).hide(); - $('#clientSecretHidden', this.el).show(); - $('#clientSecretGenerated', this.el).hide(); - } - }, + load: function(callback) { + if (this.model.isFetched && this.options.systemScopeList.isFetched) { + callback(); + return; + } - // rounds down to the nearest integer value in seconds. - getFormTokenNumberValue:function(value, timeUnit) { - if (value == "") { - return null; - } else if (timeUnit == 'hours') { - return parseInt(parseFloat(value) * 3600); - } else if (timeUnit == 'minutes') { - return parseInt(parseFloat(value) * 60); - } else { // seconds - return parseInt(value); - } - }, - - // returns "null" if given the value "default" as a string, otherwise returns input value. useful for parsing the JOSE algorithm dropdowns - defaultToNull:function(value) { - if (value == 'default') { - return null; - } else { - return value; - } - }, - - // returns "null" if the given value is falsy - emptyToNull:function(value) { - if (value) { - return value; - } else { - return null; - } - }, - - disableUnsupportedJOSEItems:function(serverSupported, query) { - var supported = ['default']; - if (serverSupported) { - supported = _.union(supported, serverSupported); - } - $(query, this.$el).each(function(idx) { - if(_.contains(supported, $(this).val())) { - $(this).prop('disabled', false); - } else { - $(this).prop('disabled', true); - } - }); - - }, + $('#loadingbox').sheet('show'); + $('#loading').html('' + $.t('common.clients') + ' ' + '' + $.t("common.scopes") + ' '); - // maps from a form-friendly name to the real grant parameter name - grantMap:{ - 'authorization_code': 'authorization_code', - 'password': 'password', - 'implicit': 'implicit', - 'client_credentials': 'client_credentials', - 'redelegate': 'urn:ietf:params:oauth:grant_type:redelegate', - 'refresh_token': 'refresh_token', - 'device': 'urn:ietf:params:oauth:grant-type:device_code' - }, - - // maps from a form-friendly name to the real response type parameter name - responseMap:{ - 'code': 'code', - 'token': 'token', - 'idtoken': 'id_token', - 'token-idtoken': 'token id_token', - 'code-idtoken': 'code id_token', - 'code-token': 'code token', - 'code-token-idtoken': 'code token id_token' - }, - - saveClient:function (event) { + $.when(this.options.systemScopeList.fetchIfNeeded({ + success: function(e) { + $('#loading-scopes').addClass('label-success'); + }, + error: app.errorHandlerView.handleError() + }), this.model.fetchIfNeeded({ + success: function(e) { + $('#loading-clients').addClass('label-success'); + }, + error: app.errorHandlerView.handleError() + })).done(function() { + $('#loadingbox').sheet('hide'); + callback(); + }); + }, - $('.control-group').removeClass('error'); + toggleRefreshTokenTimeout: function() { + $("#refreshTokenValidityTime", this.$el).toggle(); + }, - // sync any leftover collection items - _.each(this.listWidgetViews, function(v) { - v.addItem($.Event('click')); - }); - - // build the scope object - var scopes = this.scopeCollection.pluck("item"); - - // build the grant type object - var grantTypes = []; - $.each(this.grantMap, function(index,type) { - if ($('#grantTypes-' + index).is(':checked')) { - grantTypes.push(type); - } - }); - - // build the response type object - var responseTypes = []; - $.each(this.responseMap, function(index,type) { - if ($('#responseTypes-' + index).is(':checked')) { - responseTypes.push(type); - } - }); + previewLogo: function() { + if ($('#logoUri input', this.el).val()) { + $('#logoPreview', this.el).empty(); + $('#logoPreview', this.el).attr('src', $('#logoUri input', this.el).val()); + } else { + // $('#logoBlock', this.el).hide(); + $('#logoPreview', this.el).attr('src', 'resources/images/logo_placeholder.gif'); + } + }, - var generateClientSecret = $('#generateClientSecret input').is(':checked'); - var clientSecret = null; - - var tokenEndpointAuthMethod = $('#tokenEndpointAuthMethod input').filter(':checked').val(); + /** + * Set up the form based on the current state of the tokenEndpointAuthMethod + * parameter + * + * @param event + */ + toggleClientCredentials: function() { - // whether or not the client secret changed - var secretChanged = false; - - if (tokenEndpointAuthMethod == 'SECRET_BASIC' - || tokenEndpointAuthMethod == 'SECRET_POST' - || tokenEndpointAuthMethod == 'SECRET_JWT') { - - if (!generateClientSecret) { - // if it's required but we're not generating it, send the value to preserve it - clientSecret = $('#clientSecret input').val(); - - // if it's not the same as before, offer to display it - if (clientSecret != this.model.get('clientSecret')) { - secretChanged = true; - } - } else { - // it's being generated anew - secretChanged = true; - } - } - - var accessTokenValiditySeconds = null; - if (!$('disableAccessTokenTimeout').is(':checked')) { - accessTokenValiditySeconds = this.getFormTokenNumberValue($('#accessTokenValidityTime input[type=text]').val(), $('#accessTokenValidityTime select').val()); - } - - var idTokenValiditySeconds = this.getFormTokenNumberValue($('#idTokenValidityTime input[type=text]').val(), $('#idTokenValidityTime select').val()); - - var deviceCodeValiditySeconds = this.getFormTokenNumberValue($('#deviceCodeValidityTime input[type=text]').val(), $('#deviceCodeValidityTime select').val()); - - var refreshTokenValiditySeconds = null; - if ($('#allowRefresh').is(':checked')) { + var tokenEndpointAuthMethod = $('#tokenEndpointAuthMethod input', this.el).filter(':checked').val(); - if ($.inArray('refresh_token', grantTypes) == -1) { - grantTypes.push('refresh_token'); - } + if (tokenEndpointAuthMethod == 'SECRET_BASIC' || tokenEndpointAuthMethod == 'SECRET_POST' || tokenEndpointAuthMethod == 'SECRET_JWT') { - if ($.inArray('offline_access', scopes) == -1) { - scopes.push("offline_access"); - } + // client secret is required, show all the bits + $('#clientSecretPanel', this.el).show(); + // this function sets up the display portions + this.toggleGenerateClientSecret(); + } else { + // no client secret, hide all the bits + $('#clientSecretPanel', this.el).hide(); + } - if (!$('disableRefreshTokenTimeout').is(':checked')) { - refreshTokenValiditySeconds = this.getFormTokenNumberValue($('#refreshTokenValidityTime input[type=text]').val(), $('#refreshTokenValidityTime select').val()); - } - } - - // make sure that the subject identifier is consistent with the redirect URIs - var subjectType = $('#subjectType input').filter(':checked').val(); - var redirectUris = this.redirectUrisCollection.pluck("item"); - var sectorIdentifierUri = $('#sectorIdentifierUri input').val(); - if (subjectType == 'PAIRWISE' && redirectUris.length > 1 && sectorIdentifierUri == '') { - //Display an alert with an error message - app.errorHandlerView.showErrorMessage($.t("client.client-form.error.consistency"), $.t("client.client-form.error.pairwise-sector")); + // show or hide the signing algorithm method depending on what's + // selected + if (tokenEndpointAuthMethod == 'PRIVATE_KEY' || tokenEndpointAuthMethod == 'SECRET_JWT') { + $('#tokenEndpointAuthSigningAlg', this.el).show(); + } else { + $('#tokenEndpointAuthSigningAlg', this.el).hide(); + } + }, + + /** + * Set up the form based on the JWK Set selector + */ + toggleJWKSetType: function() { + var jwkSelector = $('#jwkSelector input:radio', this.el).filter(':checked').val(); + + if (jwkSelector == 'URI') { + $('#jwksUri', this.el).show(); + $('#jwks', this.el).hide(); + } else if (jwkSelector == 'VAL') { + $('#jwksUri', this.el).hide(); + $('#jwks', this.el).show(); + } else { + $('#jwksUri', this.el).hide(); + $('#jwks', this.el).hide(); + } + + }, + + /** + * Set up the form based on the "Generate" checkbox + * + * @param event + */ + toggleGenerateClientSecret: function() { + + if ($('#generateClientSecret input', this.el).is(':checked')) { + // show the "generated" block, hide the "display" checkbox + $('#displayClientSecret', this.el).hide(); + $('#clientSecret', this.el).hide(); + $('#clientSecretGenerated', this.el).show(); + $('#clientSecretHidden', this.el).hide(); + } else { + // show the display checkbox, fall back to the "display" logic + $('#displayClientSecret', this.el).show(); + this.toggleDisplayClientSecret(); + } + }, + + /** + * Handle whether or not to display the client secret + * + * @param event + */ + toggleDisplayClientSecret: function() { + + if ($('#displayClientSecret input').is(':checked')) { + // want to display it + $('#clientSecret', this.el).show(); + $('#clientSecretHidden', this.el).hide(); + $('#clientSecretGenerated', this.el).hide(); + } else { + // want to hide it + $('#clientSecret', this.el).hide(); + $('#clientSecretHidden', this.el).show(); + $('#clientSecretGenerated', this.el).hide(); + } + }, + + // rounds down to the nearest integer value in seconds. + getFormTokenNumberValue: function(value, timeUnit) { + if (value == "") { + return null; + } else if (timeUnit == 'hours') { + return parseInt(parseFloat(value) * 3600); + } else if (timeUnit == 'minutes') { + return parseInt(parseFloat(value) * 60); + } else { // seconds + return parseInt(value); + } + }, + + // returns "null" if given the value "default" as a string, otherwise + // returns input value. useful for parsing the JOSE algorithm dropdowns + defaultToNull: function(value) { + if (value == 'default') { + return null; + } else { + return value; + } + }, + + // returns "null" if the given value is falsy + emptyToNull: function(value) { + if (value) { + return value; + } else { + return null; + } + }, + + disableUnsupportedJOSEItems: function(serverSupported, query) { + var supported = ['default']; + if (serverSupported) { + supported = _.union(supported, serverSupported); + } + $(query, this.$el).each(function(idx) { + if (_.contains(supported, $(this).val())) { + $(this).prop('disabled', false); + } else { + $(this).prop('disabled', true); + } + }); + + }, + + // maps from a form-friendly name to the real grant parameter name + grantMap: { + 'authorization_code': 'authorization_code', + 'password': 'password', + 'implicit': 'implicit', + 'client_credentials': 'client_credentials', + 'redelegate': 'urn:ietf:params:oauth:grant_type:redelegate', + 'refresh_token': 'refresh_token', + 'device': 'urn:ietf:params:oauth:grant-type:device_code' + }, + + // maps from a form-friendly name to the real response type parameter name + responseMap: { + 'code': 'code', + 'token': 'token', + 'idtoken': 'id_token', + 'token-idtoken': 'token id_token', + 'code-idtoken': 'code id_token', + 'code-token': 'code token', + 'code-token-idtoken': 'code token id_token' + }, + + saveClient: function(event) { + + $('.control-group').removeClass('error'); + + // sync any leftover collection items + _.each(this.listWidgetViews, function(v) { + v.addItem($.Event('click')); + }); + + // build the scope object + var scopes = this.scopeCollection.pluck("item"); + + // build the grant type object + var grantTypes = []; + $.each(this.grantMap, function(index, type) { + if ($('#grantTypes-' + index).is(':checked')) { + grantTypes.push(type); + } + }); + + // build the response type object + var responseTypes = []; + $.each(this.responseMap, function(index, type) { + if ($('#responseTypes-' + index).is(':checked')) { + responseTypes.push(type); + } + }); + + var generateClientSecret = $('#generateClientSecret input').is(':checked'); + var clientSecret = null; + + var tokenEndpointAuthMethod = $('#tokenEndpointAuthMethod input').filter(':checked').val(); + + // whether or not the client secret changed + var secretChanged = false; + + if (tokenEndpointAuthMethod == 'SECRET_BASIC' || tokenEndpointAuthMethod == 'SECRET_POST' || tokenEndpointAuthMethod == 'SECRET_JWT') { + + if (!generateClientSecret) { + // if it's required but we're not generating it, send the value + // to preserve it + clientSecret = $('#clientSecret input').val(); + + // if it's not the same as before, offer to display it + if (clientSecret != this.model.get('clientSecret')) { + secretChanged = true; + } + } else { + // it's being generated anew + secretChanged = true; + } + } + + var accessTokenValiditySeconds = null; + if (!$('disableAccessTokenTimeout').is(':checked')) { + accessTokenValiditySeconds = this.getFormTokenNumberValue($('#accessTokenValidityTime input[type=text]').val(), $('#accessTokenValidityTime select').val()); + } + + var idTokenValiditySeconds = this.getFormTokenNumberValue($('#idTokenValidityTime input[type=text]').val(), $('#idTokenValidityTime select').val()); + + var deviceCodeValiditySeconds = this.getFormTokenNumberValue($('#deviceCodeValidityTime input[type=text]').val(), $('#deviceCodeValidityTime select').val()); + + var refreshTokenValiditySeconds = null; + if ($('#allowRefresh').is(':checked')) { + + if ($.inArray('refresh_token', grantTypes) == -1) { + grantTypes.push('refresh_token'); + } + + if ($.inArray('offline_access', scopes) == -1) { + scopes.push("offline_access"); + } + + if (!$('disableRefreshTokenTimeout').is(':checked')) { + refreshTokenValiditySeconds = this.getFormTokenNumberValue($('#refreshTokenValidityTime input[type=text]').val(), $('#refreshTokenValidityTime select').val()); + } + } + + // make sure that the subject identifier is consistent with the redirect + // URIs + var subjectType = $('#subjectType input').filter(':checked').val(); + var redirectUris = this.redirectUrisCollection.pluck("item"); + var sectorIdentifierUri = $('#sectorIdentifierUri input').val(); + if (subjectType == 'PAIRWISE' && redirectUris.length > 1 && sectorIdentifierUri == '') { + // Display an alert with an error message + app.errorHandlerView.showErrorMessage($.t("client.client-form.error.consistency"), $.t("client.client-form.error.pairwise-sector")); return false; - - } - - // process the JWKS - var jwksUri = null; - var jwks = null; - var jwkSelector = $('#jwkSelector input:radio', this.el).filter(':checked').val(); - - if (jwkSelector == 'URI') { - jwksUri = $('#jwksUri input').val(); - jwks = null; - } else if (jwkSelector == 'VAL') { - jwksUri = null; - try { - jwks = JSON.parse($('#jwks textarea').val()); - } catch (e) { - console.log("An error occurred when parsing the JWK Set"); - app.errorHandlerView.showErrorMessage($.t("client.client-form.error.jwk-set"), $.t("client.client-form.error.jwk-set-parse")); - return false; - } - } else { - jwksUri = null; - jwks = null; - } - - - - var attrs = { - clientName:this.emptyToNull($('#clientName input').val()), - clientId:this.emptyToNull($('#clientId input').val()), - clientSecret: clientSecret, - generateClientSecret:generateClientSecret, - redirectUris: redirectUris, - clientDescription:this.emptyToNull($('#clientDescription textarea').val()), - logoUri:this.emptyToNull($('#logoUri input').val()), - grantTypes: grantTypes, - accessTokenValiditySeconds: accessTokenValiditySeconds, - refreshTokenValiditySeconds: refreshTokenValiditySeconds, - idTokenValiditySeconds: idTokenValiditySeconds, - deviceCodeValiditySeconds: deviceCodeValiditySeconds, - allowRefresh: $('#allowRefresh').is(':checked'), - allowIntrospection: $('#allowIntrospection input').is(':checked'), - scope: scopes, - tosUri: this.emptyToNull($('#tosUri input').val()), - policyUri: this.emptyToNull($('#policyUri input').val()), - clientUri: this.emptyToNull($('#clientUri input').val()), - applicationType: $('#applicationType input').filter(':checked').val(), - jwksUri: jwksUri, - jwks: jwks, - subjectType: subjectType, - softwareStatement: this.emptyToNull($('#softwareStatement textarea').val()), - softwareId: this.emptyToNull($('#softwareId input').val()), - softwareVersion: this.emptyToNull($('#softwareVersion input').val()), - tokenEndpointAuthMethod: tokenEndpointAuthMethod, - responseTypes: responseTypes, - sectorIdentifierUri: sectorIdentifierUri, - initiateLoginUri: this.emptyToNull($('#initiateLoginUri input').val()), - postLogoutRedirectUris: this.postLogoutRedirectUrisCollection.pluck('item'), - claimsRedirectUris: this.claimsRedirectUrisCollection.pluck('item'), - reuseRefreshToken: $('#reuseRefreshToken').is(':checked'), - clearAccessTokensOnRefresh: $('#clearAccessTokensOnRefresh').is(':checked'), - requireAuthTime: $('#requireAuthTime input').is(':checked'), - defaultMaxAge: parseInt($('#defaultMaxAge input').val()), - contacts: this.contactsCollection.pluck('item'), - requestUris: this.requestUrisCollection.pluck('item'), - defaultACRvalues: this.defaultACRvaluesCollection.pluck('item'), - requestObjectSigningAlg: this.defaultToNull($('#requestObjectSigningAlg select').val()), - userInfoSignedResponseAlg: this.defaultToNull($('#userInfoSignedResponseAlg select').val()), - userInfoEncryptedResponseAlg: this.defaultToNull($('#userInfoEncryptedResponseAlg select').val()), - userInfoEncryptedResponseEnc: this.defaultToNull($('#userInfoEncryptedResponseEnc select').val()), - idTokenSignedResponseAlg: this.defaultToNull($('#idTokenSignedResponseAlg select').val()), - idTokenEncryptedResponseAlg: this.defaultToNull($('#idTokenEncryptedResponseAlg select').val()), - idTokenEncryptedResponseEnc: this.defaultToNull($('#idTokenEncryptedResponseEnc select').val()), - tokenEndpointAuthSigningAlg: this.defaultToNull($('#tokenEndpointAuthSigningAlg select').val()), - codeChallengeMethod: this.defaultToNull($('#codeChallengeMethod select').val()) - }; - // post-validate - if (attrs["allowRefresh"] == false) { - attrs["refreshTokenValiditySeconds"] = null; - } + } - if ($('#disableAccessTokenTimeout').is(':checked')) { - attrs["accessTokenValiditySeconds"] = null; - } + // process the JWKS + var jwksUri = null; + var jwks = null; + var jwkSelector = $('#jwkSelector input:radio', this.el).filter(':checked').val(); - if ($('#disableRefreshTokenTimeout').is(':checked')) { - attrs["refreshTokenValiditySeconds"] = null; - } + if (jwkSelector == 'URI') { + jwksUri = $('#jwksUri input').val(); + jwks = null; + } else if (jwkSelector == 'VAL') { + jwksUri = null; + try { + jwks = JSON.parse($('#jwks textarea').val()); + } catch (e) { + console.log("An error occurred when parsing the JWK Set"); + app.errorHandlerView.showErrorMessage($.t("client.client-form.error.jwk-set"), $.t("client.client-form.error.jwk-set-parse")); + return false; + } + } else { + jwksUri = null; + jwks = null; + } - // set all empty strings to nulls - for (var key in attrs) { - if (attrs[key] === "") { - attrs[key] = null; - } - } - - var _self = this; - this.model.save(attrs, { - success:function () { + var attrs = { + clientName: this.emptyToNull($('#clientName input').val()), + clientId: this.emptyToNull($('#clientId input').val()), + clientSecret: clientSecret, + generateClientSecret: generateClientSecret, + redirectUris: redirectUris, + clientDescription: this.emptyToNull($('#clientDescription textarea').val()), + logoUri: this.emptyToNull($('#logoUri input').val()), + grantTypes: grantTypes, + accessTokenValiditySeconds: accessTokenValiditySeconds, + refreshTokenValiditySeconds: refreshTokenValiditySeconds, + idTokenValiditySeconds: idTokenValiditySeconds, + deviceCodeValiditySeconds: deviceCodeValiditySeconds, + allowRefresh: $('#allowRefresh').is(':checked'), + allowIntrospection: $('#allowIntrospection input').is(':checked'), + scope: scopes, + tosUri: this.emptyToNull($('#tosUri input').val()), + policyUri: this.emptyToNull($('#policyUri input').val()), + clientUri: this.emptyToNull($('#clientUri input').val()), + applicationType: $('#applicationType input').filter(':checked').val(), + jwksUri: jwksUri, + jwks: jwks, + subjectType: subjectType, + softwareStatement: this.emptyToNull($('#softwareStatement textarea').val()), + softwareId: this.emptyToNull($('#softwareId input').val()), + softwareVersion: this.emptyToNull($('#softwareVersion input').val()), + tokenEndpointAuthMethod: tokenEndpointAuthMethod, + responseTypes: responseTypes, + sectorIdentifierUri: sectorIdentifierUri, + initiateLoginUri: this.emptyToNull($('#initiateLoginUri input').val()), + postLogoutRedirectUris: this.postLogoutRedirectUrisCollection.pluck('item'), + claimsRedirectUris: this.claimsRedirectUrisCollection.pluck('item'), + reuseRefreshToken: $('#reuseRefreshToken').is(':checked'), + clearAccessTokensOnRefresh: $('#clearAccessTokensOnRefresh').is(':checked'), + requireAuthTime: $('#requireAuthTime input').is(':checked'), + defaultMaxAge: parseInt($('#defaultMaxAge input').val()), + contacts: this.contactsCollection.pluck('item'), + requestUris: this.requestUrisCollection.pluck('item'), + defaultACRvalues: this.defaultACRvaluesCollection.pluck('item'), + requestObjectSigningAlg: this.defaultToNull($('#requestObjectSigningAlg select').val()), + userInfoSignedResponseAlg: this.defaultToNull($('#userInfoSignedResponseAlg select').val()), + userInfoEncryptedResponseAlg: this.defaultToNull($('#userInfoEncryptedResponseAlg select').val()), + userInfoEncryptedResponseEnc: this.defaultToNull($('#userInfoEncryptedResponseEnc select').val()), + idTokenSignedResponseAlg: this.defaultToNull($('#idTokenSignedResponseAlg select').val()), + idTokenEncryptedResponseAlg: this.defaultToNull($('#idTokenEncryptedResponseAlg select').val()), + idTokenEncryptedResponseEnc: this.defaultToNull($('#idTokenEncryptedResponseEnc select').val()), + tokenEndpointAuthSigningAlg: this.defaultToNull($('#tokenEndpointAuthSigningAlg select').val()), + codeChallengeMethod: this.defaultToNull($('#codeChallengeMethod select').val()) + }; - $('#modalAlertLabel').html($.t('client.client-form.saved.saved')); - - var savedModel = { - clientId: _self.model.get('clientId'), - clientSecret: _self.model.get('clientSecret'), - secretChanged: secretChanged - }; - - $('#modalAlert div.modal-header').html($.t('client.client-form.saved.saved')); - - $('#modalAlert .modal-body').html(_self.clientSavedTemplate(savedModel)); - - $('#modalAlert .modal-body #savedClientSecret').hide(); - - $('#modalAlert').on('click', '#clientSaveShow', function(event) { - event.preventDefault(); - $('#clientSaveShow').hide(); - $('#savedClientSecret').show(); - }); - - $('#modalAlert').i18n(); - $('#modalAlert').modal({ - 'backdrop': 'static', - 'keyboard': true, - 'show': true - }); - - app.clientList.add(_self.model); - app.navigate('admin/clients', {trigger:true}); - }, - error:app.errorHandlerView.handleError({log: "An error occurred when saving a client"}) - }); + // post-validate + if (attrs["allowRefresh"] == false) { + attrs["refreshTokenValiditySeconds"] = null; + } - return false; - }, + if ($('#disableAccessTokenTimeout').is(':checked')) { + attrs["accessTokenValiditySeconds"] = null; + } - render:function (eventName) { - - var data = {client: this.model.toJSON(), heartMode: heartMode}; - $(this.el).html(this.template(data)); - - var _self = this; + if ($('#disableRefreshTokenTimeout').is(':checked')) { + attrs["refreshTokenValiditySeconds"] = null; + } - // clear the sub-view collection - this.listWidgetViews = []; - - // build and bind registered redirect URI collection and view - _.each(this.model.get("redirectUris"), function (redirectUri) { - _self.redirectUrisCollection.add(new URIModel({item:redirectUri})); - }); + // set all empty strings to nulls + for ( var key in attrs) { + if (attrs[key] === "") { + attrs[key] = null; + } + } - - var redirUriView = new ListWidgetView({ - type:'uri', - placeholder: 'https://', - helpBlockText: $.t('client.client-form.redirect-uris-help'), - collection: this.redirectUrisCollection}); - $("#redirectUris .controls",this.el).html(redirUriView.render().el); - this.listWidgetViews.push(redirUriView); - - // build and bind scopes - _.each(this.model.get("scope"), function (scope) { - _self.scopeCollection.add(new Backbone.Model({item:scope})); - }); + var _self = this; + this.model.save(attrs, { + success: function() { - var scopeView = new ListWidgetView({ - placeholder: $.t('client.client-form.scope-placeholder'), - autocomplete: _.uniq(_.flatten(this.options.systemScopeList.pluck("value"))), - helpBlockText: $.t('client.client-form.scope-help'), - collection: this.scopeCollection}); - $("#scope .controls",this.el).html(scopeView.render().el); - this.listWidgetViews.push(scopeView); + $('#modalAlertLabel').html($.t('client.client-form.saved.saved')); - // build and bind contacts - _.each(this.model.get('contacts'), function (contact) { - _self.contactsCollection.add(new Backbone.Model({item:contact})); - }); - - var contactsView = new ListWidgetView({ - placeholder: $.t("client.client-form.contacts-placeholder"), - helpBlockText: $.t("client.client-form.contacts-help"), - collection: this.contactsCollection}); - $("#contacts .controls", this.el).html(contactsView.render().el); - this.listWidgetViews.push(contactsView); - - // build and bind post-logout redirect URIs - _.each(this.model.get('postLogoutRedirectUris'), function(postLogoutRedirectUri) { - _self.postLogoutRedirectUrisCollection.add(new URIModel({item:postLogoutRedirectUri})); - }); - - var postLogoutRedirectUrisView = new ListWidgetView({ - type: 'uri', - placeholder: 'https://', - helpBlockText: $.t('client.client-form.post-logout-help'), - collection: this.postLogoutRedirectUrisCollection}); - $('#postLogoutRedirectUris .controls', this.el).html(postLogoutRedirectUrisView.render().el); - this.listWidgetViews.push(postLogoutRedirectUrisView); - - // build and bind claims redirect URIs - _.each(this.model.get('claimsRedirectUris'), function(claimsRedirectUri) { - _self.claimsRedirectUrisCollection.add(new URIModel({item:claimsRedirectUri})); - }); - - var claimsRedirectUrisView = new ListWidgetView({ - type: 'uri', - placeholder: 'https://', - helpBlockText: $.t('client.client-form.claims-redirect-uris-help'), - collection: this.claimsRedirectUrisCollection}); - $('#claimsRedirectUris .controls', this.el).html(claimsRedirectUrisView.render().el); - this.listWidgetViews.push(claimsRedirectUrisView); - - // build and bind request URIs - _.each(this.model.get('requestUris'), function (requestUri) { - _self.requestUrisCollection.add(new URIModel({item:requestUri})); - }); - - var requestUriView = new ListWidgetView({ - type: 'uri', - placeholder: 'https://', - helpBlockText: $.t('client.client-form.request-uri-help'), - collection: this.requestUrisCollection}); - $('#requestUris .controls', this.el).html(requestUriView.render().el); - this.listWidgetViews.push(requestUriView); - - // build and bind default ACR values - _.each(this.model.get('defaultACRvalues'), function (defaultACRvalue) { - _self.defaultACRvaluesCollection.add(new Backbone.Model({item:defaultACRvalue})); - }); - - var defaultAcrView = new ListWidgetView({ - placeholder: $.t('client.client-form.acr-values-placeholder'), - // TODO: autocomplete from spec - helpBlockText: $.t('client.client-form.acr-values-help'), - collection: this.defaultACRvaluesCollection}); - $('#defaultAcrValues .controls', this.el).html(defaultAcrView.render().el); - this.listWidgetViews.push(defaultAcrView); - - // build and bind - - // set up token fields - if (!this.model.get("allowRefresh")) { - $("#refreshTokenValidityTime", this.$el).hide(); - } + var savedModel = { + clientId: _self.model.get('clientId'), + clientSecret: _self.model.get('clientSecret'), + secretChanged: secretChanged + }; - if (this.model.get("accessTokenValiditySeconds") == null) { - $("#access-token-timeout-time", this.$el).prop('disabled',true); - $("#access-token-timeout-unit", this.$el).prop('disabled',true); - } + $('#modalAlert div.modal-header').html($.t('client.client-form.saved.saved')); - if (this.model.get("refreshTokenValiditySeconds") == null) { - $("#refresh-token-timeout-time", this.$el).prop('disabled',true); - $("#refresh-token-timeout-unit", this.$el).prop('disabled',true); - } - - // toggle other dynamic fields - this.toggleClientCredentials(); - this.previewLogo(); - this.toggleJWKSetType(); - - // disable unsupported JOSE algorithms - this.disableUnsupportedJOSEItems(app.serverConfiguration.request_object_signing_alg_values_supported, '#requestObjectSigningAlg option'); - this.disableUnsupportedJOSEItems(app.serverConfiguration.userinfo_signing_alg_values_supported, '#userInfoSignedResponseAlg option'); - this.disableUnsupportedJOSEItems(app.serverConfiguration.userinfo_encryption_alg_values_supported, '#userInfoEncryptedResponseAlg option'); - this.disableUnsupportedJOSEItems(app.serverConfiguration.userinfo_encryption_enc_values_supported, '#userInfoEncryptedResponseEnc option'); - this.disableUnsupportedJOSEItems(app.serverConfiguration.id_token_signing_alg_values_supported, '#idTokenSignedResponseAlg option'); - this.disableUnsupportedJOSEItems(app.serverConfiguration.id_token_encryption_alg_values_supported, '#idTokenEncryptedResponseAlg option'); - this.disableUnsupportedJOSEItems(app.serverConfiguration.id_token_encryption_enc_values_supported, '#idTokenEncryptedResponseEnc option'); - this.disableUnsupportedJOSEItems(app.serverConfiguration.token_endpoint_auth_signing_alg_values_supported, '#tokenEndpointAuthSigningAlg option'); - - this.$('.nyi').clickover({ - placement: 'right', - title: $.t('common.not-yet-implemented'), - content: $.t('common.not-yet-implemented-content') - }); - - $(this.el).i18n(); - return this; - } + $('#modalAlert .modal-body').html(_self.clientSavedTemplate(savedModel)); + + $('#modalAlert .modal-body #savedClientSecret').hide(); + + $('#modalAlert').on('click', '#clientSaveShow', function(event) { + event.preventDefault(); + $('#clientSaveShow').hide(); + $('#savedClientSecret').show(); + }); + + $('#modalAlert').i18n(); + $('#modalAlert').modal({ + 'backdrop': 'static', + 'keyboard': true, + 'show': true + }); + + app.clientList.add(_self.model); + app.navigate('admin/clients', { + trigger: true + }); + }, + error: app.errorHandlerView.handleError({ + log: "An error occurred when saving a client" + }) + }); + + return false; + }, + + render: function(eventName) { + + var data = { + client: this.model.toJSON(), + heartMode: heartMode + }; + $(this.el).html(this.template(data)); + + var _self = this; + + // clear the sub-view collection + this.listWidgetViews = []; + + // build and bind registered redirect URI collection and view + _.each(this.model.get("redirectUris"), function(redirectUri) { + _self.redirectUrisCollection.add(new URIModel({ + item: redirectUri + })); + }); + + var redirUriView = new ListWidgetView({ + type: 'uri', + placeholder: 'https://', + helpBlockText: $.t('client.client-form.redirect-uris-help'), + collection: this.redirectUrisCollection + }); + $("#redirectUris .controls", this.el).html(redirUriView.render().el); + this.listWidgetViews.push(redirUriView); + + // build and bind scopes + _.each(this.model.get("scope"), function(scope) { + _self.scopeCollection.add(new Backbone.Model({ + item: scope + })); + }); + + var scopeView = new ListWidgetView({ + placeholder: $.t('client.client-form.scope-placeholder'), + autocomplete: _.uniq(_.flatten(this.options.systemScopeList.pluck("value"))), + helpBlockText: $.t('client.client-form.scope-help'), + collection: this.scopeCollection + }); + $("#scope .controls", this.el).html(scopeView.render().el); + this.listWidgetViews.push(scopeView); + + // build and bind contacts + _.each(this.model.get('contacts'), function(contact) { + _self.contactsCollection.add(new Backbone.Model({ + item: contact + })); + }); + + var contactsView = new ListWidgetView({ + placeholder: $.t("client.client-form.contacts-placeholder"), + helpBlockText: $.t("client.client-form.contacts-help"), + collection: this.contactsCollection + }); + $("#contacts .controls", this.el).html(contactsView.render().el); + this.listWidgetViews.push(contactsView); + + // build and bind post-logout redirect URIs + _.each(this.model.get('postLogoutRedirectUris'), function(postLogoutRedirectUri) { + _self.postLogoutRedirectUrisCollection.add(new URIModel({ + item: postLogoutRedirectUri + })); + }); + + var postLogoutRedirectUrisView = new ListWidgetView({ + type: 'uri', + placeholder: 'https://', + helpBlockText: $.t('client.client-form.post-logout-help'), + collection: this.postLogoutRedirectUrisCollection + }); + $('#postLogoutRedirectUris .controls', this.el).html(postLogoutRedirectUrisView.render().el); + this.listWidgetViews.push(postLogoutRedirectUrisView); + + // build and bind claims redirect URIs + _.each(this.model.get('claimsRedirectUris'), function(claimsRedirectUri) { + _self.claimsRedirectUrisCollection.add(new URIModel({ + item: claimsRedirectUri + })); + }); + + var claimsRedirectUrisView = new ListWidgetView({ + type: 'uri', + placeholder: 'https://', + helpBlockText: $.t('client.client-form.claims-redirect-uris-help'), + collection: this.claimsRedirectUrisCollection + }); + $('#claimsRedirectUris .controls', this.el).html(claimsRedirectUrisView.render().el); + this.listWidgetViews.push(claimsRedirectUrisView); + + // build and bind request URIs + _.each(this.model.get('requestUris'), function(requestUri) { + _self.requestUrisCollection.add(new URIModel({ + item: requestUri + })); + }); + + var requestUriView = new ListWidgetView({ + type: 'uri', + placeholder: 'https://', + helpBlockText: $.t('client.client-form.request-uri-help'), + collection: this.requestUrisCollection + }); + $('#requestUris .controls', this.el).html(requestUriView.render().el); + this.listWidgetViews.push(requestUriView); + + // build and bind default ACR values + _.each(this.model.get('defaultACRvalues'), function(defaultACRvalue) { + _self.defaultACRvaluesCollection.add(new Backbone.Model({ + item: defaultACRvalue + })); + }); + + var defaultAcrView = new ListWidgetView({ + placeholder: $.t('client.client-form.acr-values-placeholder'), + // TODO: autocomplete from spec + helpBlockText: $.t('client.client-form.acr-values-help'), + collection: this.defaultACRvaluesCollection + }); + $('#defaultAcrValues .controls', this.el).html(defaultAcrView.render().el); + this.listWidgetViews.push(defaultAcrView); + + // build and bind + + // set up token fields + if (!this.model.get("allowRefresh")) { + $("#refreshTokenValidityTime", this.$el).hide(); + } + + if (this.model.get("accessTokenValiditySeconds") == null) { + $("#access-token-timeout-time", this.$el).prop('disabled', true); + $("#access-token-timeout-unit", this.$el).prop('disabled', true); + } + + if (this.model.get("refreshTokenValiditySeconds") == null) { + $("#refresh-token-timeout-time", this.$el).prop('disabled', true); + $("#refresh-token-timeout-unit", this.$el).prop('disabled', true); + } + + // toggle other dynamic fields + this.toggleClientCredentials(); + this.previewLogo(); + this.toggleJWKSetType(); + + // disable unsupported JOSE algorithms + this.disableUnsupportedJOSEItems(app.serverConfiguration.request_object_signing_alg_values_supported, '#requestObjectSigningAlg option'); + this.disableUnsupportedJOSEItems(app.serverConfiguration.userinfo_signing_alg_values_supported, '#userInfoSignedResponseAlg option'); + this.disableUnsupportedJOSEItems(app.serverConfiguration.userinfo_encryption_alg_values_supported, '#userInfoEncryptedResponseAlg option'); + this.disableUnsupportedJOSEItems(app.serverConfiguration.userinfo_encryption_enc_values_supported, '#userInfoEncryptedResponseEnc option'); + this.disableUnsupportedJOSEItems(app.serverConfiguration.id_token_signing_alg_values_supported, '#idTokenSignedResponseAlg option'); + this.disableUnsupportedJOSEItems(app.serverConfiguration.id_token_encryption_alg_values_supported, '#idTokenEncryptedResponseAlg option'); + this.disableUnsupportedJOSEItems(app.serverConfiguration.id_token_encryption_enc_values_supported, '#idTokenEncryptedResponseEnc option'); + this.disableUnsupportedJOSEItems(app.serverConfiguration.token_endpoint_auth_signing_alg_values_supported, '#tokenEndpointAuthSigningAlg option'); + + this.$('.nyi').clickover({ + placement: 'right', + title: $.t('common.not-yet-implemented'), + content: $.t('common.not-yet-implemented-content') + }); + + $(this.el).i18n(); + return this; + } }); +ui.routes.push({ + path: "admin/clients", + name: "listClients", + callback: function() { -ui.routes.push({path: "admin/clients", name: "listClients", callback: - function () { + if (!isAdmin()) { + this.root(); + return; + } - if (!isAdmin()) { - this.root(); - return; - } - - this.breadCrumbView.collection.reset(); - this.breadCrumbView.collection.add([ - {text:$.t('admin.home'), href:""}, - {text:$.t('client.manage'), href:"manage/#admin/clients"} - ]); - - this.updateSidebar('admin/clients'); + this.breadCrumbView.collection.reset(); + this.breadCrumbView.collection.add([{ + text: $.t('admin.home'), + href: "" + }, { + text: $.t('client.manage'), + href: "manage/#admin/clients" + }]); - var view = new ClientListView({model:this.clientList, systemScopeList: this.systemScopeList, whiteListList: this.whiteListList}); - view.load(function() { - $('#content').html(view.render().el); - view.delegateEvents(); - setPageTitle($.t('client.manage')); - }); + this.updateSidebar('admin/clients'); - } + var view = new ClientListView({ + model: this.clientList, + systemScopeList: this.systemScopeList, + whiteListList: this.whiteListList + }); + view.load(function() { + $('#content').html(view.render().el); + view.delegateEvents(); + setPageTitle($.t('client.manage')); + }); + + } }); -ui.routes.push({path: "admin/client/new", name: "newClient", callback: - function() { +ui.routes.push({ + path: "admin/client/new", + name: "newClient", + callback: function() { console.log("newClient"); if (!isAdmin()) { this.root(); return; } - - this.breadCrumbView.collection.reset(); - this.breadCrumbView.collection.add([ - {text:$.t('admin.home'), href:""}, - {text:$.t('client.manage'), href:"manage/#admin/clients"}, - {text:$.t('client.client-form.new'), href:""} - ]); - - this.updateSidebar('admin/clients'); - - var client = new ClientModel(); - - var view = new ClientFormView({model:client, systemScopeList: this.systemScopeList}); - view.load(function() { + + this.breadCrumbView.collection.reset(); + this.breadCrumbView.collection.add([{ + text: $.t('admin.home'), + href: "" + }, { + text: $.t('client.manage'), + href: "manage/#admin/clients" + }, { + text: $.t('client.client-form.new'), + href: "" + }]); + + this.updateSidebar('admin/clients'); + + var client = new ClientModel(); + + var view = new ClientFormView({ + model: client, + systemScopeList: this.systemScopeList + }); + view.load(function() { var userInfo = getUserInfo(); var contacts = []; if (userInfo != null && userInfo.email != null) { contacts.push(userInfo.email); } - + // use a different set of defaults based on heart mode flag if (heartMode) { - client.set({ - tokenEndpointAuthMethod: "PRIVATE_KEY", - generateClientSecret:false, - displayClientSecret:false, - requireAuthTime:true, - defaultMaxAge:60000, - scope: _.uniq(_.flatten(app.systemScopeList.defaultScopes().pluck("value"))), - accessTokenValiditySeconds:3600, - refreshTokenValiditySeconds:24*3600, - idTokenValiditySeconds:300, - deviceCodeValiditySeconds:30*60, - grantTypes: ["authorization_code"], - responseTypes: ["code"], - subjectType: "PUBLIC", - jwksType: "URI", - contacts: contacts - }, { silent: true }); + client.set({ + tokenEndpointAuthMethod: "PRIVATE_KEY", + generateClientSecret: false, + displayClientSecret: false, + requireAuthTime: true, + defaultMaxAge: 60000, + scope: _.uniq(_.flatten(app.systemScopeList.defaultScopes().pluck("value"))), + accessTokenValiditySeconds: 3600, + refreshTokenValiditySeconds: 24 * 3600, + idTokenValiditySeconds: 300, + deviceCodeValiditySeconds: 30 * 60, + grantTypes: ["authorization_code"], + responseTypes: ["code"], + subjectType: "PUBLIC", + jwksType: "URI", + contacts: contacts + }, { + silent: true + }); } else { - // set up this new client to require a secret and have us autogenerate one - client.set({ - tokenEndpointAuthMethod: "SECRET_BASIC", - generateClientSecret:true, - displayClientSecret:false, - requireAuthTime:true, - defaultMaxAge:60000, - scope: _.uniq(_.flatten(app.systemScopeList.defaultScopes().pluck("value"))), - accessTokenValiditySeconds:3600, - idTokenValiditySeconds:600, - deviceCodeValiditySeconds:30*60, - grantTypes: ["authorization_code"], - responseTypes: ["code"], - subjectType: "PUBLIC", - jwksType: "URI", - contacts: contacts - }, { silent: true }); + // set up this new client to require a secret and have us + // autogenerate one + client.set({ + tokenEndpointAuthMethod: "SECRET_BASIC", + generateClientSecret: true, + displayClientSecret: false, + requireAuthTime: true, + defaultMaxAge: 60000, + scope: _.uniq(_.flatten(app.systemScopeList.defaultScopes().pluck("value"))), + accessTokenValiditySeconds: 3600, + idTokenValiditySeconds: 600, + deviceCodeValiditySeconds: 30 * 60, + grantTypes: ["authorization_code"], + responseTypes: ["code"], + subjectType: "PUBLIC", + jwksType: "URI", + contacts: contacts + }, { + silent: true + }); } - - - $('#content').html(view.render().el); - setPageTitle($.t('client.client-form.new')); - }); + + $('#content').html(view.render().el); + setPageTitle($.t('client.client-form.new')); + }); } }); -ui.routes.push({path: "admin/client/:id", name: "editClient", callback: - function(id) { +ui.routes.push({ + path: "admin/client/:id", + name: "editClient", + callback: function(id) { console.log("editClient " + id); if (!isAdmin()) { this.root(); return; } - - this.breadCrumbView.collection.reset(); - this.breadCrumbView.collection.add([ - {text:$.t('admin.home'), href:""}, - {text:$.t('client.manage'), href:"manage/#admin/clients"}, - {text:$.t('client.client-form.edit'), href:"manage/#admin/client/" + id} - ]); - - this.updateSidebar('admin/clients'); - - var client = this.clientList.get(id); - if (!client) { - client = new ClientModel({id:id}); - } - - var view = new ClientFormView({model:client, systemScopeList: app.systemScopeList}); - view.load(function() { - if ($.inArray("refresh_token", client.get("grantTypes")) != -1) { - client.set({ - allowRefresh: true - }, { silent: true }); - } - - if (client.get("jwks")) { - client.set({ - jwksType: "VAL" - }, { silent: true }); - } else { - client.set({ - jwksType: "URI" - }, { silent: true }); - } - - client.set({ - generateClientSecret:false, - displayClientSecret:false - }, { silent: true }); - - $('#content').html(view.render().el); - setPageTitle($.t('client.client-form.edit')); - }); - + + this.breadCrumbView.collection.reset(); + this.breadCrumbView.collection.add([{ + text: $.t('admin.home'), + href: "" + }, { + text: $.t('client.manage'), + href: "manage/#admin/clients" + }, { + text: $.t('client.client-form.edit'), + href: "manage/#admin/client/" + id + }]); + + this.updateSidebar('admin/clients'); + + var client = this.clientList.get(id); + if (!client) { + client = new ClientModel({ + id: id + }); + } + + var view = new ClientFormView({ + model: client, + systemScopeList: app.systemScopeList + }); + view.load(function() { + if ($.inArray("refresh_token", client.get("grantTypes")) != -1) { + client.set({ + allowRefresh: true + }, { + silent: true + }); + } + + if (client.get("jwks")) { + client.set({ + jwksType: "VAL" + }, { + silent: true + }); + } else { + client.set({ + jwksType: "URI" + }, { + silent: true + }); + } + + client.set({ + generateClientSecret: false, + displayClientSecret: false + }, { + silent: true + }); + + $('#content').html(view.render().el); + setPageTitle($.t('client.client-form.edit')); + }); + } }); ui.templates.push('resources/template/client.html'); ui.init.push(function(app) { - app.clientList = new ClientCollection(); + app.clientList = new ClientCollection(); }); diff --git a/openid-connect-server-webapp/src/main/webapp/resources/js/dynreg.js b/openid-connect-server-webapp/src/main/webapp/resources/js/dynreg.js index dca9fe2f2..81b052a91 100644 --- a/openid-connect-server-webapp/src/main/webapp/resources/js/dynreg.js +++ b/openid-connect-server-webapp/src/main/webapp/resources/js/dynreg.js @@ -15,713 +15,816 @@ * limitations under the License. *******************************************************************************/ var DynRegClient = Backbone.Model.extend({ - idAttribute: "client_id", + idAttribute: "client_id", - defaults:{ - client_id:null, - client_secret:null, - redirect_uris:[], - client_name:null, - client_uri:null, - logo_uri:null, - contacts:[], - tos_uri:null, - token_endpoint_auth_method:null, - scope:null, - grant_types:[], - response_types:[], - policy_uri:null, - - jwks_uri:null, - jwks:null, - jwksType:'URI', - - application_type:null, - sector_identifier_uri:null, - subject_type:null, - - request_object_signing_alg:null, - - userinfo_signed_response_alg:null, - userinfo_encrypted_response_alg:null, - userinfo_encrypted_response_enc:null, - - id_token_signed_response_alg:null, - id_token_encrypted_response_alg:null, - id_token_encrypted_response_enc:null, - - default_max_age:null, - require_auth_time:false, - default_acr_values:null, - - initiate_login_uri:null, - post_logout_redirect_uris:null, - - claims_redirect_uris:[], - - request_uris:[], - - software_statement:null, - software_id:null, - software_version:null, - - code_challenge_method:null, + defaults: { + client_id: null, + client_secret: null, + redirect_uris: [], + client_name: null, + client_uri: null, + logo_uri: null, + contacts: [], + tos_uri: null, + token_endpoint_auth_method: null, + scope: null, + grant_types: [], + response_types: [], + policy_uri: null, - registration_access_token:null, - registration_client_uri:null - }, - - sync: function(method, model, options){ - if (model.get('registration_access_token')) { - var headers = options.headers ? options.headers : {}; - headers['Authorization'] = 'Bearer ' + model.get('registration_access_token'); - options.headers = headers; - } - - return this.constructor.__super__.sync(method, model, options); - }, + jwks_uri: null, + jwks: null, + jwksType: 'URI', + + application_type: null, + sector_identifier_uri: null, + subject_type: null, + + request_object_signing_alg: null, + + userinfo_signed_response_alg: null, + userinfo_encrypted_response_alg: null, + userinfo_encrypted_response_enc: null, + + id_token_signed_response_alg: null, + id_token_encrypted_response_alg: null, + id_token_encrypted_response_enc: null, + + default_max_age: null, + require_auth_time: false, + default_acr_values: null, + + initiate_login_uri: null, + post_logout_redirect_uris: null, + + claims_redirect_uris: [], + + request_uris: [], + + software_statement: null, + software_id: null, + software_version: null, + + code_challenge_method: null, + + registration_access_token: null, + registration_client_uri: null + }, + + sync: function(method, model, options) { + if (model.get('registration_access_token')) { + var headers = options.headers ? options.headers : {}; + headers['Authorization'] = 'Bearer ' + model.get('registration_access_token'); + options.headers = headers; + } + + return this.constructor.__super__.sync(method, model, options); + }, + + urlRoot: 'register' - urlRoot:'register' - }); var DynRegRootView = Backbone.View.extend({ - + tagName: 'span', - - initialize:function(options) { - this.options = options; - - }, - - events:{ - "click #newreg":"newReg", - "click #editreg":"editReg" - }, - - load:function(callback) { - if (this.options.systemScopeList.isFetched) { - callback(); - return; - } - $('#loadingbox').sheet('show'); - $('#loading').html('' + $.t('common.scopes') + ' '); + initialize: function(options) { + this.options = options; - $.when(this.options.systemScopeList.fetchIfNeeded({success:function(e) {$('#loading-scopes').addClass('label-success');}, error:app.errorHandlerView.handleError()})) - .done(function() { - $('#loadingbox').sheet('hide'); - callback(); - }); }, - - render:function() { - $(this.el).html($('#tmpl-dynreg').html()); - $(this.el).i18n(); - return this; + + events: { + "click #newreg": "newReg", + "click #editreg": "editReg" }, - - newReg:function(e) { - e.preventDefault(); - this.remove(); - app.navigate('dev/dynreg/new', {trigger: true}); + + load: function(callback) { + if (this.options.systemScopeList.isFetched) { + callback(); + return; + } + + $('#loadingbox').sheet('show'); + $('#loading').html('' + $.t('common.scopes') + ' '); + + $.when(this.options.systemScopeList.fetchIfNeeded({ + success: function(e) { + $('#loading-scopes').addClass('label-success'); + }, + error: app.errorHandlerView.handleError() + })).done(function() { + $('#loadingbox').sheet('hide'); + callback(); + }); }, - - editReg:function(e) { - e.preventDefault(); + + render: function() { + $(this.el).html($('#tmpl-dynreg').html()); + $(this.el).i18n(); + return this; + }, + + newReg: function(e) { + e.preventDefault(); + this.remove(); + app.navigate('dev/dynreg/new', { + trigger: true + }); + }, + + editReg: function(e) { + e.preventDefault(); var clientId = $('#clientId').val(); var token = $('#regtoken').val(); - + var client = new DynRegClient({ client_id: clientId, registration_access_token: token }); - + var self = this; - + client.fetch({ success: function() { - var userInfo = getUserInfo(); - var contacts = client.get("contacts"); - if (userInfo != null && userInfo.email != null && ! _.contains(contacts, userInfo.email)) { - contacts.push(userInfo.email); - } - client.set({ - contacts: contacts - }, { silent: true }); - - if (client.get("jwks")) { - client.set({ - jwksType: "VAL" - }, { silent: true }); - } else { - client.set({ - jwksType: "URI" - }, { silent: true }); - } - - var view = new DynRegEditView({model: client, systemScopeList: app.systemScopeList}); - - view.load(function() { - $('#content').html(view.render().el); - view.delegateEvents(); - setPageTitle($.t('dynreg.edit-dynamically-registered')); - app.navigate('dev/dynreg/edit', {trigger: true}); - self.remove(); - }); - }, error:app.errorHandlerView.handleError({message: $.t('dynreg.invalid-access-token')}) + var userInfo = getUserInfo(); + var contacts = client.get("contacts"); + if (userInfo != null && userInfo.email != null && !_.contains(contacts, userInfo.email)) { + contacts.push(userInfo.email); + } + client.set({ + contacts: contacts + }, { + silent: true + }); + + if (client.get("jwks")) { + client.set({ + jwksType: "VAL" + }, { + silent: true + }); + } else { + client.set({ + jwksType: "URI" + }, { + silent: true + }); + } + + var view = new DynRegEditView({ + model: client, + systemScopeList: app.systemScopeList + }); + + view.load(function() { + $('#content').html(view.render().el); + view.delegateEvents(); + setPageTitle($.t('dynreg.edit-dynamically-registered')); + app.navigate('dev/dynreg/edit', { + trigger: true + }); + self.remove(); + }); + }, + error: app.errorHandlerView.handleError({ + message: $.t('dynreg.invalid-access-token') + }) }); } - + }); var DynRegEditView = Backbone.View.extend({ - + tagName: 'span', - - initialize:function(options) { - this.options = options; - if (!this.template) { - this.template = _.template($('#tmpl-dynreg-client-form').html()); - } - this.redirectUrisCollection = new Backbone.Collection(); - this.scopeCollection = new Backbone.Collection(); - this.contactsCollection = new Backbone.Collection(); - this.defaultAcrValuesCollection = new Backbone.Collection(); - this.requestUrisCollection = new Backbone.Collection(); - this.postLogoutRedirectUrisCollection = new Backbone.Collection(); - this.claimsRedirectUrisCollection = new Backbone.Collection(); - - this.listWidgetViews = []; - }, - - load:function(callback) { - if (this.options.systemScopeList.isFetched) { - callback(); - return; - } + initialize: function(options) { + this.options = options; + if (!this.template) { + this.template = _.template($('#tmpl-dynreg-client-form').html()); + } - $('#loadingbox').sheet('show'); - $('#loading').html('' + $.t('common.scopes') + ' '); + this.redirectUrisCollection = new Backbone.Collection(); + this.scopeCollection = new Backbone.Collection(); + this.contactsCollection = new Backbone.Collection(); + this.defaultAcrValuesCollection = new Backbone.Collection(); + this.requestUrisCollection = new Backbone.Collection(); + this.postLogoutRedirectUrisCollection = new Backbone.Collection(); + this.claimsRedirectUrisCollection = new Backbone.Collection(); - $.when(this.options.systemScopeList.fetchIfNeeded({success:function(e) {$('#loading-scopes').addClass('label-success');}, error:app.errorHandlerView.handleError()})) - .done(function() { - $('#loadingbox').sheet('hide'); - callback(); - }); - }, - - events:{ - "click .btn-save":"saveClient", - "click .btn-cancel":"cancel", - "click .btn-delete":"deleteClient", - "change #logoUri input":"previewLogo", - "change #tokenEndpointAuthMethod input:radio":"toggleClientCredentials", - "change #jwkSelector input:radio":"toggleJWKSetType" - }, - - cancel:function(e) { - e.preventDefault(); - app.navigate('dev/dynreg', {trigger: true}); - }, - - deleteClient:function (e) { - e.preventDefault(); - - if (confirm($.t('client.client-table.confirm'))) { - var self = this; - - this.model.destroy({ - dataType: false, processData: false, - success:function () { - self.remove(); - app.navigate('dev/dynreg', {trigger: true}); - }, - error:app.errorHandlerView.handleError({"log": "An error occurred when deleting a client"}) - }); - - } - - return false; - }, - - previewLogo:function() { - if ($('#logoUri input', this.el).val()) { - $('#logoPreview', this.el).empty(); - $('#logoPreview', this.el).attr('src', $('#logoUri input', this.el).val()); - } else { - //$('#logoBlock', this.el).hide(); - $('#logoPreview', this.el).attr('src', 'resources/images/logo_placeholder.gif'); - } - }, - - /** - * Set up the form based on the current state of the tokenEndpointAuthMethod parameter - * @param event - */ - toggleClientCredentials:function() { - - var tokenEndpointAuthMethod = $('#tokenEndpointAuthMethod input', this.el).filter(':checked').val(); - - // show or hide the signing algorithm method depending on what's selected - if (tokenEndpointAuthMethod == 'private_key_jwt' - || tokenEndpointAuthMethod == 'client_secret_jwt') { - $('#tokenEndpointAuthSigningAlg', this.el).show(); - } else { - $('#tokenEndpointAuthSigningAlg', this.el).hide(); - } - }, - - /** - * Set up the form based on the JWK Set selector - */ - toggleJWKSetType:function() { - var jwkSelector = $('#jwkSelector input:radio', this.el).filter(':checked').val(); - - if (jwkSelector == 'URI') { - $('#jwksUri', this.el).show(); - $('#jwks', this.el).hide(); - } else if (jwkSelector == 'VAL') { - $('#jwksUri', this.el).hide(); - $('#jwks', this.el).show(); - } else { - $('#jwksUri', this.el).hide(); - $('#jwks', this.el).hide(); - } - - }, - - disableUnsupportedJOSEItems:function(serverSupported, query) { - var supported = ['default']; - if (serverSupported) { - supported = _.union(supported, serverSupported); - } - $(query, this.$el).each(function(idx) { - if(_.contains(supported, $(this).val())) { - $(this).prop('disabled', false); - } else { - $(this).prop('disabled', true); - } - }); - - }, - - // returns "null" if given the value "default" as a string, otherwise returns input value. useful for parsing the JOSE algorithm dropdowns - defaultToNull:function(value) { - if (value == 'default') { - return null; - } else { - return value; - } - }, - - // returns "null" if the given value is falsy - emptyToNull:function(value) { - if (value) { - return value; - } else { - return null; - } - }, - - // maps from a form-friendly name to the real grant parameter name - grantMap:{ - 'authorization_code': 'authorization_code', - 'password': 'password', - 'implicit': 'implicit', - 'client_credentials': 'client_credentials', - 'redelegate': 'urn:ietf:params:oauth:grant_type:redelegate', - 'refresh_token': 'refresh_token' - }, - - // maps from a form-friendly name to the real response type parameter name - responseMap:{ - 'code': 'code', - 'token': 'token', - 'idtoken': 'id_token', - 'token-idtoken': 'token id_token', - 'code-idtoken': 'code id_token', - 'code-token': 'code token', - 'code-token-idtoken': 'code token id_token' - }, - - saveClient:function (e) { - e.preventDefault(); - - $('.control-group').removeClass('error'); - - // sync any leftover collection items - _.each(this.listWidgetViews, function(v) { - v.addItem($.Event('click')); - }); - - // build the scope object - var scopes = this.scopeCollection.pluck("item").join(" "); - - // build the grant type object - var grantTypes = []; - $.each(this.grantMap, function(index,type) { - if ($('#grantTypes-' + index).is(':checked')) { - grantTypes.push(type); - } - }); - - // build the response type object - var responseTypes = []; - $.each(this.responseMap, function(index,type) { - if ($('#responseTypes-' + index).is(':checked')) { - responseTypes.push(type); - } - }); - - var contacts = this.contactsCollection.pluck('item'); - var userInfo = getUserInfo(); - if (userInfo && userInfo.email) { - if (!_.contains(contacts, userInfo.email)) { - contacts.push(userInfo.email); - } - } - - // make sure that the subject identifier is consistent with the redirect URIs - var subjectType = $('#subjectType input').filter(':checked').val(); - var redirectUris = this.redirectUrisCollection.pluck("item"); - var sectorIdentifierUri = $('#sectorIdentifierUri input').val(); - if (subjectType == 'PAIRWISE' && redirectUris.length > 1 && sectorIdentifierUri == '') { - //Display an alert with an error message - app.errorHandlerView.showErrorMessage($.t("client.client-form.error.consistency"), $.t("client.client-form.error.pairwise-sector")); - return false; - - } - - // process the JWKS - var jwksUri = null; - var jwks = null; - var jwkSelector = $('#jwkSelector input:radio', this.el).filter(':checked').val(); - - if (jwkSelector == 'URI') { - jwksUri = $('#jwksUri input').val(); - jwks = null; - } else if (jwkSelector == 'VAL') { - jwksUri = null; - try { - jwks = JSON.parse($('#jwks textarea').val()); - } catch (e) { - console.log("An error occurred when parsing the JWK Set"); - app.errorHandlerView.showErrorMessage($.t("client.client-form.error.jwk-set"), $.t("client.client-form.error.jwk-set-parse")); - return false; - } - } else { - jwksUri = null; - jwks = null; - } - - var attrs = { - client_name:this.emptyToNull($('#clientName input').val()), - redirect_uris: redirectUris, - logo_uri:this.emptyToNull($('#logoUri input').val()), - grant_types: grantTypes, - scope: scopes, - client_secret: null, // never send a client secret - tos_uri: this.emptyToNull($('#tosUri input').val()), - policy_uri: this.emptyToNull($('#policyUri input').val()), - client_uri: this.emptyToNull($('#clientUri input').val()), - application_type: $('#applicationType input').filter(':checked').val(), - jwks_uri: jwksUri, - jwks: jwks, - subject_type: subjectType, - software_statement: this.emptyToNull($('#softwareStatement textarea').val()), - softwareId: this.emptyToNull($('#softwareId input').val()), - softwareVersion: this.emptyToNull($('#softwareVersion input').val()), - token_endpoint_auth_method: $('#tokenEndpointAuthMethod input').filter(':checked').val(), - response_types: responseTypes, - sector_identifier_uri: sectorIdentifierUri, - initiate_login_uri: this.emptyToNull($('#initiateLoginUri input').val()), - post_logout_redirect_uris: this.postLogoutRedirectUrisCollection.pluck('item'), - claims_redirect_uris: this.claimsRedirectUrisCollection.pluck('item'), - require_auth_time: $('#requireAuthTime input').is(':checked'), - default_max_age: parseInt($('#defaultMaxAge input').val()), - contacts: contacts, - request_uris: this.requestUrisCollection.pluck('item'), - default_acr_values: this.defaultAcrValuesCollection.pluck('item'), - request_object_signing_alg: this.defaultToNull($('#requestObjectSigningAlg select').val()), - userinfo_signed_response_alg: this.defaultToNull($('#userInfoSignedResponseAlg select').val()), - userinfo_encrypted_response_alg: this.defaultToNull($('#userInfoEncryptedResponseAlg select').val()), - userinfo_encrypted_response_enc: this.defaultToNull($('#userInfoEncryptedResponseEnc select').val()), - id_token_signed_response_alg: this.defaultToNull($('#idTokenSignedResponseAlg select').val()), - id_token_encrypted_response_alg: this.defaultToNull($('#idTokenEncryptedResponseAlg select').val()), - id_token_encrypted_response_enc: this.defaultToNull($('#idTokenEncryptedResponseEnc select').val()), - token_endpoint_auth_signing_alg: this.defaultToNull($('#tokenEndpointAuthSigningAlg select').val()), - code_challenge_method: this.defaultToNull($('#codeChallengeMethod select').val()) - }; - - // set all empty strings to nulls - for (var key in attrs) { - if (attrs[key] === "") { - attrs[key] = null; - } - } - - var _self = this; - this.model.save(attrs, { - success:function () { - // switch to an "edit" view - app.navigate('dev/dynreg/edit', {trigger: true}); - _self.remove(); - - var userInfo = getUserInfo(); - var contacts = _self.model.get("contacts"); - if (userInfo != null && userInfo.email != null && ! _.contains(contacts, userInfo.email)) { - contacts.push(userInfo.email); - } - _self.model.set({ - contacts: contacts - }, { silent: true }); - - if (_self.model.get("jwks")) { - _self.model.set({ - jwksType: "VAL" - }, { silent: true }); - } else { - _self.model.set({ - jwksType: "URI" - }, { silent: true }); - } - - var view = new DynRegEditView({model: _self.model, systemScopeList: _self.options.systemScopeList}); - - view.load(function() { - // reload - $('#content').html(view.render().el); - view.delegateEvents(); - }); - }, - error:app.errorHandlerView.handleError({log: "An error occurred when saving a client"}) - }); - - return false; - }, - - render:function() { - var data = {client: this.model.toJSON(), userInfo: getUserInfo(), heartMode: heartMode}; - $(this.el).html(this.template(data)); - this.listWidgetViews = []; - + }, + + load: function(callback) { + if (this.options.systemScopeList.isFetched) { + callback(); + return; + } + + $('#loadingbox').sheet('show'); + $('#loading').html('' + $.t('common.scopes') + ' '); + + $.when(this.options.systemScopeList.fetchIfNeeded({ + success: function(e) { + $('#loading-scopes').addClass('label-success'); + }, + error: app.errorHandlerView.handleError() + })).done(function() { + $('#loadingbox').sheet('hide'); + callback(); + }); + }, + + events: { + "click .btn-save": "saveClient", + "click .btn-cancel": "cancel", + "click .btn-delete": "deleteClient", + "change #logoUri input": "previewLogo", + "change #tokenEndpointAuthMethod input:radio": "toggleClientCredentials", + "change #jwkSelector input:radio": "toggleJWKSetType" + }, + + cancel: function(e) { + e.preventDefault(); + app.navigate('dev/dynreg', { + trigger: true + }); + }, + + deleteClient: function(e) { + e.preventDefault(); + + if (confirm($.t('client.client-table.confirm'))) { + var self = this; + + this.model.destroy({ + dataType: false, + processData: false, + success: function() { + self.remove(); + app.navigate('dev/dynreg', { + trigger: true + }); + }, + error: app.errorHandlerView.handleError({ + "log": "An error occurred when deleting a client" + }) + }); + + } + + return false; + }, + + previewLogo: function() { + if ($('#logoUri input', this.el).val()) { + $('#logoPreview', this.el).empty(); + $('#logoPreview', this.el).attr('src', $('#logoUri input', this.el).val()); + } else { + // $('#logoBlock', this.el).hide(); + $('#logoPreview', this.el).attr('src', 'resources/images/logo_placeholder.gif'); + } + }, + + /** + * Set up the form based on the current state of the tokenEndpointAuthMethod + * parameter + * + * @param event + */ + toggleClientCredentials: function() { + + var tokenEndpointAuthMethod = $('#tokenEndpointAuthMethod input', this.el).filter(':checked').val(); + + // show or hide the signing algorithm method depending on what's + // selected + if (tokenEndpointAuthMethod == 'private_key_jwt' || tokenEndpointAuthMethod == 'client_secret_jwt') { + $('#tokenEndpointAuthSigningAlg', this.el).show(); + } else { + $('#tokenEndpointAuthSigningAlg', this.el).hide(); + } + }, + + /** + * Set up the form based on the JWK Set selector + */ + toggleJWKSetType: function() { + var jwkSelector = $('#jwkSelector input:radio', this.el).filter(':checked').val(); + + if (jwkSelector == 'URI') { + $('#jwksUri', this.el).show(); + $('#jwks', this.el).hide(); + } else if (jwkSelector == 'VAL') { + $('#jwksUri', this.el).hide(); + $('#jwks', this.el).show(); + } else { + $('#jwksUri', this.el).hide(); + $('#jwks', this.el).hide(); + } + + }, + + disableUnsupportedJOSEItems: function(serverSupported, query) { + var supported = ['default']; + if (serverSupported) { + supported = _.union(supported, serverSupported); + } + $(query, this.$el).each(function(idx) { + if (_.contains(supported, $(this).val())) { + $(this).prop('disabled', false); + } else { + $(this).prop('disabled', true); + } + }); + + }, + + // returns "null" if given the value "default" as a string, + // otherwise returns input value. useful for parsing the JOSE + // algorithm dropdowns + defaultToNull: function(value) { + if (value == 'default') { + return null; + } else { + return value; + } + }, + + // returns "null" if the given value is falsy + emptyToNull: function(value) { + if (value) { + return value; + } else { + return null; + } + }, + + // maps from a form-friendly name to the real grant parameter name + grantMap: { + 'authorization_code': 'authorization_code', + 'password': 'password', + 'implicit': 'implicit', + 'client_credentials': 'client_credentials', + 'redelegate': 'urn:ietf:params:oauth:grant_type:redelegate', + 'refresh_token': 'refresh_token' + }, + + // maps from a form-friendly name to the real response type + // parameter name + responseMap: { + 'code': 'code', + 'token': 'token', + 'idtoken': 'id_token', + 'token-idtoken': 'token id_token', + 'code-idtoken': 'code id_token', + 'code-token': 'code token', + 'code-token-idtoken': 'code token id_token' + }, + + saveClient: function(e) { + e.preventDefault(); + + $('.control-group').removeClass('error'); + + // sync any leftover collection items + _.each(this.listWidgetViews, function(v) { + v.addItem($.Event('click')); + }); + + // build the scope object + var scopes = this.scopeCollection.pluck("item").join(" "); + + // build the grant type object + var grantTypes = []; + $.each(this.grantMap, function(index, type) { + if ($('#grantTypes-' + index).is(':checked')) { + grantTypes.push(type); + } + }); + + // build the response type object + var responseTypes = []; + $.each(this.responseMap, function(index, type) { + if ($('#responseTypes-' + index).is(':checked')) { + responseTypes.push(type); + } + }); + + var contacts = this.contactsCollection.pluck('item'); + var userInfo = getUserInfo(); + if (userInfo && userInfo.email) { + if (!_.contains(contacts, userInfo.email)) { + contacts.push(userInfo.email); + } + } + + // make sure that the subject identifier is consistent with the + // redirect URIs + var subjectType = $('#subjectType input').filter(':checked').val(); + var redirectUris = this.redirectUrisCollection.pluck("item"); + var sectorIdentifierUri = $('#sectorIdentifierUri input').val(); + if (subjectType == 'PAIRWISE' && redirectUris.length > 1 && sectorIdentifierUri == '') { + // Display an alert with an error message + app.errorHandlerView.showErrorMessage($.t("client.client-form.error.consistency"), $.t("client.client-form.error.pairwise-sector")); + return false; + + } + + // process the JWKS + var jwksUri = null; + var jwks = null; + var jwkSelector = $('#jwkSelector input:radio', this.el).filter(':checked').val(); + + if (jwkSelector == 'URI') { + jwksUri = $('#jwksUri input').val(); + jwks = null; + } else if (jwkSelector == 'VAL') { + jwksUri = null; + try { + jwks = JSON.parse($('#jwks textarea').val()); + } catch (e) { + console.log("An error occurred when parsing the JWK Set"); + app.errorHandlerView.showErrorMessage($.t("client.client-form.error.jwk-set"), $.t("client.client-form.error.jwk-set-parse")); + return false; + } + } else { + jwksUri = null; + jwks = null; + } + + var attrs = { + client_name: this.emptyToNull($('#clientName input').val()), + redirect_uris: redirectUris, + logo_uri: this.emptyToNull($('#logoUri input').val()), + grant_types: grantTypes, + scope: scopes, + client_secret: null, // never send a client secret + tos_uri: this.emptyToNull($('#tosUri input').val()), + policy_uri: this.emptyToNull($('#policyUri input').val()), + client_uri: this.emptyToNull($('#clientUri input').val()), + application_type: $('#applicationType input').filter(':checked').val(), + jwks_uri: jwksUri, + jwks: jwks, + subject_type: subjectType, + software_statement: this.emptyToNull($('#softwareStatement textarea').val()), + softwareId: this.emptyToNull($('#softwareId input').val()), + softwareVersion: this.emptyToNull($('#softwareVersion input').val()), + token_endpoint_auth_method: $('#tokenEndpointAuthMethod input').filter(':checked').val(), + response_types: responseTypes, + sector_identifier_uri: sectorIdentifierUri, + initiate_login_uri: this.emptyToNull($('#initiateLoginUri input').val()), + post_logout_redirect_uris: this.postLogoutRedirectUrisCollection.pluck('item'), + claims_redirect_uris: this.claimsRedirectUrisCollection.pluck('item'), + require_auth_time: $('#requireAuthTime input').is(':checked'), + default_max_age: parseInt($('#defaultMaxAge input').val()), + contacts: contacts, + request_uris: this.requestUrisCollection.pluck('item'), + default_acr_values: this.defaultAcrValuesCollection.pluck('item'), + request_object_signing_alg: this.defaultToNull($('#requestObjectSigningAlg select').val()), + userinfo_signed_response_alg: this.defaultToNull($('#userInfoSignedResponseAlg select').val()), + userinfo_encrypted_response_alg: this.defaultToNull($('#userInfoEncryptedResponseAlg select').val()), + userinfo_encrypted_response_enc: this.defaultToNull($('#userInfoEncryptedResponseEnc select').val()), + id_token_signed_response_alg: this.defaultToNull($('#idTokenSignedResponseAlg select').val()), + id_token_encrypted_response_alg: this.defaultToNull($('#idTokenEncryptedResponseAlg select').val()), + id_token_encrypted_response_enc: this.defaultToNull($('#idTokenEncryptedResponseEnc select').val()), + token_endpoint_auth_signing_alg: this.defaultToNull($('#tokenEndpointAuthSigningAlg select').val()), + code_challenge_method: this.defaultToNull($('#codeChallengeMethod select').val()) + }; + + // set all empty strings to nulls + for ( var key in attrs) { + if (attrs[key] === "") { + attrs[key] = null; + } + } + + var _self = this; + this.model.save(attrs, { + success: function() { + // switch to an "edit" view + app.navigate('dev/dynreg/edit', { + trigger: true + }); + _self.remove(); + + var userInfo = getUserInfo(); + var contacts = _self.model.get("contacts"); + if (userInfo != null && userInfo.email != null && !_.contains(contacts, userInfo.email)) { + contacts.push(userInfo.email); + } + _self.model.set({ + contacts: contacts + }, { + silent: true + }); + + if (_self.model.get("jwks")) { + _self.model.set({ + jwksType: "VAL" + }, { + silent: true + }); + } else { + _self.model.set({ + jwksType: "URI" + }, { + silent: true + }); + } + + var view = new DynRegEditView({ + model: _self.model, + systemScopeList: _self.options.systemScopeList + }); + + view.load(function() { + // reload + $('#content').html(view.render().el); + view.delegateEvents(); + }); + }, + error: app.errorHandlerView.handleError({ + log: "An error occurred when saving a client" + }) + }); + + return false; + }, + + render: function() { + var data = { + client: this.model.toJSON(), + userInfo: getUserInfo(), + heartMode: heartMode + }; + $(this.el).html(this.template(data)); + + this.listWidgetViews = []; + var _self = this; - // build and bind registered redirect URI collection and view - _.each(this.model.get("redirect_uris"), function (redirectUri) { - _self.redirectUrisCollection.add(new URIModel({item:redirectUri})); - }); - - var redirectUriView = new ListWidgetView({ - type:'uri', - placeholder: 'https://', - helpBlockText: $.t('client.client-form.redirect-uris-help'), - collection: this.redirectUrisCollection}); - $("#redirectUris .controls",this.el).html(redirectUriView.render().el); - this.listWidgetViews.push(redirectUriView); - - // build and bind scopes - var scopes = this.model.get("scope"); - var scopeSet = scopes ? scopes.split(" ") : []; - _.each(scopeSet, function (scope) { - _self.scopeCollection.add(new Backbone.Model({item:scope})); - }); - - var scopeView = new ListWidgetView({ - placeholder: $.t('client.client-form.scope-placeholder'), - autocomplete: _.uniq(_.flatten(this.options.systemScopeList.unrestrictedScopes().pluck("value"))), - helpBlockText: $.t('client.client-form.scope-help'), - collection: this.scopeCollection}); - $("#scope .controls",this.el).html(scopeView.render().el); - this.listWidgetViews.push(scopeView); - - // build and bind contacts - _.each(this.model.get('contacts'), function (contact) { - _self.contactsCollection.add(new Backbone.Model({item:contact})); - }); - - var contactView = new ListWidgetView({ - placeholder: $.t('client.client-form.contacts-placeholder'), - helpBlockText: $.t('client.client-form.contacts-help'), - collection: this.contactsCollection}); - $("#contacts .controls div", this.el).html(contactView.render().el); - this.listWidgetViews.push(contactView); - - // build and bind post-logout redirect URIs - _.each(this.model.get('post_logout_redirect_uris'), function(postLogoutRedirectUri) { - _self.postLogoutRedirectUrisCollection.add(new URIModel({item:postLogoutRedirectUri})); - }); - - var postLogoutRedirectUrisView = new ListWidgetView({ - type: 'uri', - placeholder: 'https://', - helpBlockText: $.t('client.client-form.post-logout-help'), - collection: this.postLogoutRedirectUrisCollection}); - $('#postLogoutRedirectUris .controls', this.el).html(postLogoutRedirectUrisView.render().el); - this.listWidgetViews.push(postLogoutRedirectUrisView); - - // build and bind claims redirect URIs - _.each(this.model.get('claimsRedirectUris'), function(claimsRedirectUri) { - _self.claimsRedirectUrisCollection.add(new URIModel({item:claimsRedirectUri})); - }); - - var claimsRedirectUrisView = new ListWidgetView({ - type: 'uri', - placeholder: 'https://', - helpBlockText: $.t('client.client-form.claims-redirect-uris-help'), - collection: this.claimsRedirectUrisCollection}); - $('#claimsRedirectUris .controls', this.el).html(claimsRedirectUrisView.render().el); - this.listWidgetViews.push(claimsRedirectUrisView); - - // build and bind request URIs - _.each(this.model.get('request_uris'), function (requestUri) { - _self.requestUrisCollection.add(new URIModel({item:requestUri})); - }); - - var requestUriView = new ListWidgetView({ - type: 'uri', - placeholder: 'https://', - helpBlockText: $.t('client.client-form.request-uri-help'), - collection: this.requestUrisCollection}); - $('#requestUris .controls', this.el).html(requestUriView.render().el); - this.listWidgetViews.push(requestUriView); - - // build and bind default ACR values - _.each(this.model.get('default_acr_values'), function (defaultAcrValue) { - _self.defaultAcrValuesCollection.add(new Backbone.Model({item:defaultAcrValue})); - }); - - var defaultAcrView = new ListWidgetView({ - placeholder: $.t('client.client-form.acr-values-placeholder'), - // TODO: autocomplete from spec - helpBlockText: $.t('client.client-form.acr-values-help'), - collection: this.defaultAcrValuesCollection}); - $('#defaultAcrValues .controls', this.el).html(defaultAcrView.render().el); - this.listWidgetViews.push(defaultAcrView); - - this.toggleClientCredentials(); - this.previewLogo(); - this.toggleJWKSetType(); - - // disable unsupported JOSE algorithms - this.disableUnsupportedJOSEItems(app.serverConfiguration.request_object_signing_alg_values_supported, '#requestObjectSigningAlg option'); - this.disableUnsupportedJOSEItems(app.serverConfiguration.userinfo_signing_alg_values_supported, '#userInfoSignedResponseAlg option'); - this.disableUnsupportedJOSEItems(app.serverConfiguration.userinfo_encryption_alg_values_supported, '#userInfoEncryptedResponseAlg option'); - this.disableUnsupportedJOSEItems(app.serverConfiguration.userinfo_encryption_enc_values_supported, '#userInfoEncryptedResponseEnc option'); - this.disableUnsupportedJOSEItems(app.serverConfiguration.id_token_signing_alg_values_supported, '#idTokenSignedResponseAlg option'); - this.disableUnsupportedJOSEItems(app.serverConfiguration.id_token_encryption_alg_values_supported, '#idTokenEncryptedResponseAlg option'); - this.disableUnsupportedJOSEItems(app.serverConfiguration.id_token_encryption_enc_values_supported, '#idTokenEncryptedResponseEnc option'); - this.disableUnsupportedJOSEItems(app.serverConfiguration.token_endpoint_auth_signing_alg_values_supported, '#tokenEndpointAuthSigningAlg option'); - - this.$('.nyi').clickover({ - placement: 'right', - title: $.t('common.not-yet-implemented'), - content: $.t('common.not-yet-implemented-content') - }); - - - $(this.el).i18n(); - return this; - } - -}); - -ui.routes.push({path: "dev/dynreg", name: "dynReg", callback: - function() { - - this.breadCrumbView.collection.reset(); - this.breadCrumbView.collection.add([ - {text:$.t('admin.home'), href:""}, - {text:$.t('admin.self-service-client'), href:"manage/#dev/dynreg"} - ]); - - var view = new DynRegRootView({systemScopeList: this.systemScopeList}); - - this.updateSidebar('dev/dynreg'); - - view.load(function() { - $('#content').html(view.render().el); - - setPageTitle($.t('admin.self-service-client')); + // build and bind registered redirect URI collection and view + _.each(this.model.get("redirect_uris"), function(redirectUri) { + _self.redirectUrisCollection.add(new URIModel({ + item: redirectUri + })); }); - + + var redirectUriView = new ListWidgetView({ + type: 'uri', + placeholder: 'https://', + helpBlockText: $.t('client.client-form.redirect-uris-help'), + collection: this.redirectUrisCollection + }); + $("#redirectUris .controls", this.el).html(redirectUriView.render().el); + this.listWidgetViews.push(redirectUriView); + + // build and bind scopes + var scopes = this.model.get("scope"); + var scopeSet = scopes ? scopes.split(" ") : []; + _.each(scopeSet, function(scope) { + _self.scopeCollection.add(new Backbone.Model({ + item: scope + })); + }); + + var scopeView = new ListWidgetView({ + placeholder: $.t('client.client-form.scope-placeholder'), + autocomplete: _.uniq(_.flatten(this.options.systemScopeList.unrestrictedScopes().pluck("value"))), + helpBlockText: $.t('client.client-form.scope-help'), + collection: this.scopeCollection + }); + $("#scope .controls", this.el).html(scopeView.render().el); + this.listWidgetViews.push(scopeView); + + // build and bind contacts + _.each(this.model.get('contacts'), function(contact) { + _self.contactsCollection.add(new Backbone.Model({ + item: contact + })); + }); + + var contactView = new ListWidgetView({ + placeholder: $.t('client.client-form.contacts-placeholder'), + helpBlockText: $.t('client.client-form.contacts-help'), + collection: this.contactsCollection + }); + $("#contacts .controls div", this.el).html(contactView.render().el); + this.listWidgetViews.push(contactView); + + // build and bind post-logout redirect URIs + _.each(this.model.get('post_logout_redirect_uris'), function(postLogoutRedirectUri) { + _self.postLogoutRedirectUrisCollection.add(new URIModel({ + item: postLogoutRedirectUri + })); + }); + + var postLogoutRedirectUrisView = new ListWidgetView({ + type: 'uri', + placeholder: 'https://', + helpBlockText: $.t('client.client-form.post-logout-help'), + collection: this.postLogoutRedirectUrisCollection + }); + $('#postLogoutRedirectUris .controls', this.el).html(postLogoutRedirectUrisView.render().el); + this.listWidgetViews.push(postLogoutRedirectUrisView); + + // build and bind claims redirect URIs + _.each(this.model.get('claimsRedirectUris'), function(claimsRedirectUri) { + _self.claimsRedirectUrisCollection.add(new URIModel({ + item: claimsRedirectUri + })); + }); + + var claimsRedirectUrisView = new ListWidgetView({ + type: 'uri', + placeholder: 'https://', + helpBlockText: $.t('client.client-form.claims-redirect-uris-help'), + collection: this.claimsRedirectUrisCollection + }); + $('#claimsRedirectUris .controls', this.el).html(claimsRedirectUrisView.render().el); + this.listWidgetViews.push(claimsRedirectUrisView); + + // build and bind request URIs + _.each(this.model.get('request_uris'), function(requestUri) { + _self.requestUrisCollection.add(new URIModel({ + item: requestUri + })); + }); + + var requestUriView = new ListWidgetView({ + type: 'uri', + placeholder: 'https://', + helpBlockText: $.t('client.client-form.request-uri-help'), + collection: this.requestUrisCollection + }); + $('#requestUris .controls', this.el).html(requestUriView.render().el); + this.listWidgetViews.push(requestUriView); + + // build and bind default ACR values + _.each(this.model.get('default_acr_values'), function(defaultAcrValue) { + _self.defaultAcrValuesCollection.add(new Backbone.Model({ + item: defaultAcrValue + })); + }); + + var defaultAcrView = new ListWidgetView({ + placeholder: $.t('client.client-form.acr-values-placeholder'), + // TODO: autocomplete from spec + helpBlockText: $.t('client.client-form.acr-values-help'), + collection: this.defaultAcrValuesCollection + }); + $('#defaultAcrValues .controls', this.el).html(defaultAcrView.render().el); + this.listWidgetViews.push(defaultAcrView); + + this.toggleClientCredentials(); + this.previewLogo(); + this.toggleJWKSetType(); + + // disable unsupported JOSE algorithms + this.disableUnsupportedJOSEItems(app.serverConfiguration.request_object_signing_alg_values_supported, '#requestObjectSigningAlg option'); + this.disableUnsupportedJOSEItems(app.serverConfiguration.userinfo_signing_alg_values_supported, '#userInfoSignedResponseAlg option'); + this.disableUnsupportedJOSEItems(app.serverConfiguration.userinfo_encryption_alg_values_supported, '#userInfoEncryptedResponseAlg option'); + this.disableUnsupportedJOSEItems(app.serverConfiguration.userinfo_encryption_enc_values_supported, '#userInfoEncryptedResponseEnc option'); + this.disableUnsupportedJOSEItems(app.serverConfiguration.id_token_signing_alg_values_supported, '#idTokenSignedResponseAlg option'); + this.disableUnsupportedJOSEItems(app.serverConfiguration.id_token_encryption_alg_values_supported, '#idTokenEncryptedResponseAlg option'); + this.disableUnsupportedJOSEItems(app.serverConfiguration.id_token_encryption_enc_values_supported, '#idTokenEncryptedResponseEnc option'); + this.disableUnsupportedJOSEItems(app.serverConfiguration.token_endpoint_auth_signing_alg_values_supported, '#tokenEndpointAuthSigningAlg option'); + + this.$('.nyi').clickover({ + placement: 'right', + title: $.t('common.not-yet-implemented'), + content: $.t('common.not-yet-implemented-content') + }); + + $(this.el).i18n(); + return this; + } + +}); + +ui.routes.push({ + path: "dev/dynreg", + name: "dynReg", + callback: function() { + + this.breadCrumbView.collection.reset(); + this.breadCrumbView.collection.add([{ + text: $.t('admin.home'), + href: "" + }, { + text: $.t('admin.self-service-client'), + href: "manage/#dev/dynreg" + }]); + + var view = new DynRegRootView({ + systemScopeList: this.systemScopeList + }); + + this.updateSidebar('dev/dynreg'); + + view.load(function() { + $('#content').html(view.render().el); + + setPageTitle($.t('admin.self-service-client')); + }); + } }); -ui.routes.push({path: "dev/dynreg/new", name: "newDynReg", callback: - function() { +ui.routes.push({ + path: "dev/dynreg/new", + name: "newDynReg", + callback: function() { this.breadCrumbView.collection.reset(); - this.breadCrumbView.collection.add([ - {text:$.t('admin.home'), href:""}, - {text:$.t('admin.self-service-client'), href:"manage/#dev/dynreg"}, - {text:$.t('dynreg.new-client'), href:"manage/#dev/dynreg/new"} - ]); - - this.updateSidebar('dev/dynreg'); - + this.breadCrumbView.collection.add([{ + text: $.t('admin.home'), + href: "" + }, { + text: $.t('admin.self-service-client'), + href: "manage/#dev/dynreg" + }, { + text: $.t('dynreg.new-client'), + href: "manage/#dev/dynreg/new" + }]); + + this.updateSidebar('dev/dynreg'); + var client = new DynRegClient(); - var view = new DynRegEditView({model: client, systemScopeList:this.systemScopeList}); - + var view = new DynRegEditView({ + model: client, + systemScopeList: this.systemScopeList + }); + view.load(function() { - + var userInfo = getUserInfo(); var contacts = []; if (userInfo != null && userInfo.email != null) { contacts.push(userInfo.email); } - + if (heartMode) { client.set({ - require_auth_time:true, - default_max_age:60000, + require_auth_time: true, + default_max_age: 60000, scope: _.uniq(_.flatten(app.systemScopeList.defaultUnrestrictedScopes().pluck("value"))).join(" "), token_endpoint_auth_method: 'private_key_jwt', grant_types: ["authorization_code"], response_types: ["code"], subject_type: "public", contacts: contacts - }, { silent: true }); + }, { + silent: true + }); } else { client.set({ - require_auth_time:true, - default_max_age:60000, + require_auth_time: true, + default_max_age: 60000, scope: _.uniq(_.flatten(app.systemScopeList.defaultUnrestrictedScopes().pluck("value"))).join(" "), token_endpoint_auth_method: 'client_secret_basic', grant_types: ["authorization_code"], response_types: ["code"], subject_type: "public", contacts: contacts - }, { silent: true }); + }, { + silent: true + }); } - + $('#content').html(view.render().el); view.delegateEvents(); setPageTitle($.t('dynreg.new-client')); - + }); - + } }); -ui.routes.push({path: "dev/dynreg/edit", name: "editDynReg", callback: - function() { +ui.routes.push({ + path: "dev/dynreg/edit", + name: "editDynReg", + callback: function() { this.breadCrumbView.collection.reset(); - this.breadCrumbView.collection.add([ - {text:$.t('admin.home'), href:""}, - {text:$.t('admin.self-service-client'), href:"manage/#dev/dynreg"}, - {text:$.t('dynreg.edit-existing'), href:"manage/#dev/dynreg/edit"} - ]); - - this.updateSidebar('dev/dynreg'); - + this.breadCrumbView.collection.add([{ + text: $.t('admin.home'), + href: "" + }, { + text: $.t('admin.self-service-client'), + href: "manage/#dev/dynreg" + }, { + text: $.t('dynreg.edit-existing'), + href: "manage/#dev/dynreg/edit" + }]); + + this.updateSidebar('dev/dynreg'); + setPageTitle($.t('dynreg.edit-existing')); - // note that this doesn't actually load the client, that's supposed to happen elsewhere... + // note that this doesn't actually load the client, that's supposed to + // happen elsewhere... } }); diff --git a/openid-connect-server-webapp/src/main/webapp/resources/js/grant.js b/openid-connect-server-webapp/src/main/webapp/resources/js/grant.js index 948e1c17a..c547b1efd 100644 --- a/openid-connect-server-webapp/src/main/webapp/resources/js/grant.js +++ b/openid-connect-server-webapp/src/main/webapp/resources/js/grant.js @@ -16,84 +16,95 @@ *******************************************************************************/ var ApprovedSiteModel = Backbone.Model.extend({ idAttribute: 'id', - - initialize: function() { }, - + + initialize: function() { + }, + urlRoot: 'api/approved' - + }); var ApprovedSiteCollection = Backbone.Collection.extend({ - initialize: function() { }, + initialize: function() { + }, model: ApprovedSiteModel, url: 'api/approved' }); - var ApprovedSiteListView = Backbone.View.extend({ tagName: 'span', - - initialize:function(options) { + + initialize: function(options) { this.options = options; }, - load:function(callback) { - if (this.model.isFetched && - this.options.clientList.isFetched && - this.options.systemScopeList.isFetched) { - callback(); - return; - } + load: function(callback) { + if (this.model.isFetched && this.options.clientList.isFetched && this.options.systemScopeList.isFetched) { + callback(); + return; + } - $('#loadingbox').sheet('show'); - $('#loading').html( - '' + $.t('grant.grant-table.approved-sites') + ' ' + - '' + $.t('common.clients') + ' ' + - '' + $.t('common.scopes') + ' ' - ); + $('#loadingbox').sheet('show'); + $('#loading').html('' + $.t('grant.grant-table.approved-sites') + ' ' + '' + $.t('common.clients') + ' ' + '' + $.t('common.scopes') + ' '); - $.when(this.model.fetchIfNeeded({success:function(e) {$('#loading-grants').addClass('label-success');}, error:app.errorHandlerView.handleError()}), - this.options.clientList.fetchIfNeeded({success:function(e) {$('#loading-clients').addClass('label-success');}, error:app.errorHandlerView.handleError()}), - this.options.systemScopeList.fetchIfNeeded({success:function(e) {$('#loading-scopes').addClass('label-success');}, error:app.errorHandlerView.handleError()})) - .done(function() { - $('#loadingbox').sheet('hide'); - callback(); - }); - }, - - events: { - "click .refresh-table":"refreshTable" + $.when(this.model.fetchIfNeeded({ + success: function(e) { + $('#loading-grants').addClass('label-success'); + }, + error: app.errorHandlerView.handleError() + }), this.options.clientList.fetchIfNeeded({ + success: function(e) { + $('#loading-clients').addClass('label-success'); + }, + error: app.errorHandlerView.handleError() + }), this.options.systemScopeList.fetchIfNeeded({ + success: function(e) { + $('#loading-scopes').addClass('label-success'); + }, + error: app.errorHandlerView.handleError() + })).done(function() { + $('#loadingbox').sheet('hide'); + callback(); + }); }, - - render:function (eventName) { + + events: { + "click .refresh-table": "refreshTable" + }, + + render: function(eventName) { $(this.el).html($('#tmpl-grant-table').html()); - + var approvedSiteCount = 0; - + var _self = this; - + _.each(this.model.models, function(approvedSite) { // look up client var client = this.options.clientList.getByClientId(approvedSite.get('clientId')); - + if (client != null) { - - var view = new ApprovedSiteView({model: approvedSite, client: client, systemScopeList: this.options.systemScopeList}); + + var view = new ApprovedSiteView({ + model: approvedSite, + client: client, + systemScopeList: this.options.systemScopeList + }); view.parentView = _self; $('#grant-table', this.el).append(view.render().el); approvedSiteCount = approvedSiteCount + 1; - + } - + }, this); - + this.togglePlaceholder(); $(this.el).i18n(); return this; }, - - togglePlaceholder:function() { + + togglePlaceholder: function() { // count entries if (this.model.length > 0) { $('#grant-table', this.el).show(); @@ -102,54 +113,62 @@ var ApprovedSiteListView = Backbone.View.extend({ $('#grant-table', this.el).hide(); $('#grant-table-empty', this.el).show(); } - - }, - - refreshTable:function(e) { - e.preventDefault(); - var _self = this; - $('#loadingbox').sheet('show'); - $('#loading').html( - '' + $.t('grant.grant-table.approved-sites') + ' ' + - '' + $.t('common.clients') + ' ' + - '' + $.t('common.scopes') + ' ' - ); - $.when(this.model.fetch({success:function(e) {$('#loading-grants').addClass('label-success');}, error:app.errorHandlerView.handleError()}), - this.options.clientList.fetch({success:function(e) {$('#loading-clients').addClass('label-success');}, error:app.errorHandlerView.handleError()}), - this.options.systemScopeList.fetch({success:function(e) {$('#loading-scopes').addClass('label-success');}, error:app.errorHandlerView.handleError()})) - .done(function() { - $('#loadingbox').sheet('hide'); - _self.render(); - }); - } + }, + + refreshTable: function(e) { + e.preventDefault(); + var _self = this; + $('#loadingbox').sheet('show'); + $('#loading').html('' + $.t('grant.grant-table.approved-sites') + ' ' + '' + $.t('common.clients') + ' ' + '' + $.t('common.scopes') + ' '); + + $.when(this.model.fetch({ + success: function(e) { + $('#loading-grants').addClass('label-success'); + }, + error: app.errorHandlerView.handleError() + }), this.options.clientList.fetch({ + success: function(e) { + $('#loading-clients').addClass('label-success'); + }, + error: app.errorHandlerView.handleError() + }), this.options.systemScopeList.fetch({ + success: function(e) { + $('#loading-scopes').addClass('label-success'); + }, + error: app.errorHandlerView.handleError() + })).done(function() { + $('#loadingbox').sheet('hide'); + _self.render(); + }); + } }); var ApprovedSiteView = Backbone.View.extend({ tagName: 'tr', - + initialize: function(options) { - this.options = options; + this.options = options; if (!this.template) { this.template = _.template($('#tmpl-grant').html()); } - if (!this.scopeTemplate) { - this.scopeTemplate = _.template($('#tmpl-scope-list').html()); - } + if (!this.scopeTemplate) { + this.scopeTemplate = _.template($('#tmpl-scope-list').html()); + } - if (!this.moreInfoTemplate) { - this.moreInfoTemplate = _.template($('#tmpl-client-more-info-block').html()); - } + if (!this.moreInfoTemplate) { + this.moreInfoTemplate = _.template($('#tmpl-client-more-info-block').html()); + } }, - render: function() { - + render: function() { + var creationDate = this.model.get("creationDate"); var accessDate = this.model.get("accessDate"); var timeoutDate = this.model.get("timeoutDate"); - + var displayCreationDate = $.t('grant.grant-table.unknown'); var hoverCreationDate = ""; if ((creationDate != null) && moment(creationDate).isValid()) { @@ -178,7 +197,7 @@ var ApprovedSiteView = Backbone.View.extend({ var hoverTimeoutDate = ""; if (timeoutDate == null) { displayTimeoutDate = $.t('grant.grant-table.never'); - } else if(moment(timeoutDate).isValid()) { + } else if (moment(timeoutDate).isValid()) { timeoutDate = moment(timeoutDate); if (moment().diff(timeoutDate, 'months') < 6) { displayTimeoutDate = timeoutDate.fromNow(); @@ -188,62 +207,80 @@ var ApprovedSiteView = Backbone.View.extend({ hoverTimeoutDate = timeoutDate.format("LLL"); } - - var formattedDate = {displayCreationDate: displayCreationDate, hoverCreationDate: hoverCreationDate, - displayAccessDate: displayAccessDate, hoverAccessDate: hoverAccessDate, - displayTimeoutDate: displayTimeoutDate, hoverTimeoutDate: hoverTimeoutDate}; - - var json = {grant: this.model.toJSON(), client: this.options.client.toJSON(), formattedDate: formattedDate}; - + var formattedDate = { + displayCreationDate: displayCreationDate, + hoverCreationDate: hoverCreationDate, + displayAccessDate: displayAccessDate, + hoverAccessDate: hoverAccessDate, + displayTimeoutDate: displayTimeoutDate, + hoverTimeoutDate: hoverTimeoutDate + }; + + var json = { + grant: this.model.toJSON(), + client: this.options.client.toJSON(), + formattedDate: formattedDate + }; + this.$el.html(this.template(json)); - $('.scope-list', this.el).html(this.scopeTemplate({scopes: this.model.get('allowedScopes'), systemScopes: this.options.systemScopeList})); - - $('.client-more-info-block', this.el).html(this.moreInfoTemplate({client: this.options.client.toJSON()})); - - this.$('.dynamically-registered').tooltip({title: $.t('grant.grant-table.dynamically-registered')}); - this.$('.tokens').tooltip({title: $.t('grant.grant-table.active-tokens')}); - $(this.el).i18n(); + $('.scope-list', this.el).html(this.scopeTemplate({ + scopes: this.model.get('allowedScopes'), + systemScopes: this.options.systemScopeList + })); + + $('.client-more-info-block', this.el).html(this.moreInfoTemplate({ + client: this.options.client.toJSON() + })); + + this.$('.dynamically-registered').tooltip({ + title: $.t('grant.grant-table.dynamically-registered') + }); + this.$('.tokens').tooltip({ + title: $.t('grant.grant-table.active-tokens') + }); + $(this.el).i18n(); return this; }, - + events: { 'click .btn-delete': 'deleteApprovedSite', 'click .toggleMoreInformation': 'toggleMoreInformation' }, - - deleteApprovedSite:function(e) { - e.preventDefault(); + + deleteApprovedSite: function(e) { + e.preventDefault(); if (confirm("Are you sure you want to revoke access to this site?")) { var self = this; - - this.model.destroy({ - dataType: false, processData: false, - success:function () { - self.$el.fadeTo("fast", 0.00, function () { //fade - $(this).slideUp("fast", function () { //slide up - $(this).remove(); //then remove from the DOM - self.parentView.togglePlaceholder(); - }); - }); - }, - error:app.errorHandlerView.handleError() - }); - - this.parentView.delegateEvents(); + + this.model.destroy({ + dataType: false, + processData: false, + success: function() { + self.$el.fadeTo("fast", 0.00, function() { // fade + $(this).slideUp("fast", function() { // slide up + $(this).remove(); // then remove from the DOM + self.parentView.togglePlaceholder(); + }); + }); + }, + error: app.errorHandlerView.handleError() + }); + + this.parentView.delegateEvents(); } - + return false; }, - - toggleMoreInformation:function(e) { + + toggleMoreInformation: function(e) { e.preventDefault(); if ($('.moreInformation', this.el).is(':visible')) { // hide it $('.moreInformation', this.el).hide('fast'); $('.toggleMoreInformation i', this.el).attr('class', 'icon-chevron-right'); $('.moreInformationContainer', this.el).removeClass('alert').removeClass('alert-info').addClass('muted'); - + } else { // show it $('.moreInformation', this.el).show('fast'); @@ -251,36 +288,44 @@ var ApprovedSiteView = Backbone.View.extend({ $('.moreInformationContainer', this.el).addClass('alert').addClass('alert-info').removeClass('muted'); } }, - - close:function() { + + close: function() { $(this.el).unbind(); $(this.el).empty(); } }); -ui.routes.push({path: "user/approved", name: "approvedSites", callback: - +ui.routes.push({ + path: "user/approved", + name: "approvedSites", + callback: + function() { this.breadCrumbView.collection.reset(); - this.breadCrumbView.collection.add([ - {text:$.t('admin.home'), href:""}, - {text:$.t('grant.manage-approved-sites'), href:"manage/#user/approve"} - ]); - - this.updateSidebar('user/approved'); - - var view = new ApprovedSiteListView({model:this.approvedSiteList, clientList: this.clientList, systemScopeList: this.systemScopeList}); - view.load( - function(collection, response, options) { - $('#content').html(view.render().el); - setPageTitle($.t('grant.manage-approved-sites')); - } - ); + this.breadCrumbView.collection.add([{ + text: $.t('admin.home'), + href: "" + }, { + text: $.t('grant.manage-approved-sites'), + href: "manage/#user/approve" + }]); + + this.updateSidebar('user/approved'); + + var view = new ApprovedSiteListView({ + model: this.approvedSiteList, + clientList: this.clientList, + systemScopeList: this.systemScopeList + }); + view.load(function(collection, response, options) { + $('#content').html(view.render().el); + setPageTitle($.t('grant.manage-approved-sites')); + }); } }); ui.templates.push('resources/template/grant.html'); ui.init.push(function(app) { - app.approvedSiteList = new ApprovedSiteCollection(); + app.approvedSiteList = new ApprovedSiteCollection(); }); diff --git a/openid-connect-server-webapp/src/main/webapp/resources/js/profile.js b/openid-connect-server-webapp/src/main/webapp/resources/js/profile.js index e9fd39ffe..87b402d14 100644 --- a/openid-connect-server-webapp/src/main/webapp/resources/js/profile.js +++ b/openid-connect-server-webapp/src/main/webapp/resources/js/profile.js @@ -14,21 +14,28 @@ * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ -ui.routes.push({path: "user/profile", name: "profile", callback: - function() { +ui.routes.push({ + path: "user/profile", + name: "profile", + callback: function() { - this.breadCrumbView.collection.reset(); - this.breadCrumbView.collection.add([ - {text:$.t('admin.home'), href:""}, - {text:$.t('admin.user-profile.show'), href:"manage/#user/profile"} - ]); - - this.updateSidebar('user/profile'); - - var view = new UserProfileView({model: getUserInfo()}); - $('#content').html(view.render().el); - - setPageTitle($.t('admin.user-profile.show')); - - } + this.breadCrumbView.collection.reset(); + this.breadCrumbView.collection.add([{ + text: $.t('admin.home'), + href: "" + }, { + text: $.t('admin.user-profile.show'), + href: "manage/#user/profile" + }]); + + this.updateSidebar('user/profile'); + + var view = new UserProfileView({ + model: getUserInfo() + }); + $('#content').html(view.render().el); + + setPageTitle($.t('admin.user-profile.show')); + + } }); \ No newline at end of file diff --git a/openid-connect-server-webapp/src/main/webapp/resources/js/rsreg.js b/openid-connect-server-webapp/src/main/webapp/resources/js/rsreg.js index 3507c65ac..8713c583e 100644 --- a/openid-connect-server-webapp/src/main/webapp/resources/js/rsreg.js +++ b/openid-connect-server-webapp/src/main/webapp/resources/js/rsreg.js @@ -15,492 +15,565 @@ * limitations under the License. *******************************************************************************/ var ResRegClient = Backbone.Model.extend({ - idAttribute: "client_id", + idAttribute: "client_id", - defaults:{ - client_id:null, - client_secret:null, - client_name:null, - client_uri:null, - logo_uri:null, - contacts:[], - tos_uri:null, - token_endpoint_auth_method:null, - scope:null, - policy_uri:null, - - jwks_uri:null, - jwks:null, - jwksType:'URI', - - application_type:null, - registration_access_token:null, - registration_client_uri:null - }, - - sync: function(method, model, options){ - if (model.get('registration_access_token')) { - var headers = options.headers ? options.headers : {}; - headers['Authorization'] = 'Bearer ' + model.get('registration_access_token'); - options.headers = headers; - } - - return this.constructor.__super__.sync(method, model, options); - }, + defaults: { + client_id: null, + client_secret: null, + client_name: null, + client_uri: null, + logo_uri: null, + contacts: [], + tos_uri: null, + token_endpoint_auth_method: null, + scope: null, + policy_uri: null, + + jwks_uri: null, + jwks: null, + jwksType: 'URI', + + application_type: null, + registration_access_token: null, + registration_client_uri: null + }, + + sync: function(method, model, options) { + if (model.get('registration_access_token')) { + var headers = options.headers ? options.headers : {}; + headers['Authorization'] = 'Bearer ' + model.get('registration_access_token'); + options.headers = headers; + } + + return this.constructor.__super__.sync(method, model, options); + }, + + urlRoot: 'resource' - urlRoot:'resource' - }); var ResRegRootView = Backbone.View.extend({ - + tagName: 'span', - - initialize:function(options) { - this.options = options; - - }, - - events:{ - "click #newreg":"newReg", - "click #editreg":"editReg" - }, - - load:function(callback) { - if (this.options.systemScopeList.isFetched) { - callback(); - return; - } - $('#loadingbox').sheet('show'); - $('#loading').html('' + $.t('common.scopes') + ' '); + initialize: function(options) { + this.options = options; - $.when(this.options.systemScopeList.fetchIfNeeded({success:function(e) {$('#loading-scopes').addClass('label-success');}, error:app.errorHandlerView.handleError()})) - .done(function() { - $('#loadingbox').sheet('hide'); - callback(); - }); }, - - render:function() { - $(this.el).html($('#tmpl-rsreg').html()); - $(this.el).i18n(); - return this; + + events: { + "click #newreg": "newReg", + "click #editreg": "editReg" }, - - newReg:function(e) { - e.preventDefault(); - this.remove(); - app.navigate('dev/resource/new', {trigger: true}); + + load: function(callback) { + if (this.options.systemScopeList.isFetched) { + callback(); + return; + } + + $('#loadingbox').sheet('show'); + $('#loading').html('' + $.t('common.scopes') + ' '); + + $.when(this.options.systemScopeList.fetchIfNeeded({ + success: function(e) { + $('#loading-scopes').addClass('label-success'); + }, + error: app.errorHandlerView.handleError() + })).done(function() { + $('#loadingbox').sheet('hide'); + callback(); + }); }, - - editReg:function(e) { - e.preventDefault(); + + render: function() { + $(this.el).html($('#tmpl-rsreg').html()); + $(this.el).i18n(); + return this; + }, + + newReg: function(e) { + e.preventDefault(); + this.remove(); + app.navigate('dev/resource/new', { + trigger: true + }); + }, + + editReg: function(e) { + e.preventDefault(); var clientId = $('#clientId').val(); var token = $('#regtoken').val(); - + var client = new ResRegClient({ client_id: clientId, registration_access_token: token }); - + var self = this; - + client.fetch({ success: function() { - - if (client.get("jwks")) { - client.set({ - jwksType: "VAL" - }, { silent: true }); - } else { - client.set({ - jwksType: "URI" - }, { silent: true }); - } - - var view = new ResRegEditView({model: client, systemScopeList: app.systemScopeList}); - - view.load(function() { - $('#content').html(view.render().el); - view.delegateEvents(); - setPageTitle($.t('rsreg.new')); - app.navigate('dev/resource/edit', {trigger: true}); - self.remove(); - }); - }, - error:app.errorHandlerView.handleError({message: $.t('dynreg.invalid-access-token')}) + + if (client.get("jwks")) { + client.set({ + jwksType: "VAL" + }, { + silent: true + }); + } else { + client.set({ + jwksType: "URI" + }, { + silent: true + }); + } + + var view = new ResRegEditView({ + model: client, + systemScopeList: app.systemScopeList + }); + + view.load(function() { + $('#content').html(view.render().el); + view.delegateEvents(); + setPageTitle($.t('rsreg.new')); + app.navigate('dev/resource/edit', { + trigger: true + }); + self.remove(); + }); + }, + error: app.errorHandlerView.handleError({ + message: $.t('dynreg.invalid-access-token') + }) }); } - + }); var ResRegEditView = Backbone.View.extend({ - + tagName: 'span', - - initialize:function(options) { - this.options = options; - if (!this.template) { - this.template = _.template($('#tmpl-rsreg-resource-form').html()); - } - this.redirectUrisCollection = new Backbone.Collection(); - this.scopeCollection = new Backbone.Collection(); - this.contactsCollection = new Backbone.Collection(); - this.defaultAcrValuesCollection = new Backbone.Collection(); - this.requestUrisCollection = new Backbone.Collection(); - - this.listWidgetViews = []; - }, - - load:function(callback) { - if (this.options.systemScopeList.isFetched) { - callback(); - return; - } + initialize: function(options) { + this.options = options; + if (!this.template) { + this.template = _.template($('#tmpl-rsreg-resource-form').html()); + } - $('#loadingbox').sheet('show'); - $('#loading').html('' + $.t('common.scopes') + ' '); + this.redirectUrisCollection = new Backbone.Collection(); + this.scopeCollection = new Backbone.Collection(); + this.contactsCollection = new Backbone.Collection(); + this.defaultAcrValuesCollection = new Backbone.Collection(); + this.requestUrisCollection = new Backbone.Collection(); - $.when(this.options.systemScopeList.fetchIfNeeded({success:function(e) {$('#loading-scopes').addClass('label-success');}, error:app.errorHandlerView.handleError()})) - .done(function() { - $('#loadingbox').sheet('hide'); - callback(); - }); - }, - - events:{ - "click .btn-save":"saveClient", - "click .btn-cancel":"cancel", - "click .btn-delete":"deleteClient", - "change #logoUri input":"previewLogo", - "change #tokenEndpointAuthMethod input:radio":"toggleClientCredentials", - "change #jwkSelector input:radio":"toggleJWKSetType" - }, - - cancel:function(e) { - e.preventDefault(); - app.navigate('dev/resource', {trigger: true}); - }, - - deleteClient:function (e) { - e.preventDefault(); - - if (confirm($.t('client.client-table.confirm'))) { - var self = this; - - this.model.destroy({ - dataType: false, processData: false, - success:function () { - self.remove(); - app.navigate('dev/resource', {trigger: true}); - }, - error:app.errorHandlerView.handleError() - }); - - } - - return false; - }, - - previewLogo:function() { - if ($('#logoUri input', this.el).val()) { - $('#logoPreview', this.el).empty(); - $('#logoPreview', this.el).attr('src', $('#logoUri input', this.el).val()); - } else { - //$('#logoBlock', this.el).hide(); - $('#logoPreview', this.el).attr('src', 'resources/images/logo_placeholder.gif'); - } - }, - - /** - * Set up the form based on the current state of the tokenEndpointAuthMethod parameter - * @param event - */ - toggleClientCredentials:function() { - - var tokenEndpointAuthMethod = $('#tokenEndpointAuthMethod input', this.el).filter(':checked').val(); - - // show or hide the signing algorithm method depending on what's selected - if (tokenEndpointAuthMethod == 'private_key_jwt' - || tokenEndpointAuthMethod == 'client_secret_jwt') { - $('#tokenEndpointAuthSigningAlg', this.el).show(); - } else { - $('#tokenEndpointAuthSigningAlg', this.el).hide(); - } - }, - - /** - * Set up the form based on the JWK Set selector - */ - toggleJWKSetType:function() { - var jwkSelector = $('#jwkSelector input:radio', this.el).filter(':checked').val(); - - if (jwkSelector == 'URI') { - $('#jwksUri', this.el).show(); - $('#jwks', this.el).hide(); - } else if (jwkSelector == 'VAL') { - $('#jwksUri', this.el).hide(); - $('#jwks', this.el).show(); - } else { - $('#jwksUri', this.el).hide(); - $('#jwks', this.el).hide(); - } - - }, - - disableUnsupportedJOSEItems:function(serverSupported, query) { - var supported = ['default']; - if (serverSupported) { - supported = _.union(supported, serverSupported); - } - $(query, this.$el).each(function(idx) { - if(_.contains(supported, $(this).val())) { - $(this).prop('disabled', false); - } else { - $(this).prop('disabled', true); - } - }); - - }, - - // returns "null" if given the value "default" as a string, otherwise returns input value. useful for parsing the JOSE algorithm dropdowns - defaultToNull:function(value) { - if (value == 'default') { - return null; - } else { - return value; - } - }, - - saveClient:function (e) { - e.preventDefault(); - - $('.control-group').removeClass('error'); - - // sync any leftover collection items - _.each(this.listWidgetViews, function(v) { - v.addItem($.Event('click')); - }); - - // build the scope object - var scopes = this.scopeCollection.pluck("item").join(" "); - - var contacts = this.contactsCollection.pluck('item'); - var userInfo = getUserInfo(); - if (userInfo && userInfo.email) { - if (!_.contains(contacts, userInfo.email)) { - contacts.push(userInfo.email); - } - } - - // process the JWKS - var jwksUri = null; - var jwks = null; - var jwkSelector = $('#jwkSelector input:radio', this.el).filter(':checked').val(); - - if (jwkSelector == 'URI') { - jwksUri = $('#jwksUri input').val(); - jwks = null; - } else if (jwkSelector == 'VAL') { - jwksUri = null; - try { - jwks = JSON.parse($('#jwks textarea').val()); - } catch (e) { - console.log("An error occurred when parsing the JWK Set"); - - //Display an alert with an error message - app.errorHandlerView.showErrorMessage($.t("client.client-form.error.jwk-set"), $.t("client.client-form.error.jwk-set-parse")); - return false; - } - } else { - jwksUri = null; - jwks = null; - } - - var attrs = { - client_name:$('#clientName input').val(), - logo_uri:$('#logoUri input').val(), - scope: scopes, - client_secret: null, // never send a client secret - tos_uri: $('#tosUri input').val(), - policy_uri: $('#policyUri input').val(), - client_uri: $('#clientUri input').val(), - application_type: $('#applicationType input').filter(':checked').val(), - jwks_uri: jwksUri, - jwks: jwks, - token_endpoint_auth_method: $('#tokenEndpointAuthMethod input').filter(':checked').val(), - contacts: contacts, - token_endpoint_auth_signing_alg: this.defaultToNull($('#tokenEndpointAuthSigningAlg select').val()) - }; - - // set all empty strings to nulls - for (var key in attrs) { - if (attrs[key] === "") { - attrs[key] = null; - } - } - - var _self = this; - this.model.save(attrs, { - success:function () { - // switch to an "edit" view - app.navigate('dev/resource/edit', {trigger: true}); - _self.remove(); - - if (_self.model.get("jwks")) { - _self.model.set({ - jwksType: "VAL" - }, { silent: true }); - } else { - _self.model.set({ - jwksType: "URI" - }, { silent: true }); - } - - var view = new ResRegEditView({model: _self.model, systemScopeList: _self.options.systemScopeList}); - - view.load(function() { - // reload - $('#content').html(view.render().el); - view.delegateEvents(); - }); - }, - error:app.errorHandlerView.handleError() - }); - - return false; - }, - - render:function() { - $(this.el).html(this.template({client: this.model.toJSON(), userInfo: getUserInfo()})); - this.listWidgetViews = []; - + }, + + load: function(callback) { + if (this.options.systemScopeList.isFetched) { + callback(); + return; + } + + $('#loadingbox').sheet('show'); + $('#loading').html('' + $.t('common.scopes') + ' '); + + $.when(this.options.systemScopeList.fetchIfNeeded({ + success: function(e) { + $('#loading-scopes').addClass('label-success'); + }, + error: app.errorHandlerView.handleError() + })).done(function() { + $('#loadingbox').sheet('hide'); + callback(); + }); + }, + + events: { + "click .btn-save": "saveClient", + "click .btn-cancel": "cancel", + "click .btn-delete": "deleteClient", + "change #logoUri input": "previewLogo", + "change #tokenEndpointAuthMethod input:radio": "toggleClientCredentials", + "change #jwkSelector input:radio": "toggleJWKSetType" + }, + + cancel: function(e) { + e.preventDefault(); + app.navigate('dev/resource', { + trigger: true + }); + }, + + deleteClient: function(e) { + e.preventDefault(); + + if (confirm($.t('client.client-table.confirm'))) { + var self = this; + + this.model.destroy({ + dataType: false, + processData: false, + success: function() { + self.remove(); + app.navigate('dev/resource', { + trigger: true + }); + }, + error: app.errorHandlerView.handleError() + }); + + } + + return false; + }, + + previewLogo: function() { + if ($('#logoUri input', this.el).val()) { + $('#logoPreview', this.el).empty(); + $('#logoPreview', this.el).attr('src', $('#logoUri input', this.el).val()); + } else { + // $('#logoBlock', this.el).hide(); + $('#logoPreview', this.el).attr('src', 'resources/images/logo_placeholder.gif'); + } + }, + + /** + * Set up the form based on the current state of the tokenEndpointAuthMethod + * parameter + * + * @param event + */ + toggleClientCredentials: function() { + + var tokenEndpointAuthMethod = $('#tokenEndpointAuthMethod input', this.el).filter(':checked').val(); + + // show or hide the signing algorithm method depending on what's + // selected + if (tokenEndpointAuthMethod == 'private_key_jwt' || tokenEndpointAuthMethod == 'client_secret_jwt') { + $('#tokenEndpointAuthSigningAlg', this.el).show(); + } else { + $('#tokenEndpointAuthSigningAlg', this.el).hide(); + } + }, + + /** + * Set up the form based on the JWK Set selector + */ + toggleJWKSetType: function() { + var jwkSelector = $('#jwkSelector input:radio', this.el).filter(':checked').val(); + + if (jwkSelector == 'URI') { + $('#jwksUri', this.el).show(); + $('#jwks', this.el).hide(); + } else if (jwkSelector == 'VAL') { + $('#jwksUri', this.el).hide(); + $('#jwks', this.el).show(); + } else { + $('#jwksUri', this.el).hide(); + $('#jwks', this.el).hide(); + } + + }, + + disableUnsupportedJOSEItems: function(serverSupported, query) { + var supported = ['default']; + if (serverSupported) { + supported = _.union(supported, serverSupported); + } + $(query, this.$el).each(function(idx) { + if (_.contains(supported, $(this).val())) { + $(this).prop('disabled', false); + } else { + $(this).prop('disabled', true); + } + }); + + }, + + // returns "null" if given the value "default" as a string, + // otherwise returns input value. useful for parsing the JOSE + // algorithm dropdowns + defaultToNull: function(value) { + if (value == 'default') { + return null; + } else { + return value; + } + }, + + saveClient: function(e) { + e.preventDefault(); + + $('.control-group').removeClass('error'); + + // sync any leftover collection items + _.each(this.listWidgetViews, function(v) { + v.addItem($.Event('click')); + }); + + // build the scope object + var scopes = this.scopeCollection.pluck("item").join(" "); + + var contacts = this.contactsCollection.pluck('item'); + var userInfo = getUserInfo(); + if (userInfo && userInfo.email) { + if (!_.contains(contacts, userInfo.email)) { + contacts.push(userInfo.email); + } + } + + // process the JWKS + var jwksUri = null; + var jwks = null; + var jwkSelector = $('#jwkSelector input:radio', this.el).filter(':checked').val(); + + if (jwkSelector == 'URI') { + jwksUri = $('#jwksUri input').val(); + jwks = null; + } else if (jwkSelector == 'VAL') { + jwksUri = null; + try { + jwks = JSON.parse($('#jwks textarea').val()); + } catch (e) { + console.log("An error occurred when parsing the JWK Set"); + + // Display an alert with an error message + app.errorHandlerView.showErrorMessage($.t("client.client-form.error.jwk-set"), $.t("client.client-form.error.jwk-set-parse")); + return false; + } + } else { + jwksUri = null; + jwks = null; + } + + var attrs = { + client_name: $('#clientName input').val(), + logo_uri: $('#logoUri input').val(), + scope: scopes, + client_secret: null, // never send a client secret + tos_uri: $('#tosUri input').val(), + policy_uri: $('#policyUri input').val(), + client_uri: $('#clientUri input').val(), + application_type: $('#applicationType input').filter(':checked').val(), + jwks_uri: jwksUri, + jwks: jwks, + token_endpoint_auth_method: $('#tokenEndpointAuthMethod input').filter(':checked').val(), + contacts: contacts, + token_endpoint_auth_signing_alg: this.defaultToNull($('#tokenEndpointAuthSigningAlg select').val()) + }; + + // set all empty strings to nulls + for ( var key in attrs) { + if (attrs[key] === "") { + attrs[key] = null; + } + } + + var _self = this; + this.model.save(attrs, { + success: function() { + // switch to an "edit" view + app.navigate('dev/resource/edit', { + trigger: true + }); + _self.remove(); + + if (_self.model.get("jwks")) { + _self.model.set({ + jwksType: "VAL" + }, { + silent: true + }); + } else { + _self.model.set({ + jwksType: "URI" + }, { + silent: true + }); + } + + var view = new ResRegEditView({ + model: _self.model, + systemScopeList: _self.options.systemScopeList + }); + + view.load(function() { + // reload + $('#content').html(view.render().el); + view.delegateEvents(); + }); + }, + error: app.errorHandlerView.handleError() + }); + + return false; + }, + + render: function() { + $(this.el).html(this.template({ + client: this.model.toJSON(), + userInfo: getUserInfo() + })); + + this.listWidgetViews = []; + var _self = this; - // build and bind scopes - var scopes = this.model.get("scope"); - var scopeSet = scopes ? scopes.split(" ") : []; - _.each(scopeSet, function (scope) { - _self.scopeCollection.add(new Backbone.Model({item:scope})); - }); - - var scopeView = new ListWidgetView({ - placeholder: $.t('client.client-form.scope-placeholder'), - autocomplete: _.uniq(_.flatten(this.options.systemScopeList.unrestrictedScopes().pluck("value"))), - helpBlockText: $.t('rsreg.client-form.scope-help'), - collection: this.scopeCollection}); - $("#scope .controls",this.el).html(scopeView.render().el); - this.listWidgetViews.push(scopeView); - - // build and bind contacts - _.each(this.model.get('contacts'), function (contact) { - _self.contactsCollection.add(new Backbone.Model({item:contact})); - }); - - var contactView = new ListWidgetView({ - placeholder: $.t('client.client-form.contacts-placeholder'), - helpBlockText: $.t('client.client-form.contacts-help'), - collection: this.contactsCollection}); - $("#contacts .controls", this.el).html(contactView.render().el); - this.listWidgetViews.push(contactView); - - - this.toggleClientCredentials(); - this.previewLogo(); - this.toggleJWKSetType(); - - // disable unsupported JOSE algorithms - this.disableUnsupportedJOSEItems(app.serverConfiguration.token_endpoint_auth_signing_alg_values_supported, '#tokenEndpointAuthSigningAlg option'); - - this.$('.nyi').clickover({ - placement: 'right', - title: $.t('common.not-yet-implemented'), - content: $.t('common.not-yet-implemented-content') - }); - - - $(this.el).i18n(); - return this; - } - -}); - -ui.routes.push({path: "dev/resource", name: "resReg", callback: - function() { - - this.breadCrumbView.collection.reset(); - this.breadCrumbView.collection.add([ - {text:$.t('admin.home'), href:""}, - {text:$.t('admin.self-service-resource'), href:"manage/#dev/resource"} - ]); - - this.updateSidebar('dev/resource'); - - var view = new ResRegRootView({systemScopeList: this.systemScopeList}); - view.load(function() { - $('#content').html(view.render().el); - - setPageTitle($.t('admin.self-service-resource')); + // build and bind scopes + var scopes = this.model.get("scope"); + var scopeSet = scopes ? scopes.split(" ") : []; + _.each(scopeSet, function(scope) { + _self.scopeCollection.add(new Backbone.Model({ + item: scope + })); }); - + + var scopeView = new ListWidgetView({ + placeholder: $.t('client.client-form.scope-placeholder'), + autocomplete: _.uniq(_.flatten(this.options.systemScopeList.unrestrictedScopes().pluck("value"))), + helpBlockText: $.t('rsreg.client-form.scope-help'), + collection: this.scopeCollection + }); + $("#scope .controls", this.el).html(scopeView.render().el); + this.listWidgetViews.push(scopeView); + + // build and bind contacts + _.each(this.model.get('contacts'), function(contact) { + _self.contactsCollection.add(new Backbone.Model({ + item: contact + })); + }); + + var contactView = new ListWidgetView({ + placeholder: $.t('client.client-form.contacts-placeholder'), + helpBlockText: $.t('client.client-form.contacts-help'), + collection: this.contactsCollection + }); + $("#contacts .controls", this.el).html(contactView.render().el); + this.listWidgetViews.push(contactView); + + this.toggleClientCredentials(); + this.previewLogo(); + this.toggleJWKSetType(); + + // disable unsupported JOSE algorithms + this.disableUnsupportedJOSEItems(app.serverConfiguration.token_endpoint_auth_signing_alg_values_supported, '#tokenEndpointAuthSigningAlg option'); + + this.$('.nyi').clickover({ + placement: 'right', + title: $.t('common.not-yet-implemented'), + content: $.t('common.not-yet-implemented-content') + }); + + $(this.el).i18n(); + return this; + } + +}); + +ui.routes.push({ + path: "dev/resource", + name: "resReg", + callback: function() { + + this.breadCrumbView.collection.reset(); + this.breadCrumbView.collection.add([{ + text: $.t('admin.home'), + href: "" + }, { + text: $.t('admin.self-service-resource'), + href: "manage/#dev/resource" + }]); + + this.updateSidebar('dev/resource'); + + var view = new ResRegRootView({ + systemScopeList: this.systemScopeList + }); + view.load(function() { + $('#content').html(view.render().el); + + setPageTitle($.t('admin.self-service-resource')); + }); + } }); -ui.routes.push({path: "dev/resource/new", name: "newResReg", callback: - function() { - +ui.routes.push({ + path: "dev/resource/new", + name: "newResReg", + callback: function() { + this.breadCrumbView.collection.reset(); - this.breadCrumbView.collection.add([ - {text:$.t('admin.home'), href:""}, - {text:$.t('admin.self-service-resource'), href:"manage/#dev/resource"}, - {text:$.t('rsreg.new'), href:"manage/#dev/resource/new"} - ]); - - this.updateSidebar('dev/resource'); - + this.breadCrumbView.collection.add([{ + text: $.t('admin.home'), + href: "" + }, { + text: $.t('admin.self-service-resource'), + href: "manage/#dev/resource" + }, { + text: $.t('rsreg.new'), + href: "manage/#dev/resource/new" + }]); + + this.updateSidebar('dev/resource'); + var client = new ResRegClient(); - var view = new ResRegEditView({model: client, systemScopeList:this.systemScopeList}); - + var view = new ResRegEditView({ + model: client, + systemScopeList: this.systemScopeList + }); + view.load(function() { - + var userInfo = getUserInfo(); var contacts = []; if (userInfo != null && userInfo.email != null) { contacts.push(userInfo.email); } - + client.set({ - scope: _.uniq(_.flatten(app.systemScopeList.defaultUnrestrictedScopes().pluck("value"))).join(" "), - token_endpoint_auth_method: 'client_secret_basic', - contacts: contacts - }, { silent: true }); - + scope: _.uniq(_.flatten(app.systemScopeList.defaultUnrestrictedScopes().pluck("value"))).join(" "), + token_endpoint_auth_method: 'client_secret_basic', + contacts: contacts + }, { + silent: true + }); + $('#content').html(view.render().el); view.delegateEvents(); setPageTitle($.t('rsreg.new')); - + }); - + } }); -ui.routes.push({path: "dev/resource/edit", name: "editResReg", callback: - function() { +ui.routes.push({ + path: "dev/resource/edit", + name: "editResReg", + callback: function() { this.breadCrumbView.collection.reset(); - this.breadCrumbView.collection.add([ - {text:$.t('admin.home'), href:""}, - {text:$.t('admin.self-service-resource'), href:"manage/#dev/resource"}, - {text:$.t('rsreg.edit'), href:"manage/#dev/resource/edit"} - ]); - - this.updateSidebar('dev/resource'); - + this.breadCrumbView.collection.add([{ + text: $.t('admin.home'), + href: "" + }, { + text: $.t('admin.self-service-resource'), + href: "manage/#dev/resource" + }, { + text: $.t('rsreg.edit'), + href: "manage/#dev/resource/edit" + }]); + + this.updateSidebar('dev/resource'); + setPageTitle($.t('rsreg.edit')); - // note that this doesn't actually load the client, that's supposed to happen elsewhere... + // note that this doesn't actually load the client, that's supposed to + // happen elsewhere... } }); diff --git a/openid-connect-server-webapp/src/main/webapp/resources/js/scope.js b/openid-connect-server-webapp/src/main/webapp/resources/js/scope.js index aced6de28..867f89f8a 100644 --- a/openid-connect-server-webapp/src/main/webapp/resources/js/scope.js +++ b/openid-connect-server-webapp/src/main/webapp/resources/js/scope.js @@ -17,23 +17,23 @@ var SystemScopeModel = Backbone.Model.extend({ idAttribute: 'id', - defaults:{ - id:null, - description:null, - icon:null, - value:null, - defaultScope:false, - restricted:false + defaults: { + id: null, + description: null, + icon: null, + value: null, + defaultScope: false, + restricted: false }, - + urlRoot: 'api/scopes' }); var SystemScopeCollection = Backbone.Collection.extend({ idAttribute: 'id', - + model: SystemScopeModel, - + url: 'api/scopes', defaultScopes: function() { @@ -42,149 +42,164 @@ var SystemScopeCollection = Backbone.Collection.extend({ }); return new SystemScopeCollection(filtered); }, - + unrestrictedScopes: function() { filtered = this.filter(function(scope) { return scope.get("restricted") !== true; }); return new SystemScopeCollection(filtered); }, - + defaultUnrestrictedScopes: function() { filtered = this.filter(function(scope) { return scope.get("defaultScope") === true && scope.get("restricted") !== true; }); return new SystemScopeCollection(filtered); }, - + getByValue: function(value) { - var scopes = this.where({value: value}); + var scopes = this.where({ + value: value + }); if (scopes.length == 1) { return scopes[0]; } else { return null; } } - + }); var SystemScopeView = Backbone.View.extend({ - + tagName: 'tr', - - initialize:function (options) { - this.options = options; - if (!this.template) { - this.template = _.template($('#tmpl-system-scope').html()); - } + initialize: function(options) { + this.options = options; + + if (!this.template) { + this.template = _.template($('#tmpl-system-scope').html()); + } + + this.model.bind('change', this.render, this); - this.model.bind('change', this.render, this); - - }, - - events: { - 'click .btn-edit':'editScope', - 'click .btn-delete':'deleteScope' }, - - editScope:function(e) { - e.preventDefault(); - app.navigate('admin/scope/' + this.model.id, {trigger: true}); + + events: { + 'click .btn-edit': 'editScope', + 'click .btn-delete': 'deleteScope' }, - - render:function (eventName) { - this.$el.html(this.template(this.model.toJSON())); - $('.restricted', this.el).tooltip({title: $.t('scope.system-scope-table.tooltip-restricted')}); - $('.default', this.el).tooltip({title: $.t('scope.system-scope-table.tooltip-default')}); - - $(this.el).i18n(); - return this; - }, - - deleteScope:function (e) { - e.preventDefault(); + editScope: function(e) { + e.preventDefault(); + app.navigate('admin/scope/' + this.model.id, { + trigger: true + }); + }, - if (confirm($.t("scope.system-scope-table.confirm"))) { - var _self = this; + render: function(eventName) { + this.$el.html(this.template(this.model.toJSON())); - this.model.destroy({ - dataType: false, processData: false, - success:function () { - - _self.$el.fadeTo("fast", 0.00, function () { //fade - $(this).slideUp("fast", function () { //slide up - $(this).remove(); //then remove from the DOM - _self.parentView.togglePlaceholder(); - }); - }); - }, - error:app.errorHandlerView.handleError() - }); + $('.restricted', this.el).tooltip({ + title: $.t('scope.system-scope-table.tooltip-restricted') + }); + $('.default', this.el).tooltip({ + title: $.t('scope.system-scope-table.tooltip-default') + }); - _self.parentView.delegateEvents(); - } + $(this.el).i18n(); + return this; + }, - return false; - }, - - close:function () { - $(this.el).unbind(); - $(this.el).empty(); - } + deleteScope: function(e) { + e.preventDefault(); + + if (confirm($.t("scope.system-scope-table.confirm"))) { + var _self = this; + + this.model.destroy({ + dataType: false, + processData: false, + success: function() { + + _self.$el.fadeTo("fast", 0.00, function() { // fade + $(this).slideUp("fast", function() { // slide up + $(this).remove(); // then remove from the DOM + _self.parentView.togglePlaceholder(); + }); + }); + }, + error: app.errorHandlerView.handleError() + }); + + _self.parentView.delegateEvents(); + } + + return false; + }, + + close: function() { + $(this.el).unbind(); + $(this.el).empty(); + } }); var SystemScopeListView = Backbone.View.extend({ tagName: 'span', - - initialize:function(options) { - this.options = options; - }, - - load:function(callback) { - if (this.model.isFetched) { - callback(); - return; - } - $('#loadingbox').sheet('show'); - $('#loading').html( - '' + $.t('common.scopes') + ' ' - ); - - $.when(this.model.fetchIfNeeded({success:function(e) {$('#loading-scopes').addClass('label-success');}, error:app.errorHandlerView.handleError()})) - .done(function() { - $('#loadingbox').sheet('hide'); - callback(); - }); - }, - - events:{ - "click .new-scope":"newScope", - "click .refresh-table":"refreshTable" + initialize: function(options) { + this.options = options; }, - newScope:function(e) { + load: function(callback) { + if (this.model.isFetched) { + callback(); + return; + } + + $('#loadingbox').sheet('show'); + $('#loading').html('' + $.t('common.scopes') + ' '); + + $.when(this.model.fetchIfNeeded({ + success: function(e) { + $('#loading-scopes').addClass('label-success'); + }, + error: app.errorHandlerView.handleError() + })).done(function() { + $('#loadingbox').sheet('hide'); + callback(); + }); + }, + + events: { + "click .new-scope": "newScope", + "click .refresh-table": "refreshTable" + }, + + newScope: function(e) { this.remove(); - app.navigate('admin/scope/new', {trigger: true}); + app.navigate('admin/scope/new', { + trigger: true + }); }, - - refreshTable:function(e) { - var _self = this; - $('#loadingbox').sheet('show'); - $('#loading').html( - '' + $.t('common.scopes') + ' ' - ); - $.when(this.model.fetch({success:function(e) {$('#loading-scopes').addClass('label-success');}, error:app.errorHandlerView.handleError()})) - .done(function() { - $('#loadingbox').sheet('hide'); - _self.render(); - }); + refreshTable: function(e) { + var _self = this; + $('#loadingbox').sheet('show'); + $('#loading').html('' + $.t('common.scopes') + ' '); + + $.when(this.model.fetch({ + success: function(e) { + $('#loading-scopes').addClass('label-success'); + }, + error: app.errorHandlerView.handleError() + })).done(function() { + $('#loadingbox').sheet('hide'); + _self.render(); + }); }, - - togglePlaceholder:function() { + + togglePlaceholder: function() { if (this.model.length > 0) { $('#scope-table', this.el).show(); $('#scope-table-empty', this.el).hide(); @@ -193,249 +208,271 @@ var SystemScopeListView = Backbone.View.extend({ $('#scope-table-empty', this.el).show(); } }, - - render: function (eventName) { - + + render: function(eventName) { + // append and render the table structure $(this.el).html($('#tmpl-system-scope-table').html()); - + var _self = this; - - _.each(this.model.models, function (scope) { - var view = new SystemScopeView({model: scope}); + + _.each(this.model.models, function(scope) { + var view = new SystemScopeView({ + model: scope + }); view.parentView = _self; $("#scope-table", _self.el).append(view.render().el); }, this); - + this.togglePlaceholder(); - $(this.el).i18n(); + $(this.el).i18n(); return this; } }); -var SystemScopeFormView = Backbone.View.extend({ - tagName: 'span', - - initialize:function(options) { - this.options = options; - if (!this.template) { - this.template = _.template($('#tmpl-system-scope-form').html()); - } - if (!this.iconTemplate) { - this.iconTemplate = _.template($('#tmpl-system-scope-icon').html()); - } - - // initialize our icon set into slices for the selector - if (!this.bootstrapIcons) { - this.bootstrapIcons = []; - - var iconList = ['glass', 'music', 'search', 'envelope', 'heart', 'star', 'star-empty', - 'user', 'film', 'th-large', 'th', 'th-list', 'ok', 'remove', 'zoom-in', - 'zoom-out', 'off', 'signal', 'cog', 'trash', 'home', 'file', 'time', 'road', - 'download-alt', 'download', 'upload', 'inbox', 'play-circle', 'repeat', - 'refresh', 'list-alt', 'lock', 'flag', 'headphones', 'volume-off', - 'volume-down', 'volume-up', 'qrcode', 'barcode', 'tag', 'tags', 'book', - 'bookmark', 'print', 'camera', 'font', 'bold', 'italic', 'text-height', - 'text-width', 'align-left', 'align-center', 'align-right', 'align-justify', - 'list', 'indent-left', 'indent-right', 'facetime-video', 'picture', 'pencil', - 'map-marker', 'adjust', 'tint', 'edit', 'share', 'check', 'move', 'step-backward', - 'fast-backward', 'backward', 'play', 'pause', 'stop', 'forward', 'fast-forward', - 'step-forward', 'eject', 'chevron-left', 'chevron-right', 'plus-sign', - 'minus-sign', 'remove-sign', 'ok-sign', 'question-sign', 'info-sign', - 'screenshot', 'remove-circle', 'ok-circle', 'ban-circle', 'arrow-left', - 'arrow-right', 'arrow-up', 'arrow-down', 'share-alt', 'resize-full', 'resize-small', - 'plus', 'minus', 'asterisk', 'exclamation-sign', 'gift', 'leaf', 'fire', - 'eye-open', 'eye-close', 'warning-sign', 'plane', 'calendar', 'random', - 'comment', 'magnet', 'chevron-up', 'chevron-down', 'retweet', 'shopping-cart', - 'folder-close', 'folder-open', 'resize-vertical', 'resize-horizontal', - 'hdd', 'bullhorn', 'bell', 'certificate', 'thumbs-up', 'thumbs-down', - 'hand-right', 'hand-left', 'hand-up', 'hand-down', 'circle-arrow-right', - 'circle-arrow-left', 'circle-arrow-up', 'circle-arrow-down', 'globe', - 'wrench', 'tasks', 'filter', 'briefcase', 'fullscreen']; - - var size = 3; - while (iconList.length > 0) { - this.bootstrapIcons.push(iconList.splice(0, size)); - } +var SystemScopeFormView = Backbone.View + .extend({ + tagName: 'span', - } - }, - - events:{ - 'click .btn-save':'saveScope', - 'click .btn-cancel': function() {app.navigate('admin/scope', {trigger: true}); }, - 'click .btn-icon':'selectIcon' - }, - - load:function(callback) { - if (this.model.isFetched) { - callback(); - return; - } - - $('#loadingbox').sheet('show'); - $('#loading').html( - '' + $.t("common.scopes") + ' ' - ); + initialize: function(options) { + this.options = options; + if (!this.template) { + this.template = _.template($('#tmpl-system-scope-form').html()); + } + if (!this.iconTemplate) { + this.iconTemplate = _.template($('#tmpl-system-scope-icon').html()); + } - $.when(this.model.fetchIfNeeded({success:function(e) {$('#loading-scopes').addClass('label-success');}, error:app.errorHandlerView.handleError()})) - .done(function() { - $('#loadingbox').sheet('hide'); - callback(); - }); - - }, - - saveScope:function(e) { - e.preventDefault(); - - var value = $('#value input').val(); - - if (value == null || value.trim() == "") { - // error: can't have a blank scope - return false; - } - - var valid = this.model.set({ - value:value, - description:$('#description textarea').val(), - icon:$('#iconDisplay input').val(), - defaultScope:$('#defaultScope input').is(':checked'), - restricted:$('#restricted input').is(':checked') - }); - - if (valid) { - - var _self = this; - this.model.save({}, { - success:function() { - app.systemScopeList.add(_self.model); - app.navigate('admin/scope', {trigger: true}); + // initialize our icon set into slices for the selector + if (!this.bootstrapIcons) { + this.bootstrapIcons = []; + + var iconList = ['glass', 'music', 'search', 'envelope', 'heart', 'star', 'star-empty', 'user', 'film', 'th-large', 'th', 'th-list', 'ok', 'remove', 'zoom-in', 'zoom-out', 'off', 'signal', 'cog', 'trash', 'home', 'file', 'time', 'road', 'download-alt', 'download', 'upload', 'inbox', 'play-circle', 'repeat', 'refresh', 'list-alt', 'lock', + 'flag', 'headphones', 'volume-off', 'volume-down', 'volume-up', 'qrcode', 'barcode', 'tag', 'tags', 'book', 'bookmark', 'print', 'camera', 'font', 'bold', 'italic', 'text-height', 'text-width', 'align-left', 'align-center', 'align-right', 'align-justify', 'list', 'indent-left', 'indent-right', 'facetime-video', 'picture', + 'pencil', 'map-marker', 'adjust', 'tint', 'edit', 'share', 'check', 'move', 'step-backward', 'fast-backward', 'backward', 'play', 'pause', 'stop', 'forward', 'fast-forward', 'step-forward', 'eject', 'chevron-left', 'chevron-right', 'plus-sign', 'minus-sign', 'remove-sign', 'ok-sign', 'question-sign', 'info-sign', 'screenshot', + 'remove-circle', 'ok-circle', 'ban-circle', 'arrow-left', 'arrow-right', 'arrow-up', 'arrow-down', 'share-alt', 'resize-full', 'resize-small', 'plus', 'minus', 'asterisk', 'exclamation-sign', 'gift', 'leaf', 'fire', 'eye-open', 'eye-close', 'warning-sign', 'plane', 'calendar', 'random', 'comment', 'magnet', 'chevron-up', + 'chevron-down', 'retweet', 'shopping-cart', 'folder-close', 'folder-open', 'resize-vertical', 'resize-horizontal', 'hdd', 'bullhorn', 'bell', 'certificate', 'thumbs-up', 'thumbs-down', 'hand-right', 'hand-left', 'hand-up', 'hand-down', 'circle-arrow-right', 'circle-arrow-left', 'circle-arrow-up', 'circle-arrow-down', 'globe', + 'wrench', 'tasks', 'filter', 'briefcase', 'fullscreen']; + + var size = 3; + while (iconList.length > 0) { + this.bootstrapIcons.push(iconList.splice(0, size)); + } + + } + }, + + events: { + 'click .btn-save': 'saveScope', + 'click .btn-cancel': function() { + app.navigate('admin/scope', { + trigger: true + }); }, - error:app.errorHandlerView.handleError() - }); - } + 'click .btn-icon': 'selectIcon' + }, - return false; - }, - - selectIcon:function(e) { - e.preventDefault(); - - var icon = e.target.value; - - $('#iconDisplay input').val(icon); - $('#iconDisplay #iconName').html(icon); - $('#iconDisplay i').removeClass(); - $('#iconDisplay i').addClass('icon-' + icon); - $('#iconDisplay i').addClass('icon-white'); - - $('#iconSelector').modal('hide'); - - return false; - }, - - render: function(eventName) { - this.$el.html(this.template(this.model.toJSON())); - - _.each(this.bootstrapIcons, function (items) { - $("#iconSelector .modal-body", this.el).append(this.iconTemplate({items:items})); - }, this); - - $(this.el).i18n(); - return this; - } -}); + load: function(callback) { + if (this.model.isFetched) { + callback(); + return; + } + + $('#loadingbox').sheet('show'); + $('#loading').html('' + $.t("common.scopes") + ' '); + + $.when(this.model.fetchIfNeeded({ + success: function(e) { + $('#loading-scopes').addClass('label-success'); + }, + error: app.errorHandlerView.handleError() + })).done(function() { + $('#loadingbox').sheet('hide'); + callback(); + }); + + }, + + saveScope: function(e) { + e.preventDefault(); + + var value = $('#value input').val(); + + if (value == null || value.trim() == "") { + // error: can't have a blank scope + return false; + } + + var valid = this.model.set({ + value: value, + description: $('#description textarea').val(), + icon: $('#iconDisplay input').val(), + defaultScope: $('#defaultScope input').is(':checked'), + restricted: $('#restricted input').is(':checked') + }); + + if (valid) { + + var _self = this; + this.model.save({}, { + success: function() { + app.systemScopeList.add(_self.model); + app.navigate('admin/scope', { + trigger: true + }); + }, + error: app.errorHandlerView.handleError() + }); + } + + return false; + }, + + selectIcon: function(e) { + e.preventDefault(); + + var icon = e.target.value; + + $('#iconDisplay input').val(icon); + $('#iconDisplay #iconName').html(icon); + $('#iconDisplay i').removeClass(); + $('#iconDisplay i').addClass('icon-' + icon); + $('#iconDisplay i').addClass('icon-white'); + + $('#iconSelector').modal('hide'); + + return false; + }, + + render: function(eventName) { + this.$el.html(this.template(this.model.toJSON())); + + _.each(this.bootstrapIcons, function(items) { + $("#iconSelector .modal-body", this.el).append(this.iconTemplate({ + items: items + })); + }, this); + + $(this.el).i18n(); + return this; + } + }); + +ui.routes.push({ + path: "admin/scope", + name: "siteScope", + callback: function() { -ui.routes.push({path: "admin/scope", name: "siteScope", callback: - function() { - if (!isAdmin()) { this.root(); return; } - + this.breadCrumbView.collection.reset(); - this.breadCrumbView.collection.add([ - {text:$.t('admin.home'), href:""}, - {text:$.t('scope.manage'), href:"manage/#admin/scope"} - ]); - - this.updateSidebar('admin/scope'); - - var view = new SystemScopeListView({model:this.systemScopeList}); - + this.breadCrumbView.collection.add([{ + text: $.t('admin.home'), + href: "" + }, { + text: $.t('scope.manage'), + href: "manage/#admin/scope" + }]); + + this.updateSidebar('admin/scope'); + + var view = new SystemScopeListView({ + model: this.systemScopeList + }); + view.load(function() { $('#content').html(view.render().el); view.delegateEvents(); - setPageTitle($.t('scope.manage')); + setPageTitle($.t('scope.manage')); }); - + } }); -ui.routes.push({path: "admin/scope/new", name:"newScope", callback: - function() { - - +ui.routes.push({ + path: "admin/scope/new", + name: "newScope", + callback: function() { + if (!isAdmin()) { this.root(); return; } - + this.breadCrumbView.collection.reset(); - this.breadCrumbView.collection.add([ - {text:$.t('admin.home'), href:""}, - {text:$.t('scope.manage'), href:"manage/#admin/scope"}, - {text:$.t('scope.system-scope-form.new'), href:"manage/#admin/scope/new"} - ]); - - this.updateSidebar('admin/scope'); - + this.breadCrumbView.collection.add([{ + text: $.t('admin.home'), + href: "" + }, { + text: $.t('scope.manage'), + href: "manage/#admin/scope" + }, { + text: $.t('scope.system-scope-form.new'), + href: "manage/#admin/scope/new" + }]); + + this.updateSidebar('admin/scope'); + var scope = new SystemScopeModel(); - - var view = new SystemScopeFormView({model:scope}); + + var view = new SystemScopeFormView({ + model: scope + }); view.load(function() { $('#content').html(view.render().el); setPageTitle($.t('scope.system-scope-form.new')); }); - + } }); -ui.routes.push({path: "admin/scope/:id", name: "editScope", callback: - function(sid) { +ui.routes.push({ + path: "admin/scope/:id", + name: "editScope", + callback: function(sid) { if (!isAdmin()) { this.root(); return; } - + this.breadCrumbView.collection.reset(); - this.breadCrumbView.collection.add([ - {text:$.t('admin.home'), href:""}, - {text:$.t('scope.manage'), href:"manage/#admin/scope"}, - {text:$.t('scope.system-scope-form.edit'), href:"manage/#admin/scope/" + sid} - ]); - - this.updateSidebar('admin/scope'); - + this.breadCrumbView.collection.add([{ + text: $.t('admin.home'), + href: "" + }, { + text: $.t('scope.manage'), + href: "manage/#admin/scope" + }, { + text: $.t('scope.system-scope-form.edit'), + href: "manage/#admin/scope/" + sid + }]); + + this.updateSidebar('admin/scope'); + var scope = this.systemScopeList.get(sid); if (!scope) { - scope = new SystemScopeModel({id: sid}); + scope = new SystemScopeModel({ + id: sid + }); } - - var view = new SystemScopeFormView({model:scope}); + + var view = new SystemScopeFormView({ + model: scope + }); view.load(function() { $('#content').html(view.render().el); setPageTitle($.t('scope.system-scope-form.new')); }); - + } }); ui.templates.push('resources/template/scope.html'); ui.init.push(function(app) { - app.systemScopeList = new SystemScopeCollection(); + app.systemScopeList = new SystemScopeCollection(); }); diff --git a/openid-connect-server-webapp/src/main/webapp/resources/js/token.js b/openid-connect-server-webapp/src/main/webapp/resources/js/token.js index ed012a620..36112eb3c 100644 --- a/openid-connect-server-webapp/src/main/webapp/resources/js/token.js +++ b/openid-connect-server-webapp/src/main/webapp/resources/js/token.js @@ -18,59 +18,59 @@ var AccessTokenModel = Backbone.Model.extend({ idAttribute: 'id', - defaults:{ - id:null, - value:null, - refreshTokenId:null, - scopes:[], - clientId:null, - userId:null, - expiration:null + defaults: { + id: null, + value: null, + refreshTokenId: null, + scopes: [], + clientId: null, + userId: null, + expiration: null }, - + urlRoot: 'api/tokens/access' }); var AccessTokenCollection = Backbone.Collection.extend({ idAttribute: 'id', - + model: AccessTokenModel, - + url: 'api/tokens/access' - + }); var AccessTokenView = Backbone.View.extend({ - + tagName: 'tr', - - initialize:function (options) { - this.options = options; - if (!this.template) { - this.template = _.template($('#tmpl-access-token').html()); - } + initialize: function(options) { + this.options = options; - if (!this.scopeTemplate) { - this.scopeTemplate = _.template($('#tmpl-scope-list').html()); - } + if (!this.template) { + this.template = _.template($('#tmpl-access-token').html()); + } - if (!this.moreInfoTemplate) { - this.moreInfoTemplate = _.template($('#tmpl-client-more-info-block').html()); - } + if (!this.scopeTemplate) { + this.scopeTemplate = _.template($('#tmpl-scope-list').html()); + } - this.model.bind('change', this.render, this); - - }, - - events: { - 'click .btn-delete':'deleteToken', - 'click .token-substring':'showTokenValue', + if (!this.moreInfoTemplate) { + this.moreInfoTemplate = _.template($('#tmpl-client-more-info-block').html()); + } + + this.model.bind('change', this.render, this); + + }, + + events: { + 'click .btn-delete': 'deleteToken', + 'click .token-substring': 'showTokenValue', 'click .toggleMoreInformation': 'toggleMoreInformation' }, - - render:function (eventName) { - + + render: function(eventName) { + var expirationDate = this.model.get("expiration"); if (expirationDate == null) { @@ -80,59 +80,70 @@ var AccessTokenView = Backbone.View.extend({ } else { expirationDate = moment(expirationDate).calendar(); } - - var json = {token: this.model.toJSON(), client: this.options.client.toJSON(), formattedExpiration: expirationDate}; + + var json = { + token: this.model.toJSON(), + client: this.options.client.toJSON(), + formattedExpiration: expirationDate + }; this.$el.html(this.template(json)); // hide full value - $('.token-full', this.el).hide(); - + $('.token-full', this.el).hide(); + // show scopes - $('.scope-list', this.el).html(this.scopeTemplate({scopes: this.model.get('scopes'), systemScopes: this.options.systemScopeList})); - - $('.client-more-info-block', this.el).html(this.moreInfoTemplate({client: this.options.client.toJSON()})); + $('.scope-list', this.el).html(this.scopeTemplate({ + scopes: this.model.get('scopes'), + systemScopes: this.options.systemScopeList + })); - $(this.el).i18n(); - return this; - }, - - deleteToken:function (e) { - e.preventDefault(); + $('.client-more-info-block', this.el).html(this.moreInfoTemplate({ + client: this.options.client.toJSON() + })); - if (confirm($.t("token.token-table.confirm"))) { - - var _self = this; + $(this.el).i18n(); + return this; + }, - this.model.destroy({ - dataType: false, processData: false, - success:function () { - - _self.$el.fadeTo("fast", 0.00, function () { //fade - $(this).slideUp("fast", function () { //slide up - $(this).remove(); //then remove from the DOM - // refresh the table in case we removed an id token, too - _self.parentView.refreshTable(); - }); - }); - }, - error:app.errorHandlerView.handleError() - }); + deleteToken: function(e) { + e.preventDefault(); - this.parentView.delegateEvents(); - } + if (confirm($.t("token.token-table.confirm"))) { - return false; - }, - - toggleMoreInformation:function(e) { + var _self = this; + + this.model.destroy({ + dataType: false, + processData: false, + success: function() { + + _self.$el.fadeTo("fast", 0.00, function() { // fade + $(this).slideUp("fast", function() { // slide up + $(this).remove(); // then remove from the DOM + // refresh the table in case we removed an id token, + // too + _self.parentView.refreshTable(); + }); + }); + }, + error: app.errorHandlerView.handleError() + }); + + this.parentView.delegateEvents(); + } + + return false; + }, + + toggleMoreInformation: function(e) { e.preventDefault(); if ($('.moreInformation', this.el).is(':visible')) { // hide it $('.moreInformation', this.el).hide('fast'); $('.toggleMoreInformation i', this.el).attr('class', 'icon-chevron-right'); $('.moreInformationContainer', this.el).removeClass('alert').removeClass('alert-info').addClass('muted'); - + } else { // show it $('.moreInformation', this.el).show('fast'); @@ -141,73 +152,73 @@ var AccessTokenView = Backbone.View.extend({ } }, - close:function () { - $(this.el).unbind(); - $(this.el).empty(); - }, - - showTokenValue:function (e) { - e.preventDefault(); - $('.token-substring', this.el).hide(); - $('.token-full', this.el).show(); - } + close: function() { + $(this.el).unbind(); + $(this.el).empty(); + }, + + showTokenValue: function(e) { + e.preventDefault(); + $('.token-substring', this.el).hide(); + $('.token-full', this.el).show(); + } }); var RefreshTokenModel = Backbone.Model.extend({ idAttribute: 'id', - defaults:{ - id:null, - value:null, - scopes:[], - clientId:null, - userId:null, - expiration:null + defaults: { + id: null, + value: null, + scopes: [], + clientId: null, + userId: null, + expiration: null }, - + urlRoot: 'api/tokens/refresh' }); var RefreshTokenCollection = Backbone.Collection.extend({ idAttribute: 'id', - + model: RefreshTokenModel, - + url: 'api/tokens/refresh' - + }); var RefreshTokenView = Backbone.View.extend({ - + tagName: 'tr', - - initialize:function (options) { - this.options = options; - if (!this.template) { - this.template = _.template($('#tmpl-refresh-token').html()); - } + initialize: function(options) { + this.options = options; - if (!this.scopeTemplate) { - this.scopeTemplate = _.template($('#tmpl-scope-list').html()); - } + if (!this.template) { + this.template = _.template($('#tmpl-refresh-token').html()); + } - if (!this.moreInfoTemplate) { - this.moreInfoTemplate = _.template($('#tmpl-client-more-info-block').html()); - } + if (!this.scopeTemplate) { + this.scopeTemplate = _.template($('#tmpl-scope-list').html()); + } - this.model.bind('change', this.render, this); - - }, - - events: { - 'click .btn-delete':'deleteToken', - 'click .token-substring':'showTokenValue', + if (!this.moreInfoTemplate) { + this.moreInfoTemplate = _.template($('#tmpl-client-more-info-block').html()); + } + + this.model.bind('change', this.render, this); + + }, + + events: { + 'click .btn-delete': 'deleteToken', + 'click .token-substring': 'showTokenValue', 'click .toggleMoreInformation': 'toggleMoreInformation' }, - - render:function (eventName) { - + + render: function(eventName) { + var expirationDate = this.model.get("expiration"); if (expirationDate == null) { @@ -217,53 +228,65 @@ var RefreshTokenView = Backbone.View.extend({ } else { expirationDate = moment(expirationDate).calendar(); } - - var json = {token: this.model.toJSON(), client: this.options.client.toJSON(), formattedExpiration: expirationDate, accessTokenCount: this.options.accessTokenCount}; + + var json = { + token: this.model.toJSON(), + client: this.options.client.toJSON(), + formattedExpiration: expirationDate, + accessTokenCount: this.options.accessTokenCount + }; this.$el.html(this.template(json)); // hide full value - $('.token-full', this.el).hide(); - + $('.token-full', this.el).hide(); + // show scopes - $('.scope-list', this.el).html(this.scopeTemplate({scopes: this.model.get('scopes'), systemScopes: this.options.systemScopeList})); - - $('.client-more-info-block', this.el).html(this.moreInfoTemplate({client: this.options.client.toJSON()})); - - $(this.el).i18n(); - return this; + $('.scope-list', this.el).html(this.scopeTemplate({ + scopes: this.model.get('scopes'), + systemScopes: this.options.systemScopeList + })); - }, - - deleteToken:function (e) { - e.preventDefault(); + $('.client-more-info-block', this.el).html(this.moreInfoTemplate({ + client: this.options.client.toJSON() + })); - if (confirm($.t('token.token-table.confirm-refresh'))) { - - var _self = this; + $(this.el).i18n(); + return this; - this.model.destroy({ - dataType: false, processData: false, - success:function () { - - _self.$el.fadeTo("fast", 0.00, function () { //fade - $(this).slideUp("fast", function () { //slide up - $(this).remove(); //then remove from the DOM - // refresh the table in case the access tokens have changed, too - _self.parentView.refreshTable(); - }); - }); - }, - error:app.errorHandlerView.handleError() - }); + }, - _self.parentView.delegateEvents(); - } + deleteToken: function(e) { + e.preventDefault(); - return false; - }, - - toggleMoreInformation:function(e) { + if (confirm($.t('token.token-table.confirm-refresh'))) { + + var _self = this; + + this.model.destroy({ + dataType: false, + processData: false, + success: function() { + + _self.$el.fadeTo("fast", 0.00, function() { // fade + $(this).slideUp("fast", function() { // slide up + $(this).remove(); // then remove from the DOM + // refresh the table in case the access tokens have + // changed, too + _self.parentView.refreshTable(); + }); + }); + }, + error: app.errorHandlerView.handleError() + }); + + _self.parentView.delegateEvents(); + } + + return false; + }, + + toggleMoreInformation: function(e) { e.preventDefault(); if ($('.moreInformation', this.el).is(':visible')) { // hide it @@ -279,101 +302,128 @@ var RefreshTokenView = Backbone.View.extend({ }, - close:function () { - $(this.el).unbind(); - $(this.el).empty(); - }, - - showTokenValue:function (e) { - e.preventDefault(); - $('.token-substring', this.el).hide(); - $('.token-full', this.el).show(); - } + close: function() { + $(this.el).unbind(); + $(this.el).empty(); + }, + + showTokenValue: function(e) { + e.preventDefault(); + $('.token-substring', this.el).hide(); + $('.token-full', this.el).show(); + } }); var TokenListView = Backbone.View.extend({ tagName: 'span', - - initialize:function(options) { - this.options = options; - }, - - events:{ - "click .refresh-table":"refreshTable", - 'page .paginator-access':'changePageAccess', - 'page .paginator-refresh':'changePageRefresh' + + initialize: function(options) { + this.options = options; }, - load:function(callback) { - if (this.model.access.isFetched && - this.model.refresh.isFetched && - this.options.clientList.isFetched && - this.options.systemScopeList.isFetched) { - callback(); - return; - } + events: { + "click .refresh-table": "refreshTable", + 'page .paginator-access': 'changePageAccess', + 'page .paginator-refresh': 'changePageRefresh' + }, - $('#loadingbox').sheet('show'); - $('#loading').html( - '' + $.t('token.token-table.access-tokens') + ' ' + - '' + $.t('token.token-table.refresh-tokens') + ' ' + - '' + $.t('common.clients') + ' ' + - '' + $.t('common.scopes') + ' ' - ); + load: function(callback) { + if (this.model.access.isFetched && this.model.refresh.isFetched && this.options.clientList.isFetched && this.options.systemScopeList.isFetched) { + callback(); + return; + } - $.when(this.model.access.fetchIfNeeded({success:function(e) {$('#loading-access').addClass('label-success');}, error: app.errorHandlerView.handleError()}), - this.model.refresh.fetchIfNeeded({success:function(e) {$('#loading-refresh').addClass('label-success');}, error: app.errorHandlerView.handleError()}), - this.options.clientList.fetchIfNeeded({success:function(e) {$('#loading-clients').addClass('label-success');}, error: app.errorHandlerView.handleError()}), - this.options.systemScopeList.fetchIfNeeded({success:function(e) {$('#loading-scopes').addClass('label-success');}, error: app.errorHandlerView.handleError()})) - .done(function() { - $('#loadingbox').sheet('hide'); - callback(); - }); - - }, + $('#loadingbox').sheet('show'); + $('#loading').html( + '' + $.t('token.token-table.access-tokens') + ' ' + '' + $.t('token.token-table.refresh-tokens') + ' ' + '' + $.t('common.clients') + ' ' + '' + + $.t('common.scopes') + ' '); - changePageAccess:function(event, num) { - $('.paginator-access', this.el).bootpag({page: num}); + $.when(this.model.access.fetchIfNeeded({ + success: function(e) { + $('#loading-access').addClass('label-success'); + }, + error: app.errorHandlerView.handleError() + }), this.model.refresh.fetchIfNeeded({ + success: function(e) { + $('#loading-refresh').addClass('label-success'); + }, + error: app.errorHandlerView.handleError() + }), this.options.clientList.fetchIfNeeded({ + success: function(e) { + $('#loading-clients').addClass('label-success'); + }, + error: app.errorHandlerView.handleError() + }), this.options.systemScopeList.fetchIfNeeded({ + success: function(e) { + $('#loading-scopes').addClass('label-success'); + }, + error: app.errorHandlerView.handleError() + })).done(function() { + $('#loadingbox').sheet('hide'); + callback(); + }); + + }, + + changePageAccess: function(event, num) { + $('.paginator-access', this.el).bootpag({ + page: num + }); $('#access-token-table tbody tr', this.el).each(function(index, element) { if (Math.ceil((index + 1) / 10) != num) { - $(element).hide(); - } else { - $(element).show(); - } + $(element).hide(); + } else { + $(element).show(); + } }); }, - - changePageRefresh:function(event, num) { - $('.paginator-refresh', this.el).bootpag({page: num}); + + changePageRefresh: function(event, num) { + $('.paginator-refresh', this.el).bootpag({ + page: num + }); $('#refresh-token-table tbody tr', this.el).each(function(index, element) { if (Math.ceil((index + 1) / 10) != num) { - $(element).hide(); - } else { - $(element).show(); - } + $(element).hide(); + } else { + $(element).show(); + } }); }, - - refreshTable:function(e) { - $('#loadingbox').sheet('show'); - $('#loading').html( - '' + $.t('token.token-table.access-tokens') + ' ' + - '' + $.t('token.token-table.refresh-tokens') + ' ' + - '' + $.t('common.clients') + ' ' + - '' + $.t('common.scopes') + ' ' - ); - var _self = this; - $.when(this.model.access.fetch({success:function(e) {$('#loading-access').addClass('label-success');}, error: app.errorHandlerView.handleError()}), - this.model.refresh.fetch({success:function(e) {$('#loading-refresh').addClass('label-success');}, error: app.errorHandlerView.handleError()}), - this.options.clientList.fetch({success:function(e) {$('#loading-clients').addClass('label-success');}, error: app.errorHandlerView.handleError()}), - this.options.systemScopeList.fetch({success:function(e) {$('#loading-scopes').addClass('label-success');}, error: app.errorHandlerView.handleError()})) - .done(function(){ - _self.render(); - $('#loadingbox').sheet('hide'); - }); + + refreshTable: function(e) { + $('#loadingbox').sheet('show'); + $('#loading').html( + '' + $.t('token.token-table.access-tokens') + ' ' + '' + $.t('token.token-table.refresh-tokens') + ' ' + '' + $.t('common.clients') + ' ' + '' + + $.t('common.scopes') + ' '); + var _self = this; + $.when(this.model.access.fetch({ + success: function(e) { + $('#loading-access').addClass('label-success'); + }, + error: app.errorHandlerView.handleError() + }), this.model.refresh.fetch({ + success: function(e) { + $('#loading-refresh').addClass('label-success'); + }, + error: app.errorHandlerView.handleError() + }), this.options.clientList.fetch({ + success: function(e) { + $('#loading-clients').addClass('label-success'); + }, + error: app.errorHandlerView.handleError() + }), this.options.systemScopeList.fetch({ + success: function(e) { + $('#loading-scopes').addClass('label-success'); + }, + error: app.errorHandlerView.handleError() + })).done(function() { + _self.render(); + $('#loadingbox').sheet('hide'); + }); }, - - togglePlaceholder:function() { + + togglePlaceholder: function() { if (this.model.access.length > 0) { $('#access-token-table', this.el).show(); $('#access-token-table-empty', this.el).hide(); @@ -388,122 +438,140 @@ var TokenListView = Backbone.View.extend({ $('#refresh-token-table', this.el).hide(); $('#refresh-token-table-empty', this.el).show(); } - + $('#access-token-count', this.el).html(this.model.access.length); $('#refresh-token-count', this.el).html(this.model.refresh.length); }, - - render: function (eventName) { - + + render: function(eventName) { + // append and render the table structure $(this.el).html($('#tmpl-token-table').html()); - - var _self = this; - - // set up pagination - var numPagesAccess = Math.ceil(this.model.access.length / 10); - if (numPagesAccess > 1) { - $('.paginator-access', this.el).show(); - $('.paginator-access', this.el).bootpag({ - total: numPagesAccess, - page: 1 - }); - } else { - $('.paginator-access', this.el).hide(); - } - // count up refresh tokens - var refreshCount = {}; - - _.each(this.model.access.models, function (token, index) { + var _self = this; + + // set up pagination + var numPagesAccess = Math.ceil(this.model.access.length / 10); + if (numPagesAccess > 1) { + $('.paginator-access', this.el).show(); + $('.paginator-access', this.el).bootpag({ + total: numPagesAccess, + page: 1 + }); + } else { + $('.paginator-access', this.el).hide(); + } + + // count up refresh tokens + var refreshCount = {}; + + _.each(this.model.access.models, function(token, index) { // look up client var client = _self.options.clientList.getByClientId(token.get('clientId')); - var view = new AccessTokenView({model: token, client: client, systemScopeList: _self.options.systemScopeList}); + var view = new AccessTokenView({ + model: token, + client: client, + systemScopeList: _self.options.systemScopeList + }); view.parentView = _self; var element = view.render().el; $('#access-token-table', _self.el).append(element); - if (Math.ceil((index + 1) / 10) != 1) { - $(element).hide(); - } - - //console.log(token.get('refreshTokenId')); - var refId = token.get('refreshTokenId'); - if (refId != null) { - if (refreshCount[refId]) { - refreshCount[refId] += 1; - } else { - refreshCount[refId] = 1; - } - - } + if (Math.ceil((index + 1) / 10) != 1) { + $(element).hide(); + } + + // console.log(token.get('refreshTokenId')); + var refId = token.get('refreshTokenId'); + if (refId != null) { + if (refreshCount[refId]) { + refreshCount[refId] += 1; + } else { + refreshCount[refId] = 1; + } + + } }); - //console.log(refreshCount); - - // set up pagination - var numPagesRefresh = Math.ceil(this.model.refresh.length / 10); - if (numPagesRefresh > 1) { - $('.paginator-refresh', this.el).show(); - $('.paginator-refresh', this.el).bootpag({ - total: numPagesRefresh, - page: 1 - }); - } else { - $('.paginator-refresh', this.el).hide(); - } + // console.log(refreshCount); - _.each(this.model.refresh.models, function (token, index) { + // set up pagination + var numPagesRefresh = Math.ceil(this.model.refresh.length / 10); + if (numPagesRefresh > 1) { + $('.paginator-refresh', this.el).show(); + $('.paginator-refresh', this.el).bootpag({ + total: numPagesRefresh, + page: 1 + }); + } else { + $('.paginator-refresh', this.el).hide(); + } + + _.each(this.model.refresh.models, function(token, index) { // look up client var client = _self.options.clientList.getByClientId(token.get('clientId')); - var view = new RefreshTokenView({model: token, client: client, systemScopeList: _self.options.systemScopeList, accessTokenCount: refreshCount[token.get('id')]}); + var view = new RefreshTokenView({ + model: token, + client: client, + systemScopeList: _self.options.systemScopeList, + accessTokenCount: refreshCount[token.get('id')] + }); view.parentView = _self; var element = view.render().el; $('#refresh-token-table', _self.el).append(element); - if (Math.ceil((index + 1) / 10) != 1) { - $(element).hide(); - } + if (Math.ceil((index + 1) / 10) != 1) { + $(element).hide(); + } }); - -/* - _.each(this.model.models, function (scope) { - $("#scope-table", this.el).append(new SystemScopeView({model: scope}).render().el); - }, this); -*/ - + + /* + * _.each(this.model.models, function (scope) { $("#scope-table", + * this.el).append(new SystemScopeView({model: scope}).render().el); }, + * this); + */ + this.togglePlaceholder(); - $(this.el).i18n(); + $(this.el).i18n(); return this; } }); - -ui.routes.push({path: "user/tokens", name: "tokens", callback: - function() { +ui.routes.push({ + path: "user/tokens", + name: "tokens", + callback: function() { this.breadCrumbView.collection.reset(); - this.breadCrumbView.collection.add([ - {text:$.t('admin.home'), href:""}, - {text:$.t('token.manage'), href:"manage/#user/tokens"} - ]); - - this.updateSidebar('user/tokens'); - - var view = new TokenListView({model: {access: this.accessTokensList, refresh: this.refreshTokensList}, clientList: this.clientList, systemScopeList: this.systemScopeList}); - - view.load( - function(collection, response, options) { - $('#content').html(view.render().el); - setPageTitle($.t('token.manage')); - } - ); - + this.breadCrumbView.collection.add([{ + text: $.t('admin.home'), + href: "" + }, { + text: $.t('token.manage'), + href: "manage/#user/tokens" + }]); + + this.updateSidebar('user/tokens'); + + var view = new TokenListView({ + model: { + access: this.accessTokensList, + refresh: this.refreshTokensList + }, + clientList: this.clientList, + systemScopeList: this.systemScopeList + }); + + view.load(function(collection, response, options) { + $('#content').html(view.render().el); + setPageTitle($.t('token.manage')); + }); + } }); ui.templates.push('resources/template/token.html'); ui.init.push(function(app) { - app.accessTokensList = new AccessTokenCollection(); - app.refreshTokensList = new RefreshTokenCollection(); + app.accessTokensList = new AccessTokenCollection(); + app.refreshTokensList = new RefreshTokenCollection(); }); diff --git a/openid-connect-server-webapp/src/main/webapp/resources/js/whitelist.js b/openid-connect-server-webapp/src/main/webapp/resources/js/whitelist.js index 8441bdebd..293bf669e 100644 --- a/openid-connect-server-webapp/src/main/webapp/resources/js/whitelist.js +++ b/openid-connect-server-webapp/src/main/webapp/resources/js/whitelist.js @@ -15,94 +15,107 @@ * limitations under the License. *******************************************************************************/ var WhiteListModel = Backbone.Model.extend({ - + idAttribute: "id", - - initialize: function () { }, - + + initialize: function() { + }, + urlRoot: "api/whitelist" - + }); var WhiteListCollection = Backbone.Collection.extend({ initialize: function() { - //this.fetch(); + // this.fetch(); }, - - getByClientId: function(clientId) { - var clients = this.where({clientId: clientId}); + + getByClientId: function(clientId) { + var clients = this.where({ + clientId: clientId + }); if (clients.length == 1) { return clients[0]; } else { return null; } - }, - + }, + model: WhiteListModel, url: "api/whitelist" - + }); var WhiteListListView = Backbone.View.extend({ tagName: 'span', - - initialize:function (options) { - this.options = options; + + initialize: function(options) { + this.options = options; }, - load:function(callback) { - if (this.model.isFetched && - this.options.clientList.isFetched && - this.options.systemScopeList.isFetched) { - callback(); - return; - } + load: function(callback) { + if (this.model.isFetched && this.options.clientList.isFetched && this.options.systemScopeList.isFetched) { + callback(); + return; + } - $('#loadingbox').sheet('show'); - $('#loading').html( - '' + $.t('whitelist.whitelist') + ' ' + - '' + $.t('common.clients') + ' ' + - '' + $.t('common.scopes') + ' ' - ); + $('#loadingbox').sheet('show'); + $('#loading').html('' + $.t('whitelist.whitelist') + ' ' + '' + $.t('common.clients') + ' ' + '' + $.t('common.scopes') + ' '); - $.when(this.model.fetchIfNeeded({success:function(e) {$('#loading-whitelist').addClass('label-success');}, error: app.errorHandlerView.handleError()}), - this.options.clientList.fetchIfNeeded({success:function(e) {$('#loading-clients').addClass('label-success');}, error: app.errorHandlerView.handleError()}), - this.options.systemScopeList.fetchIfNeeded({success:function(e) {$('#loading-scopes').addClass('label-success');}, error: app.errorHandlerView.handleError()})) - .done(function() { - $('#loadingbox').sheet('hide'); - callback(); - }); - }, - - events:{ - "click .refresh-table":"refreshTable" + $.when(this.model.fetchIfNeeded({ + success: function(e) { + $('#loading-whitelist').addClass('label-success'); + }, + error: app.errorHandlerView.handleError() + }), this.options.clientList.fetchIfNeeded({ + success: function(e) { + $('#loading-clients').addClass('label-success'); + }, + error: app.errorHandlerView.handleError() + }), this.options.systemScopeList.fetchIfNeeded({ + success: function(e) { + $('#loading-scopes').addClass('label-success'); + }, + error: app.errorHandlerView.handleError() + })).done(function() { + $('#loadingbox').sheet('hide'); + callback(); + }); }, - - render:function (eventName) { + + events: { + "click .refresh-table": "refreshTable" + }, + + render: function(eventName) { $(this.el).html($('#tmpl-whitelist-table').html()); - + var _self = this; - - _.each(this.model.models, function (whiteList) { - + + _.each(this.model.models, function(whiteList) { + // look up client var client = _self.options.clientList.getByClientId(whiteList.get('clientId')); - + // if there's no client ID, this is an error! if (client != null) { - var view = new WhiteListView({model: whiteList, client: client, systemScopeList: _self.options.systemScopeList}); + var view = new WhiteListView({ + model: whiteList, + client: client, + systemScopeList: _self.options.systemScopeList + }); view.parentView = _self; $('#whitelist-table', _self.el).append(view.render().el); } - + }, this); this.togglePlaceholder(); - $(this.el).i18n(); + $(this.el).i18n(); return this; }, - togglePlaceholder:function() { + togglePlaceholder: function() { if (this.model.length > 0) { $('#whitelist-table', this.el).show(); $('#whitelist-table-empty', this.el).hide(); @@ -111,108 +124,129 @@ var WhiteListListView = Backbone.View.extend({ $('#whitelist-table-empty', this.el).show(); } }, - - refreshTable:function(e) { - e.preventDefault(); - var _self = this; - $('#loadingbox').sheet('show'); - $('#loading').html( - '' + $.t('whitelist.whitelist') + ' ' + - '' + $.t('common.clients') + ' ' + - '' + $.t('common.scopes') + ' ' - ); - $.when(this.model.fetch({success:function(e) {$('#loading-whitelist').addClass('label-success');}, error: app.errorHandlerView.handleError()}), - this.options.clientList.fetch({success:function(e) {$('#loading-clients').addClass('label-success');}, error: app.errorHandlerView.handleError()}), - this.options.systemScopeList.fetch({success:function(e) {$('#loading-scopes').addClass('label-success');}, error: app.errorHandlerView.handleError()})) - .done(function() { - $('#loadingbox').sheet('hide'); - _self.render(); - }); - } + refreshTable: function(e) { + e.preventDefault(); + var _self = this; + $('#loadingbox').sheet('show'); + $('#loading').html('' + $.t('whitelist.whitelist') + ' ' + '' + $.t('common.clients') + ' ' + '' + $.t('common.scopes') + ' '); + + $.when(this.model.fetch({ + success: function(e) { + $('#loading-whitelist').addClass('label-success'); + }, + error: app.errorHandlerView.handleError() + }), this.options.clientList.fetch({ + success: function(e) { + $('#loading-clients').addClass('label-success'); + }, + error: app.errorHandlerView.handleError() + }), this.options.systemScopeList.fetch({ + success: function(e) { + $('#loading-scopes').addClass('label-success'); + }, + error: app.errorHandlerView.handleError() + })).done(function() { + $('#loadingbox').sheet('hide'); + _self.render(); + }); + } }); var WhiteListView = Backbone.View.extend({ tagName: 'tr', - - initialize:function(options) { - this.options = options; + + initialize: function(options) { + this.options = options; if (!this.template) { this.template = _.template($('#tmpl-whitelist').html()); } - - if (!this.scopeTemplate) { - this.scopeTemplate = _.template($('#tmpl-scope-list').html()); - } - if (!this.moreInfoTemplate) { - this.moreInfoTemplate = _.template($('#tmpl-client-more-info-block').html()); - } + if (!this.scopeTemplate) { + this.scopeTemplate = _.template($('#tmpl-scope-list').html()); + } + + if (!this.moreInfoTemplate) { + this.moreInfoTemplate = _.template($('#tmpl-client-more-info-block').html()); + } this.model.bind('change', this.render, this); }, - - render:function(eventName) { - - var json = {whiteList: this.model.toJSON(), client: this.options.client.toJSON()}; - + + render: function(eventName) { + + var json = { + whiteList: this.model.toJSON(), + client: this.options.client.toJSON() + }; + this.$el.html(this.template(json)); - $('.scope-list', this.el).html(this.scopeTemplate({scopes: this.model.get('allowedScopes'), systemScopes: this.options.systemScopeList})); - - $('.client-more-info-block', this.el).html(this.moreInfoTemplate({client: this.options.client.toJSON()})); - - this.$('.dynamically-registered').tooltip({title: $.t('common.dynamically-registered')}); + $('.scope-list', this.el).html(this.scopeTemplate({ + scopes: this.model.get('allowedScopes'), + systemScopes: this.options.systemScopeList + })); - $(this.el).i18n(); - return this; + $('.client-more-info-block', this.el).html(this.moreInfoTemplate({ + client: this.options.client.toJSON() + })); + + this.$('.dynamically-registered').tooltip({ + title: $.t('common.dynamically-registered') + }); + + $(this.el).i18n(); + return this; }, - - events:{ + + events: { 'click .btn-edit': 'editWhitelist', 'click .btn-delete': 'deleteWhitelist', 'click .toggleMoreInformation': 'toggleMoreInformation' }, - - editWhitelist:function(e) { - e.preventDefault(); - app.navigate('admin/whitelist/' + this.model.get('id'), {trigger: true}); + + editWhitelist: function(e) { + e.preventDefault(); + app.navigate('admin/whitelist/' + this.model.get('id'), { + trigger: true + }); }, - - deleteWhitelist:function(e) { - e.preventDefault(); - + + deleteWhitelist: function(e) { + e.preventDefault(); + if (confirm($.t('whitelist.confirm'))) { var _self = this; - - this.model.destroy({ - dataType: false, processData: false, - success:function () { - _self.$el.fadeTo("fast", 0.00, function () { //fade - $(this).slideUp("fast", function () { //slide up - $(this).remove(); //then remove from the DOM - // check the placeholder in case it's empty now - _self.parentView.togglePlaceholder(); - }); - }); - }, - error:app.errorHandlerView.handleError() - }); - - _self.parentView.delegateEvents(); + + this.model.destroy({ + dataType: false, + processData: false, + success: function() { + _self.$el.fadeTo("fast", 0.00, function() { // fade + $(this).slideUp("fast", function() { // slide up + $(this).remove(); // then remove from the DOM + // check the placeholder in case it's empty now + _self.parentView.togglePlaceholder(); + }); + }); + }, + error: app.errorHandlerView.handleError() + }); + + _self.parentView.delegateEvents(); } - + return false; }, - - toggleMoreInformation:function(e) { + + toggleMoreInformation: function(e) { e.preventDefault(); if ($('.moreInformation', this.el).is(':visible')) { // hide it $('.moreInformation', this.el).hide('fast'); $('.toggleMoreInformation i', this.el).attr('class', 'icon-chevron-right'); $('.moreInformationContainer', this.el).removeClass('alert').removeClass('alert-info').addClass('muted'); - + } else { // show it $('.moreInformation', this.el).show('fast'); @@ -221,7 +255,7 @@ var WhiteListView = Backbone.View.extend({ } }, - close:function() { + close: function() { $(this.el).unbind(); $(this.el).empty(); } @@ -229,278 +263,333 @@ var WhiteListView = Backbone.View.extend({ var WhiteListFormView = Backbone.View.extend({ tagName: 'span', - - initialize:function (options) { - this.options = options; + + initialize: function(options) { + this.options = options; if (!this.template) { this.template = _.template($('#tmpl-whitelist-form').html()); } - + this.scopeCollection = new Backbone.Collection(); this.listWidgetViews = []; - + }, - load:function(callback) { + load: function(callback) { if (this.options.client) { // we know what client we're dealing with already - if (this.model.isFetched && - this.options.client.isFetched) { - callback(); - return; - } - - $('#loadingbox').sheet('show'); - $('#loading').html( - '' + $.t('whitelist.whitelist') + ' ' + - '' + $.t('common.clients') + ' ' + - '' + $.t('common.scopes') + ' ' - ); + if (this.model.isFetched && this.options.client.isFetched) { + callback(); + return; + } + + $('#loadingbox').sheet('show'); + $('#loading').html('' + $.t('whitelist.whitelist') + ' ' + '' + $.t('common.clients') + ' ' + '' + $.t('common.scopes') + ' '); + + $.when(this.model.fetchIfNeeded({ + success: function(e) { + $('#loading-whitelist').addClass('label-success'); + }, + error: app.errorHandlerView.handleError() + }), this.options.client.fetchIfNeeded({ + success: function(e) { + $('#loading-clients').addClass('label-success'); + }, + error: app.errorHandlerView.handleError() + }), this.options.systemScopeList.fetchIfNeeded({ + success: function(e) { + $('#loading-scopes').addClass('label-success'); + }, + error: app.errorHandlerView.handleError() + })).done(function() { + $('#loadingbox').sheet('hide'); + callback(); + }); - $.when(this.model.fetchIfNeeded({success:function(e) {$('#loading-whitelist').addClass('label-success');}, error: app.errorHandlerView.handleError()}), - this.options.client.fetchIfNeeded({success:function(e) {$('#loading-clients').addClass('label-success');}, error: app.errorHandlerView.handleError()}), - this.options.systemScopeList.fetchIfNeeded({success:function(e) {$('#loading-scopes').addClass('label-success');}, error: app.errorHandlerView.handleError()})) - .done(function() { - $('#loadingbox').sheet('hide'); - callback(); - }); - } else { // we need to get the client information from the list - - if (this.model.isFetched && - this.options.clientList.isFetched && - this.options.systemScopeList.isFetched) { - + + if (this.model.isFetched && this.options.clientList.isFetched && this.options.systemScopeList.isFetched) { + var client = this.options.clientList.getByClientId(this.model.get('clientId')); this.options.client = client; - - callback(); - return; - } - $('#loadingbox').sheet('show'); - $('#loading').html( - '' + $.t('whitelist.whitelist') + ' ' + - '' + $.t('common.clients') + ' ' + - '' + $.t('common.scopes') + ' ' - ); + callback(); + return; + } + + $('#loadingbox').sheet('show'); + $('#loading').html('' + $.t('whitelist.whitelist') + ' ' + '' + $.t('common.clients') + ' ' + '' + $.t('common.scopes') + ' '); + + var _self = this; + + $.when(this.model.fetchIfNeeded({ + success: function(e) { + $('#loading-whitelist').addClass('label-success'); + }, + error: app.errorHandlerView.handleError() + }), this.options.clientList.fetchIfNeeded({ + success: function(e) { + $('#loading-clients').addClass('label-success'); + }, + error: app.errorHandlerView.handleError() + }), this.options.systemScopeList.fetchIfNeeded({ + success: function(e) { + $('#loading-scopes').addClass('label-success'); + }, + error: app.errorHandlerView.handleError() + })).done(function() { + + var client = _self.options.clientList.getByClientId(_self.model.get('clientId')); + _self.options.client = client; + + $('#loadingbox').sheet('hide'); + callback(); + }); - var _self = this; - - $.when(this.model.fetchIfNeeded({success:function(e) {$('#loading-whitelist').addClass('label-success');}, error: app.errorHandlerView.handleError()}), - this.options.clientList.fetchIfNeeded({success:function(e) {$('#loading-clients').addClass('label-success');}, error: app.errorHandlerView.handleError()}), - this.options.systemScopeList.fetchIfNeeded({success:function(e) {$('#loading-scopes').addClass('label-success');}, error: app.errorHandlerView.handleError()})) - .done(function() { - - var client = _self.options.clientList.getByClientId(_self.model.get('clientId')); - _self.options.client = client; - - $('#loadingbox').sheet('hide'); - callback(); - }); - } - - - }, - - events:{ - 'click .btn-save':'saveWhiteList', - 'click .btn-cancel':'cancelWhiteList', - + + events: { + 'click .btn-save': 'saveWhiteList', + 'click .btn-cancel': 'cancelWhiteList', + }, - - saveWhiteList:function (e) { - e.preventDefault(); + + saveWhiteList: function(e) { + e.preventDefault(); $('.control-group').removeClass('error'); - - // sync any leftover collection items - _.each(this.listWidgetViews, function(v) { - v.addItem($.Event('click')); - }); - + + // sync any leftover collection items + _.each(this.listWidgetViews, function(v) { + v.addItem($.Event('click')); + }); + // process allowed scopes - var allowedScopes = this.scopeCollection.pluck("item"); - - this.model.set({clientId: this.options.client.get('clientId')}, {silent: true}); - + var allowedScopes = this.scopeCollection.pluck("item"); + + this.model.set({ + clientId: this.options.client.get('clientId') + }, { + silent: true + }); + var valid = this.model.set({ allowedScopes: allowedScopes }); - - if (valid) { - var _self = this; - this.model.save({}, { - success:function () { - app.whiteListList.add(_self.model); - app.navigate('admin/whitelists', {trigger:true}); - }, - error:app.errorHandlerView.handleError() - }); - } - return false; - + if (valid) { + var _self = this; + this.model.save({}, { + success: function() { + app.whiteListList.add(_self.model); + app.navigate('admin/whitelists', { + trigger: true + }); + }, + error: app.errorHandlerView.handleError() + }); + } + + return false; + }, - - cancelWhiteList:function(e) { - e.preventDefault(); - // TODO: figure out where we came from and go back there instead - if (this.model.get('id') == null) { - // if it's a new whitelist entry, go back to the client listing page - app.navigate('admin/clients', {trigger:true}); - } else { - // if we're editing a whitelist, go back to the whitelists page - app.navigate('admin/whitelists', {trigger:true}); - } + + cancelWhiteList: function(e) { + e.preventDefault(); + // TODO: figure out where we came from and go back there instead + if (this.model.get('id') == null) { + // if it's a new whitelist entry, go back to the client listing page + app.navigate('admin/clients', { + trigger: true + }); + } else { + // if we're editing a whitelist, go back to the whitelists page + app.navigate('admin/whitelists', { + trigger: true + }); + } }, - - render:function (eventName) { - - var json = {whiteList: this.model.toJSON(), client: this.options.client.toJSON()}; - + + render: function(eventName) { + + var json = { + whiteList: this.model.toJSON(), + client: this.options.client.toJSON() + }; + this.$el.html(this.template(json)); - - this.listWidgetViews = []; - - var _self = this; - // build and bind scopes - _.each(this.model.get("allowedScopes"), function (scope) { - _self.scopeCollection.add(new Backbone.Model({item:scope})); - }); - var scopeView = new ListWidgetView({ - placeholder: $.t('whitelist.whitelist-form.scope-placeholder'), - autocomplete: this.options.client.get("scope"), - helpBlockText: $.t('whitelist.whitelist-form.scope-help'), - collection: this.scopeCollection}); - $("#scope .controls",this.el).html(scopeView.render().el); - this.listWidgetViews.push(scopeView); - - $(this.el).i18n(); + this.listWidgetViews = []; + + var _self = this; + // build and bind scopes + _.each(this.model.get("allowedScopes"), function(scope) { + _self.scopeCollection.add(new Backbone.Model({ + item: scope + })); + }); + + var scopeView = new ListWidgetView({ + placeholder: $.t('whitelist.whitelist-form.scope-placeholder'), + autocomplete: this.options.client.get("scope"), + helpBlockText: $.t('whitelist.whitelist-form.scope-help'), + collection: this.scopeCollection + }); + $("#scope .controls", this.el).html(scopeView.render().el); + this.listWidgetViews.push(scopeView); + + $(this.el).i18n(); return this; } }); - -ui.routes.push({path: "admin/whitelists", name: "whiteList", callback: - function () { +ui.routes.push({ + path: "admin/whitelists", + name: "whiteList", + callback: function() { if (!isAdmin()) { this.root(); return; } - - this.updateSidebar('admin/whitelists'); - - this.breadCrumbView.collection.reset(); - this.breadCrumbView.collection.add([ - {text:$.t('admin.home'), href:""}, - {text:$.t('whitelist.manage'), href:"manage/#admin/whitelists"} - ]); - - var view = new WhiteListListView({model:this.whiteListList, clientList: this.clientList, systemScopeList: this.systemScopeList}); - - view.load( - function() { - $('#content').html(view.render().el); - view.delegateEvents(); - setPageTitle($.t('whitelist.manage')); - } - ); - - + + this.updateSidebar('admin/whitelists'); + + this.breadCrumbView.collection.reset(); + this.breadCrumbView.collection.add([{ + text: $.t('admin.home'), + href: "" + }, { + text: $.t('whitelist.manage'), + href: "manage/#admin/whitelists" + }]); + + var view = new WhiteListListView({ + model: this.whiteListList, + clientList: this.clientList, + systemScopeList: this.systemScopeList + }); + + view.load(function() { + $('#content').html(view.render().el); + view.delegateEvents(); + setPageTitle($.t('whitelist.manage')); + }); + } }); -ui.routes.push({path: "admin/whitelist/new/:cid", name: "newWhitelist", callback: - function(cid) { - +ui.routes.push({ + path: "admin/whitelist/new/:cid", + name: "newWhitelist", + callback: function(cid) { if (!isAdmin()) { this.root(); return; } - + this.breadCrumbView.collection.reset(); - this.breadCrumbView.collection.add([ - {text:$.t('admin.home'), href:""}, - {text:$.t('whitelist.manage'), href:"manage/#admin/whitelists"}, - {text:$.t('whitelist.new'), href:"manage/#admin/whitelist/new/" + cid} - ]); - - this.updateSidebar('admin/whitelists'); - - var whiteList = new WhiteListModel(); - - var client = this.clientList.get(cid); - if (!client) { - client = new ClientModel({id: cid}); - } - - var view = new WhiteListFormView({model: whiteList, client: client, systemScopeList: this.systemScopeList}); - - view.load( - function() { - - // set the scopes on the model now that everything's loaded - whiteList.set({allowedScopes: client.get('scope')}, {silent: true}); - - $('#content').html(view.render().el); - view.delegateEvents(); - setPageTitle($.t('whitelist.manage')); - } - ); - + this.breadCrumbView.collection.add([{ + text: $.t('admin.home'), + href: "" + }, { + text: $.t('whitelist.manage'), + href: "manage/#admin/whitelists" + }, { + text: $.t('whitelist.new'), + href: "manage/#admin/whitelist/new/" + cid + }]); + + this.updateSidebar('admin/whitelists'); + + var whiteList = new WhiteListModel(); + + var client = this.clientList.get(cid); + if (!client) { + client = new ClientModel({ + id: cid + }); + } + + var view = new WhiteListFormView({ + model: whiteList, + client: client, + systemScopeList: this.systemScopeList + }); + + view.load(function() { + + // set the scopes on the model now that everything's loaded + whiteList.set({ + allowedScopes: client.get('scope') + }, { + silent: true + }); + + $('#content').html(view.render().el); + view.delegateEvents(); + setPageTitle($.t('whitelist.manage')); + }); + } }); - -ui.routes.push({path: "admin/whitelist/:id", name: "editWhitelist", callback: - function(id) { +ui.routes.push({ + path: "admin/whitelist/:id", + name: "editWhitelist", + callback: function(id) { if (!isAdmin()) { this.root(); return; } - + this.breadCrumbView.collection.reset(); - this.breadCrumbView.collection.add([ - {text:$.t('admin.home'), href:""}, - {text:$.t('whitelist.manage'), href:"manage/#admin/whitelists"}, - {text:$.t('whitelist.edit'), href:"manage/#admin/whitelist/" + id} - ]); - - this.updateSidebar('admin/whitelists'); - - var whiteList = this.whiteListList.get(id); - if (!whiteList) { - whiteList = new WhiteListModel({id: id}); - } - - var view = new WhiteListFormView({model: whiteList, clientList: this.clientList, systemScopeList: this.systemScopeList}); - - view.load( - function() { - $('#content').html(view.render().el); - view.delegateEvents(); - setPageTitle($.t('whitelist.manage')); - } - ); - + this.breadCrumbView.collection.add([{ + text: $.t('admin.home'), + href: "" + }, { + text: $.t('whitelist.manage'), + href: "manage/#admin/whitelists" + }, { + text: $.t('whitelist.edit'), + href: "manage/#admin/whitelist/" + id + }]); + + this.updateSidebar('admin/whitelists'); + + var whiteList = this.whiteListList.get(id); + if (!whiteList) { + whiteList = new WhiteListModel({ + id: id + }); + } + + var view = new WhiteListFormView({ + model: whiteList, + clientList: this.clientList, + systemScopeList: this.systemScopeList + }); + + view.load(function() { + $('#content').html(view.render().el); + view.delegateEvents(); + setPageTitle($.t('whitelist.manage')); + }); + } - + }); ui.templates.push('resources/template/whitelist.html'); ui.init.push(function(app) { - app.whiteListList = new WhiteListCollection(); + app.whiteListList = new WhiteListCollection(); });