]> source.dussan.org Git - archiva.git/blob
b754a403ffaa06bec7c6717bbf5a75c70bd9079f
[archiva.git] /
1 package org.apache.archiva.upload;
2 /*
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  */
20
21 import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider;
22 import org.apache.archiva.admin.model.beans.RemoteRepository;
23 import org.apache.archiva.redback.rest.api.model.User;
24 import org.apache.archiva.redback.rest.api.services.RoleManagementService;
25 import org.apache.archiva.redback.rest.api.services.UserService;
26 import org.apache.archiva.redback.rest.services.AbstractRestServicesTest;
27 import org.apache.archiva.redback.rest.services.FakeCreateAdminService;
28 import org.apache.archiva.remotedownload.AbstractDownloadTest;
29 import org.apache.archiva.rest.api.services.ArchivaRestServiceException;
30 import org.apache.archiva.security.common.ArchivaRoleConstants;
31 import org.apache.archiva.test.utils.ArchivaBlockJUnit4ClassRunner;
32 import org.apache.archiva.web.api.FileUploadService;
33 import org.apache.archiva.web.api.RuntimeInfoService;
34 import org.apache.archiva.web.model.ApplicationRuntimeInfo;
35 import org.apache.archiva.web.model.FileMetadata;
36 import org.apache.catalina.Context;
37 import org.apache.catalina.LifecycleException;
38 import org.apache.catalina.deploy.ApplicationParameter;
39 import org.apache.catalina.startup.Tomcat;
40 import org.apache.commons.io.FileUtils;
41 import org.apache.commons.lang.StringUtils;
42 import org.apache.commons.lang.SystemUtils;
43 import org.apache.cxf.jaxrs.client.JAXRSClientFactory;
44 import org.apache.cxf.jaxrs.client.WebClient;
45 import org.apache.cxf.jaxrs.ext.multipart.Attachment;
46 import org.apache.cxf.jaxrs.ext.multipart.AttachmentBuilder;
47 import org.apache.cxf.jaxrs.ext.multipart.ContentDisposition;
48 import org.apache.cxf.jaxrs.ext.multipart.MultipartBody;
49 import org.apache.cxf.message.Message;
50 import org.apache.cxf.transport.servlet.CXFServlet;
51 import org.apache.maven.wagon.providers.http.HttpWagon;
52 import org.apache.maven.wagon.repository.Repository;
53 import org.eclipse.jetty.server.Server;
54 import org.eclipse.jetty.servlet.ServletContextHandler;
55 import org.eclipse.jetty.servlet.ServletHolder;
56 import org.junit.After;
57 import org.junit.AfterClass;
58 import org.junit.Before;
59 import org.junit.BeforeClass;
60 import org.junit.Test;
61 import org.junit.runner.RunWith;
62 import org.slf4j.Logger;
63 import org.slf4j.LoggerFactory;
64 import org.slf4j.bridge.SLF4JBridgeHandler;
65 import org.springframework.web.context.ContextLoaderListener;
66
67 import javax.servlet.ServletException;
68 import javax.servlet.http.HttpServlet;
69 import javax.servlet.http.HttpServletRequest;
70 import javax.servlet.http.HttpServletResponse;
71 import java.io.File;
72 import java.io.IOException;
73 import java.net.URLEncoder;
74 import java.nio.file.Files;
75 import java.nio.file.Path;
76 import java.nio.file.Paths;
77 import java.nio.file.StandardCopyOption;
78 import java.util.Collections;
79 import java.util.List;
80 import java.util.zip.ZipEntry;
81 import java.util.zip.ZipFile;
82
83 /**
84  * @author Olivier Lamy
85  */
86 @RunWith( ArchivaBlockJUnit4ClassRunner.class )
87 public class UploadArtifactsTest
88     extends AbstractRestServicesTest
89 {
90     private Tomcat tomcat;
91
92     @Override
93     @Before
94     public void startServer( )
95         throws Exception
96     {
97         System.setProperty( "org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH", "true" );
98         System.setProperty("appserver.base", Paths.get("target/appserver-base").toAbsolutePath().toString());
99         Path appServerBase = Paths.get("target/appserver-base");
100         FileUtils.deleteDirectory(appServerBase.toAbsolutePath().toFile());
101         Path confDir = appServerBase.resolve( "conf" );
102         if ( !Files.exists(confDir))
103         {
104             Files.createDirectories(confDir);
105         }
106         Path log4jCfg = Paths.get( "src/test/resources/log4j2-test.xml" );
107         Path log4jCfgDst = confDir.resolve( log4jCfg.getFileName( ) );
108
109         Files.copy( log4jCfg, log4jCfgDst, StandardCopyOption.REPLACE_EXISTING );
110
111         Path archivaCfg = Paths.get( "src/test/resources/archiva.xml" );
112         Files.copy( archivaCfg, confDir.resolve( archivaCfg.getFileName( ) ), StandardCopyOption.REPLACE_EXISTING );
113
114         Path jcrDirectory = appServerBase.resolve("jcr" );
115
116         if ( Files.exists(jcrDirectory) )
117         {
118             FileUtils.deleteDirectory( jcrDirectory.toAbsolutePath().toFile() );
119         }
120         // We have to activate this to verify the bad path traversal protection. We cannot rely on
121         // the application server only.
122
123         SLF4JBridgeHandler.removeHandlersForRootLogger();
124         SLF4JBridgeHandler.install();
125         this.tomcat = new Tomcat();
126         this.tomcat.setBaseDir(System.getProperty("java.io.tmpdir"));
127         this.tomcat.setPort(0);
128         this.tomcat.setSilent(false);
129         Context context = this.tomcat.addContext("", System.getProperty("java.io.tmpdir"));
130         ApplicationParameter applicationParameter = new ApplicationParameter();
131         applicationParameter.setName("contextConfigLocation");
132         applicationParameter.setValue(this.getSpringConfigLocation());
133         context.addApplicationParameter(applicationParameter);
134         context.addApplicationListener(ContextLoaderListener.class.getName());
135         Tomcat.addServlet(context, "cxf", new CXFServlet());
136         context.addServletMapping("/" + this.getRestServicesPath() + "/*", "cxf");
137         this.tomcat.start();
138         this.port = this.tomcat.getConnector().getLocalPort();
139         this.log.info("start server on port {}", this.port);
140         UserService userService = this.getUserService();
141         User adminUser = new User();
142         adminUser.setUsername("admin");
143         adminUser.setPassword("rose210208");
144         adminUser.setFullName("the admin user");
145         adminUser.setEmail("toto@toto.fr");
146         userService.createAdminUser(adminUser);
147         FakeCreateAdminService fakeCreateAdminService = this.getFakeCreateAdminService();
148         // super.startServer( );
149     }
150
151     @After
152     public void stop( ) {
153         if (this.tomcat != null) {
154             try {
155                 this.tomcat.stop();
156             } catch (LifecycleException e) {
157                 //
158             }
159         }
160         System.clearProperty( "org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH" );
161     }
162
163     @Override
164     protected String getSpringConfigLocation( )
165     {
166         return "classpath*:META-INF/spring-context.xml,classpath:/spring-context-test-upload.xml";
167     }
168
169     @Override
170     protected String getRestServicesPath( )
171     {
172         return "restServices";
173     }
174
175     protected String getBaseUrl( )
176     {
177         String baseUrlSysProps = System.getProperty( "archiva.baseRestUrl" );
178         return StringUtils.isBlank( baseUrlSysProps ) ? "http://localhost:" + getServerPort() : baseUrlSysProps;
179     }
180
181     private FileUploadService getUploadService( )
182     {
183         FileUploadService service =
184             JAXRSClientFactory.create( getBaseUrl( ) + "/" + getRestServicesPath( ) + "/archivaUiServices/",
185                 FileUploadService.class,
186                 Collections.singletonList( new JacksonJaxbJsonProvider( ) ) );
187         log.debug( "Service class {}", service.getClass( ).getName( ) );
188         WebClient.client( service ).header( "Authorization", authorizationHeader );
189         WebClient.client( service ).header( "Referer", "http://localhost:" + getServerPort() );
190
191         WebClient.client( service ).header( "Referer", "http://localhost" );
192         WebClient.getConfig( service ).getRequestContext( ).put( Message.MAINTAIN_SESSION, true );
193         WebClient.getConfig( service).getRequestContext().put(Message.EXCEPTION_MESSAGE_CAUSE_ENABLED, true);
194         WebClient.getConfig( service).getRequestContext().put(Message.FAULT_STACKTRACE_ENABLED, true);
195         WebClient.getConfig( service).getRequestContext().put(Message.PROPOGATE_EXCEPTION, true);
196         WebClient.getConfig( service).getRequestContext().put("org.apache.cxf.transport.no_io_exceptions", true);
197
198         // WebClient.client( service ).
199         return service;
200     }
201
202     @Test
203     public void clearUploadedFiles( )
204         throws Exception
205     {
206         FileUploadService service = getUploadService( );
207         service.clearUploadedFiles( );
208     }
209
210     @Test
211     public void uploadFile( ) throws IOException, ArchivaRestServiceException
212     {
213         FileUploadService service = getUploadService( );
214         try
215         {
216             Path file = Paths.get( "src/test/repositories/snapshot-repo/org/apache/archiva/archiva-model/1.4-M4-SNAPSHOT/archiva-model-1.4-M4-20130425.081822-1.jar" );
217             final Attachment fileAttachment = new AttachmentBuilder( ).object( Files.newInputStream( file ) ).contentDisposition( new ContentDisposition( "form-data; filename=\"" + file.getFileName( ).toString( ) + "\"; name=\"files[]\"" ) ).build( );
218             MultipartBody body = new MultipartBody( fileAttachment );
219             service.post( body );
220         }
221         finally
222         {
223             service.clearUploadedFiles( );
224         }
225     }
226
227     @Test
228     public void failUploadFileWithBadFileName( ) throws IOException, ArchivaRestServiceException
229     {
230         FileUploadService service = getUploadService( );
231         try
232         {
233             Path file = Paths.get( "src/test/repositories/snapshot-repo/org/apache/archiva/archiva-model/1.4-M4-SNAPSHOT/archiva-model-1.4-M4-20130425.081822-1.jar" );
234             final Attachment fileAttachment = new AttachmentBuilder( ).object( Files.newInputStream( file ) ).contentDisposition( new ContentDisposition( "form-data; filename=\"/../TestFile.testext\"; name=\"files[]\"" ) ).build( );
235             MultipartBody body = new MultipartBody( fileAttachment );
236             try
237             {
238                 service.post( body );
239                 fail( "FileNames with path contents should not be allowed." );
240             }
241             catch ( ArchivaRestServiceException e )
242             {
243                 // OK
244             }
245         }
246         finally
247         {
248             service.clearUploadedFiles( );
249         }
250     }
251
252     @Test
253     public void uploadAndDeleteFile( ) throws IOException, ArchivaRestServiceException
254     {
255         FileUploadService service = getUploadService( );
256         try
257         {
258             Path file = Paths.get( "src/test/repositories/snapshot-repo/org/apache/archiva/archiva-model/1.4-M4-SNAPSHOT/archiva-model-1.4-M4-20130425.081822-1.jar" );
259             final Attachment fileAttachment = new AttachmentBuilder( ).object( Files.newInputStream( file ) ).contentDisposition( new ContentDisposition( "form-data; filename=\"" + file.getFileName( ).toString( ) + "\"; name=\"files[]\"" ) ).build( );
260             MultipartBody body = new MultipartBody( fileAttachment );
261             service.post( body );
262             service.deleteFile( file.getFileName( ).toString( ) );
263         }
264         finally
265         {
266             service.clearUploadedFiles( );
267         }
268     }
269
270     @Test
271     public void failUploadAndDeleteWrongFile( ) throws IOException, ArchivaRestServiceException
272     {
273         FileUploadService service = getUploadService( );
274         try
275         {
276             Path file = Paths.get( "src/test/repositories/snapshot-repo/org/apache/archiva/archiva-model/1.4-M4-SNAPSHOT/archiva-model-1.4-M4-20130425.081822-1.jar" );
277             final Attachment fileAttachment = new AttachmentBuilder( ).object( Files.newInputStream( file ) ).contentDisposition( new ContentDisposition( "form-data; filename=\"" + file.getFileName( ).toString( ) + "\"; name=\"files[]\"" ) ).build( );
278             MultipartBody body = new MultipartBody( fileAttachment );
279             service.post( body );
280             assertFalse( service.deleteFile( "file123" + file.getFileName( ).toString( ) ) );
281         }
282         finally
283         {
284             service.clearUploadedFiles( );
285         }
286     }
287
288     @Test
289     public void failUploadAndDeleteFileInOtherDir( ) throws IOException, ArchivaRestServiceException
290     {
291         Path testFile = null;
292         try
293         {
294             FileUploadService service = getUploadService( );
295             Path file = Paths.get( "src/test/repositories/snapshot-repo/org/apache/archiva/archiva-model/1.4-M4-SNAPSHOT/archiva-model-1.4-M4-20130425.081822-1.jar" );
296             Path targetDir = Paths.get( "target/testDelete" ).toAbsolutePath( );
297             if ( !Files.exists( targetDir ) ) Files.createDirectories( targetDir );
298             Path tempDir = SystemUtils.getJavaIoTmpDir( ).toPath( );
299             testFile = Files.createTempFile( targetDir, "TestFile", ".txt" );
300             log.debug( "Test file {}", testFile.toAbsolutePath( ) );
301             log.debug( "Tmp dir {}", tempDir.toAbsolutePath( ) );
302             assertTrue( Files.exists( testFile ) );
303             Path relativePath = tempDir.relativize( testFile.toAbsolutePath( ) );
304             final Attachment fileAttachment = new AttachmentBuilder( ).object( Files.newInputStream( file ) ).contentDisposition( new ContentDisposition( "form-data; filename=\"" + file.getFileName( ).toString( ) + "\"; name=\"files[]\"" ) ).build( );
305             MultipartBody body = new MultipartBody( fileAttachment );
306             service.post( body );
307             String relativePathEncoded = URLEncoder.encode( "../target/" + relativePath.toString( ), "UTF-8" );
308             log.debug( "Trying to delete with path traversal: {}, {}", relativePath, relativePathEncoded );
309             try
310             {
311                 service.deleteFile( relativePathEncoded );
312             }
313             catch ( ArchivaRestServiceException ex )
314             {
315                 // Expected exception
316             }
317             assertTrue( "File in another directory may not be deleted", Files.exists( testFile ) );
318         }
319         finally
320         {
321             if ( testFile != null )
322             {
323                 Files.deleteIfExists( testFile );
324             }
325         }
326     }
327
328     @Test
329     public void failSaveFileWithBadParams( ) throws IOException, ArchivaRestServiceException
330     {
331         FileUploadService service = getUploadService( );
332         Path targetFile = Paths.get( "target/test/test-testSave.4" );
333         Path targetPom = Paths.get( "target/test/test-testSave.pom" );
334         try
335         {
336             Path file = Paths.get( "src/test/repositories/snapshot-repo/org/apache/archiva/archiva-model/1.4-M4-SNAPSHOT/archiva-model-1.4-M4-20130425.081822-1.jar" );
337
338             Path targetDir = Paths.get( "target/appserver-base/test/testSave" ).toAbsolutePath( );
339             Path repoDir = Paths.get("target/appserver-base/repositories/internal/org");
340             log.info("Repo dir {}", repoDir.toAbsolutePath());
341             if (!Files.exists(repoDir)) Files.createDirectories(repoDir);
342             assertTrue(Files.exists(repoDir));
343             if ( !Files.exists( targetDir ) ) Files.createDirectories( targetDir );
344             Files.deleteIfExists( targetFile );
345             Files.deleteIfExists( targetPom );
346             Attachment fileAttachment = new AttachmentBuilder( ).object( Files.newInputStream( file ) ).contentDisposition( new ContentDisposition( "form-data; filename=\"archiva-model-1.2.jar\"; name=\"files[]\"" ) ).build( );
347             MultipartBody body = new MultipartBody( fileAttachment );
348             FileMetadata meta = service.post( body );
349             log.debug( "Metadata {}", meta.toString( ) );
350             assertTrue( service.save( "internal", "org.archiva", "archiva-model", "1.2", "jar", true ) );
351
352             fileAttachment = new AttachmentBuilder( ).object( Files.newInputStream( file ) ).contentDisposition( new ContentDisposition( "form-data; filename=\"/../TestFile.FileExt\"; name=\"files[]\"" ) ).build( );
353             body = new MultipartBody( fileAttachment );
354             meta = service.post( body );
355             log.debug( "Metadata {}", meta.toString( ) );
356             try {
357                 service.save("internal", "org", URLEncoder.encode("../../../test", "UTF-8"), URLEncoder.encode("testSave", "UTF-8"), "4", true);
358                 fail("Error expected, if the content contains bad characters.");
359             } catch (ArchivaRestServiceException e) {
360                 // OK
361             }
362             assertFalse( Files.exists( Paths.get( "target/test-testSave.4" ) ) );
363         }
364         finally
365         {
366             // service.clearUploadedFiles( );
367             Files.deleteIfExists( targetFile );
368             Files.deleteIfExists( targetPom );
369         }
370     }
371
372     @Test
373     public void saveFile( ) throws IOException, ArchivaRestServiceException
374     {
375
376         Path path = Paths.get("target/appserver-base/repositories/internal/data/repositories/internal/org/apache/archiva/archiva-model/1.2/archiva-model-1.2.jar");
377         Files.deleteIfExists( path );
378         FileUploadService service = getUploadService( );
379         Path file = Paths.get( "src/test/repositories/snapshot-repo/org/apache/archiva/archiva-model/1.4-M4-SNAPSHOT/archiva-model-1.4-M4-20130425.081822-1.jar" );
380         final Attachment fileAttachment = new AttachmentBuilder( ).object( Files.newInputStream( file ) ).contentDisposition( new ContentDisposition( "form-data; filename=\"archiva-model.jar\"; name=\"files[]\"" ) ).build( );
381         MultipartBody body = new MultipartBody( fileAttachment );
382         service.post( body );
383         service.save( "internal", "org.apache.archiva", "archiva-model", "1.2", "jar", true );
384     }
385 }