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