diff --git a/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/CrossSiteScripting/CrossSiteScripting.java b/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/CrossSiteScripting/CrossSiteScripting.java
index 943dd8103..7bf96665f 100644
--- a/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/CrossSiteScripting/CrossSiteScripting.java	
+++ b/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/CrossSiteScripting/CrossSiteScripting.java	
@@ -54,6 +54,18 @@ public class CrossSiteScripting extends GoatHillsFinancial
 {
     private final static Integer DEFAULT_RANKING = new Integer(100);
 
+    public final static String STAGE1 = "Stage 1";
+    
+    public final static String STAGE2 = "Stage 2";
+    
+    public final static String STAGE3 = "Stage 3";
+    
+    public final static String STAGE4 = "Stage 4";
+    
+    public final static String STAGE5 = "Stage 5";
+    
+    public final static String STAGE6 = "Stage 6";
+    
     protected void registerActions(String className)
     {
 	registerAction(new ListStaff(this, className, LISTSTAFF_ACTION));
@@ -140,52 +152,47 @@ public class CrossSiteScripting extends GoatHillsFinancial
 
 	if (!getLessonTracker(s).getCompleted())
 	{
-	    switch (getStage(s))
+		String stage = getStage(s);
+		if (STAGE1.equals(stage))
 	    {
-		case 1:
-		    instructions = "Stage "
-			    + getStage(s)
+		    instructions = getStage(s)
 			    + ": Execute a Stored Cross Site Scripting (XSS) attack.<br>"
 			    + "For this exercise, your mission is to cause the application to serve a script of your making "
 			    + " to some other user.";
-		    break;
-		case 2:
-		    instructions = "Stage "
-			    + getStage(s)
+	    }
+		else if (STAGE2.equals(stage))
+		{
+		    instructions = getStage(s)
 			    + ": Block Stored XSS using Input Validation.<br>"
 			    + "You will modify the application to perform input validation on the vulnerable input field "
 			    + "you just exploited.";
-		    break;
-		case 3:
-		    instructions = "Stage "
-			    + getStage(s)
+		}
+		else if (STAGE3.equals(stage))
+		{
+		    instructions = getStage(s)
 			    + ": Execute a previously Stored Cross Site Scripting (XSS) attack.<br>"
 			    + "The application is still vulnerable to scripts in the database.  Trigger a pre-stored "
 			    + "script by logging in as employee 'David' and viewing Bruce's profile.";
-		    break;
-		case 4:
-		    instructions = "Stage "
-			    + getStage(s)
+		}
+		else if (STAGE4.equals(stage))
+		{
+		    instructions = getStage(s)
 			    + ": Block Stored XSS using Output Encoding.<br>"
 			    + "Encode data served from the database to the client so that any scripts are rendered harmless.";
-		    break;
-		case 5:
-		    instructions = "Stage "
-			    + getStage(s)
+		}
+		else if (STAGE5.equals(stage))
+		{
+		    instructions = getStage(s)
 			    + ": Execute a Reflected XSS attack.<br>"
 			    + "Your goal here is to craft a link containing a script which the application will "
 			    + "serve right back to any client that activates the link.";
-		    break;
-		case 6:
-		    instructions = "Stage "
-			    + getStage(s)
+		}
+		else if (STAGE6.equals(stage))
+		{
+		    instructions = getStage(s)
 			    + ": Block Reflected XSS using Input Validation.<br>"
 			    + "Use the input validation techniques learned ealier in this lesson to close the vulnerability "
 			    + "you just exploited.";
-		    break;
-		default:
-		    // Illegal stage value
-		    break;
 	    }
 	}
 
@@ -194,8 +201,8 @@ public class CrossSiteScripting extends GoatHillsFinancial
     }
 
     @Override
-	public int getStageCount() {
-		return 6;
+	public String[] getStages() {
+		return new String[] {STAGE1, STAGE2, STAGE3, STAGE4, STAGE5, STAGE6};
 	}
 
     public void handleRequest(WebSession s)
@@ -290,12 +297,11 @@ public class CrossSiteScripting extends GoatHillsFinancial
 	public String htmlEncode(WebSession s, String text)
 	{
 		//System.out.println("Testing for stage 4 completion in lesson " + getCurrentLesson().getName());
-		if (getStage(s) == 4 && 
+		if (STAGE4.equals(getStage(s)) && 
 				text.indexOf("<script>") > -1 && text.indexOf("alert") > -1 && text.indexOf("</script>") > -1)
 		{
 			s.setMessage( "Welcome to stage 5 -- exploiting the data layer" );
-			// Set a phantom stage value to setup for the 4-5 transition
-			setStage(s, 1005);
+			setStageComplete(s, STAGE5);
 		}
 		
 		return HtmlEncoder.encode(text);
diff --git a/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/CrossSiteScripting/FindProfile.java b/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/CrossSiteScripting/FindProfile.java
index 97b1a22e2..6449bca27 100644
--- a/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/CrossSiteScripting/FindProfile.java	
+++ b/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/CrossSiteScripting/FindProfile.java	
@@ -88,23 +88,23 @@ public class FindProfile extends DefaultLessonAction
 	    }
 	    catch (ValidationException e)
 	    {
-		if (getStage(s) == 6)
+		if (CrossSiteScripting.STAGE6.equals(getStage(s)))
 		{
 		    s
 			    .setMessage("Congratulations. You have successfully completed this lesson");
-		    getLesson().getLessonTracker(s).setCompleted(true);
+		    setStageComplete(s, CrossSiteScripting.STAGE6);
 		}
 		throw e;
 	    }
 
-	    if (getStage(s) == 5)
+	    if (CrossSiteScripting.STAGE5.equals(getStage(s)))
 	    {
 		if (searchName.indexOf("<script>") > -1
 			&& searchName.indexOf("alert") > -1
 			&& searchName.indexOf("</script>") > -1)
 		{
 		    s.setMessage("Welcome to stage 6 - more input validation");
-		    setStage(s, 6);
+		    setStageComplete(s, CrossSiteScripting.STAGE5);
 		}
 	    }
 
diff --git a/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/CrossSiteScripting/UpdateProfile.java b/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/CrossSiteScripting/UpdateProfile.java
index d04699b09..193ce168a 100644
--- a/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/CrossSiteScripting/UpdateProfile.java	
+++ b/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/CrossSiteScripting/UpdateProfile.java	
@@ -81,11 +81,11 @@ public class UpdateProfile extends DefaultLessonAction
 	    }
 	    catch (ValidationException e)
 	    {
-		if (getStage(s) == 2)
+		if (CrossSiteScripting.STAGE2.equals(getStage(s)))
 		{
 		    s
 			    .setMessage("Welcome to stage 3 - demonstrate Stored XSS again");
-		    setStage(s, 3);
+		    setStageComplete(s, CrossSiteScripting.STAGE2);
 		}
 		throw e;
 	    }
diff --git a/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/CrossSiteScripting/ViewProfile.java b/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/CrossSiteScripting/ViewProfile.java
index d9d75f36c..9b2e6e47b 100644
--- a/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/CrossSiteScripting/ViewProfile.java	
+++ b/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/CrossSiteScripting/ViewProfile.java	
@@ -212,9 +212,9 @@ public class ViewProfile extends DefaultLessonAction
 
     private void updateLessonStatus(WebSession s, Employee employee)
     {
-	switch (getStage(s))
+	String stage = getStage(s);
+	if (CrossSiteScripting.STAGE1.equals(stage))
 	{
-	    case 1:
 		String address1 = employee.getAddress1().toLowerCase();
 		if (address1.indexOf("<script>") > -1
 			&& address1.indexOf("alert") > -1
@@ -222,10 +222,11 @@ public class ViewProfile extends DefaultLessonAction
 		{
 		    s
 			    .setMessage("Welcome to stage 2 - implement input validation");
-		    setStage(s, 2);
+		    setStageComplete(s, CrossSiteScripting.STAGE1);
 		}
-		break;
-	    case 3:
+	}
+	else if (CrossSiteScripting.STAGE3.equals(stage))
+	{
 		String address2 = employee.getAddress1().toLowerCase();
 		if (address2.indexOf("<script>") > -1
 			&& address2.indexOf("alert") > -1
@@ -233,19 +234,17 @@ public class ViewProfile extends DefaultLessonAction
 		{
 		    s
 			    .setMessage("Welcome to stage 4 - implement output encoding");
-		    setStage(s, 4);
+		    setStageComplete(s, CrossSiteScripting.STAGE3);
 		}
-		break;
-	    case 4:
+	}
+	else if (CrossSiteScripting.STAGE4.equals(stage))
+	{
 		if (employee.getAddress1().toLowerCase().indexOf("&lt;") > -1)
 		{
 		    s
 			    .setMessage("Welcome to stage 5 - demonstrate reflected XSS");
-		    setStage(s, 5);
+		    setStageComplete(s, CrossSiteScripting.STAGE4);
 		}
-		break;
-	    default:
-		break;
 	}
     }
 
diff --git a/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/GoatHillsFinancial/DefaultLessonAction.java b/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/GoatHillsFinancial/DefaultLessonAction.java
index 19fcf1a74..69e064fff 100644
--- a/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/GoatHillsFinancial/DefaultLessonAction.java	
+++ b/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/GoatHillsFinancial/DefaultLessonAction.java	
@@ -312,12 +312,16 @@ public abstract class DefaultLessonAction implements LessonAction
 		return authorized;
 	}
 	
-	protected void setStage(WebSession s, int stage)
+	protected void setStage(WebSession s, String stage)
 	{
 		getLesson().setStage(s, stage);
 	}
 
-	protected int getStage(WebSession s)
+	protected void setStageComplete(WebSession s, String stage) {
+		getLesson().setStageComplete(s, stage);
+	}
+	
+	protected String getStage(WebSession s)
 	{
 		return getLesson().getStage(s);
 	}
diff --git a/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/GoatHillsFinancial/GoatHillsFinancial.java b/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/GoatHillsFinancial/GoatHillsFinancial.java
index 7286e3d16..95b65b31a 100755
--- a/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/GoatHillsFinancial/GoatHillsFinancial.java	
+++ b/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/GoatHillsFinancial/GoatHillsFinancial.java	
@@ -9,7 +9,7 @@ import org.apache.ecs.Element;
 import org.apache.ecs.ElementContainer;
 import org.apache.ecs.html.A;
 import org.apache.ecs.html.IMG;
-import org.owasp.webgoat.lessons.SequentialLessonAdapter;
+import org.owasp.webgoat.lessons.RandomLessonAdapter;
 import org.owasp.webgoat.session.ParameterNotFoundException;
 import org.owasp.webgoat.session.UnauthenticatedException;
 import org.owasp.webgoat.session.UnauthorizedException;
@@ -45,7 +45,7 @@ import org.owasp.webgoat.session.WebSession;
  * 
  * For details, please see http://code.google.com/p/webgoat/
  */
-public class GoatHillsFinancial extends SequentialLessonAdapter
+public class GoatHillsFinancial extends RandomLessonAdapter
 {
 	public final static A ASPECT_LOGO = new A().setHref("http://www.aspectsecurity.com").addElement(new IMG("images/logos/aspect.jpg").setAlt("Aspect Security").setBorder(0).setHspace(0).setVspace(0));
 
@@ -161,6 +161,10 @@ public class GoatHillsFinancial extends SequentialLessonAdapter
 	lessonFunctions.put(action.getActionName(), action);
     }
 
+    public String[] getStages() {
+    	return new String[] {};
+    }
+    
     protected List<String> getHints(WebSession s)
     {
 	return new ArrayList<String>();
diff --git a/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/RandomLessonAdapter.java b/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/RandomLessonAdapter.java
new file mode 100755
index 000000000..28592ce03
--- /dev/null
+++ b/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/RandomLessonAdapter.java	
@@ -0,0 +1,45 @@
+package org.owasp.webgoat.lessons;
+
+import org.owasp.webgoat.session.LessonTracker;
+import org.owasp.webgoat.session.RandomLessonTracker;
+import org.owasp.webgoat.session.WebSession;
+
+public abstract class RandomLessonAdapter extends LessonAdapter {
+
+	public abstract String[] getStages();
+	
+	public void setStage(WebSession s, String stage) {
+		getLessonTracker(s).setStage(stage);
+	}
+	
+	public String getStage(WebSession s) {
+		return getLessonTracker(s).getStage();
+	}
+	
+	public void setStageComplete(WebSession s, String stage) {
+		getLessonTracker(s).setStageComplete(stage, true);
+	}
+	
+	@Override
+    public RandomLessonTracker getLessonTracker(WebSession s) {
+    	return (RandomLessonTracker) super.getLessonTracker(s);
+    }
+
+
+	@Override
+	public RandomLessonTracker getLessonTracker(WebSession s, AbstractLesson lesson) {
+		return (RandomLessonTracker) super.getLessonTracker(s, lesson);
+	}
+
+
+	@Override
+	public RandomLessonTracker getLessonTracker(WebSession s, String userNameOverride) {
+		return (RandomLessonTracker) super.getLessonTracker(s, userNameOverride);
+	}
+
+	@Override
+	public LessonTracker createLessonTracker() {
+		return new RandomLessonTracker(getStages());
+	}
+
+}
diff --git a/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/RoleBasedAccessControl/DeleteProfile.java b/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/RoleBasedAccessControl/DeleteProfile.java
index bc4d84e31..017d74f3c 100644
--- a/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/RoleBasedAccessControl/DeleteProfile.java	
+++ b/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/RoleBasedAccessControl/DeleteProfile.java	
@@ -160,7 +160,7 @@ public class DeleteProfile extends DefaultLessonAction
     private void updateLessonStatus(WebSession s)
     {
 	// If the logged in user is not authorized to be here, stage 1 is complete.
-	if (getStage(s) == 1) 
+	if (RoleBasedAccessControl.STAGE1.equals(getStage(s))) 
 	try
 	{
 	    int userId = getIntSessionAttribute(s, getLessonName() + "."
@@ -171,7 +171,7 @@ public class DeleteProfile extends DefaultLessonAction
 	    {
 		s
 			.setMessage("Welcome to stage 2 -- protecting the business layer");
-		setStage(s, 2);
+		setStageComplete(s, RoleBasedAccessControl.STAGE1);
 	    }
 	}
 	catch (ParameterNotFoundException e)
diff --git a/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/RoleBasedAccessControl/RoleBasedAccessControl.java b/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/RoleBasedAccessControl/RoleBasedAccessControl.java
index 6d4ceb470..db613c995 100644
--- a/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/RoleBasedAccessControl/RoleBasedAccessControl.java	
+++ b/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/RoleBasedAccessControl/RoleBasedAccessControl.java	
@@ -52,6 +52,14 @@ public class RoleBasedAccessControl extends GoatHillsFinancial
 {
     private final static Integer DEFAULT_RANKING = new Integer(125);
 
+    public final static String STAGE1 = "Stage 1";
+    
+    public final static String STAGE2 = "Stage 2";
+    
+    public final static String STAGE3 = "Stage 3";
+    
+    public final static String STAGE4 = "Stage 4";
+
     protected void registerActions(String className) {
     	registerAction(new ListStaff(this, className, LISTSTAFF_ACTION));
     	registerAction(new SearchStaff(this, className, SEARCHSTAFF_ACTION));
@@ -114,8 +122,8 @@ public class RoleBasedAccessControl extends GoatHillsFinancial
     }
 
     @Override
-	public int getStageCount() {
-		return 4;
+	public String[] getStages() {
+		return new String[] {STAGE1, STAGE2, STAGE3, STAGE4};
 	}
 
     /**
@@ -129,41 +137,40 @@ public class RoleBasedAccessControl extends GoatHillsFinancial
 
 	if (!getLessonTracker(s).getCompleted())
 	{
-	    switch (getStage(s))
+		String stage = getStage(s);
+		if (STAGE1.equals(stage))
 	    {
-		case 1:
 		    instructions = "Stage "
 			    + getStage(s)
 			    + ": Breaking functional access control.<br>"
 			    + "You should be able to login as a regular employee and delete another user's employee "
 			    + "profile, even though that is supposed to be an HR-only function.";
-		    break;
-		case 2:
+	    }
+		else if (STAGE2.equals(stage))
+		{
 		    instructions = "Stage "
 			    + getStage(s)
 			    + ": Implementing access control in the Business Layer<br>"
 			    + "Access control has already been implemented in the Presentation Layer, but as we have just "
 			    + "seen, this is not enough.  Implement access control in the Businesss Layer to verify "
 			    + "authorization to use the Delete function before actually executing it.";
-		    break;
-		case 3:
+		}
+		else if (STAGE3.equals(stage))
+		{
 		    instructions = "Stage "
 			    + getStage(s)
 			    + ": Breaking data access control.<br>"
 			    + "Data Layer access control is being already done on the staff list, but it has not been "
 			    + "globally implemented.  Take advantage of this to login as a regular employee and view the "
 			    + "CEO's employee profile.";
-		    break;
-		case 4:
+		}
+		else if (STAGE4.equals(stage))
+		{
 		    instructions = "Stage "
 			    + getStage(s)
 			    + ": Implementing access control in the Data Layer.<br>"
 			    + "Implement Data Layer access control to prevent unauthorized (and potentially career threatening) "
 			    + "access to employee personal data.";
-		    break;
-		default:
-		    // Illegal stage value
-		    break;
 	    }
 	}
 
@@ -236,7 +243,8 @@ public class RoleBasedAccessControl extends GoatHillsFinancial
 	catch (UnauthorizedException ue2)
 	{
 		// Update lesson status if necessary.
-		if (getStage(s) == 2)
+		String stage = getStage(s);
+		if (STAGE2.equals(stage))
 		{
 			try
 			{
@@ -244,7 +252,7 @@ public class RoleBasedAccessControl extends GoatHillsFinancial
 					!isAuthorized(s, getUserId(s), RoleBasedAccessControl.DELETEPROFILE_ACTION))
 			{
 				s.setMessage( "Welcome to stage 3 -- exploiting the data layer" );
-				setStage(s, 3);
+				setStageComplete(s, STAGE2);
 			}
 			} catch (ParameterNotFoundException pnfe)
 			{
@@ -253,7 +261,7 @@ public class RoleBasedAccessControl extends GoatHillsFinancial
 		}
 		//System.out.println("isAuthorized() exit stage: " + getStage(s));
 		// Update lesson status if necessary.
-		if (getStage(s) == 4)
+		if (STAGE4.equals(stage))
 		{
 			try
 			{
@@ -267,7 +275,7 @@ public class RoleBasedAccessControl extends GoatHillsFinancial
 			if (!action.isAuthorizedForEmployee(s, userId, employeeId))
 			{
 			    s.setMessage("Congratulations. You have successfully completed this lesson.");
-			    getLessonTracker( s ).setCompleted( true );
+			    setStageComplete(s, STAGE4);
 			}
 			} catch (Exception e)
 			{
@@ -370,8 +378,9 @@ public class RoleBasedAccessControl extends GoatHillsFinancial
 	    }
 	    catch (UnauthorizedException ue2)
 		{
+	    	String stage = getStage(s);
 			// Update lesson status if necessary.
-			if (getStage(s) == 2)
+			if (STAGE2.equals(stage))
 			{
 				try
 				{
@@ -379,7 +388,7 @@ public class RoleBasedAccessControl extends GoatHillsFinancial
 						!isAuthorized(s, getUserId(s), RoleBasedAccessControl.DELETEPROFILE_ACTION))
 				{
 					s.setMessage( "Welcome to stage 3 -- exploiting the data layer" );
-					setStage(s, 3);
+					setStageComplete(s, STAGE2);
 				}
 				} catch (ParameterNotFoundException pnfe)
 				{
@@ -388,7 +397,7 @@ public class RoleBasedAccessControl extends GoatHillsFinancial
 			}
 			//System.out.println("isAuthorized() exit stage: " + getStage(s));
 			// Update lesson status if necessary.
-			if (getStage(s) == 4)
+			if (STAGE4.equals(stage))
 			{
 				try
 				{
@@ -402,7 +411,7 @@ public class RoleBasedAccessControl extends GoatHillsFinancial
 				if (!action.isAuthorizedForEmployee(s, userId, employeeId))
 				{
 				    s.setMessage("Congratulations. You have successfully completed this lesson.");
-				    getLessonTracker( s ).setCompleted( true );
+				    setStageComplete(s, STAGE4);
 				}
 				} catch (Exception e)
 				{
diff --git a/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/RoleBasedAccessControl/ViewProfile.java b/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/RoleBasedAccessControl/ViewProfile.java
index 384e75b4e..75d5f8bef 100644
--- a/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/RoleBasedAccessControl/ViewProfile.java	
+++ b/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/RoleBasedAccessControl/ViewProfile.java	
@@ -95,11 +95,11 @@ public class ViewProfile extends DefaultLessonAction
 	    int employeeId = s.getParser().getIntParameter(
 		    RoleBasedAccessControl.EMPLOYEE_ID);
 
-	    if (getStage(s) == 3
+	    if (RoleBasedAccessControl.STAGE3.equals(getStage(s))
 		    && !isAuthorizedForEmployee(s, userId, employeeId))
 	    {
 		s.setMessage("Welcome to stage 4 -- protecting the data layer");
-		setStage(s, 4);
+		setStageComplete(s, RoleBasedAccessControl.STAGE3);
 	    }
 	}
 	catch (ParameterNotFoundException e)
diff --git a/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/SQLInjection/Login.java b/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/SQLInjection/Login.java
index cfb172bce..62a0d30b0 100644
--- a/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/SQLInjection/Login.java	
+++ b/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/SQLInjection/Login.java	
@@ -270,28 +270,26 @@ public class Login extends DefaultLessonAction
 		    SQLInjection.EMPLOYEE_ID);
 	    String password = s.getParser().getRawParameter(
 		    SQLInjection.PASSWORD);
-	    switch (getStage(s))
+	    String stage = getStage(s);
+	    if (SQLInjection.STAGE1.equals(stage))
 	    {
-		case 1:
 		    if (Integer.parseInt(employeeId) == SQLInjection.PRIZE_EMPLOYEE_ID
 			    && isAuthenticated(s))
 		    {
 			s.setMessage("Welcome to stage 2");
-			setStage(s, 2);
+			setStageComplete(s, SQLInjection.STAGE1);
 		    }
-		    break;
-		case 2:
+	    }
+	    else if (SQLInjection.STAGE2.equals(stage))
+	    {
 		    // This assumes the student hasn't modified login_BACKUP().
 		    if (Integer.parseInt(employeeId) == SQLInjection.PRIZE_EMPLOYEE_ID
 			    && !isAuthenticated(s)
 			    && login_BACKUP(s, employeeId, password))
 		    {
 			s.setMessage("Welcome to stage 3");
-			setStage(s, 3);
+			setStageComplete(s, SQLInjection.STAGE2);
 		    }
-		    break;
-		default:
-		    break;
 	    }
 	}
 	catch (ParameterNotFoundException pnfe)
diff --git a/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/SQLInjection/SQLInjection.java b/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/SQLInjection/SQLInjection.java
index 193fe1219..c3b4ad057 100644
--- a/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/SQLInjection/SQLInjection.java	
+++ b/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/SQLInjection/SQLInjection.java	
@@ -55,6 +55,14 @@ public class SQLInjection extends GoatHillsFinancial
 
     public final static String PRIZE_EMPLOYEE_NAME = "Neville Bartholomew";
 
+    public final static String STAGE1 = "Stage 1";
+    
+    public final static String STAGE2 = "Stage 2";
+    
+    public final static String STAGE3 = "Stage 3";
+    
+    public final static String STAGE4 = "Stage 4";
+    
     public void registerActions(String className)
     {
 	registerAction(new ListStaff(this, className, LISTSTAFF_ACTION));
@@ -122,8 +130,8 @@ public class SQLInjection extends GoatHillsFinancial
     }
 
     @Override
-	public int getStageCount() {
-		return 4;
+	public String[] getStages() {
+		return new String[] {STAGE1, STAGE2, STAGE3, STAGE4};
 	}
 
     /**
@@ -137,9 +145,9 @@ public class SQLInjection extends GoatHillsFinancial
 
 	if (!getLessonTracker(s).getCompleted())
 	{
-	    switch (getStage(s))
+		String stage = getStage(s);
+		if (STAGE1.equals(stage))
 	    {
-		case 1:
 		    instructions = "Stage "
 			    + getStage(s)
 			    + ": Use String SQL Injection to bypass authentication. "
@@ -147,32 +155,31 @@ public class SQLInjection extends GoatHillsFinancial
 			    + PRIZE_EMPLOYEE_NAME
 			    + ", who is in the Admin group.  "
 			    + "You do not have the password, but the form is SQL injectable.";
-		    break;
-		case 2:
+	    }
+		else if (STAGE2.equals(stage))
+		{
 		    instructions = "Stage "
 			    + getStage(s)
 			    + ": Use a parameterized query.<br>"
 			    + "A dynamic SQL query is not necessary for the login function to work.  Change login "
 			    + "to use a parameterized query to protect against malicious SQL in the query parameters.";
-		    break;
-		case 3:
+		}
+		else if (STAGE3.equals(stage))
+		{
 		    instructions = "Stage "
 			    + getStage(s)
 			    + ": Use Integer SQL Injection to bypass access control.<br>"
 			    + "The goal here is to view the CEO's employee profile, again, even with data access "
 			    + "control checks in place from a previous lesson.  "
 			    + "As before, you do not have the password, but the form is SQL injectable.";
-		    break;
-		case 4:
+		}
+		else if (STAGE4.equals(stage))
+		{
 		    instructions = "Stage "
 			    + getStage(s)
 			    + ": Use a parameterized query again.<br>"
 			    + "Change the ViewProfile function to use a parameterized query to protect against "
 			    + "malicious SQL in the numeric query parameter.";
-		    break;
-		default:
-		    // Illegal stage value
-		    break;
 	    }
 	}
 
diff --git a/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/SQLInjection/ViewProfile.java b/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/SQLInjection/ViewProfile.java
index 316b8c363..84cfd1672 100644
--- a/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/SQLInjection/ViewProfile.java	
+++ b/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/SQLInjection/ViewProfile.java	
@@ -224,9 +224,9 @@ public class ViewProfile extends DefaultLessonAction
 		    + SQLInjection.USER_ID);
 	    String employeeId = s.getParser().getRawParameter(
 		    SQLInjection.EMPLOYEE_ID);
-	    switch (getStage(s))
+	    String stage = getStage(s);
+	    if (SQLInjection.STAGE3.equals(stage))
 	    {
-		case 3:
 		    // If the employee we are viewing is the prize and we are not authorized to have it, 
 		    // the stage is completed
 		    if (employee != null
@@ -235,10 +235,11 @@ public class ViewProfile extends DefaultLessonAction
 				    .parseInt(userId), employee.getId()))
 		    {
 			s.setMessage("Welcome to stage 4");
-			setStage(s, 4);
+			setStageComplete(s, SQLInjection.STAGE3);
 		    }
-		    break;
-		case 4:
+	    }
+	    else if (SQLInjection.STAGE4.equals(stage))
+	    {
 		    // If we were denied the employee to view, and we would have been able to view it
 		    // in the broken state, the stage is completed.
 		    // This assumes the student hasn't modified getEmployeeProfile_BACKUP().
@@ -257,12 +258,9 @@ public class ViewProfile extends DefaultLessonAction
 			{
 			    s
 				    .setMessage("Congratulations. You have successfully completed this lesson");
-			    getLesson().getLessonTracker(s).setCompleted(true);
+			    setStageComplete(s, SQLInjection.STAGE4);
 			}
 		    }
-		    break;
-		default:
-		    break;
 	    }
 	}
 	catch (ParameterNotFoundException pnfe)
diff --git a/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/instructor/RoleBasedAccessControl/RoleBasedAccessControl_i.java b/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/instructor/RoleBasedAccessControl/RoleBasedAccessControl_i.java
index d99937e30..af0cc2d30 100644
--- a/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/instructor/RoleBasedAccessControl/RoleBasedAccessControl_i.java	
+++ b/ webgoat/main/project/JavaSource/org/owasp/webgoat/lessons/instructor/RoleBasedAccessControl/RoleBasedAccessControl_i.java	
@@ -1 +1 @@
-package org.owasp.webgoat.lessons.instructor.RoleBasedAccessControl;

import org.apache.ecs.ElementContainer;
import org.owasp.webgoat.lessons.GoatHillsFinancial.DefaultLessonAction;
import org.owasp.webgoat.lessons.GoatHillsFinancial.GoatHillsFinancial;
import org.owasp.webgoat.lessons.GoatHillsFinancial.LessonAction;
import org.owasp.webgoat.lessons.RoleBasedAccessControl.RoleBasedAccessControl;
import org.owasp.webgoat.session.ParameterNotFoundException;
import org.owasp.webgoat.session.UnauthenticatedException;
import org.owasp.webgoat.session.UnauthorizedException;
import org.owasp.webgoat.session.ValidationException;
import org.owasp.webgoat.session.WebSession;

/**
 *  Copyright (c) 2006 Free Software Foundation developed under the custody of the Open Web
 *  Application Security Project (http://www.owasp.org) This software package org.owasp.webgoat.is published by OWASP
 *  under the GPL. You should read and accept the LICENSE before you use, modify and/or redistribute
 *  this software.
 *
 */

/* STAGE 2 FIXES
Solution Summary: Edit RoleBasedAccessControl.java and change handleRequest().  
                  Modify handleRequest() with lines denoted by // STAGE 2 - FIX.
Solution Steps: 
1. This solution adds an access control check in the controller.
   Point out that their architecture may require the check to occur in the business function.
2. Look at the RoleBasedAccessControl class identify where execution happens of an action.
	a. action.handleRequest(s); is not protected by an access control check.
	b. look at handleRequest(s) to determine where access control check should occur.
	c. add protection by a programmatic authorization check before dispatching to the action:
		1. Add an isAuthorized() call before dispatching to the action, 
		       and throw an unauthorized exception.  Tell student this exception exists. 
		   Use eclipse command completion to find the isAuthorized() call on the action.  
		   From command completion - determine calling arguments of isAuthorized()
		   
		    				int userId = action.getUserId(s); 
							if (action.isAuthorized(s, userId, action.getActionName()))
							{
								action.handleRequest(s);
							}
							else				
								throw new UnauthorizedException();

Repeat stage 1 and note that the function fails with a "Not authorized" message.
 Tom will be in the list again, because the DB is reset when lesson restarts.
 Adding the access check in the RoleBasedAccessControl:handleRequest() is putting the check in the �Controller�
 The access check can also be added to DeleteProfile.deleteEmployeeProfile(), which is putting the check in the �Business Function�
*/

public class RoleBasedAccessControl_i extends RoleBasedAccessControl
{
	
	public void handleRequest(WebSession s)
	{
		//System.out.println("RoleBasedAccessControl.handleRequest()");
		if (s.getLessonSession(this) == null)
			s.openLessonSession(this);
		
		String requestedActionName = null;
		try
		{
			requestedActionName = s.getParser().getStringParameter("action");
		}
		catch (ParameterNotFoundException pnfe) 
		{
			// Missing the action - send them back to login.
			requestedActionName = LOGIN_ACTION;
		}

		try
		{
			LessonAction action = getAction(requestedActionName);
			if (action != null)
			{
				// FIXME: This code has gotten much uglier
				//System.out.println("RoleBasedAccessControl.handleRequest() dispatching to: " + action.getActionName());
				if (!action.requiresAuthentication())
				{
					// Access to Login does not require authentication.
					action.handleRequest(s);		
				}
				else 
				{
					if (action.isAuthenticated(s))
					{
						int userId = action.getUserId(s); // STAGE 2 - FIX
						
						// action.getActionName() returns the user requested function which
						// is tied to the button click from the listStaff jsp
						//
						// Checking isAuthorized() for the requested action
						
						if (action.isAuthorized(s, userId, action.getActionName())) // STAGE 2 - FIX
						{
							// Calling the handleRequest() method for the requested action					
							action.handleRequest(s);
						}
						else
							throw new UnauthorizedException(); // STAGE 2 - FIX

					}
					else
						throw new UnauthenticatedException();
				}
			}
			else
				setCurrentAction(s, ERROR_ACTION);
		}
		catch (ParameterNotFoundException pnfe)
		{
			System.out.println("Missing parameter");
			pnfe.printStackTrace();
			setCurrentAction(s, ERROR_ACTION);												
		}
		catch (ValidationException ve)
		{
			System.out.println("Validation failed");
			ve.printStackTrace();
			setCurrentAction(s, ERROR_ACTION);												
		}
		catch (UnauthenticatedException ue)
		{
			s.setMessage("Login failed");
			System.out.println("Authentication failure");
			ue.printStackTrace();
		}
		catch (UnauthorizedException ue2)
		{
			// Update lesson status if necessary.
			if (getStage(s) == 2)
			{
				try
				{
				if (GoatHillsFinancial.DELETEPROFILE_ACTION.equals(requestedActionName) &&
						!isAuthorized(s, getUserId(s), GoatHillsFinancial.DELETEPROFILE_ACTION))
				{
					s.setMessage( "Welcome to stage 3 -- exploiting the data layer" );
					setStage(s, 3);
				}
				} catch (ParameterNotFoundException pnfe)
				{
				pnfe.printStackTrace();
				}
			}
			//System.out.println("isAuthorized() exit stage: " + getStage(s));
			// Update lesson status if necessary.
			if (getStage(s) == 4)
			{
				try
				{
				//System.out.println("Checking for stage 4 completion");
				DefaultLessonAction action = (DefaultLessonAction) getAction(getCurrentAction(s));
				int userId = Integer.parseInt((String)s.getRequest().getSession().getAttribute(getLessonName() + "."
						+ GoatHillsFinancial.USER_ID));
				int employeeId = s.getParser().getIntParameter(
					GoatHillsFinancial.EMPLOYEE_ID);

				if (!action.isAuthorizedForEmployee(s, userId, employeeId))
				{
				    s.setMessage("Congratulations. You have successfully completed this lesson.");
				    getLessonTracker( s ).setCompleted( true );
				}
				} catch (Exception e)
				{
					// swallow this - shouldn't happen inthe normal course
					// e.printStackTrace();
				}
			}
			
		    s.setMessage("You are not authorized to perform this function");
		    System.out.println("Authorization failure");
		    setCurrentAction(s, ERROR_ACTION);
		    ue2.printStackTrace();
		}
		
		// All this does for this lesson is ensure that a non-null content exists.
		setContent(new ElementContainer());
	}
	
}

\ No newline at end of file
+package org.owasp.webgoat.lessons.instructor.RoleBasedAccessControl;

import org.apache.ecs.ElementContainer;
import org.owasp.webgoat.lessons.GoatHillsFinancial.DefaultLessonAction;
import org.owasp.webgoat.lessons.GoatHillsFinancial.GoatHillsFinancial;
import org.owasp.webgoat.lessons.GoatHillsFinancial.LessonAction;
import org.owasp.webgoat.lessons.RoleBasedAccessControl.RoleBasedAccessControl;
import org.owasp.webgoat.session.ParameterNotFoundException;
import org.owasp.webgoat.session.UnauthenticatedException;
import org.owasp.webgoat.session.UnauthorizedException;
import org.owasp.webgoat.session.ValidationException;
import org.owasp.webgoat.session.WebSession;

/**
 *  Copyright (c) 2006 Free Software Foundation developed under the custody of the Open Web
 *  Application Security Project (http://www.owasp.org) This software package org.owasp.webgoat.is published by OWASP
 *  under the GPL. You should read and accept the LICENSE before you use, modify and/or redistribute
 *  this software.
 *
 */

/* STAGE 2 FIXES
Solution Summary: Edit RoleBasedAccessControl.java and change handleRequest().  
                  Modify handleRequest() with lines denoted by // STAGE 2 - FIX.
Solution Steps: 
1. This solution adds an access control check in the controller.
   Point out that their architecture may require the check to occur in the business function.
2. Look at the RoleBasedAccessControl class identify where execution happens of an action.
	a. action.handleRequest(s); is not protected by an access control check.
	b. look at handleRequest(s) to determine where access control check should occur.
	c. add protection by a programmatic authorization check before dispatching to the action:
		1. Add an isAuthorized() call before dispatching to the action, 
		       and throw an unauthorized exception.  Tell student this exception exists. 
		   Use eclipse command completion to find the isAuthorized() call on the action.  
		   From command completion - determine calling arguments of isAuthorized()
		   
		    				int userId = action.getUserId(s); 
							if (action.isAuthorized(s, userId, action.getActionName()))
							{
								action.handleRequest(s);
							}
							else				
								throw new UnauthorizedException();

Repeat stage 1 and note that the function fails with a "Not authorized" message.
 Tom will be in the list again, because the DB is reset when lesson restarts.
 Adding the access check in the RoleBasedAccessControl:handleRequest() is putting the check in the �Controller�
 The access check can also be added to DeleteProfile.deleteEmployeeProfile(), which is putting the check in the �Business Function�
*/

public class RoleBasedAccessControl_i extends RoleBasedAccessControl
{
	
	public void handleRequest(WebSession s)
	{
		//System.out.println("RoleBasedAccessControl.handleRequest()");
		if (s.getLessonSession(this) == null)
			s.openLessonSession(this);
		
		String requestedActionName = null;
		try
		{
			requestedActionName = s.getParser().getStringParameter("action");
		}
		catch (ParameterNotFoundException pnfe) 
		{
			// Missing the action - send them back to login.
			requestedActionName = LOGIN_ACTION;
		}

		try
		{
			LessonAction action = getAction(requestedActionName);
			if (action != null)
			{
				// FIXME: This code has gotten much uglier
				//System.out.println("RoleBasedAccessControl.handleRequest() dispatching to: " + action.getActionName());
				if (!action.requiresAuthentication())
				{
					// Access to Login does not require authentication.
					action.handleRequest(s);		
				}
				else 
				{
					if (action.isAuthenticated(s))
					{
						int userId = action.getUserId(s); // STAGE 2 - FIX
						
						// action.getActionName() returns the user requested function which
						// is tied to the button click from the listStaff jsp
						//
						// Checking isAuthorized() for the requested action
						
						if (action.isAuthorized(s, userId, action.getActionName())) // STAGE 2 - FIX
						{
							// Calling the handleRequest() method for the requested action					
							action.handleRequest(s);
						}
						else
							throw new UnauthorizedException(); // STAGE 2 - FIX

					}
					else
						throw new UnauthenticatedException();
				}
			}
			else
				setCurrentAction(s, ERROR_ACTION);
		}
		catch (ParameterNotFoundException pnfe)
		{
			System.out.println("Missing parameter");
			pnfe.printStackTrace();
			setCurrentAction(s, ERROR_ACTION);												
		}
		catch (ValidationException ve)
		{
			System.out.println("Validation failed");
			ve.printStackTrace();
			setCurrentAction(s, ERROR_ACTION);												
		}
		catch (UnauthenticatedException ue)
		{
			s.setMessage("Login failed");
			System.out.println("Authentication failure");
			ue.printStackTrace();
		}
		catch (UnauthorizedException ue2)
		{
			String stage = getStage(s);
			// Update lesson status if necessary.
			if (STAGE2.equals(stage))
			{
				try
				{
				if (GoatHillsFinancial.DELETEPROFILE_ACTION.equals(requestedActionName) &&
						!isAuthorized(s, getUserId(s), GoatHillsFinancial.DELETEPROFILE_ACTION))
				{
					s.setMessage( "Welcome to stage 3 -- exploiting the data layer" );
					setStageComplete(s, STAGE2);
				}
				} catch (ParameterNotFoundException pnfe)
				{
				pnfe.printStackTrace();
				}
			}
			//System.out.println("isAuthorized() exit stage: " + getStage(s));
			// Update lesson status if necessary.
			if (STAGE4.equals(stage))
			{
				try
				{
				//System.out.println("Checking for stage 4 completion");
				DefaultLessonAction action = (DefaultLessonAction) getAction(getCurrentAction(s));
				int userId = Integer.parseInt((String)s.getRequest().getSession().getAttribute(getLessonName() + "."
						+ GoatHillsFinancial.USER_ID));
				int employeeId = s.getParser().getIntParameter(
					GoatHillsFinancial.EMPLOYEE_ID);

				if (!action.isAuthorizedForEmployee(s, userId, employeeId))
				{
				    s.setMessage("Congratulations. You have successfully completed this lesson.");
				    setStageComplete(s, STAGE4);
				}
				} catch (Exception e)
				{
					// swallow this - shouldn't happen inthe normal course
					// e.printStackTrace();
				}
			}
			
		    s.setMessage("You are not authorized to perform this function");
		    System.out.println("Authorization failure");
		    setCurrentAction(s, ERROR_ACTION);
		    ue2.printStackTrace();
		}
		
		// All this does for this lesson is ensure that a non-null content exists.
		setContent(new ElementContainer());
	}
	
}

\ No newline at end of file
diff --git a/ webgoat/main/project/JavaSource/org/owasp/webgoat/session/RandomLessonTracker.java b/ webgoat/main/project/JavaSource/org/owasp/webgoat/session/RandomLessonTracker.java
new file mode 100755
index 000000000..84ac3b128
--- /dev/null
+++ b/ webgoat/main/project/JavaSource/org/owasp/webgoat/session/RandomLessonTracker.java	
@@ -0,0 +1,86 @@
+package org.owasp.webgoat.session;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+public class RandomLessonTracker extends LessonTracker {
+
+	private String[] stages;
+	
+	private String stage;
+	
+	private Map<String, Boolean> completed = new HashMap<String, Boolean>();
+	
+	public RandomLessonTracker(String[] stages) {
+		if (stages == null)
+			stages = new String[0];
+		this.stages = stages;
+	}
+	
+	public void setStage(String stage) {
+		this.stage = stage;
+	}
+	
+	public String getStage() {
+		if (this.stage == null && stages.length > 0)
+			return stages[0];
+		return this.stage;
+	}
+	
+	public void setStageComplete(String stage, boolean complete) {
+		completed.put(stage, Boolean.valueOf(complete));
+		for (int i=0; i<stages.length-1; i++)
+			if (stages[i].equals(stage))
+				setStage(stages[i+1]);
+	}
+	
+	public boolean hasCompleted(String stage) {
+		Boolean complete = completed.get(stage);
+		return complete == null ? false : complete.booleanValue();
+	}
+	
+	@Override
+	public boolean getCompleted() {
+		for (int i=0; i<stages.length; i++)
+			if (!hasCompleted(stages[i]))
+				return false;
+		return true;
+	}
+	
+	@Override
+	public void setCompleted(boolean complete) {
+		throw new UnsupportedOperationException("Use individual stage completion instead");
+	}
+	
+    protected void setProperties(Properties props, Screen screen) {
+	    super.setProperties(props, screen);
+	    for (int i=0; i<stages.length; i++) {
+	    	String p = props.getProperty(screen.getTitle() + "." + stages[i] + ".completed");
+	    	if (p != null) {
+	    		setStageComplete(stages[i], Boolean.valueOf(p));
+	    	}
+	    }
+	    setStage(props.getProperty(screen.getTitle() + ".stage"));
+    }
+    
+    public void store(WebSession s, Screen screen, String user) {
+    	for (int i=0; i<stages.length; i++) {
+    		if (hasCompleted(stages[i]))
+    			lessonProperties.setProperty(screen.getTitle() + "." + stages[i] + ".completed", Boolean.TRUE.toString());
+    	}
+		lessonProperties.setProperty(screen.getTitle() + ".stage", getStage());
+		super.store(s, screen, user);
+    }
+    
+    public String toString() {
+    	StringBuffer buff = new StringBuffer();
+    	buff.append(super.toString());
+    	for (int i=0; i<stages.length; i++) {
+    		buff.append("    - completed " + stages[i] + " :....... " + hasCompleted(stages[i]) + "\n");
+    	}
+    	buff.append("    - currentStage:....... " + getStage() + "\n");
+    	return buff.toString();
+    }
+
+}
diff --git a/ webgoat/main/project/JavaSource/org/owasp/webgoat/session/WebSession.java b/ webgoat/main/project/JavaSource/org/owasp/webgoat/session/WebSession.java
index d8740d25f..8602fbb26 100644
--- a/ webgoat/main/project/JavaSource/org/owasp/webgoat/session/WebSession.java	
+++ b/ webgoat/main/project/JavaSource/org/owasp/webgoat/session/WebSession.java	
@@ -22,6 +22,7 @@ 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;
 
 /*******************************************************************************
@@ -916,6 +917,17 @@ public class WebSession
 			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 (stage>0 && stage <= stages.length)
+				rla.setStage(this, stages[stage]);
+			} catch (ParameterNotFoundException pnfe) {}
+			}
 		}
 		// else update global variables for the current screen
 		else
diff --git a/ webgoat/main/project/WebContent/WEB-INF/web.xml b/ webgoat/main/project/WebContent/WEB-INF/web.xml
old mode 100644
new mode 100755
diff --git a/ webgoat/main/project/WebContent/WEB-INF/webgoat.properties b/ webgoat/main/project/WebContent/WEB-INF/webgoat.properties
old mode 100644
new mode 100755
diff --git a/ webgoat/main/project/WebContent/main.jsp b/ webgoat/main/project/WebContent/main.jsp
index 92e6cfb25..a5071ea85 100644
--- a/ webgoat/main/project/WebContent/main.jsp	
+++ b/ webgoat/main/project/WebContent/main.jsp	
@@ -9,6 +9,7 @@ AbstractLesson currentLesson = webSession.getCurrentLesson();
 
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 <%@page import="org.owasp.webgoat.lessons.SequentialLessonAdapter"%>
+<%@page import="org.owasp.webgoat.lessons.RandomLessonAdapter"%>
 <html xmlns="http://www.w3.org/1999/xhtml">
 <head>
 <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
@@ -199,6 +200,7 @@ StringBuffer buildList = new StringBuffer();
 				</div>
 				<%
 					AbstractLesson al = webSession.getCurrentLesson();
+					System.out.println("AL is a " + al.getClass().getName());
 					if (al instanceof SequentialLessonAdapter)
 					{
 					SequentialLessonAdapter sla = (SequentialLessonAdapter) al;
@@ -215,6 +217,22 @@ StringBuffer buildList = new StringBuffer();
 						%></select></form><%
 					}
 					}
+					else if (al instanceof RandomLessonAdapter)
+					{
+					RandomLessonAdapter rla = (RandomLessonAdapter) al;
+					String[] stages = rla.getStages();
+					if (stages != null && stages.length > 0) {
+						%><form method="post" action="attack?menu=<%=webSession.getCurrentMenu()%>">
+						<select name="<%= WebSession.STAGE %>" onchange="this.form.submit();">
+						<%
+						String stage = rla.getStage(webSession);
+						for (int i=0; i<stages.length;i++) {
+						%><option <% if (stages[i].equals(stage)) out.print("selected"); %> value="<%= i+1 %>">Stage <%= i+1 %></option>
+						<%
+						}
+						%></select></form><%
+					}
+					}
 				%>
 				<div id="lessonContent"><%=webSession.getInstructions()%></div>
 				<div id="message" class="info"><%=webSession.getMessage()%></div>