1 package org.apache.maven.wagon.http;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import org.apache.maven.wagon.FileTestUtils;
23 import org.apache.maven.wagon.ResourceDoesNotExistException;
24 import org.apache.maven.wagon.StreamingWagon;
25 import org.apache.maven.wagon.StreamingWagonTestCase;
26 import org.apache.maven.wagon.TransferFailedException;
27 import org.apache.maven.wagon.Wagon;
28 import org.apache.maven.wagon.WagonException;
29 import org.apache.maven.wagon.authentication.AuthenticationInfo;
30 import org.apache.maven.wagon.authorization.AuthorizationException;
31 import org.apache.maven.wagon.proxy.ProxyInfo;
32 import org.apache.maven.wagon.proxy.ProxyInfoProvider;
33 import org.apache.maven.wagon.repository.Repository;
34 import org.apache.maven.wagon.resource.Resource;
35 import org.codehaus.plexus.util.FileUtils;
36 import org.codehaus.plexus.util.IOUtil;
37 import org.codehaus.plexus.util.StringUtils;
38 import org.eclipse.jetty.http.HttpStatus;
39 import org.eclipse.jetty.security.ConstraintMapping;
40 import org.eclipse.jetty.security.ConstraintSecurityHandler;
41 import org.eclipse.jetty.security.HashLoginService;
42 import org.eclipse.jetty.security.SecurityHandler;
43 import org.eclipse.jetty.security.authentication.BasicAuthenticator;
44 import org.eclipse.jetty.server.Connector;
45 import org.eclipse.jetty.server.HttpConfiguration;
46 import org.eclipse.jetty.server.HttpConnectionFactory;
47 import org.eclipse.jetty.server.Request;
48 import org.eclipse.jetty.server.Response;
49 import org.eclipse.jetty.server.Server;
50 import org.eclipse.jetty.server.ServerConnector;
51 import org.eclipse.jetty.server.handler.AbstractHandler;
52 import org.eclipse.jetty.server.handler.HandlerCollection;
53 import org.eclipse.jetty.servlet.DefaultServlet;
54 import org.eclipse.jetty.servlet.ServletContextHandler;
55 import org.eclipse.jetty.servlet.ServletHolder;
56 import org.eclipse.jetty.util.security.Constraint;
57 import org.eclipse.jetty.util.security.Password;
58
59 import javax.servlet.ServletException;
60 import javax.servlet.http.HttpServletRequest;
61 import javax.servlet.http.HttpServletResponse;
62
63 import java.io.ByteArrayOutputStream;
64 import java.io.File;
65 import java.io.FileInputStream;
66 import java.io.FileOutputStream;
67 import java.io.IOException;
68 import java.io.InputStream;
69 import java.io.OutputStream;
70 import java.lang.reflect.Method;
71 import java.net.URLDecoder;
72 import java.util.ArrayList;
73 import java.util.Collections;
74 import java.util.Enumeration;
75 import java.util.HashMap;
76 import java.util.List;
77 import java.util.Map;
78 import java.util.Properties;
79 import java.util.concurrent.atomic.AtomicBoolean;
80 import java.util.zip.DeflaterOutputStream;
81 import java.util.zip.GZIPOutputStream;
82
83
84
85
86 public abstract class HttpWagonTestCase
87 extends StreamingWagonTestCase
88 {
89 public static final int SC_TOO_MANY_REQUESTS = 429;
90
91 private Server server;
92 private ServerConnector connector;
93
94 protected int getLocalPort( Server server )
95 {
96 Connector connector = server.getConnectors()[0];
97 return ( ( ServerConnector ) connector ).getLocalPort();
98 }
99
100 protected void setupWagonTestingFixtures()
101 throws Exception
102 {
103
104
105 File file = FileTestUtils.createUniqueFile( "local-repository", "test-resource" );
106
107 file.delete();
108
109 file.getParentFile().mkdirs();
110
111 File repositoryDirectory = getRepositoryDirectory();
112 FileUtils.deleteDirectory( repositoryDirectory );
113 repositoryDirectory.mkdirs();
114
115 server = new Server( );
116
117
118 connector = addConnector( server );
119
120 PutHandler putHandler = new PutHandler( repositoryDirectory );
121
122 ServletContextHandler context = createContext( server, repositoryDirectory );
123 HandlerCollection handlers = new HandlerCollection();
124 handlers.addHandler( putHandler );
125 handlers.addHandler( context );
126 server.setHandler( handlers );
127
128 server.start();
129 }
130
131 protected final int getTestRepositoryPort()
132 {
133 if ( server == null )
134 {
135 return 0;
136 }
137 return connector.getLocalPort();
138 }
139
140 protected ServletContextHandler createContext( Server server, File repositoryDirectory )
141 throws IOException
142 {
143 ServletContextHandler root = new ServletContextHandler( ServletContextHandler.SESSIONS );
144 root.setResourceBase( repositoryDirectory.getAbsolutePath() );
145 ServletHolder servletHolder = new ServletHolder( new DefaultServlet() );
146 root.addServlet( servletHolder, "/*" );
147 return root;
148 }
149
150 protected void tearDownWagonTestingFixtures()
151 throws Exception
152 {
153 server.stop();
154 }
155
156 public void testHttpHeaders()
157 throws Exception
158 {
159 Properties headers = new Properties();
160 headers.setProperty( "User-Agent", "Maven-Wagon/1.0" );
161
162 StreamingWagon wagon = (StreamingWagon) getWagon();
163
164 setHttpConfiguration( wagon, headers, new Properties() );
165
166 Server server = new Server( );
167 TestHeaderHandler handler = new TestHeaderHandler();
168 server.setHandler( handler );
169 ServerConnector serverConnector = addConnector( server );
170 server.start();
171
172 wagon.connect(
173 new Repository( "id", getProtocol() + "://localhost:" + serverConnector.getLocalPort() ) );
174
175 wagon.getToStream( "resource", new ByteArrayOutputStream() );
176
177 wagon.disconnect();
178
179 server.stop();
180
181 assertEquals( "Maven-Wagon/1.0", handler.headers.get( "User-Agent" ) );
182 }
183
184
185
186
187 public void testHttpHeadersWithCommonMethods()
188 throws Exception
189 {
190 Properties properties = new Properties();
191 properties.setProperty( "User-Agent", "Maven-Wagon/1.0" );
192
193 StreamingWagon wagon = (StreamingWagon) getWagon();
194
195 Method setHttpHeaders = wagon.getClass().getMethod( "setHttpHeaders", Properties.class );
196 setHttpHeaders.invoke( wagon, properties );
197
198 Server server = new Server( );
199 ServerConnector serverConnector = addConnector( server );
200 TestHeaderHandler handler = new TestHeaderHandler();
201 server.setHandler( handler );
202 addConnector( server );
203 server.start();
204
205 wagon.connect(
206 new Repository( "id", getProtocol() + "://localhost:" + serverConnector.getLocalPort() ) );
207
208 wagon.getToStream( "resource", new ByteArrayOutputStream() );
209
210 wagon.disconnect();
211
212 server.stop();
213
214 assertEquals( "Maven-Wagon/1.0", handler.headers.get( "User-Agent" ) );
215 }
216
217 public void testUserAgentHeaderIsPresentByDefault()
218 throws Exception
219 {
220 StreamingWagon wagon = (StreamingWagon) getWagon();
221 Server server = new Server( );
222 TestHeaderHandler handler = new TestHeaderHandler();
223 server.setHandler( handler );
224 addConnector( server );
225 server.start();
226 wagon.connect( new Repository( "id", getProtocol() + "://localhost:" + getLocalPort( server ) ) );
227 wagon.getToStream( "resource", new ByteArrayOutputStream() );
228 wagon.disconnect();
229 server.stop();
230
231 assertNotNull( "default User-Agent header of wagon provider should be present",
232 handler.headers.get( "User-Agent" ) );
233 }
234
235 public void testUserAgentHeaderIsPresentOnlyOnceIfSetMultipleTimes()
236 throws Exception
237 {
238 StreamingWagon wagon = (StreamingWagon) getWagon();
239
240
241 Properties headers1 = new Properties();
242 headers1.setProperty( "User-Agent", "test-user-agent" );
243 setHttpConfiguration( wagon, headers1, new Properties() );
244
245
246 Properties headers2 = new Properties();
247 headers2.setProperty( "User-Agent", "test-user-agent" );
248 Method setHttpHeaders = wagon.getClass().getMethod( "setHttpHeaders", Properties.class );
249 setHttpHeaders.invoke( wagon, headers2 );
250
251 Server server = new Server( );
252 TestHeaderHandler handler = new TestHeaderHandler();
253 server.setHandler( handler );
254 addConnector( server );
255 server.start();
256 wagon.connect( new Repository( "id", getProtocol() + "://localhost:" + getLocalPort( server ) ) );
257 wagon.getToStream( "resource", new ByteArrayOutputStream() );
258 wagon.disconnect();
259 server.stop();
260
261 assertEquals( "test-user-agent", handler.headers.get( "User-Agent" ) );
262
263 }
264
265 protected abstract void setHttpConfiguration( StreamingWagon wagon, Properties headers, Properties params );
266
267 protected ServerConnector addConnector( Server server )
268 {
269 ServerConnector serverConnector =
270 new ServerConnector( server, new HttpConnectionFactory( new HttpConfiguration() ) );
271 server.addConnector( serverConnector );
272 return serverConnector;
273 }
274
275 protected String getRepositoryUrl( Server server )
276 {
277 int localPort = getLocalPort( server );
278 return getProtocol() + "://localhost:" + localPort;
279 }
280
281 public void testGetForbidden()
282 throws Exception
283 {
284 try
285 {
286 runTestGet( HttpServletResponse.SC_FORBIDDEN );
287 fail();
288 }
289 catch ( AuthorizationException e )
290 {
291 assertTrue( true );
292 }
293 }
294
295 public void testGet404()
296 throws Exception
297 {
298 try
299 {
300 runTestGet( HttpServletResponse.SC_NOT_FOUND );
301 fail();
302 }
303 catch ( ResourceDoesNotExistException e )
304 {
305 assertTrue( true );
306 }
307 }
308
309 public void testGet500()
310 throws Exception
311 {
312 try
313 {
314 runTestGet( HttpServletResponse.SC_INTERNAL_SERVER_ERROR );
315 fail();
316 }
317 catch ( TransferFailedException e )
318 {
319 assertTrue( true );
320 }
321 }
322
323 private void runTestGet( int status )
324 throws Exception
325 {
326 StreamingWagon wagon = (StreamingWagon) getWagon();
327
328 Server server = createStatusServer( status );
329 server.start();
330
331 String baseUrl = getRepositoryUrl( server );
332 String resourceName = "resource";
333 String serverReasonPhrase = HttpStatus.getCode( status ).getMessage();
334
335 wagon.connect( new Repository( "id", baseUrl ) );
336
337 try
338 {
339 wagon.getToStream( "resource", new ByteArrayOutputStream() );
340 fail();
341 }
342 catch ( Exception e )
343 {
344 verifyWagonExceptionMessage( e, status, baseUrl + "/" + resourceName, serverReasonPhrase );
345 throw e;
346 }
347 finally
348 {
349 wagon.disconnect();
350
351 server.stop();
352 }
353 }
354
355 public void testResourceExistsForbidden()
356 throws Exception
357 {
358 try
359 {
360 runTestResourceExists( HttpServletResponse.SC_FORBIDDEN );
361 fail();
362 }
363 catch ( AuthorizationException e )
364 {
365 assertTrue( true );
366 }
367 }
368
369 public void testResourceExists404()
370 throws Exception
371 {
372 try
373 {
374 assertFalse( runTestResourceExists( HttpServletResponse.SC_NOT_FOUND ) );
375 }
376 catch ( ResourceDoesNotExistException e )
377 {
378 assertTrue( true );
379 }
380 }
381
382 public void testResourceExists500()
383 throws Exception
384 {
385 try
386 {
387 runTestResourceExists( HttpServletResponse.SC_INTERNAL_SERVER_ERROR );
388 fail();
389 }
390 catch ( TransferFailedException e )
391 {
392 assertTrue( true );
393 }
394 }
395
396 public void testResourceExists429()
397 throws Exception
398 {
399 try
400 {
401
402 final AtomicBoolean called = new AtomicBoolean();
403
404 AbstractHandler handler = new AbstractHandler()
405 {
406 public void handle( String target, Request baseRequest, HttpServletRequest request,
407 HttpServletResponse response ) throws IOException, ServletException
408 {
409 if ( called.get() )
410 {
411 response.setStatus( HttpServletResponse.SC_INTERNAL_SERVER_ERROR );
412 baseRequest.setHandled( true );
413 }
414 else
415 {
416 called.set( true );
417 response.setStatus( SC_TOO_MANY_REQUESTS );
418 baseRequest.setHandled( true );
419 }
420 }
421 };
422
423 StreamingWagon wagon = (StreamingWagon) getWagon();
424 Server server = new Server( );
425 server.setHandler( handler );
426 addConnector( server );
427 server.start();
428 wagon.connect( new Repository( "id", getRepositoryUrl( server ) ) );
429
430 try
431 {
432 wagon.resourceExists( "resource" );
433 }
434 finally
435 {
436 wagon.disconnect();
437
438 server.stop();
439 }
440
441 fail();
442 }
443 catch ( TransferFailedException e )
444 {
445 assertTrue( true );
446 }
447 }
448
449
450 private boolean runTestResourceExists( int status )
451 throws Exception
452 {
453 StreamingWagon wagon = (StreamingWagon) getWagon();
454
455 Server server = createStatusServer( status );
456 server.start();
457
458 wagon.connect( new Repository( "id", getRepositoryUrl( server ) ) );
459
460 try
461 {
462 return wagon.resourceExists( "resource" );
463 }
464 finally
465 {
466 wagon.disconnect();
467
468 server.stop();
469 }
470 }
471
472 protected long getExpectedLastModifiedOnGet( Repository repository, Resource resource )
473 {
474 File file = new File( getRepositoryDirectory(), resource.getName() );
475 return ( file.lastModified() / 1000 ) * 1000;
476 }
477
478 protected File getRepositoryDirectory()
479 {
480 return getTestFile( "target/test-output/http-repository" );
481 }
482
483 public void testGzipGet()
484 throws Exception
485 {
486 Server server = new Server( );
487
488 String localRepositoryPath = FileTestUtils.getTestOutputDir().toString();
489 ServletContextHandler root = new ServletContextHandler( ServletContextHandler.SESSIONS );
490 root.setResourceBase( localRepositoryPath );
491 ServletHolder servletHolder = new ServletHolder( new DefaultServlet() );
492 servletHolder.setInitParameter( "gzip", "true" );
493 root.addServlet( servletHolder, "/*" );
494 addConnector( server );
495 server.setHandler( root );
496 server.start();
497
498 try
499 {
500 Wagon wagon = getWagon();
501
502 Repository testRepository = new Repository( "id", getRepositoryUrl( server ) );
503
504 File sourceFile = new File( localRepositoryPath + "/gzip" );
505
506 sourceFile.deleteOnExit();
507
508 String resName = "gzip-res.txt";
509 String sourceContent = writeTestFile( sourceFile, resName, "gzip" );
510
511 wagon.connect( testRepository );
512
513 File destFile = FileTestUtils.createUniqueFile( getName(), getName() );
514
515 destFile.deleteOnExit();
516
517 wagon.get( "gzip/" + resName, destFile );
518
519 wagon.disconnect();
520
521 String destContent = FileUtils.fileRead( destFile );
522
523 assertEquals( sourceContent, destContent );
524 }
525 finally
526 {
527 server.stop();
528 }
529 }
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581 public void testProxiedRequest()
582 throws Exception
583 {
584 ProxyInfo proxyInfo = createProxyInfo();
585 TestHeaderHandler handler = new TestHeaderHandler();
586
587 runTestProxiedRequest( proxyInfo, handler );
588 }
589
590 public void testProxiedRequestWithAuthentication()
591 throws Exception
592 {
593 ProxyInfo proxyInfo = createProxyInfo();
594 proxyInfo.setUserName( "user" );
595 proxyInfo.setPassword( "secret" );
596 AuthorizingProxyHandler handler = new AuthorizingProxyHandler();
597
598 runTestProxiedRequest( proxyInfo, handler );
599
600 assertTrue( handler.headers.containsKey( "Proxy-Authorization" ) );
601
602 if ( supportProxyPreemptiveAuthentication() )
603 {
604 assertEquals( HttpServletResponse.SC_OK, handler.handlerRequestResponses.get( 0 ).responseCode );
605 }
606 else
607 {
608 assertEquals( HttpServletResponse.SC_PROXY_AUTHENTICATION_REQUIRED,
609 handler.handlerRequestResponses.get( 0 ).responseCode );
610 assertEquals( HttpServletResponse.SC_OK, handler.handlerRequestResponses.get( 1 ).responseCode );
611 }
612
613 }
614
615 public void testProxiedRequestWithAuthenticationWithProvider()
616 throws Exception
617 {
618 final ProxyInfo proxyInfo = createProxyInfo();
619 proxyInfo.setUserName( "user" );
620 proxyInfo.setPassword( "secret" );
621 AuthorizingProxyHandler handler = new AuthorizingProxyHandler();
622
623 ProxyInfoProvider proxyInfoProvider = new ProxyInfoProvider()
624 {
625 public ProxyInfo getProxyInfo( String protocol )
626 {
627 return proxyInfo;
628 }
629 };
630 runTestProxiedRequestWithProvider( proxyInfoProvider, handler );
631
632 assertTrue( handler.headers.containsKey( "Proxy-Authorization" ) );
633
634 if ( supportProxyPreemptiveAuthentication() )
635 {
636 assertEquals( HttpServletResponse.SC_OK, handler.handlerRequestResponses.get( 0 ).responseCode );
637 }
638 else
639 {
640 assertEquals( HttpServletResponse.SC_PROXY_AUTHENTICATION_REQUIRED,
641 handler.handlerRequestResponses.get( 0 ).responseCode );
642 assertEquals( HttpServletResponse.SC_OK, handler.handlerRequestResponses.get( 1 ).responseCode );
643 }
644
645 }
646
647 public void testRedirectGetToStream()
648 throws Exception
649 {
650 StreamingWagon wagon = (StreamingWagon) getWagon();
651
652 Server realServer = new Server( );
653 TestHeaderHandler handler = new TestHeaderHandler();
654
655 realServer.setHandler( handler );
656 addConnector( realServer );
657 realServer.start();
658
659 Server redirectServer = new Server( );
660
661 addConnector( redirectServer );
662
663 String protocol = getProtocol();
664
665
666 if ( protocol.equals( "dav" ) )
667 {
668 protocol = "http";
669 }
670
671 if ( protocol.equals( "davs" ) )
672 {
673 protocol = "https";
674 }
675
676 String redirectUrl = protocol + "://localhost:" + getLocalPort( realServer );
677
678 RedirectHandler redirectHandler =
679 new RedirectHandler( "See Other", HttpServletResponse.SC_SEE_OTHER, redirectUrl, null );
680
681 redirectServer.setHandler( redirectHandler );
682
683 redirectServer.start();
684
685 wagon.connect( new Repository( "id", getRepositoryUrl( redirectServer ) ) );
686
687 File tmpResult = File.createTempFile( "foo", "get" );
688
689 try ( FileOutputStream fileOutputStream = new FileOutputStream( tmpResult ) )
690 {
691 wagon.getToStream( "resource", fileOutputStream );
692 fileOutputStream.flush();
693 fileOutputStream.close();
694 String found = FileUtils.fileRead( tmpResult );
695 assertEquals( "found:'" + found + "'", "Hello, World!", found );
696
697 checkHandlerResult( redirectHandler.handlerRequestResponses, HttpServletResponse.SC_SEE_OTHER );
698 checkHandlerResult( handler.handlerRequestResponses, HttpServletResponse.SC_OK );
699 }
700 finally
701 {
702 wagon.disconnect();
703
704 redirectServer.stop();
705 realServer.stop();
706
707 tmpResult.delete();
708 }
709 }
710
711 public void testRedirectGet()
712 throws Exception
713 {
714 StreamingWagon wagon = (StreamingWagon) getWagon();
715
716 Server realServer = new Server( );
717 TestHeaderHandler handler = new TestHeaderHandler();
718
719 realServer.setHandler( handler );
720 addConnector( realServer );
721 realServer.start();
722
723 Server redirectServer = new Server( );
724
725 addConnector( redirectServer );
726
727 String protocol = getProtocol();
728
729
730 if ( protocol.equals( "dav" ) )
731 {
732 protocol = "http";
733 }
734
735 if ( protocol.equals( "davs" ) )
736 {
737 protocol = "https";
738 }
739
740 String redirectUrl = protocol + "://localhost:" + getLocalPort( realServer );
741
742 RedirectHandler redirectHandler =
743 new RedirectHandler( "See Other", HttpServletResponse.SC_SEE_OTHER, redirectUrl, null );
744
745 redirectServer.setHandler( redirectHandler );
746
747 redirectServer.start();
748
749 wagon.connect( new Repository( "id", getRepositoryUrl( redirectServer ) ) );
750
751 File tmpResult = File.createTempFile( "foo", "get" );
752
753 try
754 {
755 wagon.get( "resource", tmpResult );
756 String found = FileUtils.fileRead( tmpResult );
757 assertEquals( "found:'" + found + "'", "Hello, World!", found );
758
759 checkHandlerResult( redirectHandler.handlerRequestResponses, HttpServletResponse.SC_SEE_OTHER );
760 checkHandlerResult( handler.handlerRequestResponses, HttpServletResponse.SC_OK );
761 }
762 finally
763 {
764 wagon.disconnect();
765
766 redirectServer.stop();
767 realServer.stop();
768
769 tmpResult.delete();
770 }
771 }
772
773
774 public void testRedirectPutFromStreamWithFullUrl()
775 throws Exception
776 {
777 Server realServer = new Server( );
778
779 addConnector( realServer );
780
781 File repositoryDirectory = getRepositoryDirectory();
782 FileUtils.deleteDirectory( repositoryDirectory );
783 repositoryDirectory.mkdirs();
784
785 PutHandler putHandler = new PutHandler( repositoryDirectory );
786
787 realServer.setHandler( putHandler );
788
789 realServer.start();
790
791 Server redirectServer = new Server( );
792
793 addConnector( redirectServer );
794
795 String protocol = getProtocol();
796
797
798 if ( protocol.equals( "dav" ) )
799 {
800 protocol = "http";
801 }
802
803 if ( protocol.equals( "davs" ) )
804 {
805 protocol = "https";
806 }
807
808 String redirectUrl = protocol + "://localhost:" + getLocalPort( realServer );
809
810 RedirectHandler redirectHandler =
811 new RedirectHandler( "See Other", HttpServletResponse.SC_SEE_OTHER, redirectUrl, repositoryDirectory );
812
813 redirectServer.setHandler( redirectHandler );
814
815 redirectServer.start();
816
817 try
818 {
819 StreamingWagon wagon = (StreamingWagon) getWagon();
820 Repository repository = new Repository( "foo", getRepositoryUrl( redirectServer ) );
821 wagon.connect( repository );
822
823 File sourceFile = new File( repositoryDirectory, "test-secured-put-resource" );
824 sourceFile.delete();
825 assertFalse( sourceFile.exists() );
826
827 File tempFile = File.createTempFile( "wagon", "tmp" );
828 tempFile.deleteOnExit();
829 String content = "put top secret";
830 FileUtils.fileWrite( tempFile.getAbsolutePath(), content );
831
832 try ( FileInputStream fileInputStream = new FileInputStream( tempFile ) )
833 {
834 wagon.putFromStream( fileInputStream, "test-secured-put-resource", content.length(), -1 );
835 assertEquals( content, FileUtils.fileRead( sourceFile.getAbsolutePath() ) );
836
837 checkRequestResponseForRedirectPutWithFullUrl( redirectHandler, putHandler );
838 }
839 finally
840 {
841 wagon.disconnect();
842 tempFile.delete();
843 }
844
845 }
846 finally
847 {
848 realServer.stop();
849 redirectServer.stop();
850 }
851 }
852
853 protected void checkRequestResponseForRedirectPutWithFullUrl( RedirectHandler redirectHandler,
854 PutHandler putHandler )
855 {
856 checkHandlerResult( redirectHandler.handlerRequestResponses, HttpServletResponse.SC_SEE_OTHER );
857 checkHandlerResult( putHandler.handlerRequestResponses, HttpServletResponse.SC_CREATED );
858 }
859
860 public void testRedirectPutFromStreamRelativeUrl()
861 throws Exception
862 {
863 Server realServer = new Server( );
864 addConnector( realServer );
865 File repositoryDirectory = getRepositoryDirectory();
866 FileUtils.deleteDirectory( repositoryDirectory );
867 repositoryDirectory.mkdirs();
868
869 PutHandler putHandler = new PutHandler( repositoryDirectory );
870
871 realServer.setHandler( putHandler );
872
873 realServer.start();
874
875 Server redirectServer = new Server( );
876
877 addConnector( redirectServer );
878
879 RedirectHandler redirectHandler =
880 new RedirectHandler( "See Other", HttpServletResponse.SC_SEE_OTHER, "/redirectRequest/foo",
881 repositoryDirectory );
882
883 redirectServer.setHandler( redirectHandler );
884
885 redirectServer.start();
886
887 try
888 {
889 StreamingWagon wagon = (StreamingWagon) getWagon();
890 Repository repository = new Repository( "foo", getRepositoryUrl( redirectServer ) );
891 wagon.connect( repository );
892
893 File sourceFile = new File( repositoryDirectory, "/redirectRequest/foo/test-secured-put-resource" );
894 sourceFile.delete();
895 assertFalse( sourceFile.exists() );
896
897 File tempFile = File.createTempFile( "wagon", "tmp" );
898 tempFile.deleteOnExit();
899 String content = "put top secret";
900 FileUtils.fileWrite( tempFile.getAbsolutePath(), content );
901
902 try ( FileInputStream fileInputStream = new FileInputStream( tempFile ) )
903 {
904 wagon.putFromStream( fileInputStream, "test-secured-put-resource", content.length(), -1 );
905 assertEquals( content, FileUtils.fileRead( sourceFile.getAbsolutePath() ) );
906
907 checkRequestResponseForRedirectPutWithRelativeUrl( redirectHandler, putHandler );
908 }
909 finally
910 {
911 wagon.disconnect();
912 tempFile.delete();
913 }
914
915 }
916 finally
917 {
918 realServer.stop();
919 redirectServer.stop();
920 }
921 }
922
923 protected void checkRequestResponseForRedirectPutWithRelativeUrl( RedirectHandler redirectHandler,
924 PutHandler putHandler )
925 {
926 checkHandlerResult( redirectHandler.handlerRequestResponses, HttpServletResponse.SC_SEE_OTHER,
927 HttpServletResponse.SC_CREATED );
928 checkHandlerResult( putHandler.handlerRequestResponses );
929 }
930
931 protected void checkHandlerResult( List<HandlerRequestResponse> handlerRequestResponses,
932 int... expectedResponseCodes )
933 {
934 boolean success = true;
935 if ( handlerRequestResponses.size() == expectedResponseCodes.length )
936 {
937 for ( int i = 0; i < expectedResponseCodes.length; i++ )
938 {
939 success &= ( expectedResponseCodes[i] == handlerRequestResponses.get( i ).responseCode );
940 }
941 }
942
943 if ( !success )
944 {
945 fail( "expected " + expectedResponseCodes + ", got " + handlerRequestResponses );
946 }
947 }
948
949 public void testRedirectPutFileWithFullUrl()
950 throws Exception
951 {
952 Server realServer = new Server( );
953
954 addConnector( realServer );
955
956 File repositoryDirectory = getRepositoryDirectory();
957 FileUtils.deleteDirectory( repositoryDirectory );
958 repositoryDirectory.mkdirs();
959
960 PutHandler putHandler = new PutHandler( repositoryDirectory );
961
962 realServer.setHandler( putHandler );
963
964 realServer.start();
965
966 Server redirectServer = new Server( );
967
968 addConnector( redirectServer );
969
970 String protocol = getProtocol();
971
972
973 if ( protocol.equals( "dav" ) )
974 {
975 protocol = "http";
976 }
977
978 if ( protocol.equals( "davs" ) )
979 {
980 protocol = "https";
981 }
982
983 String redirectUrl = protocol + "://localhost:" + getLocalPort( realServer );
984
985 RedirectHandler redirectHandler =
986 new RedirectHandler( "See Other", HttpServletResponse.SC_SEE_OTHER, redirectUrl, repositoryDirectory );
987
988 redirectServer.setHandler( redirectHandler );
989
990 redirectServer.start();
991
992 try
993 {
994 StreamingWagon wagon = (StreamingWagon) getWagon();
995 Repository repository = new Repository( "foo", getRepositoryUrl( redirectServer ) );
996 wagon.connect( repository );
997
998 File sourceFile = new File( repositoryDirectory, "test-secured-put-resource" );
999 sourceFile.delete();
1000 assertFalse( sourceFile.exists() );
1001
1002 File tempFile = File.createTempFile( "wagon", "tmp" );
1003 tempFile.deleteOnExit();
1004 String content = "put top secret";
1005 FileUtils.fileWrite( tempFile.getAbsolutePath(), content );
1006
1007 try
1008 {
1009 wagon.put( tempFile, "test-secured-put-resource" );
1010 assertEquals( content, FileUtils.fileRead( sourceFile.getAbsolutePath() ) );
1011
1012 checkRequestResponseForRedirectPutWithFullUrl( redirectHandler, putHandler );
1013 }
1014 finally
1015 {
1016 wagon.disconnect();
1017 tempFile.delete();
1018 }
1019
1020 }
1021 finally
1022 {
1023 realServer.stop();
1024 redirectServer.stop();
1025 }
1026 }
1027
1028
1029 public void testRedirectPutFileRelativeUrl()
1030 throws Exception
1031 {
1032 Server realServer = new Server( );
1033 addConnector( realServer );
1034 File repositoryDirectory = getRepositoryDirectory();
1035 FileUtils.deleteDirectory( repositoryDirectory );
1036 repositoryDirectory.mkdirs();
1037
1038 PutHandler putHandler = new PutHandler( repositoryDirectory );
1039
1040 realServer.setHandler( putHandler );
1041
1042 realServer.start();
1043
1044 Server redirectServer = new Server( );
1045
1046 addConnector( redirectServer );
1047
1048 RedirectHandler redirectHandler =
1049 new RedirectHandler( "See Other", HttpServletResponse.SC_SEE_OTHER, "/redirectRequest/foo",
1050 repositoryDirectory );
1051
1052 redirectServer.setHandler( redirectHandler );
1053
1054 redirectServer.start();
1055
1056 try
1057 {
1058 StreamingWagon wagon = (StreamingWagon) getWagon();
1059 Repository repository = new Repository( "foo", getRepositoryUrl( redirectServer ) );
1060 wagon.connect( repository );
1061
1062 File sourceFile = new File( repositoryDirectory, "/redirectRequest/foo/test-secured-put-resource" );
1063 sourceFile.delete();
1064 assertFalse( sourceFile.exists() );
1065
1066 File tempFile = File.createTempFile( "wagon", "tmp" );
1067 tempFile.deleteOnExit();
1068 String content = "put top secret";
1069 FileUtils.fileWrite( tempFile.getAbsolutePath(), content );
1070
1071 try
1072 {
1073 wagon.put( tempFile, "test-secured-put-resource" );
1074 assertEquals( content, FileUtils.fileRead( sourceFile.getAbsolutePath() ) );
1075
1076 checkRequestResponseForRedirectPutWithRelativeUrl( redirectHandler, putHandler );
1077 }
1078 finally
1079 {
1080 wagon.disconnect();
1081 tempFile.delete();
1082 }
1083
1084 }
1085 finally
1086 {
1087 realServer.stop();
1088 redirectServer.stop();
1089 }
1090 }
1091
1092 public void testRedirectPutFailureNonRepeatableStream()
1093 throws Exception
1094 {
1095 File repositoryDirectory = getRepositoryDirectory();
1096 FileUtils.deleteDirectory( repositoryDirectory );
1097 repositoryDirectory.mkdirs();
1098
1099 Server redirectServer = new Server( );
1100
1101 addConnector( redirectServer );
1102
1103 RedirectHandler redirectHandler =
1104 new RedirectHandler( "See Other", HttpServletResponse.SC_SEE_OTHER, "/redirectRequest/foo",
1105 null );
1106
1107 redirectServer.setHandler( redirectHandler );
1108
1109 redirectServer.start();
1110
1111 try
1112 {
1113 StreamingWagon wagon = (StreamingWagon) getWagon();
1114
1115 Properties params = new Properties();
1116 params.put( "http.protocol.expect-continue", "%b,false" );
1117 setHttpConfiguration( wagon, new Properties(), params );
1118 Repository repository = new Repository( "foo", getRepositoryUrl( redirectServer ) );
1119 wagon.connect( repository );
1120
1121 File sourceFile = new File( repositoryDirectory, "/redirectRequest/foo/test-secured-put-resource" );
1122 sourceFile.delete();
1123 assertFalse( sourceFile.exists() );
1124
1125 File tempFile = File.createTempFile( "wagon", "tmp" );
1126 tempFile.deleteOnExit();
1127 String content = "put top secret";
1128 FileUtils.fileWrite( tempFile.getAbsolutePath(), content );
1129
1130 try ( FileInputStream fileInputStream = new FileInputStream( tempFile ) )
1131 {
1132 wagon.putFromStream( fileInputStream, "test-secured-put-resource", content.length(), -1 );
1133
1134 if ( wagon.getClass().getName().contains( "Lightweight" ) )
1135 {
1136 assertTrue( true );
1137 }
1138 else
1139 {
1140 fail();
1141 }
1142 }
1143 catch ( TransferFailedException e )
1144 {
1145 assertTrue( true );
1146 }
1147 finally
1148 {
1149 wagon.disconnect();
1150 tempFile.delete();
1151 }
1152
1153 }
1154 finally
1155 {
1156 redirectServer.stop();
1157 }
1158 }
1159
1160
1161
1162
1163 @SuppressWarnings( "checkstyle:visibilitymodifier" )
1164 public static class RedirectHandler
1165 extends AbstractHandler
1166 {
1167 String reason;
1168
1169 int retCode;
1170
1171 String redirectUrl;
1172
1173 File repositoryDirectory;
1174
1175 public List<HandlerRequestResponse> handlerRequestResponses = new ArrayList<HandlerRequestResponse>();
1176
1177 RedirectHandler( String reason, int retCode, String redirectUrl, File repositoryDirectory )
1178 {
1179 this.reason = reason;
1180 this.retCode = retCode;
1181 this.redirectUrl = redirectUrl;
1182 this.repositoryDirectory = repositoryDirectory;
1183 }
1184
1185 public void handle( String target, Request baseRequest, HttpServletRequest request,
1186 HttpServletResponse response ) throws IOException, ServletException
1187 {
1188 if ( request.getRequestURI().contains( "redirectRequest" ) )
1189 {
1190 PutHandler putHandler = new PutHandler( this.repositoryDirectory );
1191 putHandler.handle( target, baseRequest, request, response );
1192 handlerRequestResponses.add(
1193 new HandlerRequestResponse( request.getMethod(), response.getStatus(),
1194 request.getRequestURI() ) );
1195 return;
1196 }
1197 response.setStatus( this.retCode );
1198 response.setHeader( "Location", this.redirectUrl + request.getRequestURI() );
1199 baseRequest.setHandled( true );
1200
1201 handlerRequestResponses.add(
1202 new HandlerRequestResponse( request.getMethod(), response.getStatus(),
1203 request.getRequestURI() ) );
1204 }
1205
1206
1207 }
1208
1209
1210 private void runTestProxiedRequest( ProxyInfo proxyInfo, TestHeaderHandler handler )
1211 throws Exception
1212 {
1213
1214
1215
1216
1217 Thread.sleep( 5001L );
1218
1219
1220 Server proxyServer = new Server( );
1221 ServerConnector serverConnector =
1222 new ServerConnector( proxyServer, new HttpConnectionFactory( new HttpConfiguration() ) );
1223 proxyServer.addConnector( serverConnector );
1224 proxyServer.setHandler( handler );
1225
1226 proxyServer.start();
1227
1228 proxyInfo.setPort( getLocalPort( proxyServer ) );
1229
1230 System.out.println(
1231 "start proxy on host/port " + proxyInfo.getHost() + "/" + proxyInfo.getPort() + " with non proxyHosts "
1232 + proxyInfo.getNonProxyHosts() );
1233
1234 while ( !proxyServer.isRunning() || !proxyServer.isStarted() )
1235 {
1236 Thread.sleep( 10 );
1237 }
1238
1239 try
1240 {
1241 StreamingWagon wagon = (StreamingWagon) getWagon();
1242
1243 Repository testRepository = new Repository( "id", "http://www.example.com/" );
1244
1245 String localRepositoryPath = FileTestUtils.getTestOutputDir().toString();
1246 File sourceFile = new File( localRepositoryPath, "test-proxied-resource" );
1247 FileUtils.fileWrite( sourceFile.getAbsolutePath(), "content" );
1248
1249 wagon.connect( testRepository, proxyInfo );
1250
1251 try
1252 {
1253 wagon.getToStream( "test-proxied-resource", new ByteArrayOutputStream() );
1254
1255 assertTrue( handler.headers.containsKey( "Proxy-Connection" ) );
1256 }
1257 finally
1258 {
1259 System.setProperty( "http.proxyHost", "" );
1260 System.setProperty( "http.proxyPort", "" );
1261 wagon.disconnect();
1262 }
1263 }
1264 finally
1265 {
1266 proxyServer.stop();
1267 }
1268 }
1269
1270 private void runTestProxiedRequestWithProvider( ProxyInfoProvider proxyInfoProvider, TestHeaderHandler handler )
1271 throws Exception
1272 {
1273
1274
1275
1276
1277 Thread.sleep( 5001L );
1278
1279
1280 Server proxyServer = new Server( );
1281 ServerConnector serverConnector =
1282 new ServerConnector( proxyServer, new HttpConnectionFactory( new HttpConfiguration() ) );
1283 proxyServer.addConnector( serverConnector );
1284
1285 proxyServer.setHandler( handler );
1286
1287 proxyServer.start();
1288
1289 proxyInfoProvider.getProxyInfo( null ).setPort( getLocalPort( proxyServer ) );
1290
1291 System.out.println( "start proxy on host/port " + proxyInfoProvider.getProxyInfo( null ).getHost() + "/"
1292 + proxyInfoProvider.getProxyInfo( null ).getPort() + " with non proxyHosts "
1293 + proxyInfoProvider.getProxyInfo( null ).getNonProxyHosts() );
1294
1295 while ( !proxyServer.isRunning() || !proxyServer.isStarted() )
1296 {
1297 Thread.sleep( 10 );
1298 }
1299
1300 try
1301 {
1302 StreamingWagon wagon = (StreamingWagon) getWagon();
1303
1304 Repository testRepository = new Repository( "id", "http://www.example.com/" );
1305
1306 String localRepositoryPath = FileTestUtils.getTestOutputDir().toString();
1307 File sourceFile = new File( localRepositoryPath, "test-proxied-resource" );
1308 FileUtils.fileWrite( sourceFile.getAbsolutePath(), "content" );
1309
1310 wagon.connect( testRepository, proxyInfoProvider );
1311
1312 try
1313 {
1314 wagon.getToStream( "test-proxied-resource", new ByteArrayOutputStream() );
1315
1316 assertTrue( handler.headers.containsKey( "Proxy-Connection" ) );
1317 }
1318 finally
1319 {
1320 System.setProperty( "http.proxyHost", "" );
1321 System.setProperty( "http.proxyPort", "" );
1322 wagon.disconnect();
1323 }
1324 }
1325 finally
1326 {
1327 proxyServer.stop();
1328 }
1329 }
1330
1331 private ProxyInfo createProxyInfo()
1332 {
1333 ProxyInfo proxyInfo = new ProxyInfo();
1334 proxyInfo.setHost( "localhost" );
1335 proxyInfo.setNonProxyHosts( null );
1336 proxyInfo.setType( "http" );
1337 return proxyInfo;
1338 }
1339
1340 public void testSecuredGetUnauthorized()
1341 throws Exception
1342 {
1343 try
1344 {
1345 runTestSecuredGet( null );
1346 fail();
1347 }
1348 catch ( AuthorizationException e )
1349 {
1350 assertTrue( true );
1351 }
1352 }
1353
1354 public void testSecuredGetWrongPassword()
1355 throws Exception
1356 {
1357 try
1358 {
1359 AuthenticationInfo authInfo = new AuthenticationInfo();
1360 authInfo.setUserName( "user" );
1361 authInfo.setPassword( "admin" );
1362 runTestSecuredGet( authInfo );
1363 fail();
1364 }
1365 catch ( AuthorizationException e )
1366 {
1367 assertTrue( true );
1368 }
1369 }
1370
1371 public void testSecuredGet()
1372 throws Exception
1373 {
1374 AuthenticationInfo authInfo = new AuthenticationInfo();
1375 authInfo.setUserName( "user" );
1376 authInfo.setPassword( "secret" );
1377 runTestSecuredGet( authInfo );
1378 }
1379
1380
1381 public void runTestSecuredGet( AuthenticationInfo authInfo )
1382 throws Exception
1383 {
1384 String localRepositoryPath = FileTestUtils.getTestOutputDir().toString();
1385 Server server = createSecurityServer( localRepositoryPath );
1386
1387 server.start();
1388
1389 try
1390 {
1391 StreamingWagon wagon = (StreamingWagon) getWagon();
1392
1393 Repository testRepository = new Repository( "id", getRepositoryUrl( server ) );
1394
1395 File sourceFile = new File( localRepositoryPath, "test-secured-resource" );
1396 FileUtils.fileWrite( sourceFile.getAbsolutePath(), "top secret" );
1397
1398 wagon.connect( testRepository, authInfo );
1399
1400 File file = File.createTempFile( "wagon-test", "txt" );
1401
1402 try
1403 {
1404 wagon.get( "test-secured-resource", file );
1405 }
1406 finally
1407 {
1408 wagon.disconnect();
1409 }
1410
1411 FileInputStream in = new FileInputStream( file );
1412
1413 assertEquals( "top secret", IOUtil.toString( in ) );
1414
1415
1416
1417
1418
1419
1420
1421
1422 Thread.sleep ( 2000L );
1423
1424
1425 TestSecurityHandler securityHandler = server.getChildHandlerByClass( TestSecurityHandler.class );
1426 testPreemptiveAuthenticationGet( securityHandler, supportPreemptiveAuthenticationGet() );
1427
1428 }
1429 finally
1430 {
1431 server.stop();
1432 }
1433 }
1434
1435
1436 public void testSecuredGetToStream()
1437 throws Exception
1438 {
1439 AuthenticationInfo authInfo = new AuthenticationInfo();
1440 authInfo.setUserName( "user" );
1441 authInfo.setPassword( "secret" );
1442 runTestSecuredGetToStream( authInfo );
1443 }
1444
1445 public void runTestSecuredGetToStream( AuthenticationInfo authInfo )
1446 throws Exception
1447 {
1448 String localRepositoryPath = FileTestUtils.getTestOutputDir().toString();
1449 Server server = createSecurityServer( localRepositoryPath );
1450
1451 server.start();
1452
1453 try
1454 {
1455 StreamingWagon wagon = (StreamingWagon) getWagon();
1456
1457 Repository testRepository = new Repository( "id", getRepositoryUrl( server ) );
1458
1459 File sourceFile = new File( localRepositoryPath, "test-secured-resource" );
1460 FileUtils.fileWrite( sourceFile.getAbsolutePath(), "top secret" );
1461
1462 wagon.connect( testRepository, authInfo );
1463
1464 ByteArrayOutputStream out = new ByteArrayOutputStream();
1465 try
1466 {
1467 wagon.getToStream( "test-secured-resource", out );
1468 }
1469 finally
1470 {
1471 wagon.disconnect();
1472 }
1473
1474 assertEquals( "top secret", out.toString( "US-ASCII" ) );
1475
1476
1477
1478
1479
1480
1481
1482
1483 Thread.sleep ( 2000L );
1484
1485
1486 TestSecurityHandler securityHandler = server.getChildHandlerByClass( TestSecurityHandler.class );
1487 testPreemptiveAuthenticationGet( securityHandler, supportPreemptiveAuthenticationGet() );
1488 }
1489 finally
1490 {
1491 server.stop();
1492 }
1493 }
1494
1495 public void testSecuredResourceExistsUnauthorized()
1496 throws Exception
1497 {
1498 try
1499 {
1500 runTestSecuredResourceExists( null );
1501 fail();
1502 }
1503 catch ( AuthorizationException e )
1504 {
1505 assertTrue( true );
1506 }
1507 }
1508
1509 public void testSecuredResourceExistsWrongPassword()
1510 throws Exception
1511 {
1512 try
1513 {
1514 AuthenticationInfo authInfo = new AuthenticationInfo();
1515 authInfo.setUserName( "user" );
1516 authInfo.setPassword( "admin" );
1517 runTestSecuredResourceExists( authInfo );
1518 }
1519 catch ( AuthorizationException e )
1520 {
1521 assertTrue( true );
1522 }
1523 }
1524
1525 public void testSecuredResourceExists()
1526 throws Exception
1527 {
1528 AuthenticationInfo authInfo = new AuthenticationInfo();
1529 authInfo.setUserName( "user" );
1530 authInfo.setPassword( "secret" );
1531 runTestSecuredResourceExists( authInfo );
1532 }
1533
1534 public void runTestSecuredResourceExists( AuthenticationInfo authInfo )
1535 throws Exception
1536 {
1537 String localRepositoryPath = FileTestUtils.getTestOutputDir().toString();
1538 Server server = createSecurityServer( localRepositoryPath );
1539
1540 server.start();
1541
1542 try
1543 {
1544 StreamingWagon wagon = (StreamingWagon) getWagon();
1545
1546 Repository testRepository = new Repository( "id", getRepositoryUrl( server ) );
1547
1548 File sourceFile = new File( localRepositoryPath, "test-secured-resource-exists" );
1549 FileUtils.fileWrite( sourceFile.getAbsolutePath(), "top secret" );
1550
1551 wagon.connect( testRepository, authInfo );
1552
1553 try
1554 {
1555 assertTrue( wagon.resourceExists( "test-secured-resource-exists" ) );
1556
1557 assertFalse( wagon.resourceExists( "test-secured-resource-not-exists" ) );
1558 }
1559 finally
1560 {
1561 wagon.disconnect();
1562 }
1563 }
1564 finally
1565 {
1566 server.stop();
1567 }
1568 }
1569
1570 private Server createSecurityServer( String localRepositoryPath )
1571 {
1572 Server server = new Server( );
1573
1574 SecurityHandler sh = createSecurityHandler();
1575
1576 ServletContextHandler root = new ServletContextHandler( ServletContextHandler.SESSIONS
1577 | ServletContextHandler.SECURITY );
1578 root.setResourceBase( localRepositoryPath );
1579 root.setSecurityHandler( sh );
1580 ServletHolder servletHolder = new ServletHolder( new DefaultServlet() );
1581 root.addServlet( servletHolder, "/*" );
1582
1583 server.setHandler( root );
1584 addConnector( server );
1585 return server;
1586 }
1587
1588 private Server createStatusServer( int status )
1589 {
1590 Server server = new Server( );
1591 StatusHandler handler = new StatusHandler();
1592 handler.setStatusToReturn( status );
1593 server.setHandler( handler );
1594 addConnector( server );
1595 return server;
1596 }
1597
1598
1599 private String writeTestFile( File parent, String child, String compressionType )
1600 throws IOException
1601 {
1602 File file = new File( parent, child );
1603 file.getParentFile().mkdirs();
1604 file.deleteOnExit();
1605 OutputStream out = new FileOutputStream( file );
1606 try
1607 {
1608 out.write( child.getBytes() );
1609 }
1610 finally
1611 {
1612 out.close();
1613 }
1614
1615 String ext = "";
1616 if ( "gzip".equals( compressionType ) )
1617 {
1618 ext = ".gz";
1619 }
1620 if ( "deflate".equals( compressionType ) )
1621 {
1622 ext = ".deflate";
1623 }
1624
1625 file = new File( parent, child + ext );
1626 file.deleteOnExit();
1627 String content;
1628 out = new FileOutputStream( file );
1629 if ( "gzip".equals( compressionType ) )
1630 {
1631 out = new GZIPOutputStream( out );
1632 }
1633 if ( "deflate".equals( compressionType ) )
1634 {
1635 out = new DeflaterOutputStream( out );
1636 }
1637 try
1638 {
1639
1640
1641 content = file.getAbsolutePath();
1642 out.write( content.getBytes() );
1643 }
1644 finally
1645 {
1646 out.close();
1647 }
1648
1649 return content;
1650 }
1651
1652 public void testPutForbidden()
1653 throws Exception
1654 {
1655 try
1656 {
1657 runTestPut( HttpServletResponse.SC_FORBIDDEN );
1658 fail();
1659 }
1660 catch ( AuthorizationException e )
1661 {
1662 assertTrue( true );
1663 }
1664 }
1665
1666 public void testPut404()
1667 throws Exception
1668 {
1669 try
1670 {
1671 runTestPut( HttpServletResponse.SC_NOT_FOUND );
1672 fail();
1673 }
1674 catch ( ResourceDoesNotExistException e )
1675 {
1676 assertTrue( true );
1677 }
1678 }
1679
1680 public void testPut500()
1681 throws Exception
1682 {
1683 try
1684 {
1685 runTestPut( HttpServletResponse.SC_INTERNAL_SERVER_ERROR );
1686 fail();
1687 }
1688 catch ( TransferFailedException e )
1689 {
1690 assertTrue( true );
1691 }
1692 }
1693
1694 public void testPut429()
1695 throws Exception
1696 {
1697
1698 try
1699 {
1700
1701 StreamingWagon wagon = (StreamingWagon) getWagon();
1702 Server server = new Server( );
1703 final AtomicBoolean called = new AtomicBoolean();
1704
1705 AbstractHandler handler = new AbstractHandler()
1706 {
1707 public void handle( String target, Request baseRequest, HttpServletRequest request,
1708 HttpServletResponse response ) throws IOException, ServletException
1709 {
1710 if ( called.get() )
1711 {
1712 response.setStatus( HttpServletResponse.SC_INTERNAL_SERVER_ERROR );
1713 baseRequest.setHandled( true );
1714 }
1715 else
1716 {
1717 called.set( true );
1718 response.setStatus( SC_TOO_MANY_REQUESTS );
1719 baseRequest.setHandled( true );
1720 }
1721 }
1722 };
1723
1724 server.setHandler( handler );
1725 addConnector( server );
1726 server.start();
1727
1728 wagon.connect( new Repository( "id", getRepositoryUrl( server ) ) );
1729
1730 File tempFile = File.createTempFile( "wagon", "tmp" );
1731 tempFile.deleteOnExit();
1732 FileUtils.fileWrite( tempFile.getAbsolutePath(), "content" );
1733
1734 try
1735 {
1736 wagon.put( tempFile, "resource" );
1737 fail();
1738 }
1739 finally
1740 {
1741 wagon.disconnect();
1742
1743 server.stop();
1744
1745 tempFile.delete();
1746 }
1747
1748 }
1749 catch ( TransferFailedException e )
1750 {
1751 assertTrue( true );
1752 }
1753 }
1754
1755
1756 private void runTestPut( int status )
1757 throws Exception
1758 {
1759 StreamingWagon wagon = (StreamingWagon) getWagon();
1760
1761 Server server = createStatusServer( status );
1762 server.start();
1763
1764 wagon.connect( new Repository( "id", getRepositoryUrl( server ) ) );
1765
1766 File tempFile = File.createTempFile( "wagon", "tmp" );
1767 tempFile.deleteOnExit();
1768 FileUtils.fileWrite( tempFile.getAbsolutePath(), "content" );
1769
1770 String baseUrl = getRepositoryUrl( server );
1771 String resourceName = "resource";
1772 String serverReasonPhrase = HttpStatus.getCode( status ).getMessage();
1773
1774 try
1775 {
1776 wagon.put( tempFile, resourceName );
1777 fail();
1778 }
1779 catch ( Exception e )
1780 {
1781 verifyWagonExceptionMessage( e, status, baseUrl + "/" + resourceName, serverReasonPhrase );
1782 throw e;
1783 }
1784 finally
1785 {
1786 wagon.disconnect();
1787
1788 server.stop();
1789
1790 tempFile.delete();
1791 }
1792 }
1793
1794 public void testSecuredPutUnauthorized()
1795 throws Exception
1796 {
1797 try
1798 {
1799 runTestSecuredPut( null );
1800 fail();
1801 }
1802 catch ( AuthorizationException e )
1803 {
1804 assertTrue( true );
1805 }
1806 }
1807
1808 public void testSecuredPutWrongPassword()
1809 throws Exception
1810 {
1811 try
1812 {
1813 AuthenticationInfo authInfo = new AuthenticationInfo();
1814 authInfo.setUserName( "user" );
1815 authInfo.setPassword( "admin" );
1816 runTestSecuredPut( authInfo );
1817 fail();
1818 }
1819 catch ( AuthorizationException e )
1820 {
1821 assertTrue( true );
1822 }
1823 }
1824
1825 public void testSecuredPut()
1826 throws Exception
1827 {
1828 AuthenticationInfo authInfo = new AuthenticationInfo();
1829 authInfo.setUserName( "user" );
1830 authInfo.setPassword( "secret" );
1831 runTestSecuredPut( authInfo );
1832 }
1833
1834 public void runTestSecuredPut( AuthenticationInfo authInfo )
1835 throws Exception
1836 {
1837 runTestSecuredPut( authInfo, 1 );
1838 }
1839
1840 public void runTestSecuredPut( AuthenticationInfo authInfo, int putNumber )
1841 throws Exception
1842 {
1843 String localRepositoryPath = FileTestUtils.getTestOutputDir().toString();
1844 Server server = new Server( );
1845
1846 TestSecurityHandler sh = createSecurityHandler();
1847
1848 PutHandler putHandler = new PutHandler( new File( localRepositoryPath ) );
1849
1850 sh.setHandler( putHandler );
1851 server.setHandler( sh );
1852 addConnector( server );
1853 server.start();
1854
1855 StreamingWagon wagon = (StreamingWagon) getWagon();
1856 Repository testRepository = new Repository( "id", getRepositoryUrl( server ) );
1857 wagon.connect( testRepository, authInfo );
1858 try
1859 {
1860 for ( int i = 0; i < putNumber; i++ )
1861 {
1862 File sourceFile = new File( localRepositoryPath, "test-secured-put-resource" );
1863 sourceFile.delete();
1864 assertFalse( sourceFile.exists() );
1865
1866 File tempFile = File.createTempFile( "wagon", "tmp" );
1867 tempFile.deleteOnExit();
1868 FileUtils.fileWrite( tempFile.getAbsolutePath(), "put top secret" );
1869
1870 try
1871 {
1872 wagon.put( tempFile, "test-secured-put-resource" );
1873 }
1874 finally
1875 {
1876 tempFile.delete();
1877 }
1878
1879 assertEquals( "put top secret", FileUtils.fileRead( sourceFile.getAbsolutePath() ) );
1880 }
1881 }
1882 finally
1883 {
1884 wagon.disconnect();
1885 server.stop();
1886 }
1887 assertEquals( putNumber, putHandler.putCallNumber );
1888 testPreemptiveAuthenticationPut( sh, supportPreemptiveAuthenticationPut() );
1889 }
1890
1891 public void testNonSecuredPutFromStream()
1892 throws Exception
1893 {
1894 AuthenticationInfo authInfo = new AuthenticationInfo();
1895 authInfo.setUserName( "user" );
1896 authInfo.setPassword( "secret" );
1897 runTestSecuredPutFromStream( authInfo, 1, false );
1898 }
1899
1900 public void testSecuredPutFromStream()
1901 throws Exception
1902 {
1903 AuthenticationInfo authInfo = new AuthenticationInfo();
1904 authInfo.setUserName( "user" );
1905 authInfo.setPassword( "secret" );
1906 runTestSecuredPutFromStream( authInfo, 1, true );
1907 }
1908
1909 public void runTestSecuredPutFromStream( AuthenticationInfo authInfo, int putNumber, boolean addSecurityHandler )
1910 throws Exception
1911 {
1912 String localRepositoryPath = FileTestUtils.getTestOutputDir().toString();
1913 Server server = new Server( );
1914
1915 TestSecurityHandler sh = createSecurityHandler();
1916
1917 PutHandler putHandler = new PutHandler( new File( localRepositoryPath ) );
1918
1919 if ( addSecurityHandler )
1920 {
1921 sh.setHandler( putHandler );
1922 server.setHandler( sh );
1923 }
1924 else
1925 {
1926 server.setHandler( putHandler );
1927 }
1928 addConnector( server );
1929 server.start();
1930
1931 StreamingWagon wagon = (StreamingWagon) getWagon();
1932 Repository testRepository = new Repository( "id", getRepositoryUrl( server ) );
1933 if ( addSecurityHandler )
1934 {
1935 wagon.connect( testRepository, authInfo );
1936 }
1937 else
1938 {
1939 wagon.connect( testRepository );
1940 }
1941 try
1942 {
1943 for ( int i = 0; i < putNumber; i++ )
1944 {
1945 File sourceFile = new File( localRepositoryPath, "test-secured-put-resource" );
1946 sourceFile.delete();
1947 assertFalse( sourceFile.exists() );
1948
1949 File tempFile = File.createTempFile( "wagon", "tmp" );
1950 tempFile.deleteOnExit();
1951 String content = "put top secret";
1952 FileUtils.fileWrite( tempFile.getAbsolutePath(), content );
1953
1954 try ( FileInputStream fileInputStream = new FileInputStream( tempFile ) )
1955 {
1956 wagon.putFromStream( fileInputStream, "test-secured-put-resource", content.length(), -1 );
1957 }
1958 finally
1959 {
1960 tempFile.delete();
1961 }
1962
1963 assertEquals( content, FileUtils.fileRead( sourceFile.getAbsolutePath() ) );
1964 }
1965 }
1966 finally
1967 {
1968 wagon.disconnect();
1969 server.stop();
1970 }
1971 assertEquals( putNumber, putHandler.putCallNumber );
1972 if ( addSecurityHandler )
1973 {
1974 testPreemptiveAuthenticationPut( sh, supportPreemptiveAuthenticationPut() );
1975 }
1976
1977
1978 for ( DeployedResource deployedResource : putHandler.deployedResources )
1979 {
1980 if ( StringUtils.equalsIgnoreCase( "chunked", deployedResource.transferEncoding ) )
1981 {
1982 fail( "deployedResource use chunked: " + deployedResource );
1983 }
1984 }
1985 }
1986
1987
1988 protected abstract boolean supportPreemptiveAuthenticationPut();
1989
1990 protected abstract boolean supportPreemptiveAuthenticationGet();
1991
1992 protected abstract boolean supportProxyPreemptiveAuthentication();
1993
1994 protected void testPreemptiveAuthenticationGet( TestSecurityHandler sh, boolean preemptive )
1995 {
1996 testPreemptiveAuthentication( sh, preemptive, HttpServletResponse.SC_OK );
1997 }
1998
1999 protected void testPreemptiveAuthenticationPut( TestSecurityHandler sh, boolean preemptive )
2000 {
2001 testPreemptiveAuthentication( sh, preemptive, HttpServletResponse.SC_CREATED );
2002 }
2003
2004 protected void testPreemptiveAuthentication( TestSecurityHandler sh, boolean preemptive, int statusCode )
2005 {
2006
2007 if ( preemptive )
2008 {
2009 assertEquals( "not 1 security handler use " + sh.handlerRequestResponses, 1,
2010 sh.handlerRequestResponses.size() );
2011 assertEquals( statusCode, sh.handlerRequestResponses.get( 0 ).responseCode );
2012 }
2013 else
2014 {
2015 assertEquals( "not 2 security handler use " + sh.handlerRequestResponses, 2,
2016 sh.handlerRequestResponses.size() );
2017 assertEquals( HttpServletResponse.SC_UNAUTHORIZED, sh.handlerRequestResponses.get( 0 ).responseCode );
2018 assertEquals( statusCode, sh.handlerRequestResponses.get( 1 ).responseCode );
2019
2020 }
2021 }
2022
2023 static class StatusHandler
2024 extends AbstractHandler
2025 {
2026 private int status;
2027
2028 public void setStatusToReturn( int status )
2029 {
2030 this.status = status;
2031 }
2032
2033 public void handle( String target, Request baseRequest, HttpServletRequest request,
2034 HttpServletResponse response ) throws IOException, ServletException
2035 {
2036 if ( status != 0 )
2037 {
2038 response.setStatus( status );
2039 baseRequest.setHandled( true );
2040 }
2041 }
2042 }
2043
2044 static class DeployedResource
2045 {
2046 String httpMethod;
2047
2048 String requestUri;
2049
2050 String contentLength;
2051
2052 String transferEncoding;
2053
2054 DeployedResource()
2055 {
2056
2057 }
2058
2059 @Override
2060 public String toString()
2061 {
2062 final StringBuilder sb = new StringBuilder();
2063 sb.append( "DeployedResource" );
2064 sb.append( "{httpMethod='" ).append( httpMethod ).append( '\'' );
2065 sb.append( ", requestUri='" ).append( requestUri ).append( '\'' );
2066 sb.append( ", contentLength='" ).append( contentLength ).append( '\'' );
2067 sb.append( ", transferEncoding='" ).append( transferEncoding ).append( '\'' );
2068 sb.append( '}' );
2069 return sb.toString();
2070 }
2071 }
2072
2073
2074
2075
2076 @SuppressWarnings( "checkstyle:visibilitymodifier" )
2077 public static class PutHandler
2078 extends AbstractHandler
2079 {
2080 private final File resourceBase;
2081
2082 public List<DeployedResource> deployedResources = new ArrayList<DeployedResource>();
2083
2084 public int putCallNumber = 0;
2085
2086 public List<HandlerRequestResponse> handlerRequestResponses = new ArrayList<HandlerRequestResponse>();
2087
2088 public PutHandler( File repositoryDirectory )
2089 {
2090 this.resourceBase = repositoryDirectory;
2091 }
2092
2093 public void handle( String target, Request baseRequest, HttpServletRequest request,
2094 HttpServletResponse response ) throws IOException, ServletException
2095 {
2096 if ( baseRequest.isHandled() || !"PUT".equals( baseRequest.getMethod() ) )
2097 {
2098 return;
2099 }
2100
2101 baseRequest.setHandled( true );
2102
2103 File file = new File( resourceBase, URLDecoder.decode( request.getPathInfo() ) );
2104 file.getParentFile().mkdirs();
2105 OutputStream out = null;
2106 InputStream in = null;
2107 try
2108 {
2109 in = request.getInputStream();
2110 out = new FileOutputStream( file );
2111 IOUtil.copy( in, out );
2112 out.close();
2113 out = null;
2114 in.close();
2115 in = null;
2116 }
2117 finally
2118 {
2119 IOUtil.close( in );
2120 IOUtil.close( out );
2121 }
2122 putCallNumber++;
2123 DeployedResource deployedResource = new DeployedResource();
2124
2125 deployedResource.httpMethod = request.getMethod();
2126 deployedResource.requestUri = request.getRequestURI();
2127 deployedResource.transferEncoding = request.getHeader( "Transfer-Encoding" );
2128 deployedResource.contentLength = request.getHeader( "Content-Length" );
2129 deployedResources.add( deployedResource );
2130
2131 response.setStatus( HttpServletResponse.SC_CREATED );
2132
2133 handlerRequestResponses.add(
2134 new HandlerRequestResponse( request.getMethod(), ( (Response) response ).getStatus(),
2135 request.getRequestURI() ) );
2136 }
2137 }
2138
2139 private static class AuthorizingProxyHandler
2140 extends TestHeaderHandler
2141 {
2142
2143 List<HandlerRequestResponse> handlerRequestResponses = new ArrayList<HandlerRequestResponse>();
2144
2145 public void handle( String target, Request baseRequest, HttpServletRequest request,
2146 HttpServletResponse response ) throws IOException, ServletException
2147 {
2148 System.out.println( " handle proxy request" );
2149 if ( request.getHeader( "Proxy-Authorization" ) == null )
2150 {
2151 handlerRequestResponses.add(
2152 new HandlerRequestResponse( request.getMethod(),
2153 HttpServletResponse.SC_PROXY_AUTHENTICATION_REQUIRED,
2154 request.getRequestURI() ) );
2155 response.setStatus( HttpServletResponse.SC_PROXY_AUTHENTICATION_REQUIRED );
2156 response.addHeader( "Proxy-Authenticate", "Basic realm=\"Squid proxy-caching web server\"" );
2157
2158 baseRequest.setHandled( true );
2159 return;
2160 }
2161 handlerRequestResponses.add(
2162 new HandlerRequestResponse( request.getMethod(), HttpServletResponse.SC_OK, request.getRequestURI() ) );
2163 super.handle( target, baseRequest, request, response );
2164 }
2165 }
2166
2167
2168
2169
2170 @SuppressWarnings( "checkstyle:visibilitymodifier" )
2171 private static class TestHeaderHandler
2172 extends AbstractHandler
2173 {
2174 public Map<String, String> headers = Collections.emptyMap();
2175
2176 public List<HandlerRequestResponse> handlerRequestResponses = new ArrayList<HandlerRequestResponse>();
2177
2178 TestHeaderHandler()
2179 {
2180 }
2181
2182 public void handle( String target, Request baseRrequest, HttpServletRequest request,
2183 HttpServletResponse response ) throws IOException, ServletException
2184 {
2185 headers = new HashMap<String, String>();
2186 for ( Enumeration<String> e = baseRrequest.getHeaderNames(); e.hasMoreElements(); )
2187 {
2188 String name = e.nextElement();
2189 Enumeration headerValues = baseRrequest.getHeaders( name );
2190
2191
2192
2193 StringBuffer combinedHeaderValue = new StringBuffer();
2194 for ( int i = 0; headerValues.hasMoreElements(); i++ )
2195 {
2196 if ( i > 0 )
2197 {
2198 combinedHeaderValue.append( "," );
2199 }
2200 combinedHeaderValue.append( headerValues.nextElement() );
2201 }
2202 headers.put( name, combinedHeaderValue.toString() );
2203 }
2204
2205 response.setContentType( "text/plain" );
2206 response.setStatus( HttpServletResponse.SC_OK );
2207 response.getWriter().print( "Hello, World!" );
2208
2209 handlerRequestResponses.add(
2210 new HandlerRequestResponse( baseRrequest.getMethod(), ( (Response) response ).getStatus(),
2211 baseRrequest.getRequestURI() ) );
2212
2213 baseRrequest.setHandled( true );
2214 }
2215
2216 }
2217
2218 protected TestSecurityHandler createSecurityHandler()
2219 {
2220 Constraint constraint = new Constraint();
2221 constraint.setName( Constraint.__BASIC_AUTH );
2222 constraint.setRoles( new String[]{ "admin" } );
2223 constraint.setAuthenticate( true );
2224
2225 ConstraintMapping cm = new ConstraintMapping();
2226 cm.setConstraint( constraint );
2227 cm.setPathSpec( "/*" );
2228
2229 TestSecurityHandler sh = new TestSecurityHandler();
2230 HashLoginService hashLoginService = new HashLoginService( "MyRealm" );
2231 hashLoginService.putUser( "user", new Password( "secret" ), new String[] { "admin" } );
2232 sh.setLoginService( hashLoginService );
2233 sh.setConstraintMappings( new ConstraintMapping[]{ cm } );
2234 sh.setAuthenticator ( new BasicAuthenticator() );
2235 return sh;
2236 }
2237
2238
2239
2240
2241 @SuppressWarnings( "checkstyle:visibilitymodifier" )
2242 public static class TestSecurityHandler
2243 extends ConstraintSecurityHandler
2244 {
2245
2246 public List<HandlerRequestResponse> handlerRequestResponses = new ArrayList<HandlerRequestResponse>();
2247
2248 @Override
2249 public void handle( String target, Request baseRequest, HttpServletRequest request,
2250 HttpServletResponse response ) throws IOException, ServletException
2251 {
2252 String method = request.getMethod();
2253 super.handle( target, baseRequest, request, response );
2254
2255 handlerRequestResponses.add(
2256 new HandlerRequestResponse( method, ( (Response) response ).getStatus(), request.getRequestURI() ) );
2257 }
2258 }
2259
2260
2261
2262
2263 @SuppressWarnings( "checkstyle:visibilitymodifier" )
2264 public static class HandlerRequestResponse
2265 {
2266 public String method;
2267
2268 public int responseCode;
2269
2270 public String requestUri;
2271
2272 private HandlerRequestResponse( String method, int responseCode, String requestUri )
2273 {
2274 this.method = method;
2275 this.responseCode = responseCode;
2276 this.requestUri = requestUri;
2277 }
2278
2279 @Override
2280 public String toString()
2281 {
2282 final StringBuilder sb = new StringBuilder();
2283 sb.append( "HandlerRequestResponse" );
2284 sb.append( "{method='" ).append( method ).append( '\'' );
2285 sb.append( ", responseCode=" ).append( responseCode );
2286 sb.append( ", requestUri='" ).append( requestUri ).append( '\'' );
2287 sb.append( '}' );
2288 return sb.toString();
2289 }
2290 }
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304 protected void verifyWagonExceptionMessage( Exception e, int forStatusCode, String forUrl, String forReasonPhrase )
2305 {
2306
2307 assertNotNull( e );
2308 try
2309 {
2310 assertTrue( "only verify instances of WagonException", e instanceof WagonException );
2311
2312 String reasonPhrase;
2313 String assertMessageForBadMessage = "exception message not described properly";
2314 switch ( forStatusCode )
2315 {
2316 case HttpServletResponse.SC_NOT_FOUND:
2317
2318 assertTrue( "404 not found response should throw ResourceDoesNotExistException",
2319 e instanceof ResourceDoesNotExistException );
2320 reasonPhrase = StringUtils.isEmpty( forReasonPhrase ) ? " Not Found" : ( " " + forReasonPhrase );
2321 assertEquals( assertMessageForBadMessage, "resource missing at " + forUrl + ", status: 404"
2322 + reasonPhrase, e.getMessage() );
2323 break;
2324
2325 case HttpServletResponse.SC_UNAUTHORIZED:
2326
2327 assertTrue( "401 Unauthorized should throw AuthorizationException since "
2328 + " AuthenticationException is not explicitly declared as thrown from wagon "
2329 + "methods",
2330 e instanceof AuthorizationException );
2331 reasonPhrase = StringUtils.isEmpty( forReasonPhrase ) ? " Unauthorized" : ( " " + forReasonPhrase );
2332 assertEquals( assertMessageForBadMessage, "authentication failed for " + forUrl + ", status: 401"
2333 + reasonPhrase, e.getMessage() );
2334 break;
2335
2336 case HttpServletResponse.SC_PROXY_AUTHENTICATION_REQUIRED:
2337 assertTrue( "407 Proxy authentication required should throw AuthorizationException",
2338 e instanceof AuthorizationException );
2339 reasonPhrase = StringUtils.isEmpty( forReasonPhrase ) ? " Proxy Authentication Required"
2340 : ( " " + forReasonPhrase );
2341 assertEquals( assertMessageForBadMessage, "proxy authentication failed for "
2342 + forUrl + ", status: 407" + reasonPhrase, e.getMessage() );
2343 break;
2344
2345 case HttpServletResponse.SC_FORBIDDEN:
2346 assertTrue( "403 Forbidden should throw AuthorizationException",
2347 e instanceof AuthorizationException );
2348 reasonPhrase = StringUtils.isEmpty( forReasonPhrase ) ? " Forbidden" : ( " " + forReasonPhrase );
2349 assertEquals( assertMessageForBadMessage, "authorization failed for " + forUrl + ", status: 403"
2350 + reasonPhrase, e.getMessage() );
2351 break;
2352
2353 default:
2354 assertTrue( "transfer failures should at least be wrapped in a TransferFailedException", e
2355 instanceof TransferFailedException );
2356 assertTrue( "expected status code for transfer failures should be >= 400",
2357 forStatusCode >= HttpServletResponse.SC_BAD_REQUEST );
2358 reasonPhrase = forReasonPhrase == null ? "" : " " + forReasonPhrase;
2359 assertEquals( assertMessageForBadMessage, "transfer failed for " + forUrl + ", status: "
2360 + forStatusCode + reasonPhrase, e.getMessage() );
2361 break;
2362 }
2363 }
2364 catch ( AssertionError assertionError )
2365 {
2366 logger.error( "Exception which failed assertions: ", e );
2367 throw assertionError;
2368 }
2369
2370 }
2371
2372 }