1 files deleted
7 files added
12 files modified
| | |
| | | /pom.xml
|
| | | /x509test
|
| | | /data |
| | | /*.conf |
| | |
| | | - Use standard ServletRequestWrapper instead of custom wrapper (issue 224)
|
| | |
|
| | | additions:
|
| | | - Added Git Daemon serving
|
| | | - Option to automatically tag branch tips on each push with an incremental revision number
|
| | | - Implemented multiple repository owners
|
| | | - Optional periodic LDAP user and team pre-fetching & synchronization
|
| | |
| | | - JGit 2.3.1.201302201838-r
|
| | |
|
| | | settings:
|
| | | - { name: 'git.daemonBindInterface', defaultValue: 'localhost' }
|
| | | - { name: 'git.daemonPort', defaultValue: 9418 }
|
| | | - { name: 'git.defaultIncrementalPushTagPrefix', defaultValue: 'r' }
|
| | | }
|
| | |
|
| | |
| | | # SINCE 1.1.0
|
| | | git.submoduleUrlPatterns = .*?://github.com/(.*)
|
| | |
|
| | | # Specify the interface for Git Daemon to bind it's service.
|
| | | # You may specify an ip or an empty value to bind to all interfaces.
|
| | | # Specifying localhost will result in Gitblit ONLY listening to requests to
|
| | | # localhost.
|
| | | #
|
| | | # SINCE 1.3.0
|
| | | # RESTART REQUIRED
|
| | | git.daemonBindInterface = localhost
|
| | |
|
| | | # port for serving the Git Daemon service. <= 0 disables this service.
|
| | | # On Unix/Linux systems, ports < 1024 require root permissions.
|
| | | # Recommended value: 9418
|
| | | #
|
| | | # SINCE 1.3.0
|
| | | # RESTART REQUIRED
|
| | | git.daemonPort = 9418
|
| | |
|
| | | # Allow push/pull over http/https with JGit servlet.
|
| | | # If you do NOT want to allow Git clients to clone/push to Gitblit set this
|
| | | # to false. You might want to do this if you are only using ssh:// or git://.
|
| | |
| | | * Wicket Filter ignorePaths parameter -->
|
| | | <servlet>
|
| | | <servlet-name>GitServlet</servlet-name>
|
| | | <servlet-class>com.gitblit.GitServlet</servlet-class>
|
| | | <servlet-class>com.gitblit.git.GitServlet</servlet-class>
|
| | | </servlet>
|
| | | <servlet-mapping>
|
| | | <servlet-name>GitServlet</servlet-name>
|
| | |
| | | import com.gitblit.fanout.FanoutNioService;
|
| | | import com.gitblit.fanout.FanoutService;
|
| | | import com.gitblit.fanout.FanoutSocketService;
|
| | | import com.gitblit.git.GitDaemon;
|
| | | import com.gitblit.models.FederationModel;
|
| | | import com.gitblit.models.FederationProposal;
|
| | | import com.gitblit.models.FederationSet;
|
| | |
| | | private FileBasedConfig projectConfigs;
|
| | |
|
| | | private FanoutService fanoutService;
|
| | |
|
| | | private GitDaemon gitDaemon;
|
| | |
|
| | | public GitBlit() {
|
| | | if (gitblit == null) {
|
| | |
| | | // try to authenticate by servlet container principal
|
| | | Principal principal = httpRequest.getUserPrincipal();
|
| | | if (principal != null) {
|
| | | UserModel user = getUserModel(principal.getName());
|
| | | String username = principal.getName();
|
| | | if (StringUtils.isEmpty(username)) {
|
| | | UserModel user = getUserModel(username);
|
| | | if (user != null) {
|
| | | flagWicketSession(AuthenticationType.CONTAINER);
|
| | | logger.debug(MessageFormat.format("{0} authenticated by servlet container principal from {1}",
|
| | |
| | | } else {
|
| | | logger.warn(MessageFormat.format("Failed to find UserModel for {0}, attempted servlet container authentication from {1}",
|
| | | principal.getName(), httpRequest.getRemoteAddr()));
|
| | | }
|
| | | }
|
| | | }
|
| | |
|
| | |
| | | FileBasedConfig config = (FileBasedConfig) getRepositoryConfig(r);
|
| | | if (config.isOutdated()) {
|
| | | // reload model
|
| | | logger.info(MessageFormat.format("Config for \"{0}\" has changed. Reloading model and updating cache.", repositoryName));
|
| | | logger.debug(MessageFormat.format("Config for \"{0}\" has changed. Reloading model and updating cache.", repositoryName));
|
| | | model = loadRepositoryModel(model.name);
|
| | | removeFromCachedRepositoryList(model.name);
|
| | | addToCachedRepositoryList(model);
|
| | |
| | | projectConfigs = new FileBasedConfig(getFileOrFolder(Keys.web.projectsFile, "${baseFolder}/projects.conf"), FS.detect());
|
| | | getProjectConfigs();
|
| | |
|
| | | // schedule mail engine
|
| | | configureMailExecutor(); |
| | | configureLuceneIndexing();
|
| | | configureGarbageCollector();
|
| | | if (startFederation) {
|
| | | configureFederation();
|
| | | }
|
| | | configureJGit();
|
| | | configureFanout();
|
| | | configureGitDaemon();
|
| | | |
| | | ContainerUtils.CVE_2007_0450.test();
|
| | | }
|
| | | |
| | | protected void configureMailExecutor() {
|
| | | if (mailExecutor.isReady()) {
|
| | | logger.info("Mail executor is scheduled to process the message queue every 2 minutes.");
|
| | | scheduledExecutor.scheduleAtFixedRate(mailExecutor, 1, 2, TimeUnit.MINUTES);
|
| | | } else {
|
| | | logger.warn("Mail server is not properly configured. Mail services disabled.");
|
| | | }
|
| | | }
|
| | |
|
| | | // schedule lucene engine
|
| | | enableLuceneIndexing();
|
| | | protected void configureLuceneIndexing() {
|
| | | scheduledExecutor.scheduleAtFixedRate(luceneExecutor, 1, 2, TimeUnit.MINUTES);
|
| | | logger.info("Lucene executor is scheduled to process indexed branches every 2 minutes.");
|
| | | }
|
| | |
|
| | | |
| | | protected void configureGarbageCollector() {
|
| | | // schedule gc engine
|
| | | if (gcExecutor.isReady()) {
|
| | | logger.info("GC executor is scheduled to scan repositories every 24 hours.");
|
| | |
| | | logger.info(MessageFormat.format("Next scheculed GC scan is in {0}", when));
|
| | | scheduledExecutor.scheduleAtFixedRate(gcExecutor, delay, 60*24, TimeUnit.MINUTES);
|
| | | }
|
| | | |
| | | if (startFederation) {
|
| | | configureFederation();
|
| | | }
|
| | |
|
| | | protected void configureJGit() {
|
| | | // Configure JGit
|
| | | WindowCacheConfig cfg = new WindowCacheConfig();
|
| | |
|
| | |
| | | } catch (IllegalArgumentException e) {
|
| | | logger.error("Failed to configure JGit parameters!", e);
|
| | | }
|
| | | }
|
| | |
|
| | | ContainerUtils.CVE_2007_0450.test();
|
| | | |
| | | protected void configureFanout() {
|
| | | // startup Fanout PubSub service
|
| | | if (settings.getInteger(Keys.fanout.port, 0) > 0) {
|
| | | String bindInterface = settings.getString(Keys.fanout.bindInterface, null);
|
| | |
| | | }
|
| | | }
|
| | |
|
| | | protected void enableLuceneIndexing() {
|
| | | scheduledExecutor.scheduleAtFixedRate(luceneExecutor, 1, 2, TimeUnit.MINUTES);
|
| | | logger.info("Lucene executor is scheduled to process indexed branches every 2 minutes.");
|
| | | protected void configureGitDaemon() {
|
| | | String bindInterface = settings.getString(Keys.git.daemonBindInterface, "localhost");
|
| | | int port = settings.getInteger(Keys.git.daemonPort, GitDaemon.DEFAULT_PORT);
|
| | | if (port > 0) {
|
| | | try {
|
| | | gitDaemon = new GitDaemon(bindInterface, port, getRepositoriesFolder());
|
| | | gitDaemon.start();
|
| | | logger.info(MessageFormat.format("Git daemon is listening on {0}:{1,number,0}", bindInterface, port));
|
| | | } catch (IOException e) {
|
| | | logger.error(MessageFormat.format("Failed to start Git daemon on {0}:{1,number.0}", bindInterface, port), e);
|
| | | }
|
| | | }
|
| | | }
|
| | |
|
| | | protected final Logger getLogger() {
|
| | |
| | | if (fanoutService != null) {
|
| | | fanoutService.stop();
|
| | | }
|
| | | if (gitDaemon != null) {
|
| | | gitDaemon.stop();
|
| | | }
|
| | | }
|
| | |
|
| | | /**
|
| | |
| | | // Override settings from the command-line
|
| | | settings.overrideSetting(Keys.realm.userService, params.userService);
|
| | | settings.overrideSetting(Keys.git.repositoriesFolder, params.repositoriesFolder);
|
| | | settings.overrideSetting(Keys.git.daemonPort, params.gitPort);
|
| | |
|
| | | // Start up an in-memory LDAP server, if configured
|
| | | try {
|
| | |
| | | @Parameter(names = "--ajpPort", description = "AJP port to serve. (port <= 0 will disable this connector)")
|
| | | public Integer ajpPort = FILESETTINGS.getInteger(Keys.server.ajpPort, 0);
|
| | |
|
| | | @Parameter(names = "--gitPort", description = "Git Daemon port to serve. (port <= 0 will disable this connector)")
|
| | | public Integer gitPort = FILESETTINGS.getInteger(Keys.git.daemonPort, 9418);
|
| | |
|
| | | @Parameter(names = "--alias", description = "Alias of SSL certificate in keystore for serving https.")
|
| | | public String alias = FILESETTINGS.getString(Keys.server.certificateAlias, "");
|
| | |
|
| | |
| | | */
|
| | | @Override
|
| | | protected boolean isActionAllowed(RepositoryModel repository, String action) {
|
| | | if (!StringUtils.isEmpty(action)) {
|
| | | if (action.equals(gitReceivePack)) {
|
| | | // Push request
|
| | | if (!repository.isBare) {
|
| | | logger.warn("Gitblit does not allow pushes to repositories with a working copy");
|
| | | return false;
|
| | | }
|
| | | }
|
| | | }
|
| | | // the log here has been moved into ReceiveHook to provide clients with
|
| | | // error messages
|
| | | return true;
|
| | | }
|
| | |
|
| | |
| | | }
|
| | |
|
| | | /**
|
| | | * Override the specified key with the specified value.
|
| | | * |
| | | * @param key
|
| | | * @param value
|
| | | */
|
| | | public void overrideSetting(String key, int value) {
|
| | | overrides.put(key, "" + value);
|
| | | }
|
| | |
|
| | | /**
|
| | | * Updates the values for the specified keys and persists the entire
|
| | | * configuration file.
|
| | | *
|
New file |
| | |
| | | /*
|
| | | * Copyright 2013 gitblit.com.
|
| | | *
|
| | | * Licensed under the Apache License, Version 2.0 (the "License");
|
| | | * you may not use this file except in compliance with the License.
|
| | | * You may obtain a copy of the License at
|
| | | *
|
| | | * http://www.apache.org/licenses/LICENSE-2.0
|
| | | *
|
| | | * Unless required by applicable law or agreed to in writing, software
|
| | | * distributed under the License is distributed on an "AS IS" BASIS,
|
| | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| | | * See the License for the specific language governing permissions and
|
| | | * limitations under the License.
|
| | | */
|
| | | package com.gitblit.git;
|
| | |
|
| | | import java.io.File;
|
| | | import java.net.InetSocketAddress;
|
| | |
|
| | | import org.eclipse.jgit.transport.Daemon;
|
| | | import org.eclipse.jgit.transport.DaemonClient;
|
| | |
|
| | | import com.gitblit.utils.StringUtils;
|
| | |
|
| | | /**
|
| | | * Gitblit's Git Daemon ignores any and all per-repository daemon settings
|
| | | * and integrates into Gitblit's security model.
|
| | | * |
| | | * @author James Moger
|
| | | *
|
| | | */
|
| | | public class GitDaemon extends Daemon {
|
| | |
|
| | | /**
|
| | | * Construct the Gitblit Git daemon.
|
| | | * |
| | | * @param bindInterface
|
| | | * the ip address of the interface to bind
|
| | | * @param port
|
| | | * the port to serve on
|
| | | * @param folder
|
| | | * the folder to serve from
|
| | | */
|
| | | public GitDaemon(String bindInterface, int port, File folder) {
|
| | | super(StringUtils.isEmpty(bindInterface) ? new InetSocketAddress(port) : new InetSocketAddress(bindInterface, port));
|
| | | |
| | | // set the repository resolver and pack factories
|
| | | setRepositoryResolver(new RepositoryResolver<DaemonClient>(folder));
|
| | | setUploadPackFactory(new GitblitUploadPackFactory<DaemonClient>());
|
| | | setReceivePackFactory(new GitblitReceivePackFactory<DaemonClient>());
|
| | | |
| | | // configure the git daemon to ignore the per-repository settings,
|
| | | // daemon.uploadpack and daemon.receivepack
|
| | | getService("git-upload-pack").setOverridable(false);
|
| | | getService("git-receive-pack").setOverridable(false);
|
| | | |
| | | // enable both the upload and receive services and let the resolver,
|
| | | // pack factories, and receive hook handle security
|
| | | getService("git-upload-pack").setEnabled(true);
|
| | | getService("git-receive-pack").setEnabled(true);
|
| | | }
|
| | | |
| | | }
|
New file |
| | |
| | | /*
|
| | | * Copyright 2011 gitblit.com.
|
| | | *
|
| | | * Licensed under the Apache License, Version 2.0 (the "License");
|
| | | * you may not use this file except in compliance with the License.
|
| | | * You may obtain a copy of the License at
|
| | | *
|
| | | * http://www.apache.org/licenses/LICENSE-2.0
|
| | | *
|
| | | * Unless required by applicable law or agreed to in writing, software
|
| | | * distributed under the License is distributed on an "AS IS" BASIS,
|
| | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| | | * See the License for the specific language governing permissions and
|
| | | * limitations under the License.
|
| | | */
|
| | | package com.gitblit.git;
|
| | |
|
| | | import javax.servlet.ServletConfig;
|
| | | import javax.servlet.ServletException;
|
| | | import javax.servlet.http.HttpServletRequest;
|
| | |
|
| | | import com.gitblit.GitBlit;
|
| | |
|
| | | /**
|
| | | * The GitServlet provides http/https access to Git repositories.
|
| | | * Access to this servlet is protected by the GitFilter.
|
| | | * |
| | | * @author James Moger
|
| | | * |
| | | */
|
| | | public class GitServlet extends org.eclipse.jgit.http.server.GitServlet {
|
| | |
|
| | | private static final long serialVersionUID = 1L;
|
| | |
|
| | | @Override
|
| | | public void init(ServletConfig config) throws ServletException {
|
| | | setRepositoryResolver(new RepositoryResolver<HttpServletRequest>(GitBlit.getRepositoriesFolder()));
|
| | | setUploadPackFactory(new GitblitUploadPackFactory<HttpServletRequest>());
|
| | | setReceivePackFactory(new GitblitReceivePackFactory<HttpServletRequest>());
|
| | | super.init(config);
|
| | | }
|
| | | }
|
New file |
| | |
| | | /* |
| | | * Copyright 2011 gitblit.com. |
| | | * |
| | | * Licensed under the Apache License, Version 2.0 (the "License"); |
| | | * you may not use this file except in compliance with the License. |
| | | * You may obtain a copy of the License at |
| | | * |
| | | * http://www.apache.org/licenses/LICENSE-2.0 |
| | | * |
| | | * Unless required by applicable law or agreed to in writing, software |
| | | * distributed under the License is distributed on an "AS IS" BASIS, |
| | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | * See the License for the specific language governing permissions and |
| | | * limitations under the License. |
| | | */ |
| | | package com.gitblit.git; |
| | | |
| | | import javax.servlet.http.HttpServletRequest; |
| | | |
| | | import org.eclipse.jgit.lib.PersonIdent; |
| | | import org.eclipse.jgit.lib.Repository; |
| | | import org.eclipse.jgit.transport.DaemonClient; |
| | | import org.eclipse.jgit.transport.ReceivePack; |
| | | import org.eclipse.jgit.transport.resolver.ReceivePackFactory; |
| | | import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException; |
| | | import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | |
| | | import com.gitblit.GitBlit; |
| | | import com.gitblit.models.RepositoryModel; |
| | | import com.gitblit.models.UserModel; |
| | | import com.gitblit.utils.HttpUtils; |
| | | |
| | | /** |
| | | * The receive pack factory creates a receive pack which accepts pushes from |
| | | * clients. |
| | | * |
| | | * @author James Moger |
| | | * |
| | | * @param <X> the connection type |
| | | */ |
| | | public class GitblitReceivePackFactory<X> implements ReceivePackFactory<X> { |
| | | |
| | | protected final Logger logger = LoggerFactory.getLogger(GitblitReceivePackFactory.class); |
| | | |
| | | @Override |
| | | public ReceivePack create(X req, Repository db) |
| | | throws ServiceNotEnabledException, ServiceNotAuthorizedException { |
| | | |
| | | final ReceivePack rp = new ReceivePack(db); |
| | | UserModel user = UserModel.ANONYMOUS; |
| | | String origin = ""; |
| | | String gitblitUrl = ""; |
| | | int timeout = 0; |
| | | |
| | | // XXX extract the repository name from the config |
| | | // the name is injected by GitRepositoryResolver |
| | | String repositoryName = db.getConfig().getString("gitblit", null, "repositoryName"); |
| | | |
| | | |
| | | if (req instanceof HttpServletRequest) { |
| | | // http/https request may or may not be authenticated |
| | | HttpServletRequest request = (HttpServletRequest) req; |
| | | origin = request.getRemoteHost(); |
| | | gitblitUrl = HttpUtils.getGitblitURL(request); |
| | | |
| | | // determine pushing user |
| | | String username = request.getRemoteUser(); |
| | | if (username != null && !"".equals(username)) { |
| | | user = GitBlit.self().getUserModel(username); |
| | | if (user == null) { |
| | | // anonymous push, create a temporary usermodel |
| | | user = new UserModel(username); |
| | | } |
| | | } |
| | | } else if (req instanceof DaemonClient) { |
| | | // git daemon request is alway anonymous |
| | | DaemonClient client = (DaemonClient) req; |
| | | origin = client.getRemoteAddress().getHostAddress(); |
| | | // set timeout from Git daemon |
| | | timeout = client.getDaemon().getTimeout(); |
| | | } |
| | | |
| | | // set pushing user identity for reflog |
| | | rp.setRefLogIdent(new PersonIdent(user.username, user.username + "@" + origin)); |
| | | rp.setTimeout(timeout); |
| | | |
| | | // set advanced ref permissions |
| | | RepositoryModel repository = GitBlit.self().getRepositoryModel(repositoryName); |
| | | rp.setAllowCreates(user.canCreateRef(repository)); |
| | | rp.setAllowDeletes(user.canDeleteRef(repository)); |
| | | rp.setAllowNonFastForwards(user.canRewindRef(repository)); |
| | | |
| | | // setup the receive hook |
| | | ReceiveHook hook = new ReceiveHook(); |
| | | hook.user = user; |
| | | hook.repository = repository; |
| | | hook.gitblitUrl = gitblitUrl; |
| | | |
| | | rp.setPreReceiveHook(hook); |
| | | rp.setPostReceiveHook(hook); |
| | | |
| | | return rp; |
| | | } |
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright 2011 gitblit.com. |
| | | * |
| | | * Licensed under the Apache License, Version 2.0 (the "License"); |
| | | * you may not use this file except in compliance with the License. |
| | | * You may obtain a copy of the License at |
| | | * |
| | | * http://www.apache.org/licenses/LICENSE-2.0 |
| | | * |
| | | * Unless required by applicable law or agreed to in writing, software |
| | | * distributed under the License is distributed on an "AS IS" BASIS, |
| | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | * See the License for the specific language governing permissions and |
| | | * limitations under the License. |
| | | */ |
| | | package com.gitblit.git; |
| | | |
| | | import java.util.Map; |
| | | |
| | | import javax.servlet.http.HttpServletRequest; |
| | | |
| | | import org.eclipse.jgit.lib.Ref; |
| | | import org.eclipse.jgit.lib.Repository; |
| | | import org.eclipse.jgit.transport.DaemonClient; |
| | | import org.eclipse.jgit.transport.RefFilter; |
| | | import org.eclipse.jgit.transport.UploadPack; |
| | | import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException; |
| | | import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException; |
| | | import org.eclipse.jgit.transport.resolver.UploadPackFactory; |
| | | |
| | | import com.gitblit.GitBlit; |
| | | import com.gitblit.models.UserModel; |
| | | import com.gitblit.utils.IssueUtils; |
| | | import com.gitblit.utils.PushLogUtils; |
| | | |
| | | /** |
| | | * The upload pack factory creates an upload pack which controls what refs are |
| | | * advertised to cloning/pulling clients. |
| | | * |
| | | * @author James Moger |
| | | * |
| | | * @param <X> the connection type |
| | | */ |
| | | public class GitblitUploadPackFactory<X> implements UploadPackFactory<X> { |
| | | |
| | | @Override |
| | | public UploadPack create(X req, Repository db) |
| | | throws ServiceNotEnabledException, ServiceNotAuthorizedException { |
| | | |
| | | UserModel user = UserModel.ANONYMOUS; |
| | | int timeout = 0; |
| | | |
| | | if (req instanceof HttpServletRequest) { |
| | | // http/https request may or may not be authenticated |
| | | user = GitBlit.self().authenticate((HttpServletRequest) req); |
| | | if (user == null) { |
| | | user = UserModel.ANONYMOUS; |
| | | } |
| | | } else if (req instanceof DaemonClient) { |
| | | // git daemon request is always anonymous |
| | | DaemonClient client = (DaemonClient) req; |
| | | // set timeout from Git daemon |
| | | timeout = client.getDaemon().getTimeout(); |
| | | } |
| | | |
| | | RefFilter refFilter = new UserRefFilter(user); |
| | | UploadPack up = new UploadPack(db); |
| | | up.setRefFilter(refFilter); |
| | | up.setTimeout(timeout); |
| | | |
| | | return up; |
| | | } |
| | | |
| | | /** |
| | | * Restricts advertisement of certain refs based on the permission of the |
| | | * requesting user. |
| | | */ |
| | | public static class UserRefFilter implements RefFilter { |
| | | |
| | | final UserModel user; |
| | | |
| | | public UserRefFilter(UserModel user) { |
| | | this.user = user; |
| | | } |
| | | |
| | | @Override |
| | | public Map<String, Ref> filter(Map<String, Ref> refs) { |
| | | if (user.canAdmin()) { |
| | | // admins can see all refs |
| | | return refs; |
| | | } |
| | | |
| | | // normal users can not clone gitblit refs |
| | | refs.remove(IssueUtils.GB_ISSUES); |
| | | refs.remove(PushLogUtils.GB_PUSHES); |
| | | return refs; |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | /*
|
| | | * Copyright 2011 gitblit.com.
|
| | | *
|
| | | * Licensed under the Apache License, Version 2.0 (the "License");
|
| | | * you may not use this file except in compliance with the License.
|
| | | * You may obtain a copy of the License at
|
| | | *
|
| | | * http://www.apache.org/licenses/LICENSE-2.0
|
| | | *
|
| | | * Unless required by applicable law or agreed to in writing, software
|
| | | * distributed under the License is distributed on an "AS IS" BASIS,
|
| | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| | | * See the License for the specific language governing permissions and
|
| | | * limitations under the License.
|
| | | */
|
| | | package com.gitblit.git;
|
| | |
|
| | | import groovy.lang.Binding;
|
| | | import groovy.util.GroovyScriptEngine;
|
| | |
|
| | | import java.io.File;
|
| | | import java.io.IOException;
|
| | | import java.text.MessageFormat;
|
| | | import java.util.Collection;
|
| | | import java.util.LinkedHashSet;
|
| | | import java.util.List;
|
| | | import java.util.Set;
|
| | |
|
| | | import org.eclipse.jgit.lib.PersonIdent;
|
| | | import org.eclipse.jgit.revwalk.RevCommit;
|
| | | import org.eclipse.jgit.transport.PostReceiveHook;
|
| | | import org.eclipse.jgit.transport.PreReceiveHook;
|
| | | import org.eclipse.jgit.transport.ReceiveCommand;
|
| | | import org.eclipse.jgit.transport.ReceiveCommand.Result;
|
| | | import org.eclipse.jgit.transport.ReceivePack;
|
| | | import org.slf4j.Logger;
|
| | | import org.slf4j.LoggerFactory;
|
| | |
|
| | | import com.gitblit.Constants.AccessRestrictionType;
|
| | | import com.gitblit.GitBlit;
|
| | | import com.gitblit.Keys;
|
| | | import com.gitblit.client.Translation;
|
| | | import com.gitblit.models.RepositoryModel;
|
| | | import com.gitblit.models.UserModel;
|
| | | import com.gitblit.utils.ClientLogger;
|
| | | import com.gitblit.utils.JGitUtils;
|
| | | import com.gitblit.utils.PushLogUtils;
|
| | | import com.gitblit.utils.StringUtils;
|
| | |
|
| | | /**
|
| | | * The Gitblit receive hook allows for special processing on push events.
|
| | | * That might include rejecting writes to specific branches or executing a
|
| | | * script.
|
| | | * |
| | | * @author James Moger
|
| | | * |
| | | */
|
| | | public class ReceiveHook implements PreReceiveHook, PostReceiveHook {
|
| | |
|
| | | protected final Logger logger = LoggerFactory.getLogger(ReceiveHook.class);
|
| | |
|
| | | protected UserModel user;
|
| | | |
| | | protected RepositoryModel repository;
|
| | |
|
| | | protected String gitblitUrl;
|
| | |
|
| | | private GroovyScriptEngine gse;
|
| | |
|
| | | private File groovyDir;
|
| | |
|
| | | public ReceiveHook() {
|
| | | groovyDir = GitBlit.getGroovyScriptsFolder();
|
| | | try {
|
| | | // set Grape root
|
| | | File grapeRoot = GitBlit.getFileOrFolder(Keys.groovy.grapeFolder, "${baseFolder}/groovy/grape").getAbsoluteFile();
|
| | | grapeRoot.mkdirs();
|
| | | System.setProperty("grape.root", grapeRoot.getAbsolutePath());
|
| | |
|
| | | gse = new GroovyScriptEngine(groovyDir.getAbsolutePath()); |
| | | } catch (IOException e) {
|
| | | //throw new ServletException("Failed to instantiate Groovy Script Engine!", e);
|
| | | }
|
| | | }
|
| | |
|
| | | /**
|
| | | * Instrumentation point where the incoming push event has been parsed,
|
| | | * validated, objects created BUT refs have not been updated. You might
|
| | | * use this to enforce a branch-write permissions model.
|
| | | */
|
| | | @Override
|
| | | public void onPreReceive(ReceivePack rp, Collection<ReceiveCommand> commands) {
|
| | | if (repository.isFrozen) {
|
| | | // repository is frozen/readonly
|
| | | String reason = MessageFormat.format("Gitblit does not allow pushes to \"{0}\" because it is frozen!", repository.name);
|
| | | logger.warn(reason);
|
| | | for (ReceiveCommand cmd : commands) {
|
| | | cmd.setResult(Result.REJECTED_OTHER_REASON, reason);
|
| | | }
|
| | | return;
|
| | | }
|
| | | |
| | | if (!repository.isBare) {
|
| | | // repository has a working copy
|
| | | String reason = MessageFormat.format("Gitblit does not allow pushes to \"{0}\" because it has a working copy!", repository.name);
|
| | | logger.warn(reason);
|
| | | for (ReceiveCommand cmd : commands) {
|
| | | cmd.setResult(Result.REJECTED_OTHER_REASON, reason);
|
| | | }
|
| | | return;
|
| | | }
|
| | |
|
| | | if (!user.canPush(repository)) {
|
| | | // user does not have push permissions
|
| | | String reason = MessageFormat.format("User \"{0}\" does not have push permissions for \"{1}\"!", user.username, repository.name);
|
| | | logger.warn(reason);
|
| | | for (ReceiveCommand cmd : commands) {
|
| | | cmd.setResult(Result.REJECTED_OTHER_REASON, reason);
|
| | | }
|
| | | return;
|
| | | }
|
| | |
|
| | | if (repository.accessRestriction.atLeast(AccessRestrictionType.PUSH) && repository.verifyCommitter) {
|
| | | // enforce committer verification
|
| | | if (StringUtils.isEmpty(user.emailAddress)) {
|
| | | // emit warning if user does not have an email address |
| | | logger.warn(MessageFormat.format("Consider setting an email address for {0} ({1}) to improve committer verification.", user.getDisplayName(), user.username));
|
| | | }
|
| | |
|
| | | // Optionally enforce that the committer of the left parent chain
|
| | | // match the account being used to push the commits.
|
| | | // |
| | | // This requires all merge commits are executed with the "--no-ff"
|
| | | // option to force a merge commit even if fast-forward is possible.
|
| | | // This ensures that the chain of left parents has the commit
|
| | | // identity of the merging user.
|
| | | boolean allRejected = false;
|
| | | for (ReceiveCommand cmd : commands) {
|
| | | try {
|
| | | List<RevCommit> commits = JGitUtils.getRevLog(rp.getRepository(), cmd.getOldId().name(), cmd.getNewId().name());
|
| | | for (RevCommit commit : commits) {
|
| | | PersonIdent committer = commit.getCommitterIdent();
|
| | | if (!user.is(committer.getName(), committer.getEmailAddress())) {
|
| | | String reason;
|
| | | if (StringUtils.isEmpty(user.emailAddress)) {
|
| | | // account does not have en email address
|
| | | reason = MessageFormat.format("{0} by {1} <{2}> was not committed by {3} ({4})", commit.getId().name(), committer.getName(), StringUtils.isEmpty(committer.getEmailAddress()) ? "?":committer.getEmailAddress(), user.getDisplayName(), user.username);
|
| | | } else {
|
| | | // account has an email address
|
| | | reason = MessageFormat.format("{0} by {1} <{2}> was not committed by {3} ({4}) <{5}>", commit.getId().name(), committer.getName(), StringUtils.isEmpty(committer.getEmailAddress()) ? "?":committer.getEmailAddress(), user.getDisplayName(), user.username, user.emailAddress);
|
| | | }
|
| | | logger.warn(reason);
|
| | | cmd.setResult(Result.REJECTED_OTHER_REASON, reason);
|
| | | allRejected &= true;
|
| | | break;
|
| | | } else {
|
| | | allRejected = false;
|
| | | }
|
| | | }
|
| | | } catch (Exception e) {
|
| | | logger.error("Failed to verify commits were made by pushing user", e);
|
| | | }
|
| | | }
|
| | |
|
| | | if (allRejected) {
|
| | | // all ref updates rejected, abort
|
| | | return;
|
| | | }
|
| | | }
|
| | |
|
| | | Set<String> scripts = new LinkedHashSet<String>();
|
| | | scripts.addAll(GitBlit.self().getPreReceiveScriptsInherited(repository));
|
| | | scripts.addAll(repository.preReceiveScripts);
|
| | | runGroovy(repository, user, commands, rp, scripts);
|
| | | for (ReceiveCommand cmd : commands) {
|
| | | if (!Result.NOT_ATTEMPTED.equals(cmd.getResult())) {
|
| | | logger.warn(MessageFormat.format("{0} {1} because \"{2}\"", cmd.getNewId()
|
| | | .getName(), cmd.getResult(), cmd.getMessage()));
|
| | | }
|
| | | }
|
| | | }
|
| | |
|
| | | /**
|
| | | * Instrumentation point where the incoming push has been applied to the
|
| | | * repository. This is the point where we would trigger a Jenkins build
|
| | | * or send an email.
|
| | | */
|
| | | @Override
|
| | | public void onPostReceive(ReceivePack rp, Collection<ReceiveCommand> commands) {
|
| | | if (commands.size() == 0) {
|
| | | logger.debug("skipping post-receive hooks, no refs created, updated, or removed");
|
| | | return;
|
| | | }
|
| | |
|
| | | // log ref changes
|
| | | for (ReceiveCommand cmd : commands) {
|
| | | if (Result.OK.equals(cmd.getResult())) {
|
| | | // add some logging for important ref changes
|
| | | switch (cmd.getType()) {
|
| | | case DELETE:
|
| | | logger.info(MessageFormat.format("{0} DELETED {1} in {2} ({3})", user.username, cmd.getRefName(), repository.name, cmd.getOldId().name()));
|
| | | break;
|
| | | case CREATE:
|
| | | logger.info(MessageFormat.format("{0} CREATED {1} in {2}", user.username, cmd.getRefName(), repository.name));
|
| | | break;
|
| | | case UPDATE:
|
| | | logger.info(MessageFormat.format("{0} UPDATED {1} in {2} (from {3} to {4})", user.username, cmd.getRefName(), repository.name, cmd.getOldId().name(), cmd.getNewId().name()));
|
| | | break;
|
| | | case UPDATE_NONFASTFORWARD:
|
| | | logger.info(MessageFormat.format("{0} UPDATED NON-FAST-FORWARD {1} in {2} (from {3} to {4})", user.username, cmd.getRefName(), repository.name, cmd.getOldId().name(), cmd.getNewId().name()));
|
| | | break;
|
| | | default:
|
| | | break;
|
| | | }
|
| | | }
|
| | | }
|
| | |
|
| | | if (repository.useIncrementalPushTags) {
|
| | | // tag each pushed branch tip
|
| | | String emailAddress = user.emailAddress == null ? rp.getRefLogIdent().getEmailAddress() : user.emailAddress;
|
| | | PersonIdent userIdent = new PersonIdent(user.getDisplayName(), emailAddress);
|
| | |
|
| | | for (ReceiveCommand cmd : commands) {
|
| | | if (!cmd.getRefName().startsWith("refs/heads/")) {
|
| | | // only tag branch ref changes
|
| | | continue;
|
| | | }
|
| | |
|
| | | if (!ReceiveCommand.Type.DELETE.equals(cmd.getType())
|
| | | && ReceiveCommand.Result.OK.equals(cmd.getResult())) {
|
| | | String objectId = cmd.getNewId().getName();
|
| | | String branch = cmd.getRefName().substring("refs/heads/".length());
|
| | | // get translation based on the server's locale setting
|
| | | String template = Translation.get("gb.incrementalPushTagMessage");
|
| | | String msg = MessageFormat.format(template, branch);
|
| | | String prefix;
|
| | | if (StringUtils.isEmpty(repository.incrementalPushTagPrefix)) {
|
| | | prefix = GitBlit.getString(Keys.git.defaultIncrementalPushTagPrefix, "r");
|
| | | } else {
|
| | | prefix = repository.incrementalPushTagPrefix;
|
| | | }
|
| | |
|
| | | JGitUtils.createIncrementalRevisionTag(
|
| | | rp.getRepository(),
|
| | | objectId,
|
| | | userIdent,
|
| | | prefix,
|
| | | "0",
|
| | | msg);
|
| | | }
|
| | | } |
| | | }
|
| | |
|
| | | // update push log
|
| | | try {
|
| | | PushLogUtils.updatePushLog(user, rp.getRepository(), commands);
|
| | | logger.debug(MessageFormat.format("{0} push log updated", repository.name));
|
| | | } catch (Exception e) {
|
| | | logger.error(MessageFormat.format("Failed to update {0} pushlog", repository.name), e);
|
| | | }
|
| | |
|
| | | // run Groovy hook scripts |
| | | Set<String> scripts = new LinkedHashSet<String>();
|
| | | scripts.addAll(GitBlit.self().getPostReceiveScriptsInherited(repository));
|
| | | scripts.addAll(repository.postReceiveScripts);
|
| | | runGroovy(repository, user, commands, rp, scripts);
|
| | | }
|
| | |
|
| | | /**
|
| | | * Runs the specified Groovy hook scripts.
|
| | | * |
| | | * @param repository
|
| | | * @param user
|
| | | * @param commands
|
| | | * @param scripts
|
| | | */
|
| | | protected void runGroovy(RepositoryModel repository, UserModel user,
|
| | | Collection<ReceiveCommand> commands, ReceivePack rp, Set<String> scripts) {
|
| | | if (scripts == null || scripts.size() == 0) {
|
| | | // no Groovy scripts to execute
|
| | | return;
|
| | | }
|
| | |
|
| | | Binding binding = new Binding();
|
| | | binding.setVariable("gitblit", GitBlit.self());
|
| | | binding.setVariable("repository", repository);
|
| | | binding.setVariable("receivePack", rp);
|
| | | binding.setVariable("user", user);
|
| | | binding.setVariable("commands", commands);
|
| | | binding.setVariable("url", gitblitUrl);
|
| | | binding.setVariable("logger", logger);
|
| | | binding.setVariable("clientLogger", new ClientLogger(rp));
|
| | | for (String script : scripts) {
|
| | | if (StringUtils.isEmpty(script)) {
|
| | | continue;
|
| | | }
|
| | | // allow script to be specified without .groovy extension
|
| | | // this is easier to read in the settings
|
| | | File file = new File(groovyDir, script);
|
| | | if (!file.exists() && !script.toLowerCase().endsWith(".groovy")) {
|
| | | file = new File(groovyDir, script + ".groovy");
|
| | | if (file.exists()) {
|
| | | script = file.getName();
|
| | | }
|
| | | }
|
| | | try {
|
| | | Object result = gse.run(script, binding);
|
| | | if (result instanceof Boolean) {
|
| | | if (!((Boolean) result)) {
|
| | | logger.error(MessageFormat.format(
|
| | | "Groovy script {0} has failed! Hook scripts aborted.", script));
|
| | | break;
|
| | | }
|
| | | }
|
| | | } catch (Exception e) {
|
| | | logger.error(
|
| | | MessageFormat.format("Failed to execute Groovy script {0}", script), e);
|
| | | }
|
| | | }
|
| | | }
|
| | | } |
New file |
| | |
| | | /* |
| | | * Copyright 2013 gitblit.com. |
| | | * |
| | | * Licensed under the Apache License, Version 2.0 (the "License"); |
| | | * you may not use this file except in compliance with the License. |
| | | * You may obtain a copy of the License at |
| | | * |
| | | * http://www.apache.org/licenses/LICENSE-2.0 |
| | | * |
| | | * Unless required by applicable law or agreed to in writing, software |
| | | * distributed under the License is distributed on an "AS IS" BASIS, |
| | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | * See the License for the specific language governing permissions and |
| | | * limitations under the License. |
| | | */ |
| | | package com.gitblit.git; |
| | | |
| | | import java.io.File; |
| | | import java.io.IOException; |
| | | import java.text.MessageFormat; |
| | | |
| | | import javax.servlet.http.HttpServletRequest; |
| | | |
| | | import org.eclipse.jgit.errors.RepositoryNotFoundException; |
| | | import org.eclipse.jgit.lib.Repository; |
| | | import org.eclipse.jgit.transport.DaemonClient; |
| | | import org.eclipse.jgit.transport.resolver.FileResolver; |
| | | import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | |
| | | import com.gitblit.GitBlit; |
| | | import com.gitblit.models.RepositoryModel; |
| | | import com.gitblit.models.UserModel; |
| | | |
| | | /** |
| | | * Resolves repositories and grants export access. |
| | | * |
| | | * @author James Moger |
| | | * |
| | | */ |
| | | public class RepositoryResolver<X> extends FileResolver<X> { |
| | | |
| | | private final Logger logger = LoggerFactory.getLogger(RepositoryResolver.class); |
| | | |
| | | public RepositoryResolver(File repositoriesFolder) { |
| | | super(repositoriesFolder, true); |
| | | } |
| | | |
| | | /** |
| | | * Open the repository and inject the repository name into the settings. |
| | | */ |
| | | @Override |
| | | public Repository open(final X req, final String name) |
| | | throws RepositoryNotFoundException, ServiceNotEnabledException { |
| | | Repository repo = super.open(req, name); |
| | | // XXX Set repository name for the pack factories |
| | | // We do this because the JGit API does not have a consistent way to |
| | | // retrieve the repository name from the pack factories or the hooks. |
| | | repo.getConfig().setString("gitblit", null, "repositoryName", name); |
| | | return repo; |
| | | } |
| | | |
| | | /** |
| | | * Check if this repository can be served by the requested client connection. |
| | | */ |
| | | @Override |
| | | protected boolean isExportOk(X req, String repositoryName, Repository db) throws IOException { |
| | | RepositoryModel model = GitBlit.self().getRepositoryModel(repositoryName); |
| | | |
| | | String scheme = null; |
| | | UserModel user = null; |
| | | String origin = null; |
| | | |
| | | if (req instanceof DaemonClient) { |
| | | // git daemon request |
| | | // this is an anonymous/unauthenticated protocol |
| | | DaemonClient client = (DaemonClient) req; |
| | | scheme = "git"; |
| | | origin = client.getRemoteAddress().toString(); |
| | | user = UserModel.ANONYMOUS; |
| | | } else if (req instanceof HttpServletRequest) { |
| | | // http/https request |
| | | HttpServletRequest httpRequest = (HttpServletRequest) req; |
| | | scheme = httpRequest.getScheme(); |
| | | origin = httpRequest.getRemoteAddr(); |
| | | user = GitBlit.self().authenticate(httpRequest); |
| | | if (user == null) { |
| | | user = UserModel.ANONYMOUS; |
| | | } |
| | | } |
| | | |
| | | if (user.canClone(model)) { |
| | | // user can access this git repo |
| | | logger.debug(MessageFormat.format("{0}:// access of {1} by {2} from {3} PERMITTED", |
| | | scheme, repositoryName, user.username, origin)); |
| | | return true; |
| | | } |
| | | |
| | | // user can not access this git repo |
| | | logger.warn(MessageFormat.format("{0}:// access of {1} by {2} from {3} DENIED", |
| | | scheme, repositoryName, user.username, origin)); |
| | | return false; |
| | | } |
| | | } |
| | |
| | | ## Standard Features (GO/WAR)
|
| | | - JGit SmartHTTP servlet
|
| | | - JGit http/https SmartHTTP servlet
|
| | | - JGit git protocol daemon
|
| | | - Browser and git client authentication
|
| | | - Four *per-repository* access restriction configurations with a Read-Only control flag
|
| | | -  *Anonymous View, Clone & Push*
|
| | |
| | | - Built-in AJP connector for Apache httpd
|
| | |
|
| | | ## Limitations
|
| | | - HTTP/HTTPS are the only supported Git protocols
|
| | | - HTTP/HTTPS/GIT are the only supported Git protocols
|
| | | - Built-in access controls are not path-based, they are repository-based.
|
| | |
|
| | | [jgit]: http://eclipse.org/jgit "Eclipse JGit Site"
|
| | |
| | | ObjectCacheTest.class, PermissionsTest.class, UserServiceTest.class, LdapUserServiceTest.class,
|
| | | MarkdownUtilsTest.class, JGitUtilsTest.class, SyndicationUtilsTest.class,
|
| | | DiffUtilsTest.class, MetricUtilsTest.class, TicgitUtilsTest.class, X509UtilsTest.class,
|
| | | GitBlitTest.class, FederationTests.class, RpcTests.class, GitServletTest.class,
|
| | | GitBlitTest.class, FederationTests.class, RpcTests.class, GitServletTest.class, GitDaemonTest.class,
|
| | | GroovyScriptTest.class, LuceneExecutorTest.class, IssuesTest.class, RepositoryModelTest.class,
|
| | | FanoutServiceTest.class })
|
| | | public class GitBlitSuite {
|
| | |
| | | public static final File REPOSITORIES = new File("data/git");
|
| | |
|
| | | static int port = 8280;
|
| | | static int gitPort = 8300;
|
| | | static int shutdownPort = 8281;
|
| | |
|
| | | public static String url = "http://localhost:" + port;
|
| | | public static String gitServletUrl = "http://localhost:" + port + "/git";
|
| | | public static String gitDaemonUrl = "git://localhost:" + gitPort;
|
| | | public static String account = "admin";
|
| | | public static String password = "admin";
|
| | |
|
| | |
| | | Executors.newSingleThreadExecutor().execute(new Runnable() {
|
| | | public void run() {
|
| | | GitBlitServer.main("--httpPort", "" + port, "--httpsPort", "0", "--shutdownPort",
|
| | | "" + shutdownPort, "--repositoriesFolder",
|
| | | "" + shutdownPort, "--gitPort", "" + gitPort, "--repositoriesFolder",
|
| | | "\"" + GitBlitSuite.REPOSITORIES.getAbsolutePath() + "\"", "--userService",
|
| | | "test-users.conf", "--settings", "test-gitblit.properties",
|
| | | "--baseFolder", "data");
|
| | |
| | |
|
| | | private static void cloneOrFetch(String name, String fromUrl) throws Exception {
|
| | | System.out.print("Fetching " + name + "... ");
|
| | | try {
|
| | | JGitUtils.cloneRepository(REPOSITORIES, name, fromUrl);
|
| | | } catch (Throwable t) {
|
| | | System.out.println("Error: " + t.getMessage());
|
| | | }
|
| | | System.out.println("done.");
|
| | | }
|
| | |
|
New file |
| | |
| | | /* |
| | | * Copyright 2013 gitblit.com. |
| | | * |
| | | * Licensed under the Apache License, Version 2.0 (the "License"); |
| | | * you may not use this file except in compliance with the License. |
| | | * You may obtain a copy of the License at |
| | | * |
| | | * http://www.apache.org/licenses/LICENSE-2.0 |
| | | * |
| | | * Unless required by applicable law or agreed to in writing, software |
| | | * distributed under the License is distributed on an "AS IS" BASIS, |
| | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| | | * See the License for the specific language governing permissions and |
| | | * limitations under the License. |
| | | */ |
| | | package com.gitblit.tests; |
| | | |
| | | import java.io.BufferedWriter; |
| | | import java.io.File; |
| | | import java.io.FileOutputStream; |
| | | import java.io.OutputStreamWriter; |
| | | import java.text.MessageFormat; |
| | | import java.util.Date; |
| | | import java.util.concurrent.atomic.AtomicBoolean; |
| | | |
| | | import org.eclipse.jgit.api.CloneCommand; |
| | | import org.eclipse.jgit.api.Git; |
| | | import org.eclipse.jgit.lib.Constants; |
| | | import org.eclipse.jgit.transport.PushResult; |
| | | import org.eclipse.jgit.transport.RemoteRefUpdate; |
| | | import org.eclipse.jgit.transport.RemoteRefUpdate.Status; |
| | | import org.eclipse.jgit.util.FileUtils; |
| | | import org.junit.AfterClass; |
| | | import org.junit.Assert; |
| | | import org.junit.BeforeClass; |
| | | import org.junit.Test; |
| | | |
| | | import com.gitblit.Constants.AccessRestrictionType; |
| | | import com.gitblit.Constants.AuthorizationControl; |
| | | import com.gitblit.GitBlit; |
| | | import com.gitblit.models.RepositoryModel; |
| | | |
| | | public class GitDaemonTest extends Assert { |
| | | |
| | | static File ticgitFolder = new File(GitBlitSuite.REPOSITORIES, "working/ticgit"); |
| | | |
| | | static File ticgit2Folder = new File(GitBlitSuite.REPOSITORIES, "working/ticgit2"); |
| | | |
| | | static File jgitFolder = new File(GitBlitSuite.REPOSITORIES, "working/jgit"); |
| | | |
| | | static File jgit2Folder = new File(GitBlitSuite.REPOSITORIES, "working/jgit2"); |
| | | |
| | | String url = GitBlitSuite.gitDaemonUrl; |
| | | |
| | | private static final AtomicBoolean started = new AtomicBoolean(false); |
| | | |
| | | @BeforeClass |
| | | public static void startGitblit() throws Exception { |
| | | started.set(GitBlitSuite.startGitblit()); |
| | | } |
| | | |
| | | @AfterClass |
| | | public static void stopGitblit() throws Exception { |
| | | if (started.get()) { |
| | | GitBlitSuite.stopGitblit(); |
| | | deleteWorkingFolders(); |
| | | } |
| | | } |
| | | |
| | | public static void deleteWorkingFolders() throws Exception { |
| | | if (ticgitFolder.exists()) { |
| | | GitBlitSuite.close(ticgitFolder); |
| | | FileUtils.delete(ticgitFolder, FileUtils.RECURSIVE); |
| | | } |
| | | if (ticgit2Folder.exists()) { |
| | | GitBlitSuite.close(ticgit2Folder); |
| | | FileUtils.delete(ticgit2Folder, FileUtils.RECURSIVE); |
| | | } |
| | | if (jgitFolder.exists()) { |
| | | GitBlitSuite.close(jgitFolder); |
| | | FileUtils.delete(jgitFolder, FileUtils.RECURSIVE); |
| | | } |
| | | if (jgit2Folder.exists()) { |
| | | GitBlitSuite.close(jgit2Folder); |
| | | FileUtils.delete(jgit2Folder, FileUtils.RECURSIVE); |
| | | } |
| | | } |
| | | |
| | | @Test |
| | | public void testAnonymousClone() throws Exception { |
| | | GitBlitSuite.close(ticgitFolder); |
| | | if (ticgitFolder.exists()) { |
| | | FileUtils.delete(ticgitFolder, FileUtils.RECURSIVE | FileUtils.RETRY); |
| | | } |
| | | |
| | | // set push restriction |
| | | RepositoryModel model = GitBlit.self().getRepositoryModel("ticgit.git"); |
| | | model.accessRestriction = AccessRestrictionType.PUSH; |
| | | model.authorizationControl = AuthorizationControl.NAMED; |
| | | GitBlit.self().updateRepositoryModel(model.name, model, false); |
| | | |
| | | CloneCommand clone = Git.cloneRepository(); |
| | | clone.setURI(MessageFormat.format("{0}/ticgit.git", url)); |
| | | clone.setDirectory(ticgitFolder); |
| | | clone.setBare(false); |
| | | clone.setCloneAllBranches(true); |
| | | GitBlitSuite.close(clone.call()); |
| | | assertTrue(true); |
| | | |
| | | // restore anonymous repository access |
| | | model.accessRestriction = AccessRestrictionType.NONE; |
| | | model.authorizationControl = AuthorizationControl.NAMED; |
| | | GitBlit.self().updateRepositoryModel(model.name, model, false); |
| | | } |
| | | |
| | | @Test |
| | | public void testCloneRestrictedRepo() throws Exception { |
| | | GitBlitSuite.close(ticgit2Folder); |
| | | if (ticgit2Folder.exists()) { |
| | | FileUtils.delete(ticgit2Folder, FileUtils.RECURSIVE); |
| | | } |
| | | |
| | | // restrict repository access |
| | | RepositoryModel model = GitBlit.self().getRepositoryModel("ticgit.git"); |
| | | model.accessRestriction = AccessRestrictionType.CLONE; |
| | | model.authorizationControl = AuthorizationControl.NAMED; |
| | | GitBlit.self().updateRepositoryModel(model.name, model, false); |
| | | |
| | | // delete any existing working folder |
| | | boolean cloned = false; |
| | | try { |
| | | CloneCommand clone = Git.cloneRepository(); |
| | | clone.setURI(MessageFormat.format("{0}/ticgit.git", url)); |
| | | clone.setDirectory(ticgit2Folder); |
| | | clone.setBare(false); |
| | | clone.setCloneAllBranches(true); |
| | | GitBlitSuite.close(clone.call()); |
| | | cloned = true; |
| | | } catch (Exception e) { |
| | | // swallow the exception which we expect |
| | | } |
| | | |
| | | assertFalse("Anonymous was able to clone the repository?!", cloned); |
| | | |
| | | FileUtils.delete(ticgit2Folder, FileUtils.RECURSIVE); |
| | | |
| | | // restore anonymous repository access |
| | | model.accessRestriction = AccessRestrictionType.NONE; |
| | | model.authorizationControl = AuthorizationControl.NAMED; |
| | | GitBlit.self().updateRepositoryModel(model.name, model, false); |
| | | } |
| | | |
| | | @Test |
| | | public void testAnonymousPush() throws Exception { |
| | | GitBlitSuite.close(ticgitFolder); |
| | | if (ticgitFolder.exists()) { |
| | | FileUtils.delete(ticgitFolder, FileUtils.RECURSIVE | FileUtils.RETRY); |
| | | } |
| | | |
| | | // restore anonymous repository access |
| | | RepositoryModel model = GitBlit.self().getRepositoryModel("ticgit.git"); |
| | | model.accessRestriction = AccessRestrictionType.NONE; |
| | | model.authorizationControl = AuthorizationControl.NAMED; |
| | | GitBlit.self().updateRepositoryModel(model.name, model, false); |
| | | |
| | | CloneCommand clone = Git.cloneRepository(); |
| | | clone.setURI(MessageFormat.format("{0}/ticgit.git", url)); |
| | | clone.setDirectory(ticgitFolder); |
| | | clone.setBare(false); |
| | | clone.setCloneAllBranches(true); |
| | | GitBlitSuite.close(clone.call()); |
| | | assertTrue(true); |
| | | |
| | | Git git = Git.open(ticgitFolder); |
| | | File file = new File(ticgitFolder, "TODO"); |
| | | OutputStreamWriter os = new OutputStreamWriter(new FileOutputStream(file, true), Constants.CHARSET); |
| | | BufferedWriter w = new BufferedWriter(os); |
| | | w.write("// hellol䏿–‡ " + new Date().toString() + "\n"); |
| | | w.close(); |
| | | git.add().addFilepattern(file.getName()).call(); |
| | | git.commit().setMessage("test commit").call(); |
| | | Iterable<PushResult> results = git.push().setPushAll().call(); |
| | | GitBlitSuite.close(git); |
| | | for (PushResult result : results) { |
| | | for (RemoteRefUpdate update : result.getRemoteUpdates()) { |
| | | assertEquals(Status.OK, update.getStatus()); |
| | | } |
| | | } |
| | | } |
| | | |
| | | @Test |
| | | public void testPushRestrictedRepo() throws Exception { |
| | | GitBlitSuite.close(ticgitFolder); |
| | | if (ticgitFolder.exists()) { |
| | | FileUtils.delete(ticgitFolder, FileUtils.RECURSIVE | FileUtils.RETRY); |
| | | } |
| | | |
| | | // restore anonymous repository access |
| | | RepositoryModel model = GitBlit.self().getRepositoryModel("ticgit.git"); |
| | | model.accessRestriction = AccessRestrictionType.PUSH; |
| | | model.authorizationControl = AuthorizationControl.NAMED; |
| | | GitBlit.self().updateRepositoryModel(model.name, model, false); |
| | | |
| | | CloneCommand clone = Git.cloneRepository(); |
| | | clone.setURI(MessageFormat.format("{0}/ticgit.git", url)); |
| | | clone.setDirectory(ticgitFolder); |
| | | clone.setBare(false); |
| | | clone.setCloneAllBranches(true); |
| | | GitBlitSuite.close(clone.call()); |
| | | assertTrue(true); |
| | | |
| | | Git git = Git.open(ticgitFolder); |
| | | File file = new File(ticgitFolder, "TODO"); |
| | | OutputStreamWriter os = new OutputStreamWriter(new FileOutputStream(file, true), Constants.CHARSET); |
| | | BufferedWriter w = new BufferedWriter(os); |
| | | w.write("// hellol䏿–‡ " + new Date().toString() + "\n"); |
| | | w.close(); |
| | | git.add().addFilepattern(file.getName()).call(); |
| | | git.commit().setMessage("test commit").call(); |
| | | Iterable<PushResult> results = git.push().setPushAll().call(); |
| | | GitBlitSuite.close(git); |
| | | for (PushResult result : results) { |
| | | for (RemoteRefUpdate update : result.getRemoteUpdates()) { |
| | | assertEquals(Status.REJECTED_OTHER_REASON, update.getStatus()); |
| | | } |
| | | } |
| | | } |
| | | |
| | | @Test |
| | | public void testPushToFrozenRepo() throws Exception { |
| | | GitBlitSuite.close(jgitFolder); |
| | | if (jgitFolder.exists()) { |
| | | FileUtils.delete(jgitFolder, FileUtils.RECURSIVE | FileUtils.RETRY); |
| | | } |
| | | |
| | | CloneCommand clone = Git.cloneRepository(); |
| | | clone.setURI(MessageFormat.format("{0}/test/jgit.git", url)); |
| | | clone.setDirectory(jgitFolder); |
| | | clone.setBare(false); |
| | | clone.setCloneAllBranches(true); |
| | | GitBlitSuite.close(clone.call()); |
| | | assertTrue(true); |
| | | |
| | | // freeze repo |
| | | RepositoryModel model = GitBlit.self().getRepositoryModel("test/jgit.git"); |
| | | model.isFrozen = true; |
| | | GitBlit.self().updateRepositoryModel(model.name, model, false); |
| | | |
| | | Git git = Git.open(jgitFolder); |
| | | File file = new File(jgitFolder, "TODO"); |
| | | OutputStreamWriter os = new OutputStreamWriter(new FileOutputStream(file, true), Constants.CHARSET); |
| | | BufferedWriter w = new BufferedWriter(os); |
| | | w.write("// " + new Date().toString() + "\n"); |
| | | w.close(); |
| | | git.add().addFilepattern(file.getName()).call(); |
| | | git.commit().setMessage("test commit").call(); |
| | | |
| | | Iterable<PushResult> results = git.push().call(); |
| | | for (PushResult result : results) { |
| | | for (RemoteRefUpdate update : result.getRemoteUpdates()) { |
| | | assertEquals(Status.REJECTED_OTHER_REASON, update.getStatus()); |
| | | } |
| | | } |
| | | |
| | | // unfreeze repo |
| | | model.isFrozen = false; |
| | | GitBlit.self().updateRepositoryModel(model.name, model, false); |
| | | |
| | | results = git.push().setPushAll().call(); |
| | | GitBlitSuite.close(git); |
| | | for (PushResult result : results) { |
| | | for (RemoteRefUpdate update : result.getRemoteUpdates()) { |
| | | assertEquals(Status.OK, update.getStatus()); |
| | | } |
| | | } |
| | | } |
| | | |
| | | @Test |
| | | public void testPushToNonBareRepository() throws Exception { |
| | | GitBlitSuite.close(jgit2Folder); |
| | | if (jgit2Folder.exists()) { |
| | | FileUtils.delete(jgit2Folder, FileUtils.RECURSIVE | FileUtils.RETRY); |
| | | } |
| | | |
| | | CloneCommand clone = Git.cloneRepository(); |
| | | clone.setURI(MessageFormat.format("{0}/working/jgit", url)); |
| | | clone.setDirectory(jgit2Folder); |
| | | clone.setBare(false); |
| | | clone.setCloneAllBranches(true); |
| | | GitBlitSuite.close(clone.call()); |
| | | assertTrue(true); |
| | | |
| | | Git git = Git.open(jgit2Folder); |
| | | File file = new File(jgit2Folder, "NONBARE"); |
| | | OutputStreamWriter os = new OutputStreamWriter(new FileOutputStream(file, true), Constants.CHARSET); |
| | | BufferedWriter w = new BufferedWriter(os); |
| | | w.write("// " + new Date().toString() + "\n"); |
| | | w.close(); |
| | | git.add().addFilepattern(file.getName()).call(); |
| | | git.commit().setMessage("test commit followed by push to non-bare repository").call(); |
| | | |
| | | Iterable<PushResult> results = git.push().setPushAll().call(); |
| | | GitBlitSuite.close(git); |
| | | |
| | | for (PushResult result : results) { |
| | | for (RemoteRefUpdate update : result.getRemoteUpdates()) { |
| | | assertEquals(Status.REJECTED_OTHER_REASON, update.getStatus()); |
| | | } |
| | | } |
| | | } |
| | | |
| | | } |
| | |
| | |
|
| | | static File jgit2Folder = new File(GitBlitSuite.REPOSITORIES, "working/jgit2");
|
| | |
|
| | | String url = GitBlitSuite.url;
|
| | | String url = GitBlitSuite.gitServletUrl;
|
| | | String account = GitBlitSuite.account;
|
| | | String password = GitBlitSuite.password;
|
| | |
|
| | |
| | | }
|
| | |
|
| | | CloneCommand clone = Git.cloneRepository();
|
| | | clone.setURI(MessageFormat.format("{0}/git/ticgit.git", url));
|
| | | clone.setURI(MessageFormat.format("{0}/ticgit.git", url));
|
| | | clone.setDirectory(ticgitFolder);
|
| | | clone.setBare(false);
|
| | | clone.setCloneAllBranches(true);
|
| | |
| | | boolean cloned = false;
|
| | | try {
|
| | | CloneCommand clone = Git.cloneRepository();
|
| | | clone.setURI(MessageFormat.format("{0}/git/ticgit.git", url));
|
| | | clone.setURI(MessageFormat.format("{0}/ticgit.git", url));
|
| | | clone.setDirectory(ticgit2Folder);
|
| | | clone.setBare(false);
|
| | | clone.setCloneAllBranches(true);
|
| | |
| | | boolean cloned = false;
|
| | | try {
|
| | | CloneCommand clone = Git.cloneRepository();
|
| | | clone.setURI(MessageFormat.format("{0}/git/ticgit.git", url));
|
| | | clone.setURI(MessageFormat.format("{0}/ticgit.git", url));
|
| | | clone.setDirectory(ticgit2Folder);
|
| | | clone.setBare(false);
|
| | | clone.setCloneAllBranches(true);
|
| | |
| | | // try clone again
|
| | | cloned = false;
|
| | | CloneCommand clone = Git.cloneRepository();
|
| | | clone.setURI(MessageFormat.format("{0}/git/ticgit.git", url));
|
| | | clone.setURI(MessageFormat.format("{0}/ticgit.git", url));
|
| | | clone.setDirectory(ticgit2Folder);
|
| | | clone.setBare(false);
|
| | | clone.setCloneAllBranches(true);
|
| | |
| | | FileUtils.delete(ticgitFolder, FileUtils.RECURSIVE | FileUtils.RETRY);
|
| | | }
|
| | |
|
| | | RepositoryModel model = GitBlit.self().getRepositoryModel("ticgit.git");
|
| | | model.accessRestriction = AccessRestrictionType.NONE;
|
| | | GitBlit.self().updateRepositoryModel(model.name, model, false);
|
| | |
|
| | | CloneCommand clone = Git.cloneRepository();
|
| | | clone.setURI(MessageFormat.format("{0}/git/ticgit.git", url));
|
| | | clone.setURI(MessageFormat.format("{0}/ticgit.git", url));
|
| | | clone.setDirectory(ticgitFolder);
|
| | | clone.setBare(false);
|
| | | clone.setCloneAllBranches(true);
|
| | |
| | | w.close();
|
| | | git.add().addFilepattern(file.getName()).call();
|
| | | git.commit().setMessage("test commit").call();
|
| | | git.push().setPushAll().call();
|
| | | Iterable<PushResult> results = git.push().setPushAll().call();
|
| | | GitBlitSuite.close(git);
|
| | | for (PushResult result : results) {
|
| | | for (RemoteRefUpdate update : result.getRemoteUpdates()) {
|
| | | assertEquals(Status.OK, update.getStatus());
|
| | | }
|
| | | }
|
| | | }
|
| | |
|
| | | @Test
|
| | |
| | | }
|
| | |
|
| | | CloneCommand clone = Git.cloneRepository();
|
| | | clone.setURI(MessageFormat.format("{0}/git/test/jgit.git", url));
|
| | | clone.setURI(MessageFormat.format("{0}/test/jgit.git", url));
|
| | | clone.setDirectory(jgitFolder);
|
| | | clone.setBare(false);
|
| | | clone.setCloneAllBranches(true);
|
| | |
| | | w.close();
|
| | | git.add().addFilepattern(file.getName()).call();
|
| | | git.commit().setMessage("test commit").call();
|
| | | git.push().setPushAll().setCredentialsProvider(new UsernamePasswordCredentialsProvider(account, password)).call();
|
| | | Iterable<PushResult> results = git.push().setPushAll().setCredentialsProvider(new UsernamePasswordCredentialsProvider(account, password)).call();
|
| | | GitBlitSuite.close(git);
|
| | | for (PushResult result : results) {
|
| | | for (RemoteRefUpdate update : result.getRemoteUpdates()) {
|
| | | assertEquals(Status.OK, update.getStatus());
|
| | | }
|
| | | }
|
| | | }
|
| | |
|
| | | @Test
|
| | |
| | | }
|
| | |
|
| | | CloneCommand clone = Git.cloneRepository();
|
| | | clone.setURI(MessageFormat.format("{0}/git/test/jgit.git", url));
|
| | | clone.setURI(MessageFormat.format("{0}/test/jgit.git", url));
|
| | | clone.setDirectory(jgitFolder);
|
| | | clone.setBare(false);
|
| | | clone.setCloneAllBranches(true);
|
| | |
| | | git.add().addFilepattern(file.getName()).call();
|
| | | git.commit().setMessage("test commit").call();
|
| | |
|
| | | try {
|
| | | git.push().setPushAll().setCredentialsProvider(new UsernamePasswordCredentialsProvider(account, password)).call();
|
| | | assertTrue(false);
|
| | | } catch (Exception e) {
|
| | | assertTrue(e.getCause().getMessage().contains("access forbidden"));
|
| | | Iterable<PushResult> results = git.push().setPushAll().setCredentialsProvider(new UsernamePasswordCredentialsProvider(account, password)).call();
|
| | | for (PushResult result : results) {
|
| | | for (RemoteRefUpdate update : result.getRemoteUpdates()) {
|
| | | assertEquals(Status.REJECTED_OTHER_REASON, update.getStatus());
|
| | | }
|
| | | }
|
| | |
|
| | | // unfreeze repo
|
| | | model.isFrozen = false;
|
| | | GitBlit.self().updateRepositoryModel(model.name, model, false);
|
| | |
|
| | | git.push().setPushAll().setCredentialsProvider(new UsernamePasswordCredentialsProvider(account, password)).call();
|
| | | results = git.push().setPushAll().setCredentialsProvider(new UsernamePasswordCredentialsProvider(account, password)).call();
|
| | | GitBlitSuite.close(git);
|
| | | for (PushResult result : results) {
|
| | | for (RemoteRefUpdate update : result.getRemoteUpdates()) {
|
| | | assertEquals(Status.OK, update.getStatus());
|
| | | }
|
| | | }
|
| | | }
|
| | |
|
| | | @Test
|
| | | public void testPushToNonBareRepository() throws Exception {
|
| | | CloneCommand clone = Git.cloneRepository();
|
| | | clone.setURI(MessageFormat.format("{0}/git/working/jgit", url));
|
| | | clone.setURI(MessageFormat.format("{0}/working/jgit", url));
|
| | | clone.setDirectory(jgit2Folder);
|
| | | clone.setBare(false);
|
| | | clone.setCloneAllBranches(true);
|
| | |
| | | w.close();
|
| | | git.add().addFilepattern(file.getName()).call();
|
| | | git.commit().setMessage("test commit followed by push to non-bare repository").call();
|
| | | try {
|
| | | git.push().setPushAll().setCredentialsProvider(new UsernamePasswordCredentialsProvider(account, password)).call();
|
| | | assertTrue(false);
|
| | | } catch (Exception e) {
|
| | | assertTrue(e.getCause().getMessage().contains("git-receive-pack not permitted"));
|
| | | }
|
| | | Iterable<PushResult> results = git.push().setPushAll().setCredentialsProvider(new UsernamePasswordCredentialsProvider(account, password)).call();
|
| | | GitBlitSuite.close(git);
|
| | | for (PushResult result : results) {
|
| | | for (RemoteRefUpdate update : result.getRemoteUpdates()) {
|
| | | assertEquals(Status.REJECTED_OTHER_REASON, update.getStatus());
|
| | | }
|
| | | }
|
| | | }
|
| | |
|
| | | @Test
|
| | |
| | | FileUtils.delete(verification, FileUtils.RECURSIVE);
|
| | | }
|
| | | CloneCommand clone = Git.cloneRepository();
|
| | | clone.setURI(MessageFormat.format("{0}/git/ticgit.git", url));
|
| | | clone.setURI(MessageFormat.format("{0}/ticgit.git", url));
|
| | | clone.setDirectory(verification);
|
| | | clone.setBare(true);
|
| | | clone.setCloneAllBranches(true);
|
| | |
| | | FileUtils.delete(local, FileUtils.RECURSIVE);
|
| | | }
|
| | | clone = Git.cloneRepository();
|
| | | clone.setURI(MessageFormat.format("{0}/git/{1}", url, model.name));
|
| | | clone.setURI(MessageFormat.format("{0}/{1}", url, model.name));
|
| | | clone.setDirectory(local);
|
| | | clone.setBare(false);
|
| | | clone.setCloneAllBranches(true);
|
| | |
| | | FileUtils.delete(refChecks, FileUtils.RECURSIVE);
|
| | | }
|
| | | CloneCommand clone = Git.cloneRepository();
|
| | | clone.setURI(MessageFormat.format("{0}/git/ticgit.git", url));
|
| | | clone.setURI(MessageFormat.format("{0}/ticgit.git", url));
|
| | | clone.setDirectory(refChecks);
|
| | | clone.setBare(true);
|
| | | clone.setCloneAllBranches(true);
|
| | |
| | | FileUtils.delete(local, FileUtils.RECURSIVE);
|
| | | }
|
| | | clone = Git.cloneRepository();
|
| | | clone.setURI(MessageFormat.format("{0}/git/{1}", url, model.name));
|
| | | clone.setURI(MessageFormat.format("{0}/{1}", url, model.name));
|
| | | clone.setDirectory(local);
|
| | | clone.setBare(false);
|
| | | clone.setCloneAllBranches(true);
|
| | |
| | | }
|
| | |
|
| | | CloneCommand clone = Git.cloneRepository();
|
| | | clone.setURI(MessageFormat.format("{0}/git/ticgit.git", url));
|
| | | clone.setURI(MessageFormat.format("{0}/ticgit.git", url));
|
| | | clone.setDirectory(createCheck);
|
| | | clone.setBare(true);
|
| | | clone.setCloneAllBranches(true);
|
| | |
| | | GitBlitSuite.close(personalRepo);
|
| | |
|
| | | // add a personal repository remote and a project remote
|
| | | git.getRepository().getConfig().setString("remote", "user", "url", MessageFormat.format("{0}/git/~{1}/ticgit.git", url, user.username));
|
| | | git.getRepository().getConfig().setString("remote", "project", "url", MessageFormat.format("{0}/git/project/ticgit.git", url));
|
| | | git.getRepository().getConfig().setString("remote", "user", "url", MessageFormat.format("{0}/~{1}/ticgit.git", url, user.username));
|
| | | git.getRepository().getConfig().setString("remote", "project", "url", MessageFormat.format("{0}/project/ticgit.git", url));
|
| | | git.getRepository().getConfig().save();
|
| | |
|
| | | // push to non-existent user repository
|
| | |
| | | } |
| | | |
| | | @Override |
| | | protected void enableLuceneIndexing() { |
| | | protected void configureLuceneIndexing() { |
| | | if (luceneIndexingEnabled) { |
| | | getScheduledExecutor().scheduleAtFixedRate(getLuceneExecutor(), 1, |
| | | 2, TimeUnit.MINUTES); |