1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 package org.apache.hc.core5.testing.nio;
29
30 import static org.hamcrest.MatcherAssert.assertThat;
31
32 import java.net.InetSocketAddress;
33 import java.nio.charset.StandardCharsets;
34 import java.util.Random;
35 import java.util.concurrent.Future;
36
37 import org.apache.hc.core5.http.ContentType;
38 import org.apache.hc.core5.http.HttpException;
39 import org.apache.hc.core5.http.HttpHeaders;
40 import org.apache.hc.core5.http.HttpHost;
41 import org.apache.hc.core5.http.HttpRequest;
42 import org.apache.hc.core5.http.HttpResponse;
43 import org.apache.hc.core5.http.HttpStatus;
44 import org.apache.hc.core5.http.HttpVersion;
45 import org.apache.hc.core5.http.Message;
46 import org.apache.hc.core5.http.Method;
47 import org.apache.hc.core5.http.URIScheme;
48 import org.apache.hc.core5.http.impl.bootstrap.HttpAsyncRequester;
49 import org.apache.hc.core5.http.impl.bootstrap.HttpAsyncServer;
50 import org.apache.hc.core5.http.impl.bootstrap.StandardFilter;
51 import org.apache.hc.core5.http.message.BasicHttpRequest;
52 import org.apache.hc.core5.http.nio.AsyncEntityProducer;
53 import org.apache.hc.core5.http.nio.entity.AsyncEntityProducers;
54 import org.apache.hc.core5.http.nio.entity.StringAsyncEntityConsumer;
55 import org.apache.hc.core5.http.nio.support.AbstractAsyncServerAuthFilter;
56 import org.apache.hc.core5.http.nio.support.BasicRequestProducer;
57 import org.apache.hc.core5.http.nio.support.BasicResponseConsumer;
58 import org.apache.hc.core5.http.protocol.HttpContext;
59 import org.apache.hc.core5.net.URIAuthority;
60 import org.apache.hc.core5.reactor.IOReactorConfig;
61 import org.apache.hc.core5.reactor.ListenerEndpoint;
62 import org.apache.hc.core5.testing.nio.extension.HttpAsyncRequesterResource;
63 import org.apache.hc.core5.testing.nio.extension.HttpAsyncServerResource;
64 import org.apache.hc.core5.util.Timeout;
65 import org.hamcrest.CoreMatchers;
66 import org.junit.jupiter.api.Test;
67 import org.junit.jupiter.api.extension.RegisterExtension;
68
69 public abstract class Http1AuthenticationTest {
70
71 private static final Timeout TIMEOUT = Timeout.ofMinutes(1);
72
73 @RegisterExtension
74 private final HttpAsyncServerResource serverResource;
75 @RegisterExtension
76 private final HttpAsyncRequesterResource clientResource;
77
78 public Http1AuthenticationTest(final boolean respondImmediately) {
79 this.serverResource = new HttpAsyncServerResource(bootstrap -> bootstrap
80 .setIOReactorConfig(
81 IOReactorConfig.custom()
82 .setSoTimeout(TIMEOUT)
83 .build())
84 .setLookupRegistry(null)
85 .register("*", () -> new EchoHandler(2048))
86 .replaceFilter(StandardFilter.EXPECT_CONTINUE.name(), new AbstractAsyncServerAuthFilter<String>(respondImmediately) {
87
88 @Override
89 protected String parseChallengeResponse(
90 final String challenge, final HttpContext context) throws HttpException {
91 return challenge;
92 }
93
94 @Override
95 protected boolean authenticate(
96 final String challengeResponse,
97 final URIAuthority authority,
98 final String requestUri,
99 final HttpContext context) {
100 return challengeResponse != null && challengeResponse.equals("let me pass");
101 }
102
103 @Override
104 protected String generateChallenge(
105 final String challengeResponse,
106 final URIAuthority authority,
107 final String requestUri,
108 final HttpContext context) {
109 return "who goes there?";
110 }
111
112 @Override
113 protected AsyncEntityProducer generateResponseContent(final HttpResponse unauthorized) {
114 return AsyncEntityProducers.create("You shall not pass!!!");
115 }
116 })
117 );
118 this.clientResource = new HttpAsyncRequesterResource(bootstrap -> bootstrap
119 .setIOReactorConfig(IOReactorConfig.custom()
120 .setSoTimeout(TIMEOUT)
121 .build())
122 );
123 }
124
125 @Test
126 public void testGetRequestAuthentication() throws Exception {
127 final HttpAsyncServer server = serverResource.start();
128 final Future<ListenerEndpoint> future = server.listen(new InetSocketAddress(0), URIScheme.HTTP);
129 final ListenerEndpoint listener = future.get();
130 final InetSocketAddress address = (InetSocketAddress) listener.getAddress();
131 final HttpAsyncRequester requester = clientResource.start();
132
133 final HttpHost target = new HttpHost("localhost", address.getPort());
134
135 final HttpRequest request1 = new BasicHttpRequest(Method.GET, target, "/stuff");
136 final Future<Message<HttpResponse, String>> resultFuture1 = requester.execute(
137 new BasicRequestProducer(request1, null),
138 new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), TIMEOUT, null);
139 final Message<HttpResponse, String> message1 = resultFuture1.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
140 assertThat(message1, CoreMatchers.notNullValue());
141 final HttpResponse response1 = message1.getHead();
142 assertThat(response1.getCode(), CoreMatchers.equalTo(HttpStatus.SC_UNAUTHORIZED));
143 final String body1 = message1.getBody();
144 assertThat(body1, CoreMatchers.equalTo("You shall not pass!!!"));
145
146 final HttpRequest request2 = new BasicHttpRequest(Method.GET, target, "/stuff");
147 request2.setHeader(HttpHeaders.AUTHORIZATION, "let me pass");
148 final Future<Message<HttpResponse, String>> resultFuture2 = requester.execute(
149 new BasicRequestProducer(request2, null),
150 new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), TIMEOUT, null);
151 final Message<HttpResponse, String> message2 = resultFuture2.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
152 assertThat(message2, CoreMatchers.notNullValue());
153 final HttpResponse response2 = message2.getHead();
154 assertThat(response2.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
155 final String body2 = message2.getBody();
156 assertThat(body2, CoreMatchers.equalTo(""));
157 }
158
159 @Test
160 public void testPostRequestAuthentication() throws Exception {
161 final HttpAsyncServer server = serverResource.start();
162 final Future<ListenerEndpoint> future = server.listen(new InetSocketAddress(0), URIScheme.HTTP);
163 final ListenerEndpoint listener = future.get();
164 final InetSocketAddress address = (InetSocketAddress) listener.getAddress();
165 final HttpAsyncRequester requester = clientResource.start();
166
167 final HttpHost target = new HttpHost("localhost", address.getPort());
168 final Random rnd = new Random();
169 final byte[] stuff = new byte[10240];
170 for (int i = 0; i < stuff.length; i++) {
171 stuff[i] = (byte) ('a' + rnd.nextInt(10));
172 }
173 final HttpRequest request1 = new BasicHttpRequest(Method.POST, target, "/stuff");
174 final Future<Message<HttpResponse, String>> resultFuture1 = requester.execute(
175 new BasicRequestProducer(request1, AsyncEntityProducers.create(stuff, ContentType.TEXT_PLAIN)),
176 new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), TIMEOUT, null);
177 final Message<HttpResponse, String> message1 = resultFuture1.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
178 assertThat(message1, CoreMatchers.notNullValue());
179 final HttpResponse response1 = message1.getHead();
180 assertThat(response1.getCode(), CoreMatchers.equalTo(HttpStatus.SC_UNAUTHORIZED));
181 final String body1 = message1.getBody();
182 assertThat(body1, CoreMatchers.equalTo("You shall not pass!!!"));
183
184 final HttpRequest request2 = new BasicHttpRequest(Method.POST, target, "/stuff");
185 request2.setHeader(HttpHeaders.AUTHORIZATION, "let me pass");
186 final Future<Message<HttpResponse, String>> resultFuture2 = requester.execute(
187 new BasicRequestProducer(request2, AsyncEntityProducers.create(stuff, ContentType.TEXT_PLAIN)),
188 new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), TIMEOUT, null);
189 final Message<HttpResponse, String> message2 = resultFuture2.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
190 assertThat(message2, CoreMatchers.notNullValue());
191 final HttpResponse response2 = message2.getHead();
192 assertThat(response2.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
193 final String body2 = message2.getBody();
194 assertThat(body2, CoreMatchers.equalTo(new String(stuff, StandardCharsets.US_ASCII)));
195 }
196
197 @Test
198 public void testPostRequestAuthenticationNoExpectContinue() throws Exception {
199 final HttpAsyncServer server = serverResource.start();
200 final Future<ListenerEndpoint> future = server.listen(new InetSocketAddress(0), URIScheme.HTTP);
201 final ListenerEndpoint listener = future.get();
202 final InetSocketAddress address = (InetSocketAddress) listener.getAddress();
203 final HttpAsyncRequester requester = clientResource.start();
204
205 final HttpHost target = new HttpHost("localhost", address.getPort());
206 final Random rnd = new Random();
207 final byte[] stuff = new byte[10240];
208 for (int i = 0; i < stuff.length; i++) {
209 stuff[i] = (byte) ('a' + rnd.nextInt(10));
210 }
211
212 final HttpRequest request1 = new BasicHttpRequest(Method.POST, target, "/stuff");
213 request1.setVersion(HttpVersion.HTTP_1_0);
214 final Future<Message<HttpResponse, String>> resultFuture1 = requester.execute(
215 new BasicRequestProducer(request1, AsyncEntityProducers.create(stuff, ContentType.TEXT_PLAIN)),
216 new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), TIMEOUT, null);
217 final Message<HttpResponse, String> message1 = resultFuture1.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
218 assertThat(message1, CoreMatchers.notNullValue());
219 final HttpResponse response1 = message1.getHead();
220 assertThat(response1.getCode(), CoreMatchers.equalTo(HttpStatus.SC_UNAUTHORIZED));
221 final String body1 = message1.getBody();
222 assertThat(body1, CoreMatchers.equalTo("You shall not pass!!!"));
223
224 final HttpRequest request2 = new BasicHttpRequest(Method.POST, target, "/stuff");
225 request2.setVersion(HttpVersion.HTTP_1_0);
226 request2.setHeader(HttpHeaders.AUTHORIZATION, "let me pass");
227 final Future<Message<HttpResponse, String>> resultFuture2 = requester.execute(
228 new BasicRequestProducer(request2, AsyncEntityProducers.create(stuff, ContentType.TEXT_PLAIN)),
229 new BasicResponseConsumer<>(new StringAsyncEntityConsumer()), TIMEOUT, null);
230 final Message<HttpResponse, String> message2 = resultFuture2.get(TIMEOUT.getDuration(), TIMEOUT.getTimeUnit());
231 assertThat(message2, CoreMatchers.notNullValue());
232 final HttpResponse response2 = message2.getHead();
233 assertThat(response2.getCode(), CoreMatchers.equalTo(HttpStatus.SC_OK));
234 final String body2 = message2.getBody();
235 assertThat(body2, CoreMatchers.equalTo(new String(stuff, StandardCharsets.US_ASCII)));
236 }
237
238 }