From feb38eef8cad7a45e28e5d20ffcdd04c8aa2b98f Mon Sep 17 00:00:00 2001 From: Mario Zupan Date: Thu, 1 Dec 2016 19:28:28 +0100 Subject: [PATCH] Issue #160: Provide Async Error Handling Added Toast notification for unexpected errors On 401 and 403 Errors, user is redirected to login --- .../webgoat/AjaxAuthenticationEntryPoint.java | 58 +++++++++++++++++++ .../org/owasp/webgoat/WebSecurityConfig.java | 1 + .../src/main/resources/static/css/main.css | 19 ++++++ .../resources/static/js/goatApp/goatApp.js | 5 +- .../goatApp/support/goatAsyncErrorHandler.js | 34 +++++++++++ .../js/goatApp/view/ErrorNotificationView.js | 35 +++++++++++ .../js/goatApp/view/LessonContentView.js | 7 ++- .../main/resources/templates/main_new.html | 5 ++ 8 files changed, 160 insertions(+), 4 deletions(-) create mode 100644 webgoat-container/src/main/java/org/owasp/webgoat/AjaxAuthenticationEntryPoint.java create mode 100644 webgoat-container/src/main/resources/static/js/goatApp/support/goatAsyncErrorHandler.js create mode 100644 webgoat-container/src/main/resources/static/js/goatApp/view/ErrorNotificationView.js diff --git a/webgoat-container/src/main/java/org/owasp/webgoat/AjaxAuthenticationEntryPoint.java b/webgoat-container/src/main/java/org/owasp/webgoat/AjaxAuthenticationEntryPoint.java new file mode 100644 index 000000000..3c2cfdce7 --- /dev/null +++ b/webgoat-container/src/main/java/org/owasp/webgoat/AjaxAuthenticationEntryPoint.java @@ -0,0 +1,58 @@ +/** + * ************************************************************************************************* + *

+ *

+ * This file is part of WebGoat, an Open Web Application Security Project + * utility. For details, please see http://www.owasp.org/ + *

+ * Copyright (c) 2002 - 20014 Bruce Mayhew + *

+ * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + *

+ * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + *

+ * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307, USA. + *

+ * Getting Source ============== + *

+ * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository + * for free software projects. + */ + +package org.owasp.webgoat; + +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +/** + *

LabelService class.

+ * + * @author zupzup + */ + +public class AjaxAuthenticationEntryPoint extends LoginUrlAuthenticationEntryPoint { + public AjaxAuthenticationEntryPoint(String loginFormUrl) { + super(loginFormUrl); + } + + public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException { + if(request.getHeader("x-requested-with") != null) { + response.sendError(401, authException.getMessage()); + } else { + super.commence(request, response, authException); + } + } +} diff --git a/webgoat-container/src/main/java/org/owasp/webgoat/WebSecurityConfig.java b/webgoat-container/src/main/java/org/owasp/webgoat/WebSecurityConfig.java index 51a9eecbf..92f5a4bd4 100644 --- a/webgoat-container/src/main/java/org/owasp/webgoat/WebSecurityConfig.java +++ b/webgoat-container/src/main/java/org/owasp/webgoat/WebSecurityConfig.java @@ -68,6 +68,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { security.and().csrf().disable(); http.headers().cacheControl().disable(); + http.exceptionHandling().authenticationEntryPoint(new AjaxAuthenticationEntryPoint("/login")); } //// TODO: 11/18/2016 make this a little bit more configurabe last part at least diff --git a/webgoat-container/src/main/resources/static/css/main.css b/webgoat-container/src/main/resources/static/css/main.css index 5a91c4a34..98237b084 100644 --- a/webgoat-container/src/main/resources/static/css/main.css +++ b/webgoat-container/src/main/resources/static/css/main.css @@ -977,4 +977,23 @@ font-size: 1.3em; border: 2px solid #a66; border-radius: 12px; padding: 7px; +} + +/* ERROR NOTIFICATION */ +#error-notification-container { + display: none; + position: absolute; + right: 20px; + width: 35%; + +} +#error-notification { + text-align: center; + border-radius: 4px; + color: #ffffff; + background-color: #eb6154; + border-color: #eb6154; + font-weight: bold; + font-size: 12px; + padding: 10px; } \ No newline at end of file diff --git a/webgoat-container/src/main/resources/static/js/goatApp/goatApp.js b/webgoat-container/src/main/resources/static/js/goatApp/goatApp.js index 7ea097ed6..56dbc31fd 100644 --- a/webgoat-container/src/main/resources/static/js/goatApp/goatApp.js +++ b/webgoat-container/src/main/resources/static/js/goatApp/goatApp.js @@ -1,9 +1,10 @@ -define(['jquery','underscore','backbone','goatApp/view/GoatRouter'], - function($,_,Backbone,Router){ +define(['jquery','underscore','backbone','goatApp/view/GoatRouter', 'goatApp/support/goatAsyncErrorHandler'], + function($,_,Backbone,Router, asyncErrorHandler){ 'use strict' //var goatRouter = new Router(); return { initApp: function() { + asyncErrorHandler.init(); //TODO: add query/ability to load from where they left off var goatRouter = new Router(); goatRouter.init(); diff --git a/webgoat-container/src/main/resources/static/js/goatApp/support/goatAsyncErrorHandler.js b/webgoat-container/src/main/resources/static/js/goatApp/support/goatAsyncErrorHandler.js new file mode 100644 index 000000000..f9344cff7 --- /dev/null +++ b/webgoat-container/src/main/resources/static/js/goatApp/support/goatAsyncErrorHandler.js @@ -0,0 +1,34 @@ +define( + ['backbone', 'underscore'], + function(Backbone, _) { + return { + init: function() { + var backboneSync = Backbone.sync; + + var asyncErrorHandler = function(error) { + return function(jqXHR) { + var statusCode = jqXHR.status; + var errorCodes = { + 404: true, + 500: true, + 503: true, + 504: true + }; + + if (statusCode === 401 || statusCode === 403) { + window.top.location.href = "login"; + } else if(errorCodes[statusCode]) { + Backbone.trigger("error:unhandled"); + } + }; + }; + + Backbone.sync = function(method, model, options) { + // override error handler + options.error = asyncErrorHandler(options.error); + return backboneSync(method, model, options); + } + } + }; + } +); diff --git a/webgoat-container/src/main/resources/static/js/goatApp/view/ErrorNotificationView.js b/webgoat-container/src/main/resources/static/js/goatApp/view/ErrorNotificationView.js new file mode 100644 index 000000000..52b22ba95 --- /dev/null +++ b/webgoat-container/src/main/resources/static/js/goatApp/view/ErrorNotificationView.js @@ -0,0 +1,35 @@ +define(['jquery', + 'underscore', + 'backbone'], + function($, + _, + Backbone) { + return Backbone.View.extend({ + el:'#error-notification-container', + initialize: function() { + Backbone.on("error:unhandled", this.showNotification.bind(this)); + this.hideNotification(); + this.currentTimeout = null; + }, + + showNotification: function() { + var self = this; + if (!this.$el.is(':visible')) { + this.$el.show(350); + } + if (this.currentTimeout != null) { + window.clearTimeout(this.currentTimeout); + } + this.currentTimeout = window.setTimeout(function() { + self.hideNotification(); + self.currentTimeout = null; + }, 3000); + }, + + hideNotification: function() { + if (this.$el.is(':visible')) { + this.$el.hide(350); + } + } + }); + }); diff --git a/webgoat-container/src/main/resources/static/js/goatApp/view/LessonContentView.js b/webgoat-container/src/main/resources/static/js/goatApp/view/LessonContentView.js index 2ebb25d80..c122d1e90 100644 --- a/webgoat-container/src/main/resources/static/js/goatApp/view/LessonContentView.js +++ b/webgoat-container/src/main/resources/static/js/goatApp/view/LessonContentView.js @@ -2,17 +2,20 @@ define(['jquery', 'underscore', 'backbone', - 'libs/jquery.form'], + 'libs/jquery.form', + 'goatApp/view/ErrorNotificationView'], function( $, _, Backbone, - JQueryForm) { + JQueryForm, + ErrorNotificationView) { return Backbone.View.extend({ el:'#lesson-content-wrapper', //TODO << get this fixed up in DOM initialize: function(options) { options = options || {}; + new ErrorNotificationView(); }, /* initial renering */ diff --git a/webgoat-container/src/main/resources/templates/main_new.html b/webgoat-container/src/main/resources/templates/main_new.html index 240b16dd5..ece292237 100644 --- a/webgoat-container/src/main/resources/templates/main_new.html +++ b/webgoat-container/src/main/resources/templates/main_new.html @@ -111,6 +111,11 @@
+
+
+ There was an unexpected error. Please try again. +
+