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