From a502d96a860456ec5e8c96761db70f7cabb74751 Mon Sep 17 00:00:00 2001
From: Paul Martin <paul@paulsputer.com>
Date: Sat, 30 Apr 2016 04:19:14 -0400
Subject: [PATCH] Merge pull request #1073 from gitblit/1062-DocEditorUpdates

---
 src/test/java/com/gitblit/tests/FilestoreManagerTest.java |  547 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 547 insertions(+), 0 deletions(-)

diff --git a/src/test/java/com/gitblit/tests/FilestoreManagerTest.java b/src/test/java/com/gitblit/tests/FilestoreManagerTest.java
new file mode 100644
index 0000000..c76e9dd
--- /dev/null
+++ b/src/test/java/com/gitblit/tests/FilestoreManagerTest.java
@@ -0,0 +1,547 @@
+package com.gitblit.tests;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.util.Date;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.commons.codec.digest.DigestUtils;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.gitblit.Constants.AccessPermission;
+import com.gitblit.Constants.AccessRestrictionType;
+import com.gitblit.Constants.AuthorizationControl;
+import com.gitblit.Keys;
+import com.gitblit.models.FilestoreModel.Status;
+import com.gitblit.models.RepositoryModel;
+import com.gitblit.models.UserModel;
+import com.gitblit.utils.FileUtils;
+
+
+/**
+ * Test of the filestore manager and confirming filesystem updated
+ *
+ * @author Paul Martin
+ *
+ */
+public class FilestoreManagerTest extends GitblitUnitTest {
+
+	private static final AtomicBoolean started = new AtomicBoolean(false);
+	
+	private static final BlobInfo blob_zero = new BlobInfo(0);
+	private static final BlobInfo blob_512KB = new BlobInfo(512*FileUtils.KB);
+	private static final BlobInfo blob_6MB = new BlobInfo(6*FileUtils.MB);
+	
+	private static int download_limit_default = -1;
+	private static int download_limit_test = 5*FileUtils.MB;
+	
+	private static final String invalid_hash_empty = "";
+	private static final String invalid_hash_major = "INVALID_HASH";
+	private static final String invalid_hash_regex_attack = blob_512KB.hash.replace('a', '*');
+	private static final String invalid_hash_one_long = blob_512KB.hash.concat("a");
+	private static final String invalid_hash_one_short = blob_512KB.hash.substring(1);
+	
+
+	
+	@BeforeClass
+	public static void startGitblit() throws Exception {
+		started.set(GitBlitSuite.startGitblit());
+	}
+
+	@AfterClass
+	public static void stopGitblit() throws Exception {
+		if (started.get()) {
+			GitBlitSuite.stopGitblit();
+		}
+	}
+	
+
+	
+	@Test
+	public void testAdminAccess() throws Exception {
+		
+		FileUtils.delete(filestore().getStorageFolder());
+		filestore().clearFilestoreCache();
+		
+		RepositoryModel r = new RepositoryModel("myrepo.git", null, null, new Date());
+		ByteArrayOutputStream streamOut = new ByteArrayOutputStream();
+		
+		UserModel u = new UserModel("admin");
+		u.canAdmin = true;
+
+		//No upload limit
+		settings().overrideSetting(Keys.filestore.maxUploadSize, download_limit_default);
+		
+		//Invalid hash tests
+		assertEquals(Status.Error_Invalid_Oid, filestore().downloadBlob(invalid_hash_major, u, r, streamOut));
+		assertEquals(Status.Error_Invalid_Oid, filestore().downloadBlob(invalid_hash_regex_attack, u, r, streamOut));
+		assertEquals(Status.Error_Invalid_Oid, filestore().downloadBlob(invalid_hash_one_long, u, r, streamOut));
+		assertEquals(Status.Error_Invalid_Oid, filestore().downloadBlob(invalid_hash_one_short, u, r, streamOut));
+		
+		// Download prior to upload
+		streamOut.reset();
+		assertEquals(Status.Unavailable, filestore().downloadBlob(blob_512KB.hash, u, r, streamOut));
+		streamOut.reset();
+		assertEquals(Status.Unavailable, filestore().downloadBlob(blob_512KB.hash, u, r, streamOut));
+		
+		//Bad input is rejected with no upload taking place
+		assertEquals(Status.Error_Invalid_Oid, filestore().uploadBlob(invalid_hash_empty, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+		assertEquals(Status.Error_Invalid_Oid, filestore().uploadBlob(invalid_hash_major, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+		assertEquals(Status.Error_Invalid_Oid, filestore().uploadBlob(invalid_hash_regex_attack, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+		assertEquals(Status.Error_Invalid_Oid, filestore().uploadBlob(invalid_hash_one_long, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+		assertEquals(Status.Error_Invalid_Oid, filestore().uploadBlob(invalid_hash_one_short, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+		
+		assertEquals(Status.Error_Invalid_Size, filestore().uploadBlob(blob_512KB.hash, -1, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+
+		assertEquals(Status.Error_Size_Mismatch, filestore().uploadBlob(blob_512KB.hash, 0, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+		assertEquals(Status.Error_Size_Mismatch, filestore().uploadBlob(blob_512KB.hash, blob_512KB.length-1, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+		assertEquals(Status.Error_Size_Mismatch, filestore().uploadBlob(blob_512KB.hash, blob_512KB.length+1, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+		
+		assertEquals(Status.Error_Hash_Mismatch, filestore().uploadBlob(blob_zero.hash, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+
+		//Confirm no upload with bad input
+		streamOut.reset();
+		assertEquals(Status.Unavailable, filestore().downloadBlob(blob_512KB.hash, u, r, streamOut));
+		
+		//Good input will accept the upload
+		assertEquals(Status.Available, filestore().uploadBlob(blob_512KB.hash, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+		streamOut.reset();
+		assertEquals(Status.Available, filestore().downloadBlob(blob_512KB.hash, u, r, streamOut));
+		assertArrayEquals(blob_512KB.blob, streamOut.toByteArray());
+		
+		//Subsequent failed uploads do not affect file
+		assertEquals(Status.Error_Size_Mismatch, filestore().uploadBlob(blob_512KB.hash, blob_512KB.length-1, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+		assertEquals(Status.Error_Size_Mismatch, filestore().uploadBlob(blob_512KB.hash, blob_512KB.length+1, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+		
+		streamOut.reset();
+		assertEquals(Status.Available, filestore().downloadBlob(blob_512KB.hash, u, r, streamOut));
+		assertArrayEquals(blob_512KB.blob, streamOut.toByteArray());
+		
+		//Zero length upload is valid
+		assertEquals(Status.Available, filestore().uploadBlob(blob_zero.hash, blob_zero.length, u, r, new ByteArrayInputStream(blob_zero.blob)));
+		
+		streamOut.reset();
+		assertEquals(Status.Available, filestore().downloadBlob(blob_zero.hash, u, r, streamOut));
+		assertArrayEquals(blob_zero.blob, streamOut.toByteArray());
+		
+		
+		//Pre-informed upload identifies identical errors as immediate upload
+		assertEquals(Status.Upload_Pending, filestore().addObject(blob_6MB.hash, blob_6MB.length, u, r));
+		streamOut.reset();
+		assertEquals(Status.Unavailable, filestore().downloadBlob(blob_6MB.hash, u, r, streamOut));
+		
+		assertEquals(Status.Error_Invalid_Oid, filestore().uploadBlob(invalid_hash_empty, blob_6MB.length, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+		assertEquals(Status.Error_Invalid_Oid, filestore().uploadBlob(invalid_hash_major, blob_6MB.length, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+		assertEquals(Status.Error_Invalid_Oid, filestore().uploadBlob(invalid_hash_regex_attack, blob_6MB.length, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+		assertEquals(Status.Error_Invalid_Oid, filestore().uploadBlob(invalid_hash_one_long, blob_6MB.length, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+		assertEquals(Status.Error_Invalid_Oid, filestore().uploadBlob(invalid_hash_one_short, blob_6MB.length, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+		
+		assertEquals(Status.Error_Size_Mismatch, filestore().uploadBlob(blob_6MB.hash, 0, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+		assertEquals(Status.Error_Size_Mismatch, filestore().uploadBlob(blob_6MB.hash, blob_6MB.length-1, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+		assertEquals(Status.Error_Size_Mismatch, filestore().uploadBlob(blob_6MB.hash, blob_6MB.length+1, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+		
+		streamOut.reset();
+		assertEquals(Status.Unavailable, filestore().downloadBlob(blob_6MB.hash, u, r, streamOut));
+		
+		//Good input will accept the upload
+		assertEquals(Status.Available, filestore().uploadBlob(blob_6MB.hash, blob_6MB.length, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+		streamOut.reset();
+		assertEquals(Status.Available, filestore().downloadBlob(blob_6MB.hash, u, r, streamOut));
+		assertArrayEquals(blob_6MB.blob, streamOut.toByteArray());
+		
+		//Confirm the relevant files exist
+		assertTrue("Admin did not save zero length file!", filestore().getStoragePath(blob_zero.hash).exists());
+		assertTrue("Admin did not save 512KB file!", filestore().getStoragePath(blob_512KB.hash).exists());
+		assertTrue("Admin did not save 6MB file!", filestore().getStoragePath(blob_6MB.hash).exists());
+		
+		//Clear the files and cache to test upload limit property
+		FileUtils.delete(filestore().getStorageFolder());
+		filestore().clearFilestoreCache();
+		
+		settings().overrideSetting(Keys.filestore.maxUploadSize, download_limit_test);
+		
+		assertEquals(Status.Available, filestore().uploadBlob(blob_512KB.hash, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+		streamOut.reset();
+		assertEquals(Status.Available, filestore().downloadBlob(blob_512KB.hash, u, r, streamOut));
+		assertArrayEquals(blob_512KB.blob, streamOut.toByteArray());
+		
+		assertEquals(Status.Error_Exceeds_Size_Limit, filestore().uploadBlob(blob_6MB.hash, blob_6MB.length, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+		streamOut.reset();
+		assertEquals(Status.Unavailable, filestore().downloadBlob(blob_6MB.hash, u, r, streamOut));
+		
+		assertTrue("Admin did not save 512KB file!", filestore().getStoragePath(blob_512KB.hash).exists());
+		assertFalse("Admin saved 6MB file despite (over filesize limit)!", filestore().getStoragePath(blob_6MB.hash).exists());
+		
+	}
+	
+	@Test
+	public void testAuthenticatedAccess() throws Exception {
+		
+		FileUtils.delete(filestore().getStorageFolder());
+		filestore().clearFilestoreCache();
+		
+		RepositoryModel r = new RepositoryModel("myrepo.git", null, null, new Date());
+		r.authorizationControl = AuthorizationControl.AUTHENTICATED;
+		r.accessRestriction = AccessRestrictionType.VIEW;
+		
+		ByteArrayOutputStream streamOut = new ByteArrayOutputStream();
+		
+		UserModel u = new UserModel("test");
+
+		//No upload limit
+		settings().overrideSetting(Keys.filestore.maxUploadSize, download_limit_default);
+		
+		//Invalid hash tests
+		assertEquals(Status.Error_Invalid_Oid, filestore().downloadBlob(invalid_hash_major, u, r, streamOut));
+		assertEquals(Status.Error_Invalid_Oid, filestore().downloadBlob(invalid_hash_regex_attack, u, r, streamOut));
+		assertEquals(Status.Error_Invalid_Oid, filestore().downloadBlob(invalid_hash_one_long, u, r, streamOut));
+		assertEquals(Status.Error_Invalid_Oid, filestore().downloadBlob(invalid_hash_one_short, u, r, streamOut));
+		
+		// Download prior to upload
+		streamOut.reset();
+		assertEquals(Status.Unavailable, filestore().downloadBlob(blob_512KB.hash, u, r, streamOut));
+		streamOut.reset();
+		assertEquals(Status.Unavailable, filestore().downloadBlob(blob_512KB.hash, u, r, streamOut));
+		
+		//Bad input is rejected with no upload taking place
+		assertEquals(Status.Error_Invalid_Oid, filestore().uploadBlob(invalid_hash_empty, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+		assertEquals(Status.Error_Invalid_Oid, filestore().uploadBlob(invalid_hash_major, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+		assertEquals(Status.Error_Invalid_Oid, filestore().uploadBlob(invalid_hash_regex_attack, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+		assertEquals(Status.Error_Invalid_Oid, filestore().uploadBlob(invalid_hash_one_long, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+		assertEquals(Status.Error_Invalid_Oid, filestore().uploadBlob(invalid_hash_one_short, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+		
+		assertEquals(Status.Error_Invalid_Size, filestore().uploadBlob(blob_512KB.hash, -1, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+
+		assertEquals(Status.Error_Size_Mismatch, filestore().uploadBlob(blob_512KB.hash, 0, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+		assertEquals(Status.Error_Size_Mismatch, filestore().uploadBlob(blob_512KB.hash, blob_512KB.length-1, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+		assertEquals(Status.Error_Size_Mismatch, filestore().uploadBlob(blob_512KB.hash, blob_512KB.length+1, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+		
+		assertEquals(Status.Error_Hash_Mismatch, filestore().uploadBlob(blob_zero.hash, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+
+		//Confirm no upload with bad input
+		streamOut.reset();
+		assertEquals(Status.Unavailable, filestore().downloadBlob(blob_512KB.hash, u, r, streamOut));
+		
+		//Good input will accept the upload
+		assertEquals(Status.Available, filestore().uploadBlob(blob_512KB.hash, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+		streamOut.reset();
+		assertEquals(Status.Available, filestore().downloadBlob(blob_512KB.hash, u, r, streamOut));
+		assertArrayEquals(blob_512KB.blob, streamOut.toByteArray());
+		
+		//Subsequent failed uploads do not affect file
+		assertEquals(Status.Error_Size_Mismatch, filestore().uploadBlob(blob_512KB.hash, blob_512KB.length-1, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+		assertEquals(Status.Error_Size_Mismatch, filestore().uploadBlob(blob_512KB.hash, blob_512KB.length+1, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+		
+		streamOut.reset();
+		assertEquals(Status.Available, filestore().downloadBlob(blob_512KB.hash, u, r, streamOut));
+		assertArrayEquals(blob_512KB.blob, streamOut.toByteArray());
+		
+		//Zero length upload is valid
+		assertEquals(Status.Available, filestore().uploadBlob(blob_zero.hash, blob_zero.length, u, r, new ByteArrayInputStream(blob_zero.blob)));
+		
+		streamOut.reset();
+		assertEquals(Status.Available, filestore().downloadBlob(blob_zero.hash, u, r, streamOut));
+		assertArrayEquals(blob_zero.blob, streamOut.toByteArray());
+		
+		
+		//Pre-informed upload identifies identical errors as immediate upload
+		assertEquals(Status.Upload_Pending, filestore().addObject(blob_6MB.hash, blob_6MB.length, u, r));
+		streamOut.reset();
+		assertEquals(Status.Unavailable, filestore().downloadBlob(blob_6MB.hash, u, r, streamOut));
+		
+		assertEquals(Status.Error_Invalid_Oid, filestore().uploadBlob(invalid_hash_empty, blob_6MB.length, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+		assertEquals(Status.Error_Invalid_Oid, filestore().uploadBlob(invalid_hash_major, blob_6MB.length, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+		assertEquals(Status.Error_Invalid_Oid, filestore().uploadBlob(invalid_hash_regex_attack, blob_6MB.length, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+		assertEquals(Status.Error_Invalid_Oid, filestore().uploadBlob(invalid_hash_one_long, blob_6MB.length, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+		assertEquals(Status.Error_Invalid_Oid, filestore().uploadBlob(invalid_hash_one_short, blob_6MB.length, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+		
+		assertEquals(Status.Error_Size_Mismatch, filestore().uploadBlob(blob_6MB.hash, 0, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+		assertEquals(Status.Error_Size_Mismatch, filestore().uploadBlob(blob_6MB.hash, blob_6MB.length-1, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+		assertEquals(Status.Error_Size_Mismatch, filestore().uploadBlob(blob_6MB.hash, blob_6MB.length+1, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+		
+		streamOut.reset();
+		assertEquals(Status.Unavailable, filestore().downloadBlob(blob_6MB.hash, u, r, streamOut));
+		
+		//Good input will accept the upload
+		assertEquals(Status.Available, filestore().uploadBlob(blob_6MB.hash, blob_6MB.length, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+		streamOut.reset();
+		assertEquals(Status.Available, filestore().downloadBlob(blob_6MB.hash, u, r, streamOut));
+		assertArrayEquals(blob_6MB.blob, streamOut.toByteArray());
+		
+		//Confirm the relevant files exist
+		assertTrue("Authenticated user did not save zero length file!", filestore().getStoragePath(blob_zero.hash).exists());
+		assertTrue("Authenticated user did not save 512KB file!", filestore().getStoragePath(blob_512KB.hash).exists());
+		assertTrue("Authenticated user did not save 6MB file!", filestore().getStoragePath(blob_6MB.hash).exists());
+		
+		//Clear the files and cache to test upload limit property
+		FileUtils.delete(filestore().getStorageFolder());
+		filestore().clearFilestoreCache();
+		
+		settings().overrideSetting(Keys.filestore.maxUploadSize, download_limit_test);
+		
+		assertEquals(Status.Available, filestore().uploadBlob(blob_512KB.hash, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+		streamOut.reset();
+		assertEquals(Status.Available, filestore().downloadBlob(blob_512KB.hash, u, r, streamOut));
+		assertArrayEquals(blob_512KB.blob, streamOut.toByteArray());
+		
+		assertEquals(Status.Error_Exceeds_Size_Limit, filestore().uploadBlob(blob_6MB.hash, blob_6MB.length, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+		streamOut.reset();
+		assertEquals(Status.Unavailable, filestore().downloadBlob(blob_6MB.hash, u, r, streamOut));
+		
+		assertTrue("Authenticated user did not save 512KB file!", filestore().getStoragePath(blob_512KB.hash).exists());
+		assertFalse("Authenticated user saved 6MB file (over filesize limit)!", filestore().getStoragePath(blob_6MB.hash).exists());
+		
+	}
+	
+	@Test
+	public void testAnonymousAccess() throws Exception {
+		
+		FileUtils.delete(filestore().getStorageFolder());
+		filestore().clearFilestoreCache();
+		
+		RepositoryModel r = new RepositoryModel("myrepo.git", null, null, new Date());
+		r.authorizationControl = AuthorizationControl.NAMED;
+		r.accessRestriction = AccessRestrictionType.CLONE;
+
+		ByteArrayOutputStream streamOut = new ByteArrayOutputStream();
+
+		UserModel u = UserModel.ANONYMOUS;
+
+		//No upload limit
+		settings().overrideSetting(Keys.filestore.maxUploadSize, download_limit_default);
+		
+		//Invalid hash tests
+		assertEquals(Status.Error_Invalid_Oid, filestore().downloadBlob(invalid_hash_major, u, r, streamOut));
+		assertEquals(Status.Error_Invalid_Oid, filestore().downloadBlob(invalid_hash_regex_attack, u, r, streamOut));
+		assertEquals(Status.Error_Invalid_Oid, filestore().downloadBlob(invalid_hash_one_long, u, r, streamOut));
+		assertEquals(Status.Error_Invalid_Oid, filestore().downloadBlob(invalid_hash_one_short, u, r, streamOut));
+		
+		// Download prior to upload
+		streamOut.reset();
+		assertEquals(Status.Unavailable, filestore().downloadBlob(blob_512KB.hash, u, r, streamOut));
+		streamOut.reset();
+		assertEquals(Status.Unavailable, filestore().downloadBlob(blob_512KB.hash, u, r, streamOut));
+		
+		//Bad input is rejected with no upload taking place
+		assertEquals(Status.AuthenticationRequired, filestore().uploadBlob(invalid_hash_empty, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+		assertEquals(Status.AuthenticationRequired, filestore().uploadBlob(invalid_hash_major, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+		assertEquals(Status.AuthenticationRequired, filestore().uploadBlob(invalid_hash_regex_attack, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+		assertEquals(Status.AuthenticationRequired, filestore().uploadBlob(invalid_hash_one_long, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+		assertEquals(Status.AuthenticationRequired, filestore().uploadBlob(invalid_hash_one_short, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+		
+		assertEquals(Status.AuthenticationRequired, filestore().uploadBlob(blob_512KB.hash, -1, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+
+		assertEquals(Status.AuthenticationRequired, filestore().uploadBlob(blob_512KB.hash, 0, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+		assertEquals(Status.AuthenticationRequired, filestore().uploadBlob(blob_512KB.hash, blob_512KB.length-1, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+		assertEquals(Status.AuthenticationRequired, filestore().uploadBlob(blob_512KB.hash, blob_512KB.length+1, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+		
+		assertEquals(Status.AuthenticationRequired, filestore().uploadBlob(blob_zero.hash, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+
+		//Confirm no upload with bad input
+		streamOut.reset();
+		assertEquals(Status.Unavailable, filestore().downloadBlob(blob_512KB.hash, u, r, streamOut));
+		
+		//Good input will accept the upload
+		assertEquals(Status.AuthenticationRequired, filestore().uploadBlob(blob_512KB.hash, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+		streamOut.reset();
+		assertEquals(Status.Unavailable, filestore().downloadBlob(blob_512KB.hash, u, r, streamOut));
+		
+		//Subsequent failed uploads do not affect file
+		assertEquals(Status.AuthenticationRequired, filestore().uploadBlob(blob_512KB.hash, blob_512KB.length-1, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+		assertEquals(Status.AuthenticationRequired, filestore().uploadBlob(blob_512KB.hash, blob_512KB.length+1, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+		
+		streamOut.reset();
+		assertEquals(Status.Unavailable, filestore().downloadBlob(blob_512KB.hash, u, r, streamOut));
+		
+		//Zero length upload is valid
+		assertEquals(Status.AuthenticationRequired, filestore().uploadBlob(blob_zero.hash, blob_zero.length, u, r, new ByteArrayInputStream(blob_zero.blob)));
+		
+		streamOut.reset();
+		assertEquals(Status.Unavailable, filestore().downloadBlob(blob_zero.hash, u, r, streamOut));
+		
+		
+		//Pre-informed upload identifies identical errors as immediate upload
+		assertEquals(Status.AuthenticationRequired, filestore().addObject(blob_6MB.hash, blob_6MB.length, u, r));
+		streamOut.reset();
+		assertEquals(Status.Unavailable, filestore().downloadBlob(blob_6MB.hash, u, r, streamOut));
+		
+		assertEquals(Status.AuthenticationRequired, filestore().uploadBlob(invalid_hash_empty, blob_6MB.length, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+		assertEquals(Status.AuthenticationRequired, filestore().uploadBlob(invalid_hash_major, blob_6MB.length, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+		assertEquals(Status.AuthenticationRequired, filestore().uploadBlob(invalid_hash_regex_attack, blob_6MB.length, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+		assertEquals(Status.AuthenticationRequired, filestore().uploadBlob(invalid_hash_one_long, blob_6MB.length, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+		assertEquals(Status.AuthenticationRequired, filestore().uploadBlob(invalid_hash_one_short, blob_6MB.length, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+		
+		assertEquals(Status.AuthenticationRequired, filestore().uploadBlob(blob_6MB.hash, -1, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+		
+		assertEquals(Status.AuthenticationRequired, filestore().uploadBlob(blob_6MB.hash, 0, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+		assertEquals(Status.AuthenticationRequired, filestore().uploadBlob(blob_6MB.hash, blob_6MB.length-1, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+		assertEquals(Status.AuthenticationRequired, filestore().uploadBlob(blob_6MB.hash, blob_6MB.length+1, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+		
+		streamOut.reset();
+		assertEquals(Status.Unavailable, filestore().downloadBlob(blob_6MB.hash, u, r, streamOut));
+		
+		//Good input will accept the upload
+		assertEquals(Status.AuthenticationRequired, filestore().uploadBlob(blob_6MB.hash, blob_6MB.length, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+		streamOut.reset();
+		assertEquals(Status.Unavailable, filestore().downloadBlob(blob_6MB.hash, u, r, streamOut));
+		
+		//Confirm the relevant files do not exist
+		assertFalse("Anonymous user saved zero length file!", filestore().getStoragePath(blob_zero.hash).exists());
+		assertFalse("Anonymous user 512KB file!", filestore().getStoragePath(blob_512KB.hash).exists());
+		assertFalse("Anonymous user 6MB file!", filestore().getStoragePath(blob_6MB.hash).exists());
+		
+		//Clear the files and cache to test upload limit property
+		FileUtils.delete(filestore().getStorageFolder());
+		filestore().clearFilestoreCache();
+		
+		settings().overrideSetting(Keys.filestore.maxUploadSize, download_limit_test);
+		
+		assertEquals(Status.AuthenticationRequired, filestore().uploadBlob(blob_512KB.hash, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+		streamOut.reset();
+		assertEquals(Status.Unavailable, filestore().downloadBlob(blob_512KB.hash, u, r, streamOut));
+		
+		assertEquals(Status.AuthenticationRequired, filestore().uploadBlob(blob_6MB.hash, blob_6MB.length, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+		streamOut.reset();
+		assertEquals(Status.Unavailable, filestore().downloadBlob(blob_6MB.hash, u, r, streamOut));
+		
+		assertFalse("Anonymous user saved 512KB file!", filestore().getStoragePath(blob_512KB.hash).exists());
+		assertFalse("Anonymous user saved 6MB file (over filesize limit)!", filestore().getStoragePath(blob_6MB.hash).exists());
+		
+	}
+	
+	@Test
+	public void testUnauthorizedAccess() throws Exception {
+		
+		FileUtils.delete(filestore().getStorageFolder());
+		filestore().clearFilestoreCache();
+		
+		RepositoryModel r = new RepositoryModel("myrepo.git", null, null, new Date());
+		r.authorizationControl = AuthorizationControl.NAMED;
+		r.accessRestriction = AccessRestrictionType.VIEW;
+		
+		ByteArrayOutputStream streamOut = new ByteArrayOutputStream();
+		
+		UserModel u = new UserModel("test");
+		u.setRepositoryPermission(r.name, AccessPermission.CLONE);
+		
+		//No upload limit
+		settings().overrideSetting(Keys.filestore.maxUploadSize, download_limit_default);
+		
+		//Invalid hash tests
+		assertEquals(Status.Error_Invalid_Oid, filestore().downloadBlob(invalid_hash_major, u, r, streamOut));
+		assertEquals(Status.Error_Invalid_Oid, filestore().downloadBlob(invalid_hash_regex_attack, u, r, streamOut));
+		assertEquals(Status.Error_Invalid_Oid, filestore().downloadBlob(invalid_hash_one_long, u, r, streamOut));
+		assertEquals(Status.Error_Invalid_Oid, filestore().downloadBlob(invalid_hash_one_short, u, r, streamOut));
+		
+		// Download prior to upload
+		streamOut.reset();
+		assertEquals(Status.Unavailable, filestore().downloadBlob(blob_512KB.hash, u, r, streamOut));
+		streamOut.reset();
+		assertEquals(Status.Unavailable, filestore().downloadBlob(blob_512KB.hash, u, r, streamOut));
+		
+		//Bad input is rejected with no upload taking place
+		assertEquals(Status.Error_Unauthorized, filestore().uploadBlob(invalid_hash_major, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+		assertEquals(Status.Error_Unauthorized, filestore().uploadBlob(invalid_hash_regex_attack, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+		assertEquals(Status.Error_Unauthorized, filestore().uploadBlob(invalid_hash_one_long, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+		assertEquals(Status.Error_Unauthorized, filestore().uploadBlob(invalid_hash_empty, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+		assertEquals(Status.Error_Unauthorized, filestore().uploadBlob(invalid_hash_one_short, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+		
+		assertEquals(Status.Error_Unauthorized, filestore().uploadBlob(blob_512KB.hash, -1, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+
+		assertEquals(Status.Error_Unauthorized, filestore().uploadBlob(blob_512KB.hash, 0, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+		assertEquals(Status.Error_Unauthorized, filestore().uploadBlob(blob_512KB.hash, blob_512KB.length-1, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+		assertEquals(Status.Error_Unauthorized, filestore().uploadBlob(blob_512KB.hash, blob_512KB.length+1, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+		
+		assertEquals(Status.Error_Unauthorized, filestore().uploadBlob(blob_zero.hash, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+
+		//Confirm no upload with bad input
+		streamOut.reset();
+		assertEquals(Status.Unavailable, filestore().downloadBlob(blob_512KB.hash, u, r, streamOut));
+		
+		//Good input will accept the upload
+		assertEquals(Status.Error_Unauthorized, filestore().uploadBlob(blob_512KB.hash, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+		streamOut.reset();
+		assertEquals(Status.Unavailable, filestore().downloadBlob(blob_512KB.hash, u, r, streamOut));
+		
+		//Subsequent failed uploads do not affect file
+		assertEquals(Status.Error_Unauthorized, filestore().uploadBlob(blob_512KB.hash, blob_512KB.length-1, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+		assertEquals(Status.Error_Unauthorized, filestore().uploadBlob(blob_512KB.hash, blob_512KB.length+1, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+		
+		streamOut.reset();
+		assertEquals(Status.Unavailable, filestore().downloadBlob(blob_512KB.hash, u, r, streamOut));
+		
+		//Zero length upload is valid
+		assertEquals(Status.Error_Unauthorized, filestore().uploadBlob(blob_zero.hash, blob_zero.length, u, r, new ByteArrayInputStream(blob_zero.blob)));
+		
+		streamOut.reset();
+		assertEquals(Status.Unavailable, filestore().downloadBlob(blob_zero.hash, u, r, streamOut));
+		
+		
+		//Pre-informed upload identifies identical errors as immediate upload
+		assertEquals(Status.Error_Unauthorized, filestore().addObject(blob_6MB.hash, blob_6MB.length, u, r));
+		streamOut.reset();
+		assertEquals(Status.Unavailable, filestore().downloadBlob(blob_6MB.hash, u, r, streamOut));
+		
+		assertEquals(Status.Error_Unauthorized, filestore().uploadBlob(invalid_hash_empty, blob_6MB.length, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+		assertEquals(Status.Error_Unauthorized, filestore().uploadBlob(invalid_hash_major, blob_6MB.length, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+		assertEquals(Status.Error_Unauthorized, filestore().uploadBlob(invalid_hash_regex_attack, blob_6MB.length, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+		assertEquals(Status.Error_Unauthorized, filestore().uploadBlob(invalid_hash_one_long, blob_6MB.length, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+		assertEquals(Status.Error_Unauthorized, filestore().uploadBlob(invalid_hash_one_short, blob_6MB.length, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+		
+		assertEquals(Status.Error_Unauthorized, filestore().uploadBlob(blob_6MB.hash, -1, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+		
+		assertEquals(Status.Error_Unauthorized, filestore().uploadBlob(blob_6MB.hash, 0, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+		assertEquals(Status.Error_Unauthorized, filestore().uploadBlob(blob_6MB.hash, blob_6MB.length-1, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+		assertEquals(Status.Error_Unauthorized, filestore().uploadBlob(blob_6MB.hash, blob_6MB.length+1, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+		
+		streamOut.reset();
+		assertEquals(Status.Unavailable, filestore().downloadBlob(blob_6MB.hash, u, r, streamOut));
+		
+		//Good input will accept the upload
+		assertEquals(Status.Error_Unauthorized, filestore().uploadBlob(blob_6MB.hash, blob_6MB.length, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+		streamOut.reset();
+		assertEquals(Status.Unavailable, filestore().downloadBlob(blob_6MB.hash, u, r, streamOut));
+		
+		//Confirm the relevant files exist
+		assertFalse("Unauthorized user saved zero length file!", filestore().getStoragePath(blob_zero.hash).exists());
+		assertFalse("Unauthorized user saved 512KB file!", filestore().getStoragePath(blob_512KB.hash).exists());
+		assertFalse("Unauthorized user saved 6MB file!", filestore().getStoragePath(blob_6MB.hash).exists());
+		
+		//Clear the files and cache to test upload limit property
+		FileUtils.delete(filestore().getStorageFolder());
+		filestore().clearFilestoreCache();
+		
+		settings().overrideSetting(Keys.filestore.maxUploadSize, download_limit_test);
+		
+		assertEquals(Status.Error_Unauthorized, filestore().uploadBlob(blob_512KB.hash, blob_512KB.length, u, r, new ByteArrayInputStream(blob_512KB.blob)));
+		streamOut.reset();
+		assertEquals(Status.Unavailable, filestore().downloadBlob(blob_512KB.hash, u, r, streamOut));
+		
+		assertEquals(Status.Error_Unauthorized, filestore().uploadBlob(blob_6MB.hash, blob_6MB.length, u, r, new ByteArrayInputStream(blob_6MB.blob)));
+		streamOut.reset();
+		assertEquals(Status.Unavailable, filestore().downloadBlob(blob_6MB.hash, u, r, streamOut));
+		
+		assertFalse("Unauthorized user saved 512KB file!", filestore().getStoragePath(blob_512KB.hash).exists());
+		assertFalse("Unauthorized user saved 6MB file (over filesize limit)!", filestore().getStoragePath(blob_6MB.hash).exists());
+		
+	}
+	
+}
+
+/*
+ * Test helper structure to create blobs of a given size
+ */
+final class BlobInfo {
+	public byte[] blob;
+	public String hash;
+	public int length;
+	
+	public BlobInfo(int nBytes) {
+		blob = new byte[nBytes];
+		new java.util.Random().nextBytes(blob);
+		hash = DigestUtils.sha256Hex(blob);
+		length = nBytes;
+	}
+}
\ No newline at end of file

--
Gitblit v1.9.1