Skip to content

feat(server): add HTTP 302 redirect support to HttpRecordingHandler - #4

Open
mangeshwalsane2-hash wants to merge 2 commits into
google:masterfrom
mangeshwalsane2-hash:feature/tcs-redirect-support
Open

mangeshwalsane2-hash wants to merge 2 commits into
google:masterfrom
mangeshwalsane2-hash:feature/tcs-redirect-support

Conversation

@mangeshwalsane2-hash

Copy link
Copy Markdown

Supports redirect-based SSRF verification by inspecting query parameters (?to=, ?redirect=, ?url=) on the HTTP recording endpoint. When present, TCS saves the callback interaction and responds with an HTTP 302 Found redirect to the requested destination URL. Preserves 200 OK JSON response when no redirect parameter is specified.

Supports redirect-based SSRF verification by inspecting query parameters
(?to=, ?redirect=, ?url=) on the HTTP recording endpoint. When present,
TCS saves the callback interaction and responds with an HTTP 302 Found
redirect to the requested destination URL. Preserves 200 OK JSON response
when no redirect parameter is specified.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces redirect support to the callback server's HTTP handler. It updates protobuf dependencies, implements redirect detection based on query parameters ('to', 'redirect', 'url') in HttpRecordingHandler, and handles redirect responses in HttpHandler. Additionally, it adds unit tests to verify the redirect behavior. The reviewer suggests adding more robust test cases to cover URL-encoded redirect parameters and empty redirect parameters.

Comment on lines +216 to +228
@Test
public void channelRead0_whenNoRedirectParam_returnsOkStatus() {
EmbeddedChannel channel = new EmbeddedChannel(handler);
DefaultFullHttpRequest request = buildRequest("127.0.0.1", "/" + FAKE_CBID);

channel.writeInbound(request);
FullHttpResponse response = channel.readOutbound();

assertThat(response.status()).isEqualTo(HttpResponseStatus.OK);
assertThat(response.headers().get(HttpHeaderNames.LOCATION)).isNull();
assertThat(interactionStore.get(FAKE_CBID)).containsExactly(FAKE_HTTP_INTERACTION);
verify(eventsObserverMock).onHttpInteractionRecorded();
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

While the existing tests cover basic redirect scenarios, they do not verify how the handler behaves when redirect parameters are URL-encoded (e.g., containing multiple query parameters like ?to=http%3A%2F%2Fexample.com%3Ffoo%3Dbar%26baz%3Dqux) or when they are present but empty (e.g., ?to=).

Adding test cases for these scenarios will ensure robust query parameter decoding and graceful fallback behavior.

  @Test
  public void channelRead0_whenNoRedirectParam_returnsOkStatus() {
    EmbeddedChannel channel = new EmbeddedChannel(handler);
    DefaultFullHttpRequest request = buildRequest("127.0.0.1", "/" + FAKE_CBID);

    channel.writeInbound(request);
    FullHttpResponse response = channel.readOutbound();

    assertThat(response.status()).isEqualTo(HttpResponseStatus.OK);
    assertThat(response.headers().get(HttpHeaderNames.LOCATION)).isNull();
    assertThat(interactionStore.get(FAKE_CBID)).containsExactly(FAKE_HTTP_INTERACTION);
    verify(eventsObserverMock).onHttpInteractionRecorded();
  }

  @Test
  public void channelRead0_whenRedirectParamToWithEncodedUrl_returnsDecodedLocation() {
    String destination = "http://127.0.0.1:5000/api?param1=val1&param2=val2";
    String encodedDestination = "http%3A%2F%2F127.0.0.1%3A5000%2Fapi%3Fparam1%3Dval1%26param2%3Dval2";
    EmbeddedChannel channel = new EmbeddedChannel(handler);
    DefaultFullHttpRequest request = 
        buildRequest("127.0.0.1", "/" + FAKE_CBID + "?to=" + encodedDestination);

    channel.writeInbound(request);
    FullHttpResponse response = channel.readOutbound();

    assertThat(response.status()).isEqualTo(HttpResponseStatus.FOUND);
    assertThat(response.headers().get(HttpHeaderNames.LOCATION)).isEqualTo(destination);
    assertThat(interactionStore.get(FAKE_CBID)).containsExactly(FAKE_HTTP_INTERACTION);
    verify(eventsObserverMock).onHttpInteractionRecorded();
  }

  @Test
  public void channelRead0_whenRedirectParamIsEmpty_returnsOkStatus() {
    EmbeddedChannel channel = new EmbeddedChannel(handler);
    DefaultFullHttpRequest request = buildRequest("127.0.0.1", "/" + FAKE_CBID + "?to=");

    channel.writeInbound(request);
    FullHttpResponse response = channel.readOutbound();

    assertThat(response.status()).isEqualTo(HttpResponseStatus.OK);
    assertThat(response.headers().get(HttpHeaderNames.LOCATION)).isNull();
    assertThat(interactionStore.get(FAKE_CBID)).containsExactly(FAKE_HTTP_INTERACTION);
    verify(eventsObserverMock).onHttpInteractionRecorded();
  }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant