mjawurek 1dc6c799a7 A first attempt at internationalization of WebGoat. For complete internationalization WebGoat needs two things:
1. Every text passage/label that appears in lessons must independent of the current language set for WebGoat.
2. Every lesson plan and solutions must be translated for each supported language.
Number 1 is achieved by using webgoat/util/WebgoatI18N.java and by having every output routed through this piece of code. You no longer say hints.add("Lesson Hint 1"); or ....addElement("Shopping Cart")) but you in the lesson you say hints.add(WebGoatI18N.get("Lesson Hint1")) or ....addElement(WebGoatI18N.get("Shopping Cart"). Then WebGoatI18N looks up the corresponding string for the language set as the current lanuage and returns it.
Number 2 is achieved by having subdirectories in lesson_plans corresponding to every language. That means, a lesson that has been translated to Spanish and German will be found in lesson_plans/English and lesson_plans/Spanish and lesson_plans/German.

This is how WebGoat finds out about available languages: in Course.java in loadResources() it looks for lesson plans.
Unlike before, now a lesson plan can be found multiple times in different "language" directories. So for every directory the lesson plan is found in, WebGoat associates this language with the lesson and also lets WebGoatI18N load the appropriate WebGoatLabels_$LANGAUGE$.properties file which contains the translations of labels.
So this is what you have to do for a new language:
First of all, you have to copy and translate every lesson plan that you need in the new language, and then you also have to create a WebGoatLabels_$LANGUAGE$.properties file with that labels that will be used in these lessons. Atm WebGoat crashes throws an exception when a label is missing but this can be sorted out quickly. 

git-svn-id: http://webgoat.googlecode.com/svn/trunk/webgoat@389 4033779f-a91e-0410-96ef-6bf7bf53c507
2009-10-26 15:58:15 +00:00

847 lines
22 KiB
Java

package org.owasp.webgoat.lessons;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.apache.ecs.Element;
import org.apache.ecs.ElementContainer;
import org.apache.ecs.StringElement;
import org.apache.ecs.html.Body;
import org.apache.ecs.html.Form;
import org.apache.ecs.html.Head;
import org.apache.ecs.html.Html;
import org.apache.ecs.html.IMG;
import org.apache.ecs.html.PRE;
import org.apache.ecs.html.Title;
import org.owasp.webgoat.session.ParameterNotFoundException;
import org.owasp.webgoat.session.Screen;
import org.owasp.webgoat.session.WebSession;
import org.owasp.webgoat.session.WebgoatContext;
import org.owasp.webgoat.session.WebgoatProperties;
import org.owasp.webgoat.util.WebGoatI18N;
/***************************************************************************************************
*
*
* 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 Bruce Mayhew <a href="http://code.google.com/p/webgoat">WebGoat</a>
* @created October 28, 2003
*/
public abstract class AbstractLesson extends Screen implements Comparable<Object>
{
/**
* Description of the Field
*/
public final static String ADMIN_ROLE = "admin";
public final static String CHALLENGE_ROLE = "challenge";
/**
* Description of the Field
*/
public final static String HACKED_ADMIN_ROLE = "hacked_admin";
/**
* Description of the Field
*/
public final static String USER_ROLE = "user";
private static int count = 1;
private Integer id = null;
final static IMG nextGrey = new IMG("images/right16.gif").setAlt("Next").setBorder(0).setHspace(0).setVspace(0);
final static IMG previousGrey = new IMG("images/left14.gif").setAlt("Previous").setBorder(0).setHspace(0)
.setVspace(0);
private Integer ranking;
private Category category;
private boolean hidden;
private String sourceFileName;
private Map<String,String> lessonPlanFileName = new HashMap<String,String>();
private String lessonSolutionFileName;
private WebgoatContext webgoatContext;
private LinkedList<String> availableLanguages = new LinkedList<String>();
private String defaultLanguage = "English";
/**
* Constructor for the Lesson object
*/
public AbstractLesson()
{
id = new Integer(++count);
}
public String getName()
{
String className = getClass().getName();
return className.substring(className.lastIndexOf('.') + 1);
}
public void setRanking(Integer ranking)
{
this.ranking = ranking;
}
public void setHidden(boolean hidden)
{
this.hidden = hidden;
}
public void update(WebgoatProperties properties)
{
String className = getClass().getName();
className = className.substring(className.lastIndexOf(".") + 1);
setRanking(new Integer(properties.getIntProperty("lesson." + className + ".ranking", getDefaultRanking()
.intValue())));
String categoryRankingKey = "category." + getDefaultCategory().getName() + ".ranking";
// System.out.println("Category ranking key: " + categoryRankingKey);
Category tempCategory = Category.getCategory(getDefaultCategory().getName());
tempCategory.setRanking(new Integer(properties.getIntProperty(categoryRankingKey, getDefaultCategory()
.getRanking().intValue())));
category = tempCategory;
setHidden(properties.getBooleanProperty("lesson." + className + ".hidden", getDefaultHidden()));
// System.out.println(className + " in " + tempCategory.getName() + "
// (Category Ranking: " + tempCategory.getRanking() + " Lesson ranking:
// " + getRanking() + ", hidden:" + hidden +")");
}
public boolean isCompleted(WebSession s)
{
return getLessonTracker(s, this).getCompleted();
}
/**
* Gets the credits attribute of the AbstractLesson object
*
* @return The credits value
*/
public abstract Element getCredits();
/**
* Description of the Method
*
* @param obj
* Description of the Parameter
* @return Description of the Return Value
*/
public int compareTo(Object obj)
{
return this.getRanking().compareTo(((AbstractLesson) obj).getRanking());
}
/**
* Description of the Method
*
* @param obj
* Description of the Parameter
* @return Description of the Return Value
*/
public boolean equals(Object obj)
{
return this.getScreenId() == ((AbstractLesson) obj).getScreenId();
}
/**
* Gets the category attribute of the Lesson object
*
* @return The category value
*/
public Category getCategory()
{
return category;
}
protected abstract Integer getDefaultRanking();
protected abstract Category getDefaultCategory();
protected abstract boolean getDefaultHidden();
/**
* Gets the fileMethod attribute of the Lesson class
*
* @param reader
* Description of the Parameter
* @param methodName
* Description of the Parameter
* @param numbers
* Description of the Parameter
* @return The fileMethod value
*/
public static String getFileMethod(BufferedReader reader, String methodName, boolean numbers)
{
int count = 0;
StringBuffer sb = new StringBuffer();
boolean echo = false;
boolean startCount = false;
int parenCount = 0;
try
{
String line;
while ((line = reader.readLine()) != null)
{
if ((line.indexOf(methodName) != -1)
&& ((line.indexOf("public") != -1) || (line.indexOf("protected") != -1) || (line
.indexOf("private") != -1)))
{
echo = true;
startCount = true;
}
if (echo && startCount)
{
if (numbers)
{
sb.append(pad(++count) + " ");
}
sb.append(line + "\n");
}
if (echo && (line.indexOf("{") != -1))
{
parenCount++;
}
if (echo && (line.indexOf("}") != -1))
{
parenCount--;
if (parenCount == 0)
{
startCount = false;
echo = false;
}
}
}
reader.close();
} catch (Exception e)
{
System.out.println(e);
e.printStackTrace();
}
return (sb.toString());
}
/**
* Reads text from a file into an ElementContainer. Each line in the file is represented in the
* ElementContainer by a StringElement. Each StringElement is appended with a new-line
* character.
*
* @param reader
* Description of the Parameter
* @param numbers
* Description of the Parameter
* @return Description of the Return Value
*/
public static String readFromFile(BufferedReader reader, boolean numbers)
{
return (getFileText(reader, numbers));
}
/**
* Gets the fileText attribute of the Screen class
*
* @param reader
* Description of the Parameter
* @param numbers
* Description of the Parameter
* @return The fileText value
*/
public static String getFileText(BufferedReader reader, boolean numbers)
{
int count = 0;
StringBuffer sb = new StringBuffer();
try
{
String line;
while ((line = reader.readLine()) != null)
{
if (numbers)
{
sb.append(pad(++count) + " ");
}
sb.append(line + System.getProperty("line.separator"));
}
reader.close();
} catch (Exception e)
{
System.out.println(e);
e.printStackTrace();
}
return (sb.toString());
}
/**
* Will this screen be included in an enterprise edition.
*
* @return The ranking value
*/
public boolean isEnterprise()
{
return false;
}
/**
* Gets the hintCount attribute of the Lesson object
*
* @param s
* The user's WebSession
*
* @return The hintCount value
*/
public int getHintCount(WebSession s)
{
return getHints(s).size();
}
protected abstract List<String> getHints(WebSession s);
/**
* Fill in a minor hint that will help people who basically get it, but are stuck on somthing
* silly.
*
* @param s
* The users WebSession
*
* @return The hint1 value
*/
public String getHint(WebSession s, int hintNumber)
{
return "Hint: " + getHints(s).get(hintNumber);
}
/**
* Gets the instructions attribute of the AbstractLesson object
*
* @return The instructions value
*/
public abstract String getInstructions(WebSession s);
/**
* Gets the lessonPlan attribute of the Lesson object
*
* @return The lessonPlan value
*/
protected String getLessonName()
{
int index = this.getClass().getName().indexOf("lessons.");
return this.getClass().getName().substring(index + "lessons.".length());
}
/**
* Gets the title attribute of the HelloScreen object
*
* @return The title value
*/
public abstract String getTitle();
/**
* Gets the content of lessonPlanURL
*
* @param s
* The user's WebSession
*
* @return The HTML content of the current lesson plan
*/
public String getLessonPlan(WebSession s)
{
StringBuffer src = new StringBuffer();
String lang = s.getCurrrentLanguage();
try
{
// System.out.println("Loading lesson plan file: " +
// getLessonPlanFileName());
String filename = getLessonPlanFileName(lang);
if(filename==null){
filename = getLessonPlanFileName(getDefaultLanguage());
}
src.append(readFromFile(new BufferedReader(new FileReader(s.getWebResource(filename))), false));
} catch (Exception e)
{
// s.setMessage( "Could not find lesson plan for " +
// getLessonName());
src = new StringBuffer("Could not find lesson plan for: " + getLessonName()+" and language "+lang);
}
return src.toString();
}
/**
* Gets the ranking attribute of the Lesson object
*
* @return The ranking value
*/
public Integer getRanking()
{
if (ranking != null)
{
return ranking;
}
else
{
return getDefaultRanking();
}
}
/**
* Gets the hidden value of the Lesson Object
*
* @return The hidden value
*/
public boolean getHidden()
{
return this.hidden;
}
/**
* Gets the role attribute of the AbstractLesson object
*
* @return The role value
*/
public String getRole()
{
// FIXME: Each lesson should have a role assigned to it. Each
// user/student
// should also have a role(s) assigned. The user would only be allowed
// to see lessons that correspond to their role. Eventually these roles
// will be stored in the internal database. The user will be able to
// hack
// into the database and change their role. This will allow the user to
// see the admin screens, once they figure out how to turn the admin
// switch on.
return USER_ROLE;
}
/**
* Gets the uniqueID attribute of the AbstractLesson object
*
* @return The uniqueID value
*/
public int getScreenId()
{
return id.intValue();
}
public String getHtml_DELETE_ME(WebSession s)
{
String html = null;
// FIXME: This doesn't work for the labs since they do not implement
// createContent().
String rawHtml = createContent(s).toString();
// System.out.println("Getting raw html content: " +
// rawHtml.substring(0, Math.min(rawHtml.length(), 100)));
html = convertMetachars(AbstractLesson.readFromFile(new BufferedReader(new StringReader(rawHtml)), true));
// System.out.println("Getting encoded html content: " +
// html.substring(0, Math.min(html.length(), 100)));
return html;
}
public String getSource(WebSession s)
{
String source = null;
String src = null;
try
{
// System.out.println("Loading source file: " +
// getSourceFileName());
src = convertMetacharsJavaCode(readFromFile(new BufferedReader(new FileReader(s
.getWebResource(getSourceFileName()))), true));
// TODO: For styled line numbers and better memory efficiency,
// use a custom FilterReader
// that performs the convertMetacharsJavaCode() transform plus
// optionally adds a styled
// line number. Wouldn't color syntax be great too?
} catch (Exception e)
{
s.setMessage("Could not find source file");
src = ("Could not find the source file or source file does not exist.<br/>"
+ "Send this message to: <a href=\"mailto:" + s.getWebgoatContext().getFeedbackAddress()
+ "?subject=Source " + getSourceFileName() + " not found. Lesson: "
+ s.getCurrentLesson().getLessonName() + "\">" + s.getWebgoatContext().getFeedbackAddress() + "</a>");
}
Html html = new Html();
Head head = new Head();
head.addElement(new Title(getSourceFileName()));
Body body = new Body();
body.addElement(new StringElement(src));
html.addElement(head);
html.addElement(body);
source = html.toString();
return source;
}
public String getSolution(WebSession s)
{
String src = null;
try
{
// System.out.println("Solution: " + getLessonSolutionFileName());
src = readFromFile(new BufferedReader(new FileReader(s.getWebResource(getLessonSolutionFileName()))), false);
} catch (Exception e)
{
s.setMessage("Could not find the solution file");
src = ("Could not find the solution file or solution file does not exist.<br/>"
+ "Send this message to: <a href=\"mailto:" + s.getWebgoatContext().getFeedbackAddress()
+ "?subject=Solution " + getLessonSolutionFileName() + " not found. Lesson: "
+ s.getCurrentLesson().getLessonName() + "\">" + s.getWebgoatContext().getFeedbackAddress() + "</a>");
}
// Solutions are html files
return src;
}
/**
* Get the link that can be used to request this screen.
*
* @return
*/
public String getLink()
{
StringBuffer link = new StringBuffer();
link.append("attack?");
link.append(WebSession.SCREEN);
link.append("=");
link.append(getScreenId());
link.append("&");
link.append(WebSession.MENU);
link.append("=");
link.append(getCategory().getRanking());
return link.toString();
}
/**
* Get the link to the jsp page used to render this screen.
*
* @return
*/
public String getPage(WebSession s)
{
return null;
}
/**
* Get the link to the jsp template page used to render this screen.
*
* @return
*/
public String getTemplatePage(WebSession s)
{
return null;
}
public abstract String getCurrentAction(WebSession s);
public abstract void setCurrentAction(WebSession s, String lessonScreen);
/**
* Override this method to implement accesss control in a lesson.
*
* @param s
* @param functionId
* @return
*/
public boolean isAuthorized(WebSession s, int employeeId, String functionId)
{
return false;
}
/**
* Override this method to implement accesss control in a lesson.
*
* @param s
* @param functionId
* @return
*/
public boolean isAuthorized(WebSession s, String role, String functionId)
{
boolean authorized = false;
try
{
String query = "SELECT * FROM auth WHERE role = '" + role + "' and functionid = '" + functionId + "'";
try
{
Statement answer_statement = WebSession.getConnection(s)
.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
ResultSet answer_results = answer_statement.executeQuery(query);
authorized = answer_results.first();
} catch (SQLException sqle)
{
s.setMessage("Error authorizing");
sqle.printStackTrace();
}
} catch (Exception e)
{
s.setMessage("Error authorizing");
e.printStackTrace();
}
return authorized;
}
public int getUserId(WebSession s) throws ParameterNotFoundException
{
return -1;
}
public String getUserName(WebSession s) throws ParameterNotFoundException
{
return null;
}
/**
* Description of the Method
*
* @param windowName
* Description of the Parameter
* @return Description of the Return Value
*/
public static String makeWindowScript(String windowName)
{
// FIXME: make this string static
StringBuffer script = new StringBuffer();
script.append("<script language=\"JavaScript\">\n");
script.append(" <!--\n");
script.append(" function makeWindow(url) {\n");
script.append("\n");
script.append(" agent = navigator.userAgent;\n");
script.append("\n");
script.append(" params = \"\";\n");
script.append(" params += \"toolbar=0,\";\n");
script.append(" params += \"location=0,\";\n");
script.append(" params += \"directories=0,\";\n");
script.append(" params += \"status=0,\";\n");
script.append(" params += \"menubar=0,\";\n");
script.append(" params += \"scrollbars=1,\";\n");
script.append(" params += \"resizable=1,\";\n");
script.append(" params += \"width=500,\";\n");
script.append(" params += \"height=350\";\n");
script.append("\n");
script.append(" // close the window to vary the window size\n");
script.append(" if (typeof(win) == \"object\" && !win.closed){\n");
script.append(" win.close();\n");
script.append(" }\n");
script.append("\n");
script.append(" win = window.open(url, '" + windowName + "' , params);\n");
script.append("\n");
script.append(" // bring the window to the front\n");
script.append(" win.focus();\n");
script.append(" }\n");
script.append(" //-->\n");
script.append(" </script>\n");
return script.toString();
}
/**
* Simply reads a url into an Element for display. CAUTION: you might want to tinker with any
* non-https links (href)
*
* @param url
* Description of the Parameter
* @return Description of the Return Value
*/
public static Element readFromURL(String url)
{
ElementContainer ec = new ElementContainer();
try
{
URL u = new URL(url);
HttpURLConnection huc = (HttpURLConnection) u.openConnection();
BufferedReader reader = new BufferedReader(new InputStreamReader(huc.getInputStream()));
String line;
while ((line = reader.readLine()) != null)
{
ec.addElement(new StringElement(line));
}
reader.close();
} catch (Exception e)
{
System.out.println(e);
e.printStackTrace();
}
return (ec);
}
/**
* Description of the Method
*
* @param reader
* Description of the Parameter
* @param numbers
* Description of the Parameter
* @param methodName
* Description of the Parameter
* @return Description of the Return Value
*/
public static Element readMethodFromFile(BufferedReader reader, String methodName, boolean numbers)
{
PRE pre = new PRE().addElement(getFileMethod(reader, methodName, numbers));
return (pre);
}
/**
* Description of the Method
*
* @param s
* Description of the Parameter
*/
public void handleRequest(WebSession s)
{
// call createContent first so messages will go somewhere
Form form = new Form(getFormAction(), Form.POST).setName("form").setEncType("");
form.addElement(createContent(s));
setContent(form);
}
public String getFormAction()
{
return getLink();
}
/**
* Description of the Method
*
* @param s
* Description of the Parameter
* @return Description of the Return Value
*/
public String toString()
{
return getTitle();
}
public String getDefaultLanguage(){
return this.defaultLanguage;
}
public String getLessonPlanFileName(String lang)
{
String ret = lessonPlanFileName.get(lang);
if(ret==null) ret = lessonPlanFileName.get(getDefaultLanguage());
return ret;
}
public void setLessonPlanFileName(String lang, String lessonPlanFileName)
{
this.lessonPlanFileName.put(lang,lessonPlanFileName);
this.availableLanguages.add(lang);
}
public List<String> getAvailableLanguages(){
return this.availableLanguages;
}
public String getLessonSolutionFileName()
{
return lessonSolutionFileName;
}
public void setLessonSolutionFileName(String lessonSolutionFileName)
{
this.lessonSolutionFileName = lessonSolutionFileName;
}
public String getSourceFileName()
{
return sourceFileName;
}
public void setSourceFileName(String sourceFileName)
{
// System.out.println("Setting source file of lesson " + this + " to: "
// + sourceFileName);
this.sourceFileName = sourceFileName;
}
public WebgoatContext getWebgoatContext()
{
return webgoatContext;
}
public void setWebgoatContext(WebgoatContext webgoatContext)
{
this.webgoatContext = webgoatContext;
}
}