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