summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJames Moger <james.moger@gitblit.com>2012-10-21 22:04:35 -0400
committerJames Moger <james.moger@gitblit.com>2012-10-21 22:04:35 -0400
commit72cb19b84e87e63770391a37ea3872f963574869 (patch)
tree2b48634b92c7ccf598ee6ac68c9c2f0d95a857b8 /src
parent517865c182c322b47d2cdd825c50d385a3c274f0 (diff)
downloadgitblit-72cb19b84e87e63770391a37ea3872f963574869.tar.gz
gitblit-72cb19b84e87e63770391a37ea3872f963574869.zip
Implemented optional create-on-push
If this feature is enabled then permitted users can automatically create a repository when pushing to one that does not yet exist. Permitted users are administrators and any user with the CREATE role. If the pushing account is an administrator, the created repository may be located in any folder/project space. This reposiory will inherit the server's default access restriction and authorization control. The repository owner will be the pushing account. If the pushing account is a regular user with the CREATE role, the repository can only be located in the account's personal folder (~username/myrepo.git). This repository will be VIEW restricted and accessible by NAMED users. The repository owner will be the pushing account.
Diffstat (limited to 'src')
-rw-r--r--src/com/gitblit/AccessRestrictionFilter.java49
-rw-r--r--src/com/gitblit/DownloadZipFilter.java10
-rw-r--r--src/com/gitblit/GitFilter.java57
-rw-r--r--src/com/gitblit/PagesFilter.java10
-rw-r--r--src/com/gitblit/models/UserModel.java22
5 files changed, 142 insertions, 6 deletions
diff --git a/src/com/gitblit/AccessRestrictionFilter.java b/src/com/gitblit/AccessRestrictionFilter.java
index 3a104813..78d33d21 100644
--- a/src/com/gitblit/AccessRestrictionFilter.java
+++ b/src/com/gitblit/AccessRestrictionFilter.java
@@ -62,6 +62,13 @@ public abstract class AccessRestrictionFilter extends AuthenticationFilter {
protected abstract String getUrlRequestAction(String url);
/**
+ * Determine if a non-existing repository can be created using this filter.
+ *
+ * @return true if the filter allows repository creation
+ */
+ protected abstract boolean isCreationAllowed();
+
+ /**
* Determine if the action may be executed on the repository.
*
* @param repository
@@ -91,6 +98,18 @@ public abstract class AccessRestrictionFilter extends AuthenticationFilter {
protected abstract boolean canAccess(RepositoryModel repository, UserModel user, String action);
/**
+ * Allows a filter to create a repository, if one does not exist.
+ *
+ * @param user
+ * @param repository
+ * @param action
+ * @return the repository model, if it is created, null otherwise
+ */
+ protected RepositoryModel createRepository(UserModel user, String repository, String action) {
+ return null;
+ }
+
+ /**
* doFilter does the actual work of preprocessing the request to ensure that
* the user may proceed.
*
@@ -111,14 +130,33 @@ public abstract class AccessRestrictionFilter extends AuthenticationFilter {
String fullSuffix = fullUrl.substring(repository.length());
String urlRequestType = getUrlRequestAction(fullSuffix);
+ UserModel user = getUser(httpRequest);
+
// Load the repository model
RepositoryModel model = GitBlit.self().getRepositoryModel(repository);
if (model == null) {
- // repository not found. send 404.
- logger.info(MessageFormat.format("ARF: {0} ({1})", fullUrl,
- HttpServletResponse.SC_NOT_FOUND));
- httpResponse.sendError(HttpServletResponse.SC_NOT_FOUND);
- return;
+ if (isCreationAllowed()) {
+ if (user == null) {
+ // challenge client to provide credentials for creation. send 401.
+ if (GitBlit.isDebugMode()) {
+ logger.info(MessageFormat.format("ARF: CREATE CHALLENGE {0}", fullUrl));
+ }
+ httpResponse.setHeader("WWW-Authenticate", CHALLENGE);
+ httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED);
+ return;
+ } else {
+ // see if we can create a repository for this request
+ model = createRepository(user, repository, urlRequestType);
+ }
+ }
+
+ if (model == null) {
+ // repository not found. send 404.
+ logger.info(MessageFormat.format("ARF: {0} ({1})", fullUrl,
+ HttpServletResponse.SC_NOT_FOUND));
+ httpResponse.sendError(HttpServletResponse.SC_NOT_FOUND);
+ return;
+ }
}
// Confirm that the action may be executed on the repository
@@ -139,7 +177,6 @@ public abstract class AccessRestrictionFilter extends AuthenticationFilter {
// Gitblit must conditionally authenticate users per-repository so just
// enabling http.receivepack is insufficient.
AuthenticatedRequest authenticatedRequest = new AuthenticatedRequest(httpRequest);
- UserModel user = getUser(httpRequest);
if (user != null) {
authenticatedRequest.setUser(user);
}
diff --git a/src/com/gitblit/DownloadZipFilter.java b/src/com/gitblit/DownloadZipFilter.java
index 225e5e11..90a76493 100644
--- a/src/com/gitblit/DownloadZipFilter.java
+++ b/src/com/gitblit/DownloadZipFilter.java
@@ -57,6 +57,16 @@ public class DownloadZipFilter extends AccessRestrictionFilter {
}
/**
+ * Determine if a non-existing repository can be created using this filter.
+ *
+ * @return true if the filter allows repository creation
+ */
+ @Override
+ protected boolean isCreationAllowed() {
+ return false;
+ }
+
+ /**
* Determine if the action may be executed on the repository.
*
* @param repository
diff --git a/src/com/gitblit/GitFilter.java b/src/com/gitblit/GitFilter.java
index cfe4fe3f..c09b0d20 100644
--- a/src/com/gitblit/GitFilter.java
+++ b/src/com/gitblit/GitFilter.java
@@ -18,6 +18,7 @@ package com.gitblit;
import java.text.MessageFormat;
import com.gitblit.Constants.AccessRestrictionType;
+import com.gitblit.Constants.AuthorizationControl;
import com.gitblit.models.RepositoryModel;
import com.gitblit.models.UserModel;
import com.gitblit.utils.StringUtils;
@@ -93,6 +94,16 @@ public class GitFilter extends AccessRestrictionFilter {
}
/**
+ * Determine if a non-existing repository can be created using this filter.
+ *
+ * @return true if the server allows repository creation on-push
+ */
+ @Override
+ protected boolean isCreationAllowed() {
+ return GitBlit.getBoolean(Keys.git.allowCreateOnPush, true);
+ }
+
+ /**
* Determine if the repository can receive pushes.
*
* @param repository
@@ -170,4 +181,50 @@ public class GitFilter extends AccessRestrictionFilter {
}
return true;
}
+
+ /**
+ * An authenticated user with the CREATE role can create a repository on
+ * push.
+ *
+ * @param user
+ * @param repository
+ * @param action
+ * @return the repository model, if it is created, null otherwise
+ */
+ @Override
+ protected RepositoryModel createRepository(UserModel user, String repository, String action) {
+ boolean isPush = !StringUtils.isEmpty(action) && gitReceivePack.equals(action);
+ if (isPush) {
+ if (user.canCreateOnPush(repository)) {
+ // user is pushing to a new repository
+ RepositoryModel model = new RepositoryModel();
+ model.name = repository;
+ model.owner = user.username;
+ model.projectPath = StringUtils.getFirstPathElement(repository);
+ if (model.isUsersPersonalRepository(user.username)) {
+ // personal repository, default to private for user
+ model.authorizationControl = AuthorizationControl.NAMED;
+ model.accessRestriction = AccessRestrictionType.VIEW;
+ } else {
+ // common repository, user default server settings
+ model.authorizationControl = AuthorizationControl.fromName(GitBlit.getString(Keys.git.defaultAuthorizationControl, ""));
+ model.accessRestriction = AccessRestrictionType.fromName(GitBlit.getString(Keys.git.defaultAccessRestriction, ""));
+ }
+
+ // create the repository
+ try {
+ GitBlit.self().updateRepositoryModel(repository, model, true);
+ logger.info(MessageFormat.format("{0} created {1} ON-PUSH", user.username, repository));
+ return GitBlit.self().getRepositoryModel(repository);
+ } catch (GitBlitException e) {
+ logger.error(MessageFormat.format("{0} failed to create repository {1} ON-PUSH!", user.username, repository), e);
+ }
+ } else {
+ logger.warn(MessageFormat.format("{0} is not permitted to create repository {1} ON-PUSH!", user.username, repository));
+ }
+ }
+
+ // repository could not be created or action was not a push
+ return null;
+ }
}
diff --git a/src/com/gitblit/PagesFilter.java b/src/com/gitblit/PagesFilter.java
index 11cdfa56..f88624e1 100644
--- a/src/com/gitblit/PagesFilter.java
+++ b/src/com/gitblit/PagesFilter.java
@@ -77,6 +77,16 @@ public class PagesFilter extends AccessRestrictionFilter {
}
/**
+ * Determine if a non-existing repository can be created using this filter.
+ *
+ * @return true if the filter allows repository creation
+ */
+ @Override
+ protected boolean isCreationAllowed() {
+ return false;
+ }
+
+ /**
* Determine if the action may be executed on the repository.
*
* @param repository
diff --git a/src/com/gitblit/models/UserModel.java b/src/com/gitblit/models/UserModel.java
index fc9cbfba..7995f7e4 100644
--- a/src/com/gitblit/models/UserModel.java
+++ b/src/com/gitblit/models/UserModel.java
@@ -364,6 +364,28 @@ public class UserModel implements Principal, Serializable, Comparable<UserModel>
}
return false;
}
+
+ /**
+ * Returns true if the user is allowed to create the specified repository
+ * on-push if the repository does not already exist.
+ *
+ * @param repository
+ * @return true if the user can create the repository
+ */
+ public boolean canCreateOnPush(String repository) {
+ if (canAdmin()) {
+ // admins can create any repository
+ return true;
+ }
+ if (canCreate) {
+ String projectPath = StringUtils.getFirstPathElement(repository);
+ if (!StringUtils.isEmpty(projectPath) && projectPath.equalsIgnoreCase("~" + username)) {
+ // personal repository
+ return true;
+ }
+ }
+ return false;
+ }
public boolean isTeamMember(String teamname) {
for (TeamModel team : teams) {