Browse Source

Allow specifying accepted PUSH transports

tags/v1.5.0
James Moger 10 years ago
parent
commit
e9872c8ca4

+ 3
- 0
releases.moxie View File

- Redirect to summary page on edit repository (issue-405) - Redirect to summary page on edit repository (issue-405)
- Option to allow LDAP users to directly authenticate without performing LDAP searches (pr-162) - 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) - 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: additions:
- Added an SSH daemon with public key authentication (issue-369, ticket-6) - 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 beginnings of a plugin framework for extending Gitblit (issue-381, ticket-23)
- Added a French translation (pr-163) - Added a French translation (pr-163)
- Added a setting to control what transports may be used for pushes
dependencyChanges: dependencyChanges:
- args4j 2.0.26 - args4j 2.0.26
- JGit 3.3.1 - JGit 3.3.1
settings: settings:
- { name: 'realm.ldap.bindpattern', defaultValue: ' ' } - { name: 'realm.ldap.bindpattern', defaultValue: ' ' }
- { name: 'tickets.closeOnPushCommitMessageRegex', defaultValue: '(?:fixes|closes)[\\s-]+#?(\\d+)' } - { name: 'tickets.closeOnPushCommitMessageRegex', defaultValue: '(?:fixes|closes)[\\s-]+#?(\\d+)' }
- { name: 'git.acceptedPushTransports', defaultValue: ' ' }
- { name: 'git.sshPort', defaultValue: '29418' } - { name: 'git.sshPort', defaultValue: '29418' }
- { name: 'git.sshBindInterface', defaultValue: ' ' } - { name: 'git.sshBindInterface', defaultValue: ' ' }
- { name: 'git.sshKeysManager', defaultValue: 'com.gitblit.transport.ssh.FileKeyManager' } - { name: 'git.sshKeysManager', defaultValue: 'com.gitblit.transport.ssh.FileKeyManager' }

+ 10
- 0
src/main/distrib/data/gitblit.properties View File

# SINCE 0.9.0 # SINCE 0.9.0
git.onlyAccessBareRepositories = false 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 # Allow an authenticated user to create a destination repository on a push if
# the repository does not already exist. # the repository does not already exist.
# #

+ 19
- 0
src/main/java/com/gitblit/Constants.java View File

} }
} }
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 @Documented
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
public @interface Unused { public @interface Unused {

+ 76
- 0
src/main/java/com/gitblit/GitBlit.java View File



import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;


import javax.inject.Singleton; import javax.inject.Singleton;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;


import com.gitblit.Constants.AccessPermission; import com.gitblit.Constants.AccessPermission;
import com.gitblit.Constants.Transport;
import com.gitblit.manager.GitblitManager; import com.gitblit.manager.GitblitManager;
import com.gitblit.manager.IAuthenticationManager; import com.gitblit.manager.IAuthenticationManager;
import com.gitblit.manager.IFederationManager; import com.gitblit.manager.IFederationManager;
return new Object [] { new GitBlitModule()}; 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. * Returns a list of repository URLs and the user access permission.
* *
if (settings.getBoolean(Keys.git.enableGitServlet, true)) { if (settings.getBoolean(Keys.git.enableGitServlet, true)) {
AccessPermission permission = user.getRepositoryPermission(repository).permission; AccessPermission permission = user.getRepositoryPermission(repository).permission;
if (permission.exceeds(AccessPermission.NONE)) { 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)); list.add(new RepositoryUrl(getRepositoryUrl(request, username, repository), permission));
} }
} }
if (!StringUtils.isEmpty(sshDaemonUrl)) { if (!StringUtils.isEmpty(sshDaemonUrl)) {
AccessPermission permission = user.getRepositoryPermission(repository).permission; AccessPermission permission = user.getRepositoryPermission(repository).permission;
if (permission.exceeds(AccessPermission.NONE)) { 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)); list.add(new RepositoryUrl(sshDaemonUrl, permission));
} }
} }
if (!StringUtils.isEmpty(gitDaemonUrl)) { if (!StringUtils.isEmpty(gitDaemonUrl)) {
AccessPermission permission = servicesManager.getGitDaemonAccessPermission(user, repository); AccessPermission permission = servicesManager.getGitDaemonAccessPermission(user, repository);
if (permission.exceeds(AccessPermission.NONE)) { 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)); list.add(new RepositoryUrl(gitDaemonUrl, permission));
} }
} }
list.add(new RepositoryUrl(MessageFormat.format(url, repository.name), null)); 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; return list;
} }



+ 46
- 0
src/main/java/com/gitblit/git/GitblitReceivePackFactory.java View File

*/ */
package com.gitblit.git; package com.gitblit.git;


import java.util.HashSet;
import java.util.Set;

import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;


import org.eclipse.jgit.lib.PersonIdent; import org.eclipse.jgit.lib.PersonIdent;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;


import com.gitblit.Constants.Transport;
import com.gitblit.IStoredSettings; import com.gitblit.IStoredSettings;
import com.gitblit.Keys; import com.gitblit.Keys;
import com.gitblit.manager.IGitblit; import com.gitblit.manager.IGitblit;
String origin = ""; String origin = "";
String gitblitUrl = ""; String gitblitUrl = "";
int timeout = 0; int timeout = 0;
Transport transport = null;


if (req instanceof HttpServletRequest) { if (req instanceof HttpServletRequest) {
// http/https request may or may not be authenticated // http/https request may or may not be authenticated
user = u; 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) { } else if (req instanceof GitDaemonClient) {
// git daemon request is always anonymous // git daemon request is always anonymous
GitDaemonClient client = (GitDaemonClient) req; GitDaemonClient client = (GitDaemonClient) req;


// set timeout from Git daemon // set timeout from Git daemon
timeout = client.getDaemon().getTimeout(); timeout = client.getDaemon().getTimeout();

transport = Transport.GIT;
} else if (req instanceof SshDaemonClient) { } else if (req instanceof SshDaemonClient) {
// SSH request is always authenticated // SSH request is always authenticated
SshDaemonClient client = (SshDaemonClient) req; SshDaemonClient client = (SshDaemonClient) req;
repositoryName = client.getRepositoryName(); repositoryName = client.getRepositoryName();
origin = client.getRemoteAddress().toString(); origin = client.getRemoteAddress().toString();
user = client.getUser(); user = client.getUser();

transport = Transport.SSH;
}

if (!acceptPush(transport)) {
throw new ServiceNotAuthorizedException();
} }


boolean allowAnonymousPushes = settings.getBoolean(Keys.git.allowAnonymousPushes, false); boolean allowAnonymousPushes = settings.getBoolean(Keys.git.allowAnonymousPushes, false);


return rp; 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);
}
} }

+ 3
- 0
src/main/java/com/gitblit/models/RepositoryUrl.java View File

import java.io.Serializable; import java.io.Serializable;
import com.gitblit.Constants.AccessPermission; import com.gitblit.Constants.AccessPermission;
import com.gitblit.Constants.Transport;
/** /**
* Represents a git repository url and it's associated access permission for the * Represents a git repository url and it's associated access permission for the
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
public final Transport transport;
public final String url; public final String url;
public final AccessPermission permission; public final AccessPermission permission;
public RepositoryUrl(String url, AccessPermission permission) { public RepositoryUrl(String url, AccessPermission permission) {
this.transport = Transport.fromUrl(url);
this.url = url; this.url = url;
this.permission = permission; this.permission = permission;
} }

Loading…
Cancel
Save