Merge pull request #228 from span/developer-controls

Developer controls
This commit is contained in:
Nanne 2016-04-08 18:27:29 +02:00
commit a8f8d4b4fa
11 changed files with 306 additions and 25 deletions

View File

@ -29,18 +29,23 @@
*/ */
package org.owasp.webgoat.service; package org.owasp.webgoat.service;
import java.util.HashMap;
import java.util.Map;
import org.owasp.webgoat.session.LabelDebugger; import org.owasp.webgoat.session.LabelDebugger;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseBody;
/** /**
* <p>PluginReloadService class.</p> * <p>LabelDebugService class.</p>
* *
* @author nbaars * @author nbaars
* @version $Id: $Id * @version $Id: $Id
@ -48,21 +53,52 @@ import org.springframework.web.bind.annotation.ResponseBody;
@Controller @Controller
public class LabelDebugService extends BaseService { public class LabelDebugService extends BaseService {
private static final String URL_DEBUG_LABELS_MVC = "/debug/labels.mvc";
private static final String KEY_ENABLED = "enabled";
private static final String KEY_SUCCESS = "success";
private static final Logger logger = LoggerFactory.getLogger(LabelDebugService.class); private static final Logger logger = LoggerFactory.getLogger(LabelDebugService.class);
@Autowired @Autowired
private LabelDebugger labelDebugger; private LabelDebugger labelDebugger;
/** /**
* Reload all the plugins * Checks if debugging of labels is enabled or disabled
* *
* @return a {@link org.springframework.http.ResponseEntity} object. * @return a {@link org.springframework.http.ResponseEntity} object.
*/ */
@RequestMapping(value = "/debug/labels.mvc") @RequestMapping(value = URL_DEBUG_LABELS_MVC, produces = MediaType.APPLICATION_JSON_VALUE)
public @ResponseBody public @ResponseBody
//todo parse params to add enable / disable ResponseEntity<Map<String, Object>> checkDebuggingStatus() {
ResponseEntity<String> reloadPlugins() { logger.debug("Checking label debugging, it is " + labelDebugger.isEnabled()); // FIXME parameterize
labelDebugger.enable(); Map<String, Object> result = createResponse(labelDebugger.isEnabled());
return new ResponseEntity("Label debugger enabled refresh the WebGoat page!",HttpStatus.OK); return new ResponseEntity<Map<String, Object>>(result, HttpStatus.OK);
}
/**
* Sets the enabled flag on the label debugger to the given parameter
*
* @return a {@link org.springframework.http.ResponseEntity} object.
* @throws Exception
*/
@RequestMapping(value = URL_DEBUG_LABELS_MVC, produces = MediaType.APPLICATION_JSON_VALUE, params = KEY_ENABLED)
public @ResponseBody
ResponseEntity<Map<String, Object>> setDebuggingStatus(@RequestParam("enabled") Boolean enabled) throws Exception {
logger.debug("Setting label debugging to " + labelDebugger.isEnabled()); // FIXME parameterize
Map<String, Object> result = createResponse(enabled);
labelDebugger.setEnabled(enabled);
return new ResponseEntity<Map<String, Object>>(result, HttpStatus.OK);
}
/**
* @param enabled
* @return a {@link java.util.Map} object.
*/
private Map<String, Object> createResponse(Boolean enabled) {
Map<String, Object> result = new HashMap<String, Object>();
result.put(KEY_SUCCESS, Boolean.TRUE);
result.put(KEY_ENABLED, enabled);
return result;
} }
} }

View File

@ -29,19 +29,23 @@
*/ */
package org.owasp.webgoat.service; package org.owasp.webgoat.service;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpSession;
import org.owasp.webgoat.plugins.PluginsLoader; import org.owasp.webgoat.plugins.PluginsLoader;
import org.owasp.webgoat.session.WebSession; import org.owasp.webgoat.session.WebSession;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpSession;
import java.nio.file.Paths;
/** /**
* <p>PluginReloadService class.</p> * <p>PluginReloadService class.</p>
* *
@ -59,16 +63,20 @@ public class PluginReloadService extends BaseService {
* @param session a {@link javax.servlet.http.HttpSession} object. * @param session a {@link javax.servlet.http.HttpSession} object.
* @return a {@link org.springframework.http.ResponseEntity} object. * @return a {@link org.springframework.http.ResponseEntity} object.
*/ */
@RequestMapping(value = "/reloadplugins.mvc") @RequestMapping(value = "/reloadplugins.mvc", produces = MediaType.APPLICATION_JSON_VALUE)
public @ResponseBody public @ResponseBody
ResponseEntity<String> reloadPlugins(HttpSession session) { ResponseEntity<Map<String, Object>> reloadPlugins(HttpSession session) {
WebSession webSession = (WebSession) session.getAttribute(WebSession.SESSION); WebSession webSession = (WebSession) session.getAttribute(WebSession.SESSION);
logger.debug("Loading plugins into cache"); logger.debug("Loading plugins into cache");
String pluginPath = session.getServletContext().getRealPath("plugin_lessons"); String pluginPath = session.getServletContext().getRealPath("plugin_lessons");
String targetPath = session.getServletContext().getRealPath("plugin_extracted"); String targetPath = session.getServletContext().getRealPath("plugin_extracted");
new PluginsLoader(Paths.get(pluginPath), Paths.get(targetPath)).copyJars(); new PluginsLoader(Paths.get(pluginPath), Paths.get(targetPath)).copyJars();
webSession.getCourse().loadLessonFromPlugin(session.getServletContext()); webSession.getCourse().loadLessonFromPlugin(session.getServletContext());
return new ResponseEntity("Plugins reload refresh the WebGoat page!",HttpStatus.OK);
Map<String, Object> result = new HashMap<String, Object>();
result.put("success", true);
result.put("message", "Plugins reloaded");
return new ResponseEntity<Map<String, Object>>(result, HttpStatus.OK);
} }
} }

View File

@ -10,7 +10,7 @@ import java.io.Serializable;
*/ */
public class LabelDebugger implements Serializable { public class LabelDebugger implements Serializable {
private boolean isEnabled = false; private boolean enabled = false;
/** /**
* <p>isEnabled.</p> * <p>isEnabled.</p>
@ -18,14 +18,31 @@ public class LabelDebugger implements Serializable {
* @return a boolean. * @return a boolean.
*/ */
public boolean isEnabled() { public boolean isEnabled() {
return isEnabled; return enabled;
} }
/** /**
* <p>enable.</p> * <p>Enables label debugging</p>
*/ */
public void enable() { public void enable() {
this.isEnabled = true; this.enabled = true;
}
/**
* <p>Disables label debugging</p>
*/
public void disable() {
this.enabled = false;
}
/**
* <p>Sets the status to enabled</p>
* @param enabled
* @throws Exception if enabled is null
*/
public void setEnabled(Boolean enabled) throws Exception {
if(enabled == null) throw new Exception("Cannot set enabled to null");
this.enabled = enabled;
} }
} }

View File

@ -72,9 +72,9 @@
<li role="presentation" class="disabled"><a role="menuitem" tabindex="-1" href="#">User: ${user}</a></li> <li role="presentation" class="disabled"><a role="menuitem" tabindex="-1" href="#">User: ${user}</a></li>
<li role="presentation" class="disabled"><a role="menuitem" tabindex="-1" href="#">Role: ${role}</a></li> <li role="presentation" class="disabled"><a role="menuitem" tabindex="-1" href="#">Role: ${role}</a></li>
<li role="presentation" class="divider"></li> <li role="presentation" class="divider"></li>
<li role="presentation"><a role="menuitem" tabindex="-1" href="#developer-controls">Show developer controls</a></li>
<li role="presentation" class="disabled"><a role="menuitem" tabindex="-1" href="#">${version}</a></li> <li role="presentation" class="disabled"><a role="menuitem" tabindex="-1" href="#">${version}</a></li>
<li role="presentation" class="disabled"><a role="menuitem" tabindex="-1" href="#">Build: ${build}</a></li> <li role="presentation" class="disabled"><a role="menuitem" tabindex="-1" href="#">Build: ${build}</a></li>
</ul> </ul>
</div> </div>
<button type="button" id="about-button" class="btn btn-default right_nav_button" title="About WebGoat" data-toggle="modal" data-target="#about-modal"> <button type="button" id="about-button" class="btn btn-default right_nav_button" title="About WebGoat" data-toggle="modal" data-target="#about-modal">
@ -143,6 +143,15 @@
<h4>Params</h4> <h4>Params</h4>
</div> </div>
</div> </div>
<div id="developer-control-container">
<div align="left">
<h3>Developer controls</h3>
</div>
<hr />
<div id="developer-controls">
</div>
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -765,6 +765,27 @@ cookie-container {
padding-left:3px; padding-left:3px;
} }
.developer-controls-table {
width: 100%;
}
.developer-controls-table td {
text-align: right;
}
.developer-controls-table a {
color: #e84c3d
}
#developer-control-container {
display: none;
}
#menu-container a,
.developer-controls-table a {
cursor: pointer;
}
/* ========================================================================== /* ==========================================================================
MENU / Sidebar MENU / Sidebar
========================================================================== */ ========================================================================== */

View File

@ -123,6 +123,7 @@ define(['jquery',
this.sourceView = new SourceView(); this.sourceView = new SourceView();
this.lessonHintView = new HintView(); this.lessonHintView = new HintView();
this.cookieView = new CookieView(); this.cookieView = new CookieView();
//TODO: instantiate model with values (not sure why was not working before) //TODO: instantiate model with values (not sure why was not working before)
var paramModel = new ParamModel({}); var paramModel = new ParamModel({});
paramModel.set('scrParam',this.lessonContent.get('scrParam')); paramModel.set('scrParam',this.lessonContent.get('scrParam'));

View File

@ -0,0 +1,39 @@
define([
'backbone'],
function(
Backbone) {
return Backbone.Model.extend({
id: 'label-status',
url: 'service/debug/labels.mvc',
label: '',
labels: {
enable: 'Enable label debugging',
disable: 'Disable label debugging'
},
initialize: function() {
this.load();
},
fetch: function(options) {
options || (options = {});
var data = (options.data || {});
if(this.enabled != undefined) {
options.data = { enabled: !this.enabled };
}
return Backbone.Collection.prototype.fetch.call(this, options);
},
load: function () {
this.fetch().then(this.labelStatusLoaded.bind(this));
},
labelStatusLoaded: function(data) {
this.enabled = data.enabled;
this.label = this.enabled ? this.labels['disable'] : this.labels['enable'];
this.trigger('plugins:loaded', this, data);
}
});
});

View File

@ -0,0 +1,19 @@
define([
'backbone'],
function(
Backbone) {
return Backbone.Model.extend({
url: 'service/reloadplugins.mvc',
id: 'reload-plugins',
label: 'Reload plugins',
load: function () {
this.fetch().then(this.pluginsLoaded.bind(this));
},
pluginsLoaded: function(data) {
this.trigger('plugins:loaded', this, data);
}
});
});

View File

@ -0,0 +1,77 @@
define(['jquery',
'underscore',
'backbone',
'goatApp/model/PluginReloadModel',
'goatApp/model/LabelDebugModel'],
function(
$,
_,
Backbone,
PluginReloadModel,
LabelDebugModel) {
return Backbone.View.extend({
el: '#developer-controls',
onControlClick: function(model) {
$('#' + model.id).find('td').text('Loading...');
model.load();
},
onPluginsLoaded: function(model) {
window.location.href = 'welcome.mvc';
},
onLabelsLoaded: function(model) {
this.models[1] = model;
this.render();
Backbone.history.loadUrl(Backbone.history.getFragment());
},
initialize: function(options) {
this.addMenuListener();
this.models = [new PluginReloadModel(), new LabelDebugModel()];
this.listenTo(this.models[0], 'plugins:loaded', this.onPluginsLoaded);
this.listenTo(this.models[1], 'plugins:loaded', this.onLabelsLoaded);
this.render();
},
addMenuListener: function() {
var showHandler = function(e) {
e.preventDefault();
$('#developer-control-container').show();
$(this).text('Hide developer controls').off().on('click', hideHandler);
};
var hideHandler = function(e) {
e.preventDefault();
$('#developer-control-container').hide();
$(this).text('Show developer controls').off().on('click', showHandler);
};
$('a[href="#developer-controls"]').click(showHandler);
},
render: function() {
this.$el.html('');
var table = $('<table>',{'class':'developer-controls-table table-nonfluid'});
var self = this;
_.each(this.models, function(model) {
var newRow = $('<tr>', { id: model.id });
var headerCell = $('<th>')
var statusCell = $('<td>')
var link = $('<a>', {
'text': model.label,
'title': model.label
});
link.click(_.bind(self.onControlClick, self, model));
newRow.append(headerCell.append(link));
newRow.append(statusCell);
table.append(newRow);
});
this.$el.append(table);
}
});
});

View File

@ -4,17 +4,20 @@ define(['jquery',
'goatApp/controller/LessonController', 'goatApp/controller/LessonController',
'goatApp/controller/MenuController', 'goatApp/controller/MenuController',
'goatApp/view/LessonContentView', 'goatApp/view/LessonContentView',
'goatApp/view/MenuView' 'goatApp/view/MenuView',
'goatApp/view/DeveloperControlsView'
], function ($, ], function ($,
_, _,
Backbone, Backbone,
LessonController, LessonController,
MenuController, MenuController,
LessonContentView, LessonContentView,
MenuView) { MenuView,
DeveloperControlsView) {
var lessonView = new LessonContentView(); var lessonView = new LessonContentView();
var menuView = new MenuView(); var menuView = new MenuView();
var developerControlsView = new DeveloperControlsView();
var GoatAppRouter = Backbone.Router.extend({ var GoatAppRouter = Backbone.Router.extend({
routes: { routes: {
@ -25,11 +28,11 @@ define(['jquery',
}, },
lessonController: new LessonController({ lessonController: new LessonController({
lessonView:lessonView lessonView: lessonView
}), }),
menuController: new MenuController({ menuController: new MenuController({
menuView:menuView menuView: menuView
}), }),
init:function() { init:function() {

View File

@ -0,0 +1,51 @@
package org.owasp.webgoat.session;
import org.junit.Assert;
import org.junit.Test;
public class LabelDebuggerTest {
@Test
public void testSetEnabledTrue() throws Exception {
LabelDebugger ld = new LabelDebugger();
ld.setEnabled(true);
Assert.assertTrue(ld.isEnabled());
}
@Test
public void testSetEnabledFalse() throws Exception {
LabelDebugger ld = new LabelDebugger();
ld.setEnabled(false);
Assert.assertFalse(ld.isEnabled());
}
@Test
public void testSetEnabledNullThrowsException() {
LabelDebugger ld = new LabelDebugger();
try {
ld.setEnabled(null);
} catch (Exception e) {
// We want to end up here
return;
}
Assert.fail();
}
@Test
public void testEnableIsTrue() {
LabelDebugger ld = new LabelDebugger();
ld.enable();
Assert.assertTrue(ld.isEnabled());
}
@Test
public void testDisableIsFalse() {
LabelDebugger ld = new LabelDebugger();
ld.disable();
Assert.assertFalse(ld.isEnabled());
}
}