You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

GitServletTest.java 29KB

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