From 25329a8023b039f7ca9c58ad1ab8e6f1780f9a4d Mon Sep 17 00:00:00 2001 From: George Aristy Date: Tue, 15 May 2018 16:54:33 -0400 Subject: [PATCH 1/2] (#99) Implemented basic authentication and HttpClient decorator to inject authentication header --- src/main/java/com/amihaiemil/docker/Auth.java | 44 +++++ .../com/amihaiemil/docker/AuthHttpClient.java | 144 ++++++++++++++++ .../com/amihaiemil/docker/Credentials.java | 73 ++++++++ .../java/com/amihaiemil/docker/RtImages.java | 5 - .../docker/AuthHttpClientTestCase.java | 162 ++++++++++++++++++ .../docker/CredentialsTestCase.java | 64 +++++++ 6 files changed, 487 insertions(+), 5 deletions(-) create mode 100644 src/main/java/com/amihaiemil/docker/Auth.java create mode 100644 src/main/java/com/amihaiemil/docker/AuthHttpClient.java create mode 100644 src/main/java/com/amihaiemil/docker/Credentials.java create mode 100644 src/test/java/com/amihaiemil/docker/AuthHttpClientTestCase.java create mode 100644 src/test/java/com/amihaiemil/docker/CredentialsTestCase.java diff --git a/src/main/java/com/amihaiemil/docker/Auth.java b/src/main/java/com/amihaiemil/docker/Auth.java new file mode 100644 index 00000000..db24150a --- /dev/null +++ b/src/main/java/com/amihaiemil/docker/Auth.java @@ -0,0 +1,44 @@ +/** + * Copyright (c) 2018, Mihai Emil Andronache + * All rights reserved. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1)Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2)Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3)Neither the name of docker-java-api nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +package com.amihaiemil.docker; + +/** + * Authentication for Docker API. + * @author George Aristy (george.aristy@gmail.com) + * @version $Id$ + * @see Authentication + * @since 0.0.1 + * @todo #99:30min Implement a new auth named 'Token' that will hold the user's + * identity token from the auth endpoint. Implement some operation that would + * call the /auth endpoint and obtain a token. + */ +public interface Auth { + /** + * This {@link Auth} as a Base-64 encoded string. + * @return This auth as a base64-encoded string. + */ + String encoded(); +} diff --git a/src/main/java/com/amihaiemil/docker/AuthHttpClient.java b/src/main/java/com/amihaiemil/docker/AuthHttpClient.java new file mode 100644 index 00000000..299c6b56 --- /dev/null +++ b/src/main/java/com/amihaiemil/docker/AuthHttpClient.java @@ -0,0 +1,144 @@ +/** + * Copyright (c) 2018, Mihai Emil Andronache + * All rights reserved. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1)Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2)Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3)Neither the name of docker-java-api nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +package com.amihaiemil.docker; + +import java.io.IOException; +import org.apache.http.HttpHost; +import org.apache.http.HttpRequest; +import org.apache.http.HttpResponse; +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.HttpClient; +import org.apache.http.client.ResponseHandler; +import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.conn.ClientConnectionManager; +import org.apache.http.params.HttpParams; +import org.apache.http.protocol.HttpContext; + +/** + * An authenticated HttpClient. + * @author George Aristy (george.aristy@gmail.com) + * @version $Id$ + * @since 0.0.1 + * @todo #99:30min Start decorating our internal HttpClients with this one + * for calls that require authentication headers. + */ +final class AuthHttpClient implements HttpClient { + /** + * The decorated HttpClient. + */ + private final HttpClient origin; + /** + * The authentication to inject into requests. + */ + private final Auth authentication; + + /** + * Ctor. + * @param origin The HttpClient to decorate. + * @param authentication The authentication to inject into requests. + */ + AuthHttpClient(final HttpClient origin, final Auth authentication) { + this.origin = origin; + this.authentication = authentication; + } + + @Override + public HttpParams getParams() { + throw new UnsupportedOperationException(); + } + + @Override + public ClientConnectionManager getConnectionManager() { + throw new UnsupportedOperationException(); + } + + @Override + public HttpResponse execute(final HttpUriRequest request) + throws IOException, ClientProtocolException { + final String header = "X-Registry-Auth"; + if (!request.containsHeader(header)) { + request.setHeader(header, this.authentication.encoded()); + } + return this.origin.execute(request); + } + + @Override + public HttpResponse execute( + final HttpUriRequest request, final HttpContext context + ) throws IOException, ClientProtocolException { + throw new UnsupportedOperationException(); + } + + @Override + public HttpResponse execute( + final HttpHost target, final HttpRequest request + ) throws IOException, ClientProtocolException { + throw new UnsupportedOperationException(); + } + + @Override + public HttpResponse execute( + final HttpHost target, final HttpRequest request, + final HttpContext context + ) throws IOException, ClientProtocolException { + throw new UnsupportedOperationException(); + } + + @Override + public T execute( + final HttpUriRequest request, + final ResponseHandler responseHandler + ) throws IOException, ClientProtocolException { + throw new UnsupportedOperationException(); + } + + @Override + public T execute( + final HttpUriRequest request, + final ResponseHandler responseHandler, + final HttpContext context + ) throws IOException, ClientProtocolException { + throw new UnsupportedOperationException(); + } + + @Override + public T execute( + final HttpHost target, final HttpRequest request, + final ResponseHandler responseHandler + ) throws IOException, ClientProtocolException { + throw new UnsupportedOperationException(); + } + + // @checkstyle ParameterNumber (5 lines) + @Override + public T execute( + final HttpHost target, final HttpRequest request, + final ResponseHandler responseHandler, + final HttpContext context + ) throws IOException, ClientProtocolException { + throw new UnsupportedOperationException(); + } +} diff --git a/src/main/java/com/amihaiemil/docker/Credentials.java b/src/main/java/com/amihaiemil/docker/Credentials.java new file mode 100644 index 00000000..37f8cb69 --- /dev/null +++ b/src/main/java/com/amihaiemil/docker/Credentials.java @@ -0,0 +1,73 @@ +/** + * Copyright (c) 2018, Mihai Emil Andronache + * All rights reserved. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1)Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2)Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3)Neither the name of docker-java-api nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +package com.amihaiemil.docker; + +import java.nio.charset.StandardCharsets; +import java.util.Base64; +import java.util.function.Supplier; +import javax.json.Json; + +/** + * An {@link Auth} supporting bare user credentials. + * @author George Aristy (george.aristy@gmail.com) + * @version $Id$ + * @see Authentication + * @since 0.0.1 + */ +public final class Credentials implements Auth { + /** + * The base64-encoded JSON structure holding the credentials. + */ + private final Supplier encoded; + + /** + * Ctor. + * @param user The username. + * @param pwd The user's password. + * @param email The user's email address. + * @param server Domain/IP without a protocol. + * @checkstyle ParameterNumber (4 lines) + */ + public Credentials( + final String user, final String pwd, + final String email, final String server + ) { + this.encoded = () -> Base64.getEncoder().encodeToString( + Json.createObjectBuilder() + .add("username", user) + .add("password", pwd) + .add("email", email) + .add("serveraddress", server) + .build().toString() + .getBytes(StandardCharsets.UTF_8) + ); + } + + @Override + public String encoded() { + return this.encoded.get(); + } +} diff --git a/src/main/java/com/amihaiemil/docker/RtImages.java b/src/main/java/com/amihaiemil/docker/RtImages.java index 7aeefe50..41144dda 100644 --- a/src/main/java/com/amihaiemil/docker/RtImages.java +++ b/src/main/java/com/amihaiemil/docker/RtImages.java @@ -93,11 +93,6 @@ public Iterable iterate() throws IOException { } } - // @todo #83:30min Several API calls required an authentication header as - // explained here: - // https://docs.docker.com/engine/api/v1.35/#section/Authentication - // (including Images.create()). Find a way to make a reusable object from - // that action and introduce it here. // @checkstyle ParameterNumber (4 lines) @Override public Images create( diff --git a/src/test/java/com/amihaiemil/docker/AuthHttpClientTestCase.java b/src/test/java/com/amihaiemil/docker/AuthHttpClientTestCase.java new file mode 100644 index 00000000..9da28e94 --- /dev/null +++ b/src/test/java/com/amihaiemil/docker/AuthHttpClientTestCase.java @@ -0,0 +1,162 @@ +/** + * Copyright (c) 2018, Mihai Emil Andronache + * All rights reserved. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1)Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2)Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3)Neither the name of docker-java-api nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +package com.amihaiemil.docker; + +import java.io.IOException; +import org.apache.http.Header; +import org.apache.http.HttpHost; +import org.apache.http.HttpRequest; +import org.apache.http.HttpResponse; +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.HttpClient; +import org.apache.http.client.ResponseHandler; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.conn.ClientConnectionManager; +import org.apache.http.message.BasicHeader; +import org.apache.http.params.HttpParams; +import org.apache.http.protocol.HttpContext; +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.junit.Test; + +/** + * Unit tests for {@link AuthHttpClient}. + * @author George Aristy (george.aristy@gmail.com) + * @version $Id$ + * @since 0.0.1 + */ +public final class AuthHttpClientTestCase { + /** + * Must inject the X-Registry-Auth header if absent and set it to the + * auth's value. + * @throws Exception If something goes wrong. + */ + @Test + public void injectsHeaderIfAbsent() throws Exception { + final HttpUriRequest request = new HttpGet(); + new AuthHttpClient(new NoOpHttpClient(), () -> "123").execute(request); + MatcherAssert.assertThat( + request.getFirstHeader("X-Registry-Auth").getValue(), + Matchers.is("123") + ); + } + + /** + * Leaves the request's header instact if it exists. + * @throws Exception If something goes wrong. + */ + @Test + public void leavesExistingHeaderAlone() throws Exception { + final Header auth = new BasicHeader("X-Registry-Auth", "12356"); + final HttpUriRequest request = new HttpGet(); + request.setHeader(auth); + new AuthHttpClient(new NoOpHttpClient(), () -> "abc").execute(request); + MatcherAssert.assertThat( + request.getFirstHeader("X-Registry-Auth"), + Matchers.is(auth) + ); + } + + /** + * An http client that does nothing. + */ + private static class NoOpHttpClient implements HttpClient { + @Override + public HttpParams getParams() { + throw new UnsupportedOperationException(); + } + + @Override + public ClientConnectionManager getConnectionManager() { + throw new UnsupportedOperationException(); + } + + @Override + public HttpResponse execute(final HttpUriRequest request) + throws IOException, ClientProtocolException { + //no op + return null; + } + + @Override + public HttpResponse execute( + final HttpUriRequest request, final HttpContext context + ) throws IOException, ClientProtocolException { + throw new UnsupportedOperationException(); + } + + @Override + public HttpResponse execute( + final HttpHost target, final HttpRequest request + ) throws IOException, ClientProtocolException { + throw new UnsupportedOperationException(); + } + + @Override + public HttpResponse execute( + final HttpHost target, final HttpRequest request, + final HttpContext context + ) throws IOException, ClientProtocolException { + throw new UnsupportedOperationException(); + } + + @Override + public T execute( + final HttpUriRequest request, + final ResponseHandler responseHandler + ) throws IOException, ClientProtocolException { + throw new UnsupportedOperationException(); + } + + @Override + public T execute( + final HttpUriRequest request, + final ResponseHandler responseHandler, + final HttpContext context + ) throws IOException, ClientProtocolException { + throw new UnsupportedOperationException(); + } + + @Override + public T execute( + final HttpHost target, final HttpRequest request, + final ResponseHandler responseHandler + ) throws IOException, ClientProtocolException { + throw new UnsupportedOperationException(); + } + + // @checkstyle ParameterNumber (5 lines) + @Override + public T execute( + final HttpHost target, final HttpRequest request, + final ResponseHandler responseHandler, + final HttpContext context + ) throws IOException, ClientProtocolException { + throw new UnsupportedOperationException(); + } + } +} diff --git a/src/test/java/com/amihaiemil/docker/CredentialsTestCase.java b/src/test/java/com/amihaiemil/docker/CredentialsTestCase.java new file mode 100644 index 00000000..ee919a8a --- /dev/null +++ b/src/test/java/com/amihaiemil/docker/CredentialsTestCase.java @@ -0,0 +1,64 @@ +/** + * Copyright (c) 2018, Mihai Emil Andronache + * All rights reserved. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1)Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2)Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3)Neither the name of docker-java-api nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +package com.amihaiemil.docker; + +import java.nio.charset.StandardCharsets; +import java.util.Base64; +import javax.json.Json; +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.junit.Test; + +/** + * Unit tests for {@link Credentials}. + * @author George Aristy (george.aristy@gmail.com) + * @version $Id$ + * @since 0.0.1 + */ +public final class CredentialsTestCase { + /** + * Correctly encodes to base64 all attributes as a JSON object. + */ + @Test + public void correctEncoding() { + MatcherAssert.assertThat( + new Credentials( + "user", "pass", "john@doe.com", "server" + ).encoded(), + Matchers.is( + Base64.getEncoder().encodeToString( + Json.createObjectBuilder() + .add("username", "user") + .add("password", "pass") + .add("email", "john@doe.com") + .add("serveraddress", "server") + .build().toString() + .getBytes(StandardCharsets.UTF_8) + ) + ) + ); + } +} From 9f7d8848ec2aa53e49a5ff5c26b5cd1513763a9a Mon Sep 17 00:00:00 2001 From: George Aristy Date: Wed, 23 May 2018 10:06:24 -0400 Subject: [PATCH 2/2] (#99) Implemented basic authentication and HttpClient decorator to inject authentication header As per PR review: * AuthHttpClientTestCase: now mocking HttpClient by using Mockito --- .../docker/AuthHttpClientTestCase.java | 110 ++++-------------- 1 file changed, 20 insertions(+), 90 deletions(-) diff --git a/src/test/java/com/amihaiemil/docker/AuthHttpClientTestCase.java b/src/test/java/com/amihaiemil/docker/AuthHttpClientTestCase.java index 9da28e94..c4fbd2f2 100644 --- a/src/test/java/com/amihaiemil/docker/AuthHttpClientTestCase.java +++ b/src/test/java/com/amihaiemil/docker/AuthHttpClientTestCase.java @@ -25,23 +25,16 @@ */ package com.amihaiemil.docker; -import java.io.IOException; import org.apache.http.Header; -import org.apache.http.HttpHost; -import org.apache.http.HttpRequest; -import org.apache.http.HttpResponse; -import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpClient; -import org.apache.http.client.ResponseHandler; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpUriRequest; -import org.apache.http.conn.ClientConnectionManager; import org.apache.http.message.BasicHeader; -import org.apache.http.params.HttpParams; -import org.apache.http.protocol.HttpContext; import org.hamcrest.MatcherAssert; import org.hamcrest.Matchers; +import org.junit.BeforeClass; import org.junit.Test; +import org.mockito.Mockito; /** * Unit tests for {@link AuthHttpClient}. @@ -50,6 +43,22 @@ * @since 0.0.1 */ public final class AuthHttpClientTestCase { + /** + * Mock HttpClient that does nothing. + */ + private static HttpClient noOpClient; + + /** + * Setup the mock http client. + * @throws Exception If something does wrong. + */ + @BeforeClass + public static void setup() throws Exception { + noOpClient = Mockito.mock(HttpClient.class); + Mockito.when(noOpClient.execute(Mockito.any(HttpUriRequest.class))) + .thenReturn(null); + } + /** * Must inject the X-Registry-Auth header if absent and set it to the * auth's value. @@ -58,7 +67,7 @@ public final class AuthHttpClientTestCase { @Test public void injectsHeaderIfAbsent() throws Exception { final HttpUriRequest request = new HttpGet(); - new AuthHttpClient(new NoOpHttpClient(), () -> "123").execute(request); + new AuthHttpClient(noOpClient, () -> "123").execute(request); MatcherAssert.assertThat( request.getFirstHeader("X-Registry-Auth").getValue(), Matchers.is("123") @@ -74,89 +83,10 @@ public void leavesExistingHeaderAlone() throws Exception { final Header auth = new BasicHeader("X-Registry-Auth", "12356"); final HttpUriRequest request = new HttpGet(); request.setHeader(auth); - new AuthHttpClient(new NoOpHttpClient(), () -> "abc").execute(request); + new AuthHttpClient(noOpClient, () -> "abc").execute(request); MatcherAssert.assertThat( request.getFirstHeader("X-Registry-Auth"), Matchers.is(auth) ); } - - /** - * An http client that does nothing. - */ - private static class NoOpHttpClient implements HttpClient { - @Override - public HttpParams getParams() { - throw new UnsupportedOperationException(); - } - - @Override - public ClientConnectionManager getConnectionManager() { - throw new UnsupportedOperationException(); - } - - @Override - public HttpResponse execute(final HttpUriRequest request) - throws IOException, ClientProtocolException { - //no op - return null; - } - - @Override - public HttpResponse execute( - final HttpUriRequest request, final HttpContext context - ) throws IOException, ClientProtocolException { - throw new UnsupportedOperationException(); - } - - @Override - public HttpResponse execute( - final HttpHost target, final HttpRequest request - ) throws IOException, ClientProtocolException { - throw new UnsupportedOperationException(); - } - - @Override - public HttpResponse execute( - final HttpHost target, final HttpRequest request, - final HttpContext context - ) throws IOException, ClientProtocolException { - throw new UnsupportedOperationException(); - } - - @Override - public T execute( - final HttpUriRequest request, - final ResponseHandler responseHandler - ) throws IOException, ClientProtocolException { - throw new UnsupportedOperationException(); - } - - @Override - public T execute( - final HttpUriRequest request, - final ResponseHandler responseHandler, - final HttpContext context - ) throws IOException, ClientProtocolException { - throw new UnsupportedOperationException(); - } - - @Override - public T execute( - final HttpHost target, final HttpRequest request, - final ResponseHandler responseHandler - ) throws IOException, ClientProtocolException { - throw new UnsupportedOperationException(); - } - - // @checkstyle ParameterNumber (5 lines) - @Override - public T execute( - final HttpHost target, final HttpRequest request, - final ResponseHandler responseHandler, - final HttpContext context - ) throws IOException, ClientProtocolException { - throw new UnsupportedOperationException(); - } - } }