package org.owasp.webgoat.session; import java.io.IOException; import java.io.PrintWriter; import java.security.Principal; import java.sql.Connection; import java.sql.SQLException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.Hashtable; import java.util.List; import java.util.Map; import java.util.Vector; import javax.servlet.ServletContext; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.owasp.webgoat.lessons.AbstractLesson; import org.owasp.webgoat.lessons.Category; import org.owasp.webgoat.lessons.RandomLessonAdapter; import org.owasp.webgoat.lessons.SequentialLessonAdapter; import org.owasp.webgoat.lessons.model.RequestParameter; import org.owasp.webgoat.util.WebGoatI18N; 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 Aspect * Security * @author Bruce Mayhew WebGoat * * @created October 28, 2003 */ public class WebSession { final Logger logger = LoggerFactory.getLogger(WebSession.class); /** * Description of the Field */ public final static String ADMIN = "admin"; /** * Tomcat role for a webgoat user */ public final static String WEBGOAT_USER = "webgoat_user"; /** * Tomcat role for a webgoat admin */ public final static String WEBGOAT_ADMIN = "webgoat_admin"; /** * Description of the Field */ public final static String CHALLENGE = "Challenge"; /** * Description of the Field */ public final static String COLOR = "color"; public final static String COURSE = "course"; /** * Description of the Field */ public final static int ERROR = 0; public static final String STAGE = "stage"; /** * Description of the Field */ public final static String JSESSION_ID = "jsessionid"; /** * Description of the Field */ public final static String LOGOUT = "Logout"; /** * Description of the Field */ public final static String RESTART = "Restart"; /** * Description of the Field */ public final static String MENU = "menu"; /** * Description of the Field */ public final static String SCREEN = "Screen"; /** * Description of the Field */ public final static String SESSION = "websession"; public final static String SHOWSOURCE = "ShowSource"; public final static String SHOWSOLUTION = "ShowSolution"; public final static String SHOWHINTS = "ShowHints"; public final static String SHOW = "show"; public final static String SHOW_NEXTHINT = "NextHint"; public final static String SHOW_PREVIOUSHINT = "PreviousHint"; public final static String SHOW_PARAMS = "Params"; public final static String SHOW_COOKIES = "Cookies"; public final static String SHOW_SOURCE = "Source"; public final static String SHOW_SOLUTION = "Solution"; public final static String DEBUG = "debug"; public final static String LANGUAGE = "language"; /** * Description of the Field */ public final static int WELCOME = -1; private WebgoatContext webgoatContext; private ServletContext context = null; private Course course; private int currentScreen = WELCOME; private int previousScreen = ERROR; private int hintNum = -1; private boolean isAdmin = false; private boolean isHackedAdmin = false; private boolean isAuthenticated = false; private boolean isColor = false; private boolean isDebug = false; private boolean hasHackedHackableAdmin = false; private StringBuffer message = new StringBuffer(""); private ParameterParser myParser; private HttpServletRequest request = null; private HttpServletResponse response = null; private String servletName; private HashMap session = new HashMap(); private boolean showCookies = false; private boolean showParams = false; private boolean showRequest = false; private boolean showSource = false; private boolean showSolution = false; private boolean completedHackableAdmin = false; private int currentMenu; private String currentLanguage = null; private List cookiesOnLastRequest; private List parmsOnLastRequest; /** * Constructor for the WebSession object * * @param servlet Description of the Parameter * @param context Description of the Parameter */ public WebSession(WebgoatContext webgoatContext, ServletContext context) { this.webgoatContext = webgoatContext; // initialize from web.xml showParams = webgoatContext.isShowParams(); showCookies = webgoatContext.isShowCookies(); showSource = webgoatContext.isShowSource(); showSolution = webgoatContext.isShowSolution(); showRequest = webgoatContext.isShowRequest(); currentLanguage = webgoatContext.getDefaultLanguage(); this.context = context; course = new Course(); course.loadCourses(webgoatContext, context, "/"); } public static synchronized Connection getConnection(WebSession s) throws SQLException { return DatabaseUtilities.getConnection(s); } public static void returnConnection(WebSession s) { DatabaseUtilities.returnConnection(s.getUserName()); } /** * Description of the Method * * @param key Description of the Parameter * @param value Description of the Parameter */ public void add(String key, Object value) { session.put(key, value); } /** * Description of the Method */ public void clearMessage() { message.setLength(0); } /** * Description of the Method */ public void eatCookies() { Cookie[] cookies = request.getCookies(); for (int loop = 0; loop < cookies.length; loop++) { if (!cookies[loop].getName().startsWith("JS")) {// skip jsessionid cookie cookies[loop].setMaxAge(0);// mark for deletion by browser response.addCookie(cookies[loop]); } } } /** * Description of the Method * * @param key Description of the Parameter * @return Description of the Return Value */ public Object get(String key) { return (session.get(key)); } /** * Gets the context attribute of the WebSession object * * @return The context value */ public ServletContext getContext() { return context; } public List getRoles() { List roles = new ArrayList(); roles.add(AbstractLesson.USER_ROLE); if (isAdmin()) { roles.add(AbstractLesson.ADMIN_ROLE); } return roles; } /** * Sets the admin flag - this routine is ONLY here to allow someone a * backdoor to setting the user up as an admin. * * This is also used by the WebSession to set the admin, but the method * should be private * * @param state */ public void setAdmin(boolean state) { isAdmin = state; } public String getRole() { String role = ""; if (isAdmin()) { role = AbstractLesson.ADMIN_ROLE; } else if (isHackedAdmin()) { role = AbstractLesson.HACKED_ADMIN_ROLE; } else if (isChallenge()) { role = AbstractLesson.CHALLENGE_ROLE; } else { role = AbstractLesson.USER_ROLE; } return role; } /** * Gets the course attribute of the WebSession object * * @return The course value */ public Course getCourse() { return course; } public void setCourse(Course course) { this.course = course; } /** * Gets the currentScreen attribute of the WebSession object * * @return The currentScreen value */ public int getCurrentScreen() { return (currentScreen); } public void setCurrentScreen(int screen) { currentScreen = screen; } public String getRestartLink() { return getCurrentLesson().getLink() + "&" + RESTART + "=" + getCurrentScreen(); } public String getCurrentLink() { String thisLink = "attack"; Enumeration e = request.getParameterNames(); boolean isFirstParameter = true; while (e.hasMoreElements()) { String name = e.nextElement(); if (isFirstParameter) { isFirstParameter = false; thisLink += "?"; } else { thisLink += "&"; } thisLink = thisLink + name + "=" + request.getParameter(name); } return thisLink; } public AbstractLesson getCurrentLesson() { return getCourse().getLesson(this, getCurrentScreen(), getRoles()); } public AbstractLesson getLesson(int id) { return getCourse().getLesson(this, id, getRoles()); } public List getLessons(Category category) { return getCourse().getLessons(this, category, getRoles()); } /** * Gets the hint1 attribute of the WebSession object * * @return The hint1 value */ private int getHintNum() { return (hintNum); } public String getHint() { String hint = null; int hints = getCurrentLesson().getHintCount(this); if (getHintNum() > hints) { hintNum = -1; } if (getHintNum() >= 0) // FIXME { hint = getCurrentLesson().getHint(this, getHintNum()); } return hint; } public List getParams() { Vector params = null; if (showParams() && getParser() != null) { params = new Vector(); Enumeration e = getParser().getParameterNames(); while ((e != null) && e.hasMoreElements()) { String name = (String) e.nextElement(); String[] values = getParser().getParameterValues(name); for (int loop = 0; (values != null) && (loop < values.length); loop++) { params.add(new Parameter(name, values[loop])); // params.add( name + " -> " + values[loop] ); } } Collections.sort(params); } return params; } public List getCookies() { List cookies = null; if (showCookies()) { cookies = Arrays.asList(request.getCookies()); } /* * List cookies = new Vector(); HttpServletRequest request = getRequest(); Cookie[] cookies * = request.getCookies(); if ( cookies.length == 0 ) { list.addElement( new LI( * "No Cookies" ) ); } for ( int i = 0; i < cookies.length; i++ ) { Cookie cookie = * cookies[i]; cookies.add(cookie); //list.addElement( new LI( cookie.getName() + " -> " + * cookie.getValue() ) ); } */ return cookies; } /** * Gets the cookie attribute of the CookieScreen object * * @param s Description of the Parameter * @return The cookie value */ public String getCookie(String cookieName) { Cookie[] cookies = getRequest().getCookies(); for (int i = 0; i < cookies.length; i++) { if (cookies[i].getName().equalsIgnoreCase(cookieName)) { return (cookies[i].getValue()); } } return (null); } public String getSource() { return "Sorry. No Java Source viewing available."; // return getCurrentLesson().getSource(this); } public String getSolution() { return "Sorry. No solution is available."; // return getCurrentLesson().getSolution(this); } public String getInstructions() { return getCurrentLesson().getInstructions(this); } /** * Gets the message attribute of the WebSession object * * @return The message value */ public String getMessage() { return (message.toString()); } /** * Gets the parser attribute of the WebSession object * * @return The parser value */ public ParameterParser getParser() { return (myParser); } /** * Gets the previousScreen attribute of the WebSession object * * @return The previousScreen value */ public int getPreviousScreen() { return (previousScreen); } /** * Gets the request attribute of the WebSession object * * @return The request value */ public HttpServletRequest getRequest() { return request; } public void setRequest(HttpServletRequest request) { this.request = request; } /** * Gets the response attribute of the WebSession object * * @return The response value */ public HttpServletResponse getResponse() { return response; } /** * Gets the servletName attribute of the WebSession object * * @return The servletName value */ public String getServletName() { return (servletName); } /** * Gets the sourceFile attribute of the WebSession object * * @param screen Description of the Parameter * @return The sourceFile value */ public String getWebResource(String fileName) { // Note: doesn't work for admin path! Maybe with a ../ attack return (context.getRealPath(fileName)); } /** * Gets the admin attribute of the WebSession object * * @return The admin value */ public boolean isAdmin() { return (isAdmin); } /** * Gets the hackedAdmin attribute of the WebSession object * * @return The hackedAdmin value */ public boolean isHackedAdmin() { return (isHackedAdmin); } /** * Has the user ever hacked the hackable admin * * @return The hackedAdmin value */ public boolean completedHackableAdmin() { return (completedHackableAdmin); } /** * Gets the authenticated attribute of the WebSession object * * @return The authenticated value */ public boolean isAuthenticated() { return (isAuthenticated); } private Map lessonSessions = new Hashtable(); public boolean isAuthenticatedInLesson(AbstractLesson lesson) { boolean authenticated = false; LessonSession lessonSession = getLessonSession(lesson); if (lessonSession != null) { authenticated = lessonSession.isAuthenticated(); } // System.out.println("Authenticated for lesson " + lesson + "? " + authenticated); return authenticated; } public boolean isAuthorizedInLesson(int employeeId, String functionId) { return getCurrentLesson().isAuthorized(this, employeeId, functionId); } public boolean isAuthorizedInLesson(String role, String functionId) { return getCurrentLesson().isAuthorized(this, role, functionId); } public int getUserIdInLesson() throws ParameterNotFoundException { return getCurrentLesson().getUserId(this); } public String getUserNameInLesson() throws ParameterNotFoundException { return getCurrentLesson().getUserName(this); } public void openLessonSession(AbstractLesson lesson) { System.out.println("Opening new lesson session for lesson " + lesson); LessonSession lessonSession = new LessonSession(); lessonSessions.put(lesson, lessonSession); } public void closeLessonSession(AbstractLesson lesson) { lessonSessions.remove(lesson); } public LessonSession getLessonSession(AbstractLesson lesson) { return lessonSessions.get(lesson); } /** * Gets the challenge attribute of the WebSession object * * @return The challenge value */ public boolean isChallenge() { if (getCurrentLesson() != null) { return (Category.CHALLENGE.equals(getCurrentLesson().getCategory())); } return false; } /** * Gets the color attribute of the WebSession object * * @return The color value */ public boolean isColor() { return (isColor); } /** * Gets the screen attribute of the WebSession object * * @param value Description of the Parameter * @return The screen value */ public boolean isScreen(int value) { return (getCurrentScreen() == value); } /** * Gets the user attribute of the WebSession object * * @return The user value */ public boolean isUser() { return (!isAdmin && !isChallenge()); } /** * Sets the message attribute of the WebSession object * * @param text The new message value */ public void setMessage(String text) { message.append("
" + " * " + text); } public void setLineBreak(String text) { message.append("

" + text); } /** * Description of the Method * * @return Description of the Return Value */ public boolean showCookies() { return (showCookies); } /** * Description of the Method * * @return Description of the Return Value */ public boolean showParams() { return (showParams); } /** * Description of the Method * * @return Description of the Return Value */ public boolean showRequest() { return (showRequest); } /** * Description of the Method * * @return Description of the Return Value */ public boolean showSource() { return (showSource); } public boolean showSolution() { return (showSolution); } /** * Gets the userName attribute of the WebSession object * * @return The userName value */ public String getUserName() { HttpServletRequest request = getRequest(); if (request == null) { throw new RuntimeException("Could not find the ServletRequest in the web session"); } Principal principal = request.getUserPrincipal(); if (principal == null) { throw new RuntimeException("Could not find the Principal in the Servlet Request"); } return principal.getName(); } /** * Parse parameters from the given request, handle any servlet commands, and * update this session based on the parameters. * * @param request Description of the Parameter * @param response Description of the Parameter * @param name Description of the Parameter */ public void update(HttpServletRequest request, HttpServletResponse response, String name) throws IOException { String content = null; clearMessage(); this.request = request; this.response = response; this.servletName = name; if (myParser == null) { myParser = new ParameterParser(request); } else { myParser.update(request); } if (myParser.getRawParameter(LANGUAGE, null) != null) { this.currentLanguage = new String(myParser.getRawParameter(LANGUAGE, null)); WebGoatI18N.setCurrentLanguage(this.currentLanguage); } // System.out.println("Current Screen 1: " + currentScreen ); // System.out.println("Previous Screen 1: " + previousScreen ); // FIXME: requires ?Logout=true // FIXME: doesn't work right -- no reauthentication // REMOVED - we have explicit logout now via spriing security /* if (myParser.getRawParameter(LOGOUT, null) != null) { System.out.println("Logout " + request.getUserPrincipal()); eatCookies(); request.getSession().invalidate(); currentScreen = WELCOME; previousScreen = ERROR; } */ // There are several scenarios where we want the first lesson to be loaded // 1) Previous screen is Welcome - Start of the course // 2) After a logout and after the session has been reinitialized if ((this.getPreviousScreen() == WebSession.WELCOME) || (getRequest().getSession(false) != null && // getRequest().getSession(false).isNew() && this.getCurrentScreen() == WebSession.WELCOME && this.getPreviousScreen() == WebSession.ERROR)) { currentScreen = course.getFirstLesson().getScreenId(); hintNum = -1; } // System.out.println("Current Screen 2: " + currentScreen ); // System.out.println("Previous Screen 2: " + previousScreen ); // update the screen variables previousScreen = currentScreen; try { // If the request is new there should be no parameters. // This can occur from a session timeout or a the starting of a new course. if (!request.getSession().isNew()) { currentScreen = myParser.getIntParameter(SCREEN, currentScreen); } else { if (!myParser.getRawParameter(SCREEN, "NULL").equals("NULL")) { this.setMessage("Session Timeout - Starting new Session."); } } } catch (Exception e) { } // clear variables when switching screens if (this.getCurrentScreen() != this.getPreviousScreen()) { if (webgoatContext.isDebug()) { setMessage("Changed to a new screen, clearing cookies and hints"); } eatCookies(); hintNum = -1; } else if (myParser.getRawParameter(STAGE, null) != null) { AbstractLesson al = getCurrentLesson(); if (al instanceof SequentialLessonAdapter) { SequentialLessonAdapter sla = (SequentialLessonAdapter) al; int stage = myParser.getIntParameter(STAGE, sla.getStage(this)); if (stage > 0 && stage <= sla.getStageCount()) { sla.setStage(this, stage); } } else if (al instanceof RandomLessonAdapter) { try { RandomLessonAdapter rla = (RandomLessonAdapter) al; int stage = myParser.getIntParameter(STAGE) - 1; String[] stages = rla.getStages(); if (stages == null) { stages = new String[0]; } if (stage >= 0 && stage < stages.length) { rla.setStage(this, stages[stage]); } } catch (ParameterNotFoundException pnfe) { } } } // else update global variables for the current screen else { // Handle "restart" commands int lessonId = myParser.getIntParameter(RESTART, -1); if (lessonId != -1) { restartLesson(lessonId); } // if ( myParser.getBooleanParameter( RESTART, false ) ) // { // getCurrentLesson().getLessonTracker( this ).getLessonProperties().setProperty( // CHALLENGE_STAGE, "1" ); // } // Handle "show" commands String showCommand = myParser.getStringParameter(SHOW, null); if (showCommand != null) { if (showCommand.equalsIgnoreCase(SHOW_PARAMS)) { showParams = !showParams; } else if (showCommand.equalsIgnoreCase(SHOW_COOKIES)) { showCookies = !showCookies; } else if (showCommand.equalsIgnoreCase(SHOW_SOURCE)) { content = getSource(); // showSource = true; } else if (showCommand.equalsIgnoreCase(SHOW_SOLUTION)) { content = getSolution(); // showSource = true; } else if (showCommand.equalsIgnoreCase(SHOW_NEXTHINT)) { getNextHint(); } else if (showCommand.equalsIgnoreCase(SHOW_PREVIOUSHINT)) { getPreviousHint(); } } } isAdmin = request.isUserInRole(WEBGOAT_ADMIN); isHackedAdmin = myParser.getBooleanParameter(ADMIN, isAdmin); if (isHackedAdmin) { System.out.println("Hacked admin"); hasHackedHackableAdmin = true; } isColor = myParser.getBooleanParameter(COLOR, isColor); isDebug = myParser.getBooleanParameter(DEBUG, isDebug); // System.out.println( "showParams:" + showParams ); // System.out.println( "showSource:" + showSource ); // System.out.println( "showSolution:" + showSolution ); // System.out.println( "showCookies:" + showCookies ); // System.out.println( "showRequest:" + showRequest ); if (content != null) { response.setContentType("text/html"); PrintWriter out = new PrintWriter(response.getOutputStream()); out.print(content); out.flush(); out.close(); } } public void updateLastAttackRequestInfo(HttpServletRequest request) { // store cookies Cookie[] cookies = request.getCookies(); if (cookies == null) { this.cookiesOnLastRequest = new ArrayList(); } else { this.cookiesOnLastRequest = Arrays.asList(cookies); } // store parameters Map parmMap = request.getParameterMap(); logger.info("PARM MAP: " + parmMap); if (parmMap == null) { this.parmsOnLastRequest = new ArrayList(); } else { this.parmsOnLastRequest = new ArrayList(); for (String name : parmMap.keySet()) { String[] values = parmMap.get(name); String delim = ""; StringBuffer sb = new StringBuffer(); if (values != null && values.length > 0) { for (String parm : values) { sb.append(delim).append(parm); delim = ","; } } RequestParameter parm = new RequestParameter(name, sb.toString()); this.parmsOnLastRequest.add(parm); } } } private void restartLesson(int lessonId) { AbstractLesson al = getLesson(lessonId); System.out.println("Restarting lesson: " + al); al.getLessonTracker(this).setCompleted(false); if (al instanceof SequentialLessonAdapter) { SequentialLessonAdapter sla = (SequentialLessonAdapter) al; sla.getLessonTracker(this).setStage(1); } else if (al instanceof RandomLessonAdapter) { RandomLessonAdapter rla = (RandomLessonAdapter) al; rla.setStage(this, rla.getStages()[0]); } } /** * @param string */ public void setHasHackableAdmin(String role) { hasHackedHackableAdmin = (AbstractLesson.HACKED_ADMIN_ROLE.equals(role) & hasHackedHackableAdmin); // if the user got the Admin=true parameter correct AND they accessed an admin screen if (hasHackedHackableAdmin) { completedHackableAdmin = true; } } /** * @return Returns the isDebug. */ public boolean isDebug() { return isDebug; } /** * @param header - request header value to return * @return */ public String getHeader(String header) { return getRequest().getHeader(header); } public String getNextHint() { String hint = null; // FIXME int maxHints = getCurrentLesson().getHintCount(this); if (hintNum < maxHints - 1) { hintNum++; // Hints are indexed from 0 getCurrentLesson().getLessonTracker(this).setMaxHintLevel(getHintNum() + 1); hint = (String) getCurrentLesson().getHint(this, getHintNum()); } return hint; } public String getPreviousHint() { String hint = null; if (hintNum > 0) { hintNum--; // Hints are indexed from 0 getCurrentLesson().getLessonTracker(this).setMaxHintLevel(getHintNum() + 1); hint = (String) getCurrentLesson().getHint(this, getHintNum()); } return hint; } public void setCurrentMenu(Integer ranking) { currentMenu = ranking.intValue(); } public int getCurrentMenu() { return currentMenu; } public WebgoatContext getWebgoatContext() { return webgoatContext; } public String getCurrrentLanguage() { return currentLanguage; } /** * @return the cookiesOnLastRequest */ public List getCookiesOnLastRequest() { return cookiesOnLastRequest; } /** * @return the parmsOnLastRequest */ public List getParmsOnLastRequest() { return parmsOnLastRequest; } }