/*
 * Created on Jun 1, 2005
 *
 * TODO To change the template for this generated file go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
package org.owasp.webgoat.lessons;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

import org.apache.ecs.Element;
import org.apache.ecs.ElementContainer;
import org.apache.ecs.html.A;
import org.apache.ecs.html.BR;
import org.apache.ecs.html.IMG;
import org.apache.ecs.html.Input;
import org.apache.ecs.html.P;
import org.apache.ecs.html.PRE;

import org.owasp.webgoat.session.DatabaseUtilities;
import org.owasp.webgoat.session.ECSFactory;
import org.owasp.webgoat.session.WebSession;

/**
 * @author asmolen
 *
 * TODO To change the template for this generated type comment go to
 * Window - Preferences - Java - Code Style - Code Templates
 */
public class WsSqlInjection extends LessonAdapter {
	public final static String ccNumber = "cc_number";
	private final static String ACCT_NUM = "account_number";
	private String accountNumber;
	final static IMG CREDITS_LOGO = new IMG( "images/logos/parasoft.jpg" ).setAlt( "Parasoft" ).setBorder( 0 ).setHspace( 0 ).setVspace( 0 );
	private static Connection connection = null;
	/* (non-Javadoc)
	 * @see lessons.AbstractLesson#getMenuItem()
	 */
	static boolean completed;
	
	protected Category getDefaultCategory()
	{
		return AbstractLesson.WEB_SERVICES;
	}
	
	protected List getHints()
	{
		List<String> hints = new ArrayList<String>();
		hints.add( "Try connecting to the WSDL with a browser or Web Service tool." );
		hints.add( "Sometimes the server side code will perform input validation before issuing  " +
				"the request to the web service operation.  Try to bypass this check by " +
				"accessing the web service directly");
		hints.add( "The URL for the web service is: http://localhost/WebGoat/services/WsSqlInjection?WSDL <br>" +
				"The WSDL can usually be viewed by adding a ?WSDL on the end of the request.");
		hints.add( "Create a new soap request for the getCreditCard(String id) operation.");
		hints.add("A soap request uses the following HTTP header: <br> " +
        "SOAPAction: some action header, can be &quot;&quot;<br><br>" +
	    "The soap message body has the following format:<br>" +
	    "&lt;?xml version='1.0' encoding='UTF-8'?&gt; <br>" +
	    "&nbsp;&nbsp;&lt;SOAP-ENV:Envelope xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/' xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'&gt; <br>" +
	    "&nbsp;&nbsp;&nbsp;&nbsp;&lt;SOAP-ENV:Body&gt; <br>" +
	    "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;ns1:getCreditCard SOAP-ENV:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/' xmlns:ns1='http://lessons'&gt; <br>" +
	    "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;id xsi:type='xsd:string'&gt;101&lt;/id&gt; <br>" +
	    "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;/ns1:getCreditCard&gt; <br>" +
	    "&nbsp;&nbsp;&nbsp;&nbsp;&lt;/SOAP-ENV:Body&gt; <br>" +
	    "&nbsp;&nbsp;&lt;/SOAP-ENV:Envelope&gt; <br>" +
		"");
/*		"&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt; <br>" +
		"  &lt;SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" <br>" +
		"	                  xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" <br>" +
		"	                  xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"&gt; <br>" +
		"     &lt;SOAP-ENV:Body&gt; <br>" +
		"		  &lt;ns1:getCreditCard SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\" xmlns:ns1=\"http://lessons\"&gt; <br>" +
		"		   &lt;id xsi:type=\"xsd:string\"&gt;101&lt;/id&gt; <br>"+
		"		  &lt;/ns1:getCreditCard&gt; <br>" +
		"     &lt;/SOAP-ENV:Body&gt; <br>" +
		"  &lt;/SOAP-ENV:Envelope&gt; <br><br>" +
		"Intercept the HTTP request and try to create a soap request.");	*/	
		return hints;
	}

	private final static Integer DEFAULT_RANKING = new Integer(150);

	protected Integer getDefaultRanking()
	{
		return DEFAULT_RANKING;
	}

	public String getTitle()
	{
		return "Web Service SQL Injection";
	}
	protected Element makeAccountLine( WebSession s )
	{
		ElementContainer ec = new ElementContainer();
		
		ec.addElement( new P().addElement( "Enter your Account Number: " ) );

		accountNumber = s.getParser().getRawParameter( ACCT_NUM, "101" );
		Input input = new Input( Input.TEXT, ACCT_NUM, accountNumber.toString() );
		ec.addElement( input );

		Element b = ECSFactory.makeButton( "Go!" );
		ec.addElement( b );

		return ec;
	}
	protected Element createContent(WebSession s)
	{
		ElementContainer ec = new ElementContainer();
		try
		{
			if ( connection == null )
			{
				connection = DatabaseUtilities.makeConnection( s );
			}
			ec.addElement( makeAccountLine(s) );

			String query = "SELECT * FROM user_data WHERE userid = " + accountNumber ;
			ec.addElement( new PRE( query ) );
			for (int i=0; i<accountNumber.length(); i++) {
				char c = accountNumber.charAt(i);
				if (c < '0' || c > '9') {
					ec.addElement("Invalid account number. ");
                    accountNumber = "0";
				}
			}
			try
			{
				ResultSet results = getResults(accountNumber);
				if ( ( results != null ) && ( results.first() == true ) )
				{
					ResultSetMetaData resultsMetaData = results.getMetaData();
					ec.addElement( DatabaseUtilities.writeTable( results, resultsMetaData ) );
					results.last();
					if ( results.getRow() >= 6 )
					{
                        //this should never happen
					}
				}
				else 
				{
					ec.addElement( "No results matched.  Try Again." );
				}
			}
			catch ( SQLException sqle )
			{
				ec.addElement( new P().addElement( sqle.getMessage() ) );
			}
			A a = new A("services/WsSqlInjection?WSDL","WebGoat WSDL");
			ec.addElement(new P().addElement("Exploit the following WSDL to access sensitive data:"));
			ec.addElement(new BR());
			ec.addElement(a);
			getLessonTracker( s ).setCompleted( completed );
		}
		catch (Exception e)
		{
			s.setMessage("Error generating " + this.getClass().getName());
			e.printStackTrace();
		}
		return (ec);
	}	
	public ResultSet getResults (String id) {
		try
		{				
			Connection connection = DatabaseUtilities.makeConnection();
			if (connection == null) {
				return null;
			}
			String query = "SELECT * FROM user_data WHERE userid = " + id ;
			try
			{
				Statement statement = connection.createStatement( ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY );
				ResultSet results = statement.executeQuery( query );
				return results;
			}
			catch ( SQLException sqle )
			{
			}
		}
		catch ( Exception e )
		{
		}
	return null;		
	}
	public String[] getCreditCard(String id) {
		ResultSet results = getResults(id);
		if ((results != null)) {
			try {
				results.last();
				String[] users = new String[results.getRow()];
				if (users.length > 4) {
					completed = true;
				}
				results.beforeFirst();
				while (results.next() == true) {
					int i = results.getRow();
					users[i-1] = results.getString(ccNumber);
				}
				return users;
			} catch (SQLException sqle) {
			}
		}
		return null;
	}
	
    public Element getCredits()
    {
    	return super.getCustomCredits("By Alex Smolen", CREDITS_LOGO);
    }
}
