diff options
Diffstat (limited to 'src/main/java')
-rw-r--r-- | src/main/java/com/gitblit/Constants.java | 19 | ||||
-rw-r--r-- | src/main/java/com/gitblit/GitBlit.java | 76 | ||||
-rw-r--r-- | src/main/java/com/gitblit/git/GitblitReceivePackFactory.java | 46 | ||||
-rw-r--r-- | src/main/java/com/gitblit/models/RepositoryUrl.java | 3 |
4 files changed, 144 insertions, 0 deletions
diff --git a/src/main/java/com/gitblit/Constants.java b/src/main/java/com/gitblit/Constants.java index 26e0de3c..af533996 100644 --- a/src/main/java/com/gitblit/Constants.java +++ b/src/main/java/com/gitblit/Constants.java @@ -540,6 +540,25 @@ public class Constants { }
}
+ public static enum Transport {
+ // ordered for url advertisements, assuming equal access permissions
+ SSH, HTTPS, HTTP, GIT;
+
+ public static Transport fromString(String value) {
+ for (Transport t : values()) {
+ if (t.name().equalsIgnoreCase(value)) {
+ return t;
+ }
+ }
+ return null;
+ }
+
+ public static Transport fromUrl(String url) {
+ String scheme = url.substring(0, url.indexOf("://"));
+ return fromString(scheme);
+ }
+ }
+
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface Unused {
diff --git a/src/main/java/com/gitblit/GitBlit.java b/src/main/java/com/gitblit/GitBlit.java index 26ab3f3b..08342521 100644 --- a/src/main/java/com/gitblit/GitBlit.java +++ b/src/main/java/com/gitblit/GitBlit.java @@ -17,12 +17,17 @@ package com.gitblit; import java.text.MessageFormat; import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashSet; import java.util.List; +import java.util.Set; import javax.inject.Singleton; import javax.servlet.http.HttpServletRequest; import com.gitblit.Constants.AccessPermission; +import com.gitblit.Constants.Transport; import com.gitblit.manager.GitblitManager; import com.gitblit.manager.IAuthenticationManager; import com.gitblit.manager.IFederationManager; @@ -116,6 +121,32 @@ public class GitBlit extends GitblitManager { return new Object [] { new GitBlitModule()}; } + protected boolean acceptPush(Transport byTransport) { + if (byTransport == null) { + logger.info("Unknown transport, push rejected!"); + return false; + } + + Set<Transport> transports = new HashSet<Transport>(); + for (String value : getSettings().getStrings(Keys.git.acceptedPushTransports)) { + Transport transport = Transport.fromString(value); + if (transport == null) { + logger.info(String.format("Ignoring unknown registered transport %s", value)); + continue; + } + + transports.add(transport); + } + + if (transports.isEmpty()) { + // no transports are explicitly specified, all are acceptable + return true; + } + + // verify that the transport is permitted + return transports.contains(byTransport); + } + /** * Returns a list of repository URLs and the user access permission. * @@ -137,6 +168,12 @@ public class GitBlit extends GitblitManager { if (settings.getBoolean(Keys.git.enableGitServlet, true)) { AccessPermission permission = user.getRepositoryPermission(repository).permission; if (permission.exceeds(AccessPermission.NONE)) { + Transport transport = Transport.fromString(request.getScheme()); + if (permission.atLeast(AccessPermission.PUSH) && !acceptPush(transport)) { + // downgrade the repo permission for this transport + // because it is not an acceptable PUSH transport + permission = AccessPermission.CLONE; + } list.add(new RepositoryUrl(getRepositoryUrl(request, username, repository), permission)); } } @@ -146,6 +183,12 @@ public class GitBlit extends GitblitManager { if (!StringUtils.isEmpty(sshDaemonUrl)) { AccessPermission permission = user.getRepositoryPermission(repository).permission; if (permission.exceeds(AccessPermission.NONE)) { + if (permission.atLeast(AccessPermission.PUSH) && !acceptPush(Transport.SSH)) { + // downgrade the repo permission for this transport + // because it is not an acceptable PUSH transport + permission = AccessPermission.CLONE; + } + list.add(new RepositoryUrl(sshDaemonUrl, permission)); } } @@ -155,6 +198,11 @@ public class GitBlit extends GitblitManager { if (!StringUtils.isEmpty(gitDaemonUrl)) { AccessPermission permission = servicesManager.getGitDaemonAccessPermission(user, repository); if (permission.exceeds(AccessPermission.NONE)) { + if (permission.atLeast(AccessPermission.PUSH) && !acceptPush(Transport.GIT)) { + // downgrade the repo permission for this transport + // because it is not an acceptable PUSH transport + permission = AccessPermission.CLONE; + } list.add(new RepositoryUrl(gitDaemonUrl, permission)); } } @@ -173,6 +221,34 @@ public class GitBlit extends GitblitManager { list.add(new RepositoryUrl(MessageFormat.format(url, repository.name), null)); } } + + // sort transports by highest permission and then by transport security + Collections.sort(list, new Comparator<RepositoryUrl>() { + + @Override + public int compare(RepositoryUrl o1, RepositoryUrl o2) { + if (!o1.isExternal() && o2.isExternal()) { + // prefer Gitblit over external + return -1; + } else if (o1.isExternal() && !o2.isExternal()) { + // prefer Gitblit over external + return 1; + } else if (o1.isExternal() && o2.isExternal()) { + // sort by Transport ordinal + return o1.transport.compareTo(o2.transport); + } else if (o1.permission.exceeds(o2.permission)) { + // prefer highest permission + return -1; + } else if (o2.permission.exceeds(o1.permission)) { + // prefer highest permission + return 1; + } + + // prefer more secure transports + return o1.transport.compareTo(o2.transport); + } + }); + return list; } diff --git a/src/main/java/com/gitblit/git/GitblitReceivePackFactory.java b/src/main/java/com/gitblit/git/GitblitReceivePackFactory.java index 41e348ba..afda23b0 100644 --- a/src/main/java/com/gitblit/git/GitblitReceivePackFactory.java +++ b/src/main/java/com/gitblit/git/GitblitReceivePackFactory.java @@ -15,6 +15,9 @@ */ package com.gitblit.git; +import java.util.HashSet; +import java.util.Set; + import javax.servlet.http.HttpServletRequest; import org.eclipse.jgit.lib.PersonIdent; @@ -26,6 +29,7 @@ import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.gitblit.Constants.Transport; import com.gitblit.IStoredSettings; import com.gitblit.Keys; import com.gitblit.manager.IGitblit; @@ -66,6 +70,7 @@ public class GitblitReceivePackFactory<X> implements ReceivePackFactory<X> { String origin = ""; String gitblitUrl = ""; int timeout = 0; + Transport transport = null; if (req instanceof HttpServletRequest) { // http/https request may or may not be authenticated @@ -82,6 +87,13 @@ public class GitblitReceivePackFactory<X> implements ReceivePackFactory<X> { user = u; } } + + // determine the transport + if ("http".equals(client.getScheme())) { + transport = Transport.HTTP; + } else if ("https".equals(client.getScheme())) { + transport = Transport.HTTPS; + } } else if (req instanceof GitDaemonClient) { // git daemon request is always anonymous GitDaemonClient client = (GitDaemonClient) req; @@ -90,12 +102,20 @@ public class GitblitReceivePackFactory<X> implements ReceivePackFactory<X> { // set timeout from Git daemon timeout = client.getDaemon().getTimeout(); + + transport = Transport.GIT; } else if (req instanceof SshDaemonClient) { // SSH request is always authenticated SshDaemonClient client = (SshDaemonClient) req; repositoryName = client.getRepositoryName(); origin = client.getRemoteAddress().toString(); user = client.getUser(); + + transport = Transport.SSH; + } + + if (!acceptPush(transport)) { + throw new ServiceNotAuthorizedException(); } boolean allowAnonymousPushes = settings.getBoolean(Keys.git.allowAnonymousPushes, false); @@ -125,4 +145,30 @@ public class GitblitReceivePackFactory<X> implements ReceivePackFactory<X> { return rp; } + + protected boolean acceptPush(Transport byTransport) { + if (byTransport == null) { + logger.info("Unknown transport, push rejected!"); + return false; + } + + Set<Transport> transports = new HashSet<Transport>(); + for (String value : gitblit.getSettings().getStrings(Keys.git.acceptedPushTransports)) { + Transport transport = Transport.fromString(value); + if (transport == null) { + logger.info(String.format("Ignoring unknown registered transport %s", value)); + continue; + } + + transports.add(transport); + } + + if (transports.isEmpty()) { + // no transports are explicitly specified, all are acceptable + return true; + } + + // verify that the transport is permitted + return transports.contains(byTransport); + } }
\ No newline at end of file diff --git a/src/main/java/com/gitblit/models/RepositoryUrl.java b/src/main/java/com/gitblit/models/RepositoryUrl.java index a24def57..d155dbda 100644 --- a/src/main/java/com/gitblit/models/RepositoryUrl.java +++ b/src/main/java/com/gitblit/models/RepositoryUrl.java @@ -18,6 +18,7 @@ package com.gitblit.models; import java.io.Serializable;
import com.gitblit.Constants.AccessPermission;
+import com.gitblit.Constants.Transport;
/**
* Represents a git repository url and it's associated access permission for the
@@ -30,10 +31,12 @@ public class RepositoryUrl implements Serializable { private static final long serialVersionUID = 1L;
+ public final Transport transport;
public final String url;
public final AccessPermission permission;
public RepositoryUrl(String url, AccessPermission permission) {
+ this.transport = Transport.fromUrl(url);
this.url = url;
this.permission = permission;
}
|