
main change is to force spring security to always send user to welcome.mvc after login which gets their session setup properly before redirecting to start.mvc
440 lines
16 KiB
Java
440 lines
16 KiB
Java
package org.owasp.webgoat;
|
|
|
|
import java.io.IOException;
|
|
import java.io.PrintWriter;
|
|
import java.text.SimpleDateFormat;
|
|
import java.util.Date;
|
|
import java.util.Locale;
|
|
import java.util.TimeZone;
|
|
import javax.servlet.ServletContext;
|
|
import javax.servlet.ServletException;
|
|
import javax.servlet.http.HttpServlet;
|
|
import javax.servlet.http.HttpServletRequest;
|
|
import javax.servlet.http.HttpServletResponse;
|
|
import javax.servlet.http.HttpSession;
|
|
import org.owasp.webgoat.lessons.AbstractLesson;
|
|
import org.owasp.webgoat.lessons.WelcomeScreen;
|
|
import org.owasp.webgoat.lessons.admin.WelcomeAdminScreen;
|
|
import org.owasp.webgoat.session.Course;
|
|
import org.owasp.webgoat.session.ErrorScreen;
|
|
import org.owasp.webgoat.session.Screen;
|
|
import org.owasp.webgoat.session.UserTracker;
|
|
import org.owasp.webgoat.session.WebSession;
|
|
import org.owasp.webgoat.session.WebgoatContext;
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
/**
|
|
* *************************************************************************************************
|
|
*
|
|
*
|
|
* This file is part of WebGoat, an Open Web Application Security Project
|
|
* utility. For details, please see http://www.owasp.org/
|
|
*
|
|
* Copyright (c) 2002 - 2007 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 code.google.com, a repository
|
|
* for free software projects.
|
|
*
|
|
* For details, please see http://code.google.com/p/webgoat/
|
|
*
|
|
*
|
|
* @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect
|
|
* Security</a>
|
|
* @author Bruce Mayhew <a href="http://code.google.com/p/webgoat">WebGoat</a>
|
|
* @created October 28, 2003
|
|
*/
|
|
public class HammerHead extends HttpServlet {
|
|
|
|
final Logger logger = LoggerFactory.getLogger(HammerHead.class);
|
|
|
|
private static final String WELCOMED = "welcomed";
|
|
|
|
/**
|
|
*
|
|
*/
|
|
private static final long serialVersionUID = 645640331343188020L;
|
|
|
|
/**
|
|
* Description of the Field
|
|
*/
|
|
protected static SimpleDateFormat httpDateFormat;
|
|
|
|
/**
|
|
* Set the session timeout to be 2 days
|
|
*/
|
|
private final static int sessionTimeoutSeconds = 60 * 60 * 24 * 2;
|
|
|
|
// private final static int sessionTimeoutSeconds = 1;
|
|
/**
|
|
* Properties file path
|
|
*/
|
|
public static String propertiesPath = null;
|
|
|
|
/**
|
|
* provides convenience methods for getting setup information from the
|
|
* ServletContext
|
|
*/
|
|
private WebgoatContext webgoatContext = null;
|
|
|
|
/**
|
|
* Description of the Method
|
|
*
|
|
* @param request Description of the Parameter
|
|
* @param response Description of the Parameter
|
|
* @exception IOException Description of the Exception
|
|
* @exception ServletException Description of the Exception
|
|
*/
|
|
@Override
|
|
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
|
|
doPost(request, response);
|
|
}
|
|
|
|
/**
|
|
* Description of the Method
|
|
*
|
|
* @param request Description of the Parameter
|
|
* @param response Description of the Parameter
|
|
* @exception IOException Description of the Exception
|
|
* @exception ServletException Description of the Exception
|
|
*/
|
|
@Override
|
|
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
|
|
Screen screen = null;
|
|
|
|
WebSession mySession = null;
|
|
try {
|
|
logger.debug("Entering doPost");
|
|
logger.debug("request: " + request);
|
|
logger.debug("principle: " + request.getUserPrincipal());
|
|
// setCacheHeaders(response, 0);
|
|
ServletContext context = getServletContext();
|
|
|
|
// FIXME: If a response is written by updateSession(), do not
|
|
// call makeScreen() and writeScreen()
|
|
mySession = updateSession(request, response, context);
|
|
if (response.isCommitted()) {
|
|
logger.debug("Response already committed, exiting");
|
|
return;
|
|
}
|
|
|
|
if ("true".equals(request.getParameter("start"))) {
|
|
logger.warn("Redirecting to start controller");
|
|
response.sendRedirect("start.mvc");
|
|
return;
|
|
}
|
|
|
|
// Note: For the lesson to track the status, we need to update
|
|
// the lesson tracker object
|
|
// from the screen.createContent() method. The create content is
|
|
// the only point
|
|
// where the lesson "knows" what has happened. To track it at a
|
|
// latter point would
|
|
// require the lesson to have memory.
|
|
screen = makeScreen(mySession);
|
|
// This calls the lesson's
|
|
// handleRequest()
|
|
if (response.isCommitted()) {
|
|
return;
|
|
}
|
|
|
|
// perform lesson-specific tracking activities
|
|
if (screen instanceof AbstractLesson) {
|
|
AbstractLesson lesson = (AbstractLesson) screen;
|
|
|
|
// we do not count the initial display of the lesson screen as a visit
|
|
if ("GET".equals(request.getMethod())) {
|
|
String uri = request.getRequestURI() + "?" + request.getQueryString();
|
|
if (!uri.endsWith(lesson.getLink())) {
|
|
screen.getLessonTracker(mySession).incrementNumVisits();
|
|
}
|
|
} else if ("POST".equals(request.getMethod())
|
|
&& mySession.getPreviousScreen() == mySession.getCurrentScreen()) {
|
|
screen.getLessonTracker(mySession).incrementNumVisits();
|
|
}
|
|
}
|
|
|
|
// log the access to this screen for this user
|
|
UserTracker userTracker = UserTracker.instance();
|
|
userTracker.update(mySession, screen);
|
|
log(request, screen.getClass().getName() + " | " + mySession.getParser().toString());
|
|
|
|
// Redirect the request to our View servlet
|
|
String userAgent = request.getHeader("user-agent");
|
|
String clientBrowser = "Not known!";
|
|
if (userAgent != null) {
|
|
clientBrowser = userAgent;
|
|
}
|
|
request.setAttribute("client.browser", clientBrowser);
|
|
// removed - this is being done in updateSession call
|
|
//request.getSession().setAttribute(WebSession.SESSION, mySession);
|
|
// not sure why this is being set in the session?
|
|
//request.getSession().setAttribute(WebSession.COURSE, mySession.getCourse());
|
|
String viewPage = getViewPage(mySession);
|
|
logger.debug("Forwarding to view: " + viewPage);
|
|
logger.debug("Screen: " + screen);
|
|
request.getRequestDispatcher(viewPage).forward(request, response);
|
|
} catch (Throwable t) {
|
|
logger.error("Error handling request", t);
|
|
screen = new ErrorScreen(mySession, t);
|
|
} finally {
|
|
try {
|
|
if (screen instanceof ErrorScreen) {
|
|
this.writeScreen(mySession, screen, response);
|
|
}
|
|
} catch (Throwable thr) {
|
|
logger.error("Could not write error screen", thr);
|
|
}
|
|
WebSession.returnConnection(mySession);
|
|
logger.debug("Leaving doPost: ");
|
|
}
|
|
}
|
|
|
|
private String getViewPage(WebSession webSession) {
|
|
// now always display the lesson content
|
|
String page = "/lesson_content.jsp";
|
|
//page = "/main.jsp";
|
|
return page;
|
|
}
|
|
|
|
/**
|
|
* Description of the Method
|
|
*
|
|
* @param date Description of the Parameter
|
|
* @return RFC 1123 http date format
|
|
*/
|
|
protected static String formatHttpDate(Date date) {
|
|
synchronized (httpDateFormat) {
|
|
return httpDateFormat.format(date);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Return information about this servlet
|
|
*
|
|
* @return The servletInfo value
|
|
*/
|
|
@Override
|
|
public String getServletInfo() {
|
|
return "WebGoat is sponsored by Aspect Security.";
|
|
}
|
|
|
|
/**
|
|
* Return properties path
|
|
*
|
|
* @throws javax.servlet.ServletException
|
|
*/
|
|
@Override
|
|
public void init() throws ServletException {
|
|
logger.info("Initializing main webgoat servlet");
|
|
httpDateFormat = new SimpleDateFormat("EEE, dd MMM yyyyy HH:mm:ss z", Locale.US);
|
|
httpDateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
|
|
propertiesPath = getServletContext().getRealPath("./WEB-INF/webgoat.properties");
|
|
webgoatContext = new WebgoatContext(this);
|
|
}
|
|
|
|
/**
|
|
* Description of the Method
|
|
*
|
|
* @param request Description of the Parameter
|
|
* @param message Description of the Parameter
|
|
*/
|
|
public void log(HttpServletRequest request, String message) {
|
|
String output = new Date() + " | " + request.getRemoteHost() + ":" + request.getRemoteAddr() + " | " + message;
|
|
log(output);
|
|
logger.debug(output);
|
|
}
|
|
|
|
/*
|
|
* public List getLessons(Category category, String role) { Course course =
|
|
* mySession.getCourse(); // May need to clone the List before returning it. //return new
|
|
* ArrayList(course.getLessons(category, role)); return course.getLessons(category, role); }
|
|
*/
|
|
/**
|
|
* Description of the Method
|
|
*
|
|
* @param s Description of the Parameter
|
|
* @return Description of the Return Value
|
|
*/
|
|
protected Screen makeScreen(WebSession s) {
|
|
Screen screen = null;
|
|
int scr = s.getCurrentScreen();
|
|
Course course = s.getCourse();
|
|
|
|
if (s.isUser() || s.isChallenge()) {
|
|
if (scr == WebSession.WELCOME) {
|
|
screen = new WelcomeScreen(s);
|
|
} else {
|
|
AbstractLesson lesson = course.getLesson(s, scr, AbstractLesson.USER_ROLE);
|
|
if (lesson == null && s.isHackedAdmin()) {
|
|
// If admin was hacked, let the user see some of the
|
|
// admin screens
|
|
lesson = course.getLesson(s, scr, AbstractLesson.HACKED_ADMIN_ROLE);
|
|
}
|
|
|
|
if (lesson != null) {
|
|
screen = lesson;
|
|
|
|
// We need to do some bookkeeping for the hackable admin
|
|
// interface.
|
|
// This is the only place we can tell if the user
|
|
// successfully hacked the hackable
|
|
// admin and has actually accessed an admin screen. You
|
|
// need BOTH pieces of information
|
|
// in order to satisfy the remote admin lesson.
|
|
s.setHasHackableAdmin(screen.getRole());
|
|
|
|
lesson.handleRequest(s);
|
|
s.setCurrentMenu(lesson.getCategory().getRanking());
|
|
} else {
|
|
screen = new ErrorScreen(s, "Invalid screen requested. Try: http://localhost/WebGoat/attack");
|
|
}
|
|
}
|
|
} else if (s.isAdmin()) {
|
|
if (scr == WebSession.WELCOME) {
|
|
screen = new WelcomeAdminScreen(s);
|
|
} else {
|
|
// Admin can see all roles.
|
|
// FIXME: should be able to pass a list of roles.
|
|
AbstractLesson lesson = course.getLesson(s, scr, AbstractLesson.ADMIN_ROLE);
|
|
if (lesson == null) {
|
|
lesson = course.getLesson(s, scr, AbstractLesson.HACKED_ADMIN_ROLE);
|
|
}
|
|
if (lesson == null) {
|
|
lesson = course.getLesson(s, scr, AbstractLesson.USER_ROLE);
|
|
}
|
|
|
|
if (lesson != null) {
|
|
screen = lesson;
|
|
|
|
// We need to do some bookkeeping for the hackable admin
|
|
// interface.
|
|
// This is the only place we can tell if the user
|
|
// successfully hacked the hackable
|
|
// admin and has actually accessed an admin screen. You
|
|
// need BOTH pieces of information
|
|
// in order to satisfy the remote admin lesson.
|
|
s.setHasHackableAdmin(screen.getRole());
|
|
|
|
lesson.handleRequest(s);
|
|
s.setCurrentMenu(lesson.getCategory().getRanking());
|
|
} else {
|
|
screen = new ErrorScreen(s,
|
|
"Invalid screen requested. Try Setting Admin to false or Try: http://localhost/WebGoat/attack");
|
|
}
|
|
}
|
|
}
|
|
|
|
return (screen);
|
|
}
|
|
|
|
/**
|
|
* This method sets the required expiration headers in the response for a
|
|
* given RunData object. This method attempts to set all relevant headers,
|
|
* both for HTTP 1.0 and HTTP 1.1.
|
|
*
|
|
* @param response The new cacheHeaders value
|
|
* @param expiry The new cacheHeaders value
|
|
*/
|
|
protected static void setCacheHeaders(HttpServletResponse response, int expiry) {
|
|
if (expiry == 0) {
|
|
response.setHeader("Pragma", "no-cache");
|
|
response.setHeader("Cache-Control", "no-cache");
|
|
response.setHeader("Expires", formatHttpDate(new Date()));
|
|
} else {
|
|
Date expiryDate = new Date(System.currentTimeMillis() + expiry);
|
|
response.setHeader("Expires", formatHttpDate(expiryDate));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Description of the Method
|
|
*
|
|
* @param request Description of the Parameter
|
|
* @param response Description of the Parameter
|
|
* @param context Description of the Parameter
|
|
* @return Description of the Return Value
|
|
* @throws java.io.IOException
|
|
*/
|
|
protected WebSession updateSession(HttpServletRequest request, HttpServletResponse response, ServletContext context)
|
|
throws IOException {
|
|
HttpSession hs;
|
|
// session should already be created by spring security
|
|
hs = request.getSession(false);
|
|
|
|
logger.debug("HH Entering Session_id: " + hs.getId());
|
|
// dumpSession( hs );
|
|
// Get our session object out of the HTTP session
|
|
WebSession session = null;
|
|
Object o = hs.getAttribute(WebSession.SESSION);
|
|
|
|
if ((o != null) && o instanceof WebSession) {
|
|
session = (WebSession) o;
|
|
hs.setAttribute(WebSession.COURSE, session.getCourse());
|
|
} else {
|
|
// Create new custom session and save it in the HTTP session
|
|
logger.warn("HH Creating new WebSession");
|
|
session = new WebSession(webgoatContext, context);
|
|
// Ensure splash screen shows on any restart
|
|
// rlawson - removed this since we show splash screen at login now
|
|
//hs.removeAttribute(WELCOMED);
|
|
hs.setAttribute(WebSession.SESSION, session);
|
|
// reset timeout
|
|
hs.setMaxInactiveInterval(sessionTimeoutSeconds);
|
|
}
|
|
|
|
session.update(request, response, this.getServletName());
|
|
// update last attack request info (cookies, parms)
|
|
// this is so the REST services can have access to them via the session
|
|
session.updateLastAttackRequestInfo(request);
|
|
|
|
// to authenticate
|
|
logger.debug("HH Leaving Session_id: " + hs.getId());
|
|
//dumpSession( hs );
|
|
return (session);
|
|
}
|
|
|
|
/**
|
|
* Description of the Method
|
|
*
|
|
* @param s Description of the Parameter
|
|
* @param screen
|
|
* @param response Description of the Parameter
|
|
* @exception IOException Description of the Exception
|
|
*/
|
|
protected void writeScreen(WebSession s, Screen screen, HttpServletResponse response) throws IOException {
|
|
response.setContentType("text/html");
|
|
|
|
PrintWriter out = response.getWriter();
|
|
|
|
if (s == null) {
|
|
screen = new ErrorScreen(s, "Page to display was null");
|
|
}
|
|
|
|
// set the content-length of the response.
|
|
// Trying to avoid chunked-encoding. (Aspect required)
|
|
response.setContentLength(screen.getContentLength());
|
|
response.setHeader("Content-Length", screen.getContentLength() + "");
|
|
|
|
screen.output(out);
|
|
out.flush();
|
|
out.close();
|
|
}
|
|
}
|