package org.apache.maven.wagon.http; /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import org.apache.maven.wagon.FileTestUtils; import org.apache.maven.wagon.ResourceDoesNotExistException; import org.apache.maven.wagon.StreamingWagon; import org.apache.maven.wagon.StreamingWagonTestCase; import org.apache.maven.wagon.TransferFailedException; import org.apache.maven.wagon.Wagon; import org.apache.maven.wagon.authentication.AuthenticationInfo; import org.apache.maven.wagon.authorization.AuthorizationException; import org.apache.maven.wagon.proxy.ProxyInfo; import org.apache.maven.wagon.repository.Repository; import org.apache.maven.wagon.resource.Resource; import org.codehaus.plexus.util.FileUtils; import org.codehaus.plexus.util.IOUtil; import org.codehaus.plexus.util.StringOutputStream; import org.codehaus.plexus.util.StringUtils; import org.mortbay.jetty.Handler; import org.mortbay.jetty.HttpConnection; import org.mortbay.jetty.Request; import org.mortbay.jetty.Response; import org.mortbay.jetty.Server; import org.mortbay.jetty.handler.AbstractHandler; import org.mortbay.jetty.handler.HandlerCollection; import org.mortbay.jetty.security.Constraint; import org.mortbay.jetty.security.ConstraintMapping; import org.mortbay.jetty.security.HashUserRealm; import org.mortbay.jetty.security.SecurityHandler; import org.mortbay.jetty.servlet.Context; import org.mortbay.jetty.servlet.DefaultServlet; import org.mortbay.jetty.servlet.ServletHolder; import javax.servlet.ServletException; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.lang.reflect.Method; import java.net.URLDecoder; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.zip.GZIPOutputStream; /** * @version $Id: LightweightHttpWagonTest.java 680764 2008-07-29 16:45:51Z brett $ */ public abstract class HttpWagonTestCase extends StreamingWagonTestCase { private Server server; protected void setupWagonTestingFixtures() throws Exception { // File round trip testing File file = FileTestUtils.createUniqueFile( "local-repository", "test-resource" ); file.delete(); file.getParentFile().mkdirs(); File repositoryDirectory = getRepositoryDirectory(); FileUtils.deleteDirectory( repositoryDirectory ); repositoryDirectory.mkdirs(); server = new Server( 0 ); PutHandler putHandler = new PutHandler( repositoryDirectory ); server.addHandler( putHandler ); createContext( server, repositoryDirectory ); addConnectors( server ); server.start(); testRepository.setUrl( getTestRepositoryUrl() ); } @Override protected final int getTestRepositoryPort() { if ( server == null ) { return 0; } return server.getConnectors()[0].getLocalPort(); } protected void createContext( Server server, File repositoryDirectory ) throws IOException { Context root = new Context( server, "/", Context.SESSIONS ); root.setResourceBase( repositoryDirectory.getAbsolutePath() ); ServletHolder servletHolder = new ServletHolder( new DefaultServlet() ); root.addServlet( servletHolder, "/*" ); } protected void tearDownWagonTestingFixtures() throws Exception { server.stop(); } public void testWagonGetFileList() throws Exception { File dir = getRepositoryDirectory(); FileUtils.deleteDirectory( dir ); File f = new File( dir, "file-list" ); f.mkdirs(); super.testWagonGetFileList(); } public void testHttpHeaders() throws Exception { Properties properties = new Properties(); properties.setProperty( "User-Agent", "Maven-Wagon/1.0" ); StreamingWagon wagon = (StreamingWagon) getWagon(); setHttpHeaders( wagon, properties ); Server server = new Server( 0 ); TestHeaderHandler handler = new TestHeaderHandler(); server.setHandler( handler ); addConnectors( server ); server.start(); wagon.connect( new Repository( "id", getProtocol() + "://localhost:" + server.getConnectors()[0].getLocalPort() ) ); wagon.getToStream( "resource", new StringOutputStream() ); wagon.disconnect(); server.stop(); assertEquals( "Maven-Wagon/1.0", handler.headers.get( "User-Agent" ) ); } /** * test set of User-Agent as it's done by aether wagon connector with using setHttpHeaders */ public void testHttpHeadersWithCommonMethods() throws Exception { Properties properties = new Properties(); properties.setProperty( "User-Agent", "Maven-Wagon/1.0" ); StreamingWagon wagon = (StreamingWagon) getWagon(); Method setHttpHeaders = wagon.getClass().getMethod( "setHttpHeaders", Properties.class ); setHttpHeaders.invoke( wagon, properties ); Server server = new Server( 0 ); TestHeaderHandler handler = new TestHeaderHandler(); server.setHandler( handler ); addConnectors( server ); server.start(); wagon.connect( new Repository( "id", getProtocol() + "://localhost:" + server.getConnectors()[0].getLocalPort() ) ); wagon.getToStream( "resource", new StringOutputStream() ); wagon.disconnect(); server.stop(); assertEquals( "Maven-Wagon/1.0", handler.headers.get( "User-Agent" ) ); } protected abstract void setHttpHeaders( StreamingWagon wagon, Properties properties ); protected void addConnectors( Server server ) { } protected String getRepositoryUrl( Server server ) { int localPort = server.getConnectors()[0].getLocalPort(); return getProtocol() + "://localhost:" + localPort; } public void testGetForbidden() throws Exception { try { runTestGet( HttpServletResponse.SC_FORBIDDEN ); fail(); } catch ( AuthorizationException e ) { assertTrue( true ); } } public void testGet404() throws Exception { try { runTestGet( HttpServletResponse.SC_NOT_FOUND ); fail(); } catch ( ResourceDoesNotExistException e ) { assertTrue( true ); } } public void testGet500() throws Exception { try { runTestGet( HttpServletResponse.SC_INTERNAL_SERVER_ERROR ); fail(); } catch ( TransferFailedException e ) { assertTrue( true ); } } private void runTestGet( int status ) throws Exception { StreamingWagon wagon = (StreamingWagon) getWagon(); Server server = new Server( 0 ); StatusHandler handler = new StatusHandler(); handler.setStatusToReturn( status ); server.setHandler( handler ); addConnectors( server ); server.start(); wagon.connect( new Repository( "id", getRepositoryUrl( server ) ) ); try { wagon.getToStream( "resource", new StringOutputStream() ); fail(); } finally { wagon.disconnect(); server.stop(); } } public void testResourceExistsForbidden() throws Exception { try { runTestResourceExists( HttpServletResponse.SC_FORBIDDEN ); fail(); } catch ( AuthorizationException e ) { assertTrue( true ); } } public void testResourceExists404() throws Exception { try { assertFalse( runTestResourceExists( HttpServletResponse.SC_NOT_FOUND ) ); } catch ( ResourceDoesNotExistException e ) { assertTrue( true ); } } public void testResourceExists500() throws Exception { try { runTestResourceExists( HttpServletResponse.SC_INTERNAL_SERVER_ERROR ); fail(); } catch ( TransferFailedException e ) { assertTrue( true ); } } private boolean runTestResourceExists( int status ) throws Exception { StreamingWagon wagon = (StreamingWagon) getWagon(); Server server = new Server( 0 ); StatusHandler handler = new StatusHandler(); handler.setStatusToReturn( status ); server.setHandler( handler ); addConnectors( server ); server.start(); wagon.connect( new Repository( "id", getRepositoryUrl( server ) ) ); try { return wagon.resourceExists( "resource" ); } finally { wagon.disconnect(); server.stop(); } } protected long getExpectedLastModifiedOnGet( Repository repository, Resource resource ) { File file = new File( getRepositoryDirectory(), resource.getName() ); return ( file.lastModified() / 1000 ) * 1000; } protected File getRepositoryDirectory() { return getTestFile( "target/test-output/http-repository" ); } public void testGzipGet() throws Exception { Server server = new Server( getTestRepositoryPort() ); String localRepositoryPath = FileTestUtils.getTestOutputDir().toString(); Context root = new Context( server, "/", Context.SESSIONS ); root.setResourceBase( localRepositoryPath ); ServletHolder servletHolder = new ServletHolder( new DefaultServlet() ); servletHolder.setInitParameter( "gzip", "true" ); root.addServlet( servletHolder, "/*" ); addConnectors( server ); server.start(); try { Wagon wagon = getWagon(); Repository testRepository = new Repository( "id", getRepositoryUrl( server ) ); File sourceFile = new File( localRepositoryPath + "/gzip" ); sourceFile.deleteOnExit(); String resName = "gzip-res.txt"; String sourceContent = writeTestFileGzip( sourceFile, resName ); wagon.connect( testRepository ); File destFile = FileTestUtils.createUniqueFile( getName(), getName() ); destFile.deleteOnExit(); wagon.get( "gzip/" + resName, destFile ); wagon.disconnect(); String destContent = FileUtils.fileRead( destFile ); assertEquals( sourceContent, destContent ); } finally { server.stop(); } } public void testProxiedRequest() throws Exception { ProxyInfo proxyInfo = createProxyInfo(); TestHeaderHandler handler = new TestHeaderHandler(); runTestProxiedRequest( proxyInfo, handler ); } public void testProxiedRequestWithAuthentication() throws Exception { ProxyInfo proxyInfo = createProxyInfo(); proxyInfo.setUserName( "user" ); proxyInfo.setPassword( "secret" ); AuthorizingProxyHandler handler = new AuthorizingProxyHandler(); runTestProxiedRequest( proxyInfo, handler ); assertTrue( handler.headers.containsKey( "Proxy-Authorization" ) ); if ( supportProxyPreemptiveAuthentication() ) { assertEquals( 200, handler.handlerRequestResponses.get( 0 ).responseCode ); } else { assertEquals( 407, handler.handlerRequestResponses.get( 0 ).responseCode ); assertEquals( 200, handler.handlerRequestResponses.get( 1 ).responseCode ); } } public void testRedirectGetToStream() throws Exception { StreamingWagon wagon = (StreamingWagon) getWagon(); Server server = new Server( 0 ); TestHeaderHandler handler = new TestHeaderHandler(); server.setHandler( handler ); addConnectors( server ); server.start(); Server redirectServer = new Server( 0 ); addConnectors( redirectServer ); String protocol = getProtocol(); // protocol is wagon protocol but in fact dav is http(s) if ( protocol.equals( "dav" ) ) { protocol = "http"; } if ( protocol.equals( "davs" ) ) { protocol = "https"; } String redirectUrl = protocol + "://localhost:" + server.getConnectors()[0].getLocalPort(); RedirectHandler redirectHandler = new RedirectHandler( "Found", 303, redirectUrl, null ); redirectServer.setHandler( redirectHandler ); redirectServer.start(); wagon.connect( new Repository( "id", getRepositoryUrl( redirectServer ) ) ); File tmpResult = File.createTempFile( "foo", "get" ); FileOutputStream fileOutputStream = new FileOutputStream( tmpResult ); try { wagon.getToStream( "resource", fileOutputStream ); fileOutputStream.flush(); fileOutputStream.close(); String found = FileUtils.fileRead( tmpResult ); assertEquals( "found:'" + found + "'", "Hello, World!", found ); assertEquals( 1, handler.handlerRequestResponses.size() ); assertEquals( 200, handler.handlerRequestResponses.get( 0 ).responseCode ); assertEquals( 1, redirectHandler.handlerRequestResponses.size() ); assertEquals( 302, redirectHandler.handlerRequestResponses.get( 0 ).responseCode ); } finally { wagon.disconnect(); server.stop(); tmpResult.delete(); } } public void testRedirectGet() throws Exception { StreamingWagon wagon = (StreamingWagon) getWagon(); Server server = new Server( 0 ); TestHeaderHandler handler = new TestHeaderHandler(); server.setHandler( handler ); addConnectors( server ); server.start(); Server redirectServer = new Server( 0 ); addConnectors( redirectServer ); String protocol = getProtocol(); // protocol is wagon protocol but in fact dav is http(s) if ( protocol.equals( "dav" ) ) { protocol = "http"; } if ( protocol.equals( "davs" ) ) { protocol = "https"; } String redirectUrl = protocol + "://localhost:" + server.getConnectors()[0].getLocalPort(); RedirectHandler redirectHandler = new RedirectHandler( "Found", 303, redirectUrl, null ); redirectServer.setHandler( redirectHandler ); redirectServer.start(); wagon.connect( new Repository( "id", getRepositoryUrl( redirectServer ) ) ); File tmpResult = File.createTempFile( "foo", "get" ); try { wagon.get( "resource", tmpResult ); String found = FileUtils.fileRead( tmpResult ); assertEquals( "found:'" + found + "'", "Hello, World!", found ); assertEquals( 1, handler.handlerRequestResponses.size() ); assertEquals( 200, handler.handlerRequestResponses.get( 0 ).responseCode ); assertEquals( 1, redirectHandler.handlerRequestResponses.size() ); assertEquals( 302, redirectHandler.handlerRequestResponses.get( 0 ).responseCode ); } finally { wagon.disconnect(); server.stop(); tmpResult.delete(); } } public void testRedirectPutFromStreamWithFullUrl() throws Exception { Server realServer = new Server( 0 ); addConnectors( realServer ); File repositoryDirectory = getRepositoryDirectory(); FileUtils.deleteDirectory( repositoryDirectory ); repositoryDirectory.mkdirs(); PutHandler putHandler = new PutHandler( repositoryDirectory ); realServer.setHandler( putHandler ); realServer.start(); Server redirectServer = new Server( 0 ); addConnectors( redirectServer ); String protocol = getProtocol(); // protocol is wagon protocol but in fact dav is http(s) if ( protocol.equals( "dav" ) ) { protocol = "http"; } if ( protocol.equals( "davs" ) ) { protocol = "https"; } String redirectUrl = protocol + "://localhost:" + realServer.getConnectors()[0].getLocalPort(); RedirectHandler redirectHandler = new RedirectHandler( "Found", 303, redirectUrl, repositoryDirectory ); redirectServer.setHandler( redirectHandler ); redirectServer.start(); try { StreamingWagon wagon = (StreamingWagon) getWagon(); Repository repository = new Repository( "foo", getRepositoryUrl( redirectServer ) ); wagon.connect( repository ); File sourceFile = new File( repositoryDirectory, "test-secured-put-resource" ); sourceFile.delete(); assertFalse( sourceFile.exists() ); File tempFile = File.createTempFile( "wagon", "tmp" ); tempFile.deleteOnExit(); String content = "put top secret"; FileUtils.fileWrite( tempFile.getAbsolutePath(), content ); FileInputStream fileInputStream = new FileInputStream( tempFile ); try { wagon.putFromStream( fileInputStream, "test-secured-put-resource", content.length(), -1 ); } finally { fileInputStream.close(); tempFile.delete(); } assertEquals( content, FileUtils.fileRead( sourceFile.getAbsolutePath() ) ); checkRequestResponseForRedirectPutFromStreamWithFullUrl( putHandler, redirectHandler ); } finally { realServer.stop(); redirectServer.stop(); } } protected void checkRequestResponseForRedirectPutFromStreamWithFullUrl( PutHandler putHandler, RedirectHandler redirectHandler ) { assertEquals( "found:" + putHandler.handlerRequestResponses, 1, putHandler.handlerRequestResponses.size() ); assertEquals( "found:" + putHandler.handlerRequestResponses, 201, putHandler.handlerRequestResponses.get( 0 ).responseCode ); assertEquals( "found:" + redirectHandler.handlerRequestResponses, 1, redirectHandler.handlerRequestResponses.size() ); assertEquals( "found:" + redirectHandler.handlerRequestResponses, 302, redirectHandler.handlerRequestResponses.get( 0 ).responseCode ); } public void testRedirectPutFromStreamRelativeUrl() throws Exception { Server realServer = new Server( 0 ); addConnectors( realServer ); File repositoryDirectory = getRepositoryDirectory(); FileUtils.deleteDirectory( repositoryDirectory ); repositoryDirectory.mkdirs(); PutHandler putHandler = new PutHandler( repositoryDirectory ); realServer.setHandler( putHandler ); realServer.start(); Server redirectServer = new Server( 0 ); addConnectors( redirectServer ); RedirectHandler redirectHandler = new RedirectHandler( "Found", 303, "/redirectRequest/foo", repositoryDirectory ); redirectServer.setHandler( redirectHandler ); redirectServer.start(); try { StreamingWagon wagon = (StreamingWagon) getWagon(); Repository repository = new Repository( "foo", getRepositoryUrl( redirectServer ) ); wagon.connect( repository ); File sourceFile = new File( repositoryDirectory, "/redirectRequest/foo/test-secured-put-resource" ); sourceFile.delete(); assertFalse( sourceFile.exists() ); File tempFile = File.createTempFile( "wagon", "tmp" ); tempFile.deleteOnExit(); String content = "put top secret"; FileUtils.fileWrite( tempFile.getAbsolutePath(), content ); FileInputStream fileInputStream = new FileInputStream( tempFile ); try { wagon.putFromStream( fileInputStream, "test-secured-put-resource", content.length(), -1 ); } finally { fileInputStream.close(); tempFile.delete(); } assertEquals( content, FileUtils.fileRead( sourceFile.getAbsolutePath() ) ); checkRequestResponseForRedirectPutFromStreamWithRelativeUrl( putHandler, redirectHandler ); } finally { realServer.stop(); redirectServer.stop(); } } protected void checkRequestResponseForRedirectPutFromStreamWithRelativeUrl( PutHandler putHandler, RedirectHandler redirectHandler ) { assertEquals( "found:" + putHandler.handlerRequestResponses, 0, putHandler.handlerRequestResponses.size() ); assertEquals( "found:" + redirectHandler.handlerRequestResponses, 2, redirectHandler.handlerRequestResponses.size() ); assertEquals( "found:" + redirectHandler.handlerRequestResponses, 302, redirectHandler.handlerRequestResponses.get( 0 ).responseCode ); assertEquals( "found:" + redirectHandler.handlerRequestResponses, 201, redirectHandler.handlerRequestResponses.get( 1 ).responseCode ); } public void testRedirectPutFileWithFullUrl() throws Exception { Server realServer = new Server( 0 ); addConnectors( realServer ); File repositoryDirectory = getRepositoryDirectory(); FileUtils.deleteDirectory( repositoryDirectory ); repositoryDirectory.mkdirs(); PutHandler putHandler = new PutHandler( repositoryDirectory ); realServer.setHandler( putHandler ); realServer.start(); Server redirectServer = new Server( 0 ); addConnectors( redirectServer ); String protocol = getProtocol(); // protocol is wagon protocol but in fact dav is http(s) if ( protocol.equals( "dav" ) ) { protocol = "http"; } if ( protocol.equals( "davs" ) ) { protocol = "https"; } String redirectUrl = protocol + "://localhost:" + realServer.getConnectors()[0].getLocalPort(); RedirectHandler redirectHandler = new RedirectHandler( "Found", 303, redirectUrl, repositoryDirectory ); redirectServer.setHandler( redirectHandler ); redirectServer.start(); try { StreamingWagon wagon = (StreamingWagon) getWagon(); Repository repository = new Repository( "foo", getRepositoryUrl( redirectServer ) ); wagon.connect( repository ); File sourceFile = new File( repositoryDirectory, "test-secured-put-resource" ); sourceFile.delete(); assertFalse( sourceFile.exists() ); File tempFile = File.createTempFile( "wagon", "tmp" ); tempFile.deleteOnExit(); String content = "put top secret"; FileUtils.fileWrite( tempFile.getAbsolutePath(), content ); try { wagon.put( tempFile, "test-secured-put-resource" ); } finally { tempFile.delete(); } assertEquals( content, FileUtils.fileRead( sourceFile.getAbsolutePath() ) ); } finally { realServer.stop(); redirectServer.stop(); } } public void testRedirectPutFileRelativeUrl() throws Exception { Server realServer = new Server( 0 ); addConnectors( realServer ); File repositoryDirectory = getRepositoryDirectory(); FileUtils.deleteDirectory( repositoryDirectory ); repositoryDirectory.mkdirs(); PutHandler putHandler = new PutHandler( repositoryDirectory ); realServer.setHandler( putHandler ); realServer.start(); Server redirectServer = new Server( 0 ); addConnectors( redirectServer ); RedirectHandler redirectHandler = new RedirectHandler( "Found", 303, "/redirectRequest/foo", repositoryDirectory ); redirectServer.setHandler( redirectHandler ); redirectServer.start(); try { StreamingWagon wagon = (StreamingWagon) getWagon(); Repository repository = new Repository( "foo", getRepositoryUrl( redirectServer ) ); wagon.connect( repository ); File sourceFile = new File( repositoryDirectory, "/redirectRequest/foo/test-secured-put-resource" ); sourceFile.delete(); assertFalse( sourceFile.exists() ); File tempFile = File.createTempFile( "wagon", "tmp" ); tempFile.deleteOnExit(); String content = "put top secret"; FileUtils.fileWrite( tempFile.getAbsolutePath(), content ); try { wagon.put( tempFile, "test-secured-put-resource" ); } finally { tempFile.delete(); } assertEquals( content, FileUtils.fileRead( sourceFile.getAbsolutePath() ) ); } finally { realServer.stop(); redirectServer.stop(); } } public static class RedirectHandler extends AbstractHandler { String reason; int retCode; String redirectUrl; File repositoryDirectory; public List handlerRequestResponses = new ArrayList(); RedirectHandler( String reason, int retCode, String redirectUrl, File repositoryDirectory ) { this.reason = reason; this.retCode = retCode; this.redirectUrl = redirectUrl; this.repositoryDirectory = repositoryDirectory; } public void handle( String s, HttpServletRequest req, HttpServletResponse resp, int i ) throws IOException, ServletException { if ( req.getRequestURI().contains( "redirectRequest" ) ) { PutHandler putHandler = new PutHandler( this.repositoryDirectory ); putHandler.handle( s, req, resp, i ); handlerRequestResponses.add( new HandlerRequestResponse( req.getMethod(), ( (Response) resp ).getStatus(), req.getRequestURI() ) ); return; } resp.setStatus( this.retCode ); resp.sendRedirect( this.redirectUrl + "/" + req.getRequestURI() ); handlerRequestResponses.add( new HandlerRequestResponse( req.getMethod(), ( (Response) resp ).getStatus(), req.getRequestURI() ) ); } } private void runTestProxiedRequest( ProxyInfo proxyInfo, TestHeaderHandler handler ) throws Exception { // what an UGLY hack! // but apparently jetty needs some time to free up resources // <5s: broken test :( Thread.sleep( 5001L ); Server proxyServer = new Server( 0 ); proxyServer.setHandler( handler ); proxyServer.start(); proxyInfo.setPort( proxyServer.getConnectors()[0].getLocalPort() ); System.out.println( "start proxy on host/port " + proxyInfo.getHost() + "/" + proxyInfo.getPort() + " with non proxyHosts " + proxyInfo.getNonProxyHosts() ); while ( !proxyServer.isRunning() || !proxyServer.isStarted() ) { Thread.sleep( 10 ); } try { StreamingWagon wagon = (StreamingWagon) getWagon(); Repository testRepository = new Repository( "id", "http://www.example.com/" ); String localRepositoryPath = FileTestUtils.getTestOutputDir().toString(); File sourceFile = new File( localRepositoryPath, "test-proxied-resource" ); FileUtils.fileWrite( sourceFile.getAbsolutePath(), "content" ); wagon.connect( testRepository, proxyInfo ); StringOutputStream out = new StringOutputStream(); try { wagon.getToStream( "test-proxied-resource", out ); assertTrue( handler.headers.containsKey( "Proxy-Connection" ) ); } finally { System.setProperty( "http.proxyHost", "" ); System.setProperty( "http.proxyPort", "" ); wagon.disconnect(); } } finally { proxyServer.stop(); } } private ProxyInfo createProxyInfo() { ProxyInfo proxyInfo = new ProxyInfo(); proxyInfo.setHost( "localhost" ); proxyInfo.setNonProxyHosts( null ); proxyInfo.setType( "http" ); return proxyInfo; } public void testSecuredGetUnauthorized() throws Exception { try { runTestSecuredGet( null ); fail(); } catch ( AuthorizationException e ) { assertTrue( true ); } } public void testSecuredGetWrongPassword() throws Exception { try { AuthenticationInfo authInfo = new AuthenticationInfo(); authInfo.setUserName( "user" ); authInfo.setPassword( "admin" ); runTestSecuredGet( authInfo ); fail(); } catch ( AuthorizationException e ) { assertTrue( true ); } } public void testSecuredGet() throws Exception { AuthenticationInfo authInfo = new AuthenticationInfo(); authInfo.setUserName( "user" ); authInfo.setPassword( "secret" ); runTestSecuredGet( authInfo ); } public void runTestSecuredGet( AuthenticationInfo authInfo ) throws Exception { String localRepositoryPath = FileTestUtils.getTestOutputDir().toString(); Server server = createSecurityServer( localRepositoryPath ); server.start(); try { StreamingWagon wagon = (StreamingWagon) getWagon(); Repository testRepository = new Repository( "id", getRepositoryUrl( server ) ); File sourceFile = new File( localRepositoryPath, "test-secured-resource" ); FileUtils.fileWrite( sourceFile.getAbsolutePath(), "top secret" ); wagon.connect( testRepository, authInfo ); File file = File.createTempFile( "wagon-test", "txt" ); try { wagon.get( "test-secured-resource", file ); } finally { wagon.disconnect(); } FileInputStream in = new FileInputStream( file ); assertEquals( "top secret", IOUtil.toString( in ) ); TestSecurityHandler securityHandler = (TestSecurityHandler) ( (Context) server.getHandler() ).getHandler(); testPreemptiveAuthenticationGet( securityHandler, supportPreemptiveAuthenticationGet() ); } finally { server.stop(); } } public void testSecuredGetToStream() throws Exception { AuthenticationInfo authInfo = new AuthenticationInfo(); authInfo.setUserName( "user" ); authInfo.setPassword( "secret" ); runTestSecuredGetToStream( authInfo ); } public void runTestSecuredGetToStream( AuthenticationInfo authInfo ) throws Exception { String localRepositoryPath = FileTestUtils.getTestOutputDir().toString(); Server server = createSecurityServer( localRepositoryPath ); server.start(); try { StreamingWagon wagon = (StreamingWagon) getWagon(); Repository testRepository = new Repository( "id", getRepositoryUrl( server ) ); File sourceFile = new File( localRepositoryPath, "test-secured-resource" ); FileUtils.fileWrite( sourceFile.getAbsolutePath(), "top secret" ); wagon.connect( testRepository, authInfo ); StringOutputStream out = new StringOutputStream(); try { wagon.getToStream( "test-secured-resource", out ); } finally { wagon.disconnect(); } assertEquals( "top secret", out.toString() ); TestSecurityHandler securityHandler = (TestSecurityHandler) ( (Context) server.getHandler() ).getHandler(); testPreemptiveAuthenticationGet( securityHandler, supportPreemptiveAuthenticationGet() ); } finally { server.stop(); } } public void testSecuredResourceExistsUnauthorized() throws Exception { try { runTestSecuredResourceExists( null ); fail(); } catch ( AuthorizationException e ) { assertTrue( true ); } } public void testSecuredResourceExistsWrongPassword() throws Exception { try { AuthenticationInfo authInfo = new AuthenticationInfo(); authInfo.setUserName( "user" ); authInfo.setPassword( "admin" ); runTestSecuredResourceExists( authInfo ); } catch ( AuthorizationException e ) { assertTrue( true ); } } public void testSecuredResourceExists() throws Exception { AuthenticationInfo authInfo = new AuthenticationInfo(); authInfo.setUserName( "user" ); authInfo.setPassword( "secret" ); runTestSecuredResourceExists( authInfo ); } public void runTestSecuredResourceExists( AuthenticationInfo authInfo ) throws Exception { String localRepositoryPath = FileTestUtils.getTestOutputDir().toString(); Server server = createSecurityServer( localRepositoryPath ); server.start(); try { StreamingWagon wagon = (StreamingWagon) getWagon(); Repository testRepository = new Repository( "id", getRepositoryUrl( server ) ); File sourceFile = new File( localRepositoryPath, "test-secured-resource-exists" ); FileUtils.fileWrite( sourceFile.getAbsolutePath(), "top secret" ); wagon.connect( testRepository, authInfo ); try { assertTrue( wagon.resourceExists( "test-secured-resource-exists" ) ); assertFalse( wagon.resourceExists( "test-secured-resource-not-exists" ) ); } finally { wagon.disconnect(); } } finally { server.stop(); } } private Server createSecurityServer( String localRepositoryPath ) { Server server = new Server( 0 ); SecurityHandler sh = createSecurityHandler(); Context root = new Context( Context.SESSIONS ); root.setContextPath( "/" ); root.addHandler( sh ); root.setResourceBase( localRepositoryPath ); ServletHolder servletHolder = new ServletHolder( new DefaultServlet() ); root.addServlet( servletHolder, "/*" ); server.setHandler( root ); addConnectors( server ); return server; } private String writeTestFileGzip( File parent, String child ) throws IOException { File file = new File( parent, child ); file.getParentFile().mkdirs(); file.deleteOnExit(); OutputStream out = new FileOutputStream( file ); try { out.write( child.getBytes() ); } finally { out.close(); } file = new File( parent, child + ".gz" ); file.deleteOnExit(); String content; out = new FileOutputStream( file ); out = new GZIPOutputStream( out ); try { // write out different data than non-gz file, so we can // assert the gz version was returned content = file.getAbsolutePath(); out.write( content.getBytes() ); } finally { out.close(); } return content; } public void testPutForbidden() throws Exception { try { runTestPut( HttpServletResponse.SC_FORBIDDEN ); fail(); } catch ( AuthorizationException e ) { assertTrue( true ); } } public void testPut404() throws Exception { try { runTestPut( HttpServletResponse.SC_NOT_FOUND ); fail(); } catch ( ResourceDoesNotExistException e ) { assertTrue( true ); } } public void testPut500() throws Exception { try { runTestPut( HttpServletResponse.SC_INTERNAL_SERVER_ERROR ); fail(); } catch ( TransferFailedException e ) { assertTrue( true ); } } private void runTestPut( int status ) throws Exception { StreamingWagon wagon = (StreamingWagon) getWagon(); Server server = new Server( 0 ); StatusHandler handler = new StatusHandler(); handler.setStatusToReturn( status ); server.setHandler( handler ); addConnectors( server ); server.start(); wagon.connect( new Repository( "id", getRepositoryUrl( server ) ) ); File tempFile = File.createTempFile( "wagon", "tmp" ); tempFile.deleteOnExit(); FileUtils.fileWrite( tempFile.getAbsolutePath(), "content" ); try { wagon.put( tempFile, "resource" ); fail(); } finally { wagon.disconnect(); server.stop(); tempFile.delete(); } } public void testSecuredPutUnauthorized() throws Exception { try { runTestSecuredPut( null ); fail(); } catch ( TransferFailedException e ) { assertTrue( true ); } } public void testSecuredPutWrongPassword() throws Exception { try { AuthenticationInfo authInfo = new AuthenticationInfo(); authInfo.setUserName( "user" ); authInfo.setPassword( "admin" ); runTestSecuredPut( authInfo ); fail(); } catch ( TransferFailedException e ) { assertTrue( true ); } } public void testSecuredPut() throws Exception { AuthenticationInfo authInfo = new AuthenticationInfo(); authInfo.setUserName( "user" ); authInfo.setPassword( "secret" ); runTestSecuredPut( authInfo ); } public void runTestSecuredPut( AuthenticationInfo authInfo ) throws Exception { runTestSecuredPut( authInfo, 1 ); } public void runTestSecuredPut( AuthenticationInfo authInfo, int putNumber ) throws Exception { String localRepositoryPath = FileTestUtils.getTestOutputDir().toString(); Server server = new Server( 0 ); TestSecurityHandler sh = createSecurityHandler(); PutHandler putHandler = new PutHandler( new File( localRepositoryPath ) ); HandlerCollection handlers = new HandlerCollection(); handlers.setHandlers( new Handler[]{ sh, putHandler } ); server.setHandler( handlers ); addConnectors( server ); server.start(); StreamingWagon wagon = (StreamingWagon) getWagon(); Repository testRepository = new Repository( "id", getRepositoryUrl( server ) ); wagon.connect( testRepository, authInfo ); try { for ( int i = 0; i < putNumber; i++ ) { File sourceFile = new File( localRepositoryPath, "test-secured-put-resource" ); sourceFile.delete(); assertFalse( sourceFile.exists() ); File tempFile = File.createTempFile( "wagon", "tmp" ); tempFile.deleteOnExit(); FileUtils.fileWrite( tempFile.getAbsolutePath(), "put top secret" ); try { wagon.put( tempFile, "test-secured-put-resource" ); } finally { tempFile.delete(); } assertEquals( "put top secret", FileUtils.fileRead( sourceFile.getAbsolutePath() ) ); } } finally { wagon.disconnect(); server.stop(); } assertEquals( putNumber, putHandler.putCallNumber ); testPreemptiveAuthenticationPut( sh, supportPreemptiveAuthenticationPut() ); } public void testNonSecuredPutFromStream() throws Exception { AuthenticationInfo authInfo = new AuthenticationInfo(); authInfo.setUserName( "user" ); authInfo.setPassword( "secret" ); runTestSecuredPutFromStream( authInfo, 1, false ); } public void testSecuredPutFromStream() throws Exception { AuthenticationInfo authInfo = new AuthenticationInfo(); authInfo.setUserName( "user" ); authInfo.setPassword( "secret" ); runTestSecuredPutFromStream( authInfo, 1, true ); } public void runTestSecuredPutFromStream( AuthenticationInfo authInfo, int putNumber, boolean addSecurityHandler ) throws Exception { String localRepositoryPath = FileTestUtils.getTestOutputDir().toString(); Server server = new Server( 0 ); TestSecurityHandler sh = createSecurityHandler(); PutHandler putHandler = new PutHandler( new File( localRepositoryPath ) ); HandlerCollection handlers = new HandlerCollection(); handlers.setHandlers( addSecurityHandler ? new Handler[]{ sh, putHandler } : new Handler[]{ putHandler } ); server.setHandler( handlers ); addConnectors( server ); server.start(); StreamingWagon wagon = (StreamingWagon) getWagon(); Repository testRepository = new Repository( "id", getRepositoryUrl( server ) ); if ( addSecurityHandler ) { wagon.connect( testRepository, authInfo ); } else { wagon.connect( testRepository ); } try { for ( int i = 0; i < putNumber; i++ ) { File sourceFile = new File( localRepositoryPath, "test-secured-put-resource" ); sourceFile.delete(); assertFalse( sourceFile.exists() ); File tempFile = File.createTempFile( "wagon", "tmp" ); tempFile.deleteOnExit(); String content = "put top secret"; FileUtils.fileWrite( tempFile.getAbsolutePath(), content ); FileInputStream fileInputStream = new FileInputStream( tempFile ); try { wagon.putFromStream( fileInputStream, "test-secured-put-resource", content.length(), -1 ); } finally { fileInputStream.close(); tempFile.delete(); } assertEquals( content, FileUtils.fileRead( sourceFile.getAbsolutePath() ) ); } } finally { wagon.disconnect(); server.stop(); } assertEquals( putNumber, putHandler.putCallNumber ); if ( addSecurityHandler ) { testPreemptiveAuthenticationPut( sh, supportPreemptiveAuthenticationPut() ); } // ensure we didn't use chunked transfer which doesn't work on ngnix for ( DeployedResource deployedResource : putHandler.deployedResources ) { if ( StringUtils.equalsIgnoreCase( "chunked", deployedResource.transferEncoding ) ) { fail( "deployedResource use chunked: " + deployedResource ); } } } protected abstract boolean supportPreemptiveAuthenticationPut(); protected abstract boolean supportPreemptiveAuthenticationGet(); protected abstract boolean supportProxyPreemptiveAuthentication(); protected void testPreemptiveAuthenticationGet( TestSecurityHandler sh, boolean preemptive ) { testPreemptiveAuthentication( sh, preemptive ); } protected void testPreemptiveAuthenticationPut( TestSecurityHandler sh, boolean preemptive ) { testPreemptiveAuthentication( sh, preemptive ); } protected void testPreemptiveAuthentication( TestSecurityHandler sh, boolean preemptive ) { if ( preemptive ) { assertEquals( "not 1 security handler use " + sh.handlerRequestResponses, 1, sh.handlerRequestResponses.size() ); assertEquals( 200, sh.handlerRequestResponses.get( 0 ).responseCode ); } else { assertEquals( "not 2 security handler use " + sh.handlerRequestResponses, 2, sh.handlerRequestResponses.size() ); assertEquals( 401, sh.handlerRequestResponses.get( 0 ).responseCode ); assertEquals( 200, sh.handlerRequestResponses.get( 1 ).responseCode ); } } static class StatusHandler extends AbstractHandler { private int status; public void setStatusToReturn( int status ) { this.status = status; } public void handle( String target, HttpServletRequest request, HttpServletResponse response, int dispatch ) throws IOException, ServletException { if ( status != 0 ) { response.setStatus( status ); ( (Request) request ).setHandled( true ); } } } static class DeployedResource { String httpMethod; String requestUri; String contentLength; String transferEncoding; public DeployedResource() { // no op } @Override public String toString() { final StringBuilder sb = new StringBuilder(); sb.append( "DeployedResource" ); sb.append( "{httpMethod='" ).append( httpMethod ).append( '\'' ); sb.append( ", requestUri='" ).append( requestUri ).append( '\'' ); sb.append( ", contentLength='" ).append( contentLength ).append( '\'' ); sb.append( ", transferEncoding='" ).append( transferEncoding ).append( '\'' ); sb.append( '}' ); return sb.toString(); } } public static class PutHandler extends AbstractHandler { private final File resourceBase; public List deployedResources = new ArrayList(); public int putCallNumber = 0; public List handlerRequestResponses = new ArrayList(); public PutHandler( File repositoryDirectory ) { this.resourceBase = repositoryDirectory; } public void handle( String target, HttpServletRequest request, HttpServletResponse response, int dispatch ) throws IOException, ServletException { Request base_request = request instanceof Request ? (Request) request : HttpConnection.getCurrentConnection().getRequest(); if ( base_request.isHandled() || !"PUT".equals( base_request.getMethod() ) ) { return; } base_request.setHandled( true ); File file = new File( resourceBase, URLDecoder.decode( request.getPathInfo() ) ); file.getParentFile().mkdirs(); FileOutputStream out = new FileOutputStream( file ); ServletInputStream in = request.getInputStream(); try { IOUtil.copy( in, out ); } finally { in.close(); out.close(); } putCallNumber++; DeployedResource deployedResource = new DeployedResource(); deployedResource.httpMethod = request.getMethod(); deployedResource.requestUri = request.getRequestURI(); deployedResource.transferEncoding = request.getHeader( "Transfer-Encoding" ); deployedResource.contentLength = request.getHeader( "Content-Length" ); deployedResources.add( deployedResource ); response.setStatus( HttpServletResponse.SC_CREATED ); handlerRequestResponses.add( new HandlerRequestResponse( request.getMethod(), ( (Response) response ).getStatus(), request.getRequestURI() ) ); } } private static class AuthorizingProxyHandler extends TestHeaderHandler { List handlerRequestResponses = new ArrayList(); public void handle( String target, HttpServletRequest request, HttpServletResponse response, int dispatch ) throws IOException, ServletException { System.out.println( " handle proxy request" ); if ( request.getHeader( "Proxy-Authorization" ) == null ) { handlerRequestResponses.add( new HandlerRequestResponse( request.getMethod(), 407, request.getRequestURI() ) ); response.setStatus( 407 ); response.addHeader( "Proxy-Authenticate", "Basic realm=\"Squid proxy-caching web server\"" ); ( (Request) request ).setHandled( true ); return; } handlerRequestResponses.add( new HandlerRequestResponse( request.getMethod(), 200, request.getRequestURI() ) ); super.handle( target, request, response, dispatch ); } } private static class TestHeaderHandler extends AbstractHandler { public Map headers = Collections.emptyMap(); public List handlerRequestResponses = new ArrayList(); public TestHeaderHandler() { } public void handle( String target, HttpServletRequest request, HttpServletResponse response, int dispatch ) throws IOException, ServletException { headers = new HashMap(); for ( Enumeration e = request.getHeaderNames(); e.hasMoreElements(); ) { String name = (String) e.nextElement(); headers.put( name, request.getHeader( name ) ); } response.setContentType( "text/plain" ); response.setStatus( HttpServletResponse.SC_OK ); response.getWriter().print( "Hello, World!" ); handlerRequestResponses.add( new HandlerRequestResponse( request.getMethod(), ( (Response) response ).getStatus(), request.getRequestURI() ) ); ( (Request) request ).setHandled( true ); } } protected TestSecurityHandler createSecurityHandler() { Constraint constraint = new Constraint(); constraint.setName( Constraint.__BASIC_AUTH ); constraint.setRoles( new String[]{ "admin" } ); constraint.setAuthenticate( true ); ConstraintMapping cm = new ConstraintMapping(); cm.setConstraint( constraint ); cm.setPathSpec( "/*" ); TestSecurityHandler sh = new TestSecurityHandler(); HashUserRealm hashUserRealm = new HashUserRealm( "MyRealm" ); hashUserRealm.put( "user", "secret" ); hashUserRealm.addUserToRole( "user", "admin" ); sh.setUserRealm( hashUserRealm ); sh.setConstraintMappings( new ConstraintMapping[]{ cm } ); return sh; } public static class TestSecurityHandler extends SecurityHandler { public List handlerRequestResponses = new ArrayList(); @Override public void handle( String target, HttpServletRequest request, HttpServletResponse response, int dispatch ) throws IOException, ServletException { String method = request.getMethod(); super.handle( target, request, response, dispatch ); handlerRequestResponses.add( new HandlerRequestResponse( method, ( (Response) response ).getStatus(), request.getRequestURI() ) ); } } public static class HandlerRequestResponse { public String method; public int responseCode; public String requestUri; private HandlerRequestResponse( String method, int responseCode, String requestUri ) { this.method = method; this.responseCode = responseCode; this.requestUri = requestUri; } @Override public String toString() { final StringBuilder sb = new StringBuilder(); sb.append( "HandlerRequestResponse" ); sb.append( "{method='" ).append( method ).append( '\'' ); sb.append( ", responseCode=" ).append( responseCode ); sb.append( ", requestUri='" ).append( requestUri ).append( '\'' ); sb.append( '}' ); return sb.toString(); } } }