// Test case for CWE-421 (Race Condition During Access to Alternate Channel)
// http://cwe.mitre.org/data/definitions/421.html
package test.cwe807.semmle.tests;




import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;

class Test {
	byte[] secretData = "The password is: passw0rd".getBytes();

	// fake stub for testing
	public boolean isAuthenticated(String username) {
		return true;
	}

	// fake stub for testing
	public boolean doAuthenticate(Socket connection, String username) {
		return true;
	}

	// fake stub for testing
	public boolean doAuthenticate(SocketChannel connection, String username) {
		return true;
	}
	
	public void doConnect(int desiredPort, String username) {
		ServerSocket listenSocket = new ServerSocket(desiredPort);

		if (isAuthenticated(username)) {
			Socket connection1 = listenSocket.accept();
			// BAD: no authentication over the socket
			connection1.getOutputStream().write(secretData);
		}

		Socket connection2 = listenSocket.accept();
		// GOOD: authentication happens over the socket
		if (doAuthenticate(connection2, username)) {
			connection2.getOutputStream().write(secretData);
		}

		if (isAuthenticated(username)) {
			// FP: we authenticate both beforehand and over the socket
			Socket connection3 = listenSocket.accept();
			if (doAuthenticate(connection3, username)) {
				connection3.getOutputStream().write(secretData);
			}
		}
		
	}

	public void doConnectChannel(int desiredPort, String username) {
		ServerSocketChannel listenChannel = ServerSocketChannel.open();
		SocketAddress port = new InetSocketAddress(desiredPort);
		listenChannel.bind(port);

		if (isAuthenticated(username)) {
			SocketChannel connection1 = listenChannel.accept();
			// BAD: no authentication over the socket
			connection1.write(ByteBuffer.wrap(secretData));
		}

		SocketChannel connection2 = listenChannel.accept();
		// GOOD: authentication happens over the socket
		if (doAuthenticate(connection2, username)) {
			connection2.write(ByteBuffer.wrap(secretData));
		}
		
	}
}
