package com.google.testing.security.firingrange.tests.reverseclickjacking; import static org.mockito.Mockito.contains; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import com.google.common.base.Strings; import com.google.common.collect.ImmutableSet; import com.google.common.net.HttpHeaders; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * Tests for {@link UniversalReverseClickjackingJsonpEndpoint}. */ @RunWith(JUnit4.class) public class UniversalReverseClickjackingJsonpEndpointTest { private HttpServletRequest request = mock(HttpServletRequest.class); private HttpServletResponse response = mock(HttpServletResponse.class); private PrintWriter writer = mock(PrintWriter.class); @Before public void setUpMocks() throws IOException { when(response.getWriter()).thenReturn(writer); } @Test public void returnsCallback() throws IOException { when(request.getParameter(UniversalReverseClickjackingJsonpEndpoint.ECHOED_PARAM)) .thenReturn("FOO"); new UniversalReverseClickjackingJsonpEndpoint().doGet(request, response); verify(response).setStatus(200); verify(response).setHeader(HttpHeaders.CONTENT_TYPE, "application/json"); verify(writer).write("/**/FOO({'foobar':'foo'});"); } @Test public void refusesXssInjection() throws IOException { when(request.getParameter(UniversalReverseClickjackingJsonpEndpoint.ECHOED_PARAM)) .thenReturn("<foo>"); new UniversalReverseClickjackingJsonpEndpoint().doGet(request, response); verify(response).setStatus(400); // Verify that we also don't write broken callbacks verify(writer, never()).write(contains("/**/<foo>(")); } @Test public void refusesEmptyCallback() throws IOException { when(request.getParameter(UniversalReverseClickjackingJsonpEndpoint.ECHOED_PARAM)) .thenReturn(""); new UniversalReverseClickjackingJsonpEndpoint().doGet(request, response); verify(response).setStatus(400); // Verify that we also don't write broken callbacks verify(writer, never()).write(contains("/**/(")); } @Test public void checksCallbackLength() throws IOException { String callback = Strings.repeat("a", UniversalReverseClickjackingJsonpEndpoint.MAX_CALLBACK_LENGTH); when(request.getParameter(UniversalReverseClickjackingJsonpEndpoint.ECHOED_PARAM)) .thenReturn(callback); new UniversalReverseClickjackingJsonpEndpoint().doGet(request, response); verify(response).setStatus(200); verify(response).setHeader(HttpHeaders.CONTENT_TYPE, "application/json"); verify(writer).write("/**/" + callback + "({'foobar':'foo'});"); when(request.getParameter(UniversalReverseClickjackingJsonpEndpoint.ECHOED_PARAM)) .thenReturn(callback + "a"); new UniversalReverseClickjackingJsonpEndpoint().doGet(request, response); verify(response).setStatus(400); // Verify that we also don't write overlong callbacks verify(writer, never()).write(contains("/**/" + callback + "a(")); } @Test public void checksCallbackRegex() throws IOException { ImmutableSet<String> invalidCallbacks = ImmutableSet.of(".", "-", "_", ".invalid", "-invalid", "_invalid"); for (String callback : invalidCallbacks) { when(request.getParameter(UniversalReverseClickjackingJsonpEndpoint.ECHOED_PARAM)) .thenReturn(callback); new UniversalReverseClickjackingJsonpEndpoint().doGet(request, response); } verify(response, times(invalidCallbacks.size())).setStatus(400); // Verify that we also don't write invalid callbacks verify(writer, never()).write(contains("/**/")); } }