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