BasicHttpProxyToHttpTest.java
/*
* Copyright (c) 2016-2023 AsyncHttpClient Project. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.asynchttpclient;
import io.github.artsok.RepeatedIfExceptionsTest;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.asynchttpclient.Realm.AuthScheme;
import org.asynchttpclient.test.EchoHandler;
import org.eclipse.jetty.proxy.ProxyServlet;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.concurrent.Future;
import static io.netty.handler.codec.http.HttpHeaderNames.PROXY_AUTHENTICATE;
import static io.netty.handler.codec.http.HttpHeaderNames.PROXY_AUTHORIZATION;
import static org.asynchttpclient.Dsl.asyncHttpClient;
import static org.asynchttpclient.Dsl.get;
import static org.asynchttpclient.Dsl.proxyServer;
import static org.asynchttpclient.Dsl.realm;
import static org.asynchttpclient.test.TestUtils.addHttpConnector;
import static org.junit.jupiter.api.Assertions.assertEquals;
/**
* Test that validates that when having an HTTP proxy and trying to access an HTTP through the proxy the proxy credentials should be passed after it gets a 407 response.
*/
public class BasicHttpProxyToHttpTest {
private static final Logger LOGGER = LoggerFactory.getLogger(BasicHttpProxyToHttpTest.class);
private int httpPort;
private int proxyPort;
private Server httpServer;
private Server proxy;
@BeforeEach
public void setUpGlobal() throws Exception {
httpServer = new Server();
ServerConnector connector1 = addHttpConnector(httpServer);
httpServer.setHandler(new EchoHandler());
httpServer.start();
httpPort = connector1.getLocalPort();
proxy = new Server();
ServerConnector connector2 = addHttpConnector(proxy);
ServletHandler servletHandler = new ServletHandler();
ServletHolder servletHolder = servletHandler.addServletWithMapping(BasicAuthProxyServlet.class, "/*");
servletHolder.setInitParameter("maxThreads", "20");
proxy.setHandler(servletHandler);
proxy.start();
proxyPort = connector2.getLocalPort();
LOGGER.info("Local HTTP Server (" + httpPort + "), Proxy (" + proxyPort + ") started successfully");
}
@AfterEach
public void tearDownGlobal() {
if (proxy != null) {
try {
proxy.stop();
} catch (Exception e) {
LOGGER.error("Failed to properly close proxy", e);
}
}
if (httpServer != null) {
try {
httpServer.stop();
} catch (Exception e) {
LOGGER.error("Failed to properly close server", e);
}
}
}
@RepeatedIfExceptionsTest(repeats = 5)
public void nonPreemptiveProxyAuthWithPlainHttpTarget() throws Exception {
try (AsyncHttpClient client = asyncHttpClient()) {
String targetUrl = "http://localhost:" + httpPort + "/foo/bar";
Request request = get(targetUrl)
.setProxyServer(proxyServer("127.0.0.1", proxyPort).setRealm(realm(AuthScheme.BASIC, "johndoe", "pass")))
// .setRealm(realm(AuthScheme.BASIC, "user", "passwd"))
.build();
Future<Response> responseFuture = client.executeRequest(request);
Response response = responseFuture.get();
assertEquals(response.getStatusCode(), HttpServletResponse.SC_OK);
assertEquals("/foo/bar", response.getHeader("X-pathInfo"));
}
}
@SuppressWarnings("serial")
public static class BasicAuthProxyServlet extends ProxyServlet {
@Override
protected void service(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException {
LOGGER.debug(">>> got a request !");
String authorization = request.getHeader(PROXY_AUTHORIZATION.toString());
if (authorization == null) {
response.setStatus(HttpServletResponse.SC_PROXY_AUTHENTICATION_REQUIRED);
response.setHeader(PROXY_AUTHENTICATE.toString(), "Basic realm=\"Fake Realm\"");
response.getOutputStream().flush();
} else if ("Basic am9obmRvZTpwYXNz".equals(authorization)) {
super.service(request, response);
} else {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.getOutputStream().flush();
}
}
}
}