Skip to content

Commit

Permalink
[JENKINS-73139] Converting tests to com.sun.net.httpserver (#54)
Browse files Browse the repository at this point in the history
Co-authored-by: Basil Crow <me@basilcrow.com>
Co-authored-by: Mark Waite <mark.earl.waite@gmail.com>
  • Loading branch information
3 people committed Aug 14, 2024
1 parent cf07975 commit 90a488b
Show file tree
Hide file tree
Showing 4 changed files with 158 additions and 131 deletions.
Original file line number Diff line number Diff line change
@@ -1,25 +1,24 @@
package org.jenkinsci.plugins.kubernetes.credentials;

import com.cloudbees.plugins.credentials.CredentialsScope;
import com.sun.net.httpserver.HttpServer;
import com.sun.net.httpserver.HttpsConfigurator;
import com.sun.net.httpserver.HttpsServer;
import edu.umd.cs.findbugs.annotations.NonNull;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
import org.eclipse.jetty.server.SecureRequestCustomizer;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.SslConnectionFactory;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.junit.After;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Test;
import org.jvnet.hudson.test.FlagRule;

import java.io.IOException;
import java.io.InputStream;
import java.net.InetSocketAddress;
import java.net.URL;
import java.security.KeyStore;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;

import static org.junit.Assert.fail;

Expand Down Expand Up @@ -49,11 +48,7 @@ public abstract class AbstractOpenShiftBearerTokenCredentialFIPSTest {

protected String motivation;

private Server server;

private ServerConnector sslConnector;

private ServerConnector serverConnector;
private HttpServer server;


public AbstractOpenShiftBearerTokenCredentialFIPSTest(
Expand All @@ -69,44 +64,43 @@ public void prepareFakeOAuthServer() throws Exception {
if (keystore == null) {
fail("Unable to find keystore.jks");
}
server = new Server();

HttpConfiguration httpsConfig = new HttpConfiguration();
httpsConfig.addCustomizer(new SecureRequestCustomizer());
InetSocketAddress address = new InetSocketAddress(0);
if ("https".equals(scheme)) {
server = HttpsServer.create(address, 0);
setupHttps((HttpsServer) server);
} else {
server = HttpServer.create(address, 0);
}
OpenShiftBearerTokenCredentialMockServer.registerHttpHandlers(server);

SslContextFactory.Server sslContextFactory = new SslContextFactory.Server();
sslContextFactory.setKeyStorePath(keystore.toExternalForm());
sslContextFactory.setKeyManagerPassword("unittest");
sslContextFactory.setKeyStorePassword("unittest");
server.start();
}

sslConnector = new ServerConnector(server, new SslConnectionFactory(sslContextFactory, "http/1.1"), new HttpConnectionFactory(httpsConfig));
serverConnector = new ServerConnector(server);
server.setConnectors(new Connector[]{serverConnector, sslConnector});
private void setupHttps(HttpsServer httpsServer) throws Exception {
SSLContext sslContext = SSLContext.getInstance("TLS");
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
KeyStore ks = KeyStore.getInstance("JKS");
try (InputStream is = keystore.openStream()) {
ks.load(is, "unittest".toCharArray());
}
kmf.init(ks, "unittest".toCharArray());

ServletContextHandler context = new ServletContextHandler();
context.setContextPath("/");
context.addServlet(new ServletHolder(new MockHttpServlet()), "/*");
server.setHandler(context);
server.start();
sslContext.init(kmf.getKeyManagers(), null, null);
httpsServer.setHttpsConfigurator(new HttpsConfigurator(sslContext));
}

@After
public void unprepareFakeOAuthServer() throws Exception {
server.stop();
public void unprepareFakeOAuthServer() {
server.stop(0);
}

@Test
public void ensureFIPSCompliantURIRequest() throws IOException {
OpenShiftBearerTokenCredentialImpl cred;
cred = new OpenShiftBearerTokenCredentialImpl(CredentialsScope.GLOBAL, "id", "description", "username", "password");
try {
int port;
if ("https".equals(scheme)) {
port = sslConnector.getLocalPort();
} else {
port = serverConnector.getLocalPort();
}
cred.getToken(scheme + "://localhost:" + port + "/valid-response", null, skipTLSVerify);
cred.getToken(scheme + "://localhost:" + server.getAddress().getPort() + "/valid-response", null, skipTLSVerify);
if (!shouldPass) {
fail("This test was expected to fail, reason: " + motivation);
}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package org.jenkinsci.plugins.kubernetes.credentials;

import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpServer;
import com.sun.net.httpserver.HttpsServer;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
* @author Nevin Sunny
*/
public class OpenShiftBearerTokenCredentialMockServer {

public static void registerHttpHandlers(HttpServer server) {
server.createContext(
"/bad-location/oauth/authorize",
OpenShiftBearerTokenCredentialMockServer::badLocationHandler);
server.createContext(
"/missing-location/oauth/authorize",
OpenShiftBearerTokenCredentialMockServer::missingLocationHandler);
server.createContext(
"/bad-response/oauth/authorize",
OpenShiftBearerTokenCredentialMockServer::badResponseHandler);
server.createContext(
"/valid-response/oauth/authorize",
OpenShiftBearerTokenCredentialMockServer::validResponseHandler1);
server.createContext(
"/valid-response2/oauth/authorize",
OpenShiftBearerTokenCredentialMockServer::validResponseHandler2);
server.createContext("/", OpenShiftBearerTokenCredentialMockServer::defaultHandler);
}

private static void badLocationHandler(HttpExchange he) throws IOException {
he.getResponseHeaders().set("Location", "bad");
he.sendResponseHeaders(302, -1);
}

private static void missingLocationHandler(HttpExchange he) throws IOException {
he.sendResponseHeaders(302, -1); // No Location header
}

private static void badResponseHandler(HttpExchange he) throws IOException {
he.sendResponseHeaders(400, -1);
}

private static void validResponseHandler1(HttpExchange he) throws IOException {
he.getResponseHeaders().set("Location", "http://my-service/#access_token=1234&expires_in=86400");
he.sendResponseHeaders(302, -1);
}

private static void validResponseHandler2(HttpExchange he) throws IOException {
he.getResponseHeaders().set("Location", "http://my-service/#access_token=1235&expires_in=86400");
he.sendResponseHeaders(302, -1);
}

private static void defaultHandler(HttpExchange he) throws IOException {
String path = he.getRequestURI().getPath();
Pattern r = Pattern.compile("(.*)/.well-known/oauth-authorization-server");
// Now create matcher object.
Matcher m = r.matcher(path);
if (m.find()) {
String scheme = he.getHttpContext().getServer() instanceof HttpsServer ? "https" : "http";
String rootURL = scheme + "://localhost:" + he.getLocalAddress().getPort() + "/";
String responseToClient = "{\n" +
" \"issuer\": \"" + rootURL + "\",\n" +
" \"authorization_endpoint\": \"" + rootURL + "/" + m.group(1) + "/oauth/authorize\",\n" +
" \"token_endpoint\": \"" + rootURL + "/oauth/token\",\n" +
" \"scopes_supported\": [\n" +
" \"user:check-access\",\n" +
" \"user:full\",\n" +
" \"user:info\",\n" +
" \"user:list-projects\",\n" +
" \"user:list-scoped-projects\"\n" +
" ],\n" +
" \"response_types_supported\": [\n" +
" \"code\",\n" +
" \"token\"\n" +
" ],\n" +
" \"grant_types_supported\": [\n" +
" \"authorization_code\",\n" +
" \"implicit\"\n" +
" ],\n" +
" \"code_challenge_methods_supported\": [\n" +
" \"plain\",\n" +
" \"S256\"\n" +
" ]\n" +
"}";
byte[] responseBytes = responseToClient.getBytes(StandardCharsets.UTF_8);
he.sendResponseHeaders(200, responseBytes.length);
try (OutputStream os = he.getResponseBody()) {
os.write(responseBytes);
}
} else {
String responseToClient = "Bad test: unknown path " + path;
byte[] responseBytes = responseToClient.getBytes(StandardCharsets.UTF_8);
he.sendResponseHeaders(500, responseBytes.length);
try (OutputStream os = he.getResponseBody()) {
os.write(responseBytes);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
package org.jenkinsci.plugins.kubernetes.credentials;

import com.cloudbees.plugins.credentials.CredentialsScope;
import com.sun.net.httpserver.HttpServer;
import hudson.util.Secret;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
Expand Down Expand Up @@ -33,37 +31,39 @@ public class OpenShiftBearerTokenCredentialTest {
@Rule
public ExpectedException expectedEx = ExpectedException.none();

private Server server;
private HttpServer server;

@Before
public void prepareFakeOAuthServer() throws Exception {
InetSocketAddress addr = new InetSocketAddress("localhost", 0);
server = new Server(addr);
ServletContextHandler context = new ServletContextHandler();
context.setContextPath("/");
context.addServlet(new ServletHolder(new MockHttpServlet()), "/*");
server.setHandler(context);
InetSocketAddress address = new InetSocketAddress("localhost", 0);
server = HttpServer.create(address, 0);
OpenShiftBearerTokenCredentialMockServer.registerHttpHandlers(server);
server.start();
}

@After
public void unprepareFakeOAuthServer() throws Exception {
server.stop();
public void unprepareFakeOAuthServer() {
server.stop(0);
}

private String getURI() {
InetSocketAddress address = server.getAddress();
return "http://" + address.getHostString() + ":" + address.getPort() + "/";
}

@Test
public void testValidResponse() throws IOException {
OpenShiftBearerTokenCredentialImpl t = new OpenShiftBearerTokenCredentialImpl(CredentialsScope.GLOBAL, CREDENTIAL_ID, "sample", USERNAME, PASSWORD);
String token = t.getToken(server.getURI() + "valid-response", null, true);
String token = t.getToken(getURI() + "valid-response", null, true);
assertEquals("1234", token);
}

@Test
public void testMultipleCachedTokens() throws IOException {
OpenShiftBearerTokenCredentialImpl t = new OpenShiftBearerTokenCredentialImpl(CredentialsScope.GLOBAL, CREDENTIAL_ID, "sample", USERNAME, PASSWORD);
String token1 = t.getToken(server.getURI() + "valid-response", null, true);
String token2 = t.getToken(server.getURI() + "valid-response2", null, true);
String token3 = t.getToken(server.getURI() + "valid-response", null, true);
String token1 = t.getToken(getURI() + "valid-response", null, true);
String token2 = t.getToken(getURI() + "valid-response2", null, true);
String token3 = t.getToken(getURI() + "valid-response", null, true);
assertEquals("1234", token1);
assertEquals("1235", token2);
assertEquals("1234", token3);
Expand All @@ -75,7 +75,7 @@ public void testBadStatusCode() throws IOException {
expectedEx.expectMessage("The response from the OAuth server was invalid: The OAuth service didn't respond with a redirection but with '400: Bad Request'");

OpenShiftBearerTokenCredentialImpl t = new OpenShiftBearerTokenCredentialImpl(CredentialsScope.GLOBAL, CREDENTIAL_ID, "sample", USERNAME, PASSWORD);
t.getToken(server.getURI() + "bad-response", null, true);
t.getToken(getURI() + "bad-response", null, true);
}

@Test
Expand All @@ -84,7 +84,7 @@ public void testMissingLocation() throws IOException {
expectedEx.expectMessage("The response from the OAuth server was invalid: The OAuth service didn't respond with location header");

OpenShiftBearerTokenCredentialImpl t = new OpenShiftBearerTokenCredentialImpl(CredentialsScope.GLOBAL, CREDENTIAL_ID, "sample", USERNAME, PASSWORD);
t.getToken(server.getURI() + "missing-location", null, true);
t.getToken(getURI() + "missing-location", null, true);
}

@Test
Expand All @@ -93,7 +93,7 @@ public void testBadLocation() throws IOException {
expectedEx.expectMessage("The response from the OAuth server was invalid: The response contained no token");

OpenShiftBearerTokenCredentialImpl t = new OpenShiftBearerTokenCredentialImpl(CredentialsScope.GLOBAL, CREDENTIAL_ID, "sample", USERNAME, PASSWORD);
t.getToken(server.getURI() + "bad-location", null, true);
t.getToken(getURI() + "bad-location", null, true);
}

@Test
Expand Down

0 comments on commit 90a488b

Please sign in to comment.