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