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.repository.Repository;
32 import org.apache.maven.wagon.resource.Resource;
33 import org.codehaus.plexus.util.FileUtils;
34 import org.codehaus.plexus.util.IOUtil;
35 import org.codehaus.plexus.util.StringOutputStream;
36 import org.codehaus.plexus.util.StringUtils;
37 import org.mortbay.jetty.Handler;
38 import org.mortbay.jetty.HttpConnection;
39 import org.mortbay.jetty.Request;
40 import org.mortbay.jetty.Response;
41 import org.mortbay.jetty.Server;
42 import org.mortbay.jetty.handler.AbstractHandler;
43 import org.mortbay.jetty.handler.HandlerCollection;
44 import org.mortbay.jetty.security.Constraint;
45 import org.mortbay.jetty.security.ConstraintMapping;
46 import org.mortbay.jetty.security.HashUserRealm;
47 import org.mortbay.jetty.security.SecurityHandler;
48 import org.mortbay.jetty.servlet.Context;
49 import org.mortbay.jetty.servlet.DefaultServlet;
50 import org.mortbay.jetty.servlet.ServletHolder;
51
52 import javax.servlet.ServletException;
53 import javax.servlet.ServletInputStream;
54 import javax.servlet.http.HttpServletRequest;
55 import javax.servlet.http.HttpServletResponse;
56 import java.io.File;
57 import java.io.FileInputStream;
58 import java.io.FileOutputStream;
59 import java.io.IOException;
60 import java.io.OutputStream;
61 import java.lang.reflect.Method;
62 import java.net.URLDecoder;
63 import java.util.ArrayList;
64 import java.util.Collections;
65 import java.util.Enumeration;
66 import java.util.HashMap;
67 import java.util.List;
68 import java.util.Map;
69 import java.util.Properties;
70 import java.util.zip.GZIPOutputStream;
71
72
73
74
75 public abstract class HttpWagonTestCase
76 extends StreamingWagonTestCase
77 {
78 private Server server;
79
80 protected void setupWagonTestingFixtures()
81 throws Exception
82 {
83
84
85 File file = FileTestUtils.createUniqueFile( "local-repository", "test-resource" );
86
87 file.delete();
88
89 file.getParentFile().mkdirs();
90
91 File repositoryDirectory = getRepositoryDirectory();
92 FileUtils.deleteDirectory( repositoryDirectory );
93 repositoryDirectory.mkdirs();
94
95 server = new Server( 0 );
96
97 PutHandler putHandler = new PutHandler( repositoryDirectory );
98 server.addHandler( putHandler );
99
100 createContext( server, repositoryDirectory );
101
102 addConnectors( server );
103
104 server.start();
105
106 testRepository.setUrl( getTestRepositoryUrl() );
107 }
108
109 @Override
110 protected final int getTestRepositoryPort()
111 {
112 if ( server == null )
113 {
114 return 0;
115 }
116 return server.getConnectors()[0].getLocalPort();
117 }
118
119 protected void createContext( Server server, File repositoryDirectory )
120 throws IOException
121 {
122 Context root = new Context( server, "/", Context.SESSIONS );
123 root.setResourceBase( repositoryDirectory.getAbsolutePath() );
124 ServletHolder servletHolder = new ServletHolder( new DefaultServlet() );
125 root.addServlet( servletHolder, "/*" );
126 }
127
128 protected void tearDownWagonTestingFixtures()
129 throws Exception
130 {
131 server.stop();
132 }
133
134 public void testWagonGetFileList()
135 throws Exception
136 {
137 File dir = getRepositoryDirectory();
138 FileUtils.deleteDirectory( dir );
139
140 File f = new File( dir, "file-list" );
141 f.mkdirs();
142
143 super.testWagonGetFileList();
144 }
145
146 public void testHttpHeaders()
147 throws Exception
148 {
149 Properties properties = new Properties();
150 properties.setProperty( "User-Agent", "Maven-Wagon/1.0" );
151
152 StreamingWagon wagon = (StreamingWagon) getWagon();
153
154 setHttpHeaders( wagon, properties );
155
156 Server server = new Server( 0 );
157 TestHeaderHandler handler = new TestHeaderHandler();
158 server.setHandler( handler );
159 addConnectors( server );
160 server.start();
161
162 wagon.connect(
163 new Repository( "id", getProtocol() + "://localhost:" + server.getConnectors()[0].getLocalPort() ) );
164
165 wagon.getToStream( "resource", new StringOutputStream() );
166
167 wagon.disconnect();
168
169 server.stop();
170
171 assertEquals( "Maven-Wagon/1.0", handler.headers.get( "User-Agent" ) );
172 }
173
174
175
176
177 public void testHttpHeadersWithCommonMethods()
178 throws Exception
179 {
180 Properties properties = new Properties();
181 properties.setProperty( "User-Agent", "Maven-Wagon/1.0" );
182
183 StreamingWagon wagon = (StreamingWagon) getWagon();
184
185 Method setHttpHeaders = wagon.getClass().getMethod( "setHttpHeaders", Properties.class );
186 setHttpHeaders.invoke( wagon, properties );
187
188 Server server = new Server( 0 );
189 TestHeaderHandler handler = new TestHeaderHandler();
190 server.setHandler( handler );
191 addConnectors( server );
192 server.start();
193
194 wagon.connect(
195 new Repository( "id", getProtocol() + "://localhost:" + server.getConnectors()[0].getLocalPort() ) );
196
197 wagon.getToStream( "resource", new StringOutputStream() );
198
199 wagon.disconnect();
200
201 server.stop();
202
203 assertEquals( "Maven-Wagon/1.0", handler.headers.get( "User-Agent" ) );
204 }
205
206 protected abstract void setHttpHeaders( StreamingWagon wagon, Properties properties );
207
208 protected void addConnectors( Server server )
209 {
210 }
211
212 protected String getRepositoryUrl( Server server )
213 {
214 int localPort = server.getConnectors()[0].getLocalPort();
215 return getProtocol() + "://localhost:" + localPort;
216 }
217
218 public void testGetForbidden()
219 throws Exception
220 {
221 try
222 {
223 runTestGet( HttpServletResponse.SC_FORBIDDEN );
224 fail();
225 }
226 catch ( AuthorizationException e )
227 {
228 assertTrue( true );
229 }
230 }
231
232 public void testGet404()
233 throws Exception
234 {
235 try
236 {
237 runTestGet( HttpServletResponse.SC_NOT_FOUND );
238 fail();
239 }
240 catch ( ResourceDoesNotExistException e )
241 {
242 assertTrue( true );
243 }
244 }
245
246 public void testGet500()
247 throws Exception
248 {
249 try
250 {
251 runTestGet( HttpServletResponse.SC_INTERNAL_SERVER_ERROR );
252 fail();
253 }
254 catch ( TransferFailedException e )
255 {
256 assertTrue( true );
257 }
258 }
259
260 private void runTestGet( int status )
261 throws Exception
262 {
263 StreamingWagon wagon = (StreamingWagon) getWagon();
264
265 Server server = new Server( 0 );
266 StatusHandler handler = new StatusHandler();
267 handler.setStatusToReturn( status );
268 server.setHandler( handler );
269 addConnectors( server );
270 server.start();
271
272 wagon.connect( new Repository( "id", getRepositoryUrl( server ) ) );
273
274 try
275 {
276 wagon.getToStream( "resource", new StringOutputStream() );
277 fail();
278 }
279 finally
280 {
281 wagon.disconnect();
282
283 server.stop();
284 }
285 }
286
287 public void testResourceExistsForbidden()
288 throws Exception
289 {
290 try
291 {
292 runTestResourceExists( HttpServletResponse.SC_FORBIDDEN );
293 fail();
294 }
295 catch ( AuthorizationException e )
296 {
297 assertTrue( true );
298 }
299 }
300
301 public void testResourceExists404()
302 throws Exception
303 {
304 try
305 {
306 assertFalse( runTestResourceExists( HttpServletResponse.SC_NOT_FOUND ) );
307 }
308 catch ( ResourceDoesNotExistException e )
309 {
310 assertTrue( true );
311 }
312 }
313
314 public void testResourceExists500()
315 throws Exception
316 {
317 try
318 {
319 runTestResourceExists( HttpServletResponse.SC_INTERNAL_SERVER_ERROR );
320 fail();
321 }
322 catch ( TransferFailedException e )
323 {
324 assertTrue( true );
325 }
326 }
327
328 private boolean runTestResourceExists( int status )
329 throws Exception
330 {
331 StreamingWagon wagon = (StreamingWagon) getWagon();
332
333 Server server = new Server( 0 );
334 StatusHandler handler = new StatusHandler();
335 handler.setStatusToReturn( status );
336 server.setHandler( handler );
337 addConnectors( server );
338 server.start();
339
340 wagon.connect( new Repository( "id", getRepositoryUrl( server ) ) );
341
342 try
343 {
344 return wagon.resourceExists( "resource" );
345 }
346 finally
347 {
348 wagon.disconnect();
349
350 server.stop();
351 }
352 }
353
354 protected long getExpectedLastModifiedOnGet( Repository repository, Resource resource )
355 {
356 File file = new File( getRepositoryDirectory(), resource.getName() );
357 return ( file.lastModified() / 1000 ) * 1000;
358 }
359
360 protected File getRepositoryDirectory()
361 {
362 return getTestFile( "target/test-output/http-repository" );
363 }
364
365 public void testGzipGet()
366 throws Exception
367 {
368 Server server = new Server( getTestRepositoryPort() );
369
370 String localRepositoryPath = FileTestUtils.getTestOutputDir().toString();
371 Context root = new Context( server, "/", Context.SESSIONS );
372 root.setResourceBase( localRepositoryPath );
373 ServletHolder servletHolder = new ServletHolder( new DefaultServlet() );
374 servletHolder.setInitParameter( "gzip", "true" );
375 root.addServlet( servletHolder, "/*" );
376 addConnectors( server );
377 server.start();
378
379 try
380 {
381 Wagon wagon = getWagon();
382
383 Repository testRepository = new Repository( "id", getRepositoryUrl( server ) );
384
385 File sourceFile = new File( localRepositoryPath + "/gzip" );
386
387 sourceFile.deleteOnExit();
388
389 String resName = "gzip-res.txt";
390 String sourceContent = writeTestFileGzip( sourceFile, resName );
391
392 wagon.connect( testRepository );
393
394 File destFile = FileTestUtils.createUniqueFile( getName(), getName() );
395
396 destFile.deleteOnExit();
397
398 wagon.get( "gzip/" + resName, destFile );
399
400 wagon.disconnect();
401
402 String destContent = FileUtils.fileRead( destFile );
403
404 assertEquals( sourceContent, destContent );
405 }
406 finally
407 {
408 server.stop();
409 }
410 }
411
412 public void testProxiedRequest()
413 throws Exception
414 {
415 ProxyInfo proxyInfo = createProxyInfo();
416 TestHeaderHandler handler = new TestHeaderHandler();
417
418 runTestProxiedRequest( proxyInfo, handler );
419 }
420
421 public void testProxiedRequestWithAuthentication()
422 throws Exception
423 {
424 ProxyInfo proxyInfo = createProxyInfo();
425 proxyInfo.setUserName( "user" );
426 proxyInfo.setPassword( "secret" );
427 AuthorizingProxyHandler handler = new AuthorizingProxyHandler();
428
429 runTestProxiedRequest( proxyInfo, handler );
430
431 assertTrue( handler.headers.containsKey( "Proxy-Authorization" ) );
432
433 if ( supportProxyPreemptiveAuthentication() )
434 {
435 assertEquals( 200, handler.securityHandlerRequestReponses.get( 0 ).responseCode );
436 }
437 else
438 {
439 assertEquals( 407, handler.securityHandlerRequestReponses.get( 0 ).responseCode );
440 assertEquals( 200, handler.securityHandlerRequestReponses.get( 1 ).responseCode );
441 }
442
443 }
444
445 private void runTestProxiedRequest( ProxyInfo proxyInfo, TestHeaderHandler handler )
446 throws Exception
447 {
448
449
450
451 Thread.sleep( 5001L );
452
453 Server proxyServer = new Server( 0 );
454
455 proxyServer.setHandler( handler );
456
457 proxyServer.start();
458
459 proxyInfo.setPort( proxyServer.getConnectors()[0].getLocalPort() );
460
461 System.out.println(
462 "start proxy on host/port " + proxyInfo.getHost() + "/" + proxyInfo.getPort() + " with non proxyHosts "
463 + proxyInfo.getNonProxyHosts() );
464
465 while ( !proxyServer.isRunning() || !proxyServer.isStarted() )
466 {
467 Thread.sleep( 10 );
468 }
469
470 try
471 {
472 StreamingWagon wagon = (StreamingWagon) getWagon();
473
474 System.out.println( " wagon hashCode " + wagon.hashCode() );
475
476 Repository testRepository = new Repository( "id", "http://www.example.com/" );
477
478 String localRepositoryPath = FileTestUtils.getTestOutputDir().toString();
479 File sourceFile = new File( localRepositoryPath, "test-proxied-resource" );
480 FileUtils.fileWrite( sourceFile.getAbsolutePath(), "content" );
481
482 wagon.connect( testRepository, proxyInfo );
483
484 StringOutputStream out = new StringOutputStream();
485 try
486 {
487 wagon.getToStream( "test-proxied-resource", out );
488
489 assertTrue( handler.headers.containsKey( "Proxy-Connection" ) );
490 }
491 finally
492 {
493 System.setProperty( "http.proxyHost", "" );
494 System.setProperty( "http.proxyPort", "" );
495 wagon.disconnect();
496 }
497 }
498 finally
499 {
500 proxyServer.stop();
501 }
502 }
503
504 private ProxyInfo createProxyInfo()
505 {
506 ProxyInfo proxyInfo = new ProxyInfo();
507 proxyInfo.setHost( "localhost" );
508 proxyInfo.setNonProxyHosts( null );
509 proxyInfo.setType( "http" );
510 return proxyInfo;
511 }
512
513 public void testSecuredGetUnauthorized()
514 throws Exception
515 {
516 try
517 {
518 runTestSecuredGet( null );
519 fail();
520 }
521 catch ( AuthorizationException e )
522 {
523 assertTrue( true );
524 }
525 }
526
527 public void testSecuredGetWrongPassword()
528 throws Exception
529 {
530 try
531 {
532 AuthenticationInfo authInfo = new AuthenticationInfo();
533 authInfo.setUserName( "user" );
534 authInfo.setPassword( "admin" );
535 runTestSecuredGet( authInfo );
536 fail();
537 }
538 catch ( AuthorizationException e )
539 {
540 assertTrue( true );
541 }
542 }
543
544 public void testSecuredGet()
545 throws Exception
546 {
547 AuthenticationInfo authInfo = new AuthenticationInfo();
548 authInfo.setUserName( "user" );
549 authInfo.setPassword( "secret" );
550 runTestSecuredGet( authInfo );
551 }
552
553 public void runTestSecuredGet( AuthenticationInfo authInfo )
554 throws Exception
555 {
556 String localRepositoryPath = FileTestUtils.getTestOutputDir().toString();
557 Server server = createSecurityServer( localRepositoryPath );
558 server.start();
559
560 try
561 {
562 StreamingWagon wagon = (StreamingWagon) getWagon();
563
564 Repository testRepository = new Repository( "id", getRepositoryUrl( server ) );
565
566 File sourceFile = new File( localRepositoryPath, "test-secured-resource" );
567 FileUtils.fileWrite( sourceFile.getAbsolutePath(), "top secret" );
568
569 wagon.connect( testRepository, authInfo );
570
571 StringOutputStream out = new StringOutputStream();
572 try
573 {
574 wagon.getToStream( "test-secured-resource", out );
575 }
576 finally
577 {
578 wagon.disconnect();
579 }
580
581 assertEquals( "top secret", out.toString() );
582 }
583 finally
584 {
585 server.stop();
586 }
587 }
588
589 public void testSecuredResourceExistsUnauthorized()
590 throws Exception
591 {
592 try
593 {
594 runTestSecuredResourceExists( null );
595 fail();
596 }
597 catch ( AuthorizationException e )
598 {
599 assertTrue( true );
600 }
601 }
602
603 public void testSecuredResourceExistsWrongPassword()
604 throws Exception
605 {
606 try
607 {
608 AuthenticationInfo authInfo = new AuthenticationInfo();
609 authInfo.setUserName( "user" );
610 authInfo.setPassword( "admin" );
611 runTestSecuredResourceExists( authInfo );
612 }
613 catch ( AuthorizationException e )
614 {
615 assertTrue( true );
616 }
617 }
618
619 public void testSecuredResourceExists()
620 throws Exception
621 {
622 AuthenticationInfo authInfo = new AuthenticationInfo();
623 authInfo.setUserName( "user" );
624 authInfo.setPassword( "secret" );
625 runTestSecuredResourceExists( authInfo );
626 }
627
628 public void runTestSecuredResourceExists( AuthenticationInfo authInfo )
629 throws Exception
630 {
631 String localRepositoryPath = FileTestUtils.getTestOutputDir().toString();
632 Server server = createSecurityServer( localRepositoryPath );
633 server.start();
634
635 try
636 {
637 StreamingWagon wagon = (StreamingWagon) getWagon();
638
639 Repository testRepository = new Repository( "id", getRepositoryUrl( server ) );
640
641 File sourceFile = new File( localRepositoryPath, "test-secured-resource-exists" );
642 FileUtils.fileWrite( sourceFile.getAbsolutePath(), "top secret" );
643
644 wagon.connect( testRepository, authInfo );
645
646 try
647 {
648 assertTrue( wagon.resourceExists( "test-secured-resource-exists" ) );
649
650 assertFalse( wagon.resourceExists( "test-secured-resource-not-exists" ) );
651 }
652 finally
653 {
654 wagon.disconnect();
655 }
656 }
657 finally
658 {
659 server.stop();
660 }
661 }
662
663 private Server createSecurityServer( String localRepositoryPath )
664 {
665 Server server = new Server( 0 );
666
667 SecurityHandler sh = createSecurityHandler();
668
669 Context root = new Context( Context.SESSIONS );
670 root.setContextPath( "/" );
671 root.addHandler( sh );
672 root.setResourceBase( localRepositoryPath );
673 ServletHolder servletHolder = new ServletHolder( new DefaultServlet() );
674 root.addServlet( servletHolder, "/*" );
675
676 server.setHandler( root );
677 addConnectors( server );
678 return server;
679 }
680
681
682 private String writeTestFileGzip( File parent, String child )
683 throws IOException
684 {
685 File file = new File( parent, child );
686 file.getParentFile().mkdirs();
687 file.deleteOnExit();
688 OutputStream out = new FileOutputStream( file );
689 try
690 {
691 out.write( child.getBytes() );
692 }
693 finally
694 {
695 out.close();
696 }
697
698 file = new File( parent, child + ".gz" );
699 file.deleteOnExit();
700 String content;
701 out = new FileOutputStream( file );
702 out = new GZIPOutputStream( out );
703 try
704 {
705
706
707 content = file.getAbsolutePath();
708 out.write( content.getBytes() );
709 }
710 finally
711 {
712 out.close();
713 }
714
715 return content;
716 }
717
718 public void testPutForbidden()
719 throws Exception
720 {
721 try
722 {
723 runTestPut( HttpServletResponse.SC_FORBIDDEN );
724 fail();
725 }
726 catch ( AuthorizationException e )
727 {
728 assertTrue( true );
729 }
730 }
731
732 public void testPut404()
733 throws Exception
734 {
735 try
736 {
737 runTestPut( HttpServletResponse.SC_NOT_FOUND );
738 fail();
739 }
740 catch ( ResourceDoesNotExistException e )
741 {
742 assertTrue( true );
743 }
744 }
745
746 public void testPut500()
747 throws Exception
748 {
749 try
750 {
751 runTestPut( HttpServletResponse.SC_INTERNAL_SERVER_ERROR );
752 fail();
753 }
754 catch ( TransferFailedException e )
755 {
756 assertTrue( true );
757 }
758 }
759
760 private void runTestPut( int status )
761 throws Exception
762 {
763 StreamingWagon wagon = (StreamingWagon) getWagon();
764
765 Server server = new Server( 0 );
766 StatusHandler handler = new StatusHandler();
767 handler.setStatusToReturn( status );
768 server.setHandler( handler );
769 addConnectors( server );
770 server.start();
771
772 wagon.connect( new Repository( "id", getRepositoryUrl( server ) ) );
773
774 File tempFile = File.createTempFile( "wagon", "tmp" );
775 tempFile.deleteOnExit();
776 FileUtils.fileWrite( tempFile.getAbsolutePath(), "content" );
777
778 try
779 {
780 wagon.put( tempFile, "resource" );
781 fail();
782 }
783 finally
784 {
785 wagon.disconnect();
786
787 server.stop();
788
789 tempFile.delete();
790 }
791 }
792
793 public void testSecuredPutUnauthorized()
794 throws Exception
795 {
796 try
797 {
798 runTestSecuredPut( null );
799 fail();
800 }
801 catch ( TransferFailedException e )
802 {
803 assertTrue( true );
804 }
805 }
806
807 public void testSecuredPutWrongPassword()
808 throws Exception
809 {
810 try
811 {
812 AuthenticationInfo authInfo = new AuthenticationInfo();
813 authInfo.setUserName( "user" );
814 authInfo.setPassword( "admin" );
815 runTestSecuredPut( authInfo );
816 fail();
817 }
818 catch ( TransferFailedException e )
819 {
820 assertTrue( true );
821 }
822 }
823
824 public void testSecuredPut()
825 throws Exception
826 {
827 AuthenticationInfo authInfo = new AuthenticationInfo();
828 authInfo.setUserName( "user" );
829 authInfo.setPassword( "secret" );
830 runTestSecuredPut( authInfo );
831 }
832
833 public void runTestSecuredPut( AuthenticationInfo authInfo )
834 throws Exception
835 {
836 runTestSecuredPut( authInfo, 1 );
837 }
838
839 public void runTestSecuredPut( AuthenticationInfo authInfo, int putNumber )
840 throws Exception
841 {
842 String localRepositoryPath = FileTestUtils.getTestOutputDir().toString();
843 Server server = new Server( 0 );
844
845 TestSecurityHandler sh = createSecurityHandler();
846
847 PutHandler putHandler = new PutHandler( new File( localRepositoryPath ) );
848
849 HandlerCollection handlers = new HandlerCollection();
850 handlers.setHandlers( new Handler[]{ sh, putHandler } );
851
852 server.setHandler( handlers );
853 addConnectors( server );
854 server.start();
855
856 StreamingWagon wagon = (StreamingWagon) getWagon();
857 Repository testRepository = new Repository( "id", getRepositoryUrl( server ) );
858 wagon.connect( testRepository, authInfo );
859 try
860 {
861 for ( int i = 0; i < putNumber; i++ )
862 {
863 File sourceFile = new File( localRepositoryPath, "test-secured-put-resource" );
864 sourceFile.delete();
865 assertFalse( sourceFile.exists() );
866
867 File tempFile = File.createTempFile( "wagon", "tmp" );
868 tempFile.deleteOnExit();
869 FileUtils.fileWrite( tempFile.getAbsolutePath(), "put top secret" );
870
871 try
872 {
873 wagon.put( tempFile, "test-secured-put-resource" );
874 }
875 finally
876 {
877 tempFile.delete();
878 }
879
880 assertEquals( "put top secret", FileUtils.fileRead( sourceFile.getAbsolutePath() ) );
881 }
882 }
883 finally
884 {
885 wagon.disconnect();
886 server.stop();
887 }
888 assertEquals( putNumber, putHandler.putCallNumber );
889 testPreemptiveAuthentication( sh );
890 }
891
892 public void testNonSecuredPutFromStream()
893 throws Exception
894 {
895 AuthenticationInfo authInfo = new AuthenticationInfo();
896 authInfo.setUserName( "user" );
897 authInfo.setPassword( "secret" );
898 runTestSecuredPutFromStream( authInfo, 1, false );
899 }
900
901 public void testSecuredPutFromStream()
902 throws Exception
903 {
904 AuthenticationInfo authInfo = new AuthenticationInfo();
905 authInfo.setUserName( "user" );
906 authInfo.setPassword( "secret" );
907 runTestSecuredPutFromStream( authInfo, 1, true );
908 }
909
910 public void runTestSecuredPutFromStream( AuthenticationInfo authInfo, int putNumber, boolean addSecurityHandler )
911 throws Exception
912 {
913 String localRepositoryPath = FileTestUtils.getTestOutputDir().toString();
914 Server server = new Server( 0 );
915
916 TestSecurityHandler sh = createSecurityHandler();
917
918 PutHandler putHandler = new PutHandler( new File( localRepositoryPath ) );
919
920 HandlerCollection handlers = new HandlerCollection();
921 handlers.setHandlers( addSecurityHandler ? new Handler[]{ sh, putHandler } : new Handler[]{ putHandler } );
922
923 server.setHandler( handlers );
924 addConnectors( server );
925 server.start();
926
927 StreamingWagon wagon = (StreamingWagon) getWagon();
928 Repository testRepository = new Repository( "id", getRepositoryUrl( server ) );
929 if ( addSecurityHandler )
930 {
931 wagon.connect( testRepository, authInfo );
932 }
933 else
934 {
935 wagon.connect( testRepository );
936 }
937 try
938 {
939 for ( int i = 0; i < putNumber; i++ )
940 {
941 File sourceFile = new File( localRepositoryPath, "test-secured-put-resource" );
942 sourceFile.delete();
943 assertFalse( sourceFile.exists() );
944
945 File tempFile = File.createTempFile( "wagon", "tmp" );
946 tempFile.deleteOnExit();
947 String content = "put top secret";
948 FileUtils.fileWrite( tempFile.getAbsolutePath(), content );
949
950 FileInputStream fileInputStream = new FileInputStream( tempFile );
951 try
952 {
953 wagon.putFromStream( fileInputStream, "test-secured-put-resource", content.length(), -1 );
954 }
955 finally
956 {
957 fileInputStream.close();
958 tempFile.delete();
959
960 }
961
962 assertEquals( content, FileUtils.fileRead( sourceFile.getAbsolutePath() ) );
963 }
964 }
965 finally
966 {
967 wagon.disconnect();
968 server.stop();
969 }
970 assertEquals( putNumber, putHandler.putCallNumber );
971 if ( addSecurityHandler )
972 {
973 testPreemptiveAuthentication( sh );
974 }
975
976
977 for ( DeployedResource deployedResource : putHandler.deployedResources )
978 {
979 if ( StringUtils.equalsIgnoreCase( "chunked", deployedResource.transferEncoding ) )
980 {
981 fail( "deployedResource use chunked: " + deployedResource );
982 }
983 }
984 }
985
986
987 protected abstract boolean supportPreemptiveAuthentication();
988
989 protected boolean supportProxyPreemptiveAuthentication()
990 {
991 return false;
992 }
993
994 protected void testPreemptiveAuthentication( TestSecurityHandler sh )
995 {
996
997 if ( supportPreemptiveAuthentication() )
998 {
999 assertEquals( "not 1 security handler use " + sh.securityHandlerRequestReponses, 1,
1000 sh.securityHandlerRequestReponses.size() );
1001 assertEquals( 200, sh.securityHandlerRequestReponses.get( 0 ).responseCode );
1002 }
1003 else
1004 {
1005 assertEquals( "not 2 security handler use " + sh.securityHandlerRequestReponses, 2,
1006 sh.securityHandlerRequestReponses.size() );
1007 assertEquals( 401, sh.securityHandlerRequestReponses.get( 0 ).responseCode );
1008 assertEquals( 200, sh.securityHandlerRequestReponses.get( 1 ).responseCode );
1009
1010 }
1011 }
1012
1013 static class StatusHandler
1014 extends AbstractHandler
1015 {
1016 private int status;
1017
1018 public void setStatusToReturn( int status )
1019 {
1020 this.status = status;
1021 }
1022
1023 public void handle( String target, HttpServletRequest request, HttpServletResponse response, int dispatch )
1024 throws IOException, ServletException
1025 {
1026 if ( status != 0 )
1027 {
1028 response.setStatus( status );
1029 ( (Request) request ).setHandled( true );
1030 }
1031 }
1032 }
1033
1034 static class DeployedResource
1035 {
1036 String httpMethod;
1037
1038 String requestUri;
1039
1040 String contentLength;
1041
1042 String transferEncoding;
1043
1044 public DeployedResource()
1045 {
1046
1047 }
1048
1049 @Override
1050 public String toString()
1051 {
1052 final StringBuilder sb = new StringBuilder();
1053 sb.append( "DeployedResource" );
1054 sb.append( "{httpMethod='" ).append( httpMethod ).append( '\'' );
1055 sb.append( ", requestUri='" ).append( requestUri ).append( '\'' );
1056 sb.append( ", contentLength='" ).append( contentLength ).append( '\'' );
1057 sb.append( ", transferEncoding='" ).append( transferEncoding ).append( '\'' );
1058 sb.append( '}' );
1059 return sb.toString();
1060 }
1061 }
1062
1063 static class PutHandler
1064 extends AbstractHandler
1065 {
1066 private final File resourceBase;
1067
1068 public List<DeployedResource> deployedResources = new ArrayList<DeployedResource>();
1069
1070 public int putCallNumber = 0;
1071
1072 public PutHandler( File repositoryDirectory )
1073 {
1074 this.resourceBase = repositoryDirectory;
1075 }
1076
1077 public void handle( String target, HttpServletRequest request, HttpServletResponse response, int dispatch )
1078 throws IOException, ServletException
1079 {
1080 Request base_request =
1081 request instanceof Request ? (Request) request : HttpConnection.getCurrentConnection().getRequest();
1082
1083 if ( base_request.isHandled() || !"PUT".equals( base_request.getMethod() ) )
1084 {
1085 return;
1086 }
1087
1088 base_request.setHandled( true );
1089
1090 File file = new File( resourceBase, URLDecoder.decode( request.getPathInfo() ) );
1091 file.getParentFile().mkdirs();
1092 FileOutputStream out = new FileOutputStream( file );
1093 ServletInputStream in = request.getInputStream();
1094 try
1095 {
1096 IOUtil.copy( in, out );
1097 }
1098 finally
1099 {
1100 in.close();
1101 out.close();
1102 }
1103 System.out.println( "put file " + request.getPathInfo() );
1104 putCallNumber++;
1105 DeployedResource deployedResource = new DeployedResource();
1106
1107 deployedResource.httpMethod = request.getMethod();
1108 deployedResource.requestUri = request.getRequestURI();
1109 deployedResource.transferEncoding = request.getHeader( "Transfer-Encoding" );
1110 deployedResource.contentLength = request.getHeader( "Content-Length" );
1111 deployedResources.add( deployedResource );
1112
1113 response.setStatus( HttpServletResponse.SC_CREATED );
1114 }
1115 }
1116
1117 private static class AuthorizingProxyHandler
1118 extends TestHeaderHandler
1119 {
1120
1121 List<SecurityHandlerRequestReponse> securityHandlerRequestReponses =
1122 new ArrayList<SecurityHandlerRequestReponse>();
1123
1124 public void handle( String target, HttpServletRequest request, HttpServletResponse response, int dispatch )
1125 throws IOException, ServletException
1126 {
1127 System.out.println( " handle proxy request" );
1128 if ( request.getHeader( "Proxy-Authorization" ) == null )
1129 {
1130 securityHandlerRequestReponses.add( new SecurityHandlerRequestReponse( request.getMethod(), 407 ) );
1131 response.setStatus( 407 );
1132 response.addHeader( "Proxy-Authenticate", "Basic realm=\"Squid proxy-caching web server\"" );
1133
1134 ( (Request) request ).setHandled( true );
1135 return;
1136 }
1137 securityHandlerRequestReponses.add( new SecurityHandlerRequestReponse( request.getMethod(), 200 ) );
1138 super.handle( target, request, response, dispatch );
1139 }
1140 }
1141
1142 private static class TestHeaderHandler
1143 extends AbstractHandler
1144 {
1145 public Map headers = Collections.EMPTY_MAP;
1146
1147 public TestHeaderHandler()
1148 {
1149 }
1150
1151 public void handle( String target, HttpServletRequest request, HttpServletResponse response, int dispatch )
1152 throws IOException, ServletException
1153 {
1154 headers = new HashMap();
1155 for ( Enumeration e = request.getHeaderNames(); e.hasMoreElements(); )
1156 {
1157 String name = (String) e.nextElement();
1158 headers.put( name, request.getHeader( name ) );
1159 }
1160
1161 response.setContentType( "text/plain" );
1162 response.setStatus( HttpServletResponse.SC_OK );
1163 response.getWriter().println( "Hello, World!" );
1164
1165 ( (Request) request ).setHandled( true );
1166 }
1167
1168 }
1169
1170 protected TestSecurityHandler createSecurityHandler()
1171 {
1172 Constraint constraint = new Constraint();
1173 constraint.setName( Constraint.__BASIC_AUTH );
1174 constraint.setRoles( new String[]{ "admin" } );
1175 constraint.setAuthenticate( true );
1176
1177 ConstraintMapping cm = new ConstraintMapping();
1178 cm.setConstraint( constraint );
1179 cm.setPathSpec( "/*" );
1180
1181 TestSecurityHandler sh = new TestSecurityHandler();
1182 HashUserRealm hashUserRealm = new HashUserRealm( "MyRealm" );
1183 hashUserRealm.put( "user", "secret" );
1184 hashUserRealm.addUserToRole( "user", "admin" );
1185 sh.setUserRealm( hashUserRealm );
1186 sh.setConstraintMappings( new ConstraintMapping[]{ cm } );
1187 return sh;
1188 }
1189
1190 public static class TestSecurityHandler
1191 extends SecurityHandler
1192 {
1193
1194 public List<SecurityHandlerRequestReponse> securityHandlerRequestReponses =
1195 new ArrayList<SecurityHandlerRequestReponse>();
1196
1197 @Override
1198 public void handle( String target, HttpServletRequest request, HttpServletResponse response, int dispatch )
1199 throws IOException, ServletException
1200 {
1201 String method = request.getMethod();
1202 super.handle( target, request, response, dispatch );
1203 System.out.println( "method in SecurityHandler: " + method );
1204
1205 securityHandlerRequestReponses.add(
1206 new SecurityHandlerRequestReponse( method, ( (Response) response ).getStatus() ) );
1207 }
1208
1209 }
1210
1211 public static class SecurityHandlerRequestReponse
1212 {
1213 public String method;
1214
1215 public int responseCode;
1216
1217 private SecurityHandlerRequestReponse( String method, int responseCode )
1218 {
1219 this.method = method;
1220 this.responseCode = responseCode;
1221 }
1222
1223 @Override
1224 public String toString()
1225 {
1226 final StringBuilder sb = new StringBuilder();
1227 sb.append( "SecurityHandlerRequestReponse" );
1228 sb.append( "{method='" ).append( method ).append( '\'' );
1229 sb.append( ", responseCode=" ).append( responseCode );
1230 sb.append( '}' );
1231 return sb.toString();
1232 }
1233 }
1234 }