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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44 package org.eclipse.jgit.http.test;
45
46 import static org.junit.Assert.assertEquals;
47 import static org.junit.Assert.assertFalse;
48 import static org.junit.Assert.assertTrue;
49 import static org.junit.Assert.fail;
50
51 import java.io.IOException;
52 import java.util.Arrays;
53 import java.util.Collection;
54 import java.util.EnumSet;
55 import java.util.List;
56
57 import javax.servlet.DispatcherType;
58 import javax.servlet.Filter;
59 import javax.servlet.FilterChain;
60 import javax.servlet.FilterConfig;
61 import javax.servlet.ServletException;
62 import javax.servlet.ServletRequest;
63 import javax.servlet.ServletResponse;
64 import javax.servlet.http.HttpServletRequest;
65 import javax.servlet.http.HttpServletResponse;
66
67 import org.eclipse.jetty.servlet.FilterHolder;
68 import org.eclipse.jetty.servlet.ServletContextHandler;
69 import org.eclipse.jetty.servlet.ServletHolder;
70 import org.eclipse.jgit.errors.TransportException;
71 import org.eclipse.jgit.errors.UnsupportedCredentialItem;
72 import org.eclipse.jgit.http.server.GitServlet;
73 import org.eclipse.jgit.junit.TestRepository;
74 import org.eclipse.jgit.junit.http.AccessEvent;
75 import org.eclipse.jgit.junit.http.AppServer;
76 import org.eclipse.jgit.junit.http.HttpTestCase;
77 import org.eclipse.jgit.lib.ConfigConstants;
78 import org.eclipse.jgit.lib.NullProgressMonitor;
79 import org.eclipse.jgit.lib.Repository;
80 import org.eclipse.jgit.revwalk.RevBlob;
81 import org.eclipse.jgit.revwalk.RevCommit;
82 import org.eclipse.jgit.transport.CredentialItem;
83 import org.eclipse.jgit.transport.CredentialsProvider;
84 import org.eclipse.jgit.transport.HttpTransport;
85 import org.eclipse.jgit.transport.Transport;
86 import org.eclipse.jgit.transport.URIish;
87 import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
88 import org.eclipse.jgit.transport.http.HttpConnectionFactory;
89 import org.eclipse.jgit.transport.http.JDKHttpConnectionFactory;
90 import org.eclipse.jgit.transport.http.apache.HttpClientConnectionFactory;
91 import org.eclipse.jgit.util.HttpSupport;
92 import org.junit.Before;
93 import org.junit.Test;
94 import org.junit.runner.RunWith;
95 import org.junit.runners.Parameterized;
96 import org.junit.runners.Parameterized.Parameters;
97
98 @RunWith(Parameterized.class)
99 public class SmartClientSmartServerSslTest extends HttpTestCase {
100
101
102
103
104
105
106
107
108
109 private CredentialsProvider testCredentials = new CredentialsProvider() {
110
111 @Override
112 public boolean isInteractive() {
113 return false;
114 }
115
116 @Override
117 public boolean supports(CredentialItem... items) {
118 for (CredentialItem item : items) {
119 if (item instanceof CredentialItem.InformationalMessage) {
120 continue;
121 }
122 if (item instanceof CredentialItem.YesNoType) {
123 continue;
124 }
125 return false;
126 }
127 return true;
128 }
129
130 @Override
131 public boolean get(URIish uri, CredentialItem... items)
132 throws UnsupportedCredentialItem {
133 for (CredentialItem item : items) {
134 if (item instanceof CredentialItem.InformationalMessage) {
135 continue;
136 }
137 if (item instanceof CredentialItem.YesNoType) {
138 ((CredentialItem.YesNoType) item).setValue(true);
139 continue;
140 }
141 return false;
142 }
143 return true;
144 }
145 };
146
147 private URIish remoteURI;
148
149 private URIish secureURI;
150
151 private RevBlob A_txt;
152
153 private RevCommit A, B;
154
155 @Parameters
156 public static Collection<Object[]> data() {
157
158 return Arrays.asList(new Object[][] {
159 { new JDKHttpConnectionFactory() },
160 { new HttpClientConnectionFactory() } });
161 }
162
163 public SmartClientSmartServerSslTest(HttpConnectionFactory cf) {
164 HttpTransport.setConnectionFactory(cf);
165 }
166
167 @Override
168 protected AppServer createServer() {
169 return new AppServer(0, 0);
170 }
171
172 @Override
173 @Before
174 public void setUp() throws Exception {
175 super.setUp();
176
177 final TestRepository<Repository> src = createTestRepository();
178 final String srcName = src.getRepository().getDirectory().getName();
179 src.getRepository()
180 .getConfig()
181 .setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null,
182 ConfigConstants.CONFIG_KEY_LOGALLREFUPDATES, true);
183
184 GitServlet gs = new GitServlet();
185
186 ServletContextHandler app = addNormalContext(gs, src, srcName);
187
188 server.setUp();
189
190 remoteURI = toURIish(app, srcName);
191 secureURI = new URIish(rewriteUrl(remoteURI.toString(), "https",
192 server.getSecurePort()));
193
194 A_txt = src.blob("A");
195 A = src.commit().add("A_txt", A_txt).create();
196 B = src.commit().parent(A).add("A_txt", "C").add("B", "B").create();
197 src.update(master, B);
198
199 src.update("refs/garbage/a/very/long/ref/name/to/compress", B);
200 }
201
202 private ServletContextHandler addNormalContext(GitServlet gs, TestRepository<Repository> src, String srcName) {
203 ServletContextHandler app = server.addContext("/git");
204 app.addFilter(new FilterHolder(new Filter() {
205
206 @Override
207 public void init(FilterConfig filterConfig)
208 throws ServletException {
209
210 }
211
212
213 @Override
214 public void doFilter(ServletRequest request,
215 ServletResponse response, FilterChain chain)
216 throws IOException, ServletException {
217 final HttpServletResponse httpServletResponse = (HttpServletResponse) response;
218 final HttpServletRequest httpServletRequest = (HttpServletRequest) request;
219 final StringBuffer fullUrl = httpServletRequest.getRequestURL();
220 if (httpServletRequest.getQueryString() != null) {
221 fullUrl.append("?")
222 .append(httpServletRequest.getQueryString());
223 }
224 String urlString = rewriteUrl(fullUrl.toString(), "https",
225 server.getSecurePort());
226 httpServletResponse
227 .setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
228 httpServletResponse.setHeader(HttpSupport.HDR_LOCATION,
229 urlString.replace("/https/", "/"));
230 }
231
232 @Override
233 public void destroy() {
234
235 }
236 }), "/https/*", EnumSet.of(DispatcherType.REQUEST));
237 app.addFilter(new FilterHolder(new Filter() {
238
239 @Override
240 public void init(FilterConfig filterConfig)
241 throws ServletException {
242
243 }
244
245
246 @Override
247 public void doFilter(ServletRequest request,
248 ServletResponse response, FilterChain chain)
249 throws IOException, ServletException {
250 final HttpServletResponse httpServletResponse = (HttpServletResponse) response;
251 final HttpServletRequest httpServletRequest = (HttpServletRequest) request;
252 final StringBuffer fullUrl = httpServletRequest.getRequestURL();
253 if (httpServletRequest.getQueryString() != null) {
254 fullUrl.append("?")
255 .append(httpServletRequest.getQueryString());
256 }
257 String urlString = rewriteUrl(fullUrl.toString(), "http",
258 server.getPort());
259 httpServletResponse
260 .setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
261 httpServletResponse.setHeader(HttpSupport.HDR_LOCATION,
262 urlString.replace("/back/", "/"));
263 }
264
265 @Override
266 public void destroy() {
267
268 }
269 }), "/back/*", EnumSet.of(DispatcherType.REQUEST));
270 gs.setRepositoryResolver(new TestRepositoryResolver(src, srcName));
271 app.addServlet(new ServletHolder(gs), "/*");
272 return app;
273 }
274
275 @Test
276 public void testInitialClone_ViaHttps() throws Exception {
277 Repository dst = createBareRepository();
278 assertFalse(dst.hasObject(A_txt));
279
280 try (Transport t = Transport.open(dst, secureURI)) {
281 t.setCredentialsProvider(testCredentials);
282 t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
283 }
284 assertTrue(dst.hasObject(A_txt));
285 assertEquals(B, dst.exactRef(master).getObjectId());
286 fsck(dst, B);
287
288 List<AccessEvent> requests = getRequests();
289 assertEquals(2, requests.size());
290 }
291
292 @Test
293 public void testInitialClone_RedirectToHttps() throws Exception {
294 Repository dst = createBareRepository();
295 assertFalse(dst.hasObject(A_txt));
296
297 URIish cloneFrom = extendPath(remoteURI, "/https");
298 try (Transport t = Transport.open(dst, cloneFrom)) {
299 t.setCredentialsProvider(testCredentials);
300 t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
301 }
302 assertTrue(dst.hasObject(A_txt));
303 assertEquals(B, dst.exactRef(master).getObjectId());
304 fsck(dst, B);
305
306 List<AccessEvent> requests = getRequests();
307 assertEquals(3, requests.size());
308 }
309
310 @Test
311 public void testInitialClone_RedirectBackToHttp() throws Exception {
312 Repository dst = createBareRepository();
313 assertFalse(dst.hasObject(A_txt));
314
315 URIish cloneFrom = extendPath(secureURI, "/back");
316 try (Transport t = Transport.open(dst, cloneFrom)) {
317 t.setCredentialsProvider(testCredentials);
318 t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
319 fail("Should have failed (redirect from https to http)");
320 } catch (TransportException e) {
321 assertTrue(e.getMessage().contains("not allowed"));
322 }
323 }
324
325 @Test
326 public void testInitialClone_SslFailure() throws Exception {
327 Repository dst = createBareRepository();
328 assertFalse(dst.hasObject(A_txt));
329
330 try (Transport t = Transport.open(dst, secureURI)) {
331
332 t.setCredentialsProvider(
333 new UsernamePasswordCredentialsProvider("any", "anypwd"));
334 t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
335 fail("Should have failed (SSL certificate not trusted)");
336 } catch (TransportException e) {
337 assertTrue(e.getMessage().contains("Secure connection"));
338 }
339 }
340
341 }