Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

GitServletTest.java 30KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803
  1. package com.gitblit.tests;
  2. import static org.junit.Assert.assertEquals;
  3. import static org.junit.Assert.assertFalse;
  4. import static org.junit.Assert.assertTrue;
  5. import java.io.BufferedWriter;
  6. import java.io.File;
  7. import java.io.FileOutputStream;
  8. import java.io.IOException;
  9. import java.io.OutputStreamWriter;
  10. import java.text.MessageFormat;
  11. import java.util.Date;
  12. import java.util.List;
  13. import java.util.concurrent.atomic.AtomicBoolean;
  14. import org.eclipse.jgit.api.CloneCommand;
  15. import org.eclipse.jgit.api.Git;
  16. import org.eclipse.jgit.api.ResetCommand.ResetType;
  17. import org.eclipse.jgit.api.errors.GitAPIException;
  18. import org.eclipse.jgit.lib.Constants;
  19. import org.eclipse.jgit.lib.Repository;
  20. import org.eclipse.jgit.revwalk.RevCommit;
  21. import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
  22. import org.eclipse.jgit.transport.CredentialsProvider;
  23. import org.eclipse.jgit.transport.PushResult;
  24. import org.eclipse.jgit.transport.RefSpec;
  25. import org.eclipse.jgit.transport.RemoteRefUpdate;
  26. import org.eclipse.jgit.transport.RemoteRefUpdate.Status;
  27. import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
  28. import org.eclipse.jgit.util.FileUtils;
  29. import org.junit.AfterClass;
  30. import org.junit.BeforeClass;
  31. import org.junit.Test;
  32. import com.gitblit.Constants.AccessPermission;
  33. import com.gitblit.Constants.AccessRestrictionType;
  34. import com.gitblit.Constants.AuthorizationControl;
  35. import com.gitblit.GitBlit;
  36. import com.gitblit.Keys;
  37. import com.gitblit.models.RefLogEntry;
  38. import com.gitblit.models.RepositoryModel;
  39. import com.gitblit.models.UserModel;
  40. import com.gitblit.utils.ArrayUtils;
  41. import com.gitblit.utils.JGitUtils;
  42. import com.gitblit.utils.RefLogUtils;
  43. public class GitServletTest {
  44. static File ticgitFolder = new File(GitBlitSuite.REPOSITORIES, "working/ticgit");
  45. static File ticgit2Folder = new File(GitBlitSuite.REPOSITORIES, "working/ticgit2");
  46. static File jgitFolder = new File(GitBlitSuite.REPOSITORIES, "working/jgit");
  47. static File jgit2Folder = new File(GitBlitSuite.REPOSITORIES, "working/jgit2");
  48. String url = GitBlitSuite.gitServletUrl;
  49. String account = GitBlitSuite.account;
  50. String password = GitBlitSuite.password;
  51. private static final AtomicBoolean started = new AtomicBoolean(false);
  52. private static UserModel getUser() {
  53. UserModel user = new UserModel("james");
  54. user.password = "james";
  55. return user;
  56. }
  57. private static void delete(UserModel user) {
  58. if (GitBlit.self().getUserModel(user.username) != null) {
  59. GitBlit.self().deleteUser(user.username);
  60. }
  61. }
  62. @BeforeClass
  63. public static void startGitblit() throws Exception {
  64. started.set(GitBlitSuite.startGitblit());
  65. delete(getUser());
  66. }
  67. @AfterClass
  68. public static void stopGitblit() throws Exception {
  69. if (started.get()) {
  70. GitBlitSuite.stopGitblit();
  71. deleteWorkingFolders();
  72. }
  73. delete(getUser());
  74. }
  75. public static void deleteWorkingFolders() throws Exception {
  76. if (ticgitFolder.exists()) {
  77. GitBlitSuite.close(ticgitFolder);
  78. FileUtils.delete(ticgitFolder, FileUtils.RECURSIVE);
  79. }
  80. if (ticgit2Folder.exists()) {
  81. GitBlitSuite.close(ticgit2Folder);
  82. FileUtils.delete(ticgit2Folder, FileUtils.RECURSIVE);
  83. }
  84. if (jgitFolder.exists()) {
  85. GitBlitSuite.close(jgitFolder);
  86. FileUtils.delete(jgitFolder, FileUtils.RECURSIVE);
  87. }
  88. if (jgit2Folder.exists()) {
  89. GitBlitSuite.close(jgit2Folder);
  90. FileUtils.delete(jgit2Folder, FileUtils.RECURSIVE);
  91. }
  92. }
  93. @Test
  94. public void testClone() throws Exception {
  95. GitBlitSuite.close(ticgitFolder);
  96. if (ticgitFolder.exists()) {
  97. FileUtils.delete(ticgitFolder, FileUtils.RECURSIVE | FileUtils.RETRY);
  98. }
  99. CloneCommand clone = Git.cloneRepository();
  100. clone.setURI(MessageFormat.format("{0}/ticgit.git", url));
  101. clone.setDirectory(ticgitFolder);
  102. clone.setBare(false);
  103. clone.setCloneAllBranches(true);
  104. clone.setCredentialsProvider(new UsernamePasswordCredentialsProvider(account, password));
  105. GitBlitSuite.close(clone.call());
  106. assertTrue(true);
  107. }
  108. @Test
  109. public void testBogusLoginClone() throws Exception {
  110. // restrict repository access
  111. RepositoryModel model = GitBlit.self().getRepositoryModel("ticgit.git");
  112. model.accessRestriction = AccessRestrictionType.CLONE;
  113. GitBlit.self().updateRepositoryModel(model.name, model, false);
  114. // delete any existing working folder
  115. boolean cloned = false;
  116. try {
  117. CloneCommand clone = Git.cloneRepository();
  118. clone.setURI(MessageFormat.format("{0}/ticgit.git", url));
  119. clone.setDirectory(ticgit2Folder);
  120. clone.setBare(false);
  121. clone.setCloneAllBranches(true);
  122. clone.setCredentialsProvider(new UsernamePasswordCredentialsProvider("bogus", "bogus"));
  123. GitBlitSuite.close(clone.call());
  124. cloned = true;
  125. } catch (Exception e) {
  126. // swallow the exception which we expect
  127. }
  128. // restore anonymous repository access
  129. model.accessRestriction = AccessRestrictionType.NONE;
  130. GitBlit.self().updateRepositoryModel(model.name, model, false);
  131. assertFalse("Bogus login cloned a repository?!", cloned);
  132. }
  133. @Test
  134. public void testUnauthorizedLoginClone() throws Exception {
  135. // restrict repository access
  136. RepositoryModel model = GitBlit.self().getRepositoryModel("ticgit.git");
  137. model.accessRestriction = AccessRestrictionType.CLONE;
  138. model.authorizationControl = AuthorizationControl.NAMED;
  139. UserModel user = new UserModel("james");
  140. user.password = "james";
  141. GitBlit.self().updateUserModel(user.username, user, true);
  142. GitBlit.self().updateRepositoryModel(model.name, model, false);
  143. FileUtils.delete(ticgit2Folder, FileUtils.RECURSIVE);
  144. // delete any existing working folder
  145. boolean cloned = false;
  146. try {
  147. CloneCommand clone = Git.cloneRepository();
  148. clone.setURI(MessageFormat.format("{0}/ticgit.git", url));
  149. clone.setDirectory(ticgit2Folder);
  150. clone.setBare(false);
  151. clone.setCloneAllBranches(true);
  152. clone.setCredentialsProvider(new UsernamePasswordCredentialsProvider(user.username, user.password));
  153. GitBlitSuite.close(clone.call());
  154. cloned = true;
  155. } catch (Exception e) {
  156. // swallow the exception which we expect
  157. }
  158. assertFalse("Unauthorized login cloned a repository?!", cloned);
  159. FileUtils.delete(ticgit2Folder, FileUtils.RECURSIVE);
  160. // switch to authenticated
  161. model.authorizationControl = AuthorizationControl.AUTHENTICATED;
  162. GitBlit.self().updateRepositoryModel(model.name, model, false);
  163. // try clone again
  164. cloned = false;
  165. CloneCommand clone = Git.cloneRepository();
  166. clone.setURI(MessageFormat.format("{0}/ticgit.git", url));
  167. clone.setDirectory(ticgit2Folder);
  168. clone.setBare(false);
  169. clone.setCloneAllBranches(true);
  170. clone.setCredentialsProvider(new UsernamePasswordCredentialsProvider(user.username, user.password));
  171. GitBlitSuite.close(clone.call());
  172. cloned = true;
  173. assertTrue("Authenticated login could not clone!", cloned);
  174. FileUtils.delete(ticgit2Folder, FileUtils.RECURSIVE);
  175. // restore anonymous repository access
  176. model.accessRestriction = AccessRestrictionType.NONE;
  177. model.authorizationControl = AuthorizationControl.NAMED;
  178. GitBlit.self().updateRepositoryModel(model.name, model, false);
  179. delete(user);
  180. }
  181. @Test
  182. public void testAnonymousPush() throws Exception {
  183. GitBlitSuite.close(ticgitFolder);
  184. if (ticgitFolder.exists()) {
  185. FileUtils.delete(ticgitFolder, FileUtils.RECURSIVE | FileUtils.RETRY);
  186. }
  187. RepositoryModel model = GitBlit.self().getRepositoryModel("ticgit.git");
  188. model.accessRestriction = AccessRestrictionType.NONE;
  189. GitBlit.self().updateRepositoryModel(model.name, model, false);
  190. CloneCommand clone = Git.cloneRepository();
  191. clone.setURI(MessageFormat.format("{0}/ticgit.git", url));
  192. clone.setDirectory(ticgitFolder);
  193. clone.setBare(false);
  194. clone.setCloneAllBranches(true);
  195. clone.setCredentialsProvider(new UsernamePasswordCredentialsProvider(account, password));
  196. GitBlitSuite.close(clone.call());
  197. assertTrue(true);
  198. Git git = Git.open(ticgitFolder);
  199. File file = new File(ticgitFolder, "TODO");
  200. OutputStreamWriter os = new OutputStreamWriter(new FileOutputStream(file, true), Constants.CHARSET);
  201. BufferedWriter w = new BufferedWriter(os);
  202. w.write("// hellol中文 " + new Date().toString() + "\n");
  203. w.close();
  204. git.add().addFilepattern(file.getName()).call();
  205. git.commit().setMessage("test commit").call();
  206. Iterable<PushResult> results = git.push().setPushAll().call();
  207. GitBlitSuite.close(git);
  208. for (PushResult result : results) {
  209. for (RemoteRefUpdate update : result.getRemoteUpdates()) {
  210. assertEquals(Status.OK, update.getStatus());
  211. }
  212. }
  213. }
  214. @Test
  215. public void testSubfolderPush() throws Exception {
  216. GitBlitSuite.close(jgitFolder);
  217. if (jgitFolder.exists()) {
  218. FileUtils.delete(jgitFolder, FileUtils.RECURSIVE | FileUtils.RETRY);
  219. }
  220. CloneCommand clone = Git.cloneRepository();
  221. clone.setURI(MessageFormat.format("{0}/test/jgit.git", url));
  222. clone.setDirectory(jgitFolder);
  223. clone.setBare(false);
  224. clone.setCloneAllBranches(true);
  225. clone.setCredentialsProvider(new UsernamePasswordCredentialsProvider(account, password));
  226. GitBlitSuite.close(clone.call());
  227. assertTrue(true);
  228. Git git = Git.open(jgitFolder);
  229. File file = new File(jgitFolder, "TODO");
  230. OutputStreamWriter os = new OutputStreamWriter(new FileOutputStream(file, true), Constants.CHARSET);
  231. BufferedWriter w = new BufferedWriter(os);
  232. w.write("// " + new Date().toString() + "\n");
  233. w.close();
  234. git.add().addFilepattern(file.getName()).call();
  235. git.commit().setMessage("test commit").call();
  236. Iterable<PushResult> results = git.push().setPushAll().setCredentialsProvider(new UsernamePasswordCredentialsProvider(account, password)).call();
  237. GitBlitSuite.close(git);
  238. for (PushResult result : results) {
  239. for (RemoteRefUpdate update : result.getRemoteUpdates()) {
  240. assertEquals(Status.OK, update.getStatus());
  241. }
  242. }
  243. }
  244. @Test
  245. public void testPushToFrozenRepo() throws Exception {
  246. GitBlitSuite.close(jgitFolder);
  247. if (jgitFolder.exists()) {
  248. FileUtils.delete(jgitFolder, FileUtils.RECURSIVE | FileUtils.RETRY);
  249. }
  250. CloneCommand clone = Git.cloneRepository();
  251. clone.setURI(MessageFormat.format("{0}/test/jgit.git", url));
  252. clone.setDirectory(jgitFolder);
  253. clone.setBare(false);
  254. clone.setCloneAllBranches(true);
  255. clone.setCredentialsProvider(new UsernamePasswordCredentialsProvider(account, password));
  256. GitBlitSuite.close(clone.call());
  257. assertTrue(true);
  258. // freeze repo
  259. RepositoryModel model = GitBlit.self().getRepositoryModel("test/jgit.git");
  260. model.isFrozen = true;
  261. GitBlit.self().updateRepositoryModel(model.name, model, false);
  262. Git git = Git.open(jgitFolder);
  263. File file = new File(jgitFolder, "TODO");
  264. OutputStreamWriter os = new OutputStreamWriter(new FileOutputStream(file, true), Constants.CHARSET);
  265. BufferedWriter w = new BufferedWriter(os);
  266. w.write("// " + new Date().toString() + "\n");
  267. w.close();
  268. git.add().addFilepattern(file.getName()).call();
  269. git.commit().setMessage("test commit").call();
  270. Iterable<PushResult> results = git.push().setPushAll().setCredentialsProvider(new UsernamePasswordCredentialsProvider(account, password)).call();
  271. for (PushResult result : results) {
  272. for (RemoteRefUpdate update : result.getRemoteUpdates()) {
  273. assertEquals(Status.REJECTED_OTHER_REASON, update.getStatus());
  274. }
  275. }
  276. // unfreeze repo
  277. model.isFrozen = false;
  278. GitBlit.self().updateRepositoryModel(model.name, model, false);
  279. results = git.push().setPushAll().setCredentialsProvider(new UsernamePasswordCredentialsProvider(account, password)).call();
  280. GitBlitSuite.close(git);
  281. for (PushResult result : results) {
  282. for (RemoteRefUpdate update : result.getRemoteUpdates()) {
  283. assertEquals(Status.OK, update.getStatus());
  284. }
  285. }
  286. }
  287. @Test
  288. public void testPushToNonBareRepository() throws Exception {
  289. CloneCommand clone = Git.cloneRepository();
  290. clone.setURI(MessageFormat.format("{0}/working/jgit", url));
  291. clone.setDirectory(jgit2Folder);
  292. clone.setBare(false);
  293. clone.setCloneAllBranches(true);
  294. clone.setCredentialsProvider(new UsernamePasswordCredentialsProvider(account, password));
  295. GitBlitSuite.close(clone.call());
  296. assertTrue(true);
  297. Git git = Git.open(jgit2Folder);
  298. File file = new File(jgit2Folder, "NONBARE");
  299. OutputStreamWriter os = new OutputStreamWriter(new FileOutputStream(file, true), Constants.CHARSET);
  300. BufferedWriter w = new BufferedWriter(os);
  301. w.write("// " + new Date().toString() + "\n");
  302. w.close();
  303. git.add().addFilepattern(file.getName()).call();
  304. git.commit().setMessage("test commit followed by push to non-bare repository").call();
  305. Iterable<PushResult> results = git.push().setPushAll().setCredentialsProvider(new UsernamePasswordCredentialsProvider(account, password)).call();
  306. GitBlitSuite.close(git);
  307. for (PushResult result : results) {
  308. for (RemoteRefUpdate update : result.getRemoteUpdates()) {
  309. assertEquals(Status.REJECTED_OTHER_REASON, update.getStatus());
  310. }
  311. }
  312. }
  313. @Test
  314. public void testCommitterVerification() throws Exception {
  315. UserModel user = getUser();
  316. // account only uses account name to verify
  317. testCommitterVerification(user, user.username, null, true);
  318. // committer email address is ignored because account does not specify email
  319. testCommitterVerification(user, user.username, "something", true);
  320. // completely different committer
  321. testCommitterVerification(user, "joe", null, false);
  322. // test display name verification
  323. user.displayName = "James Moger";
  324. testCommitterVerification(user, user.displayName, null, true);
  325. testCommitterVerification(user, user.displayName, "something", true);
  326. testCommitterVerification(user, "joe", null, false);
  327. // test email address verification
  328. user.emailAddress = "something";
  329. testCommitterVerification(user, user.displayName, null, false);
  330. testCommitterVerification(user, user.displayName, "somethingelse", false);
  331. testCommitterVerification(user, user.displayName, user.emailAddress, true);
  332. // use same email address but with different committer
  333. testCommitterVerification(user, "joe", "somethingelse", false);
  334. }
  335. private void testCommitterVerification(UserModel user, String displayName, String emailAddress, boolean expectedSuccess) throws Exception {
  336. delete(user);
  337. CredentialsProvider cp = new UsernamePasswordCredentialsProvider(user.username, user.password);
  338. // fork from original to a temporary bare repo
  339. File verification = new File(GitBlitSuite.REPOSITORIES, "refchecks/verify-committer.git");
  340. if (verification.exists()) {
  341. FileUtils.delete(verification, FileUtils.RECURSIVE);
  342. }
  343. CloneCommand clone = Git.cloneRepository();
  344. clone.setURI(MessageFormat.format("{0}/ticgit.git", url));
  345. clone.setDirectory(verification);
  346. clone.setBare(true);
  347. clone.setCloneAllBranches(true);
  348. clone.setCredentialsProvider(cp);
  349. GitBlitSuite.close(clone.call());
  350. // require push permissions and committer verification
  351. RepositoryModel model = GitBlit.self().getRepositoryModel("refchecks/verify-committer.git");
  352. model.authorizationControl = AuthorizationControl.NAMED;
  353. model.accessRestriction = AccessRestrictionType.PUSH;
  354. model.verifyCommitter = true;
  355. // grant user push permission
  356. user.setRepositoryPermission(model.name, AccessPermission.PUSH);
  357. GitBlit.self().updateUserModel(user.username, user, true);
  358. GitBlit.self().updateRepositoryModel(model.name, model, false);
  359. // clone temp bare repo to working copy
  360. File local = new File(GitBlitSuite.REPOSITORIES, "refchecks/verify-wc");
  361. if (local.exists()) {
  362. FileUtils.delete(local, FileUtils.RECURSIVE);
  363. }
  364. clone = Git.cloneRepository();
  365. clone.setURI(MessageFormat.format("{0}/{1}", url, model.name));
  366. clone.setDirectory(local);
  367. clone.setBare(false);
  368. clone.setCloneAllBranches(true);
  369. clone.setCredentialsProvider(cp);
  370. GitBlitSuite.close(clone.call());
  371. Git git = Git.open(local);
  372. // force an identity which may or may not match the account's identity
  373. git.getRepository().getConfig().setString("user", null, "name", displayName);
  374. git.getRepository().getConfig().setString("user", null, "email", emailAddress);
  375. git.getRepository().getConfig().save();
  376. // commit a file and push it
  377. File file = new File(local, "PUSHCHK");
  378. OutputStreamWriter os = new OutputStreamWriter(new FileOutputStream(file, true), Constants.CHARSET);
  379. BufferedWriter w = new BufferedWriter(os);
  380. w.write("// " + new Date().toString() + "\n");
  381. w.close();
  382. git.add().addFilepattern(file.getName()).call();
  383. git.commit().setMessage("push test").call();
  384. Iterable<PushResult> results = git.push().setCredentialsProvider(cp).setRemote("origin").call();
  385. for (PushResult result : results) {
  386. RemoteRefUpdate ref = result.getRemoteUpdate("refs/heads/master");
  387. Status status = ref.getStatus();
  388. if (expectedSuccess) {
  389. assertTrue("Verification failed! User was NOT able to push commit! " + status.name(), Status.OK.equals(status));
  390. } else {
  391. assertTrue("Verification failed! User was able to push commit! " + status.name(), Status.REJECTED_OTHER_REASON.equals(status));
  392. }
  393. }
  394. GitBlitSuite.close(git);
  395. // close serving repository
  396. GitBlitSuite.close(verification);
  397. }
  398. @Test
  399. public void testBlockClone() throws Exception {
  400. testRefChange(AccessPermission.VIEW, null, null, null);
  401. }
  402. @Test
  403. public void testBlockPush() throws Exception {
  404. testRefChange(AccessPermission.CLONE, null, null, null);
  405. }
  406. @Test
  407. public void testBlockBranchCreation() throws Exception {
  408. testRefChange(AccessPermission.PUSH, Status.REJECTED_OTHER_REASON, null, null);
  409. }
  410. @Test
  411. public void testBlockBranchDeletion() throws Exception {
  412. testRefChange(AccessPermission.CREATE, Status.OK, Status.REJECTED_OTHER_REASON, null);
  413. }
  414. @Test
  415. public void testBlockBranchRewind() throws Exception {
  416. testRefChange(AccessPermission.DELETE, Status.OK, Status.OK, Status.REJECTED_OTHER_REASON);
  417. }
  418. @Test
  419. public void testBranchRewind() throws Exception {
  420. testRefChange(AccessPermission.REWIND, Status.OK, Status.OK, Status.OK);
  421. }
  422. private void testRefChange(AccessPermission permission, Status expectedCreate, Status expectedDelete, Status expectedRewind) throws Exception {
  423. UserModel user = getUser();
  424. delete(user);
  425. CredentialsProvider cp = new UsernamePasswordCredentialsProvider(user.username, user.password);
  426. // fork from original to a temporary bare repo
  427. File refChecks = new File(GitBlitSuite.REPOSITORIES, "refchecks/ticgit.git");
  428. if (refChecks.exists()) {
  429. FileUtils.delete(refChecks, FileUtils.RECURSIVE);
  430. }
  431. CloneCommand clone = Git.cloneRepository();
  432. clone.setURI(MessageFormat.format("{0}/ticgit.git", url));
  433. clone.setDirectory(refChecks);
  434. clone.setBare(true);
  435. clone.setCloneAllBranches(true);
  436. clone.setCredentialsProvider(cp);
  437. GitBlitSuite.close(clone.call());
  438. // elevate repository to clone permission
  439. RepositoryModel model = GitBlit.self().getRepositoryModel("refchecks/ticgit.git");
  440. switch (permission) {
  441. case VIEW:
  442. model.accessRestriction = AccessRestrictionType.CLONE;
  443. break;
  444. case CLONE:
  445. model.accessRestriction = AccessRestrictionType.CLONE;
  446. break;
  447. default:
  448. model.accessRestriction = AccessRestrictionType.PUSH;
  449. }
  450. model.authorizationControl = AuthorizationControl.NAMED;
  451. // grant user specified
  452. user.setRepositoryPermission(model.name, permission);
  453. GitBlit.self().updateUserModel(user.username, user, true);
  454. GitBlit.self().updateRepositoryModel(model.name, model, false);
  455. // clone temp bare repo to working copy
  456. File local = new File(GitBlitSuite.REPOSITORIES, "refchecks/ticgit-wc");
  457. if (local.exists()) {
  458. FileUtils.delete(local, FileUtils.RECURSIVE);
  459. }
  460. clone = Git.cloneRepository();
  461. clone.setURI(MessageFormat.format("{0}/{1}", url, model.name));
  462. clone.setDirectory(local);
  463. clone.setBare(false);
  464. clone.setCloneAllBranches(true);
  465. clone.setCredentialsProvider(cp);
  466. try {
  467. GitBlitSuite.close(clone.call());
  468. } catch (GitAPIException e) {
  469. if (permission.atLeast(AccessPermission.CLONE)) {
  470. throw e;
  471. } else {
  472. // close serving repository
  473. GitBlitSuite.close(refChecks);
  474. // user does not have clone permission
  475. assertTrue(e.getMessage(), e.getMessage().contains("not permitted"));
  476. return;
  477. }
  478. }
  479. Git git = Git.open(local);
  480. // commit a file and push it
  481. File file = new File(local, "PUSHCHK");
  482. OutputStreamWriter os = new OutputStreamWriter(new FileOutputStream(file, true), Constants.CHARSET);
  483. BufferedWriter w = new BufferedWriter(os);
  484. w.write("// " + new Date().toString() + "\n");
  485. w.close();
  486. git.add().addFilepattern(file.getName()).call();
  487. git.commit().setMessage("push test").call();
  488. Iterable<PushResult> results = null;
  489. try {
  490. results = git.push().setCredentialsProvider(cp).setRemote("origin").call();
  491. } catch (GitAPIException e) {
  492. if (permission.atLeast(AccessPermission.PUSH)) {
  493. throw e;
  494. } else {
  495. // close serving repository
  496. GitBlitSuite.close(refChecks);
  497. // user does not have push permission
  498. assertTrue(e.getMessage(), e.getMessage().contains("not permitted"));
  499. GitBlitSuite.close(git);
  500. return;
  501. }
  502. }
  503. for (PushResult result : results) {
  504. RemoteRefUpdate ref = result.getRemoteUpdate("refs/heads/master");
  505. Status status = ref.getStatus();
  506. if (permission.atLeast(AccessPermission.PUSH)) {
  507. assertTrue("User failed to push commit?! " + status.name(), Status.OK.equals(status));
  508. } else {
  509. // close serving repository
  510. GitBlitSuite.close(refChecks);
  511. assertTrue("User was able to push commit! " + status.name(), Status.REJECTED_OTHER_REASON.equals(status));
  512. GitBlitSuite.close(git);
  513. // skip delete test
  514. return;
  515. }
  516. }
  517. // create a local branch and push the new branch back to the origin
  518. git.branchCreate().setName("protectme").call();
  519. RefSpec refSpec = new RefSpec("refs/heads/protectme:refs/heads/protectme");
  520. results = git.push().setCredentialsProvider(cp).setRefSpecs(refSpec).setRemote("origin").call();
  521. for (PushResult result : results) {
  522. RemoteRefUpdate ref = result.getRemoteUpdate("refs/heads/protectme");
  523. Status status = ref.getStatus();
  524. if (Status.OK.equals(expectedCreate)) {
  525. assertTrue("User failed to push creation?! " + status.name(), status.equals(expectedCreate));
  526. } else {
  527. // close serving repository
  528. GitBlitSuite.close(refChecks);
  529. assertTrue("User was able to push ref creation! " + status.name(), status.equals(expectedCreate));
  530. GitBlitSuite.close(git);
  531. // skip delete test
  532. return;
  533. }
  534. }
  535. // delete the branch locally
  536. git.branchDelete().setBranchNames("protectme").call();
  537. // push a delete ref command
  538. refSpec = new RefSpec(":refs/heads/protectme");
  539. results = git.push().setCredentialsProvider(cp).setRefSpecs(refSpec).setRemote("origin").call();
  540. for (PushResult result : results) {
  541. RemoteRefUpdate ref = result.getRemoteUpdate("refs/heads/protectme");
  542. Status status = ref.getStatus();
  543. if (Status.OK.equals(expectedDelete)) {
  544. assertTrue("User failed to push ref deletion?! " + status.name(), status.equals(Status.OK));
  545. } else {
  546. // close serving repository
  547. GitBlitSuite.close(refChecks);
  548. assertTrue("User was able to push ref deletion?! " + status.name(), status.equals(expectedDelete));
  549. GitBlitSuite.close(git);
  550. // skip rewind test
  551. return;
  552. }
  553. }
  554. // rewind master by two commits
  555. git.reset().setRef("HEAD~2").setMode(ResetType.HARD).call();
  556. // commit a change on this detached HEAD
  557. file = new File(local, "REWINDCHK");
  558. os = new OutputStreamWriter(new FileOutputStream(file, true), Constants.CHARSET);
  559. w = new BufferedWriter(os);
  560. w.write("// " + new Date().toString() + "\n");
  561. w.close();
  562. git.add().addFilepattern(file.getName()).call();
  563. RevCommit commit = git.commit().setMessage("rewind master and new commit").call();
  564. // Reset master to our new commit now we our local branch tip is no longer
  565. // upstream of the remote branch tip. It is an alternate tip of the branch.
  566. JGitUtils.setBranchRef(git.getRepository(), "refs/heads/master", commit.getName());
  567. // Try pushing our new tip to the origin.
  568. // This requires the server to "rewind" it's master branch and update it
  569. // to point to our alternate tip. This leaves the original master tip
  570. // unreferenced.
  571. results = git.push().setCredentialsProvider(cp).setRemote("origin").setForce(true).call();
  572. for (PushResult result : results) {
  573. RemoteRefUpdate ref = result.getRemoteUpdate("refs/heads/master");
  574. Status status = ref.getStatus();
  575. if (Status.OK.equals(expectedRewind)) {
  576. assertTrue("User failed to rewind master?! " + status.name(), status.equals(expectedRewind));
  577. } else {
  578. assertTrue("User was able to rewind master?! " + status.name(), status.equals(expectedRewind));
  579. }
  580. }
  581. GitBlitSuite.close(git);
  582. // close serving repository
  583. GitBlitSuite.close(refChecks);
  584. delete(user);
  585. }
  586. @Test
  587. public void testCreateOnPush() throws Exception {
  588. testCreateOnPush(false, false);
  589. testCreateOnPush(true, false);
  590. testCreateOnPush(false, true);
  591. }
  592. private void testCreateOnPush(boolean canCreate, boolean canAdmin) throws Exception {
  593. UserModel user = new UserModel("sampleuser");
  594. user.password = user.username;
  595. delete(user);
  596. user.canCreate = canCreate;
  597. user.canAdmin = canAdmin;
  598. GitBlit.self().updateUserModel(user.username, user, true);
  599. CredentialsProvider cp = new UsernamePasswordCredentialsProvider(user.username, user.password);
  600. // fork from original to a temporary bare repo
  601. File tmpFolder = File.createTempFile("gitblit", "").getParentFile();
  602. File createCheck = new File(tmpFolder, "ticgit.git");
  603. if (createCheck.exists()) {
  604. FileUtils.delete(createCheck, FileUtils.RECURSIVE);
  605. }
  606. File personalRepo = new File(GitBlitSuite.REPOSITORIES, MessageFormat.format("~{0}/ticgit.git", user.username));
  607. GitBlitSuite.close(personalRepo);
  608. if (personalRepo.exists()) {
  609. FileUtils.delete(personalRepo, FileUtils.RECURSIVE);
  610. }
  611. File projectRepo = new File(GitBlitSuite.REPOSITORIES, "project/ticgit.git");
  612. GitBlitSuite.close(projectRepo);
  613. if (projectRepo.exists()) {
  614. FileUtils.delete(projectRepo, FileUtils.RECURSIVE);
  615. }
  616. CloneCommand clone = Git.cloneRepository();
  617. clone.setURI(MessageFormat.format("{0}/ticgit.git", url));
  618. clone.setDirectory(createCheck);
  619. clone.setBare(true);
  620. clone.setCloneAllBranches(true);
  621. clone.setCredentialsProvider(cp);
  622. Git git = clone.call();
  623. GitBlitSuite.close(personalRepo);
  624. // add a personal repository remote and a project remote
  625. git.getRepository().getConfig().setString("remote", "user", "url", MessageFormat.format("{0}/~{1}/ticgit.git", url, user.username));
  626. git.getRepository().getConfig().setString("remote", "project", "url", MessageFormat.format("{0}/project/ticgit.git", url));
  627. git.getRepository().getConfig().save();
  628. // push to non-existent user repository
  629. try {
  630. Iterable<PushResult> results = git.push().setRemote("user").setPushAll().setCredentialsProvider(cp).call();
  631. for (PushResult result : results) {
  632. RemoteRefUpdate ref = result.getRemoteUpdate("refs/heads/master");
  633. Status status = ref.getStatus();
  634. assertTrue("User failed to create repository?! " + status.name(), Status.OK.equals(status));
  635. }
  636. assertTrue("User canAdmin:" + user.canAdmin + " canCreate:" + user.canCreate, user.canAdmin || user.canCreate);
  637. // confirm default personal repository permissions
  638. RepositoryModel model = GitBlit.self().getRepositoryModel(MessageFormat.format("~{0}/ticgit.git", user.username));
  639. assertEquals("Unexpected owner", user.username, ArrayUtils.toString(model.owners));
  640. assertEquals("Unexpected authorization control", AuthorizationControl.NAMED, model.authorizationControl);
  641. assertEquals("Unexpected access restriction", AccessRestrictionType.VIEW, model.accessRestriction);
  642. } catch (GitAPIException e) {
  643. assertTrue(e.getMessage(), e.getMessage().contains("git-receive-pack not found"));
  644. assertFalse("User canAdmin:" + user.canAdmin + " canCreate:" + user.canCreate, user.canAdmin || user.canCreate);
  645. }
  646. // push to non-existent project repository
  647. try {
  648. Iterable<PushResult> results = git.push().setRemote("project").setPushAll().setCredentialsProvider(cp).call();
  649. GitBlitSuite.close(git);
  650. for (PushResult result : results) {
  651. RemoteRefUpdate ref = result.getRemoteUpdate("refs/heads/master");
  652. Status status = ref.getStatus();
  653. assertTrue("User failed to create repository?! " + status.name(), Status.OK.equals(status));
  654. }
  655. assertTrue("User canAdmin:" + user.canAdmin, user.canAdmin);
  656. // confirm default project repository permissions
  657. RepositoryModel model = GitBlit.self().getRepositoryModel("project/ticgit.git");
  658. assertEquals("Unexpected owner", user.username, ArrayUtils.toString(model.owners));
  659. assertEquals("Unexpected authorization control", AuthorizationControl.fromName(GitBlit.getString(Keys.git.defaultAuthorizationControl, "NAMED")), model.authorizationControl);
  660. assertEquals("Unexpected access restriction", AccessRestrictionType.fromName(GitBlit.getString(Keys.git.defaultAccessRestriction, "NONE")), model.accessRestriction);
  661. } catch (GitAPIException e) {
  662. assertTrue(e.getMessage(), e.getMessage().contains("git-receive-pack not found"));
  663. assertFalse("User canAdmin:" + user.canAdmin, user.canAdmin);
  664. }
  665. GitBlitSuite.close(git);
  666. delete(user);
  667. }
  668. @Test
  669. public void testPushLog() throws IOException {
  670. String name = "refchecks/ticgit.git";
  671. File refChecks = new File(GitBlitSuite.REPOSITORIES, name);
  672. Repository repository = new FileRepositoryBuilder().setGitDir(refChecks).build();
  673. List<RefLogEntry> pushes = RefLogUtils.getRefLog(name, repository);
  674. GitBlitSuite.close(repository);
  675. assertTrue("Repository has an empty push log!", pushes.size() > 0);
  676. }
  677. }