View Javadoc

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