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