1 package org.apache.archiva.upload;
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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
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.services.RoleManagementService;
24 import org.apache.archiva.redback.rest.services.AbstractRestServicesTest;
25 import org.apache.archiva.remotedownload.AbstractDownloadTest;
26 import org.apache.archiva.rest.api.services.ArchivaRestServiceException;
27 import org.apache.archiva.security.common.ArchivaRoleConstants;
28 import org.apache.archiva.test.utils.ArchivaBlockJUnit4ClassRunner;
29 import org.apache.archiva.web.api.FileUploadService;
30 import org.apache.archiva.web.api.RuntimeInfoService;
31 import org.apache.archiva.web.model.ApplicationRuntimeInfo;
32 import org.apache.commons.io.FileUtils;
33 import org.apache.commons.lang.StringUtils;
34 import org.apache.commons.lang.SystemUtils;
35 import org.apache.cxf.jaxrs.client.JAXRSClientFactory;
36 import org.apache.cxf.jaxrs.client.WebClient;
37 import org.apache.cxf.jaxrs.ext.multipart.Attachment;
38 import org.apache.cxf.jaxrs.ext.multipart.AttachmentBuilder;
39 import org.apache.cxf.jaxrs.ext.multipart.ContentDisposition;
40 import org.apache.cxf.jaxrs.ext.multipart.MultipartBody;
41 import org.apache.maven.wagon.providers.http.HttpWagon;
42 import org.apache.maven.wagon.repository.Repository;
43 import org.eclipse.jetty.server.Server;
44 import org.eclipse.jetty.servlet.ServletContextHandler;
45 import org.eclipse.jetty.servlet.ServletHolder;
46 import org.junit.After;
47 import org.junit.AfterClass;
48 import org.junit.Before;
49 import org.junit.BeforeClass;
50 import org.junit.Test;
51 import org.junit.runner.RunWith;
52 import org.slf4j.Logger;
53 import org.slf4j.LoggerFactory;
55 import javax.servlet.ServletException;
56 import javax.servlet.http.HttpServlet;
57 import javax.servlet.http.HttpServletRequest;
58 import javax.servlet.http.HttpServletResponse;
60 import java.io.IOException;
61 import java.net.URLEncoder;
62 import java.nio.file.Files;
63 import java.nio.file.Path;
64 import java.nio.file.Paths;
65 import java.nio.file.StandardCopyOption;
66 import java.util.Collections;
67 import java.util.List;
68 import java.util.zip.ZipEntry;
69 import java.util.zip.ZipFile;
72 * @author Olivier Lamy
74 @RunWith( ArchivaBlockJUnit4ClassRunner.class )
75 public class UploadArtifactsTest
76 extends AbstractRestServicesTest
80 public void startServer()
83 File appServerBase = new File( System.getProperty( "appserver.base" ) );
84 File confDir = new File(appServerBase, "conf");
85 if (!confDir.exists()) {
88 Path log4jCfg = Paths.get("src/test/resources/log4j2-test.xml");
89 Path log4jCfgDst = confDir.toPath().resolve(log4jCfg.getFileName());
90 Files.copy( log4jCfg, log4jCfgDst, StandardCopyOption.REPLACE_EXISTING );
92 File jcrDirectory = new File( appServerBase, "jcr" );
94 if ( jcrDirectory.exists() )
96 FileUtils.deleteDirectory( jcrDirectory );
98 // We have to activate this to verify the bad path traversal protection. We cannot rely on
99 // the application server only.
100 System.setProperty("org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH","true");
107 System.clearProperty("org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH" );
111 protected String getSpringConfigLocation()
113 return "classpath*:META-INF/spring-context.xml,classpath:/spring-context-with-jcr.xml";
117 protected String getRestServicesPath()
119 return "restServices";
122 protected String getBaseUrl()
124 String baseUrlSysProps = System.getProperty( "archiva.baseRestUrl" );
125 return StringUtils.isBlank( baseUrlSysProps ) ? "http://localhost:" + port : baseUrlSysProps;
128 private FileUploadService getUploadService()
130 FileUploadService service =
131 JAXRSClientFactory.create( getBaseUrl( ) + "/" + getRestServicesPath( ) + "/archivaUiServices/",
132 FileUploadService.class,
133 Collections.singletonList( new JacksonJaxbJsonProvider( ) ) );
135 WebClient.client( service ).header( "Authorization", authorizationHeader );
136 WebClient.client( service ).header( "Referer", "http://localhost:" + port );
138 WebClient.client( service ).header( "Referer", "http://localhost" );
143 public void clearUploadedFiles()
146 FileUploadService service = getUploadService( );
147 service.clearUploadedFiles();
151 public void uploadFile() throws IOException, ArchivaRestServiceException
153 FileUploadService service = getUploadService( );
156 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" );
157 final Attachment fileAttachment = new AttachmentBuilder( ).object( Files.newInputStream( file ) ).contentDisposition( new ContentDisposition( "form-data; filename=\"" + file.getFileName( ).toString( ) + "\"; name=\"files[]\"" ) ).build( );
158 MultipartBody body = new MultipartBody( fileAttachment );
159 service.post( body );
162 service.clearUploadedFiles( );
167 public void uploadAndDeleteFile() throws IOException, ArchivaRestServiceException
169 FileUploadService service = getUploadService( );
172 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" );
173 final Attachment fileAttachment = new AttachmentBuilder( ).object( Files.newInputStream( file ) ).contentDisposition( new ContentDisposition( "form-data; filename=\"" + file.getFileName( ).toString( ) + "\"; name=\"files[]\"" ) ).build( );
174 MultipartBody body = new MultipartBody( fileAttachment );
175 service.post( body );
176 service.deleteFile( file.getFileName( ).toString( ) );
179 service.clearUploadedFiles();
184 public void uploadAndDeleteWrongFile() throws IOException, ArchivaRestServiceException
186 FileUploadService service = getUploadService( );
189 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" );
190 final Attachment fileAttachment = new AttachmentBuilder( ).object( Files.newInputStream( file ) ).contentDisposition( new ContentDisposition( "form-data; filename=\"" + file.getFileName( ).toString( ) + "\"; name=\"files[]\"" ) ).build( );
191 MultipartBody body = new MultipartBody( fileAttachment );
192 service.post( body );
193 assertFalse( service.deleteFile( "file123" + file.getFileName( ).toString( ) ) );
195 service.clearUploadedFiles();
200 public void uploadAndDeleteFileInOtherDir() throws IOException, ArchivaRestServiceException
202 Path testFile = null;
205 FileUploadService service = getUploadService( );
206 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" );
207 Path targetDir = Paths.get( "target/testDelete" ).toAbsolutePath( );
208 if ( !Files.exists( targetDir ) ) Files.createDirectory( targetDir );
209 Path tempDir = SystemUtils.getJavaIoTmpDir( ).toPath( );
210 testFile = Files.createTempFile( targetDir, "TestFile", ".txt" );
211 log.debug( "Test file {}", testFile.toAbsolutePath( ) );
212 log.debug( "Tmp dir {}", tempDir.toAbsolutePath( ) );
213 assertTrue( Files.exists( testFile ) );
214 Path relativePath = tempDir.relativize( testFile.toAbsolutePath( ) );
215 final Attachment fileAttachment = new AttachmentBuilder( ).object( Files.newInputStream( file ) ).contentDisposition( new ContentDisposition( "form-data; filename=\"" + file.getFileName( ).toString( ) + "\"; name=\"files[]\"" ) ).build( );
216 MultipartBody body = new MultipartBody( fileAttachment );
217 service.post( body );
218 String relativePathEncoded = URLEncoder.encode( "../target/" + relativePath.toString( ), "UTF-8" );
219 log.debug( "Trying to delete with path traversal: {}, {}", relativePath, relativePathEncoded );
222 service.deleteFile( relativePathEncoded );
224 catch ( ArchivaRestServiceException ex )
226 // Expected exception
228 assertTrue( "File in another directory may not be deleted", Files.exists( testFile ) );
231 if (testFile!=null) {
232 Files.deleteIfExists( testFile );