releases.moxie | ●●●●● patch | view | raw | blame | history | |
src/main/distrib/data/gitblit.properties | ●●●●● patch | view | raw | blame | history | |
src/main/java/com/gitblit/Constants.java | ●●●●● patch | view | raw | blame | history | |
src/main/java/com/gitblit/GitBlit.java | ●●●●● patch | view | raw | blame | history | |
src/main/java/com/gitblit/git/GitblitReceivePackFactory.java | ●●●●● patch | view | raw | blame | history | |
src/main/java/com/gitblit/models/RepositoryUrl.java | ●●●●● patch | view | raw | blame | history |
releases.moxie
@@ -23,10 +23,12 @@ - Redirect to summary page on edit repository (issue-405) - Option to allow LDAP users to directly authenticate without performing LDAP searches (pr-162) - Replace JCommander with args4j to be consistent with other tools (ticket-28) - Sort repository urls by descending permissions and by transport security within equal permissions additions: - Added an SSH daemon with public key authentication (issue-369, ticket-6) - Added beginnings of a plugin framework for extending Gitblit (issue-381, ticket-23) - Added a French translation (pr-163) - Added a setting to control what transports may be used for pushes dependencyChanges: - args4j 2.0.26 - JGit 3.3.1 @@ -41,6 +43,7 @@ settings: - { name: 'realm.ldap.bindpattern', defaultValue: ' ' } - { name: 'tickets.closeOnPushCommitMessageRegex', defaultValue: '(?:fixes|closes)[\\s-]+#?(\\d+)' } - { name: 'git.acceptedPushTransports', defaultValue: ' ' } - { name: 'git.sshPort', defaultValue: '29418' } - { name: 'git.sshBindInterface', defaultValue: ' ' } - { name: 'git.sshKeysManager', defaultValue: 'com.gitblit.transport.ssh.FileKeyManager' } src/main/distrib/data/gitblit.properties
@@ -173,6 +173,16 @@ # SINCE 0.9.0 git.onlyAccessBareRepositories = false # Specify the list of acceptable transports for pushes. # If this setting is empty, all transports are acceptable. # # Valid choices are: GIT HTTP HTTPS SSH # # SINCE 1.5.0 # SPACE-DELIMITED git.acceptedPushTransports = HTTP HTTPS SSH # Allow an authenticated user to create a destination repository on a push if # the repository does not already exist. # src/main/java/com/gitblit/Constants.java
@@ -540,6 +540,25 @@ } } 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 { src/main/java/com/gitblit/GitBlit.java
@@ -17,12 +17,17 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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; } 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.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 @@ 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 @@ 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 @@ // 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 @@ 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); } } src/main/java/com/gitblit/models/RepositoryUrl.java
@@ -18,6 +18,7 @@ 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 @@ 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; }